标签:dm8168 omx h264 解码 chunking
源码来源: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)
标签:dm8168 omx h264 解码 chunking
原文地址:http://blog.csdn.net/gzengh/article/details/43201667