]> git.sesse.net Git - ffmpeg/blobdiff - avconv.c
avconv: call flush_encoders() from transcode() directly.
[ffmpeg] / avconv.c
index 12ee3dc9f3a3aa7f621df3b2fc238768771717d3..11d77419eb916db2f2c99b2f3fcf850c898be0da 100644 (file)
--- a/avconv.c
+++ b/avconv.c
@@ -143,7 +143,6 @@ static int qp_hist = 0;
 static char *vfilters = NULL;
 #endif
 
-static int intra_only = 0;
 static int audio_sample_rate = 0;
 #define QSCALE_NONE -99999
 static float audio_qscale = QSCALE_NONE;
@@ -198,7 +197,7 @@ static int64_t extra_size = 0;
 static int nb_frames_dup = 0;
 static int nb_frames_drop = 0;
 static int input_sync;
-static uint64_t limit_filesize = 0;
+static uint64_t limit_filesize = UINT64_MAX;
 static int force_fps = 0;
 static char *forced_key_frames = NULL;
 
@@ -304,6 +303,7 @@ typedef struct OutputFile {
     int ost_index;       /* index of the first stream in output_streams */
     int64_t recording_time; /* desired length of the resulting file in microseconds */
     int64_t start_time;     /* start time in microseconds */
+    uint64_t limit_filesize;
 } OutputFile;
 
 static InputStream *input_streams = NULL;
@@ -394,7 +394,7 @@ static int configure_video_filters(InputStream *ist, OutputStream *ost)
     codec->width  = ost->output_video_filter->inputs[0]->w;
     codec->height = ost->output_video_filter->inputs[0]->h;
     codec->sample_aspect_ratio = ost->st->sample_aspect_ratio =
-        ost->frame_aspect_ratio ? // overriden by the -aspect cli option
+        ost->frame_aspect_ratio ? // overridden by the -aspect cli option
         av_d2q(ost->frame_aspect_ratio*codec->height/codec->width, 255) :
         ost->output_video_filter->inputs[0]->sample_aspect_ratio;
 
@@ -457,7 +457,6 @@ static int exit_program(int ret)
         fclose(vstats_file);
     av_free(vstats_filename);
 
-    av_free(streamid_map);
     av_free(meta_data_maps);
 
     av_freep(&input_streams);
@@ -1076,7 +1075,7 @@ static void do_video_resample(OutputStream *ost,
     if (resample_changed) {
         avfilter_graph_free(&ost->graph);
         if (configure_video_filters(ist, ost)) {
-            fprintf(stderr, "Error reinitialising filters!\n");
+            fprintf(stderr, "Error reinitializing filters!\n");
             exit_program(1);
         }
     }
@@ -1153,7 +1152,7 @@ static void do_video_out(AVFormatContext *s,
 
         if (s->oformat->flags & AVFMT_RAWPICTURE) {
             /* raw pictures are written as AVPicture structure to
-               avoid any copies. We support temorarily the older
+               avoid any copies. We support temporarily the older
                method. */
             AVFrame* old_frame = enc->coded_frame;
             enc->coded_frame = dec->coded_frame; //FIXME/XXX remove this hack
@@ -1398,6 +1397,91 @@ static void generate_silence(uint8_t* buf, enum AVSampleFormat sample_fmt, size_
     memset(buf, fill_char, size);
 }
 
+static void flush_encoders(OutputStream *ost_table, int nb_ostreams)
+{
+    int i, ret;
+
+    for (i = 0; i < nb_ostreams; i++) {
+        OutputStream   *ost = &ost_table[i];
+        AVCodecContext *enc = ost->st->codec;
+        AVFormatContext *os = output_files[ost->file_index].ctx;
+
+        if (!ost->encoding_needed)
+            continue;
+
+        if (ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO && enc->frame_size <=1)
+            continue;
+        if (ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO && (os->oformat->flags & AVFMT_RAWPICTURE))
+            continue;
+
+        for(;;) {
+            AVPacket pkt;
+            int fifo_bytes;
+            av_init_packet(&pkt);
+            pkt.stream_index= ost->index;
+
+            switch (ost->st->codec->codec_type) {
+            case AVMEDIA_TYPE_AUDIO:
+                fifo_bytes = av_fifo_size(ost->fifo);
+                ret = 0;
+                /* encode any samples remaining in fifo */
+                if (fifo_bytes > 0) {
+                    int osize = av_get_bytes_per_sample(enc->sample_fmt);
+                    int fs_tmp = enc->frame_size;
+
+                    av_fifo_generic_read(ost->fifo, audio_buf, fifo_bytes, NULL);
+                    if (enc->codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME) {
+                        enc->frame_size = fifo_bytes / (osize * enc->channels);
+                    } else { /* pad */
+                        int frame_bytes = enc->frame_size*osize*enc->channels;
+                        if (allocated_audio_buf_size < frame_bytes)
+                            exit_program(1);
+                        generate_silence(audio_buf+fifo_bytes, enc->sample_fmt, frame_bytes - fifo_bytes);
+                    }
+
+                    ret = avcodec_encode_audio(enc, bit_buffer, bit_buffer_size, (short *)audio_buf);
+                    pkt.duration = av_rescale((int64_t)enc->frame_size*ost->st->time_base.den,
+                                              ost->st->time_base.num, enc->sample_rate);
+                    enc->frame_size = fs_tmp;
+                }
+                if (ret <= 0) {
+                    ret = avcodec_encode_audio(enc, bit_buffer, bit_buffer_size, NULL);
+                }
+                if (ret < 0) {
+                    fprintf(stderr, "Audio encoding failed\n");
+                    exit_program(1);
+                }
+                audio_size += ret;
+                pkt.flags |= AV_PKT_FLAG_KEY;
+                break;
+            case AVMEDIA_TYPE_VIDEO:
+                ret = avcodec_encode_video(enc, bit_buffer, bit_buffer_size, NULL);
+                if (ret < 0) {
+                    fprintf(stderr, "Video encoding failed\n");
+                    exit_program(1);
+                }
+                video_size += ret;
+                if(enc->coded_frame && enc->coded_frame->key_frame)
+                    pkt.flags |= AV_PKT_FLAG_KEY;
+                if (ost->logfile && enc->stats_out) {
+                    fprintf(ost->logfile, "%s", enc->stats_out);
+                }
+                break;
+            default:
+                ret=-1;
+            }
+
+            if (ret <= 0)
+                break;
+            pkt.data = bit_buffer;
+            pkt.size = ret;
+            if (enc->coded_frame && enc->coded_frame->pts != AV_NOPTS_VALUE)
+                pkt.pts= av_rescale_q(enc->coded_frame->pts, enc->time_base, ost->st->time_base);
+            write_frame(os, &pkt, ost->st->codec, ost->bitstream_filters);
+        }
+    }
+}
+
 /* pkt = NULL means EOF (needed to flush decoder buffers) */
 static int output_packet(InputStream *ist, int ist_index,
                          OutputStream *ost_table, int nb_ostreams,
@@ -1713,90 +1797,6 @@ static int output_packet(InputStream *ist, int ist_index,
         }
     }
  discard_packet:
-    if (pkt == NULL) {
-        /* EOF handling */
-
-        for(i=0;i<nb_ostreams;i++) {
-            ost = &ost_table[i];
-            if (ost->source_index == ist_index) {
-                AVCodecContext *enc= ost->st->codec;
-                os = output_files[ost->file_index].ctx;
-
-                if(ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO && enc->frame_size <=1)
-                    continue;
-                if(ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO && (os->oformat->flags & AVFMT_RAWPICTURE))
-                    continue;
-
-                if (ost->encoding_needed) {
-                    for(;;) {
-                        AVPacket pkt;
-                        int fifo_bytes;
-                        av_init_packet(&pkt);
-                        pkt.stream_index= ost->index;
-
-                        switch(ost->st->codec->codec_type) {
-                        case AVMEDIA_TYPE_AUDIO:
-                            fifo_bytes = av_fifo_size(ost->fifo);
-                            ret = 0;
-                            /* encode any samples remaining in fifo */
-                            if (fifo_bytes > 0) {
-                                int osize = av_get_bytes_per_sample(enc->sample_fmt);
-                                int fs_tmp = enc->frame_size;
-
-                                av_fifo_generic_read(ost->fifo, audio_buf, fifo_bytes, NULL);
-                                if (enc->codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME) {
-                                    enc->frame_size = fifo_bytes / (osize * enc->channels);
-                                } else { /* pad */
-                                    int frame_bytes = enc->frame_size*osize*enc->channels;
-                                    if (allocated_audio_buf_size < frame_bytes)
-                                        exit_program(1);
-                                    generate_silence(audio_buf+fifo_bytes, enc->sample_fmt, frame_bytes - fifo_bytes);
-                                }
-
-                                ret = avcodec_encode_audio(enc, bit_buffer, bit_buffer_size, (short *)audio_buf);
-                                pkt.duration = av_rescale((int64_t)enc->frame_size*ost->st->time_base.den,
-                                                          ost->st->time_base.num, enc->sample_rate);
-                                enc->frame_size = fs_tmp;
-                            }
-                            if(ret <= 0) {
-                                ret = avcodec_encode_audio(enc, bit_buffer, bit_buffer_size, NULL);
-                            }
-                            if (ret < 0) {
-                                fprintf(stderr, "Audio encoding failed\n");
-                                exit_program(1);
-                            }
-                            audio_size += ret;
-                            pkt.flags |= AV_PKT_FLAG_KEY;
-                            break;
-                        case AVMEDIA_TYPE_VIDEO:
-                            ret = avcodec_encode_video(enc, bit_buffer, bit_buffer_size, NULL);
-                            if (ret < 0) {
-                                fprintf(stderr, "Video encoding failed\n");
-                                exit_program(1);
-                            }
-                            video_size += ret;
-                            if(enc->coded_frame && enc->coded_frame->key_frame)
-                                pkt.flags |= AV_PKT_FLAG_KEY;
-                            if (ost->logfile && enc->stats_out) {
-                                fprintf(ost->logfile, "%s", enc->stats_out);
-                            }
-                            break;
-                        default:
-                            ret=-1;
-                        }
-
-                        if(ret<=0)
-                            break;
-                        pkt.data= bit_buffer;
-                        pkt.size= ret;
-                        if(enc->coded_frame && enc->coded_frame->pts != AV_NOPTS_VALUE)
-                            pkt.pts= av_rescale_q(enc->coded_frame->pts, enc->time_base, ost->st->time_base);
-                        write_frame(os, &pkt, ost->st->codec, ost->bitstream_filters);
-                    }
-                }
-            }
-        }
-    }
 
     return 0;
 }
@@ -1818,6 +1818,48 @@ static void print_sdp(OutputFile *output_files, int n)
     av_freep(&avc);
 }
 
+static int init_input_stream(int ist_index, OutputStream *output_streams, int nb_output_streams,
+                             char *error, int error_len)
+{
+    int i;
+    InputStream *ist = &input_streams[ist_index];
+    if (ist->decoding_needed) {
+        AVCodec *codec = ist->dec;
+        if (!codec)
+            codec = avcodec_find_decoder(ist->st->codec->codec_id);
+        if (!codec) {
+            snprintf(error, sizeof(error), "Decoder (codec id %d) not found for input stream #%d.%d",
+                    ist->st->codec->codec_id, ist->file_index, ist->st->index);
+            return AVERROR(EINVAL);
+        }
+
+        /* update requested sample format for the decoder based on the
+           corresponding encoder sample format */
+        for (i = 0; i < nb_output_streams; i++) {
+            OutputStream *ost = &output_streams[i];
+            if (ost->source_index == ist_index) {
+                update_sample_fmt(ist->st->codec, codec, ost->st->codec);
+                break;
+            }
+        }
+
+        if (avcodec_open2(ist->st->codec, codec, &ist->opts) < 0) {
+            snprintf(error, sizeof(error), "Error while opening decoder for input stream #%d.%d",
+                    ist->file_index, ist->st->index);
+            return AVERROR(EINVAL);
+        }
+        assert_codec_experimental(ist->st->codec, 0);
+        assert_avoptions(ist->opts);
+    }
+
+    ist->pts = ist->st->avg_frame_rate.num ? - ist->st->codec->has_b_frames*AV_TIME_BASE / av_q2d(ist->st->avg_frame_rate) : 0;
+    ist->next_pts = AV_NOPTS_VALUE;
+    init_pts_correction(&ist->pts_ctx);
+    ist->is_start = 1;
+
+    return 0;
+}
+
 /*
  * The following code is the main loop of the file converter
  */
@@ -1826,7 +1868,7 @@ static int transcode(OutputFile *output_files,
                      InputFile *input_files,
                      int nb_input_files)
 {
-    int ret = 0, i, j;
+    int ret = 0, i;
     AVFormatContext *is, *os;
     AVCodecContext *codec, *icodec;
     OutputStream *ost;
@@ -1871,8 +1913,10 @@ static int transcode(OutputFile *output_files,
         if (ost->st->stream_copy) {
             uint64_t extra_size = (uint64_t)icodec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE;
 
-            if (extra_size > INT_MAX)
+            if (extra_size > INT_MAX) {
+                ret = AVERROR(EINVAL);
                 goto fail;
+            }
 
             /* if stream_copy is selected, no need to decode or encode */
             codec->codec_id = icodec->codec_id;
@@ -1889,8 +1933,10 @@ static int transcode(OutputFile *output_files,
             codec->rc_max_rate    = icodec->rc_max_rate;
             codec->rc_buffer_size = icodec->rc_buffer_size;
             codec->extradata= av_mallocz(extra_size);
-            if (!codec->extradata)
+            if (!codec->extradata) {
+                ret = AVERROR(ENOMEM);
                 goto fail;
+            }
             memcpy(codec->extradata, icodec->extradata, icodec->extradata_size);
             codec->extradata_size= icodec->extradata_size;
             if(!copy_tb && av_q2d(icodec->time_base)*icodec->ticks_per_frame > av_q2d(ist->st->time_base) && av_q2d(ist->st->time_base) < 1.0/500){
@@ -1945,8 +1991,10 @@ static int transcode(OutputFile *output_files,
             switch(codec->codec_type) {
             case AVMEDIA_TYPE_AUDIO:
                 ost->fifo= av_fifo_alloc(1024);
-                if(!ost->fifo)
+                if (!ost->fifo) {
+                    ret = AVERROR(ENOMEM);
                     goto fail;
+                }
                 ost->reformat_pair = MAKE_SFMT_PAIR(AV_SAMPLE_FMT_NONE,AV_SAMPLE_FMT_NONE);
                 if (!codec->sample_rate) {
                     codec->sample_rate = icodec->sample_rate;
@@ -2120,51 +2168,10 @@ static int transcode(OutputFile *output_files,
         }
     }
 
-    /* open each decoder */
-    for (i = 0; i < nb_input_streams; i++) {
-        ist = &input_streams[i];
-        if (ist->decoding_needed) {
-            AVCodec *codec = ist->dec;
-            if (!codec)
-                codec = avcodec_find_decoder(ist->st->codec->codec_id);
-            if (!codec) {
-                snprintf(error, sizeof(error), "Decoder (codec id %d) not found for input stream #%d.%d",
-                        ist->st->codec->codec_id, ist->file_index, ist->st->index);
-                ret = AVERROR(EINVAL);
-                goto dump_format;
-            }
-
-            /* update requested sample format for the decoder based on the
-               corresponding encoder sample format */
-            for (j = 0; j < nb_output_streams; j++) {
-                ost = &output_streams[j];
-                if (ost->source_index == i) {
-                    update_sample_fmt(ist->st->codec, codec, ost->st->codec);
-                    break;
-                }
-            }
-
-            if (avcodec_open2(ist->st->codec, codec, &ist->opts) < 0) {
-                snprintf(error, sizeof(error), "Error while opening decoder for input stream #%d.%d",
-                        ist->file_index, ist->st->index);
-                ret = AVERROR(EINVAL);
-                goto dump_format;
-            }
-            assert_codec_experimental(ist->st->codec, 0);
-            assert_avoptions(ost->opts);
-        }
-    }
-
-    /* init pts */
-    for (i = 0; i < nb_input_streams; i++) {
-        AVStream *st;
-        ist = &input_streams[i];
-        st= ist->st;
-        ist->pts = st->avg_frame_rate.num ? - st->codec->has_b_frames*AV_TIME_BASE / av_q2d(st->avg_frame_rate) : 0;
-        ist->next_pts = AV_NOPTS_VALUE;
-        init_pts_correction(&ist->pts_ctx);
-        ist->is_start = 1;
-    }
+    /* init input streams */
+    for (i = 0; i < nb_input_streams; i++)
+        if ((ret = init_input_stream(i, output_streams, nb_output_streams, error, sizeof(error)) < 0))
+            goto dump_format;
 
     /* open files and write file headers */
     for (i = 0; i < nb_output_files; i++) {
@@ -2236,14 +2243,17 @@ static int transcode(OutputFile *output_files,
            smallest output pts */
         file_index = -1;
         for (i = 0; i < nb_output_streams; i++) {
+            OutputFile *of;
             int64_t ipts;
             double  opts;
             ost = &output_streams[i];
+            of = &output_files[ost->file_index];
             os = output_files[ost->file_index].ctx;
             ist = &input_streams[ost->source_index];
-            if(ost->is_past_recording_time || no_packet[ist->file_index])
+            if (ost->is_past_recording_time || no_packet[ist->file_index] ||
+                (os->pb && avio_tell(os->pb) >= of->limit_filesize))
                 continue;
-                opts = ost->st->pts.val * av_q2d(ost->st->time_base);
+            opts = ost->st->pts.val * av_q2d(ost->st->time_base);
             ipts = ist->pts;
             if (!input_files[ist->file_index].eof_reached){
                 if(ipts < ipts_min) {
@@ -2271,10 +2281,6 @@ static int transcode(OutputFile *output_files,
             break;
         }
 
-        /* finish if limit size exhausted */
-        if (limit_filesize != 0 && limit_filesize <= avio_tell(output_files[0].ctx->pb))
-            break;
-
         /* read a frame from it and output it in the fifo */
         is = input_files[file_index].ctx;
         ret= av_read_frame(is, &pkt);
@@ -2361,6 +2367,7 @@ static int transcode(OutputFile *output_files,
             output_packet(ist, i, output_streams, nb_output_streams, NULL);
         }
     }
+    flush_encoders(output_streams, nb_output_streams);
 
     term_exit();
 
@@ -3167,8 +3174,6 @@ static OutputStream *new_video_stream(AVFormatContext *oc)
         video_enc->pix_fmt = frame_pix_fmt;
         st->sample_aspect_ratio = video_enc->sample_aspect_ratio;
 
-        if (intra_only)
-            video_enc->gop_size = 0;
         if (video_qscale || same_quant) {
             video_enc->flags |= CODEC_FLAG_QSCALE;
             video_enc->global_quality = FF_QP2LAMBDA * video_qscale;
@@ -3560,6 +3565,7 @@ static void opt_output_file(const char *filename)
     output_files[nb_output_files - 1].ost_index = nb_output_streams - oc->nb_streams;
     output_files[nb_output_files - 1].recording_time = recording_time;
     output_files[nb_output_files - 1].start_time     = start_time;
+    output_files[nb_output_files - 1].limit_filesize = limit_filesize;
     av_dict_copy(&output_files[nb_output_files - 1].opts, format_opts, 0);
 
     /* check filename in case of an image number is expected */
@@ -3687,6 +3693,7 @@ static void opt_output_file(const char *filename)
     chapters_input_file = INT_MAX;
     recording_time = INT64_MAX;
     start_time     = 0;
+    limit_filesize = UINT64_MAX;
 
     av_freep(&meta_data_maps);
     nb_meta_data_maps = 0;
@@ -3695,6 +3702,8 @@ static void opt_output_file(const char *filename)
     metadata_chapters_autocopy = 1;
     av_freep(&stream_maps);
     nb_stream_maps = 0;
+    av_freep(&streamid_map);
+    nb_streamid_map = 0;
 
     av_dict_free(&codec_names);
 
@@ -4088,13 +4097,12 @@ static const OptionDef options[] = {
     { "padleft", HAS_ARG | OPT_VIDEO, {(void*)opt_pad}, "Removed, use the pad filter instead", "size" },
     { "padright", HAS_ARG | OPT_VIDEO, {(void*)opt_pad}, "Removed, use the pad filter instead", "size" },
     { "padcolor", HAS_ARG | OPT_VIDEO, {(void*)opt_pad}, "Removed, use the pad filter instead", "color" },
-    { "intra", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&intra_only}, "use only intra frames"},
     { "vn", OPT_BOOL | OPT_VIDEO, {(void*)&video_disable}, "disable video" },
     { "vdt", OPT_INT | HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)&video_discard}, "discard threshold", "n" },
     { "qscale", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_qscale}, "use fixed video quantizer scale (VBR)", "q" },
     { "rc_override", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_video_rc_override_string}, "rate control override for specific intervals", "override" },
     { "vcodec", HAS_ARG | OPT_VIDEO, {(void*)opt_video_codec}, "force video codec ('copy' to copy stream)", "codec" },
-    { "me_threshold", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_me_threshold}, "motion estimaton threshold",  "threshold" },
+    { "me_threshold", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_me_threshold}, "motion estimation threshold",  "threshold" },
     { "same_quant", OPT_BOOL | OPT_VIDEO, {(void*)&same_quant},
       "use same quantizer as source (implies VBR)" },
     { "pass", HAS_ARG | OPT_VIDEO, {(void*)opt_pass}, "select the pass number (1 or 2)", "n" },