]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/utils.c
avcodec/mpeg4video: fix 2 more incorrectly associated comments
[ffmpeg] / libavformat / utils.c
index 06758bf8b7b54f10f030a2eb5f390602fedf66ec..fc4de4c34eba75c0cce1076092a63f125abe722f 100644 (file)
@@ -653,6 +653,70 @@ no_packet:
     return 0;
 }
 
+static int update_wrap_reference(AVFormatContext *s, AVStream *st, int stream_index, AVPacket *pkt)
+{
+    int64_t ref = pkt->dts;
+    int i, pts_wrap_behavior;
+    int64_t pts_wrap_reference;
+    AVProgram *first_program;
+
+    if (ref == AV_NOPTS_VALUE)
+        ref = pkt->pts;
+    if (st->pts_wrap_reference != AV_NOPTS_VALUE || st->pts_wrap_bits >= 63 || ref == AV_NOPTS_VALUE || !s->correct_ts_overflow)
+        return 0;
+    ref &= (1LL<<st->pts_wrap_bits)-1;
+
+    // reference time stamp should be 60 s before first time stamp
+    pts_wrap_reference = ref - av_rescale(60, st->time_base.den, st->time_base.num);
+    // if first time stamp is not more than 1/8 and 60s before the wrap point, subtract rather than add wrap offset
+    pts_wrap_behavior = (ref < (1LL<<st->pts_wrap_bits) - (1LL<<st->pts_wrap_bits-3)) ||
+        (ref < (1LL<<st->pts_wrap_bits) - av_rescale(60, st->time_base.den, st->time_base.num)) ?
+        AV_PTS_WRAP_ADD_OFFSET : AV_PTS_WRAP_SUB_OFFSET;
+
+    first_program = av_find_program_from_stream(s, NULL, stream_index);
+
+    if (!first_program) {
+        int default_stream_index = av_find_default_stream_index(s);
+        if (s->streams[default_stream_index]->pts_wrap_reference == AV_NOPTS_VALUE) {
+            for (i=0; i<s->nb_streams; i++) {
+                s->streams[i]->pts_wrap_reference = pts_wrap_reference;
+                s->streams[i]->pts_wrap_behavior = pts_wrap_behavior;
+            }
+        }
+        else {
+            st->pts_wrap_reference = s->streams[default_stream_index]->pts_wrap_reference;
+            st->pts_wrap_behavior = s->streams[default_stream_index]->pts_wrap_behavior;
+        }
+    }
+    else {
+        AVProgram *program = first_program;
+        while (program) {
+            if (program->pts_wrap_reference != AV_NOPTS_VALUE) {
+                pts_wrap_reference = program->pts_wrap_reference;
+                pts_wrap_behavior = program->pts_wrap_behavior;
+                break;
+            }
+            program = av_find_program_from_stream(s, program, stream_index);
+        }
+
+        // update every program with differing pts_wrap_reference
+        program = first_program;
+        while(program) {
+            if (program->pts_wrap_reference != pts_wrap_reference) {
+                for (i=0; i<program->nb_stream_indexes; i++) {
+                    s->streams[program->stream_index[i]]->pts_wrap_reference = pts_wrap_reference;
+                    s->streams[program->stream_index[i]]->pts_wrap_behavior = pts_wrap_behavior;
+                }
+
+                program->pts_wrap_reference = pts_wrap_reference;
+                program->pts_wrap_behavior = pts_wrap_behavior;
+            }
+            program = av_find_program_from_stream(s, program, stream_index);
+        }
+    }
+    return 1;
+}
+
 int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
 {
     int ret, i, err;
@@ -709,6 +773,17 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
         }
 
         st= s->streams[pkt->stream_index];
+
+        if (update_wrap_reference(s, st, pkt->stream_index, pkt) && st->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET) {
+            // correct first time stamps to negative values
+            if (!is_relative(st->first_dts))
+                st->first_dts = wrap_timestamp(st, st->first_dts);
+            if (!is_relative(st->start_time))
+                st->start_time = wrap_timestamp(st, st->start_time);
+            if (!is_relative(st->cur_dts))
+                st->cur_dts = wrap_timestamp(st, st->cur_dts);
+        }
+
         pkt->dts = wrap_timestamp(st, pkt->dts);
         pkt->pts = wrap_timestamp(st, pkt->pts);
 
@@ -868,65 +943,6 @@ static AVPacketList *get_next_pkt(AVFormatContext *s, AVStream *st, AVPacketList
     return NULL;
 }
 
-static int update_wrap_reference(AVFormatContext *s, AVStream *st, int stream_index)
-{
-    if (s->correct_ts_overflow && st->pts_wrap_bits < 63 &&
-        st->pts_wrap_reference == AV_NOPTS_VALUE && st->first_dts != AV_NOPTS_VALUE) {
-        int i;
-
-        // reference time stamp should be 60 s before first time stamp
-        int64_t pts_wrap_reference = st->first_dts - av_rescale(60, st->time_base.den, st->time_base.num);
-        // if first time stamp is not more than 1/8 and 60s before the wrap point, subtract rather than add wrap offset
-        int pts_wrap_behavior = (st->first_dts < (1LL<<st->pts_wrap_bits) - (1LL<<st->pts_wrap_bits-3)) ||
-            (st->first_dts < (1LL<<st->pts_wrap_bits) - av_rescale(60, st->time_base.den, st->time_base.num)) ?
-            AV_PTS_WRAP_ADD_OFFSET : AV_PTS_WRAP_SUB_OFFSET;
-
-        AVProgram *first_program = av_find_program_from_stream(s, NULL, stream_index);
-
-        if (!first_program) {
-            int default_stream_index = av_find_default_stream_index(s);
-            if (s->streams[default_stream_index]->pts_wrap_reference == AV_NOPTS_VALUE) {
-                for (i=0; i<s->nb_streams; i++) {
-                    s->streams[i]->pts_wrap_reference = pts_wrap_reference;
-                    s->streams[i]->pts_wrap_behavior = pts_wrap_behavior;
-                }
-            }
-            else {
-                st->pts_wrap_reference = s->streams[default_stream_index]->pts_wrap_reference;
-                st->pts_wrap_behavior = s->streams[default_stream_index]->pts_wrap_behavior;
-            }
-        }
-        else {
-            AVProgram *program = first_program;
-            while (program) {
-                if (program->pts_wrap_reference != AV_NOPTS_VALUE) {
-                    pts_wrap_reference = program->pts_wrap_reference;
-                    pts_wrap_behavior = program->pts_wrap_behavior;
-                    break;
-                }
-                program = av_find_program_from_stream(s, program, stream_index);
-            }
-
-            // update every program with differing pts_wrap_reference
-            program = first_program;
-            while(program) {
-                if (program->pts_wrap_reference != pts_wrap_reference) {
-                    for (i=0; i<program->nb_stream_indexes; i++) {
-                        s->streams[program->stream_index[i]]->pts_wrap_reference = pts_wrap_reference;
-                        s->streams[program->stream_index[i]]->pts_wrap_behavior = pts_wrap_behavior;
-                    }
-
-                    program->pts_wrap_reference = pts_wrap_reference;
-                    program->pts_wrap_behavior = pts_wrap_behavior;
-                }
-                program = av_find_program_from_stream(s, program, stream_index);
-            }
-        }
-        return 1;
-    }
-    return 0;
-}
-
 static void update_initial_timestamps(AVFormatContext *s, int stream_index,
                                       int64_t dts, int64_t pts, AVPacket *pkt)
 {
@@ -971,15 +987,6 @@ static void update_initial_timestamps(AVFormatContext *s, int stream_index,
         }
     }
 
-    if (update_wrap_reference(s, st, stream_index) && st->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET) {
-        // correct first time stamps to negative values
-        st->first_dts = wrap_timestamp(st, st->first_dts);
-        st->cur_dts = wrap_timestamp(st, st->cur_dts);
-        pkt->dts = wrap_timestamp(st, pkt->dts);
-        pkt->pts = wrap_timestamp(st, pkt->pts);
-        pts = wrap_timestamp(st, pts);
-    }
-
     if (st->start_time == AV_NOPTS_VALUE)
         st->start_time = pts;
 }
@@ -2694,6 +2701,113 @@ int ff_alloc_extradata(AVCodecContext *avctx, int size)
     return ret;
 }
 
+int ff_rfps_add_frame(AVFormatContext *ic, AVStream *st, int64_t ts)
+{
+    int i, j;
+    int64_t last = st->info->last_dts;
+
+    if(   ts != AV_NOPTS_VALUE && last != AV_NOPTS_VALUE && ts > last
+       && ts - (uint64_t)last < INT64_MAX){
+        double dts= (is_relative(ts) ?  ts - RELATIVE_TS_BASE : ts) * av_q2d(st->time_base);
+        int64_t duration= ts - last;
+
+        if (!st->info->duration_error)
+            st->info->duration_error = av_mallocz(sizeof(st->info->duration_error[0])*2);
+        if (!st->info->duration_error)
+            return AVERROR(ENOMEM);
+
+//         if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+//             av_log(NULL, AV_LOG_ERROR, "%f\n", dts);
+        for (i=0; i<MAX_STD_TIMEBASES; i++) {
+            if (st->info->duration_error[0][1][i] < 1e10) {
+                int framerate= get_std_framerate(i);
+                double sdts= dts*framerate/(1001*12);
+                for(j=0; j<2; j++){
+                    int64_t ticks= llrint(sdts+j*0.5);
+                    double error= sdts - ticks + j*0.5;
+                    st->info->duration_error[j][0][i] += error;
+                    st->info->duration_error[j][1][i] += error*error;
+                }
+            }
+        }
+        st->info->duration_count++;
+
+        if (st->info->duration_count % 10 == 0) {
+            int n = st->info->duration_count;
+            for (i=0; i<MAX_STD_TIMEBASES; i++) {
+                if (st->info->duration_error[0][1][i] < 1e10) {
+                    double a0     = st->info->duration_error[0][0][i] / n;
+                    double error0 = st->info->duration_error[0][1][i] / n - a0*a0;
+                    double a1     = st->info->duration_error[1][0][i] / n;
+                    double error1 = st->info->duration_error[1][1][i] / n - a1*a1;
+                    if (error0 > 0.04 && error1 > 0.04) {
+                        st->info->duration_error[0][1][i] = 2e10;
+                        st->info->duration_error[1][1][i] = 2e10;
+                    }
+                }
+            }
+        }
+
+        // ignore the first 4 values, they might have some random jitter
+        if (st->info->duration_count > 3 && is_relative(ts) == is_relative(last))
+            st->info->duration_gcd = av_gcd(st->info->duration_gcd, duration);
+    }
+    if (ts != AV_NOPTS_VALUE)
+        st->info->last_dts = ts;
+
+    return 0;
+}
+
+void ff_rfps_calculate(AVFormatContext *ic)
+{
+    int i, j;
+
+    for (i = 0; i<ic->nb_streams; i++) {
+        AVStream *st = ic->streams[i];
+
+        if (st->codec->codec_type != AVMEDIA_TYPE_VIDEO)
+            continue;
+        // the check for tb_unreliable() is not completely correct, since this is not about handling
+        // a unreliable/inexact time base, but a time base that is finer than necessary, as e.g.
+        // ipmovie.c produces.
+        if (tb_unreliable(st->codec) && st->info->duration_count > 15 && st->info->duration_gcd > FFMAX(1, st->time_base.den/(500LL*st->time_base.num)) && !st->r_frame_rate.num)
+            av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, st->time_base.den, st->time_base.num * st->info->duration_gcd, INT_MAX);
+        if (st->info->duration_count>1 && !st->r_frame_rate.num
+            && tb_unreliable(st->codec)) {
+            int num = 0;
+            double best_error= 0.01;
+
+            for (j=0; j<MAX_STD_TIMEBASES; j++) {
+                int k;
+
+                if(st->info->codec_info_duration && st->info->codec_info_duration*av_q2d(st->time_base) < (1001*12.0)/get_std_framerate(j))
+                    continue;
+                if(!st->info->codec_info_duration && 1.0 < (1001*12.0)/get_std_framerate(j))
+                    continue;
+                for(k=0; k<2; k++){
+                    int n= st->info->duration_count;
+                    double a= st->info->duration_error[k][0][j] / n;
+                    double error= st->info->duration_error[k][1][j]/n - a*a;
+
+                    if(error < best_error && best_error> 0.000000001){
+                        best_error= error;
+                        num = get_std_framerate(j);
+                    }
+                    if(error < 0.02)
+                        av_log(NULL, AV_LOG_DEBUG, "rfps: %f %f\n", get_std_framerate(j) / 12.0/1001, error);
+                }
+            }
+            // do not increase frame rate by more than 1 % in order to match a standard rate.
+            if (num && (!st->r_frame_rate.num || (double)num/(12*1001) < 1.01 * av_q2d(st->r_frame_rate)))
+                av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, num, 12*1001, INT_MAX);
+        }
+
+        av_freep(&st->info->duration_error);
+        st->info->last_dts = AV_NOPTS_VALUE;
+        st->info->duration_count = 0;
+    }
+}
+
 int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
 {
     int i, count, ret = 0, j;
@@ -2705,7 +2819,8 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
     int flush_codecs = ic->probesize > 0;
 
     if(ic->pb)
-        av_log(ic, AV_LOG_DEBUG, "File position before avformat_find_stream_info() is %"PRId64"\n", avio_tell(ic->pb));
+        av_log(ic, AV_LOG_DEBUG, "Before avformat_find_stream_info() pos: %"PRId64" bytes read:%"PRId64" seeks:%d\n",
+               avio_tell(ic->pb), ic->pb->bytes_read, ic->pb->seek_count);
 
     for(i=0;i<ic->nb_streams;i++) {
         const AVCodec *codec;
@@ -2910,39 +3025,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
             }
         }
 #if FF_API_R_FRAME_RATE
-        {
-            int64_t last = st->info->last_dts;
-
-            if(   pkt->dts != AV_NOPTS_VALUE && last != AV_NOPTS_VALUE && pkt->dts > last
-               && pkt->dts - (uint64_t)last < INT64_MAX){
-                double dts= (is_relative(pkt->dts) ?  pkt->dts - RELATIVE_TS_BASE : pkt->dts) * av_q2d(st->time_base);
-                int64_t duration= pkt->dts - last;
-
-                if (!st->info->duration_error)
-                    st->info->duration_error = av_mallocz(sizeof(st->info->duration_error[0])*2);
-                if (!st->info->duration_error)
-                    return AVERROR(ENOMEM);
-
-//                 if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
-//                     av_log(NULL, AV_LOG_ERROR, "%f\n", dts);
-                for (i=0; i<MAX_STD_TIMEBASES; i++) {
-                    int framerate= get_std_framerate(i);
-                    double sdts= dts*framerate/(1001*12);
-                    for(j=0; j<2; j++){
-                        int64_t ticks= llrint(sdts+j*0.5);
-                        double error= sdts - ticks + j*0.5;
-                        st->info->duration_error[j][0][i] += error;
-                        st->info->duration_error[j][1][i] += error*error;
-                    }
-                }
-                st->info->duration_count++;
-                // ignore the first 4 values, they might have some random jitter
-                if (st->info->duration_count > 3 && is_relative(pkt->dts) == is_relative(last))
-                    st->info->duration_gcd = av_gcd(st->info->duration_gcd, duration);
-            }
-            if (pkt->dts != AV_NOPTS_VALUE)
-                st->info->last_dts = pkt->dts;
-        }
+        ff_rfps_add_frame(ic, st, pkt->dts);
 #endif
         if(st->parser && st->parser->parser->split && !st->codec->extradata){
             int i= st->parser->parser->split(st->codec, pkt->data, pkt->size);
@@ -2998,6 +3081,9 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
         st = ic->streams[i];
         avcodec_close(st->codec);
     }
+
+    ff_rfps_calculate(ic);
+
     for(i=0;i<ic->nb_streams;i++) {
         st = ic->streams[i];
         if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
@@ -3036,40 +3122,6 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
                               best_fps, 12*1001, INT_MAX);
                 }
             }
-            // the check for tb_unreliable() is not completely correct, since this is not about handling
-            // a unreliable/inexact time base, but a time base that is finer than necessary, as e.g.
-            // ipmovie.c produces.
-            if (tb_unreliable(st->codec) && st->info->duration_count > 15 && st->info->duration_gcd > FFMAX(1, st->time_base.den/(500LL*st->time_base.num)) && !st->r_frame_rate.num)
-                av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, st->time_base.den, st->time_base.num * st->info->duration_gcd, INT_MAX);
-            if (st->info->duration_count>1 && !st->r_frame_rate.num
-                && tb_unreliable(st->codec)) {
-                int num = 0;
-                double best_error= 0.01;
-
-                for (j=0; j<MAX_STD_TIMEBASES; j++) {
-                    int k;
-
-                    if(st->info->codec_info_duration && st->info->codec_info_duration*av_q2d(st->time_base) < (1001*12.0)/get_std_framerate(j))
-                        continue;
-                    if(!st->info->codec_info_duration && 1.0 < (1001*12.0)/get_std_framerate(j))
-                        continue;
-                    for(k=0; k<2; k++){
-                        int n= st->info->duration_count;
-                        double a= st->info->duration_error[k][0][j] / n;
-                        double error= st->info->duration_error[k][1][j]/n - a*a;
-
-                        if(error < best_error && best_error> 0.000000001){
-                            best_error= error;
-                            num = get_std_framerate(j);
-                        }
-                        if(error < 0.02)
-                            av_log(NULL, AV_LOG_DEBUG, "rfps: %f %f\n", get_std_framerate(j) / 12.0/1001, error);
-                    }
-                }
-                // do not increase frame rate by more than 1 % in order to match a standard rate.
-                if (num && (!st->r_frame_rate.num || (double)num/(12*1001) < 1.01 * av_q2d(st->r_frame_rate)))
-                    av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, num, 12*1001, INT_MAX);
-            }
 
             if (!st->r_frame_rate.num){
                 if(    st->codec->time_base.den * (int64_t)st->time_base.num
@@ -3132,7 +3184,8 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
         av_freep(&ic->streams[i]->info);
     }
     if(ic->pb)
-        av_log(ic, AV_LOG_DEBUG, "File position after avformat_find_stream_info() is %"PRId64"\n", avio_tell(ic->pb));
+        av_log(ic, AV_LOG_DEBUG, "After avformat_find_stream_info() pos: %"PRId64" bytes read:%"PRId64" seeks:%d frames:%d\n",
+               avio_tell(ic->pb), ic->pb->bytes_read, ic->pb->seek_count, count);
     return ret;
 }