#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <gbm.h>
#include <png.h>
#include <EGL/egl.h>
#include <GLES2/gl2.h>
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#include <stdio.h>
#include <stdlib.h>
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#include <stdio.h>
#include <stdlib.h>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
// 模拟 DMA 缓冲区(实际应使用 Rockchip 的 DRM/DMA-BUF 接口)
typedef struct {
int width;
int height;
uint8_t *nv12_data;
} DMABuffer;
// EGL 配置
EGLDisplay eglDisplay;
EGLContext eglContext;
EGLSurface eglSurface;
// 初始化 EGL
int init_egl(int width, int height) {
eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (eglDisplay == EGL_NO_DISPLAY) return -1;
EGLint major, minor;
if (!eglInitialize(eglDisplay, &major, &minor)) return -1;
EGLint configAttrs[] = {
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_NONE
};
EGLConfig eglConfig;
EGLint numConfigs;
if (!eglChooseConfig(eglDisplay, configAttrs, &eglConfig, 1, &numConfigs)) return -1;
EGLint surfaceAttrs[] = { EGL_WIDTH, width, EGL_HEIGHT, height, EGL_NONE };
eglSurface = eglCreatePbufferSurface(eglDisplay, eglConfig, surfaceAttrs);
if (eglSurface == EGL_NO_SURFACE) return -1;
EGLint contextAttrs[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE };
eglContext = eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, contextAttrs);
if (eglContext == EGL_NO_CONTEXT) return -1;
if (!eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) return -1;
return 0;
}
GLuint y_texture, uv_texture;
void load_nv12_texture(const DMABuffer &buf) {
// Y 平面
glBindTexture(GL_TEXTURE_2D, y_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, buf.width, buf.height, 0, GL_RED, GL_UNSIGNED_BYTE, buf.nv12_data);
// UV 平面
const uint8_t *uv_data = buf.nv12_data + buf.width * buf.height;
glBindTexture(GL_TEXTURE_2D, uv_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG8, buf.width / 2, buf.height / 2, 0, GL_RG, GL_UNSIGNED_BYTE, uv_data);
}
GLuint compile_shader(GLenum type, const char *source) {
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &source, NULL);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (!status) {
char log[1024];
glGetShaderInfoLog(shader, 1024, NULL, log);
printf("Shader compile error: %s\n", log);
glDeleteShader(shader);
return 0;
}
return shader;
}
GLuint create_program(const char *vs_source, const char *fs_source) {
GLuint vs = compile_shader(GL_VERTEX_SHADER, vs_source);
GLuint fs = compile_shader(GL_FRAGMENT_SHADER, fs_source);
GLuint program = glCreateProgram();
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
GLint status;
glGetProgramiv(program, GL_LINK_STATUS, &status);
if (!status) {
char log[1024];
glGetProgramInfoLog(program, 1024, NULL, log);
printf("Program link error: %s\n", log);
glDeleteProgram(program);
return 0;
}
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
const char *vertex_shader_source = R"(
#version 300 es
layout(location = 0) in vec2 position;
layout(location = 1) in vec2 texCoord;
out vec2 v_texCoord;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
v_texCoord = texCoord;
}
)";
const char *fragment_shader_source = R"(
#version 300 es
precision mediump float;
in vec2 v_texCoord;
out vec4 fragColor;
uniform sampler2D y_texture;
uniform sampler2D uv_texture;
uniform vec2 texScale; // (target_width / src_width, target_height / src_height)
void main() {
// 缩放后的纹理坐标
vec2 scaledCoord = v_texCoord * texScale;
// 采样 Y 平面
float y = texture(y_texture, scaledCoord).r;
// 采样 UV 平面(NV12 的 UV 是 2x2 下采样的)
vec2 uvCoord = scaledCoord * 0.5;
vec2 uv = texture(uv_texture, uvCoord).rg;
// 输出 NV12(实际需要分开处理,此处仅作示例)
// 实际应用中,Y 和 UV 需要分别渲染到两个 FBO
fragColor = vec4(y, uv, 0.0, 1.0); // 伪代码,实际需分开输出
}
)";
// 模拟 DMA 输入队列(实际应使用 Rockchip 的 V4L2 或 DRM 接口)
std::queue<DMABuffer> dma_input_queue;
std::mutex dma_mutex;
std::condition_variable dma_cv;
// 模拟 DMA 数据生成线程(实际应替换为摄像头采集)
void dma_producer_thread() {
while (true) {
DMABuffer buf;
buf.width = 1920;
buf.height = 1080;
buf.nv12_data = (uint8_t *)malloc(buf.width * buf.height * 3 / 2);
// ... 填充测试数据(实际应从摄像头读取) ...
{
std::lock_guard<std::mutex> lock(dma_mutex);
dma_input_queue.push(buf);
dma_cv.notify_one();
}
std::this_thread::sleep_for(std::chrono::milliseconds(33)); // ~30FPS
}
}
typedef struct {
int width;
int height;
uint8_t *y_data; // Y 平面
uint8_t *uv_data; // UV 平面
} ScaledFrame;
std::queue<ScaledFrame> output_queue;
std::mutex output_mutex;
std::condition_variable output_cv;
GLuint fbo_y, fbo_uv;
GLuint output_y, output_uv;
void setup_fbo(int width, int height) {
// Y 平面 FBO
glGenFramebuffers(1, &fbo_y);
glBindFramebuffer(GL_FRAMEBUFFER, fbo_y);
glGenTextures(1, &output_y);
glBindTexture(GL_TEXTURE_2D, output_y);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, output_y, 0);
// UV 平面 FBO
glGenFramebuffers(1, &fbo_uv);
glBindFramebuffer(GL_FRAMEBUFFER, fbo_uv);
glGenTextures(1, &output_uv);
glBindTexture(GL_TEXTURE_2D, output_uv);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG8, width / 2, height / 2, 0, GL_RG, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, output_uv, 0);
}
void render_nv12(GLuint program, int src_width, int src_height, int target_width, int target_height) {
glViewport(0, 0, target_width, target_height);
// 渲染 Y 平面
glBindFramebuffer(GL_FRAMEBUFFER, fbo_y);
glUseProgram(program);
glUniform2f(glGetUniformLocation(program, "texScale"),
(float)target_width / src_width,
(float)target_height / src_height);
glUniform1i(glGetUniformLocation(program, "y_texture"), 0);
glUniform1i(glGetUniformLocation(program, "uv_texture"), 1);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, y_texture);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, uv_texture);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// 渲染 UV 平面
glBindFramebuffer(GL_FRAMEBUFFER, fbo_uv);
glViewport(0, 0, target_width / 2, target_height / 2);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
void read_nv12_data(int width, int height, ScaledFrame &frame) {
frame.y_data = (uint8_t *)malloc(width * height);
frame.uv_data = (uint8_t *)malloc(width * height / 2);
frame.width = width;
frame.height = height;
// 读取 Y 平面
glBindFramebuffer(GL_FRAMEBUFFER, fbo_y);
glReadPixels(0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE, frame.y_data);
// 读取 UV 平面
glBindFramebuffer(GL_FRAMEBUFFER, fbo_uv);
glReadPixels(0, 0, width / 2, height / 2, GL_RG, GL_UNSIGNED_BYTE, frame.uv_data);
}
void processing_loop(int target_width, int target_height) {
GLuint program = create_program(vertex_shader_source, fragment_shader_source);
setup_fbo(target_width, target_height);
while (true) {
DMABuffer input_buf;
{
std::unique_lock<std::mutex> lock(dma_mutex);
dma_cv.wait(lock, [] { return !dma_input_queue.empty(); });
input_buf = dma_input_queue.front();
dma_input_queue.pop();
}
// 加载纹理
load_nv12_texture(input_buf);
// 渲染缩放
render_nv12(program, input_buf.width, input_buf.height, target_width, target_height);
// 读取缩放后的数据
ScaledFrame output_frame;
read_nv12_data(target_width, target_height, output_frame);
// 存入输出队列
{
std::lock_guard<std::mutex> lock(output_mutex);
output_queue.push(output_frame);
output_cv.notify_one();
}
// 释放输入缓冲区
free(input_buf.nv12_data);
}
}
void consumer_thread() {
while (true) {
ScaledFrame frame;
{
std::unique_lock<std::mutex> lock(output_mutex);
output_cv.wait(lock, [] { return !output_queue.empty(); });
frame = output_queue.front();
output_queue.pop();
}
// 合并为 NV12(可选)
uint8_t *nv12_out = (uint8_t *)malloc(frame.width * frame.height * 3 / 2);
memcpy(nv12_out, frame.y_data, frame.width * frame.height);
memcpy(nv12_out + frame.width * frame.height, frame.uv_data, frame.width * frame.height / 2);
// ... 处理 nv12_out(如编码、显示或写入文件) ...
// 释放内存
free(frame.y_data);
free(frame.uv_data);
free(nv12_out);
}
}
int main() {
int target_width = 1280, target_height = 720;
// 初始化 EGL + GLES3
if (init_egl(target_width, target_height) < 0) {
printf("EGL init failed!\n");
return -1;
}
// 初始化纹理
glGenTextures(1, &y_texture);
glGenTextures(1, &uv_texture);
// 启动线程
std::thread producer(dma_producer_thread);
std::thread processor(processing_loop, target_width, target_height);
std::thread consumer(consumer_thread);
producer.join();
processor.join();
consumer.join();
eglTerminate(eglDisplay);
return 0;
} 完善上述代码,并解释