跳到主要内容

3.4.3 JDK API 说明

1.数据类型定义(data_type)

1.1 枚举类型: media_type

设备媒体类型枚举:

含义
MEDIA_TYPE_CANT_STAT无法获取设备状态
MEDIA_TYPE_UNKNOWN未知
MEDIA_TYPE_VIDEO视频
MEDIA_TYPE_VBIVBI(垂直消隐)
MEDIA_TYPE_RADIO广播
MEDIA_TYPE_SDRSDR(软件定义无线电)
MEDIA_TYPE_TOUCH触摸输入
MEDIA_TYPE_SUBDEV子设备
MEDIA_TYPE_DVB_FRONTEND数字电视前端
MEDIA_TYPE_DVB_DEMUX数字电视解复用
MEDIA_TYPE_DVB_DVR数字电视录像
MEDIA_TYPE_DVB_NET数字电视网络
MEDIA_TYPE_DTV_CA数字电视条件访问
MEDIA_TYPE_MEDIA媒体设备

1.2 枚举类型: codec_type

表示当前设备或上下文是否为编码或解码:

含义
NOT_CODEC非编解码
CODEC_DEC解码
CODEC_ENC编码

1.3 结构体:v4l2_ctx

V4L2 捕获及编码上下文结构体定义:

struct v4l2_ctx {
int fd; // 设备文件句柄
unsigned int width; // 视频宽度
unsigned int height; // 视频高度
unsigned int pixelformat; // 输入像素格式
unsigned int out_pixelformat; // 输出像素格式
int nplanes; // 输入平面数
int out_nplanes; // 输出平面数
struct buffer* cap_buffers; // 捕获缓冲区数组
struct buffer* out_buffers; // 输出缓冲区数组
__u32 bytesperline[VIDEO_MAX_PLANES]; // 各输入平面行字节数
__u32 out_bytesperline[VIDEO_MAX_PLANES]; // 各输出平面行字节数
FILE* file[2]; // 输入/输出文件指针
int verbose; // 日志详细等级
enum codec_type ctype; // 编码/解码类型
};

2.核心接口

2.1JdkFrame:图像帧封装类

class JdkFrame {
public:
JdkFrame(int dma_fd_, size_t size_, int w, int h);
~JdkFrame();

// 将 DMA 缓冲区映射到 CPU 内存并返回指针
unsigned char* toHost() const;
// 克隆返回数据副本
std::vector<unsigned char> Clone() const;
// 保存为 NV12 格式 .yuv 文件
bool saveToFile(const std::string& filename) const;
// 从文件加载数据(与 saveToFile 配对使用)
bool loadFromFile(const std::string& filename, size_t expected_size);

// 获取底层 DMA FD
int getDMAFd() const;
// 获取缓冲区大小
size_t getSize() const { return size_; }
// 获取分辨率
int getWidth() const { return width_; }
int getHeight() const { return height_; }

// 将原始 NALU 数据拷贝到内部 buffer(如编码后写入)
// offset:目标缓冲区偏移
int MemCopy(const uint8_t* nalu, int nalu_size, int offset = 0);

private:
size_t size_; // 缓冲区总大小
int width_;
int height_;
JdkDma dma_; // DMA 同步辅助
std::shared_ptr<JdkDmaBuffer> data; // 底层 DMA buffer
};

using JdkFramePtr = std::shared_ptr<JdkFrame>;

2.2JdkDmaJdkDmaBuffer:DMA 内存及异步传输类

class JdkDmaBuffer {
public:
// 构造并分配 DMA 缓冲区
explicit JdkDmaBuffer(size_t size);
~JdkDmaBuffer();

// 返回映射后的用户空间地址
void* data() const;
// 整块填充值
void fill(uint8_t val);

// 获取物理地址(需先调用 map_phys_addr)
void map_phys_addr();

// 公开字段(只读)
size_t m_size;
uint64_t m_phys;
};

class JdkDma {
public:
// 通过 DMA 引擎异步复制数据
int Asyn(const JdkDmaBuffer& dst, const JdkDmaBuffer& src, size_t size);
// FD 间的 DMA 复制
int Asyn(const int& dst_fd, const int& src_fd, size_t size);
};

2.3JdkCamera:摄像头图像采集接口

class JdkCamera {
public:
/**
* 创建并打开 V4L2 设备
* @param device 设备路径 (e.g. "/dev/video0")
* @param width 期望采集宽度
* @param height 期望采集高度
* @param pixfmt V4L2 像素格式 (e.g. V4L2_PIX_FMT_NV12)
* @param req_count 请求的缓冲区数量 (默认 4)
* @return 成功返回 JdkCameraPtr,否则返回 nullptr
*/
static std::shared_ptr<JdkCamera> create(const std::string& device,
int width,
int height,
__u32 pixfmt,
int req_count = 4);
/** 获取一帧图像(阻塞) */
JdkFramePtr getFrame();

~JdkCamera();

private:
explicit JdkCamera(const std::string& device);
class Impl;
std::unique_ptr<Impl> impl_;
};
using JdkCameraPtr = std::shared_ptr<JdkCamera>;

2.4JdkDecoder:硬件视频解码器

class JdkDecoder {
public:
/**
* 初始化硬件解码器
* @param width 输出分辨率宽度
* @param height 输出分辨率高度
* @param payload 输入码流类型 (见 MppCodingType)
* @param Format 输出像素格式 (默认 NV12)
*/
JdkDecoder(int width, int height,
MppCodingType payload,
MppPixelFormat Format = PIXEL_FORMAT_NV12);
~JdkDecoder();

/** 解码,从已封装帧中解码 */
std::shared_ptr<JdkFrame> Decode(std::shared_ptr<JdkFrame> frame);
/** 解码,从裸 NALU 数据解码 */
std::shared_ptr<JdkFrame> Decode(const uint8_t* nalu, int nalu_size);

private:
int width_;
int height_;
MppCodingType payload_;
int format_;
int channel_id_;
MppVdecCtx* pVdecCtx = nullptr;
};

2.5JdkEncoder:硬件视频编码器

class JdkEncoder {
public:
/**
* 初始化硬件编码器
* @param width 输入分辨率宽度
* @param height 输入分辨率高度
* @param payload 输出码流类型 (见 MppCodingType)
* @param Format 输入像素格式 (默认 NV12)
*/
JdkEncoder(int width, int height,
MppCodingType payload,
MppPixelFormat Format = PIXEL_FORMAT_NV12);
~JdkEncoder();

/** 编码,将原始帧编码为压缩码流 */
std::shared_ptr<JdkFrame> Encode(std::shared_ptr<JdkFrame> frame);

private:
int width_;
int height_;
MppCodingType payload_;
int format_;
int encoder_id_ = 0;
MppVencCtx* pVencCtx = nullptr;
};

2.6JdkDrm:基于 DRM 的视频输出接口

/** 支持的像素格式 */
enum class PixelFmt : uint32_t {
NV12 = DRM_FORMAT_NV12
};

class JdkDrm {
public:
/**
* 打开 DRM 设备并初始化
* @param width 显示宽度
* @param height 显示高度
* @param stride 行跨度 (bytes)
* @param fmt 像素格式
* @param device DRM 设备路径 (默认 "/dev/dri/card0")
*/
JdkDrm(int width, int height, int stride,
PixelFmt fmt = PixelFmt::NV12,
const char* device = "/dev/dri/card0");
~JdkDrm();

/** 发送一帧到 DRM 屏幕 */
int sendFrame(std::shared_ptr<JdkFrame> frame);
/** 销毁指定的 framebuffer */
void destroyFb(uint32_t fb, uint32_t handle);
/** 打开 DRM 设备 */
int openCard(const char* dev);
/** 自动选取合适的 connector/crtc/plane */
int pickConnectorCrtcPlane();
/** 导入 DMA FD 为 DRM framebuffer */
int importFb(int dma_fd, uint32_t& fb_id, uint32_t& handle);

private:
struct LastFB {
uint32_t fb_id;
uint32_t handle;
int dma_fd;
} last_;
};

2.7JdkV2D:图像处理(缩放、格式转换、图像叠加)

/** 支持的目标像素格式(枚举值请参考完整头文件) */
enum V2DFormat {
// 例如: V2D_NV12, V2D_RGB888, ……
};

/** 矩形区域 */
struct V2DRect {
int x, y, width, height;
};

class JdkV2D {
public:
JdkV2D() = default;
~JdkV2D() = default;

/** 格式转换 */
JdkFramePtr convert_format(const JdkFramePtr& input,
V2DFormat out_format);
/** 缩放 */
JdkFramePtr resize(const JdkFramePtr& input,
int out_width, int out_height);
/** 同时缩放并格式转换 */
JdkFramePtr resize_and_convert(const JdkFramePtr& input,
int out_width, int out_height,
V2DFormat out_format);
/** 填充矩形区域 */
bool fill_rect(const JdkFramePtr& image,
const V2DRect& rect,
uint32_t rgba_color);
/** 绘制矩形边框 */
bool draw_rect(const JdkFramePtr& image,
const V2DRect& rect,
uint32_t rgba_color,
int thickness = 2);
/** 绘制多矩形 */
bool draw_rects(const JdkFramePtr& image,
const std::vector<V2DRect>& rects,
uint32_t rgba_color,
int thickness = 2);
/** 图像融合(bottom 上叠加 top) */
JdkFramePtr blend(const JdkFramePtr& bottom,
const JdkFramePtr& top);
};

2.8JdkVo:VO(Video Output)显示接口

class JdkVo {
public:
/**
* 初始化 Vo 输出
* @param width 输出宽度
* @param height 输出高度
* @param Format 像素格式 (默认 NV12)
*/
JdkVo(int width, int height,
MppPixelFormat Format = PIXEL_FORMAT_NV12);
~JdkVo();

/** 发送一帧到 Vo 硬件输出 */
int sendFrame(std::shared_ptr<JdkFrame> frame);

private:
int width_;
int height_;
MppPixelFormat format_;
int channel_id_;
MppVoCtx* pVoCtx = nullptr;
};
  • 附录:开发提示

    • 请根据平台实际情况,确认是否支持 DRM/VO/V4L2 模块。
    • 所有资源接口均使用 std::shared_ptr 进行内存自动管理。
    • 推荐使用 RAII 模式管理解码器、编码器等模块资源。
    • 实际使用中应对返回值进行错误处理,避免野指针或内存泄漏。