首页 > 代码库 > H264解码深度解析——DM8168 OMX从H264文件读取一帧数据(do chunking of h264)
H264解码深度解析——DM8168 OMX从H264文件读取一帧数据(do chunking of h264)
源码来源:TI - DM8168 - EZSDK - OMX - examples - decode_display
基本执行流程如下:
Decode_GetNextFrameSize(H264_ParsingCtx *pc)函数源码(加注释)如下:
/****************************************************************************** Decode_GetNextFrameSize Function Declaration \*****************************************************************************/ /** * * @brief Gets the size of thenext frame, It is doing chunking of h264 * elementary bitstream and providing frames to OMX component. * * @param in: * pc: Pointer to H264_ParsingCtx structure * * @param Out: * None * * @return uint32_t - Frame Size * */ unsigned int Decode_GetNextFrameSize(H264_ParsingCtx *pc) { FILE *fp = pc->fp; // pc->fp指向的是H264文件 unsigned char *readBuf = pc->readBuf; H264_ChunkingCtx *ctx = &pc->ctx; AVChunk_Buf *inBuf = &pc->inBuf; AVChunk_Buf *outBuf = &pc->outBuf; unsigned char termCond = 1; if(pc->firstParse == 1) // pc->firstParse的初始化值就是1 termCond = 0; while ((!feof (fp)) || ((((pc->firstParse == 0) && (pc->bytes != 0)) && (pc->bytes <= READSIZE) && (pc->tmp <=pc->bytes)))) { if (pc->firstParse == 1) { pc->bytes = fread (readBuf, 1, READSIZE, fp);//将H264比特流读取到readBuf if (!pc->bytes) { return 0; } inBuf->ptr = readBuf; // inBuf->ptr也指向了H264比特流数据 pc->tmp = 0; pc->firstParse = 0; } else { if (pc->bytes <= pc->tmp) { pc->bytes = fread (readBuf, 1, READSIZE, fp); if (!pc->bytes) { return 0; } inBuf->ptr = readBuf; pc->tmp = 0; } } while (pc->bytes > pc->tmp) { inBuf->bufsize = ((pc->bytes - pc->tmp) > 184) ? 184 : (pc->bytes -pc->tmp); //并不是必须184,测试了多个其他数值都没有问题,我也不知道184意义何在? inBuf->bufused = 0; while (inBuf->bufsize != inBuf->bufused) { //调用Decode_DoChunking()从码流中分出一帧 if (AVC_SUCCESS == Decode_DoChunking (ctx, outBuf, 1, inBuf, NULL)) { pc->frameNo = pc->chunkCnt++; pc->frameSize = outBuf->bufused; pc->tmp += inBuf->bufused; inBuf->ptr += inBuf->bufused; return pc->frameSize; } } /* while (inBuf->bufSize */ pc->tmp += inBuf->bufused; inBuf->ptr += inBuf->bufused; }/* while (pc->bytes) */ }/* while ((!feof (fp)...)) */ return 0; }
Decode_DoChunking()函数源码(加注释)如下:
/****************************************************************************** Decode_DoChunking Function Declaration \*****************************************************************************/ /** * * @brief Does H.264 FrameChunking. * * @param in: * c: Pointer to H264_ChunkingCtx structure * opBufs: Pointer to AVChunk_Buf Structure * numOutBufs: Number of output buffers * inBuf: Pointer to AVChunk_Buf Structure * attrs: Additional attributes * * @param Out: * None * * @return AVC_Err - AVC Error Code * */ AVC_Err Decode_DoChunking (H264_ChunkingCtx*c, AVChunk_Buf *opBufs, unsigned intnumOutBufs, AVChunk_Buf *inBuf, void *attrs) { inti = 0, j, frame_end, sc_found, tmp, bytes; unsigned int w, z; unsigned char *inp; inp= &inBuf->ptr[inBuf->bufused]; bytes = inBuf->bufsize - inBuf->bufused; /*TI 在这里构建了一个状态机,通过改变和判定c->state 变量来跳转,共有如下5个状态: H264_ST_LOOKING_FOR_SPS, // Initial state at start, look forSPS //查找序列参数集,初始状态 H264_ST_LOOKING_FOR_ZERO_SLICE, //Looking for slice header with zero MB num //查找带0MB num的slice头 H264_ST_INSIDE_PICTURE, //Inside a picture, looking for nextpicure start //处于一个图片内部,查找下一幅图的开始 H264_ST_STREAM_ERR, //When some discontinuity wasdetected in the stream //错误处理 H264_ST_HOLDING_SC, //Intermediate state, when a newframe is detected //过渡状态 */ BACK: if(H264_ST_INSIDE_PICTURE == c->state) //处于一个图像内部 { tmp = i; sc_found = frame_end = 0; while (i < bytes) { z = c->workingWord << 8; w = c->fifthByte; c->workingWord = z | w; c->fifthByte = inp[i++]; if (z == 0x100)//查找新的图像 { w &= 0x1f; if (w == H264_NAL_ACCESS_UNIT_CODEDSLICE_CODE_FOR_NONIDR || w == H264_NAL_ACCESS_UNIT_CODEDSLICE_CODE_FOR_IDR) { /* check for MB number in slice header */ if (c->fifthByte & 0x80) { sc_found = frame_end = 1; break; } } /* if (w)*/ if (w == H264_PPS_START_CODE || w == H264_SPS_START_CODE) { sc_found = frame_end = 1; break; } /* if (w)*/ } /* if(z) */ } /*while (i) */ j= i - tmp; /* minus 5 to remove next header that is already copied */ if (frame_end) { j -= 5; } if (j > (int32_t) (opBufs->bufsize - opBufs->bufused)) { /* output buffer is full, end the frame right here */ AVCLOG (AVC_MOD_MAIN, AVC_LVL_TRACE_ALL,("memcpy(%p,%d,%p,%d,%d)", opBufs->ptr, opBufs->bufused, inp, tmp, opBufs->bufsize - opBufs->bufused)); memcpy (&opBufs->ptr[opBufs->bufused], &inp[tmp], opBufs->bufsize -opBufs->bufused); opBufs->bufused = opBufs->bufsize; c->state = H264_ST_LOOKING_FOR_ZERO_SLICE; frame_end = 1; } else if (j > 0) { AVCLOG (AVC_MOD_MAIN, AVC_LVL_TRACE_ALL, ("memcpy(%p,%d,%p,%d,%d)", opBufs->ptr, opBufs->bufused, inp, tmp, j)); memcpy (&opBufs->ptr[opBufs->bufused], &inp[tmp], j); opBufs->bufused += j; } else { opBufs->bufused += j; } if (frame_end) { if (sc_found) { c->state = H264_ST_HOLDING_SC; //转换状态到Holding,以便下次调用该dochunking函数时状态判定合理 // printf("FrameSize = %d\n", i); } inBuf->bufused += i; return AVC_SUCCESS;//返回成功读取一帧的标志值 } } if(H264_ST_LOOKING_FOR_ZERO_SLICE == c->state) { tmp = i; sc_found = 0; while (i < bytes) { z = c->workingWord << 8; w = c->fifthByte; c->workingWord = z | w; c->fifthByte = inp[i++]; if (z == 0x100) { w &= 0x1f; if (w == H264_NAL_ACCESS_UNIT_CODEDSLICE_CODE_FOR_NONIDR || w == H264_NAL_ACCESS_UNIT_CODEDSLICE_CODE_FOR_IDR) { /* check for MB number in slice header */ if (c->fifthByte & 0x80)//判定nal头后面一个字节的最高位是否为1 { sc_found = 1; break; } /* if (c) */ } /* if (w) */ } /* if (z) */ }/* while (i) */ j= i - tmp; if (j > (opBufs->bufsize - opBufs->bufused)) { /* output buffer is full, discard this data, go back to looking for seq start code */ opBufs->bufused = 0; c->state = H264_ST_LOOKING_FOR_SPS; } else if (j > 0) { AVCLOG (AVC_MOD_MAIN, AVC_LVL_TRACE_ALL,("memcpy(%p,%d,%p,%d,%d)", opBufs->ptr, opBufs->bufused,inp, tmp, j)); memcpy (&opBufs->ptr[opBufs->bufused], &inp[tmp], j); //将参数集比特数据copy到输出缓存区 opBufs->bufused += j; } if (sc_found) { /* Set the attribute at rioWptr */ c->state = H264_ST_INSIDE_PICTURE;//转换状态 } }/* if (c->state...) */ if(H264_ST_STREAM_ERR == c->state) { while (i < bytes) { z = c->workingWord << 8; w = c->fifthByte; c->workingWord = z | w; c->fifthByte = inp[i++]; if (z == 0x100) { w &= 0x1f; if (w == H264_NAL_ACCESS_UNIT_CODEDSLICE_CODE_FOR_NONIDR || w == H264_NAL_ACCESS_UNIT_CODEDSLICE_CODE_FOR_IDR) { /* chueck for MB number in slice header */ if (c->fifthByte & 0x80) { c->state = H264_ST_HOLDING_SC; break; } } if (w == H264_PPS_START_CODE || w == H264_SPS_START_CODE) { c->state = H264_ST_HOLDING_SC; break; } } /* if (z) */ }/* while (i) */ } if(H264_ST_LOOKING_FOR_SPS == c->state) //初始状态,查找SPS { while (i < bytes) { z = c->workingWord << 8; // c->workingWord初始值为0xFFFFFFFF,左移8位, z=0xFFFFFF00 w = c->fifthByte; // c->fifthByte初始值为0xFF c->workingWord = z | w; c->fifthByte = inp[i++];//从H264码流读取一个byte /*H264码流每一帧NALU起始码都是0x00000001 整体看以上四步, 当循环5次时,c->workingWord=0x00000001 当循环6次时,z=0x00000100, w此时为nalu头(如不了解nalu头请网上搜索) */ if (z == 0x100) { // printf("%d: %08x @ %d\n",chunkCnt, c->workingWord, // inBuf->bufused+i-6); w &= 0x1f; if (w == H264_SPS_START_CODE)//判定NAL类型是否为SPS { c->state = H264_ST_HOLDING_SC;//将状态改到HOLDING_SC break; } /* if (w) */ } /* if (z) */ }/* while (i) */ } if(H264_ST_HOLDING_SC == c->state) { w= c->workingWord; opBufs->bufused = 0; if (opBufs->bufsize < 5) { /* Means output buffer does not have space for 4 bytes, bad error */ AVCLOG (AVC_MOD_MAIN,AVC_LVL_CRITICAL_ERROR, ("Bad error")); } // Copy these 5 bytes into output 将nalu起始码和nal头copy到输出缓存区 for (j = 0; j < 4; j++, w <<= 8) { opBufs->ptr[opBufs->bufused + j] = ((w >> 24) & 0xFF); } opBufs->ptr[opBufs->bufused + j] = c->fifthByte; opBufs->bufused += 5; // Copying frame start code done, now proceed to next state 状态转换 w= c->workingWord & 0x1f; if (w == H264_PPS_START_CODE || w == H264_SPS_START_CODE) { c->state = H264_ST_LOOKING_FOR_ZERO_SLICE; } else { c->state = H264_ST_INSIDE_PICTURE; } c->workingWord = H264_WORKING_WORD_INIT; c->fifthByte = 0xFF; } if(i < bytes) { goto BACK; } inBuf->bufused += i; return AVC_ERR_INSUFFICIENT_INPUT; }
H264解码深度解析——DM8168 OMX从H264文件读取一帧数据(do chunking of h264)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。