1 概述 HwJpeg 库用于支持 Rockchip 平台 JPEG 硬编解码,是平台 MPP(Media Process Platform) 库 JPEG 编解码逻辑的封装。其中,MpiJpegEncoder 类封装了硬编码相关操作,MpiJpegDecoder 类封装了硬解码相关操作,用于支持图片或 MJPEG 码流解码。 工程包含主要目录: - mpi:HwJpeg 库实现代码 - test:HwJpeg 测试实例 > 工程代码使用 mk 文件组织,在 Android SDK 环境下直接编译使用即可。 2 MpiJpegDecoder MpiJpegDecoder 类是平台 JPEG 硬解码的封装,支持输入 JPG 图片及 MJPEG 码流,同时支持同步及 异步解码方式。 - decodePacket(char* data, size_t size, OutputFrame_t *aframeOut); - decodeFile(const char *input_file, const char *output_file); decodePacket & decodeFile 为同步解码方式,同步解码方式使用简单,阻塞等待解码输出, OutputFrame_t 为解码输出封装,包含输出帧宽、高、物理地址、虚拟地址等信息。 - decode_sendpacket(char* input_buf, size_t buf_len); - decode_getoutframe(OutputFrame_t *aframeOut); decode_sendpacket & decode_getoutframe 用于配合实现异步解码输出,应用端处理开启两个线程,一 个线程送输入 decode_sendpacket,另一个线程异步取输出 decode_getoutframe。 **Note:** 1. HwJpeg 解码默认输出 RAW NV12 数据 2. 平台硬解码器只处理对齐过的 buffer,因此 MpiJpegDecoder 输出的 YUV buffer 经过 16 位对齐。 如果原始宽高非 16 位对齐,直接显示可能出现底部绿边等问题,MpiJpegDecoder 实现代码中 OUTPUT_CROP 宏用于实现 OutFrame 的裁剪操作,可手动开启,也可以外部获取 OutFrame 句柄再进行相应的裁剪。 3. OutFrame buffer 在解码库内部循环使用,在解码显示完成之后使用 deinitOutputFrame 释放内存 解码使用示例: ``` MpiJpegDecoder decoder; MpiJpegDecoder::OutputFrame_t frameOut; ret = decoder.prepareDecoder(); if (!ret) { ALOGE("failed to prepare JPEG decoder"); goto DECODE_OUT; } memset(&frameOut, 0, sizeof(MpiJpegDecoder::OutputFrame_t)); ret = decoder.decodePacket(buf, size, &frameOut); if (!ret) { ALOGE("failed to decode packet"); goto DECODE_OUT; } decoder.deinitOutputFrame(&frameOut); decoder.flushBuffer(); ``` 3 MpiJpegEncoder MpiJpegEncoder 类是平台 JPEG 硬编码的封装,目前主要有三类接口提供: - encodeFrame(char *data, OutputPacket_t *aPktOut); - encodeFile(const char *input_file, const char *output_file); encodeFrame & encodeFile 为同步阻塞编码方式,OutputPacket_t 为编码输出封装, 包含输出数据的内存地址信息。 - encode(EncInInfo *inInfo, OutputPacket_t *outPkt); encode 输入数据类型为文件 fd,是为 cameraHal 设计的一套编码方式,输出 JPEG 图片 包含编码缩略图、APP1 EXIF 头信息等。 **Note:** 1. OutputPacket_t buffer 在编码库内部循环使用,在编码处理完成之后使用 deinitOutputPacket 释放内存 编码使用示例: ``` MpiJpegEncoder encoder; MpiJpegEncoder::OutputPacket_t pktOut; ret = encoder.prepareEncoder(); if (!ret) { ALOGE("failed to prepare JPEG encoder"); goto ENCODE_OUT; } ret = encoder.updateEncodeCfg(720 /*width*/, 1080 /*height*/, MpiJpegEncoder::INPUT_FMT_YUV420SP); if (!ret) { ALOGE("failed to update encode config"); goto ENCODE_OUT; } memset(&pktOut, 0, sizeof(MpiJpegEncoder::OutputPacket_t)); ret = encoder.encodeFrame(buf, &pktOut); if (!ret) { ALOGE("failed to encode packet"); goto ENCODE_OUT; } /* TODO - Get diaplay for the PacketOut. * - Pakcet address: pktOut.data * - Pakcet size: pktOut.size */ /* Output frame buffers within limits, so release frame buffer if one frame has been display successful. */ encoder.deinitOutputPacket(&pktOut); ```