文档
注册

JPEGD图片解码

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

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

Atlas 200/300/500 推理产品上,当前版本不支持该功能。

Atlas 训练系列产品上,当前版本不支持该功能。

接口调用流程

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

图1 接口调用的流程

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

  1. 调用hi_mpi_sys_init接口进行媒体数据处理系统初始化。
  2. 调用hi_mpi_vdec_create_chn接口创建通道。
  3. 调用hi_mpi_dvpp_malloc接口申请Device上的内存,存放输入或输出数据。

    Atlas 200I/500 A2推理产品上,还支持使用aclrtMalloc接口申请内存。

    Atlas A2训练系列产品/Atlas 800I 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 200I/500 A2推理产品上,若使用aclrtMalloc接口申请内存,则需使用aclrtFree接口释放内存。

    Atlas A2训练系列产品/Atlas 800I A2推理产品上,若使用aclrtMalloc接口申请内存,则需使用aclrtFree接口释放内存。

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

示例代码

您可以从样例介绍中获取完整样例代码。

本节中的示例重点介绍JPEGD图片解码的代码逻辑,AscendCL初始化和去初始化请参见AscendCL初始化,运行管理资源申请与释放请参见运行管理资源申请与释放

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

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// 1.AscendCL初始化

// 2.运行管理资源申请

// 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);

// 如果运行模式为ACL_HOST,则需要申请Host内存,将输入图片数据读入Host内存,再通过aclrtMemcpy接口将Host的图片数据传输到Device,数据传输完成后,需及时释放Host内存;否则直接将输入图片数据读入Device内存
// runMode表示软件栈的运行模式,可通过aclrtGetRunMode接口获取
if (runMode == ACL_HOST) {
    void* hostInputAddr = nullptr;
    // 申请Host内存
    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);
   }
}

// 8.2 如果运行模式为ACL_HOST,且Host上需要展示JPEGD输出的图片数据,则需要申请Host内存,通过aclrtMemcpy接口将Device的输出图片数据传输到Host
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. 释放运行管理资源

// 13.AscendCL去初始化

// ....
搜索结果
找到“0”个结果

当前产品无相关内容

未找到相关内容,请尝试其他搜索词