从零开始学习音视频编程技术(六) FFMPEG Qt视频播放器之显示图像

xiaoxiao2021-02-28  102

从零开始学习音视频编程技术(六) FFMPEG Qt视频播放器之显示图像 分享到: QQ空间 微信 新浪微博 腾讯微博 人人网 时间:2016年09月07日 人气: 2640

前面讲解了如何用FFMPEG解码视频。

现在,我们就着手用FFMPEG+Qt写一个视频播放器吧:

由于现在我们需要显示图像了,因此现在开始需要使用Qt GUI工程了。

创建工程的时候记得选择Qt GUI应用。

引用FFMPEG请参考前面的文章,这里不再介绍。

做过图像界面开发的都知道,任何耗时的操作都不能放在主线程进行,一旦主线程阻塞了,那么体现出来的就是界面卡了。 而我们读取视频和解码视频是一个非常耗时的操作,因此需要另外开辟一个线程来专门做这件事。

Qt里面线程的用法 则是写一个类继承QThread, 然后重载其run函数,把耗时的操作全部放入run函数。

1 2 3 4 5 6 7 8 9 10 11 12 class  VideoPlayer :  public  QThread {      Q_OBJECT   public :      explicit  VideoPlayer();      ~VideoPlayer();   protected :      void  run();   };

这里run函数里面就是写我们读取视频和解码视频的代码了;

读取和解码还是和前面说的一样的方法:

改动的一点是:

由于我们需要用Qt的控件来显示,因此是把解码之后的YUV数据转换成了RGB32格式的数据:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ///这里我们改成了 将解码后的YUV数据转换成RGB32     img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,              pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,              PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);        numBytes = avpicture_get_size(PIX_FMT_RGB32, pCodecCtx->width,pCodecCtx->height);        out_buffer = (uint8_t *) av_malloc(numBytes *  sizeof (uint8_t));      avpicture_fill((AVPicture *) pFrameRGB, out_buffer, PIX_FMT_RGB32,              pCodecCtx->width, pCodecCtx->height);                             .... ... ..   sws_scale(img_convert_ctx,                  (uint8_t  const  *  const  *) pFrame->data,                  pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data,                  pFrameRGB->linesize);

同时将转换后的RGB32数据存入QImage对象:

1 2 //把这个RGB数据 用QImage加载 QImage tmpImg((uchar *)out_buffer,pCodecCtx->width,pCodecCtx->height,QImage::Format_RGB32);

由于我们不能够在子线程中操作界面,(操作界面只能在主线程中进行,几乎所有的图形界面开发都是这样设定),因此我们只能给主线程发送信号,信号带上这个QIMage,让主线程帮忙把这个图像显示出来。

声明信号:

1 2 signals:          void  sig_GetOneFrame(QImage);  //没获取到一帧图像 就发送此信号

发送信号:

1 2 3 4 //把这个RGB数据 用QImage加载                 QImage tmpImg((uchar *)out_buffer,pCodecCtx->width,pCodecCtx->height,QImage::Format_RGB32); QImage image = tmpImg.copy();  //把图像复制一份 传递给界面显示 emit sig_GetOneFrame(image);   //发送信号

主线程绑定并接收信号:

1 2      mPlayer =  new  VideoPlayer;          connect(mPlayer,SIGNAL(sig_GetOneFrame(QImage)), this ,SLOT(slotGetOneFrame(QImage)));

信号处理函数如下:

1 2 3 4 void  MainWindow::slotGetOneFrame(QImage img){      mImage = img;      update();  //调用update将执行 paintEvent函数 }

主线程显示图像 则是通过QPainter直接绘制:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 void  MainWindow::paintEvent(QPaintEvent *event){      QPainter painter( this );      painter.setBrush(Qt::black);      painter.drawRect(0, 0,  this ->width(),  this ->height());  //先画成黑色        if  (mImage.size().width() <= 0)  return ;        ///将图像按比例缩放成和窗口一样大小      QImage img = mImage.scaled( this ->size(),Qt::KeepAspectRatio);        int  x =  this ->width() - img.width();      int  y =  this ->height() - img.height();        x /= 2;      y /= 2;        painter.drawImage(QPoint(x,y),img);  //画出图像   }

运行之后的程序如下:

当然这个离播放器还有十万八千里的步伐,后面我们将会一步一步完善它。

古语有云:不积跬步,无以至千里;不积小流,无以成江海。

写代码也一样,得慢慢来,一步一步往目标走,总能成功。

完整的工程下载地址:

http://download.csdn.net/detail/qq214517703/9624527

转载请注明原文地址: https://www.6miu.com/read-69314.html

最新回复(0)