要使用 C++ 和 FFmpeg 解码 MP4 视频文件并将解码出的帧以 23 帧每秒的速度传输到 OpenGL 显示,您需要执行以下几个步骤:
设置 FFmpeg: 首先确保您已经安装了 FFmpeg,并且能够在您的项目中包含它的头文件和库。
初始化 FFmpeg: 在您的代码中,您需要初始化 FFmpeg 库。
打开视频文件: 使用 FFmpeg 打开 MP4 文件并找到流信息。
解码视频帧: 使用解码器提取每一帧的视频数据。
OpenGL 绘制: 将解码的数据转换为纹理,然后使用 OpenGL 渲染显示。
控制帧率: 使用
std::this_thread::sleep_for
来控制每秒渲染的帧数。
下面是一个简单的框架示例,展示如何实现这个过程:
#include <iostream>
#include <thread>
#include <chrono>
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
}
// 初始化 OpenGL 函数(假设已定义)
void initOpenGL();
void renderFrame(AVFrame* frame);
int main() {
// 初始化 FFmpeg
av_register_all();
const char* filename = "your_video.mp4";
AVFormatContext* formatCtx = nullptr;
// 打开视频文件
if (avformat_open_input(&formatCtx, filename, nullptr, nullptr) != 0) {
std::cerr << "Could not open file." << std::endl;
return -1;
}
// 查找流信息
if (avformat_find_stream_info(formatCtx, nullptr) < 0) {
std::cerr << "Could not find stream information." << std::endl;
return -1;
}
// 找到视频流
int videoStreamIndex = -1;
for (unsigned int i = 0; i < formatCtx->nb_streams; ++i) {
if (formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStreamIndex = i;
break;
}
}
if (videoStreamIndex == -1) {
std::cerr << "Could not find a video stream." << std::endl;
return -1;
}
// 获取解码器上下文
AVCodecParameters* codecParams = formatCtx->streams[videoStreamIndex]->codecpar;
AVCodec* codec = avcodec_find_decoder(codecParams->codec_id);
if (!codec) {
std::cerr << "Unsupported codec!" << std::endl;
return -1;
}
AVCodecContext* codecCtx = avcodec_alloc_context3(codec);
avcodec_parameters_to_context(codecCtx, codecParams);
if (avcodec_open2(codecCtx, codec, nullptr) < 0) {
std::cerr << "Could not open codec." << std::endl;
return -1;
}
// 初始化 OpenGL
initOpenGL();
AVPacket packet;
AVFrame* frame = av_frame_alloc();
struct SwsContext* sws_ctx = sws_getContext(
codecParams->width,
codecParams->height,
codecCtx->pix_fmt,
codecParams->width,
codecParams->height,
AV_PIX_FMT_RGB24,
SWS_BILINEAR,
nullptr,
nullptr,
nullptr);
while (av_read_frame(formatCtx, &packet) >= 0) {
if (packet.stream_index == videoStreamIndex) {
avcodec_send_packet(codecCtx, &packet);
while (avcodec_receive_frame(codecCtx, frame) == 0) {
renderFrame(frame); // 此函数用于渲染当前帧
// 控制帧率:23fps => 每帧间隔约43.48ms
std::this_thread::sleep_for(std::chrono::milliseconds(43));
}
}
av_packet_unref(&packet);
}
// 清理资源
av_frame_free(&frame);
sws_freeContext(sws_ctx);
avcodec_free_context(&codecCtx);
avformat_close_input(&formatCtx);
return 0;
}
注意事项:
- 确保链接到正确的 FFmpeg 库,例如
libavformat
,libavcodec
, 和libswscale
。 - 您可能需要根据自己的 OpenGL 环境实现
initOpenGL()
和renderFrame()
函数,以适应具体需求。 - 根据您所需的效果和环境,可能需要进一步优化和调整代码。
内容由零声教学AI助手提供,问题来源于学员提问