Qt,ffmpeg,SDL2实现一个简单的视频播放器
先贴一下这三个库的版本:
QT:6.2.4
fmpeg:5.1.3
SDL2
总体思路是参考的雷神的博客:最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)_flush decoder_雷霄骅的博客-CSDN博客
1 #include "videopanel.h" 2 #include "ui_VideoPanel.h" 3 4 5 VideoPanel::VideoPanel(QWidget *parent) : 6 QWidget(parent), ui(new Ui::VideoPanel) { 7 ui->setupUi(this); 8 9 } 10 11 VideoPanel::~VideoPanel() { 12 SDL_Quit(); 13 av_frame_free(&frame); 14 av_frame_free(&yuvFrame); 15 avcodec_close(codecContext); 16 avformat_close_input(&formatContext); 17 delete ui; 18 } 19 20 void VideoPanel::initAV() { 21 avformat_network_init(); 22 formatContext = avformat_alloc_context(); 23 frame = av_frame_alloc(); 24 yuvFrame = av_frame_alloc(); 25 if(pt.joinable()) pt.join(); 26 } 27 28 int VideoPanel::openFile(const char *fileName) { 29 initAV(); 30 31 if(avformat_open_input(&formatContext,fileName, nullptr, nullptr) != 0){ 32 printf("Couldn't open input stream.\n"); 33 return -1; 34 } 35 36 if(avformat_find_stream_info(formatContext, nullptr) <0 ){ 37 printf("Couldn't find stream information.\n"); 38 return -1; 39 } 40 41 videoIndex=-1; 42 for(i=0; i<formatContext->nb_streams; i++){ 43 if(formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){ 44 videoIndex=i; 45 break; 46 } 47 } 48 49 if(videoIndex==-1){ 50 printf("Didn't find a video stream.\n"); 51 return -1; 52 } 53 54 codecContext = avcodec_alloc_context3(nullptr); 55 if(avcodec_parameters_to_context(codecContext,formatContext->streams[videoIndex]->codecpar) < 0){ 56 printf("Can't find codec\n"); 57 } 58 59 codec = avcodec_find_decoder(codecContext->codec_id); 60 codecContext->codec_id = codec->id; 61 avcodec_open2(codecContext, codec, nullptr); 62 63 avPacket=(AVPacket *)av_malloc(sizeof(AVPacket)); 64 65 img_convert_ctx = sws_getContext(codecContext->width, 66 codecContext->height, 67 codecContext->pix_fmt, 68 codecContext->width, 69 codecContext->height, 70 AV_PIX_FMT_YUV420P, 71 SWS_BICUBIC, 72 nullptr, 73 nullptr, 74 nullptr); 75 76 if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)){ 77 printf( "Could not initialize SDL - %s\n", SDL_GetError()); 78 return -1; 79 } 80 81 screen_width = codecContext->width; 82 screen_height = codecContext->height; 83 84 sdlWindow = SDL_CreateWindowFrom((void *)ui->label->winId()); 85 86 if(!sdlWindow) { 87 printf("SDL: could not create window - exiting:%s\n",SDL_GetError()); 88 return -1; 89 } 90 91 sdlRenderer = SDL_CreateRenderer(sdlWindow, -1,SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); 92 if(!sdlRenderer){ 93 av_log(NULL, AV_LOG_WARNING, "Failed to initialize a hardware accelerated renderer: %s\n", SDL_GetError()); 94 sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0); 95 } 96 97 sdlTexture = SDL_CreateTexture(sdlRenderer, 98 SDL_PIXELFORMAT_IYUV, 99 SDL_TEXTUREACCESS_STREAMING, 100 codecContext->width, 101 codecContext->height); 102 103 sdlRect.x = 0; 104 sdlRect.y = 0; 105 sdlRect.w = screen_width; 106 sdlRect.h = screen_height; 107 108 yuvFrame->width = codecContext->width; 109 yuvFrame->height = codecContext->height; 110 yuvFrame->format = AV_PIX_FMT_YUV420P; 111 av_frame_get_buffer(yuvFrame,1); 112 113 frame_time = 1000.0 / av_q2d(formatContext->streams[videoIndex]->r_frame_rate); 114 115 pt = std::thread(&VideoPanel::playThread, this); 116 return 0; 117 } 118 119 void VideoPanel::playThread() { 120 while(av_read_frame(formatContext, avPacket) >= 0){ 121 if(avPacket->stream_index == videoIndex){ 122 if ((ret = avcodec_send_packet(codecContext, avPacket)) == AVERROR(EAGAIN)) { 123 av_log(codecContext, AV_LOG_ERROR, "Receive_frame and send_packet both returned EAGAIN, which is an API violation.\n"); 124 } 125 else { 126 av_packet_unref(avPacket); 127 } 128 129 while (avcodec_receive_frame(codecContext, frame) == 0){ 130 sws_scale(img_convert_ctx, 131 (const uint8_t * const*)frame->data, 132 frame->linesize, 133 0, 134 codecContext->height, 135 yuvFrame->data, 136 yuvFrame->linesize); 137 138 SDL_UpdateYUVTexture(sdlTexture, 139 &sdlRect, 140 yuvFrame->data[0], 141 yuvFrame->linesize[0], 142 yuvFrame->data[1], 143 yuvFrame->linesize[1], 144 yuvFrame->data[2], 145 yuvFrame->linesize[2]); 146 147 SDL_RenderClear(sdlRenderer); 148 SDL_RenderCopy(sdlRenderer, sdlTexture, nullptr, &sdlRect); 149 SDL_RenderPresent(sdlRenderer); 150 SDL_Delay(40); 151 } 152 } 153 av_packet_unref(avPacket); 154 } 155 sws_freeContext(img_convert_ctx); 156 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)