H264解码深度解析——DM8168 OMX从H264文件读取一帧数据(do chunking of h264)

来源:互联网 发布:淘宝网店logo 编辑:程序博客网 时间:2024/05/01 14:40

 

源码来源: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;}

 

1 0
原创粉丝点击