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