Merge commit 'f154ef1ae5b03f288dd8c025dab1884b4cb20c1a'
authorMichael Niedermayer <michaelni@gmx.at>
Thu, 9 Aug 2012 13:14:57 +0000 (15:14 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Thu, 9 Aug 2012 13:23:00 +0000 (15:23 +0200)
* commit 'f154ef1ae5b03f288dd8c025dab1884b4cb20c1a':
  avconv: send EOF to lavfi even if flushing the decoder fails
  avconv: get rid of pointless temporary variable.
  avconv: simplify transcode().
  avconv: cosmetics
  avconv: replace no_packet array in transcode() with a var in InputStream
  avconv: remove unused variable from InputFile.
  avconv: remove commented out cruft.
  avconv: maintain sync on lavfi outputs.

Conflicts:
ffmpeg.c
ffmpeg.h

Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
ffmpeg.c
ffmpeg.h

diff --cc ffmpeg.c
+++ b/ffmpeg.c
@@@ -1410,23 -1068,12 +1410,21 @@@ static int decode_audio(InputStream *is
          avcodec_get_frame_defaults(ist->decoded_frame);
      decoded_frame = ist->decoded_frame;
  
 +    update_benchmark(NULL);
      ret = avcodec_decode_audio4(avctx, decoded_frame, got_output, pkt);
-     if (ret < 0) {
-         return ret;
-     }
-     if (avctx->sample_rate <= 0) {
 +    update_benchmark("decode_audio %d.%d", ist->file_index, ist->st->index);
-     if (!*got_output) {
-         /* no audio frame */
-         if (!pkt->size)
++
++    if (ret >= 0 && avctx->sample_rate <= 0) {
 +        av_log(avctx, AV_LOG_ERROR, "Sample rate %d invalid\n", avctx->sample_rate);
 +        return AVERROR_INVALIDDATA;
 +    }
 +
+     if (!*got_output || ret < 0) {
+         if (!pkt->size) {
              for (i = 0; i < ist->nb_filters; i++)
 -                av_buffersrc_buffer(ist->filters[i]->filter, NULL);
 +                av_buffersrc_add_ref(ist->filters[i]->filter, NULL,
 +                                     AV_BUFFERSRC_FLAG_NO_COPY);
+         }
          return ret;
      }
  
@@@ -1535,41 -1209,20 +1533,39 @@@ static int decode_video(InputStream *is
      else
          avcodec_get_frame_defaults(ist->decoded_frame);
      decoded_frame = ist->decoded_frame;
 +    pkt->dts  = av_rescale_q(ist->dts, AV_TIME_BASE_Q, ist->st->time_base);
  
 +    update_benchmark(NULL);
      ret = avcodec_decode_video2(ist->st->codec,
                                  decoded_frame, got_output, pkt);
-     if (ret < 0)
-         return ret;
-     quality = same_quant ? decoded_frame->quality : 0;
-     if (!*got_output) {
-         /* no picture yet */
-         if (!pkt->size)
 +    update_benchmark("decode_video %d.%d", ist->file_index, ist->st->index);
+     if (!*got_output || ret < 0) {
+         if (!pkt->size) {
              for (i = 0; i < ist->nb_filters; i++)
 -                av_buffersrc_buffer(ist->filters[i]->filter, NULL);
 +                av_buffersrc_add_ref(ist->filters[i]->filter, NULL, AV_BUFFERSRC_FLAG_NO_COPY);
+         }
          return ret;
      }
  
 -    decoded_frame->pts = guess_correct_pts(&ist->pts_ctx, decoded_frame->pkt_pts,
 -                                           decoded_frame->pkt_dts);
+     quality = same_quant ? decoded_frame->quality : 0;
++
 +    if(ist->top_field_first>=0)
 +        decoded_frame->top_field_first = ist->top_field_first;
 +
 +    best_effort_timestamp= av_frame_get_best_effort_timestamp(decoded_frame);
 +    if(best_effort_timestamp != AV_NOPTS_VALUE)
 +        ist->next_pts = ist->pts = av_rescale_q(decoded_frame->pts = best_effort_timestamp, ist->st->time_base, AV_TIME_BASE_Q);
 +
 +    if (debug_ts) {
 +        av_log(NULL, AV_LOG_INFO, "decoder -> ist_index:%d type:video "
 +                "frame_pts:%s frame_pts_time:%s best_effort_ts:%"PRId64" best_effort_ts_time:%s keyframe:%d frame_type:%d \n",
 +                ist->st->index, av_ts2str(decoded_frame->pts),
 +                av_ts2timestr(decoded_frame->pts, &ist->st->time_base),
 +                best_effort_timestamp,
 +                av_ts2timestr(best_effort_timestamp, &ist->st->time_base),
 +                decoded_frame->key_frame, decoded_frame->pict_type);
 +    }
 +
      pkt->size = 0;
      pre_process_video_frame(ist, (AVPicture *)decoded_frame, &buffer_to_free);
  
@@@ -2387,177 -1948,27 +2383,177 @@@ static int need_output(void
      return 0;
  }
  
 -static InputFile *select_input_file(void)
 +static int input_acceptable(InputStream *ist)
  {
 -    InputFile *ifile = NULL;
 -    int64_t ipts_min = INT64_MAX;
 -    int i;
 +    av_assert1(!ist->discard);
-     return !input_files[ist->file_index]->unavailable &&
++    return !input_files[ist->file_index]->eagain &&
 +           !input_files[ist->file_index]->eof_reached;
 +}
  
 -    for (i = 0; i < nb_input_streams; i++) {
 -        InputStream *ist = input_streams[i];
 -        int64_t ipts     = ist->last_dts;
 +static int find_graph_input(FilterGraph *graph)
 +{
 +    int i, nb_req_max = 0, file_index = -1;
 +
 +    for (i = 0; i < graph->nb_inputs; i++) {
 +        int nb_req = av_buffersrc_get_nb_failed_requests(graph->inputs[i]->filter);
 +        if (nb_req > nb_req_max) {
 +            InputStream *ist = graph->inputs[i]->ist;
 +            if (input_acceptable(ist)) {
 +                nb_req_max = nb_req;
 +                file_index = ist->file_index;
 +            }
 +        }
 +    }
  
 -        if (ist->discard || input_files[ist->file_index]->eagain)
 -            continue;
 -        if (!input_files[ist->file_index]->eof_reached) {
 -            if (ipts < ipts_min) {
 -                ipts_min = ipts;
 -                ifile    = input_files[ist->file_index];
 +    return file_index;
 +}
 +
 +/**
 + * Select the input file to read from.
 + *
 + * @return  >=0 index of the input file to use;
 + *          -1  if no file is acceptable;
 + *          -2  to read from filters without reading from a file
 + */
 +static int select_input_file(void)
 +{
 +    int i, ret, nb_active_out = nb_output_streams, ost_index = -1;
 +    int64_t opts_min;
 +    OutputStream *ost;
 +    AVFilterBufferRef *dummy;
 +
 +    for (i = 0; i < nb_output_streams; i++)
 +        nb_active_out -= output_streams[i]->unavailable =
 +            output_streams[i]->is_past_recording_time;
 +    while (nb_active_out) {
 +        opts_min = INT64_MAX;
 +        ost_index = -1;
 +        for (i = 0; i < nb_output_streams; i++) {
 +            OutputStream *ost = output_streams[i];
 +            int64_t opts = av_rescale_q(ost->st->cur_dts, ost->st->time_base,
 +                                        AV_TIME_BASE_Q);
 +            if (!ost->unavailable && opts < opts_min) {
 +                opts_min  = opts;
 +                ost_index = i;
              }
          }
 +        if (ost_index < 0)
 +            return -1;
 +
 +        ost = output_streams[ost_index];
 +        if (ost->source_index >= 0) {
 +            /* ost is directly connected to an input */
 +            InputStream *ist = input_streams[ost->source_index];
 +            if (input_acceptable(ist))
 +                return ist->file_index;
 +        } else {
 +            /* ost is connected to a complex filtergraph */
 +            av_assert1(ost->filter);
 +            ret = av_buffersink_get_buffer_ref(ost->filter->filter, &dummy,
 +                                               AV_BUFFERSINK_FLAG_PEEK);
 +            if (ret >= 0)
 +                return -2;
 +            ret = find_graph_input(ost->filter->graph);
 +            if (ret >= 0)
 +                return ret;
 +        }
 +        ost->unavailable = 1;
 +        nb_active_out--;
      }
 +    return -1;
 +}
  
 -    return ifile;
 +static int check_keyboard_interaction(int64_t cur_time)
 +{
 +    int i, ret, key;
 +    static int64_t last_time;
 +    if (received_nb_signals)
 +        return AVERROR_EXIT;
 +    /* read_key() returns 0 on EOF */
 +    if(cur_time - last_time >= 100000 && !run_as_daemon){
 +        key =  read_key();
 +        last_time = cur_time;
 +    }else
 +        key = -1;
 +    if (key == 'q')
 +        return AVERROR_EXIT;
 +    if (key == '+') av_log_set_level(av_log_get_level()+10);
 +    if (key == '-') av_log_set_level(av_log_get_level()-10);
 +    if (key == 's') qp_hist     ^= 1;
 +    if (key == 'h'){
 +        if (do_hex_dump){
 +            do_hex_dump = do_pkt_dump = 0;
 +        } else if(do_pkt_dump){
 +            do_hex_dump = 1;
 +        } else
 +            do_pkt_dump = 1;
 +        av_log_set_level(AV_LOG_DEBUG);
 +    }
 +    if (key == 'c' || key == 'C'){
 +        char buf[4096], target[64], command[256], arg[256] = {0};
 +        double time;
 +        int k, n = 0;
 +        fprintf(stderr, "\nEnter command: <target> <time> <command>[ <argument>]\n");
 +        i = 0;
 +        while ((k = read_key()) != '\n' && k != '\r' && i < sizeof(buf)-1)
 +            if (k > 0)
 +                buf[i++] = k;
 +        buf[i] = 0;
 +        if (k > 0 &&
 +            (n = sscanf(buf, "%63[^ ] %lf %255[^ ] %255[^\n]", target, &time, command, arg)) >= 3) {
 +            av_log(NULL, AV_LOG_DEBUG, "Processing command target:%s time:%f command:%s arg:%s",
 +                   target, time, command, arg);
 +            for (i = 0; i < nb_filtergraphs; i++) {
 +                FilterGraph *fg = filtergraphs[i];
 +                if (fg->graph) {
 +                    if (time < 0) {
 +                        ret = avfilter_graph_send_command(fg->graph, target, command, arg, buf, sizeof(buf),
 +                                                          key == 'c' ? AVFILTER_CMD_FLAG_ONE : 0);
 +                        fprintf(stderr, "Command reply for stream %d: ret:%d res:%s\n", i, ret, buf);
 +                    } else {
 +                        ret = avfilter_graph_queue_command(fg->graph, target, command, arg, 0, time);
 +                    }
 +                }
 +            }
 +        } else {
 +            av_log(NULL, AV_LOG_ERROR,
 +                   "Parse error, at least 3 arguments were expected, "
 +                   "only %d given in string '%s'\n", n, buf);
 +        }
 +    }
 +    if (key == 'd' || key == 'D'){
 +        int debug=0;
 +        if(key == 'D') {
 +            debug = input_streams[0]->st->codec->debug<<1;
 +            if(!debug) debug = 1;
 +            while(debug & (FF_DEBUG_DCT_COEFF|FF_DEBUG_VIS_QP|FF_DEBUG_VIS_MB_TYPE)) //unsupported, would just crash
 +                debug += debug;
 +        }else
 +            if(scanf("%d", &debug)!=1)
 +                fprintf(stderr,"error parsing debug value\n");
 +        for(i=0;i<nb_input_streams;i++) {
 +            input_streams[i]->st->codec->debug = debug;
 +        }
 +        for(i=0;i<nb_output_streams;i++) {
 +            OutputStream *ost = output_streams[i];
 +            ost->st->codec->debug = debug;
 +        }
 +        if(debug) av_log_set_level(AV_LOG_DEBUG);
 +        fprintf(stderr,"debug=%d\n", debug);
 +    }
 +    if (key == '?'){
 +        fprintf(stderr, "key    function\n"
 +                        "?      show this help\n"
 +                        "+      increase verbosity\n"
 +                        "-      decrease verbosity\n"
 +                        "c      Send command to filtergraph\n"
 +                        "D      cycle through available debug modes\n"
 +                        "h      dump packets/hex press to cycle through the 3 states\n"
 +                        "q      quit\n"
 +                        "s      Show QP histogram\n"
 +        );
 +    }
 +    return 0;
  }
  
  #if HAVE_PTHREADS
@@@ -2706,15 -2131,9 +2717,16 @@@ static int transcode(void
          goto fail;
  #endif
  
-     for (; received_sigterm == 0;) {
-         int file_index, ist_index;
+     while (!received_sigterm) {
+         InputFile *ifile;
          AVPacket pkt;
++        int file_index;
 +        int64_t cur_time= av_gettime();
 +
 +        /* if 'q' pressed, exits */
 +        if (stdin_interaction)
 +            if (check_keyboard_interaction(cur_time) < 0)
 +                break;
  
          /* check if there's any stream where output is still needed */
          if (!need_output()) {
          }
  
          /* select the stream that we must read now */
 -        ifile = select_input_file();
 +        file_index = select_input_file();
          /* if none, if is finished */
 -        if (!ifile) {
 +        if (file_index == -2) {
 +            poll_filters() ;
 +            continue;
 +        }
 +        if (file_index < 0) {
-             if (no_packet_count) {
-                 no_packet_count = 0;
-                 for (i = 0; i < nb_input_files; i++)
-                     input_files[i]->unavailable = 0;
+             if (got_eagain()) {
+                 reset_eagain();
                  av_usleep(10000);
                  continue;
              }
              av_log(NULL, AV_LOG_VERBOSE, "No more inputs to read from, finishing.\n");
              break;
          }
++        ifile = input_files[file_index];
  
-         is  = input_files[file_index]->ctx;
-         ret = get_input_packet(input_files[file_index], &pkt);
+         is  = ifile->ctx;
+         ret = get_input_packet(ifile, &pkt);
  
          if (ret == AVERROR(EAGAIN)) {
-             input_files[file_index]->unavailable = 1;
-             no_packet_count++;
+             ifile->eagain = 1;
              continue;
          }
          if (ret < 0) {
                  if (exit_on_error)
                      exit_program(1);
              }
-             input_files[file_index]->eof_reached = 1;
+             ifile->eof_reached = 1;
  
-             for (i = 0; i < input_files[file_index]->nb_streams; i++) {
-                 ist = input_streams[input_files[file_index]->ist_index + i];
+             for (i = 0; i < ifile->nb_streams; i++) {
+                 ist = input_streams[ifile->ist_index + i];
                  if (ist->decoding_needed)
                      output_packet(ist, NULL);
 +                poll_filters();
              }
  
              if (opt_shortest)
          }
          /* the following test is needed in case new streams appear
             dynamically in stream : we ignore them */
-         if (pkt.stream_index >= input_files[file_index]->nb_streams) {
 -        if (pkt.stream_index >= ifile->nb_streams)
++        if (pkt.stream_index >= ifile->nb_streams) {
 +            report_new_stream(file_index, &pkt);
              goto discard_packet;
-         ist_index = input_files[file_index]->ist_index + pkt.stream_index;
-         ist = input_streams[ist_index];
 +        }
+         ist = input_streams[ifile->ist_index + pkt.stream_index];
          if (ist->discard)
              goto discard_packet;
  
 +        if(!ist->wrap_correction_done && input_files[file_index]->ctx->start_time != AV_NOPTS_VALUE && ist->st->pts_wrap_bits < 64){
 +            uint64_t stime = av_rescale_q(input_files[file_index]->ctx->start_time, AV_TIME_BASE_Q, ist->st->time_base);
 +            uint64_t stime2= stime + (1LL<<ist->st->pts_wrap_bits);
 +            ist->wrap_correction_done = 1;
 +            if(pkt.dts != AV_NOPTS_VALUE && pkt.dts > stime && pkt.dts - stime > stime2 - pkt.dts) {
 +                pkt.dts -= 1LL<<ist->st->pts_wrap_bits;
 +                ist->wrap_correction_done = 0;
 +            }
 +            if(pkt.pts != AV_NOPTS_VALUE && pkt.pts > stime && pkt.pts - stime > stime2 - pkt.pts) {
 +                pkt.pts -= 1LL<<ist->st->pts_wrap_bits;
 +                ist->wrap_correction_done = 0;
 +            }
 +        }
 +
          if (pkt.dts != AV_NOPTS_VALUE)
-             pkt.dts += av_rescale_q(input_files[ist->file_index]->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);
+             pkt.dts += av_rescale_q(ifile->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);
          if (pkt.pts != AV_NOPTS_VALUE)
-             pkt.pts += av_rescale_q(input_files[ist->file_index]->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);
+             pkt.pts += av_rescale_q(ifile->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);
  
          if (pkt.pts != AV_NOPTS_VALUE)
              pkt.pts *= ist->ts_scale;
          if (pkt.dts != AV_NOPTS_VALUE)
              pkt.dts *= ist->ts_scale;
  
 -        if (pkt.dts != AV_NOPTS_VALUE && ist->next_dts != AV_NOPTS_VALUE
 -            && (is->iformat->flags & AVFMT_TS_DISCONT)) {
 +        if (debug_ts) {
 +            av_log(NULL, AV_LOG_INFO, "demuxer -> ist_index:%d type:%s "
 +                    "next_dts:%s next_dts_time:%s next_pts:%s next_pts_time:%s  pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s off:%"PRId64"\n",
-                     ist_index, av_get_media_type_string(ist->st->codec->codec_type),
++                    ifile->ist_index + pkt.stream_index, av_get_media_type_string(ist->st->codec->codec_type),
 +                    av_ts2str(ist->next_dts), av_ts2timestr(ist->next_dts, &AV_TIME_BASE_Q),
 +                    av_ts2str(ist->next_pts), av_ts2timestr(ist->next_pts, &AV_TIME_BASE_Q),
 +                    av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ist->st->time_base),
 +                    av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ist->st->time_base),
 +                    input_files[ist->file_index]->ts_offset);
 +        }
 +
 +        if (pkt.dts != AV_NOPTS_VALUE && ist->next_dts != AV_NOPTS_VALUE && !copy_ts) {
              int64_t pkt_dts = av_rescale_q(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q);
              int64_t delta   = pkt_dts - ist->next_dts;
 -            if ((FFABS(delta) > 1LL * dts_delta_threshold * AV_TIME_BASE || pkt_dts + 1 < ist->last_dts) && !copy_ts) {
 +            if (is->iformat->flags & AVFMT_TS_DISCONT) {
 +            if(delta < -1LL*dts_delta_threshold*AV_TIME_BASE ||
 +                (delta > 1LL*dts_delta_threshold*AV_TIME_BASE &&
 +                 ist->st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) ||
 +                pkt_dts+1<ist->pts){
-                 input_files[ist->file_index]->ts_offset -= delta;
+                 ifile->ts_offset -= delta;
                  av_log(NULL, AV_LOG_DEBUG,
                         "timestamp discontinuity %"PRId64", new offset= %"PRId64"\n",
-                        delta, input_files[ist->file_index]->ts_offset);
+                        delta, ifile->ts_offset);
                  pkt.dts-= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
                  if (pkt.pts != AV_NOPTS_VALUE)
                      pkt.pts-= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
              }
 +            } else {
 +                if ( delta < -1LL*dts_error_threshold*AV_TIME_BASE ||
 +                    (delta > 1LL*dts_error_threshold*AV_TIME_BASE && ist->st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) ||
 +                     pkt_dts+1<ist->pts){
 +                    av_log(NULL, AV_LOG_WARNING, "DTS %"PRId64", next:%"PRId64" st:%d invalid dropping\n", pkt.dts, ist->next_dts, pkt.stream_index);
 +                    pkt.dts = AV_NOPTS_VALUE;
 +                }
 +                if (pkt.pts != AV_NOPTS_VALUE){
 +                    int64_t pkt_pts = av_rescale_q(pkt.pts, ist->st->time_base, AV_TIME_BASE_Q);
 +                    delta   = pkt_pts - ist->next_dts;
 +                    if ( delta < -1LL*dts_error_threshold*AV_TIME_BASE ||
 +                        (delta > 1LL*dts_error_threshold*AV_TIME_BASE && ist->st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) ||
 +                        pkt_pts+1<ist->pts) {
 +                        av_log(NULL, AV_LOG_WARNING, "PTS %"PRId64", next:%"PRId64" invalid dropping st:%d\n", pkt.pts, ist->next_dts, pkt.stream_index);
 +                        pkt.pts = AV_NOPTS_VALUE;
 +                    }
 +                }
 +            }
          }
  
 -        if (output_packet(ist, &pkt) < 0 || poll_filters() < 0) {
 -            av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d\n",
 -                   ist->file_index, ist->st->index);
 +        sub2video_heartbeat(ist, pkt.pts);
 +
-         // fprintf(stderr,"read #%d.%d size=%d\n", ist->file_index, ist->st->index, pkt.size);
 +        if ((ret = output_packet(ist, &pkt)) < 0 ||
 +            ((ret = poll_filters()) < 0 && ret != AVERROR_EOF)) {
 +            char buf[128];
 +            av_strerror(ret, buf, sizeof(buf));
 +            av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d: %s\n",
 +                   ist->file_index, ist->st->index, buf);
              if (exit_on_error)
                  exit_program(1);
              av_free_packet(&pkt);
diff --cc ffmpeg.h
+++ b/ffmpeg.h
@@@ -242,12 -230,11 +242,12 @@@ typedef struct InputStream 
  typedef struct InputFile {
      AVFormatContext *ctx;
      int eof_reached;      /* true if eof reached */
-     int unavailable;      /* true if the file is unavailable (possibly temporarily) */
+     int eagain;           /* true if last read attempt returned EAGAIN */
 -    int ist_index;        /* index of first stream in ist_table */
 +    int ist_index;        /* index of first stream in input_streams */
      int64_t ts_offset;
 -    int nb_streams;       /* number of stream that avconv is aware of; may be different
 +    int nb_streams;       /* number of stream that ffmpeg is aware of; may be different
                               from ctx.nb_streams if new streams appear during av_read_frame() */
 +    int nb_streams_warn;  /* number of streams that the user was warned of */
      int rate_emu;
  
  #if HAVE_PTHREADS