• ffmpeg转码时对编码率和固定码率的处理


    http://www.rosoo.net/a/201107/14663.html

    一般fps在代码里这样表示

    Fps = den/num

    如果den = 15,num=1,则fps = 15。

    如果帧率固定,pts*fps 就表示当前是第几帧。

    当输入视频流的帧率不固定,如rmvb ,而输出视频流的帧率固定,ffmpeg作如下处理(参考ffmpeg代码版本0.6.1):

    1、  记录和输出视频流ost相对应的输入视频流ist,变量为ost->sync_ist。这是在av_transcode函数进行输出流初始化时进行的。代码分别为:

    1. if (ist->discard && ist->st->discard != AVDISCARD_ALL && !skip && 
    2.   ist->st->codec->codec_type == ost->st->codec->codec_type) { 
    3.     if(best_nb_frames < ist->st->codec_info_nb_frames){ 
    4.       best_nb_frames= ist->st->codec_info_nb_frames; 
    5.       ost->source_index = j; 
    6.       found = 1; 
    7.     } 
    8.   } 
    9.   if (!found) { 
    10.    if(! opt_programid) { 
    11.       /* try again and reuse existing stream */ 
    12.       for(j=0;j<nb_istreams;j++) { 
    13.       ist = ist_table[j]; 
    14.       if (   ist->st->codec->codec_type == ost->st->codec->codec_type 
    15.    && ist->st->discard != AVDISCARD_ALL) { 
    16.       ost->source_index = j; 
    17.       found = 1; 
    18.       } 
    19.       } 
    20.       } 
    21.       ist = ist_table[ost->source_index]; 
    22.       ist->discard = 0; 
    23.       ost->sync_ist = (nb_stream_maps > 0) ? 
    24. ist_table[file_table[stream_maps[n].sync_file_index].ist_index + 
    25.           stream_maps[n].sync_stream_index] : ist; 

    2、  记录输出视频流ost的时间戳。输出为固定帧率,故可以简化为记录帧数,变量为ost->sync_opts。

    3、  将ost对应的ist的pts转换成固定帧率的帧数形式。代码为

    1. sync_ipts = get_sync_ipts(ost) / av_q2d(enc->time_base); 

    get_sync_ipts计算ost对应的ist的pts,

    av_q2d返回enc->time_base.num/ enc->time_base.den,即1/fps.

    4、  将sync_ipts和ost->sync_opts进行求差。

    1. double vdelta = sync_ipts - ost->sync_opts; 

    5、  根据vdelta来判断不同的情况。

    l  情况一:Vdelta<-1.1,表示当前输入帧的播放时间在当前输出帧的前一帧之前,故舍弃该帧,nb_frames = 0。

    l  情况二: (video_sync_method == 2 || (video_sync_method<0 && (s->oformat->flags & AVFMT_VARIABLE_FPS))){

    if(vdelta<=-0.6){

    nb_frames=0;

    }else if(vdelta>0.6)

    ost->sync_opts= lrintf(sync_ipts);}

    这里video_sync_method==2 和video_sync_method < 0 表示什么意义,不是很清楚。貌似ffmpeg里video_sync_method一直设为-1。AVFMT_VARIABLE_FPS应该是变帧率的意 思。这种情况下,vdelta<=0.6,表示位于当前帧之前,也舍弃该帧,nb_frames = 0;vdelta>0.6表示位于当前帧之后,直接把该帧的时间戳作为输出的时间出来输出该帧;0.6<vdelta<=0.6时,不 做任何处理,nb_frames 根据默认值为1。

    l  情况三:vdelta > 1.1

    此时nb_frames = lrintf(vdelta),需要做插帧操作。

    Ffmpeg的插帧操作,貌似是把当前输出帧重复输出nb_frames次。

    1. AVFrame* old_frame = enc->coded_frame; 
    2. enc->coded_frame = dec->coded_frame; //FIXME/XXX remove this hack 
    3. pkt.data= (uint8_t *)final_picture; 
    4. pkt.size=  sizeof(AVPicture); 
    5. pkt.pts= av_rescale_q(ost->sync_opts, enc->time_base, ost->st->time_base); 
    6. pkt.flags |= AV_PKT_FLAG_KEY; 
    7. write_frame(s, &pkt, ost->st->codec, bitstream_filters[ost->file_index][pkt.stream_index]); 
    8. enc->coded_frame = old_frame; 

    输出的数据在pkt.data里,final_picture即为经过处理的输入Pic。

    6、输出视频流的帧率,是从输入视频流的包头数据中获得的。Rmvb的vedio MDPR块里,保存有fps和fps2信息。Ffmpeg取fps作为帧率,fps2丢弃了。Fps2有什么用,还不清楚。介绍rmvb格式的文章里也没有看到过关于fps的任何介绍。

  • 相关阅读:
    Java学习笔记day01
    对有序数组进行二分查找(折半查找)
    对数组进行冒泡排序
    LeetCode #344. Reverse String
    LeetCode #292. Nim Game
    LeetCode #258. Add Digits
    Android DiskLruCache完全解析,硬盘缓存的最佳方案
    Android源码解析——LruCache
    Messenger与AIDL的异同
    Android应用层View绘制流程与源码分析
  • 原文地址:https://www.cnblogs.com/jingzhishen/p/3767342.html
Copyright © 2020-2023  润新知