基於Qt、FFMpeg的音視頻播放器設計三(Qt界面設計及OpenGL繪製視頻)

本部分總結了一下界面繪製和OpenGL繪製視頻,由於使用的是Qt的openGL,功能上沒有那麼複雜,實現起來也比較簡單,畢竟人家已經給封好的,完整的代碼中使用OpenGL繪製視頻,對數據的頂點shader、片元shader着色,對yuv材質的綁定,分配材質內存空間、創建材質顯卡空間、紋理以及顯卡繪製每幀視頻時如何對齊等等一些內容,這部分內容是OpenGL中的,較爲複雜,待繼續學習後有一定收穫再來總結,現在我們繼續看這裏。

一、基於QT的播放器界面繪製

在做opengl繪製視頻前,我們先需要設計一個界面,打開vs2013中該項目中的ui,進入Qt設計界面,設置好界面的屬性後,在我們繪製視頻時,可以選擇3D引擎UX,或者OpenGL,但在這裏我們用Qt自帶的OpenGL。選擇Qt的控件Open GL Widget,在界面中繪製一片區域,設置大小以及屬性,之後加入兩個按鈕控件爲打開文件和播放視頻,加入相對應的圖標,如何加入,網上有很多方法,這裏就不囉嗦了,主要得知道這裏兩個按鈕的變量名爲openButton和playButton,後面需要用到的。

二、通過QT顯示轉碼後的RGB數據

現在我們需要將FFMpeg解碼後的視頻播放出來,如何播放?在上面中我們創建了窗口openGLWidget,這裏我們重載這個類(是對象openGLWidget的類QOpenGLWidget,重載的是這個類),然後使用我們自己的方法來控制這個窗口。這裏我將QOpenGLWidget類提升爲VideoWidget類。

然後我們在VS2013中用類嚮導創建該類進行實現(要繼承自QOpenGLWidget)。首先在VideoWidget.h中申明定時器和窗口的重新繪製的函數。

#pragma once
#include <QtWidgets/qwidget.h>
#include <QOpenGLWidget>

class VideoWidget:public QOpenGLWidget
{
public:
	VideoWidget(QWidget *parent = NULL);

	void paintEvent(QPaintEvent *event);//窗口的重新繪製
	void timerEvent(QTimerEvent *event);//定時器
	virtual ~VideoWidget();
};

對於paintEvent的定義,我們知道繪製時需要FFMpeg解碼出來的視頻幀,而對於解封裝、解碼我們都在XFFMpeg類中完成,這裏我們需要使用它。而在VideoWidget的構造函數裏需要打開視頻,同時設置定製器來顯示播放,目前這是測試階段,我們就先考慮單線程,播放時有些卡頓,當然後面我們會使用多線程解決這一問題,現在我們看下paintEvent的定義。

void VideoWidget::paintEvent(QPaintEvent *e)
{//繪製
	static QImage *image = NULL;

	if (image == NULL)
	{
		uchar *buf = new uchar[width()*height() * 4];//存放解碼後的視頻空間
		image = new QImage(buf, width(), height(), QImage::Format_ARGB32);
	}

	AVPacket pkt = XFFmpeg::Get()->Read();//讀取視頻幀
	if (pkt.stream_index != XFFmpeg::Get()->videoStream)
	{//不爲視頻幀,釋放pkt的空間
		av_packet_unref(&pkt);
		return;
	}
	if (pkt.size == 0) return;

	AVFrame *yuv = XFFmpeg::Get()->Decode(&pkt);//解碼讀取到的視頻幀
	av_packet_unref(&pkt);//解碼成後也需要釋放空間
	if (yuv == NULL) return;

	//將解碼後的視頻幀轉化爲RGB
	XFFmpeg::Get()->ToRGB(yuv, (char *)image->bits(),width(),height());


	QPainter painter;//hua
	painter.begin(this);
	painter.drawImage(QPoint(0, 0), *image);//繪製FFMpeg解碼後的視頻
	painter.end();//


}

XFFMpeg的讀取、解碼、轉換爲RGB在之前我們也都說明過。這裏要說下的可能就是

if (image == NULL)
           {
              uchar *buf = new uchar[width()*height() * 4];//存放解碼後的視頻空間
              image = new QImage(buf, width(), height(), QImage::Format_ARGB32);
           }

這裏的buf用來後面對於解碼後的視頻幀繪製時用到的,開闢的空間後*4是RGB有三個色彩同時這裏還有一個通道數,共佔用了四個字節,後面的image 的格式 QImage::Format_ARGB32也選擇了32位的設置,都對應了在XFFMPeg中解碼以及轉化RGB格式時所設置的一些參數。

後面就是它的構造函數以及定時器函數,裏面也都比較簡單。

VideoWidget::VideoWidget(QWidget *parent) :QOpenGLWidget(parent)
{
	XFFmpeg::Get()->Open("1080.mp4");//打開視頻
	startTimer(10);//設置定時器
}
void VideoWidget::timerEvent(QTimerEvent *event)
{
	this->update();//定時器更新
}

對於這部分內容大概就這麼多,繪製基本如此,下一篇中我們進行視頻播放進度控制,處理之前的卡頓現象。

下一篇鏈接:https://blog.csdn.net/hfuu1504011020/article/details/82705890

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章