JPEGE图片编码
VPC图像处理典型功能
VPC(Vision Preprocessing Core)负责图像处理功能,支持对图片做抠图、缩放、格式转换等操作。关于VPC功能的详细介绍请参见功能说明,关于VPC功能对输入、输出的约束要求,请参见约束说明。
本节以抠图、缩放为例说明VPC图像处理时的接口调用流程,同时配合以下典型功能的示例代码辅助理解该接口调用流程:
接口调用流程(以抠图、缩放为例)
开发应用时,如果涉及抠图、缩放等图片处理,则应用程序中必须包含图片处理的代码逻辑,关于图片处理的接口调用流程,请先参见AscendCL接口调用流程了解整体流程,再查看本节中的流程说明。
图1 抠图缩放流程

关键接口的说明如下(以抠图、缩放处理为例):
-
调用acldvppCreateChannel接口创建图片数据处理的通道。
创建图片数据处理的通道前,需先调用acldvppCreateChannelDesc接口创建通道描述信息。
-
调用acldvppCreateRoiConfig接口、acldvppCreateResizeConfig接口分别创建抠图区域位置的配置、缩放配置。
-
实现抠图、缩放功能前,若需要申请Device上的内存存放输入或输出数据,需调用acldvppMalloc申请内存。
-
执行抠图、缩放。
- 关于抠图:
-
调用acldvppVpcCropAsync异步接口,按指定区域从输入图片中抠图,再将抠的图片存放到输出内存中,作为输出图片。
输出图片区域与抠图区域cropArea不一致时会对图片再做一次缩放操作。
-
当前系统还提供了acldvppVpcCropAndPasteAsync异步接口,支持按指定区域从输入图片中抠图,再将抠的图片贴到目标图片的指定位置,作为输出图片。
- 抠图区域cropArea的宽高与贴图区域pasteArea宽高不一致时会对图片再做一次缩放操作。
- 如果用户需要将目标图片读入内存用于存放输出图片,将贴图区域叠加在目标图片上,则需要编写代码逻辑:在申请输出内存后,将目标图片读入输出内存。
-
- 关于缩放
- 调用acldvppVpcResizeAsync异步接口,将输入图片缩放到输出图片大小。
- 缩放后输出图片内存根据YUV420SP格式计算,计算公式:对齐后的宽*对齐后的高*3/2
- 对于异步接口,还需调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成。
- 关于抠图:
-
调用acldvppFree接口释放输入、输出内存。
-
调用acldvppDestroyRoiConfig接口、acldvppDestroyResizeConfig接口分别销毁抠图区域位置的配置、缩放配置。
-
调用acldvppDestroyChannel接口销毁图片数据处理的通道。
销毁图片数据处理的通道后,再调用acldvppDestroyChannelDesc接口销毁通道描述信息。
图片缩放示例代码
调用acldvppSetResizeConfigInterpolation接口指定缩放算法,再调用acldvppVpcResizeAsync异步接口,将输入图片缩放到输出图片大小。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br> 43<br> 44<br> 45<br> 46<br> 47<br> 48<br> 49<br> 50<br> 51<br> 52<br> 53<br> 54<br> 55<br> 56<br> 57<br> 58<br> 59<br> 60<br> 61<br> 62<br> 63<br> 64<br> 65<br> 66<br> 67<br> 68<br> 69<br> 70<br> 71<br> 72<br> 73<br> 74<br> 75<br> 76<br> 77<br> 78<br> 79<br> 80<br> 81<br> 82<br> 83<br> 84<br> 85<br> 86<br> 87<br> 88<br> 89<br> 90<br> 91<br> 92<br> 93<br> 94<br> 95<br> 96<br> 97<br> 98<br> 99<br>100<br>101<br>102<br>103<br>104<br>105<br>106<br>107<br>108<br>109<br>110<br>111<br>112<br>113<br> | <br>// 1.AscendCL初始化<br>aclRet = aclInit(nullptr);<br>// 2.运行管理资源申请(依次申请Device、Context、Stream)<br>aclrtContext context_;<br>aclrtStream stream_;<br>aclrtSetDevice(0);<br>aclrtCreateContext(&context_, 0);<br>aclrtCreateStream(&stream_);<br>// 3. 创建图片缩放配置数据、指定缩放算法<br>// resizeConfig_是acldvppResizeConfig类型<br>acldvppResizeConfig *resizeConfig_ = acldvppCreateResizeConfig();<br>aclError ret = acldvppSetResizeConfigInterpolation(resizeConfig, 0);<br>// 4. 创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型<br>dvppChannelDesc_ = acldvppCreateChannelDesc();<br>// 5. 创建图片数据处理的通道。<br>ret = acldvppCreateChannel(dvppChannelDesc_);<br>// 6. 申请输入内存(区分运行状态)<br>// 调用aclrtGetRunMode接口获取软件栈的运行模式,如果调用aclrtGetRunMode接口获取软件栈的运行模式为ACL_HOST,则需要通过aclrtMemcpy接口将输入图片数据传输到Device,数据传输完成后,需及时释放内存;否则直接申请并使用Device的内存<br>aclrtRunMode runMode;<br>ret = aclrtGetRunMode(&runMode);<br>// inputPicWidth、inputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例<br>uint32_t resizeInBufferSize = inputPicWidth * inputPicHeight * 3 / 2;<br>if(runMode == ACL_HOST) { <br> <br> void* vpcInHostBuffer = nullptr;<br> vpcInHostBuffer = malloc(resizeInBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, vpcInHostBuffer, resizeInBufferSize);<br> // 申请Device内存resizeInDevBuffer_<br> aclRet = acldvppMalloc(&resizeInDevBuffer_, resizeInBufferSize);<br> // 通过aclrtMemcpy接口将输入图片数据传输到Device<br> aclRet = aclrtMemcpy(resizeInDevBuffer_, resizeInBufferSize, vpcInHostBuffer, resizeInBufferSize, ACL_MEMCPY_HOST_TO_DEVICE);<br> // 数据传输完成后,及时释放内存<br> free(vpcInHostBuffer);<br>} else {<br> // 申请Device输入内存resizeInDevBuffer_<br> ret = acldvppMalloc(&resizeInDevBuffer_, resizeInBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, resizeInDevBuffer_, resizeInBufferSize);<br>}<br>// 7. 申请缩放输出内存resizeOutBufferDev_,内存大小resizeOutBufferSize_根据计算公式得出<br>// outputPicWidth、outputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例<br>uint32_t resizeOutBufferSize_ = outputPicWidth * outputPicHeight * 3 / 2;<br>ret = acldvppMalloc(&resizeOutBufferDev_, resizeOutBufferSize_)<br>// 8. 创建缩放输入图片的描述信息,并设置各属性值<br>// resizeInputDesc_是acldvppPicDesc类型<br>resizeInputDesc_ = acldvppCreatePicDesc();<br>acldvppSetPicDescData(resizeInputDesc_, resizeInDevBuffer_);<br>acldvppSetPicDescFormat(resizeInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);<br>acldvppSetPicDescWidth(resizeInputDesc_, inputWidth_);<br>acldvppSetPicDescHeight(resizeInputDesc_, inputHeight_);<br>acldvppSetPicDescWidthStride(resizeInputDesc_, inputWidthStride);<br>acldvppSetPicDescHeightStride(resizeInputDesc_, inputHeightStride);<br>acldvppSetPicDescSize(resizeInputDesc_, resizeInBufferSize);<br>// 9. 创建缩放输出图片的描述信息,并设置各属性值<br>// 如果缩放的输出图片作为模型推理的输入,则输出图片的宽高要与模型要求的宽高保持一致<br>// resizeOutputDesc_是acldvppPicDesc类型<br>resizeOutputDesc_ = acldvppCreatePicDesc();<br>acldvppSetPicDescData(resizeOutputDesc_, resizeOutBufferDev_);<br>acldvppSetPicDescFormat(resizeOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); <br>acldvppSetPicDescWidth(resizeOutputDesc_, resizeOutputWidth_);<br>acldvppSetPicDescHeight(resizeOutputDesc_, resizeOutputHeight_);<br>acldvppSetPicDescWidthStride(resizeOutputDesc_, resizeOutputWidthStride);<br>acldvppSetPicDescHeightStride(resizeOutputDesc_, resizeOutputHeightStride);<br>acldvppSetPicDescSize(resizeOutputDesc_, resizeOutBufferSize_);<br>// 10. 执行异步缩放,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成<br>ret = acldvppVpcResizeAsync(dvppChannelDesc_, resizeInputDesc_,<br> resizeOutputDesc_, resizeConfig_, stream_);<br>ret = aclrtSynchronizeStream(stream_);<br>// 11. 缩放结束后,释放资源,包括缩放输入/输出图片的描述信息、缩放输入/输出内存<br>acldvppDestroyPicDesc(resizeInputDesc_);<br>acldvppDestroyPicDesc(resizeOutputDesc_);<br>if(runMode == ACL_HOST) { <br> // 该模式下,由于处理结果在Device侧,因此需要调用内存复制接口传输结果数据后,再释放Device侧内存<br> <br> void* vpcOutHostBuffer = nullptr;<br> vpcOutHostBuffer = malloc(resizeOutBufferSize_);<br> <br> aclRet = aclrtMemcpy(vpcOutHostBuffer, resizeOutBufferSize_, resizeOutBufferDev_, resizeOutBufferSize_, ACL_MEMCPY_DEVICE_TO_HOST);<br> // 释放掉输入输出的device内存<br> (void)acldvppFree(resizeInDevBuffer_);<br> (void)acldvppFree(resizeOutBufferDev_);<br> // 数据使用完成后,释放内存<br> free(vpcOutHostBuffer);<br>} else { <br> // 此时运行在device侧,处理结果也在Device侧,可以根据需要操作处理结果后,释放Device侧内存<br> (void)acldvppFree(resizeInDevBuffer_);<br> (void)acldvppFree(resizeOutBufferDev_);<br>}<br>acldvppDestroyChannel(dvppChannelDesc_);<br>(void)acldvppDestroyChannelDesc(dvppChannelDesc_);<br>dvppChannelDesc_ = nullptr;<br>// 12. 释放运行管理资源(依次释放Stream、Context、Device)<br>aclrtDestroyStream(stream_);<br>aclrtDestroyContext(context_);<br>aclrtResetDevice(0);<br>// 13.AscendCL去初始化<br>aclRet = aclFinalize();<br>// ....<br> |
|---|
格式转换示例代码
格式转换支持以下两种实现方式:
- 在实现抠图、缩放等功能时,调用对应的接口(例如acldvppVpcCropAsync接口)时,通过将输入图片和输出图片的格式设置成不同的,达到转换图片格式的目的。
- 如果仅仅做图片格式转换,也可以直接调用acldvppVpcConvertColorAsync接口。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br> 43<br> 44<br> 45<br> 46<br> 47<br> 48<br> 49<br> 50<br> 51<br> 52<br> 53<br> 54<br> 55<br> 56<br> 57<br> 58<br> 59<br> 60<br> 61<br> 62<br> 63<br> 64<br> 65<br> 66<br> 67<br> 68<br> 69<br> 70<br> 71<br> 72<br> 73<br> 74<br> 75<br> 76<br> 77<br> 78<br> 79<br> 80<br> 81<br> 82<br> 83<br> 84<br> 85<br> 86<br> 87<br> 88<br> 89<br> 90<br> 91<br> 92<br> 93<br> 94<br> 95<br> 96<br> 97<br> 98<br> 99<br>100<br>101<br>102<br>103<br>104<br>105<br>106<br>107<br> | <br>// 1.AscendCL初始化<br>aclRet = aclInit(nullptr);<br>// 2.运行管理资源申请(依次申请Device、Context、Stream)<br>aclrtContext context_;<br>aclrtStream stream_;<br>aclrtSetDevice(0);<br>aclrtCreateContext(&context_, 0);<br>aclrtCreateStream(&stream_);<br>// 3. 创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型<br>dvppChannelDesc_ = acldvppCreateChannelDesc();<br>// 4. 创建图片数据处理的通道。<br>aclError ret = acldvppCreateChannel(dvppChannelDesc_);<br>// 5. 申请输入内存(区分运行状态)<br>// 调用aclrtGetRunMode接口获取软件栈的运行模式,如果调用aclrtGetRunMode接口获取软件栈的运行模式为ACL_HOST,则需要通过aclrtMemcpy接口将输入图片数据传输到Device,数据传输完成后,需及时释放内存;否则直接申请并使用Device的内存<br>aclrtRunMode runMode;<br>ret = aclrtGetRunMode(&runMode);<br>// inputPicWidth、inputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例<br>uint32_t inBufferSize = inputPicWidth * inputPicHeight * 3 / 2;<br>if(runMode == ACL_HOST){ <br> <br> void* vpcInHostBuffer = nullptr;<br> vpcInHostBuffer = malloc(inBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, vpcInHostBuffer, inBufferSize);<br> // 申请Device内存inDevBuffer_<br> aclRet = acldvppMalloc(&inDevBuffer_, inBufferSize);<br> // 通过aclrtMemcpy接口将输入图片数据传输到Device<br> aclRet = aclrtMemcpy(inDevBuffer_, inBufferSize, vpcInHostBuffer, inBufferSize, ACL_MEMCPY_HOST_TO_DEVICE);<br> // 数据传输完成后,及时释放内存<br> free(vpcInHostBuffer);<br>} else {<br> // 申请Device输入内存inDevBuffer_<br> ret = acldvppMalloc(&inDevBuffer_, inBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, inDevBuffer_, inBufferSize);<br>}<br>// 6. 申请色域转换输出内存outBufferDev_,内存大小outBufferSize_根据计算公式得出<br>// outputPicWidth、outputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例<br>uint32_t outBufferSize_ = outputPicWidth * outputPicHeight * 3 / 2<br>ret = acldvppMalloc(&outBufferDev_, outBufferSize_)<br>// 7. 创建色域转换输入图片的描述信息,并设置各属性值<br>// inputDesc_是acldvppPicDesc类型<br>inputDesc_ = acldvppCreatePicDesc();<br>acldvppSetPicDescData(inputDesc_, inDevBuffer_);<br>acldvppSetPicDescFormat(inputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);<br>acldvppSetPicDescWidth(inputDesc_, inputWidth_);<br>acldvppSetPicDescHeight(inputDesc_, inputHeight_);<br>acldvppSetPicDescWidthStride(inputDesc_, inputWidthStride);<br>acldvppSetPicDescHeightStride(inputDesc_, inputHeightStride);<br>acldvppSetPicDescSize(inputDesc_, inBufferSize);<br>// 8. 创建色域转换的输出图片的描述信息,并设置各属性值, 输出的宽和高要求和输入一致<br>// 如果色域转换的输出图片作为模型推理的输入,则输出图片的宽高要与模型要求的宽高保持一致<br>// outputDesc_是acldvppPicDesc类型<br>outputDesc_= acldvppCreatePicDesc();<br>acldvppSetPicDescData(outputDesc_, outBufferDev_);<br>acldvppSetPicDescFormat(outputDesc_, PIXEL_FORMAT_YUV_400); <br>acldvppSetPicDescWidth(outputDesc_, outputWidth_);<br>acldvppSetPicDescHeight(outputDesc_, outputHeight_);<br>acldvppSetPicDescWidthStride(outputDesc_, outputWidthStride);<br>acldvppSetPicDescHeightStride(outputDesc_, outputHeightStride);<br>acldvppSetPicDescSize(outputDesc_, outBufferSize_);<br>// 9. 执行异步色域转换,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成<br>ret = acldvppVpcConvertColorAsync(dvppChannelDesc_, inputDesc_, outputDesc_, stream_);<br>ret = aclrtSynchronizeStream(stream_);<br>// 10. 色域转换结束后,释放资源,包括输入/输出图片的描述信息、输入/输出内存<br>acldvppDestroyPicDesc(inputDesc_);<br>acldvppDestroyPicDesc(outputDesc_);<br>if(runMode == ACL_HOST) { <br> // 该模式下,由于处理结果在Device侧,因此需要调用内存复制接口传输结果数据后,再释放Device侧内存<br> <br> void* vpcOutHostBuffer = nullptr;<br> vpcOutHostBuffer = malloc(outBufferSize_);<br> <br> aclRet = aclrtMemcpy(vpcOutHostBuffer, outBufferSize_, outBufferDev_, outBufferSize_, ACL_MEMCPY_DEVICE_TO_HOST);<br> // 释放掉输入输出的device内存<br> (void)acldvppFree(inDevBuffer_);<br> (void)acldvppFree(outBufferDev_);<br> // 数据使用完成后,释放内存<br> free(vpcOutHostBuffer);<br>} else { <br> // 此时运行在device侧,处理结果也在Device侧,可以根据需要操作处理结果后,释放Device侧内存<br> (void)acldvppFree(inDevBuffer_);<br> (void)acldvppFree(outBufferDev_);<br>}<br>acldvppDestroyChannel(dvppChannelDesc_);<br>(void)acldvppDestroyChannelDesc(dvppChannelDesc_);<br>dvppChannelDesc_ = nullptr;<br>// 11. 释放运行管理资源(依次释放Stream、Context、Device)<br>aclrtDestroyStream(stream_);<br>aclrtDestroyContext(context_);<br>aclrtResetDevice(0);<br>// 12.AscendCL去初始化<br>aclRet = aclFinalize();<br>// ....<br> |
|---|
抠图缩放(一图一框)示例代码
调用acldvppVpcCropResizeAsync异步接口,按指定区域从输入图片中抠图,再将抠的图片存放到输出内存中,作为输出图片,此外,还支持指定缩放算法。当输出图片区域与抠图区域cropArea不一致时会对图片再做一次缩放操作。
您可以从样例介绍中获取完整样例代码。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br> 43<br> 44<br> 45<br> 46<br> 47<br> 48<br> 49<br> 50<br> 51<br> 52<br> 53<br> 54<br> 55<br> 56<br> 57<br> 58<br> 59<br> 60<br> 61<br> 62<br> 63<br> 64<br> 65<br> 66<br> 67<br> 68<br> 69<br> 70<br> 71<br> 72<br> 73<br> 74<br> 75<br> 76<br> 77<br> 78<br> 79<br> 80<br> 81<br> 82<br> 83<br> 84<br> 85<br> 86<br> 87<br> 88<br> 89<br> 90<br> 91<br> 92<br> 93<br> 94<br> 95<br> 96<br> 97<br> 98<br> 99<br>100<br>101<br>102<br>103<br>104<br>105<br>106<br>107<br>108<br>109<br>110<br>111<br>112<br>113<br> | <br>// 1.AscendCL初始化<br>aclRet = aclInit(nullptr);<br>// 2.运行管理资源申请(依次申请Device、Context、Stream)<br>aclrtContext context_;<br>aclrtStream stream_;<br>aclrtSetDevice(0);<br>aclrtCreateContext(&context_, 0);<br>aclrtCreateStream(&stream_);<br>// 3. 创建缩放配置数据,并指定抠图区域的位置<br>// resizeConfig_是acldvppResizeConfig类型<br>resizeConfig_ = acldvppCreateResizeConfig();<br>aclError aclRet = acldvppSetResizeConfigInterpolation(resizeConfig_, 0);<br>// cropArea_是acldvppRoiConfig类型<br>cropArea_ = acldvppCreateRoiConfig(550, 749, 480, 679);<br>// 4. 创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型<br>dvppChannelDesc_ = acldvppCreateChannelDesc();<br>// 5. 创建图片数据处理的通道。<br>ret = acldvppCreateChannel(dvppChannelDesc_);<br>// 6. 申请输入内存(区分运行状态)<br>// 调用aclrtGetRunMode接口获取软件栈的运行模式,如果调用aclrtGetRunMode接口获取软件栈的运行模式为ACL_HOST,则需要通过aclrtMemcpy接口将输入图片数据传输到Device,数据传输完成后,需及时释放内存;否则直接申请并使用Device的内存<br>aclrtRunMode runMode;<br>ret = aclrtGetRunMode(&runMode);<br>// inputPicWidth、inputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例<br>uint32_t cropInBufferSize = inputPicWidth * inputPicHeight * 3 / 2;<br>if(runMode == ACL_HOST) { <br> <br> void* cropInHostBuffer = nullptr;<br> cropInHostBuffer = malloc(cropInBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, cropInHostBuffer, cropInBufferSize);<br> // 申请Device内存cropInDevBuffer_<br> aclRet = acldvppMalloc(&cropInDevBuffer_, cropInBufferSize);<br> // 通过aclrtMemcpy接口图片数据传输到Device<br> aclRet = aclrtMemcpy(cropInDevBuffer_, cropInBufferSize, cropInHostBuffer, cropInBufferSize, ACL_MEMCPY_HOST_TO_DEVICE);<br> // 数据传输完成后,及时释放内存<br> free(cropInHostBuffer);<br>} else { <br> // 申请Device输入内存cropInDevBuffer_<br> ret = acldvppMalloc(&cropInDevBuffer_, cropInBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, cropInDevBuffer_, cropInBufferSize);<br>}<br>// 7. 申请Device输出内存cropOutBufferDev_,内存大小cropOutBufferSize_根据计算公式得出<br>// outputPicWidth、outputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例<br>uint32_t cropOutBufferSize_ = outputPicWidth * outputPicHeight * 3 / 2;<br>ret = acldvppMalloc(&cropOutBufferDev_, cropOutBufferSize_)<br>// 8. 创建输入图片的描述信息,并设置各属性值,cropInputDesc_是acldvppPicDesc类型<br>cropInputDesc_ = acldvppCreatePicDesc();<br>acldvppSetPicDescData(cropInputDesc_, cropInDevBuffer_);<br>acldvppSetPicDescFormat(cropInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);<br>acldvppSetPicDescWidth(cropInputDesc_, inputWidth_);<br>acldvppSetPicDescHeight(cropInputDesc_, inputHeight_);<br>acldvppSetPicDescWidthStride(cropInputDesc_, inputWidthStride);<br>acldvppSetPicDescHeightStride(cropInputDesc_, inputHeightStride);<br>acldvppSetPicDescSize(cropInputDesc_, cropInBufferSize);<br>// 9. 创建输出图片的描述信息,并设置各属性值,cropOutputDesc_是acldvppPicDesc类型<br>// 如果抠图的输出图片作为模型推理的输入,则输出图片的宽高要与模型要求的宽高保持一致<br>cropOutputDesc_ = acldvppCreatePicDesc();<br>acldvppSetPicDescData(cropOutputDesc_, cropOutBufferDev_);<br>acldvppSetPicDescFormat(cropOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); acldvppSetPicDescWidth(cropOutputDesc_, OutputWidth_);<br>acldvppSetPicDescHeight(cropOutputDesc_, OutputHeight_);<br>acldvppSetPicDescWidthStride(cropOutputDesc_, OutputWidthStride);<br>acldvppSetPicDescHeightStride(cropOutputDesc_, OutputHeightStride);<br>acldvppSetPicDescSize(cropOutputDesc_, cropOutBufferSize_);<br>// 10. 执行异步抠图缩放,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成<br>ret = acldvppVpcCropResizeAsync(dvppChannelDesc_, cropInputDesc_,<br> cropOutputDesc_, cropArea_, resizeConfig_, stream_);<br>ret = aclrtSynchronizeStream(stream_);<br>// 11. 抠图贴图结束后,释放资源,包括输入/输出图片的描述信息、输入/输出内存、通道描述信息、通道等<br>acldvppDestroyRoiConfig(cropArea_);<br>acldvppDestroyResizeConfig(resizeConfig_);<br>acldvppDestroyPicDesc(cropInputDesc_);<br>acldvppDestroyPicDesc(cropOutputDesc_);<br>if(runMode == ACL_HOST) { <br> // 该模式下,由于处理结果在Device侧,因此需要调用内存复制接口传输结果数据后,再释放Device侧内存<br> <br> void* cropOutHostBuffer = nullptr;<br> cropOutHostBuffer = malloc(cropOutBufferSize_);<br> <br> aclRet = aclrtMemcpy(cropOutHostBuffer, cropOutBufferSize_, cropOutBufferDev_, cropOutBufferSize_, ACL_MEMCPY_DEVICE_TO_HOST);<br> // 释放掉输入输出的device内存<br> (void)acldvppFree(cropInDevBuffer_);<br> (void)acldvppFree(cropOutBufferDev_);<br> // 数据使用完成后,释放内存<br> free(cropOutHostBuffer);<br>} else { <br> // 此时运行在device侧,处理结果也在Device侧,可以根据需要操作抠图结果后,释放Device侧内存<br> (void)acldvppFree(cropInDevBuffer_);<br> (void)acldvppFree(cropOutBufferDev_);<br>}<br>acldvppDestroyChannel(dvppChannelDesc_);<br>(void)acldvppDestroyChannelDesc(dvppChannelDesc_);<br>dvppChannelDesc_ = nullptr;<br>// 12. 释放运行管理资源(依次释放Stream、Context、Device)<br>aclrtDestroyStream(stream_);<br>aclrtDestroyContext(context_);<br>aclrtResetDevice(0);<br>// 13.AscendCL去初始化<br>aclRet = aclFinalize();<br>// ....<br> |
|---|
抠图贴图缩放(一图一框)示例代码
调用acldvppVpcCropResizePasteAsync异步接口,按指定区域从输入图片中抠图,再将抠的图片贴到目标图片的指定位置,作为输出图片,此外,还支持指定缩放算法。当抠图区域cropArea的宽高与贴图区域pasteArea宽高不一致时会对图片再做一次缩放操作。如果用户需要将目标图片读入内存用于存放输出图片,将贴图区域叠加在目标图片上,则需要编写代码逻辑:在申请输出内存后,将目标图片读入输出内存。
您可以从样例介绍中获取完整样例代码。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br> 43<br> 44<br> 45<br> 46<br> 47<br> 48<br> 49<br> 50<br> 51<br> 52<br> 53<br> 54<br> 55<br> 56<br> 57<br> 58<br> 59<br> 60<br> 61<br> 62<br> 63<br> 64<br> 65<br> 66<br> 67<br> 68<br> 69<br> 70<br> 71<br> 72<br> 73<br> 74<br> 75<br> 76<br> 77<br> 78<br> 79<br> 80<br> 81<br> 82<br> 83<br> 84<br> 85<br> 86<br> 87<br> 88<br> 89<br> 90<br> 91<br> 92<br> 93<br> 94<br> 95<br> 96<br> 97<br> 98<br> 99<br>100<br>101<br>102<br>103<br>104<br>105<br>106<br>107<br>108<br>109<br>110<br>111<br>112<br>113<br>114<br>115<br>116<br>117<br>118<br>119<br>120<br> | <br>// 1.AscendCL初始化<br>aclRet = aclInit(nullptr);<br>// 2.运行管理资源申请(依次申请Device、Context、Stream)<br>aclrtContext context_;<br>aclrtStream stream_;<br>aclrtSetDevice(0);<br>aclrtCreateContext(&context_, 0);<br>aclrtCreateStream(&stream_);<br>// 3. 创建缩放配置数据,并指定抠图区域的位置、指定贴图区域的位置<br>// resizeConfig_是acldvppResizeConfig类型<br>resizeConfig_ = acldvppCreateResizeConfig();<br>aclError aclRet = acldvppSetResizeConfigInterpolation(resizeConfig_, 0);<br>// cropArea_和pasteArea_是acldvppRoiConfig类型<br>cropArea_ = acldvppCreateRoiConfig(512, 711, 512, 711);<br>pasteArea_ = acldvppCreateRoiConfig(16, 215, 16, 215);<br>// 4. 创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型<br>dvppChannelDesc_ = acldvppCreateChannelDesc();<br>// 5. 创建图片数据处理的通道。<br>ret = acldvppCreateChannel(dvppChannelDesc_);<br>// 6. 申请输入内存(区分运行状态)<br>// 调用aclrtGetRunMode接口获取软件栈的运行模式,如果调用aclrtGetRunMode接口获取软件栈的运行模式为ACL_HOST,则需要通过aclrtMemcpy接口将输入图片数据传输到Device,数据传输完成后,需及时释放内存;否则直接申请并使用Device的内存<br>aclrtRunMode runMode;<br>ret = aclrtGetRunMode(&runMode);<br>// inputPicWidth、inputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例<br>uint32_t vpcInBufferSize = inputPicWidth * inputPicHeight * 3 / 2;<br>if(runMode == ACL_HOST) { <br> <br> void* vpcInHostBuffer = nullptr;<br> vpcInHostBuffer = malloc(vpcInBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, vpcInHostBuffer, vpcInBufferSize);<br> // 申请Device内存vpcInDevBuffer_<br> aclRet = acldvppMalloc(&vpcInDevBuffer_, vpcInBufferSize);<br> // 通过aclrtMemcpy接口将输入图片数据传输到Device<br> aclRet = aclrtMemcpy(vpcInDevBuffer_, vpcInBufferSize, vpcInHostBuffer, vpcInBufferSize, ACL_MEMCPY_HOST_TO_DEVICE);<br> // 数据传输完成后,及时释放内存<br> free(vpcInHostBuffer);<br>} else {<br> // 申请Device输入内存vpcInDevBuffer_<br> ret = acldvppMalloc(&vpcInDevBuffer_, vpcInBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, vpcInDevBuffer_, vpcInBufferSize);<br>}<br>// 7. 申请输出内存vpcOutBufferDev_,内存大小vpcOutBufferSize_根据计算公式得出<br>// outputPicWidth、outputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例<br>uint32_t vpcOutBufferSize_ = outputPicWidth * outputPicHeight * 3 / 2;<br>ret = acldvppMalloc(&vpcOutBufferDev_, vpcOutBufferSize_)<br>// 8. 创建输入图片的描述信息,并设置各属性值<br>// 此处示例将解码的输出内存作为抠图贴图的输入,vpcInputDesc_是acldvppPicDesc类型<br>vpcInputDesc_ = acldvppCreatePicDesc();<br>acldvppSetPicDescData(vpcInputDesc_, decodeOutBufferDev_); <br>acldvppSetPicDescFormat(vpcInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);<br>acldvppSetPicDescWidth(vpcInputDesc_, inputWidth_);<br>acldvppSetPicDescHeight(vpcInputDesc_, inputHeight_);<br>acldvppSetPicDescWidthStride(vpcInputDesc_, jpegOutWidthStride);<br>acldvppSetPicDescHeightStride(vpcInputDesc_, jpegOutHeightStride);<br>acldvppSetPicDescSize(vpcInputDesc_, jpegOutBufferSize);<br>// 9. 创建输出图片的描述信息,并设置各属性值<br>// 如果抠图贴图的输出图片作为模型推理的输入,则输出图片的宽高要与模型要求的宽高保持一致<br>// vpcOutputDesc_是acldvppPicDesc类型<br>vpcOutputDesc_ = acldvppCreatePicDesc();<br>acldvppSetPicDescData(vpcOutputDesc_, vpcOutBufferDev_);<br>acldvppSetPicDescFormat(vpcOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);<br>acldvppSetPicDescWidth(vpcOutputDesc_, dvppOutWidth);<br>acldvppSetPicDescHeight(vpcOutputDesc_, dvppOutHeight);<br>acldvppSetPicDescWidthStride(vpcOutputDesc_, dvppOutWidthStride);<br>acldvppSetPicDescHeightStride(vpcOutputDesc_, dvppOutHeightStride);<br>acldvppSetPicDescSize(vpcOutputDesc_, vpcOutBufferSize_);<br>// 10. 执行异步抠图贴图缩放,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成<br>ret = acldvppVpcCropResizePasteAsync(dvppChannelDesc_, vpcInputDesc_,<br> vpcOutputDesc_, cropArea_, pasteArea_, resizeConfig_, stream_);<br>ret = aclrtSynchronizeStream(stream_);<br>// 11. 抠图贴图结束后,释放资源,包括输入/输出图片的描述信息、输入/输出内存、通道描述信息、通道等<br>acldvppDestroyRoiConfig(cropArea_);<br>acldvppDestroyRoiConfig(pasteArea_);<br>acldvppDestroyResizeConfig(resizeConfig_);<br>acldvppDestroyPicDesc(vpcInputDesc_);<br>acldvppDestroyPicDesc(vpcOutputDesc_);<br>if(runMode == ACL_HOST) { <br> // 该模式下,由于处理结果在Device侧,因此需要调用内存复制接口传输结果数据后,再释放Device侧内存<br> <br> void* vpcOutHostBuffer = nullptr;<br> vpcOutHostBuffer = malloc(vpcOutBufferSize_);<br> <br> aclRet = aclrtMemcpy(vpcOutHostBuffer, vpcOutBufferSize_, vpcOutBufferDev_, vpcOutBufferSize_, ACL_MEMCPY_DEVICE_TO_HOST);<br> // 释放掉输入输出的device内存<br> (void)acldvppFree(vpcInDevBuffer_);<br> (void)acldvppFree(vpcOutBufferDev_);<br> // 数据使用完成后,释放内存<br> free(vpcOutHostBuffer);<br>} else { <br> // 此时运行在device侧,处理结果也在Device侧,可以根据需要操作处理结果后,释放Device侧内存<br> (void)acldvppFree(vpcInDevBuffer_);<br> (void)acldvppFree(vpcOutBufferDev_);<br>}<br>acldvppDestroyChannel(dvppChannelDesc_);<br>(void)acldvppDestroyChannelDesc(dvppChannelDesc_);<br>dvppChannelDesc_ = nullptr;<br>// 12. 释放运行管理资源(依次释放Stream、Context、Device)<br>aclrtDestroyStream(stream_);<br>aclrtDestroyContext(context_);<br>aclrtResetDevice(0);<br>// 13.AscendCL去初始化<br>aclRet = aclFinalize();<br>// ....<br> |
|---|
抠图贴图(一图多框)示例代码
调用acldvppVpcBatchCropAndPasteAsync异步接口,按指定区域从输入图片中抠图,再将抠的图片贴到目标图片的指定位置,作为输出图片。当抠图区域cropArea的宽高与贴图区域pasteArea宽高不一致时会对图片再做一次缩放操作。如果用户需要将目标图片读入内存用于存放输出图片,将贴图区域叠加在目标图片上,则需要编写代码逻辑:在申请输出内存后,将目标图片读入输出内存。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br> 43<br> 44<br> 45<br> 46<br> 47<br> 48<br> 49<br> 50<br> 51<br> 52<br> 53<br> 54<br> 55<br> 56<br> 57<br> 58<br> 59<br> 60<br> 61<br> 62<br> 63<br> 64<br> 65<br> 66<br> 67<br> 68<br> 69<br> 70<br> 71<br> 72<br> 73<br> 74<br> 75<br> 76<br> 77<br> 78<br> 79<br> 80<br> 81<br> 82<br> 83<br> 84<br> 85<br> 86<br> 87<br> 88<br> 89<br> 90<br> 91<br> 92<br> 93<br> 94<br> 95<br> 96<br> 97<br> 98<br> 99<br>100<br>101<br>102<br>103<br>104<br>105<br>106<br>107<br>108<br>109<br>110<br>111<br>112<br>113<br>114<br>115<br>116<br>117<br>118<br>119<br>120<br>121<br>122<br>123<br>124<br>125<br>126<br>127<br>128<br>129<br>130<br> | cpp<br>// 1.AscendCL初始化<br>aclRet = aclInit(nullptr);<br>// 2.运行管理资源申请(依次申请Device、Context、Stream)<br>aclrtContext context_;<br>aclrtStream stream_;<br>aclrtSetDevice(0);<br>aclrtCreateContext(&context_, 0);<br>aclrtCreateStream(&stream_);<br>// 3.指定批量抠图区域的位置、指定批量贴图区域的位置,cropAreas_和pasteAreas_是acldvppRoiConfig类型<br>acldvppRoiConfig *cropAreas_[2], pasteAreas_[2];<br>cropAreas_[0] = acldvppCreateRoiConfig(512, 711, 512, 711);<br>cropAreas_[1] = acldvppCreateRoiConfig(512, 711, 512, 711);<br>pasteAreas_[0] = acldvppCreateRoiConfig(16, 215, 16, 215);<br>pasteAreas_[1] = acldvppCreateRoiConfig(16, 215, 16, 215);<br>// 4. 创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型<br>dvppChannelDesc_ = acldvppCreateChannelDesc();<br>// 5. 创建图片数据处理的通道。<br>aclError ret = acldvppCreateChannel(dvppChannelDesc_);<br>// 6. 申请输入内存(区分运行状态)<br>// 调用aclrtGetRunMode接口获取软件栈的运行模式,如果调用aclrtGetRunMode接口获取软件栈的运行模式为ACL_HOST,则需要通过aclrtMemcpy接口将输入图片数据传输到Device,数据传输完成后,需及时释放内存;否则直接申请并使用Device的内存<br>aclrtRunMode runMode;<br>ret = aclrtGetRunMode(&runMode);<br>// inputPicWidth、inputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例<br>uint32_t vpcInBufferSize = inputPicWidth * inputPicHeight * 3 / 2;<br>if(runMode == ACL_HOST) { <br> <br> void* vpcInHostBuffer = nullptr;<br> vpcInHostBuffer = malloc(vpcInBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, vpcInHostBuffer, vpcInBufferSize);<br> // 申请Device内存vpcInDevBuffer_<br> aclRet = acldvppMalloc(&vpcInDevBuffer_, vpcInBufferSize);<br> <br> aclRet = aclrtMemcpy(vpcInDevBuffer_, vpcInBufferSize, vpcInHostBuffer, vpcInBufferSize, ACL_MEMCPY_HOST_TO_DEVICE);<br> // 数据传输完成后,及时释放内存<br> free(vpcInHostBuffer);<br>} else {<br> // 申请Device输入内存vpcInDevBuffer_<br> ret = acldvppMalloc(&vpcInDevBuffer_, vpcInBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, vpcInDevBuffer_, vpcInBufferSize);<br>}<br>// 7. 申请输出内存vpcOutBufferDev_,内存大小vpcOutBufferSize_根据计算公式得出<br>// outputPicWidth、outputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例<br>uint32_t vpcOutBufferSize_ = outputPicWidth * outputPicHeight * 3 / 2;<br>ret = acldvppMalloc(&vpcOutBufferDev_, vpcOutBufferSize_)<br>// 8. 创建输入图片的描述信息,并设置各属性值<br>// 此处示例将解码的输出内存作为抠图贴图的输入,vpcInputDesc_是acldvppPicDesc类型<br>vpcInputBatchDesc_ = acldvppCreateBatchPicDesc(1);<br>vpcInputDesc_ = acldvppGetPicDesc(vpcInputBatchDesc_, 0);<br>acldvppSetPicDescData(vpcInputDesc_, decodeOutBufferDev_); <br>acldvppSetPicDescFormat(vpcInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);<br>acldvppSetPicDescWidth(vpcInputDesc_, inputWidth_);<br>acldvppSetPicDescHeight(vpcInputDesc_, inputHeight_);<br>acldvppSetPicDescWidthStride(vpcInputDesc_, jpegOutWidthStride);<br>acldvppSetPicDescHeightStride(vpcInputDesc_, jpegOutHeightStride);<br>acldvppSetPicDescSize(vpcInputDesc_, jpegOutBufferSize);<br>// 9. 创建批量输出图片的描述信息,并设置各属性值<br>// 如果抠图贴图的输出图片作为模型推理的输入,则输出图片的宽高要与模型要求的宽高保持一致<br>// vpcOutputDesc_是acldvppPicDesc类型<br>vpcOutputBatchDesc_ = acldvppCreateBatchPicDesc(2);<br>for (index=0; index<2; ++index){<br> vecOutPtr_.push_back(vpcOutBufferDev_);<br> vpcOutputDesc_ = acldvppGetPicDesc(vpcInputBatchDesc_, index);<br> acldvppSetPicDescData(vpcOutputDesc_, vpcOutBufferDev_);<br> acldvppSetPicDescFormat(vpcOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);<br> acldvppSetPicDescWidth(vpcOutputDesc_, dvppOutWidth);<br> acldvppSetPicDescHeight(vpcOutputDesc_, dvppOutHeight);<br> acldvppSetPicDescWidthStride(vpcOutputDesc_, dvppOutWidthStride);<br> acldvppSetPicDescHeightStride(vpcOutputDesc_, dvppOutHeightStride);<br> acldvppSetPicDescSize(vpcOutputDesc_, vpcOutBufferSize_);<br>}<br>// 10. 创建roiNums,每张图对应需要抠图和贴图的数量<br>uint32_ttotalNum = 0;<br>std::unique_ptr<uint32_t[]> roiNums(new (std::nothrow) uint32_t[1]);<br>roiNums[0]=2;<br>// 11. 执行异步抠图贴图,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成<br>ret = acldvppVpcBatchCropAndPasteAsync(dvppChannelDesc_, vpcInputBatchDesc_, roiNums.get(), 1,<br> vpcOutputBatchDesc_, cropAreas_, pasteAreas_, stream_);<br>ret = aclrtSynchronizeStream(stream_);<br>// 12. 抠图贴图结束后,释放资源,包括输入/输出图片的描述信息、输入/输出内存、通道描述信息、通道等<br>acldvppDestroyRoiConfig(cropAreas_[0]);<br>acldvppDestroyRoiConfig(cropAreas_[1]);<br>acldvppDestroyRoiConfig(pasteAreas_[0]);<br>acldvppDestroyRoiConfig(pasteAreas_[1]);<br>(void)acldvppFree(vpcInDevBuffer_);<br>for(index=0; index<2; ++index){<br>if(runMode == ACL_HOST) { <br> // 该模式下,由于处理结果在Device侧,因此需要调用内存复制接口传输结果数据后,再释放Device侧内存<br> <br> void* vpcOutHostBuffer = nullptr;<br> vpcOutHostBuffer = malloc(vpcOutBufferSize_);<br> <br> aclRet = aclrtMemcpy(vpcOutHostBuffer, vpcOutBufferSize_, vpcOutBufferDev_, vpcOutBufferSize_, ACL_MEMCPY_DEVICE_TO_HOST);<br> // 释放掉输入输出的device内存<br> (void)acldvppFree(vpcOutBufferDev_);<br> // 数据使用完成后,释放内存<br> free(vpcOutHostBuffer);<br>} else { <br> // 此时运行在device侧,处理结果也在Device侧,可以根据需要操作处理结果后,释放Device侧内存<br> <br> (void)acldvppFree(vpcOutBufferDev_);<br>}<br>}<br>acldvppDestroyBatchPicDesc(vpcInputDesc_);<br>acldvppDestroyBatchPicDesc(vpcOutputDesc_);<br>acldvppDestroyChannel(dvppChannelDesc_);<br>(void)acldvppDestroyChannelDesc(dvppChannelDesc_);<br>dvppChannelDesc_ = nullptr;<br>// 13. 释放运行管理资源(依次释放Stream、Context、Device)<br>aclrtDestroyStream(stream_);<br>aclrtDestroyContext(context_);<br>aclrtResetDevice(0);<br>// 14.AscendCL去初始化<br>aclRet = aclFinalize();<br>// ....<br> |
|---|
父主题: 媒体数据处理V1
JPEGD图像解码
JPEGD(JPEG Decoder)负责完成图像解码功能,将.jpg、.jpeg、.JPG、.JPEG图片解码成YUV格式图片。关于JPEGD功能的详细介绍及约束请参见功能及约束说明。
本节介绍JPEGD图片解码的接口调用流程,同时配合示例代码辅助理解该接口调用流程。
接口调用流程
开发应用时,如果涉及对JPEG图片的解码,则应用程序中必须包含图片解码的代码逻辑,关于图片解码的接口调用流程,请先参见AscendCL接口调用流程了解整体流程,再查看本节中的流程说明。
图1 JPEG图片解码

当前系统支持.jpg、.jpeg、.JPG、.JPEG图片的解码,针对不同的源图编码格式,输出不同编码格式的图片,关键接口的说明如下:
-
调用acldvppCreateChannel接口创建图片数据处理的通道。
创建图片数据处理的通道前,需先调用acldvppCreateChannelDesc接口创建通道描述信息。
-
实现JPEG图片解码功能前,若需要申请Device上的内存存放输入或输出数据,需调用acldvppMalloc申请内存。
在申请输出内存前,可根据存放JPEG图片数据的内存,调用acldvppJpegPredictDecSize接口预估JPEG图片解码后所需的输出内存的大小。
实际输出内存大小可能与调用acldvppJpegPredictDecSize接口预估的内存大小存在差异,如果用户需要获取解码后的实际输出内存大小,需调用acldvppPicDesc类型下的acldvppGetPicDescSize接口获取。
-
调用acldvppJpegDecodeAsync异步接口进行解码。
对于异步接口,还需调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成。
-
在解码结束后,需及时调用acldvppFree接口释放输入、输出内存。
-
调用acldvppDestroyChannel接口销毁图片数据处理的通道。
销毁图片数据处理的通道后,再调用acldvppDestroyChannelDesc接口销毁通道描述信息。
示例代码
您可以从样例介绍中获取完整样例代码。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br>29<br>30<br>31<br>32<br>33<br>34<br>35<br>36<br>37<br>38<br>39<br>40<br>41<br>42<br>43<br>44<br>45<br>46<br>47<br>48<br>49<br>50<br>51<br>52<br>53<br>54<br>55<br>56<br>57<br>58<br>59<br>60<br>61<br>62<br>63<br>64<br>65<br>66<br>67<br>68<br>69<br>70<br>71<br>72<br>73<br>74<br>75<br>76<br>77<br>78<br>79<br>80<br>81<br>82<br>83<br>84<br>85<br>86<br>87<br>88<br>89<br>90<br>91<br>92<br>93<br> | <br>// 1.AscendCL初始化<br>aclRet = aclInit(nullptr);<br>// 2.运行管理资源申请(依次申请Device、Context、Stream)<br>aclrtContext context_;<br>aclrtStream stream_;<br>aclrtSetDevice(0);<br>aclrtCreateContext(&context_, 0);<br>aclrtCreateStream(&stream_);<br>// 3.创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型<br>dvppChannelDesc_ = acldvppCreateChannelDesc();<br>// 4.创建图片数据处理的通道。<br>aclError ret = acldvppCreateChannel(dvppChannelDesc_);<br>// 5. 申请输入内存(区分运行状态)<br>// 调用aclrtGetRunMode接口获取软件栈的运行模式,如果调用aclrtGetRunMode接口获取软件栈的运行模式为ACL_HOST,则需要通过aclrtMemcpy接口将输入图片数据传输到Device,数据传输完成后,需及时释放内存;否则直接申请并使用Device的内存<br>aclrtRunMode runMode;<br>ret = aclrtGetRunMode(&runMode);<br>if(runMode == ACL_HOST){<br> <br> void* inputHostBuff = nullptr;<br> inputHostBuff = malloc(inDevBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, inputHostBuff, inDevBufferSize);<br> // 申请Device内存inDevBuffer_<br> aclRet = acldvppMalloc(&inDevBuffer_, inDevBufferSize);<br> // 通过aclrtMemcpy接口将输入图片数据传输到Device<br> aclRet = aclrtMemcpy(inDevBuffer_, inDevBufferSize, inputHostBuff, inDevBufferSize, ACL_MEMCPY_HOST_TO_DEVICE);<br>} else {<br> // 申请Device输入内存inDevBuffer_<br> ret = acldvppMalloc(&inDevBuffer_, inBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, inDevBuffer_, inBufferSize);<br>}<br>// 6. 申请解码输出内存decodeOutDevBuffer_<br>// 预估JPEGD处理结果所需的内存大小<br>uint32_t decodeOutBufferSize = 0;<br>ret = acldvppJpegPredictDecSize(inputHostBuff, inDevBufferSize, PIXEL_FORMAT_YVU_SEMIPLANAR_420,&decodeOutBufferSize)<br>ret = acldvppMalloc(&decodeOutDevBuffer_, decodeOutBufferSize)<br>// 及时释放内存<br>free(inputHostBuff);<br>// 7. 创建解码输出图片的描述信息,设置各属性值<br>// decodeOutputDesc是acldvppPicDesc类型<br>decodeOutputDesc_ = acldvppCreatePicDesc();<br>acldvppSetPicDescData(decodeOutputDesc_, decodeOutDevBuffer_);<br>acldvppSetPicDescFormat(decodeOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); <br>acldvppSetPicDescWidth(decodeOutputDesc_, inputWidth_);<br>acldvppSetPicDescHeight(decodeOutputDesc_, inputHeight_);<br>acldvppSetPicDescWidthStride(decodeOutputDesc_, decodeOutWidthStride);<br>acldvppSetPicDescHeightStride(decodeOutputDesc_, decodeOutHeightStride);<br>acldvppSetPicDescSize(decodeOutputDesc_, decodeOutBufferSize);<br>// 8. 执行异步解码,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成<br>ret = acldvppJpegDecodeAsync(dvppChannelDesc_, inDevBuffer_, inDevBufferSize, decodeOutputDesc_, stream_);<br>ret = aclrtSynchronizeStream(stream_);<br>// 9. 解码结束后,释放资源,包括解码输出图片的描述信息、解码输出内存、通道描述信息、通道等<br>acldvppDestroyPicDesc(decodeOutputDesc_);<br>if(runMode == ACL_HOST) { <br> // 该模式下,由于处理结果在Device侧,因此需要调用内存复制接口传输结果数据后,再释放Device侧内存<br> <br> void* vpcOutHostBuffer = nullptr;<br> vpcOutHostBuffer = malloc(decodeOutBufferSize);<br> <br> aclRet = aclrtMemcpy(vpcOutHostBuffer, decodeOutBufferSize, decodeOutDevBuffer_, decodeOutBufferSize, ACL_MEMCPY_DEVICE_TO_HOST);<br> // 释放掉输入输出的device内存<br> (void)acldvppFree(inDevBuffer_);<br> (void)acldvppFree(decodeOutDevBuffer_);<br> // 数据使用完成后,释放内存<br> free(vpcOutHostBuffer);<br>} else { <br> // 此时运行在device侧,处理结果也在Device侧,可以根据需要操作处理结果后,释放Device侧内存<br> (void)acldvppFree(inDevBuffer_);<br> (void)acldvppFree(decodeOutDevBuffer_);<br>}<br>acldvppDestroyChannel(dvppChannelDesc_);<br>(void)acldvppDestroyChannelDesc(dvppChannelDesc_);<br>dvppChannelDesc_ = nullptr;<br>// 10. 释放运行管理资源(依次释放Stream、Context、Device)<br>aclrtDestroyStream(stream_);<br>aclrtDestroyContext(context_);<br>aclrtResetDevice(0);<br>// 11.AscendCL去初始化<br>aclRet = aclFinalize();<br>// ....<br> |
|---|
父主题: 媒体数据处理V1
JPEGE图片编码
JPEGE(JPEG Encoder)负责完成图像编码功能,将YUV格式图片编码成.jpg图片。关于JPEGE功能的详细介绍及约束请参见功能及约束说明。
本节介绍JPEGE图片编码的接口调用流程,同时配合示例代码辅助理解该接口调用流程。
接口调用流程
开发应用时,如果涉及将YUV格式图片编码成JPEG压缩格式的图片文件,则应用程序中必须包含图片编码的代码逻辑,关于图片编码的接口调用流程,请先参见AscendCL接口调用流程了解整体流程,再查看本节中的流程说明。
图1 JPEG图片编码

当前系统支持将YUV格式图片编码成.jpg图片,关键接口的说明如下:
-
调用acldvppCreateChannel接口创建图片数据处理的通道。
创建图片数据处理的通道前,需先调用acldvppCreateChannelDesc接口创建通道描述信息。
-
调用acldvppCreateJpegeConfig接口创建图片编码配置数据。
-
实现JPEG图片编码功能前,若需要申请Device上的内存存放输入或输出数据,需调用acldvppMalloc申请内存。
在申请输出内存前,可调用acldvppJpegPredictEncSize接口根据输入图片描述信息、图片编码配置数据可预估图片编码后所需的输出内存的大小。
实际输出内存大小可能与调用acldvppJpegPredictEncSize接口预估的内存大小存在差异,如果用户需要获取编码后的实际输出内存大小,可通过acldvppJpegEncodeAsync接口的出参size获取。
-
调用acldvppJpegEncodeAsync异步接口进行编码。
对于异步接口,还需调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成。
-
调用acldvppDestroyJpegeConfig接口销毁图片编码配置数据。
-
在编码结束后,需及时调用acldvppFree接口释放输入、输出内存。
-
调用acldvppDestroyChannel接口销毁图片数据处理的通道。
销毁图片数据处理的通道后,再调用acldvppDestroyChannelDesc接口销毁通道描述信息。
示例代码
您可以从样例介绍中获取完整样例代码。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br>29<br>30<br>31<br>32<br>33<br>34<br>35<br>36<br>37<br>38<br>39<br>40<br>41<br>42<br>43<br>44<br>45<br>46<br>47<br>48<br>49<br>50<br>51<br>52<br>53<br>54<br>55<br>56<br>57<br>58<br>59<br>60<br>61<br>62<br>63<br>64<br>65<br>66<br>67<br>68<br>69<br>70<br>71<br>72<br>73<br>74<br>75<br>76<br>77<br>78<br>79<br>80<br>81<br>82<br>83<br>84<br>85<br>86<br>87<br>88<br>89<br>90<br>91<br>92<br>93<br>94<br>95<br>96<br>97<br>98<br>99<br> | <br>// 1.AscendCL初始化<br>aclRet = aclInit(nullptr);<br>// 2.运行管理资源申请(依次申请Device、Context、Stream)<br>aclrtContext context_;<br>aclrtStream stream_;<br>aclrtSetDevice(0);<br>aclrtCreateContext(&context_, 0);<br>aclrtCreateStream(&stream_);<br>// 3.创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型<br>dvppChannelDesc_ = acldvppCreateChannelDesc();<br>// 4.创建图片数据处理的通道<br>aclRet = acldvppCreateChannel(dvppChannelDesc_);<br>// 5.申请输入内存(区分运行状态)<br>// 调用aclrtGetRunMode接口获取软件栈的运行模式,如果调用aclrtGetRunMode接口获取软件栈的运行模式为ACL_HOST,则需要通过aclrtMemcpy接口将输入图片数据传输到Device,数据传输完成后,需及时释放内存;否则直接申请并使用Device的内存<br>aclrtRunMode runMode;<br>ret = aclrtGetRunMode(&runMode);<br>// inputPicWidth、inputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例<br>uint32_t PicBufferSize = inputPicWidth * inputPicHeight * 3 / 2;<br>if(runMode == ACL_HOST){ <br> <br> void* vpcInHostBuffer = nullptr;<br> vpcInHostBuffer = malloc(PicBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, vpcInHostBuffer, PicBufferSize);<br> // 申请Device内存inDevBuffer_<br> aclRet = acldvppMalloc(&inDevBuffer_, PicBufferSize);<br> // 通过aclrtMemcpy接口将输入图片数据传输到Device<br> aclRet = aclrtMemcpy(inDevBuffer_, PicBufferSize, vpcInHostBuffer, PicBufferSize, ACL_MEMCPY_HOST_TO_DEVICE);<br> // 数据传输完成后,及时释放内存<br> free(vpcInHostBuffer);<br>} else {<br> // 申请Device输入内存inDevBuffer_<br> ret = acldvppMalloc(&inDevBuffer_, PicBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, inDevBuffer_, PicBufferSize);<br>}<br>// 6. 创建编码输入图片的描述信息,并设置各属性值<br>// encodeInputDesc_是acldvppPicDesc类型<br>encodeInputDesc_ = acldvppCreatePicDesc();<br>acldvppSetPicDescData(encodeInputDesc_, reinterpret_cast<void *>(inDevBuffer_));<br>acldvppSetPicDescFormat(encodeInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);<br>acldvppSetPicDescWidth(encodeInputDesc_, inputWidth_);<br>acldvppSetPicDescHeight(encodeInputDesc_, inputHeight_);<br>acldvppSetPicDescWidthStride(encodeInputDesc_, encodeInWidthStride);<br>acldvppSetPicDescHeightStride(encodeInputDesc_, encodeInHeightStride);<br>acldvppSetPicDescSize(encodeInputDesc_, inDevBufferSizeE_);<br>// 7. 创建图片编码配置数据,设置编码质量<br>// 编码质量范围[0, 100],其中level 0编码质量与level 100差不多,而在[1, 100]内数值越小输出图片质量越差。<br>jpegeConfig_ = acldvppCreateJpegeConfig();<br>acldvppSetJpegeConfigLevel(jpegeConfig_, 100);<br>// 8. 申请输出内存,申请Device内存encodeOutBufferDev_,存放编码后的输出数据<br>uint32_t outBufferSize= 0;<br>ret = acldvppJpegPredictEncSize(encodeInputDesc_, jpegeConfig_, &outBufferSize);<br>ret = acldvppMalloc(&encodeOutBufferDev_, outBufferSize)<br>// 9. 执行异步编码,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成<br>aclRet = acldvppJpegEncodeAsync(dvppChannelDesc_, encodeInputDesc_, encodeOutBufferDev_,<br> &outBufferSize, jpegeConfig_, stream_);<br>aclRet = aclrtSynchronizeStream(stream_);<br>// 10. 编码结束后,释放资源,包括编码输入/输出图片的描述信息、编码输入/输出内存、通道描述信息、通道等<br>acldvppDestroyPicDesc(encodeInputDesc_);<br>if(runMode == ACL_HOST) { <br> // 该模式下,由于处理结果在Device侧,因此需要调用内存复制接口传输结果数据后,再释放Device侧内存<br> <br> void* outputHostBuffer = nullptr;<br> outputHostBuffer = malloc(outBufferSize_);<br> <br> aclRet = aclrtMemcpy(outputHostBuffer, outBufferSize_, encodeOutBufferDev_, outBufferSize_, ACL_MEMCPY_DEVICE_TO_HOST);<br> // 释放掉输入输出的device内存<br> (void)acldvppFree(inputDevBuff);<br> (void)acldvppFree(encodeOutBufferDev_);<br> // 数据使用完成后,释放内存<br> free(outputHostBuffer);<br>} else { <br> // 此时运行在device侧,处理结果也在Device侧,可以根据需要操作处理结果后,释放Device侧内存<br> (void)acldvppFree(inputDevBuff);<br> (void)acldvppFree(encodeOutBufferDev_);<br>}<br>acldvppDestroyChannel(dvppChannelDesc_);<br>(void)acldvppDestroyChannelDesc(dvppChannelDesc_);<br>dvppChannelDesc_ = nullptr;<br>// 11. 释放运行管理资源(依次释放Stream、Context、Device)<br>aclrtDestroyStream(stream_);<br>aclrtDestroyContext(context_);<br>aclrtResetDevice(0);<br>// 12.AscendCL去初始化<br>aclRet = aclFinalize();<br>// ....<br> |
|---|
父主题: 媒体数据处理V1
PNGD图片解码
PNGD(PNG decoder)负责PNG格式图片的解码。关于PNGD功能的详细介绍及约束请参见功能及约束说明。
本节介绍PNGD图片编码的接口调用流程,同时配合示例代码辅助理解该接口调用流程。
接口调用流程
开发应用时,如果涉及对PNG图片的解码,则应用程序中必须包含图片解码的代码逻辑,关于图片解码的接口调用流程,请先参见AscendCL接口调用流程了解整体流程,再查看本节中的流程说明。
图1 PNG图片解码

当前系统支持png图片的解码,支持输出RGB、RGBA编码格式的图片,关键接口的说明如下:
-
调用acldvppCreateChannel接口创建图片数据处理的通道。
创建图片数据处理的通道前,需先调用acldvppCreateChannelDesc接口创建通道描述信息。
-
实现PNG图片解码功能前,若需要申请Device上的内存存放输入或输出数据,需调用acldvppMalloc申请内存。
在申请输出内存前,可调用acldvppPngPredictDecSize接口根据存放png图片数据的内存计算出png图片解码后所需的输出内存的大小。
-
调用acldvppPngDecodeAsync异步接口进行解码。
对于异步接口,还需调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成。
-
在解码结束后,需及时调用acldvppFree接口释放输入、输出内存。
-
调用acldvppDestroyChannel接口销毁图片数据处理的通道。
销毁图片数据处理的通道后,再调用acldvppDestroyChannelDesc接口销毁通道描述信息。
示例代码
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br>29<br>30<br>31<br>32<br>33<br>34<br>35<br>36<br>37<br>38<br>39<br>40<br>41<br>42<br>43<br>44<br>45<br>46<br>47<br>48<br>49<br>50<br>51<br>52<br>53<br>54<br>55<br>56<br>57<br>58<br>59<br>60<br>61<br>62<br>63<br>64<br>65<br>66<br>67<br>68<br>69<br>70<br>71<br>72<br>73<br>74<br>75<br>76<br>77<br>78<br>79<br>80<br>81<br>82<br>83<br>84<br>85<br>86<br>87<br>88<br>89<br> | <br>// 1.AscendCL初始化<br>aclRet = aclInit(nullptr);<br>// 2.运行管理资源申请(依次申请Device、Context、Stream)<br>aclrtContext context_;<br>aclrtStream stream_;<br>aclrtSetDevice(0);<br>aclrtCreateContext(&context_, 0);<br>aclrtCreateStream(&stream_);<br>// 3.创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型<br>dvppChannelDesc_ = acldvppCreateChannelDesc();<br>// 4.创建图片数据处理的通道。<br>aclError ret = acldvppCreateChannel(dvppChannelDesc_);<br>// 5. 申请输入内存(区分运行状态)<br>// 调用aclrtGetRunMode接口获取软件栈的运行模式,如果调用aclrtGetRunMode接口获取软件栈的运行模式为ACL_HOST,则需要通过aclrtMemcpy接口将输入图片数据传输到Device,数据传输完成后,需及时释放内存;否则直接申请并使用Device的内存<br>aclrtRunMode runMode;<br>ret = aclrtGetRunMode(&runMode);<br>if(runMode == ACL_HOST){<br> <br> void* inputHostBuff = nullptr;<br> inputHostBuff = malloc(inDevBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, inputHostBuff, inDevBufferSize);<br> // 申请Device内存inDevBuffer_<br> aclRet = acldvppMalloc(&inDevBuffer_, inDevBufferSize);<br> // 通过aclrtMemcpy接口将输入图片数据传输到Device<br> aclRet = aclrtMemcpy(inDevBuffer_, inDevBufferSize, inputHostBuff, inDevBufferSize, ACL_MEMCPY_HOST_TO_DEVICE);<br>} else {<br> // 申请Device输入内存inDevBuffer_<br> ret = acldvppMalloc(&inDevBuffer_, inDevBufferSize);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, inDevBuffer_, inDevBufferSize);<br>}<br>// 6. 申请解码输出内存decodeOutDevBuffer_<br>// 计算PNGD处理结果所需的内存大小<br>uint32_t decodeOutBufferSize = 0;<br>ret = acldvppPngPredictDecSize(inputHostBuff, inDevBufferSize, PIXEL_FORMAT_RGB_888,&decodeOutBufferSize)<br>ret = acldvppMalloc(&decodeOutDevBuffer_, decodeOutBufferSize)<br>// 及时释放内存<br>free(inputHostBuff);<br>// 7. 创建解码输出图片的描述信息,设置各属性值<br>// decodeOutputDesc是acldvppPicDesc类型<br>decodeOutputDesc_ = acldvppCreatePicDesc();<br>acldvppSetPicDescData(decodeOutputDesc_, decodeOutDevBuffer_);<br>acldvppSetPicDescFormat(decodeOutputDesc_, PIXEL_FORMAT_RGB_888); <br>acldvppSetPicDescSize(decodeOutputDesc_, decodeOutBufferSize);<br>// 8. 执行异步解码,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成<br>ret = acldvppPngDecodeAsync(dvppChannelDesc_, inDevBuffer_, inDevBufferSize, decodeOutputDesc_, stream_);<br>ret = aclrtSynchronizeStream(stream_);<br>// 9. 解码结束后,释放资源,包括解码输出图片的描述信息、解码输出内存、通道描述信息、通道等<br>acldvppDestroyPicDesc(decodeOutputDesc_);<br>if(runMode == ACL_HOST) { <br> // 该模式下,由于处理结果在Device侧,因此需要调用内存复制接口传输结果数据后,再释放Device侧内存<br> <br> void* OutHostBuffer = nullptr;<br> OutHostBuffer = malloc(decodeOutBufferSize);<br> <br> aclRet = aclrtMemcpy(OutHostBuffer, decodeOutBufferSize, decodeOutDevBuffer_, decodeOutBufferSize, ACL_MEMCPY_DEVICE_TO_HOST);<br> // 释放掉输入输出的device内存<br> (void)acldvppFree(inDevBuffer_);<br> (void)acldvppFree(decodeOutDevBuffer_);<br> // 数据使用完成后,释放内存<br> free(OutHostBuffer);<br>} else { <br> // 此时运行在device侧,处理结果也在Device侧,可以根据需要操作处理结果后,释放Device侧内存<br> (void)acldvppFree(inDevBuffer_);<br> (void)acldvppFree(decodeOutDevBuffer_);<br>}<br>acldvppDestroyChannel(dvppChannelDesc_);<br>(void)acldvppDestroyChannelDesc(dvppChannelDesc_);<br>dvppChannelDesc_ = nullptr;<br>// 10. 释放运行管理资源(依次释放Stream、Context、Device)<br>aclrtDestroyStream(stream_);<br>aclrtDestroyContext(context_);<br>aclrtResetDevice(0);<br>// 11.AscendCL去初始化<br>aclRet = aclFinalize();<br>// ....<br> |
|---|
父主题: 媒体数据处理V1
VDEC视频解码
VDEC(Video Decoder)负责将H264/H265格式的视频码流解码为YUV/RGB格式的图片。关于VDEC功能的详细介绍及约束请参见功能及约束说明。
本节介绍VDEC视频编码的接口调用流程,同时配合示例代码辅助理解该接口调用流程。
接口调用流程
开发应用时,如果涉及视频解码,则应用程序中必须包含视频解码的代码逻辑,关于视频解码的接口调用流程,请先参见AscendCL接口调用流程了解整体流程,再查看本节中的流程说明。
图1 视频解码流程

实现视频的解码,关键接口的说明如下:
- 调用aclvdecCreateChannel接口创建视频解码处理的通道。
- 创建视频解码处理通道前,需先执行以下操作:
-
调用aclvdecCreateChannelDesc接口创建通道描述信息。
-
调用aclvdecSetChannelDesc系列接口设置通道描述信息的属性,包括解码通道号、线程、回调函数、视频编码协议等,其中:
-
回调函数需由用户提前创建,用于在视频解码后,获取解码数据,并及时释放相关资源,回调函数的原型请参见aclvdecCallback。
在回调函数内,用户需调用acldvppGetPicDescRetCode接口获取retCode返回码判断是否解码成功,retCode为0表示解码成功,为1表示解码失败。如果解码失败,需要根据日志中的返回码判断具体的问题,返回码请参见返回码说明。
解码结束后,建议用户在回调函数内及时释放VDEC的输入码流内存、输出图片内存以及相应的视频码流描述信息、图片描述信息。
-
线程需由用户提前创建,并自定义线程函数,在线程函数内调用aclrtProcessReport接口,等待指定时间后,触发1.b.i中的回调函数。
:::note 说明 如果不调用aclvdecSetChannelDescOutPicFormat接口设置输出格式,则默认使用YUV420SP NV12。 :::
-
-
- aclvdecCreateChannel接口内部封装了如下接口,无需用户单独调用:
- aclrtCreateStream接口:显式创建Stream,VDEC内部使用。
- aclrtSubscribeReport接口:指定处理Stream上回调函数的线程,回调函数和线程是由用户调用aclvdecSetChannelDesc系列接口时指定的。
- 创建视频解码处理通道前,需先执行以下操作:
- 调用aclvdecSendFrame接口将视频码流解码成YUV420SP格式的图片。
-
**视频解码前,**需先执行以下操作:
- 调用acldvppCreateStreamDesc接口创建输入视频码流描述信息,并调用acldvppSetStreamDesc系列接口设置输入视频的内存地址、内存大小、码流格式等属性。
- 调用acldvppCreatePicDesc接口创建输出图片描述信息,并调用acldvppSetPicDesc系列接口设置输出图片的内存地址、内存大小、图片格式等属性。
-
视频解码时:
aclvdecSendFrame接口内部封装了aclrtLaunchCallback接口,用于在Stream的任务队列中增加一个需要执行的回调函数。用户无需单独调用aclrtLaunchCallback接口。
-
视频解码后,视频解码的结果数据通过回调函数获取:
获取解码数据前,先获取retCode的值,判断解码是否成功,0表示解码成功,1表示解码失败。如果解码失败,需要根据日志中的返回码判断具体的问题,返回码请参见返回码说明。
如果用户需要获取解码的帧序号,则可以在aclvdecSendFrame接口的userData参数处定义,然后解码的帧序号可以通过userData参数传递给VDEC的回调函数,用于确定回调函数中处理的是第几帧数据。
如果不想获取某一帧的解码结果, 可以调用aclvdecSendSkippedFrame接口, 将待解码的码流(输入内存)传到解码器进行解码,此时,解码结果最终不会输出,解码完成的回调函数中返回的output为nullptr。
-
- 调用aclvdecDestroyChannel接口销毁视频处理的通道。
- 系统会等待已发送帧解码完成且用户的回调函数处理完成后再销毁通道。
- aclvdecDestroyChannel接口内部封装了如下接口,无需用户单独调用:
- aclrtUnSubscribeReport接口:取消线程注册(Stream上的回调函数不再由指定线程处理)。
- aclrtDestroyStream接口:销毁Stream。
- 销毁通道后,需调用aclvdecDestroyChannelDesc接口销毁通道描述信息。
- 销毁通道描述信息后,用户才可以销毁1.b.ii中创建的线程。
示例代码
您可以从样例介绍中获取完整样例代码。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br> 43<br> 44<br> 45<br> 46<br> 47<br> 48<br> 49<br> 50<br> 51<br> 52<br> 53<br> 54<br> 55<br> 56<br> 57<br> 58<br> 59<br> 60<br> 61<br> 62<br> 63<br> 64<br> 65<br> 66<br> 67<br> 68<br> 69<br> 70<br> 71<br> 72<br> 73<br> 74<br> 75<br> 76<br> 77<br> 78<br> 79<br> 80<br> 81<br> 82<br> 83<br> 84<br> 85<br> 86<br> 87<br> 88<br> 89<br> 90<br> 91<br> 92<br> 93<br> 94<br> 95<br> 96<br> 97<br> 98<br> 99<br>100<br>101<br>102<br>103<br>104<br>105<br>106<br>107<br>108<br>109<br>110<br>111<br>112<br>113<br>114<br>115<br>116<br>117<br>118<br>119<br>120<br>121<br>122<br>123<br>124<br>125<br>126<br>127<br>128<br>129<br>130<br>131<br>132<br>133<br> | cpp<br>// 1.AscendCL初始化<br>aclRet = aclInit(nullptr);<br>// 2.运行管理资源申请(依次申请Device、Context、Stream)<br>aclrtContext context_;<br>aclrtStream stream_;<br>aclrtSetDevice(0);<br>aclrtCreateContext(&context_, 0);<br>aclrtCreateStream(&stream_);<br>// 3.创建回调函数<br>void callback(acldvppStreamDesc *input, acldvppPicDesc *output, void *userdata)<br>{<br> static int count = 1;<br> if (output != nullptr) {<br> // 获取VDEC解码的输出内存,调用自定义函数WriteToFile将输出内存中的数据写入文件后,再调用acldvppFree接口释放输出内存<br> void *vdecOutBufferDev = acldvppGetPicDescData(output);<br> if (vdecOutBufferDev != nullptr) {<br> // 0: vdec success; others, vdec failed<br> // retCode为0表示解码成功,为1表示解码失败<br> int retCode = acldvppGetPicDescRetCode(output);<br> if (retCode == 0) {<br> // process task: write file<br> uint32_t size = acldvppGetPicDescSize(output);<br> std::string fileNameSave = "outdir/image" + std::to_string(count);<br> // vdec输出结果在device侧,在WriteToFile方法中进行下述处理<br> if (!Utils::WriteToFile(fileNameSave.c_str(), vdecOutBufferDev, size)) {<br> ERROR_LOG("write file failed.");<br> }<br> } else {<br> ERROR_LOG("vdec decode frame failed.");<br> }<br> // free output vdecOutBufferDev<br> aclError ret = acldvppFree(vdecOutBufferDev);<br> }<br> // 释放acldvppPicDesc类型的数据,表示解码后输出图片描述数据<br> aclError ret = acldvppDestroyPicDesc(output);<br> }<br> // free input vdecInBufferDev and destroy stream desc<br> if (input != nullptr) {<br> void *vdecInBufferDev = acldvppGetStreamDescData(input);<br> if (vdecInBufferDev != nullptr) {<br> aclError ret = acldvppFree(vdecInBufferDev);<br> }<br> // 释放acldvppStreamDesc类型的数据,表示解码的输入码流描述数据<br> aclError ret = acldvppDestroyStreamDesc(input);<br> }<br> INFO_LOG("success to callback %d.", count);<br> count++;<br>}<br>// 4.创建视频码流处理通道时的通道描述信息,设置视频处理通道描述信息的属性,其中线程、callback回调函数需要用户提前创建。<br>// vdecChannelDesc_是aclvdecChannelDesc类型<br>vdecChannelDesc_ = aclvdecCreateChannelDesc();<br>ret = aclvdecSetChannelDescChannelId(vdecChannelDesc_, 10);<br>ret = aclvdecSetChannelDescThreadId(vdecChannelDesc_, threadId_);<br>ret = aclvdecSetChannelDescCallback(vdecChannelDesc_, callback);<br>// 示例中使用的是H265_MAIN_LEVEL视频编码协议<br>ret = aclvdecSetChannelDescEnType(vdecChannelDesc_, static_cast<acldvppStreamFormat>(enType_));<br>// 示例中使用的是PIXEL_FORMAT_YVU_SEMIPLANAR_420<br>ret = aclvdecSetChannelDescOutPicFormat(vdecChannelDesc_, static_cast<acldvppPixelFormat>(format_));<br>// 5.创建视频码流处理的通道<br>ret = aclvdecCreateChannel(vdecChannelDesc_);<br>// 6.申请输入码流内存(区分运行状态)<br>// 调用aclrtGetRunMode接口获取软件栈的运行模式,如果调用aclrtGetRunMode接口获取软件栈的运行模式为ACL_HOST,则需要通过aclrtMemcpy接口将输入图片数据传输到Device,数据传输完成后,需及时释放内存;否则直接申请并使用Device的内存<br>aclrtRunMode runMode;<br>ret = aclrtGetRunMode(&runMode);<br>if(runMode == ACL_HOST){ <br> <br> void* inputHostBuff= nullptr;<br> // inBufferSize_为输入码流大小<br> inputHostBuff= malloc(inBufferSize_);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, inputHostBuff, inBufferSize_);<br> // 申请Device内存inBufferDev_<br> aclRet = acldvppMalloc(&inBufferDev_, inBufferSize_);<br> // 通过aclrtMemcpy接口将输入图片数据传输到Device<br> aclRet = aclrtMemcpy(inBufferDev_, inBufferSize_, inputHostBuff, inBufferSize_, ACL_MEMCPY_HOST_TO_DEVICE);<br> // 数据传输完成后,及时释放内存<br> free(inputHostBuff);<br>} else {<br> // 申请Device输入内存dataDev, StreamBufferSize为输入码流大小<br> ret = acldvppMalloc(&inBufferDev_, inBufferSize_);<br> // 将输入图片读入内存中,该自定义函数ReadPicFile由用户实现<br> ReadPicFile(picName, inBufferDev_, inBufferSize_);<br>}<br>// 7.循环10次执行视频解码,输出10张YUV420SP NV12格式的图片<br>int rest_len = 10;<br>int32_t count = 0;<br>while (rest_len > 0) {<br> // 7.1 创建输入视频码流描述信息,设置码流信息的属性<br> streamInputDesc_ = acldvppCreateStreamDesc(); <br> // inBufferDev_表示Device存放输入视频数据的内存,inBufferSize_表示内存大小 <br> ret = acldvppSetStreamDescData(streamInputDesc_, inBufferDev_);<br> ret = acldvppSetStreamDescSize(streamInputDesc_, inBufferSize_);<br> // 7.2 申请Device内存picOutBufferDev_,用于存放VDEC解码后的输出数据<br> ret = acldvppMalloc(&picOutBufferDev_, size);<br> // 7.3 创建输出图片描述信息,设置图片描述信息的属性<br> // picOutputDesc_是acldvppPicDesc类型<br> picOutputDesc_ = acldvppCreatePicDesc();<br> ret = acldvppSetPicDescData(picOutputDesc_, picOutBufferDev_);<br> ret = acldvppSetPicDescSize(picOutputDesc_, size);<br> ret = acldvppSetPicDescFormat(picOutputDesc_, static_cast<acldvppPixelFormat>(format_));<br> // 7.4 执行视频码流解码,解码每帧数据后,系统自动调用callback回调函数将解码后的数据写入文件,再及时释放相关资源<br> ret = aclvdecSendFrame(vdecChannelDesc_, streamInputDesc_, picOutputDesc_, nullptr, nullptr);<br> // ......<br> ++count;<br> rest_len = rest_len - 1;<br> // ......<br>}<br>// 8.释放图片处理通道、图片描述信息<br>ret = aclvdecDestroyChannel(vdecChannelDesc_);<br>aclvdecDestroyChannelDesc(vdecChannelDesc_);<br>// 9. 释放运行管理资源(依次释放Stream、Context、Device)<br>aclrtDestroyStream(stream_);<br>aclrtDestroyContext(context_);<br>aclrtResetDevice(0);<br>// 10.AscendCL去初始化<br>aclRet = aclFinalize();<br>// ......<br> |
|---|
返回码说明
表1 返回码列表
| 返回码 | 含义 | 可能原因及解决方法 |
|---|---|---|
| AICPU_DVPP_KERNEL_STATE_SUCCESS = 0 | 解码成功。 | - |
| AICPU_DVPP_KERNEL_STATE_FAILED = 1 | 其它错误。 | - |
| AICPU_DVPP_KERNEL_STATE_DVPP_ERROR = 2 | AscendCL内部调用其它模块的接口失败。 | - |
| AICPU_DVPP_KERNEL_STATE_PARAM_INVALID = 3 | 参数校验失败。 | 请检查接口的参数是否符合接口要求。 |
| AICPU_DVPP_KERNEL_STATE_OUTPUT_SIZE_INVALID = 4 | 输出内存大小校验失败。 | 请检查输出内存大小是否符合接口要求。 |
| AICPU_DVPP_KERNEL_STATE_INTERNAL_ERROR = 5 | 系统内部错误。 | - |
| AICPU_DVPP_KERNEL_STATE_QUEUE_FULL = 6 | 系统内部队列满。 | - |
| AICPU_DVPP_KERNEL_STATE_QUEUE_EMPTY = 7 | 系统内部队列空。 | - |
| AICPU_DVPP_KERNEL_STATE_QUEUE_NOT_EXIST = 8 | 系统内部队列不存在。 | - |
| AICPU_DVPP_KERNEL_STATE_GET_CONTEX_FAILED = 9 | 获取系统内部上下文失败。 | - |
| AICPU_DVPP_KERNEL_STATE_SUBMIT_EVENT_FAILED = 10 | 提交系统内部事件失败。 | - |
| AICPU_DVPP_KERNEL_STATE_MEMORY_FAILED = 11 | 系统内部申请内存失败。 | 请检查系统是否有可用内存。 |
| AICPU_DVPP_KERNEL_STATE_SEND_NOTIFY_FAILED = 12 | 发送系统内部通知失败。 | - |
| AICPU_DVPP_KERNEL_STATE_VPC_OPERATE_FAILED = 13 | 系统内部接口处理失败。 | - |
| AICPU_DVPP_KERNEL_STATE_CHANNEL_ABNORMAL = 14 | 当前通道异常。 | - |
| ERR_INVALID_STATE = 0x10001 | VDEC解码器状态异常错误。 | - |
| ERR_HARDWARE = 0x10002 | 硬件错误,包含解码器启动、执行、停止等异常。 | - |
| ERR_SCD_CUT_FAIL = 0x10003 | 将视频码流分解成多帧图片异常。 | 请检查输入的视频流数据是否正确。 |
| ERR_VDM_DECODE_FAIL = 0x10004 | 解码某一帧异常。 | 请检查输入的视频流数据是否正确。 |
| ERR_ALLOC_MEM_FAIL = 0x10005 | 内部申请内存失败。 | 请检查系统是否有可用内存,若忽略错误,则可能导致用户持续送入码流却无任何解码结果输出。 |
| ERR_ALLOC_DYNAMIC_MEM_FAIL = 0x10006 | 包括输入视频分辨率超范围、内部动态申请内存失败等异常。 | 请检查输入视频流的分辨率、系统是否有可用内存,若忽略错误,则可能导致用户持续送入码流却无任何解码结果输出。 |
| ERR_ALLOC_IN_OR_OUT_PORT_MEM_FAIL = 0x10007 | 系统内部申请VDEC的输入、输出buffer异常。 | 请检查系统是否有可用内存,若忽略错误,则可能导致用户持续送入码流却无任何解码结果输出。 |
| ERR_BITSTREAM = 0x10008 | 码流错误(如语法解析失败、重发eos或首帧即发送eos)。 | 请检查输入的视频流数据是否正确。 |
| ERR_VIDEO_FORMAT = 0x10009 | 输入视频格式错误。 | 请检查输入视频的格式是否为h264或h265。 |
| ERR_IMAGE_FORMAT = 0x1000a | 输出格式配置错误。 | 请检查输出图像的格式是否为nv12或nv21。 |
| ERR_CALLBACK = 0x1000b | 回调函数为空。 | 请检查配置的回调函数是否为空。 |
| ERR_INPUT_BUFFER = 0x1000c | 输入内存为空。 | 请检输入内存是否为空。 |
| ERR_INBUF_SIZE = 0x1000d | 输入内存大小<=0。 | 请检查输入内存大小是否小于等于0。 |
| ERR_THREAD_CREATE_FBD_FAIL = 0x1000e | 系统内部将解码结果通过回调函数返回给用户的线程异常。 | 请检查系统中资源(例如:线程、内存等)是否可用。 |
| ERR_CREATE_INSTANCE_FAIL = 0x1000f | 创建解码实例失败。 | - |
| ERR_INIT_DECODER_FAIL = 0x10010 | 初始化解码器失败,例如解码实例个数超出范围(最大16)。 | - |
| ERR_GET_CHANNEL_HANDLE_FAIL = 0x10011 | 系统内部获取某路视频流的解码句柄失败。 | - |
| ERR_COMPONENT_SET_FAIL = 0x10012 | 系统内部设置解码实例异常。 | 请检查解码的入参值是否正确,例如输入视频格式video_format、输出帧格式image_format等。 |
| ERR_COMPARE_NAME_FAIL = 0x10013 | 系统内部设置解码实例名称异常。 | 请检查解码的入参值是否正确,例如输入视频格式video_format、输出帧格式image_format等。 |
| ERR_OTHER = 0x10014 | 其它错误。 | - |
| ERR_DECODE_NOPIC = 0x20000 | 隔行码流场景下使用,隔行码流每帧发送两场,解码时其中一块无图像输出,属于正常现象,会返回该错误码;隔行码流的解码输出数据都在奇数场对应的输出buffer中。 | - |
| 0x20001 | 参考帧个数设置错误。 | 请检查码流实际参考帧个数与用户设置的参考帧个数是否一致。 |
| 0x20002 | VDEC解码帧存大小设置错误。 | 请检查输入码流实际宽、高与用户设置的宽、高是否一致。 |
| 0xA0058001 | 无效的Device ID。 | 请检查Device ID。 |
| 0xA0058002 | 无效的channel ID。 | 请检查传入接口的通道号是否正确,或者检查通道总数是否达到上限。 |
| 0xA0058003 | 参数不合法,例如不合法的枚举值。 | 请根据日志检查出错的参数。 |
| 0xA0058004 | 资源已存在。 | 请检查是否重复创建通道。 |
| 0xA0058005 | 通道资源不存在。 | 请检查是否使用了不存在的通道号或通道句柄。 |
| 0xA0058006 | 函数参数中有空指针。 | 请根据日志检查接口的入参。 |
| 0xA0058007 | 使能系统、Device或通道前未配置对应的参数。 | 请根据日志检查接口的入参。 |
| 0xA0058008 | 不支持的参数或者功能。 | 请根据日志检查接口的入参。 |
| 0xA0058009 | 该操作不允许,如试图修改静态配置参数。 | - |
| 0xA005800C | 分配内存失败,如系统内存不足。 | 请检查系统是否有可用内存,若忽略错误,则可能导致用户持续送入码流却无任何解码结果输出。 |
| 0xA005800D | 分配缓存失败,如申请的数据缓冲区太大。 | - |
| 0xA005800E | 缓冲区中无数据。 | 系统未完成解码,缓冲区中无解码结果数据,需等待缓冲区中有数据后,再尝试获取数据。 |
| 0xA005800F | 缓冲区中数据满。 | 用户发送输入码流数据的速度太快,导致输入缓冲区数据满,请尝试降低发送输入码流数据的速度,或者在创建通道时将缓冲区大小设置为较大值。 |
| 0xA0058010 | 系统没有初始化或者相关依赖的模块没有加载。 | 请检查是否调用系统初始化接口。 |
| 0xA0058011 | 地址错误。 | - |
| 0xA0058012 | 系统忙。 | 请检查VDEC解码总路数是否达到上限。 |
| 0xA0058013 | 缓存小于实际需要的大小。 | - |
| 0xA0058014 | 硬件或软件处理超时。 | - |
| 0xA0058015 | 内部系统错误。 | - |
| 0xA005803F | 最大的返回码,该模块的错误码必须小于该值。 | - |
父主题: 媒体数据处理V1
VENC视频编码
VENC(Video Encoder)将YUV420SP格式的图片编码成H264/H265格式的视频码流。关于VENC功能的详细介绍及约束请参见功能及约束说明。
本节介绍VENC视频编码的接口调用流程,同时配合示例代码辅助理解该接口调用流程。
接口调用流程
开发应用时,如果涉及视频编码,则应用程序中必须包含视频编码的代码逻辑,关于视频编码的接口调用流程,请先参见AscendCL接口调用流程了解整体流程,再查看本节中的流程说明。
图1 视频编码流程

实现视频的编码,关键接口的说明如下:
- 调用aclvencCreateChannel接口创建视频编码处理的通道。
- 创建视频编码处理通道前,需先执行以下操作:
-
调用aclvencCreateChannelDesc接口创建通道描述信息。
-
调用aclvencSetChannelDescParam接口设置通道描述信息的属性,包括线程、回调函数、视频编码协议、输入图片格式等,其中:
-
回调函数需由用户提前创建,用于在视频编码后,获取编码数据,并及时释放相关资源,回调函数的原型请参见aclvencCallback。
视频编码结束后,建议用户在回调函数内及时释放输入图片内存、以及相应的图片描述信息。视频编码的输出内存由系统管理,不由用户管理,因此无需用户释放。
-
线程需由用户提前创建,并自定义线程函数,在线程函数内调用aclrtProcessReport接口,等待指定时间后,触发1.b.i中的回调函数。
:::note 说明 推荐使用aclvencSetChannelDescParam接口设置通道描述信息的属性,通过枚举值来选择通过该接口设置某一个属性的值。
但为兼容旧版本,也可以调用aclvencSetChannelDesc系列接口设置通道描述信息的属性,每个属性的设置对应一个set接口。 :::
-
-
- aclvencCreateChannel接口内部封装了如下接口,无需用户单独调用:
- aclrtCreateStream接口:显式创建Stream,VENC内部使用。
- aclrtSubscribeReport接口:指定处理Stream上回调函数的线程,回调函数和线程是由用户调用aclvencSetChannelDescParam接口时指定的。
- 创建视频编码处理通道前,需先执行以下操作:
- 调用aclvencSendFrame接口将YUV420SP格式的图片编码成H264/H265格式的视频码流。
- 视频编码前,需先执行以下操作:
- 调用acldvppCreatePicDesc接口创建输入图片描述信息,并调用acldvppSetPicDesc系列接口设置输入图片的内存地址、内存大小、图片格式等属性。
- 调用aclvencCreateFrameConfig接口创建单帧编码配置数据,并调用aclvencSetFrameConfig系列接口设置是否强制重新开始I帧间隔、是否结束帧。
- 视频编码时,aclvencSendFrame接口内部封装了aclrtLaunchCallback接口,用于在Stream的任务队列中增加一个需要执行的回调函数。用户无需单独调用aclrtLaunchCallback接口。
- 视频编码后,视频编码的结果数据通过回调函数获取。
- 视频编码前,需先执行以下操作:
- 调用aclvencDestroyChannel接口销毁视频处理的通道。
- 系统会等待已发送帧编码完成且用户的回调函数处理完成后再销毁通道。
- aclvencDestroyChannel接口内部封装了如下接口,无需用户单独调用:
- aclrtUnSubscribeReport接口:取消线程注册(Stream上的回调函数不再由指定线程处理)。
- aclrtDestroyStream接口:销毁Stream。
- 销毁通道后,需调用aclvencDestroyChannelDesc接口销毁通道描述信息。
- 销毁通道描述信息后,用户才可以销毁1.b.ii中创建的线程。
示例代码
您可以从样例介绍中获取完整样例代码。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> 41<br> 42<br> 43<br> 44<br> 45<br> 46<br> 47<br> 48<br> 49<br> 50<br> 51<br> 52<br> 53<br> 54<br> 55<br> 56<br> 57<br> 58<br> 59<br> 60<br> 61<br> 62<br> 63<br> 64<br> 65<br> 66<br> 67<br> 68<br> 69<br> 70<br> 71<br> 72<br> 73<br> 74<br> 75<br> 76<br> 77<br> 78<br> 79<br> 80<br> 81<br> 82<br> 83<br> 84<br> 85<br> 86<br> 87<br> 88<br> 89<br> 90<br> 91<br> 92<br> 93<br> 94<br> 95<br> 96<br> 97<br> 98<br> 99<br>100<br>101<br>102<br>103<br>104<br>105<br>106<br>107<br>108<br>109<br>110<br>111<br>112<br>113<br>114<br>115<br>116<br>117<br>118<br>119<br>120<br>121<br>122<br>123<br>124<br>125<br> | <br>// 1.AscendCL初始化<br>aclRet = aclInit(nullptr);<br>// 2.运行管理资源申请(依次申请Device、Context、Stream)<br>aclrtContext context_;<br>aclrtStream stream_;<br>aclrtSetDevice(0);<br>aclrtCreateContext(&context_, 0);<br>aclrtCreateStream(&stream_);<br>// 3.创建执行回调函数的线程及线程函数<br>static bool runFlag = true;<br>void *ThreadFunc(void *arg)<br>{<br> // Notice: create context for this thread<br> int deviceId = 0;<br> aclrtContext context = nullptr;<br> aclError ret = aclrtCreateContext(&context, deviceId);<br> INFO_LOG("process callback thread start ");<br> while (runFlag) {<br> // Notice: timeout 1000ms<br> (void)aclrtProcessReport(1000);<br> }<br> // ......<br> ret = aclrtDestroyContext(context);<br> return (void*)0;<br>}<br>int createThreadErr = pthread_create(&threadId_, nullptr, ThreadFunc, nullptr);<br>// 4.创建回调函数<br>void callback(acldvppPicDesc *input, acldvppStreamDesc *outputStreamDesc, void *userdata)<br>{<br> // 获取视频编码结果数据,并写入文件<br> void *outputDev = acldvppGetStreamDescData(outputStreamDesc);<br> uint32_t streamDescSize = acldvppGetStreamDescSize(outputStreamDesc);<br> if (!Utils::WriteToFile(g_outFileFp, outputDev, streamDescSize)) {<br> ERROR_LOG("write file:%s failed.", g_outFile.c_str());<br> }<br> INFO_LOG("success to callback, stream size:%u", streamDescSize);<br>}<br>// 5.创建视频编码处理通道时的通道描述信息,设置通道描述信息的属性,其中线程、callback回调函数需要用户提前创建<br>// vencChannelDesc_是aclvdecChannelDesc类型<br>vencChannelDesc_ = aclvencCreateChannelDesc();<br>auto ret = aclvencSetChannelDescThreadId(vencChannelDesc_, threadId_);<br>ret = aclvencSetChannelDescCallback(vencChannelDesc_, callback);<br>ret = aclvencSetChannelDescEnType(vencChannelDesc_, enType_);<br>ret = aclvencSetChannelDescPicFormat(vencChannelDesc_, format_);<br>ret = aclvencSetChannelDescPicWidth(vencChannelDesc_, 128);<br>ret = aclvencSetChannelDescPicHeight(vencChannelDesc_, 128);<br>ret = aclvencSetChannelDescKeyFrameInterval(vencChannelDesc_, 16);<br>// 6.创建视频码流处理的通道、单帧编码配置数据<br>ret = aclvencCreateChannel(vencChannelDesc_);<br>// vencFrameConfig_是aclvencFrameConfig类型<br>vencFrameConfig_ = aclvencCreateFrameConfig();<br>// 7.申请Device内存dataDev,存放视频编码的输入数据<br>// 7.1 读入图片数据<br>const char *fileName = "../dvpp_venc_128x128_nv12.yuv";<br>FILE *fp = fopen(fileName, "rb+");<br>fseek(fp, 0, SEEK_END);<br>long fileLenLong = ftell(fp);<br>fseek(fp, 0, SEEK_SET);<br>auto fileLen = static_cast<uint32_t>(fileLenLong);<br>uint32_t dataSize = fileLen;<br>// 调用aclrtGetRunMode接口获取软件栈的运行模式,如果调用aclrtGetRunMode接口获取软件栈的运行模式为ACL_HOST,则需要通过aclrtMemcpy接口将输入图片数据传输到Device,数据传输完成后,需及时释放内存;否则直接申请并使用Device的内存<br>aclrtRunMode runMode;<br>ret = aclrtGetRunMode(&runMode);<br>if(runMode == ACL_HOST) { <br> void *dataHost = malloc(fileLen);<br> size_t readSize = fread(dataHost, 1, fileLen, fp)<br> void *dataDev = nullptr;<br> ret = acldvppMalloc(&dataDev, dataSize);<br> ret = aclrtMemcpy(dataDev, dataSize, dataHost, fileLen, ACL_MEMCPY_HOST_TO_DEVICE);<br> // 完成数据传输后,需及时释放内存<br> free(dataHost);<br>} <br>else { <br> ret = acldvppMalloc(&dataDev, dataSize);<br>}<br>// 8.执行视频编码<br>size_t g_vencCnt = 16;<br>// 8.1 创建输入图片描述信息,设置输入图片数据的内存地址和内存大小<br>inputPicputDesc_ = acldvppCreatePicDesc();<br>ret = acldvppSetPicDescData(inputPicputDesc_, dataDev);<br>ret = acldvppSetPicDescSize(inputPicputDesc_, dataSize);<br>// 8.2 设置单帧编码配置数据,不是结束帧<br>ret = aclvencSetFrameConfigEos(vencFrameConfig_, 0);<br>ret = aclvencSetFrameConfigForceIFrame(vencFrameConfig_, 0)<br>// 8.3 创建输出码流描述信息<br>acldvppStreamDesc *outputStreamDesc = nullptr;<br>// 8.4 执行视频编码<br>while (g_vencCnt > 0) {<br> ret = aclvencSendFrame(vencChannelDesc_, inputPicputDesc_,<br> static_cast<void *>(outputStreamDesc), vencFrameConfig_, nullptr);<br> g_vencCnt--;<br> }<br>// 8.5 设置单帧编码配置数据,是结束帧<br>ret = aclvencSetFrameConfigEos(vencFrameConfig_, 1);<br>ret = aclvencSetFrameConfigForceIFrame(vencFrameConfig_, 0)<br>// 8.6 执行最后一帧的视频编码<br>ret = aclvencSendFrame(vencChannelDesc_, nullptr, nullptr, vencFrameConfig_, nullptr);<br>// 9.释放资源<br>(void)aclvencDestroyChannel(vencChannelDesc_);<br>(void)aclvencDestroyChannelDesc(vencChannelDesc_);<br>(void)acldvppDestroyPicDesc(inputPicputDesc_);<br>(void)aclvencDestroyFrameConfig(vencFrameConfig_);<br>// 释放内存和销毁线程<br>(void)acldvppFree(inBufferDev_);<br>void *res = nullptr;<br>int joinThreadErr = pthread_join(threadId_, &res);<br>// 10. 释放运行管理资源(依次释放Stream、Context、Device)<br>aclrtDestroyStream(stream_);<br>aclrtDestroyContext(context_);<br>aclrtResetDevice(0);<br>// 11.AscendCL去初始化<br>aclRet = aclFinalize();<br>// ......<br> |
|---|
如果调用aclvencSetChannelDescParam接口设置通道描述信息的属性,调用aclvencGetChannelDescParam接口获取通道描述信息中的属性值,示例代码如下:
// 设置回调函数
void *func = (void *)callback;
aclvencSetChannelDescParam(vencChannelDesc_, ACL_VENC_CALLBACK_PTR, 8, &func);
// 获取回调函数
void *func1 = nullptr;
aclvencGetChannelDescParam(vencChannelDesc_, ACL_VENC_CALLBACK_PTR, 8, &len, &func1);
// 设置输入图片格式
acldvppPixelFormat format = PIXEL_FORMAT_YUV_SEMIPLANAR_420;
aclvencSetChannelDescParam(vencChannelDesc_, ACL_VENC_PIXEL_FORMAT_UINT32, 4, &format);
// 获取输入图片格式
acldvppPixelFormat format1 = PIXEL_FORMAT_YUV_SEMIPLANAR_420;
aclvencGetChannelDescParam(vencChannelDesc_, ACL_VENC_PIXEL_FORMAT_UINT32, 4, &len, &format1);
// 设置图片宽度
uint32_t width = 128;
aclvencSetChannelDescParam(vencChannelDesc_, ACL_VENC_PIC_WIDTH_UINT32, 4, &width);
// 获取图片高度
uint32_t width1 = 0;
aclvencGetChannelDescParam(vencChannelDesc_, ACL_VENC_PIC_WIDTH_UINT32, 4, &len, &width1);
// 设置图片高度
uint32_t height = 128;
aclvencSetChannelDescParam(vencChannelDesc_, ACL_VENC_PIC_HEIGHT_UINT32, 4, &height);
// 获取图片高度
uint32_t height1 = 0;
aclvencGetChannelDescParam(vencChannelDesc_, ACL_VENC_PIC_HEIGHT_UINT32, 4, &len, &height1);
// 设置编码输出缓存地址
ret = acldvppMalloc(&buf, bufSize);
aclvencSetChannelDescParam(vencChannelDesc_, ACL_VENC_BUF_ADDR_PTR, 8, &buf);
// 获取编码输出缓存地址
void *buf1 = nullptr;
aclvencGetChannelDescParam(vencChannelDesc_, ACL_VENC_BUF_ADDR_PTR, 8, &len, &buf1);
父主题: 媒体数据处理V1
在线提单