一帧image编码完的数据存储在h264buffer中,编码后的h264码流的大小为nH264Size
因为对于NALU,并不是一帧对应一个NALU,而是对于SLICE而言,一个slice就封装层一个nal,所以一帧可以有多个slice,即一帧有多个nal。
具体一帧中有几个nalu则是可以再pps中参数中进行设定的,每遇到一个IDR,则此时就将对应的SPS,PPS进行一个更新,NAL的生成过程:先是对header里面的8个bits进行设定,然后是Payload。
对于字节流编码的码流编码,去掉每个slice前面的4个前缀码,就是nal的内容了。而对于rtp封装打包不需要前缀码,所以在进行rfc3984_pack进行打包之前需提取nal。
为了让处理流程看起来比较顺畅,我把几个处理流程都写在同一函数里头。
//return value: number of the slice
static int Frame_Slice_Nal_Pro(unsigned char *h264buffer, int nH264Size)
{
int i;
int nSliceCount = -1;
unsigned char *pcSliceBuffer[SLICE_NUM]; //存储slice,去掉每个slice前面的4个前缀码,就是nal的内
容了。
int pnSliceSize[SLICE_NUM]; //每个slice的size,即每个nal的大小+4
for(i=0; i<nH264Size-4; i++)
{
unsigned char *src = h264buffer + i;
//这里是进行字节流格式的码流编码,有开始4个前缀码,对于RTP封装则不需要前缀码。
if( (*src == 0x00)
&& (*(src+1) == 0x00)
&& (*(src+2) == 0x00)
&& (*(src+3) == 0x01))
{
nSliceCount++;
pcSliceBuffer[nSliceCount] = src;
pnSliceSize[nSliceCount] = 1;
}
else
{
if (nSliceCount >= 0)
{
pnSliceSize[nSliceCount]++;
}
}
}
if (nSliceCount >= 0)
{
pnSliceSize[nSliceCount] += 4;
}
//提取nal
mblk_t *m;
MSQueue *nalus;
int i;
int nNalNum = nSliceCount + 1;
for(i=0; i<nNalNum; i++) {
m = allocb(pnSliceSize[i] + 10, 0);
//拷贝nal到mblk中,然后将mblk存于nalus队列里头
memcpy(m->b_wptr, pcSliceBuffer[i] + 4, (pnSliceSize[i] - 4));
m->b_wptr += pnSliceSize[i] - 4;
ms_queue_put(nalus,m);
}
..................
//rtp打包发送出去
if(!ms_queue_empty(nalus))
rfc3984_pack(d->packer,nalus,f->outputs[0],ts);
............
return (nSliceCount + 1);
}