FFMPEG处理音频时间戳的主要逻辑

https://blog.csdn.net/win_lin/article/details/13512517



FFMPEG处理音频时间戳的主要逻辑

FFMPEG处理音频时间戳的主要逻辑是:

1. demux读取AVPacket。以输入flv为例,timebase是1/1000,第一个音频包可能是46,代表0.046秒。

2. decoder解码AVPacket为AVFrame,frame的pts为NOPTS,需要设置,否则后面都会有问题。主要是调用:av_rescale_delta:

[cpp]  view plain  copy
  1. AVRational in_tb = decoded_frame_tb;  
  2. AVRational fs_tb = (AVRational){1, ist->codec->sample_rate};  
  3. int duration = decoded_frame->nb_samples;  
  4. AVRational out_tb = (AVRational){1, ist->codec->sample_rate};  
  5.   
  6. decoded_frame->pts = av_rescale_delta(in_tb, decoded_frame->pts, fs_tb, duration, &rescale_last_pts, out_tb);  
相当于下面的逻辑:

[cpp]  view plain  copy
  1. // init the rescale_last_pts, set to 0 for the first decoded_frame->pts is 0  
  2. if (rescale_last_pts == AV_NOPTS_VALUE) {  
  3.     rescale_last_pts = av_rescale_q(decoded_frame->pts, in_tb, fs_tb) + duration;  
  4. }  
  5. // the fs_tb equals to out_tb, so decoded_frame->pts equals to rescale_last_pts  
  6. decoded_frame->pts = av_rescale_q(rescale_last_pts, fs_tb, out_tb);;  
  7. rescale_last_pts += duration;  
还可以简化为:

[cpp]  view plain  copy
  1. /** 
  2. * for audio encoding, we simplify the rescale algorithm to following. 
  3. */  
  4. if (rescale_last_pts == AV_NOPTS_VALUE) {  
  5.     rescale_last_pts = 0;  
  6. }  
  7. decoded_frame->pts = rescale_last_pts;  
  8. rescale_last_pts += decoded_frame->nb_samples; // duration  
实际上就是以nb_samples为时长,让pts为这个的总和,累积的samples就可以。因为默认把tb设置为sample_rate,所以samples数目就是pts。

3. filter过滤,实际上没有处理。

[cpp]  view plain  copy
  1. // correct the pts  
  2. int64_t filtered_frame_pts = AV_NOPTS_VALUE;  
  3. if (picref->pts != AV_NOPTS_VALUE) {  
  4.     // rescale the tb, actual the ofilter tb equals to ost tb,  
  5.     // so this step canbe ignored and we always set start_time to 0.  
  6.     filtered_frame_pts = av_rescale_q(picref->pts, ofilter->inputs[0]->time_base, ost->codec->time_base)   
  7.         - av_rescale_q(start_time, AV_TIME_BASE_Q, ost->codec->time_base);  
  8. }  
  9.   
  10. // convert to frame  
  11. avfilter_copy_buf_props(filtered_frame, picref);  
  12. printf("filter -> picref_pts=%"PRId64", frame_pts=%"PRId64", filtered_pts=%"PRId64"\n",   
  13.     picref->pts, filtered_frame->pts, filtered_frame_pts);  
  14. filtered_frame->pts = filtered_frame_pts;  

4. encoder编码,主要是生成dts。

5. muxer输出前,需要做处理。譬如输出rtmp流,要将tb变为1/1000,flv的tb,也就是毫秒单位。

另外,时间戳从零开始。

[cpp]  view plain  copy
  1.     // correct the output, enforce start at 0.  
  2.     static int64_t starttime = -1;  
  3. #if 1  
  4.     if (starttime < 0) {  
  5.         starttime = (pkt.dts < pkt.pts)? pkt.dts : pkt.pts;  
  6.     }  
  7.     pkt.dts -= starttime;  
  8.     pkt.pts -= starttime;  
  9. #endif  
  10.   
  11. #if 1  
  12.     // rescale audio ts to AVRational(1, 1000) for flv format.  
  13.     AVRational flv_tb = (AVRational){1, 1000};  
  14.     pkt.dts = av_rescale_q(pkt.dts, ost->codec->time_base, flv_tb);  
  15.     pkt.pts = av_rescale_q(pkt.pts, ost->codec->time_base, flv_tb);  
  16. #endif  

6. 最后一步,写入:

[cpp]  view plain  copy
  1. ret = av_interleaved_write_frame(oc, &pkt);  

就OK了。

你可能感兴趣的:(video)