---
title: JPEGD图片解码
description: "JPEGD（JPEG Decoder）负责完成图像解码功能，将.jpg、.jpeg、.JPG、.JPEG图片解码成YUV格式图片。关于JPEGD功能的详细介绍及约束请参见JPEGD功能及约束说明。"
url: https://www.hiascend.com/document/detail/zh/Atlas200IDKA2DeveloperKit/latest/Application%20Development%20Guide/aadgc/aclcppdevg_000039.html
sourcePath: /source/zh/Atlas200IDKA2DeveloperKit/23.0.RC2/Application Development Guide/aadgc/aclcppdevg_000039.html
indexId: 19f8e2da96e584c47812193c2dd1191c07469ad5a57c528ba78fcb1f9de609aa104
---
# JPEGD图片解码

JPEGD（JPEG Decoder）负责完成图像解码功能，将.jpg、.jpeg、.JPG、.JPEG图片解码成YUV格式图片。关于JPEGD功能的详细介绍及约束请参见JPEGD功能及约束说明。

本节介绍JPEGD图片解码的接口调用流程，同时配合示例代码辅助理解该接口调用流程。

#### 接口调用流程

开发应用时，如果涉及对JPEG图片的解码，则应用程序中必须包含解码的代码逻辑，关于图片解码的接口调用流程，请先参见AscendCL接口调用流程了解整体流程，再查看本节中的流程说明。

图1 接口调用的流程

当前系统支持解码JPEG图片，关键接口的说明如下：

1. 调用  hi_mpi_sys_init
接口进行媒体数据处理系统初始化。
2. 调用  hi_mpi_vdec_create_chn
接口创建通道。
3. 调用  hi_mpi_dvpp_malloc
接口申请Device上的内存，存放输入或输出数据。
  Atlas 200/500 A2推理产品上，还支持使用aclrtMalloc接口申请内存。

  调用hi_mpi_dvpp_malloc接口申请的内存为媒体数据处理的专用内存，但专用内存的地址空间有限，若关注内存规划或内存资源有限时，建议调用aclrtMalloc接口申请内存。

4. 解码前，需调用  hi_mpi_vdec_start_recv_stream
接口通知解码器启动接收码流，再调用  hi_mpi_vdec_send_stream
接口发送解码码流，  hi_mpi_vdec_send_stream
接口是异步接口，调用该接口仅表示任务下发成功，还需要调  hi_mpi_vdec_get_frame
接口获取解码结果数据，成功获取解码数据后，可以调用  hi_mpi_vdec_release_frame
接口释放帧相关的资源。解码结束后，需调用  hi_mpi_vdec_stop_recv_stream
接口通知解码器停止接收码流。
5. 调用  hi_mpi_dvpp_free
接口释放输入、输出内存。
  Atlas 200/500 A2推理产品上，若使用aclrtMalloc接口申请内存，则需使用aclrtFree接口释放内存。

6. 调用  hi_mpi_vdec_destroy_chn
接口销毁通道。
7. 调用  hi_mpi_sys_exit
接口进行媒体数据处理系统去初始化。


#### 示例代码

调用接口后，需增加异常处理的分支，并记录报错日志、提示日志，此处不一一列举。以下是关键步骤的代码示例，不可以直接拷贝编译运行，仅供参考。

```
// 1.AscendCL初始化
aclRet = aclInit(nullptr);

// 2.运行管理资源申请（依次申请Device、Context）
aclrtContext g_context;
aclRet = aclrtSetDevice(0);
aclRet = aclrtCreateContext(&g_context, 0);
// 获取软件栈的运行模式，不同运行模式影响后续的接口调用流程（例如是否进行数据传输等）
aclrtRunMode runMode;
aclError aclRet = aclrtGetRunMode(&runMode);

// 3.初始化媒体数据处理系统
int32_t ret = hi_mpi_sys_init();

// 4.创建通道
hi_vdec_chn chnId;
hi_vdec_chn_attr chnAttr;

chnAttr.type = HI_PT_JPEG;
chnAttr.mode = HI_VDEC_SEND_MODE_FRAME;
chnAttr.pic_width = 1920;
chnAttr.pic_height = 1080;
chnAttr.stream_buf_size = 1920 * 1080;

ret = hi_mpi_vdec_create_chn(chnId, &chnAttr);

// 5.设置通道属性
hi_vdec_chn_param chnParam;
ret = hi_mpi_vdec_get_chn_param(chnId, &chnParam);

chnParam.pic_param.pixel_format = HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420;
chnParam.pic_param.alpha = 255;
chnParam.display_frame_num = 0;
ret = hi_mpi_vdec_set_chn_param(chnId, &chnParam);

// 6.解码器启动接收码流
ret = hi_mpi_vdec_start_recv_stream(chnId);

// 7.发送码流
// 7.1 申请输入内存
uint8_t* inputAddr = nullptr;
// inputsize表示输入图片占用的内存大小，此处以1024 Byte为例，用户需根据实际情况计算内存大小
int32_t inputSize = 1024;
ret = hi_mpi_dvpp_malloc(0, &inputAddr, inputSize);

if (runMode == ACL_HOST) {
    void* hostInputAddr = nullptr;
    
    aclRet = aclrtMallocHost(&hostInputAddr, inputSize);
    // 将输入图片读入内存中，该自定义函数ReadStreamFile由用户实现
    ReadStreamFile(fileName, hostInputAddr, inputSize);
    // 数据传输
    aclRet = aclrtMemcpy(inputAddr, inputSize, hostInputAddr, inputSize, ACL_MEMCPY_HOST_TO_DEVICE);    
} else {
    // 将输入图片读入内存中，该自定义函数ReadStreamFile由用户实现
    ReadStreamFile(fileName, inputAddr, inputSize);
}

// 7.2 构造存放输入图片信息的结构体
hi_vdec_stream stStream{};
hi_img_info stImgInfo{};
stStream.pts = 0;
if (g_runMode == ACL_HOST) {
    stStream.addr  = (uint8_t *)hostInputAddr;
} else {
    stStream.addr  = (uint8_t *)inputAddr;
}
stStream.len = inputSize;
stStream.end_of_frame = HI_TRUE;
stStream.end_of_stream = HI_FALSE;
stStream.need_display  = HI_TRUE;

ret = hi_mpi_dvpp_get_image_info(HI_PT_JPEG, &stStream, &stImgInfo);
if (g_runMode == ACL_HOST) {
    // 如果不使用Host上的数据，需及时释放
   aclrtFreeHost(hostInputAddr);
    hostInputAddr = nullptr;
}
stStream.addr = (uint8_t *)inputAddr;

// 7.3 构造存放输出图片信息的结构体，并申请输出内存
hi_vdec_pic_info outPicInfo{};
void *outBuffer = nullptr;
outPicInfo.width  = stImgInfo.width;
outPicInfo.height = stImgInfo.height;
outPicInfo.width_stride  = stImgInfo.width_stride;
outPicInfo.height_stride = stImgInfo.height_stride;
outPicInfo.buffer_size   = stImgInfo.img_buf_size;
outPicInfo.pixel_format  = HI_PIXEL_FORMAT_UNKNOWN;

ret = hi_mpi_dvpp_malloc(0, &outBuffer, outPicInfo.buffer_size);

outPicInfo.vir_addr = (uint64_t)outBuffer;

// 7.4 发送需解码的输入图片
ret = hi_mpi_vdec_send_stream(chnId, &stStream, &outPicInfo, 0);

// 8.接收解码结果
// 8.1 获取解码结果
hi_video_frame_info frame;    
hi_vdec_stream stream;
hi_vdec_supplement_info stSupplement;
ret = hi_mpi_vdec_get_frame(chnId, &frame, &stSupplement, &stream, 0);
if (ret == HI_SUCCESS) {
   decResult = frame.v_frame.frame_flag;
   if (decResult == 0) { // 0: Decode success
       printf("[%s][%d] Chn %u GetFrame Success, Decode Success \n",__FUNCTION__, __LINE__, chnId);
   } else { // Decode fail
       printf("[%s][%d] Chn %u GetFrame Success, Decode Fail \n",__FUNCTION__, __LINE__, chnId);
   }
}

if (g_runMode == ACL_HOST) {
    void* hostOutputAddr = nullptr;
    aclRet = aclrtMallocHost(&hostOutputAddr, outputSize);
    aclRet = aclrtMemcpy(hostOutputAddr, outputSize, frame.v_frame.virt_addr[0], outputSize, ACL_MEMCPY_DEVICE_TO_HOST);
    // ......
    // 数据使用完成后，及时释放不使用的内存
    aclrtFreeHost(hostOutputAddr);
    hostOutputAddr = nullptr;
} else {
    // 可以直接使用JPEGD的输出图片数据，在frame.v_frame.virt_addr[0]指向的内存中
    // ......
}


// 8.3 释放输入、输出内存
ret = hi_mpi_dvpp_free(frame.v_frame.virt_addr[0]);
ret = hi_mpi_dvpp_free(stream.addr);

// 8.4 释放资源
ret = hi_mpi_vdec_release_frame(chnId, &frame);

// 9.解码器停止接收码流
ret = hi_mpi_vdec_stop_recv_stream(chnId);

// 10.销毁通道
ret = hi_mpi_vdec_destroy_chn(chnId);

// 11. 媒体数据处理系统去初始化
ret = hi_mpi_sys_exit();

// 12. 释放运行管理资源（依次释放Context、Device）
aclRet = aclrtDestroyContext(g_context);
aclRet = aclrtResetDevice(0);

// 13.AscendCL去初始化
aclRet = aclFinalize();

// ....
```
