如何在QT中绘制Nvidia Jetson采集的摄像头数据的fd句柄

支持直接绘制采集数据的fd句柄,不需要通过DMA将数据dump到内存中再绘制。
代码参考自Jetson Multimedia API,结合QOpenGLWidget的使用心得。
使用了自行编写的一些辅助类,诸如线程互斥锁TLock_t,需要自行替换。


JetsonViewWidget.h

/*
* Ryan chen 2021
* Contact: 70565912@qq.com
*/
#ifndef JETSON_VIEW_WIDGET_H
#define JETSON_VIEW_WIDGET_H

#include <QtCore>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include "Common.h"
#include <GLES2/gl2ext.h>

class JetsonViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
	Q_OBJECT
public:
	JetsonViewWidget(QWidget* parent = nullptr);
	virtual ~JetsonViewWidget();
	int  Init(int width, int height);
	int  DrawDmaHandle(int dma_fd);
	void Close();
	int  GetWidth() {return m_width;};
	int  GetHeight() {return m_height;};

protected:
	void initializeGL();
	void paintGL();

private:
	int  InitializeShaders(void);
	void CreateShader(GLuint program, GLenum type, const char *source, int size);
	int  CreateTexture();

	int m_width = 0;
	int m_height = 0;
	TLock_t m_lock;
	std::vector<int> m_listDmaFd;
	uint32_t m_textureId = 0;        /**< Holds the GL Texture ID used for rendering. */
	PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = 0;
};
#endif // JETSON_VIEW_WIDGET_H

JetsonViewWidget.cpp

/*
* Ryan chen 2021
* Contact: 70565912@qq.com
*/
#include "JetsonViewWidget.h"
#include <QtGui>
#include <QLayout>
#include <QCloseEvent>
#include <nvbuf_utils.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>

JetsonViewWidget::JetsonViewWidget(QWidget* parent)
: QOpenGLWidget(parent)
{
	QSurfaceFormat format;
	format.setDepthBufferSize(24);
	format.setStencilBufferSize(8);
	format.setVersion(3, 2);
	format.setProfile(QSurfaceFormat::CoreProfile);
	setFormat(format);
}

JetsonViewWidget::~JetsonViewWidget()
{
	Close();
}

int JetsonViewWidget::Init(int width, int height)
{
	m_width = width;
	m_height = height;

	Close();

	if (context() && m_width && m_height)
	{
        makeCurrent();
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

		glViewport(0, 0, m_width, m_height);
        glScissor(0, 0, m_width, m_height);
        if (InitializeShaders() < 0)
        {
        printf("Error while initializing shaders\n");
        return -1;
        }
        CreateTexture();
        doneCurrent();
	}
	return 0;
}

void JetsonViewWidget::Close()
{
	if (context())
	{
        if (m_textureId)
        {
        	makeCurrent();
        	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        	glClear(GL_COLOR_BUFFER_BIT);
        	glDeleteTextures(1, &m_textureId);
        	doneCurrent();
        }
	}
}

int JetsonViewWidget::DrawDmaHandle(int dma_fd)
{
	if (!context())
        return 0;

	if (this->isHidden())
	{
        printf("window is hidden.\n");
        return 0;
	}

	m_lock.Lock();
	m_listDmaFd.push_back(dma_fd);
	m_lock.Unlock();
	QMetaObject::invokeMethod(this, "update");
	return 0;
}

void JetsonViewWidget::initializeGL()
{
	initializeOpenGLFunctions();
	glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress("glEGLImageTargetTexture2DOES");
	if (!glEGLImageTargetTexture2DOES)
        printf("ERROR getting proc addr of glEGLImageTargetTexture2DOES\n");
	Init(m_width, m_height);
}

void JetsonViewWidget::paintGL()
{
	int dma_fd = 0;

	m_lock.Lock();
	if (m_listDmaFd.size())
        dma_fd = m_listDmaFd.back();
	m_listDmaFd.clear();
	m_lock.Unlock();

	if (!dma_fd)
        return;
	if (isHidden())
        return;

	EGLDisplay egl_display = 	eglGetCurrentDisplay();
	if (!egl_display)
        return;

	EGLImageKHR hEglImage;
	int iErr;
	hEglImage = NvEGLImageFromFd(egl_display, dma_fd);
	if (!hEglImage)
	{
        printf("Could not get EglImage from fd. Not rendering\n");
        return;
	}

	makeCurrent();
	glActiveTexture(GL_TEXTURE0);

	glBindTexture(GL_TEXTURE_EXTERNAL_OES, m_textureId);
	glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, hEglImage);
	glDrawArrays(GL_TRIANGLES, 0, 6);
	iErr = glGetError();
	if (iErr != GL_NO_ERROR)
	{
        printf("glDrawArrays arrays failed: %d\n", iErr);
	}
	doneCurrent();

	NvDestroyEGLImage(egl_display, 	hEglImage);
}

void JetsonViewWidget::CreateShader(GLuint program, GLenum type, const char *source, int size)
{
	char log[4096];
	int result = GL_FALSE;
	GLuint shader = glCreateShader(type);
	glShaderSource(shader, 1, &source, &size);
	glCompileShader(shader);
	glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
	if (!result)
	{
        glGetShaderInfoLog(shader, sizeof(log), NULL, log);
        printf("Got Fatal Log as %s\n", log);
	}
	glAttachShader(program, shader);
	if (glGetError() != GL_NO_ERROR)
	{
        printf("Got gl error as %d\n", 	glGetError());
	}
}

int JetsonViewWidget::InitializeShaders(void)
{
	GLuint program;
	int result = GL_FALSE;
	char log[4096];
	uint32_t pos_location = 0;
	// pos_x, pos_y, uv_u, uv_v
	float vertexTexBuf[24] = {
        -1.0f, -1.0f, 0.0f, 1.0f,
        -1.0f,  1.0f, 0.0f, 0.0f,
        1.0f,  1.0f, 1.0f, 0.0f,
        -1.0f, -1.0f, 0.0f, 1.0f,
        1.0f,  1.0f, 1.0f, 0.0f,
        1.0f, -1.0f, 1.0f, 1.0f,
	};
	static const char kVertexShader[] = "varying vec2 interp_tc;\n"
        "attribute vec4 in_pos;\n"
        "void main() { \n"
        "interp_tc = in_pos.zw; \n" "gl_Position = vec4(in_pos.xy, 0, 1); \n" "}\n";
	static const char kFragmentShader[] =
        "#extension GL_OES_EGL_image_external : require\n"
        "precision mediump float;\n" "varying vec2 interp_tc; \n"
        "uniform samplerExternalOES tex; \n" "void main() {\n"
        "gl_FragColor = texture2D(tex, interp_tc);\n" "}\n";

	glEnable(GL_SCISSOR_TEST);
	program = glCreateProgram();
	CreateShader(program, GL_VERTEX_SHADER, kVertexShader,
        sizeof(kVertexShader));
	CreateShader(program, GL_FRAGMENT_SHADER, kFragmentShader,
        sizeof(kFragmentShader));
	glLinkProgram(program);
	if (glGetError() != GL_NO_ERROR)
	{
        printf("Got gl error as %d\n", glGetError());
        return -1;
	}
	glGetProgramiv(program, GL_LINK_STATUS, &result);
	if (!result)
	{
        glGetShaderInfoLog(program, sizeof(log), NULL, log);
        printf("Error while Linking %s\n", log);
        return -1;
	}
	glUseProgram(program);

	if (glGetError() != GL_NO_ERROR)
	{
        printf("Got gl error as %d\n", glGetError());
        return -1;
	}

	GLuint vbo; // Store vetex and tex coords
	glGenBuffers(1, &vbo);
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertexTexBuf), vertexTexBuf, GL_STATIC_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	pos_location = glGetAttribLocation(program, "in_pos");
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glVertexAttribPointer(pos_location, 4, GL_FLOAT, GL_FALSE, 0, (void*)0);
	glEnableVertexAttribArray(pos_location);
	glActiveTexture(GL_TEXTURE0);
	glUniform1i(glGetUniformLocation(program, "texSampler"), 0);
	if (glGetError() != GL_NO_ERROR)
	{
        printf("Got gl error as %d\n", glGetError());
        return -1;
	}
	printf("Shaders intialized\n");
	return 0;
}

int JetsonViewWidget::CreateTexture()
{
	int viewport[4];
	glGetIntegerv(GL_VIEWPORT, viewport);
	glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
	glScissor(viewport[0], viewport[1], viewport[2], viewport[3]);
	glGenTextures(1, &m_textureId);
	glBindTexture(GL_TEXTURE_EXTERNAL_OES, m_textureId);
	return 0;
}
上一篇:ABAP基础篇4 常用的字符串操作语法


下一篇:Global variable in ABAP function group