ffmpeg的mpegenc.c中,缺少了psm头的写入,而ps流的封包应当是
ps<-sys<-psm<-pes,即pes在写入sys头之后写pes之前应当先写入psm头,因此mpegenc.c中需要增加写入psm头的函数,如下:
static uint8_t get_stream_type(int stream_codec_id){uint8_t res = 0;switch(stream_codec_id){case AV_CODEC_ID_PCM_MULAW:res = STREAM_TYPE_AUDIO_PCM_MULAW;break;case AV_CODEC_ID_MPEG2VIDEO:res = STREAM_TYPE_VIDEO_MPEG2;break;case AV_CODEC_ID_MP3:res = STREAM_TYPE_AUDIO_MPEG2;break;case AV_CODEC_ID_MPEG4:res = STREAM_TYPE_VIDEO_MPEG4;break;case AV_CODEC_ID_AC3:res = STREAM_TYPE_AUDIO_AC3;break;case AV_CODEC_ID_AAC:res = STREAM_TYPE_AUDIO_AAC;break;case AV_CODEC_ID_H264:res = STREAM_TYPE_VIDEO_H264;break;default:break;}return res;}
static int put_psm_header(AVFormatContext *ctx,uint8_t *buf){MpegMuxContext *s = ctx->priv_data;int size, i, private_stream_coded, id;PutBitContext pb;int streamnum = 0;for (int i = 0 ; i < ctx->nb_streams; i++){if (ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO|| ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO){streamnum++;}}int streminfolen = streamnum * 4;
init_put_bits(&pb, buf, (16 + streminfolen) * 8);
put_bits32(&pb, 0x000001bc);put_bits(&pb, 16, 10 + streminfolen); /*program stream map length*/put_bits(&pb, 1, 1); /*current next indicator */put_bits(&pb, 2, 3); /*reserved*/put_bits(&pb, 5, 0); /*program stream map version*/put_bits(&pb, 7, 0x7F); /*reserved */put_bits(&pb, 1, 1); /*marker bit */put_bits(&pb, 16,0); /*programe stream info length*/put_bits(&pb, 16, streminfolen); /*elementary stream map length is*/for (int i = 0 ; i < ctx->nb_streams; i++){AVStream* st = ctx->streams[i];if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO || st->codec->codec_type == AVMEDIA_TYPE_AUDIO){put_bits(&pb, 8, get_stream_type(st->codec->codec_id)); /*stream_type*/if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO){put_bits(&pb, 8, AUDIO_ID); /*elementary_stream_id*/}if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO){put_bits(&pb, 8, VIDEO_ID); /*elementary_stream_id*/}put_bits(&pb, 16, 0); /*elementary_stream_info_length is*/}}uint32_t crc = 0;//crc32(0, buf, 13 + streminfolen);/*audio*//*crc (2e b9 0f 3d)*/put_bits32(&pb, crc); /*crc */flush_put_bits(&pb);return 16 + streminfolen;}
其中get_stream_type函数是用来依据编码器ID得到流类型关键字,该函数被put_psm_header调用,而put_psm_header函数是用来写入psm头的,在mpegenc.c中查找调用put_system_header函数的调用,该函数是用来写system头的,该函数中CRC值写了0进去,因为参照mpeg.c中并没有判断该数值,如果要提高输出的兼容性,应当计算起始标志之后,即头四个字节之后的crc值写进去。
该函数的调用方式一般如下:
size = put_system_header(ctx, buf_ptr, id);
buf_ptr += size;
在每段该代码后都加上
size = put_psm_header(ctx, buf_ptr);
buf_ptr += size;
即可实现将psm头写入到mpeg流中。