系列索引:FFmpeg入门系列索引
上一篇:FFmpeg入门教程04.04:解码视频并保存为YUV格式文件
前两篇介绍了视频帧解码和帧数据解码保存,都是不够实时和直观,本篇介绍使用Qt作为界面来显示解码后的数据。
使用ffmpeg解码视频每一帧,因为比较耗时,所以独立一个线程。解码完成后的数据发送给界面,界面渲染显示图像数据,界面显示一个线程。
解码流程和之前一样。
解码流程图为:
Qt显示流程为
视频解码显示流程图为:
解码部分
解码部分和之前的一样,不过需要调整一下。
像初始化变量、打开文件、分配解码器上下文、打开解码器等等,这些操作只需要一次,并且耗时很短,不需要放在独立线程里面。而发送数据给解码器、解码、接收解码器解码结果、格式转换这些操作会一直持续直到视频处理结束,此部分最耗时,放在独立线程中。
qt的多线程结构的一种为:
1 2 3 4 5 6 7 8
| class FFmpegVideo:public QThread{ public: ... protected: void run(); private: ... }
CPP
|
继承QThread之后,重写run()函数,所有耗时操作在此函数中,且只有此函数的内容是在其他线程中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| void FFmpegVideo::run() { if(!openFlag){ qDebug()<<"Please open file first."; return; }
while(av_read_frame(fmtCtx,pkt)>=0){ if(pkt->stream_index == videoStreamIndex){ if(avcodec_send_packet(videoCodecCtx,pkt)>=0){ int ret; while((ret=avcodec_receive_frame(videoCodecCtx,yuvFrame))>=0){ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) return; else if (ret < 0) { fprintf(stderr, "Error during decoding\n"); exit(1); } sws_scale(img_ctx, yuvFrame->data,yuvFrame->linesize, 0,videoCodecCtx->height, rgbFrame->data,rgbFrame->linesize);
QImage img(out_buffer, videoCodecCtx->width,videoCodecCtx->height, QImage::Format_RGB32); emit sendQImage(img); QThread::msleep(30); } } av_packet_unref(pkt); } } }
CPP
|
显示部分
首先创建一个基于QWidget的类,名为FFmpegWidget。使用时,在ui中添加一个基本QWidget控件
ui
使用时将此控件提升为FFmpegWidget就可以了。这样对FFmpegWidget的操作就会直接作用与界面。
prompt
一帧解码完成之后会将数据转换为QImage的格式,然后发送信号emit sendQImage(const QImage img);
,将打包好的QImage图像发送出来。在显示界面有个对应的处理槽receiveQImage(const QImage img);
将接收到的图像数据赋值给界面类的全局变量。
1 2 3 4 5
| void FFmpegWidget::receiveQImage(const QImage &rImg) { img = rImg.scaled(this->size()); update(); }
CPP
|
更新img数据后,调用update()函数刷新界面,此函数会自动调用paintEvent函数绘制界面。
重写qt的paintEvent函数,界面会循环调用这个函数来在界面上绘图(当然,调用update()函数时也会调用此函数。)。
1 2 3 4 5
| void FFmpegWidget::paintEvent(QPaintEvent *) { QPainter painter(this); painter.drawImage(0,0,img); }
CPP
|
界面为:
ui
效果为:
result
cpu占用率为:
cpu rate
源码在ffmpeg_beginner中10.07.video_decode_by_cpu_display_by_qwidget
下。
下一篇:FFmpeg入门教程04.06:软解并使用QOpenGL播放视频(YUV420P->OpenGL)