http://blog.chinaunix.net/uid-26000296-id-3483782.html
一、FFmpeg忽略了adaptation_field()数据
FFmpeg忽略了包含PCR值的adaptation_filed数据;
代码(libavformat/mpegts.c)分析如下:
/* 解析TS包 */
int handle_packet(MpegTSContext *ts, const uint8_t *packet)
{
...
pid = AV_RB16(packet + 1) & 0x1fff; //SYNTAX: PID
is_start = packet[1] & 0x40; //SYNTAX: payload_unit_start_indicator
...
/* continuity check (currently not used) */
cc = (packet[3] & 0xf); //SYNTAX: continuity_counter
expected_cc = (packet[3] & 0x10) ? (tss->last_cc + 1) & 0x0f : tss->last_cc;
cc_ok = (tss->last_cc < 0) || (expected_cc == cc);
tss->last_cc = cc;
/* skip adaptation field */
afc = (packet[3] >> 4) & 3; //SYNTAX: adaptation_field_control
p = packet + 4;
if (afc == 0) /* reserved value */
return 0;
if (afc == 2) /* adaptation field only */
return 0;
if (afc == 3)
{
/* skip adapation field */
p += p[0] + 1;
}
...
}
二、解码初始时间戳的计算
原理如下:
a. 分析阶段: 分析多个TS包,并找到第一个PES包的PTS,做为初始偏移量;
b. PTS置零: 分析与初始化阶段完成后,
解码TS的第一个PES包,得到其PTS值,
减去初始偏移量,使得第一个编码后帧的PTS为零;
c. DTS/PTS增量累加;
1. PTS置零代码分析
main(){
|-- ...
|-- parse_options(){
|-- …
|-- opt_input_file(){
|-- …
av_find_stream_info(ic);
timestamp = start_time;
timestamp += ic->start_time;
…
input_files_ts_offset[nb_input_files] =
input_ts_offset - (copy_ts ? 0 : timestamp);
…
}
…
}
|-- transcode(){
|-- …
for( ; received_sigterm == 0; ) {
AVPacket pkt;
…
ret = av_read_frame(is, &pkt);
…
pkt.dts += av_rescale_q(input_files_ts_offset[nb_input_files],
AV_TIME_BASE_Q, ist->st->time_base);
}
}
三、编码音视频帧的DTS/PTS计算
音频帧的DTS/PTS计算:
一个音频帧(对于AAC来说, 是1024个采样点),
相对于音频采样率(如 44100个采样点/second = 44.1KHz)来说,
累加上每帧的增量(1024*1000/44100 = 23ms/frame)
st->time_base.den = 1000 //时钟基, 1 second = 1000 ms
frame_size = 1024 //一帧 = 1024个采样点
st->pts = {val=0,
num=22050,
den=44100}; // 音频采样率
int mpegts_push_data();
pkt.pts += av_rescale_q(input_files_ts_offset[ist->file_index], AV_TIME_BASE_Q, ist->st->time_base);