一帧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); }