当前位置:网站首页>Player practice 17 xvideowidget

Player practice 17 xvideowidget

2022-06-12 14:09:00 Sister Suo

int main(int argc, char *argv[])
{
    
    testtread tt;
    tt.init();

    QApplication a(argc, argv);
    Xplay2 w;
    w.show();

    w.ui.openGLWidget->Init(tt.demux.width, tt.demux.height);

    tt.video = w.ui.openGLWidget;
    tt.start();
    return a.exec();
}

In actual combat 14 in , It is read directly yuv One fan divided into one request OpenGL Drawing :
fp = fopen(“out240x128.yuv”, “rb”);
Here we get it by decoding frame To draw

open .ui file , add to OpenGL Control :
 Insert picture description here
Promote to class xvideowidget:
 Insert picture description here
stay ui_Xplay2 You can see the following code in the file :

class Ui_Xplay2Class
{
    
public:
    xvideowidget *openGLWidget;

    void setupUi(QWidget *Xplay2Class)
    {
    
        if (Xplay2Class->objectName().isEmpty())
            Xplay2Class->setObjectName(QString::fromUtf8("Xplay2Class"));
        Xplay2Class->resize(1072, 790);
        openGLWidget = new xvideowidget(Xplay2Class);
        openGLWidget->setObjectName(QString::fromUtf8("openGLWidget"));
        openGLWidget->setGeometry(QRect(149, 129, 800, 600));

        retranslateUi(Xplay2Class);

        QMetaObject::connectSlotsByName(Xplay2Class);
    } // setupUi

    void retranslateUi(QWidget *Xplay2Class)
    {
    
        Xplay2Class->setWindowTitle(QCoreApplication::translate("Xplay2Class", "Xplay2", nullptr));
    } // retranslateUi

};

You can see xvideowidget *openGLWidget; Put a point in the big class of this interface xvideowidget The pointer to OpenGLwidget, And call with this pointer resize Other methods

Add... To the code xvideowidget.h:

#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QGLShaderProgram>
#include <mutex>
struct AVFrame;
class xvideowidget : public QOpenGLWidget, protected QOpenGLFunctions
{
    
	Q_OBJECT

public:
	void Init(int width, int height);

	// Whether successful or not, release frame Space 
	virtual void Repaint(AVFrame* frame);

	xvideowidget(QWidget* parent);
	~xvideowidget();
protected:
	// Refresh the display 
	void paintGL();

	// initialization gl
	void initializeGL();

	//  Window size change 
	void resizeGL(int width, int height);
private:
	std::mutex mux;

	//shader Program 
	QGLShaderProgram program;

	//shader in yuv Variable address 
	GLuint unis[3] = {
     0 };
	//openg Of  texture Address 
	GLuint texs[3] = {
     0 };

	// Material memory space 
	unsigned char* datas[3] = {
     0 };

	int width = 0;
	int height = 0;
};

xvideowidget.cpp And actual combat 14 The difference is the actual combat 14 The width and height of the lieutenant general are determined in advance , Here, the width and height are set according to the transmitted data , And provides a new interface , The purpose is to set the width and height , Allocate material memory space , Set the zoom in / out method :

void xvideowidget::Init(int width, int height)
{
    
	mux.lock();
	this->width = width;
	this->height = height;
	delete datas[0];
	delete datas[1];
	delete datas[2];
	/// Allocate material memory space 
	datas[0] = new unsigned char[width * height];		//Y
	datas[1] = new unsigned char[width * height / 4];	//U
	datas[2] = new unsigned char[width * height / 4];	//V


	if (texs[0])
	{
    
		glDeleteTextures(3, texs);
	}
	// Create materials 
	glGenTextures(3, texs);

	//Y
	glBindTexture(GL_TEXTURE_2D, texs[0]);
	// Zoom in and filter , linear interpolation  GL_NEAREST( Efficient , But mosaic is serious )
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	// Create material graphics card space 
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, 0);

	//U
	glBindTexture(GL_TEXTURE_2D, texs[1]);
	// Zoom in and filter , linear interpolation 
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	// Create material graphics card space 
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width / 2, height / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);

	//V
	glBindTexture(GL_TEXTURE_2D, texs[2]);
	// Zoom in and filter , linear interpolation 
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	// Create material graphics card space 
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width / 2, height / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);

	mux.unlock();
}

Because creating materials also uses height and width , So put it into this interface
Creating material graphics card space requires tex, Deleting will also delete tex, In order to prevent half of the application from being deleted, resulting in program downtime , Put a lock on it , Used by other functions data And tex And lock the , about repaint() This kind of frequent , Pay attention to the amount of code locked , Will affect performance , about init It doesn't matter if it only happens once

Reading and drawing will block , Therefore use QThread:

class testtread :public QThread
{
    
public:
    void init()
    {
    
        const char* path = "E:\\ffmpeg\\test.mp4";
        const char* url = "rtsp://27.22.78.122:8554/1";
        cout << "demux.Open = " << demux.Open(path) << endl;
        cout << "vdecode.open()" << vdecode.open(demux.CopyVPara()) << endl;
        cout << "adecode.open()" << adecode.open(demux.CopyAPara()) << endl;
    }
    void run()
    {
    
        for (;;)
        {
    
            AVPacket* pkt = demux.readfz();
            if (demux.isvideo(pkt) == true)
            {
    

                vdecode.send(pkt);
                AVFrame* frame = vdecode.receive();
                //cout << " Video decoding " <<frame<< endl;
                video->Repaint(frame);
                Sleep(40);
            }
            else
            {
    
                //adecode.send(pkt);
                //AVFrame* frame = adecode.receive();

                //cout << " Audio decoding " <<frame<< endl;
            }
            if (!pkt)break;
        }
    }
    xdemux demux;
    xvideowidget* video;
protected:
    
    xdecode vdecode;
    xdecode adecode;
    
};

Because after the main thread exits video Have been deleted , However, the thread is still , So there will be some small problems , We'll deal with it later
main function :

int main(int argc, char *argv[])
{
    
    testtread tt;
    tt.init();

    QApplication a(argc, argv);
    Xplay2 w;
    w.show();

    w.ui.openGLWidget->Init(tt.demux.width, tt.demux.height);

    tt.video = w.ui.openGLWidget;
    tt.start();
    return a.exec();
}

1. Instantiate a thread ,
Instantiating a thread also instantiates demux,vdecode,adecode,xvideowidget*, And transmit the unpacked video information to vdecode, Audio information is transmitted to adecode

2. Open one QT The window of

3. Transmit the width and height information obtained by unpacking to ui The initialization function of the control added in the window , Give Way QT A video window with the same width and height as our media file can be displayed on the window , It just can't display the picture
tt Of demux And video,w Of ui Are all out of class accesses , So let's open these members to public

4. Let the point in the thread xvideowidget The pointer to the control we added , call start That is, the of the calling thread run, stay run Will be decoded in packet issue openg Draw and display on the control

void xvideowidget::Repaint(AVFrame* frame)
{
    
	if (!frame)
	{
    
		qDebug() << "show failed1" ;
		return;
	}
	mux.lock();
	// Fault tolerance , Make sure the dimensions are correct 
	if (!datas[0] || width * height == 0 || frame->width != this->width || frame->height != this->height)
	{
    
		av_frame_free(&frame);
		mux.unlock();
		qDebug() << "show failed2";
		return;
	}
	memcpy(datas[0], frame->data[0], width * height);
	memcpy(datas[1], frame->data[1], width * height / 4);
	memcpy(datas[2], frame->data[2], width * height / 4);
	// Row alignment problem 
	mux.unlock();

	// Refresh the display 
	update();
	qDebug()<< "repaint" ;
}

The operation is as follows :
 Insert picture description here

原网站

版权声明
本文为[Sister Suo]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/03/202203010513446757.html