下面是一个简单的示例代码,展示了如何使用FFmpeg和OpenGL进行视频解码和渲染:
#include <iostream>
#include <GL/glut.h>
#include <opencv2/opencv.hpp>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
// 视频相关变量
AVFormatContext* formatCtx;
AVCodecContext* codecCtx;
AVFrame* frame;
int videoStreamIndex;
struct SwsContext* swsCtx;
// OpenGL窗口尺寸
int windowWidth = 800;
int windowHeight = 600;
// 纹理ID和大小
GLuint textureID;
int textureWidth, textureHeight;
void display() {
glClear(GL_COLOR_BUFFER_BIT);
// 使用纹理绘制图像
glBindTexture(GL_TEXTURE_2D, textureID);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 1.0); glVertex2f(-1.0, -1.0);
glTexCoord2f(1.0, 1.0); glVertex2f(1.0, -1.0);
glTexCoord2f(1.0, 0.0); glVertex2f(1.0, 1.0);
glTexCoord2f(0.0, 0.0); glVertex2f(-1.0, 1.0);
glEnd();
glutSwapBuffers();
}
void reshape(int width, int height) {
windowWidth = width;
windowHeight = height;
glViewport(0, 0, windowWidth, windowHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1.0, 1.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void decodeFrame(AVCodecContext* codecCtx, AVPacket* packet) {
// 发送解码数据包到解码器
avcodec_send_packet(codecCtx, packet);
while (avcodec_receive_frame(codecCtx, frame) == 0) {
// 格式转换
sws_scale(swsCtx,
frame->data,
frame->linesize,
0,
codecCtx->height,
frame->data,
frame->linesize);
// 更新纹理数据
glBindTexture(GL_TEXTURE_2D, textureID);
glTexSubImage2D(GL_TEXTURE_2D,
0,
0,
0,
textureWidth,
textureHeight,
GL_RGB,
GL_UNSIGNED_BYTE,
frame->data[0]);
glutPostRedisplay();
}
}
int main(int argc, char** argv) {
if (argc < 2) {
std::cout << "Please provide a video file." << std::endl;
return -1;
}
// 初始化FFmpeg
av_register_all();
// 打开视频文件
if (avformat_open_input(&formatCtx, argv[1], nullptr, nullptr) != 0) {
std::cout << "Failed to open video file." << std::endl;
return -1;
}
// 获取视频流信息
if (avformat_find_stream_info(formatCtx, nullptr) < 0) {
std::cout << "Failed to find stream information." << std::endl;
return -1;
}
// 查找视频流
for (int i = 0; i < formatCtx->nb_streams; i++) {
if (formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStreamIndex = i;
break;
}
}
// 获取解码器参数
AVCodecParameters* codecParams = formatCtx->streams[videoStreamIndex]->codecpar;
// 获取解码器
AVCodec* codec = avcodec_find_decoder(codecParams->codec_id);
// 打开解码器
if (avcodec_open2(codecCtx, codec, nullptr) < 0) {
std::cout << "Failed to open decoder." << std::endl;
return -1;
}
// 分配帧对象内存
frame = av_frame_alloc();
// 创建OpenGL窗口
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(windowWidth, windowHeight);
glutCreateWindow("Video Player");
// 初始化OpenGL纹理
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// 设置回调函数和窗口大小变化的回调函数
glutDisplayFunc(display);
glutReshapeFunc(reshape);
// 设置格式转换上下文
swsCtx = sws_getContext(codecParams->width,
codecParams->height,
static_cast<AVPixelFormat>(codecParams->format),
codecParams->width,
codecParams->height,
AV_PIX_FMT_RGB24,
SWS_BILINEAR,
nullptr,
nullptr,
nullptr);
// 读取视频帧
AVPacket packet;
while (av_read_frame(formatCtx, &packet) >= 0) {
if (packet.stream_index == videoStreamIndex) {
decodeFrame(codecCtx, &packet);
}
av_packet_unref(&packet);
}
// 清理资源
av_frame_free(&frame);
avcodec_close(codecCtx);
avformat_close_input(&formatCtx);
return 0;
}
这只是一个简单的示例,实际的实现可能需要根据具体情况进行修改和扩展。
内容由零声教学AI助手提供,问题来源于学员提问