首页问答详情

hi3559AV 硬解码mp4,ts等封装好的视频

¥ 10
已结题
     
金富贵
金富贵  发布于  2022-02-25 15:38:36
采纳率 0%
3个问答

由于项目需要,需要在hi3559 平台上做播放器,用海思自带的demo 是跑通了,但是他解码的是.h264 和.h265等纯码流形式的视频,但是项目需要直接打开mp4,ts,flv等封装好的视频文件,现在思路是想用ffmpeg 去解封装,然后解封装之后的数据去给海思解码通道去解码。ffmpeg解封装代码```cpp
int dcodec_open(const char *url)
{

  1. // 初始化格式上下文
  2. AVFormatContext *fmt_ctx =NULL;
  3. fmt_ctx = avformat_alloc_context();
  4. if (fmt_ctx == NULL) {
  5. printf("failed to alloc format context\n");
  6. goto _Error;
  7. }
  8. // 打开输入流
  9. if (avformat_open_input(&fmt_ctx, url, NULL, NULL) < 0) {
  10. printf("failed to open input url\n");
  11. goto _Error;
  12. }
  13. // 读取媒体文件信息
  14. if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
  15. printf("failed to find stream\n");
  16. goto _Error;
  17. }
  18. av_dump_format(fmt_ctx, 0, url, 0);
  19. // 寻找音频流和视频流下标
  20. int video_index = -1, audio_index = -1;
  21. for (int i = 0; i < fmt_ctx->nb_streams; i++) {
  22. if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
  23. printf("video_index\n");
  24. video_index = i;
  25. }
  26. }
  27. auto streams =fmt_ctx->streams;
  28. // 由打印的视频文件信息确定码流类型
  29. char videofile[128];
  30. printf("\ntype the name of output videofile:");
  31. scanf("%s", videofile);
  32. FILE *fvideo = fopen(videofile, "w+");
  33. AVPacket *packet = av_packet_alloc();
  34. while (av_read_frame(fmt_ctx, packet) == 0) {
  35. if (packet->stream_index == video_index) {
  36. fwrite(packet->data, 1, packet->size, fvideo);
  37. }
  38. av_packet_unref(packet);
  39. }
  40. Error
  41. if (fmt_ctx) avformat_close_input(&fmt_ctx);
  42. if (fvideo) fclose(fvideo);
  43. if (packet) av_packet_free(&packet);

}
然后下面是sample vdec里面的COMM_VDEC_SendStream 函数代码片段

  1. HI_VOID * COMM_VDEC_SendStream(HI_VOID *pArgs)
  2. {
  3. VDEC_THREAD_PARAM_S *pstVdecThreadParam =(VDEC_THREAD_PARAM_S *)pArgs;
  4. HI_BOOL bEndOfStream = HI_FALSE;
  5. HI_S32 s32UsedBytes = 0, s32ReadLen = 0;
  6. FILE *fpStrm=NULL;
  7. HI_U8 *pu8Buf = NULL;
  8. VDEC_STREAM_S stStream;
  9. HI_BOOL bFindStart, bFindEnd;
  10. HI_U64 u64PTS = 0;
  11. HI_U32 u32Len, u32Start;
  12. HI_S32 s32Ret, i;
  13. HI_CHAR cStreamFile[256];
  14. prctl(PR_SET_NAME, "VideoSendStream", 0,0,0);
  15. snprintf(cStreamFile, sizeof(cStreamFile), "%s/%s", pstVdecThreadParam->cFilePath,pstVdecThreadParam->cFileName);
  16. if(cStreamFile != 0)
  17. {
  18. fpStrm = fopen(cStreamFile, "rb");
  19. if(fpStrm == NULL)
  20. {
  21. SAMPLE_PRT("chn %d can't open file %s in send stream thread!\n", pstVdecThreadParam->s32ChnId, cStreamFile);
  22. return (HI_VOID *)(HI_FAILURE);
  23. }
  24. }
  25. printf("\n \033[0;36m chn %d, stream file:%s, userbufsize: %d \033[0;39m\n", pstVdecThreadParam->s32ChnId,
  26. pstVdecThreadParam->cFileName, pstVdecThreadParam->s32MinBufSize);
  27. pu8Buf = malloc(pstVdecThreadParam->s32MinBufSize);
  28. if(pu8Buf == NULL)
  29. {
  30. SAMPLE_PRT("chn %d can't alloc %d in send stream thread!\n", pstVdecThreadParam->s32ChnId, pstVdecThreadParam->s32MinBufSize);
  31. fclose(fpStrm);
  32. return (HI_VOID *)(HI_FAILURE);
  33. }
  34. fflush(stdout);
  35. u64PTS = pstVdecThreadParam->u64PtsInit;
  36. while (1)
  37. {
  38. if (pstVdecThreadParam->eThreadCtrl == THREAD_CTRL_STOP)
  39. {
  40. break;
  41. }
  42. else if (pstVdecThreadParam->eThreadCtrl == THREAD_CTRL_PAUSE)
  43. {
  44. sleep(1);
  45. continue;
  46. }
  47. bEndOfStream = HI_FALSE;
  48. bFindStart = HI_FALSE;
  49. bFindEnd = HI_FALSE;
  50. u32Start = 0;
  51. fseek(fpStrm, s32UsedBytes, SEEK_SET);
  52. s32ReadLen = fread(pu8Buf, 1, pstVdecThreadParam->s32MinBufSize, fpStrm);
  53. if (s32ReadLen == 0)
  54. {
  55. if (pstVdecThreadParam->bCircleSend == HI_TRUE)
  56. {
  57. memset(&stStream, 0, sizeof(VDEC_STREAM_S) );
  58. stStream.bEndOfStream = HI_TRUE;
  59. HI_MPI_VDEC_SendStream(pstVdecThreadParam->s32ChnId, &stStream, -1);
  60. s32UsedBytes = 0;
  61. fseek(fpStrm, 0, SEEK_SET);
  62. s32ReadLen = fread(pu8Buf, 1, pstVdecThreadParam->s32MinBufSize, fpStrm);
  63. }
  64. else
  65. {
  66. break;
  67. }
  68. }
  69. if (pstVdecThreadParam->s32StreamMode==VIDEO_MODE_FRAME && pstVdecThreadParam->enType == PT_H264)
  70. {
  71. for (i=0; i<s32ReadLen-8; i++)
  72. {
  73. int tmp = pu8Buf[i+3] & 0x1F;
  74. if ( pu8Buf[i ] == 0 && pu8Buf[i+1] == 0 && pu8Buf[i+2] == 1 &&
  75. (
  76. ((tmp == 0x5 || tmp == 0x1) && ((pu8Buf[i+4]&0x80) == 0x80)) ||
  77. (tmp == 20 && (pu8Buf[i+7]&0x80) == 0x80)
  78. )
  79. )
  80. {
  81. bFindStart = HI_TRUE;
  82. i += 8;
  83. break;
  84. }
  85. }
  86. for (; i<s32ReadLen-8; i++)
  87. {
  88. int tmp = pu8Buf[i+3] & 0x1F;
  89. if ( pu8Buf[i ] == 0 && pu8Buf[i+1] == 0 && pu8Buf[i+2] == 1 &&
  90. (
  91. tmp == 15 || tmp == 7 || tmp == 8 || tmp == 6 ||
  92. ((tmp == 5 || tmp == 1) && ((pu8Buf[i+4]&0x80) == 0x80)) ||
  93. (tmp == 20 && (pu8Buf[i+7]&0x80) == 0x80)
  94. )
  95. )
  96. {
  97. bFindEnd = HI_TRUE;
  98. break;
  99. }
  100. }
  101. if(i>0)s32ReadLen = i;
  102. if (bFindStart == HI_FALSE)
  103. {
  104. SAMPLE_PRT("chn %d can not find H264 start code!s32ReadLen %d, s32UsedBytes %d.!\n",
  105. pstVdecThreadParam->s32ChnId, s32ReadLen, s32UsedBytes);
  106. }
  107. if (bFindEnd == HI_FALSE)
  108. {
  109. s32ReadLen = i+8;
  110. }
  111. }
  112. else if (pstVdecThreadParam->s32StreamMode==VIDEO_MODE_FRAME && pstVdecThreadParam->enType == PT_H265)
  113. {
  114. HI_BOOL bNewPic = HI_FALSE;
  115. for (i=0; i<s32ReadLen-6; i++)
  116. {
  117. HI_U32 tmp = (pu8Buf[i+3]&0x7E)>>1;
  118. bNewPic = ( pu8Buf[i+0] == 0 && pu8Buf[i+1] == 0 && pu8Buf[i+2] == 1
  119. && (tmp >= 0 && tmp <= 21) && ((pu8Buf[i+5]&0x80) == 0x80) );
  120. if (bNewPic)
  121. {
  122. bFindStart = HI_TRUE;
  123. i += 6;
  124. break;
  125. }
  126. }
  127. for (; i<s32ReadLen-6; i++)
  128. {
  129. HI_U32 tmp = (pu8Buf[i+3]&0x7E)>>1;
  130. bNewPic = (pu8Buf[i+0] == 0 && pu8Buf[i+1] == 0 && pu8Buf[i+2] == 1
  131. &&( tmp == 32 || tmp == 33 || tmp == 34 || tmp == 39 || tmp == 40 || ((tmp >= 0 && tmp <= 21) && (pu8Buf[i+5]&0x80) == 0x80) )
  132. );
  133. if (bNewPic)
  134. {
  135. bFindEnd = HI_TRUE;
  136. break;
  137. }
  138. }
  139. if(i>0)s32ReadLen = i;
  140. if (bFindStart == HI_FALSE)
  141. {
  142. SAMPLE_PRT("chn %d can not find H265 start code!s32ReadLen %d, s32UsedBytes %d.!\n",
  143. pstVdecThreadParam->s32ChnId, s32ReadLen, s32UsedBytes);
  144. }
  145. if (bFindEnd == HI_FALSE)
  146. {
  147. s32ReadLen = i+6;
  148. }
  149. }
  150. else if (pstVdecThreadParam->enType == PT_MJPEG || pstVdecThreadParam->enType == PT_JPEG)
  151. {
  152. for (i=0; i<s32ReadLen-1; i++)
  153. {
  154. if (pu8Buf[i] == 0xFF && pu8Buf[i+1] == 0xD8)
  155. {
  156. u32Start = i;
  157. bFindStart = HI_TRUE;
  158. i = i + 2;
  159. break;
  160. }
  161. }
  162. for (; i<s32ReadLen-3; i++)
  163. {
  164. if ((pu8Buf[i] == 0xFF) && (pu8Buf[i+1]& 0xF0) == 0xE0)
  165. {
  166. u32Len = (pu8Buf[i+2]<<8) + pu8Buf[i+3];
  167. i += 1 + u32Len;
  168. }
  169. else
  170. {
  171. break;
  172. }
  173. }
  174. for (; i<s32ReadLen-1; i++)
  175. {
  176. if (pu8Buf[i] == 0xFF && pu8Buf[i+1] == 0xD9)
  177. {
  178. bFindEnd = HI_TRUE;
  179. break;
  180. }
  181. }
  182. s32ReadLen = i+2;
  183. if (bFindStart == HI_FALSE)
  184. {
  185. SAMPLE_PRT("chn %d can not find JPEG start code!s32ReadLen %d, s32UsedBytes %d.!\n",
  186. pstVdecThreadParam->s32ChnId, s32ReadLen, s32UsedBytes);
  187. }
  188. }
  189. else
  190. {
  191. if((s32ReadLen != 0) && (s32ReadLen < pstVdecThreadParam->s32MinBufSize))
  192. {
  193. bEndOfStream = HI_TRUE;
  194. }
  195. }
  196. stStream.u64PTS = u64PTS;
  197. stStream.pu8Addr = pu8Buf + u32Start;
  198. stStream.u32Len = s32ReadLen;
  199. stStream.bEndOfFrame = (pstVdecThreadParam->s32StreamMode==VIDEO_MODE_FRAME)? HI_TRUE: HI_FALSE;
  200. stStream.bEndOfStream = bEndOfStream;
  201. stStream.bDisplay = 1;
  202. SendAgain:
  203. s32Ret=HI_MPI_VDEC_SendStream(pstVdecThreadParam->s32ChnId, &stStream, pstVdecThreadParam->s32MilliSec);
  204. if( (HI_SUCCESS != s32Ret) && (THREAD_CTRL_START == pstVdecThreadParam->eThreadCtrl) )
  205. {
  206. usleep(pstVdecThreadParam->s32IntervalTime);
  207. goto SendAgain;
  208. }
  209. else
  210. {
  211. bEndOfStream = HI_FALSE;
  212. s32UsedBytes = s32UsedBytes +s32ReadLen + u32Start;
  213. u64PTS += pstVdecThreadParam->u64PtsIncrease;
  214. }
  215. usleep(pstVdecThreadParam->s32IntervalTime);
  216. }
  217. /* send the flag of stream end */
  218. memset(&stStream, 0, sizeof(VDEC_STREAM_S) );
  219. stStream.bEndOfStream = HI_TRUE;
  220. HI_MPI_VDEC_SendStream(pstVdecThreadParam->s32ChnId, &stStream, -1);
  221. printf("\033[0;35m chn %d send steam thread return ... \033[0;39m\n", pstVdecThreadParam->s32ChnId);
  222. fflush(stdout);
  223. if (pu8Buf != HI_NULL)
  224. {
  225. free(pu8Buf);
  226. }
  227. fclose(fpStrm);
  228. return (HI_VOID *)HI_SUCCESS;
  229. }

这里海思的函数主要是打开文件,然后去分割每一个视频帧的大小,fseek(fpStrm, s32UsedBytes, SEEK_SET)将文件指针位置定位到s32UsedBytes处,一开始为0位置,s32UsedBytes是变量随着whiile循环逐渐变大,
s32ReadLen = fread(pu8Buf, 1, pstVdecThreadParam->s32MinBufSize, fpStrm);读取一帧数据到pu8Buf,
pstVdecThreadParam->s32StreamMode==VIDEO_MODE_FRAME && pstVdecThreadParam->enType == PT_H264 这里面应该就是找到视频数据流中一帧的长度。
然而我用ffmpeg 解封装之后的数据,包括AVPacket,还有fmt_ctx->streams[i],一帧一帧的数据,如何跟海思sample vdec HI_MPI_VDEC_SendStream(pstVdecThreadParam->s32ChnId, &stStream, pstVdecThreadParam->s32MilliSec) 这个函数中的stStream数据相匹配。或者说我这边用ffmpeg解封的步骤有问题,请大佬解惑

我来回答
3098
0
0
回答
1个
黑白110 发布于2022-04-29 09:30:19

好长阿,帮顶

0

Markdown 语法

  • 加粗 **内容**
  • 斜体 *内容*
  • 删除线 ~~内容~~
  • 引用 > 引用内容
  • 代码 `代码`
  • 代码块 ```编程语言↵代码```
  • 链接 [链接标题](url)
  • 无序列表 - 内容
  • 有序列表 1. 内容
  • 缩进 内容
  • 图片 ![alt](url)

Markdown 语法

  • 加粗 **内容**
  • 斜体 *内容*
  • 删除线 ~~内容~~
  • 引用 > 引用内容
  • 代码 `代码`
  • 代码块 ```编程语言↵代码```
  • 链接 [链接标题](url)
  • 无序列表 - 内容
  • 有序列表 1. 内容
  • 缩进 内容
  • 图片 ![alt](url)
+ 添加网盘链接/附件
或将文件直接拖到这里
悬赏:
EBC
网盘
* 网盘链接:
* 提取码:
悬赏:
EBC
Loading...
易百纳技术社区
确定要删除此文章、专栏、评论吗?
确定
取消
易百纳技术社区
在专栏模块发布专栏,可获得其他E友的打赏
回答悬赏问答,被题主采纳后即可获得悬赏金
在上传资料时,有价值的资料可设置为付费资源
达到一定金额,收益即可提现~
收益也可用来充值ebc,下载资料、兑换礼品更容易
活动规则
  • 1.周任务为周期性任务,每周周一00:00刷新,上周完成的任务不会累计到本周,本周需要从头开始任务,当前任务完成后才可以完成下一个任务
  • 2.发布的专栏与资料需要与平台的板块有相关性,禁止注水,专栏/资料任务以审核通过的篇数为准
  • 3.任务完成后,现金奖励直接打款到微信账户;EBC/收益将自动发放到个人账户,可前往“我的钱包”查看;其他奖励请联系客服兑换
  • 4.每周最后三个任务将会有以下奖品掉落:社区热卖开发板、小米音响、视频年度会员、京东卡、华为手机等等