]> git.sesse.net Git - ffmpeg/blobdiff - avconv.c
avconv: Factorize video resampling.
[ffmpeg] / avconv.c
index 16d6514bd40deefe29347a42d8a127ace6beb410..6fa3e9426fcc1af9dce6520f63a0ccc9cdf15161 100644 (file)
--- a/avconv.c
+++ b/avconv.c
@@ -637,133 +637,6 @@ static void choose_pixel_fmt(AVStream *st, AVCodec *codec)
     }
 }
 
-static enum CodecID find_codec_or_die(const char *name, enum AVMediaType type, int encoder)
-{
-    const char *codec_string = encoder ? "encoder" : "decoder";
-    AVCodec *codec;
-
-    if(!name)
-        return CODEC_ID_NONE;
-    codec = encoder ?
-        avcodec_find_encoder_by_name(name) :
-        avcodec_find_decoder_by_name(name);
-    if(!codec) {
-        av_log(NULL, AV_LOG_ERROR, "Unknown %s '%s'\n", codec_string, name);
-        exit_program(1);
-    }
-    if(codec->type != type) {
-        av_log(NULL, AV_LOG_ERROR, "Invalid %s type '%s'\n", codec_string, name);
-        exit_program(1);
-    }
-    return codec->id;
-}
-
-static AVCodec *choose_codec(AVFormatContext *s, AVStream *st, enum AVMediaType type, AVDictionary *codec_names)
-{
-    AVDictionaryEntry *e = NULL;
-    char *codec_name = NULL;
-    int ret;
-
-    while (e = av_dict_get(codec_names, "", e, AV_DICT_IGNORE_SUFFIX)) {
-        char *p = strchr(e->key, ':');
-
-        if ((ret = check_stream_specifier(s, st, p ? p + 1 : "")) > 0)
-            codec_name = e->value;
-        else if (ret < 0)
-            exit_program(1);
-    }
-
-    if (!codec_name) {
-        if (s->oformat) {
-            st->codec->codec_id = av_guess_codec(s->oformat, NULL, s->filename, NULL, type);
-            return avcodec_find_encoder(st->codec->codec_id);
-        }
-    } else if (!strcmp(codec_name, "copy"))
-        st->stream_copy = 1;
-    else {
-        st->codec->codec_id = find_codec_or_die(codec_name, type, s->iformat == NULL);
-        return s->oformat ? avcodec_find_encoder_by_name(codec_name) :
-                            avcodec_find_decoder_by_name(codec_name);
-    }
-
-    return NULL;
-}
-
-static OutputStream *new_output_stream(AVFormatContext *oc, int file_idx, enum AVMediaType type)
-{
-    OutputStream *ost;
-    AVStream *st = av_new_stream(oc, oc->nb_streams < nb_streamid_map ? streamid_map[oc->nb_streams] : 0);
-    int idx      = oc->nb_streams - 1;
-
-    if (!st) {
-        av_log(NULL, AV_LOG_ERROR, "Could not alloc stream.\n");
-        exit_program(1);
-    }
-
-    output_streams_for_file[file_idx] =
-        grow_array(output_streams_for_file[file_idx],
-                   sizeof(*output_streams_for_file[file_idx]),
-                   &nb_output_streams_for_file[file_idx],
-                   oc->nb_streams);
-    ost = output_streams_for_file[file_idx][idx] =
-        av_mallocz(sizeof(OutputStream));
-    if (!ost) {
-        fprintf(stderr, "Could not alloc output stream\n");
-        exit_program(1);
-    }
-    ost->file_index = file_idx;
-    ost->index = idx;
-    ost->st    = st;
-    st->codec->codec_type = type;
-    ost->enc = choose_codec(oc, st, type, codec_names);
-    if (ost->enc) {
-        ost->opts  = filter_codec_opts(codec_opts, ost->enc->id, oc, st);
-    }
-
-    avcodec_get_context_defaults3(st->codec, ost->enc);
-    st->codec->codec_type = type; // XXX hack, avcodec_get_context_defaults2() sets type to unknown for stream copy
-
-    ost->sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
-    return ost;
-}
-
-static int read_avserver_streams(AVFormatContext *s, const char *filename)
-{
-    int i, err;
-    AVFormatContext *ic = NULL;
-    int nopts = 0;
-
-    err = avformat_open_input(&ic, filename, NULL, NULL);
-    if (err < 0)
-        return err;
-    /* copy stream format */
-    for(i=0;i<ic->nb_streams;i++) {
-        AVStream *st;
-        OutputStream *ost;
-        AVCodec *codec;
-
-        codec = avcodec_find_encoder(ic->streams[i]->codec->codec_id);
-        ost   = new_output_stream(s, nb_output_files, codec->type);
-        st    = ost->st;
-
-        // FIXME: a more elegant solution is needed
-        memcpy(st, ic->streams[i], sizeof(AVStream));
-        st->info = NULL;
-        avcodec_copy_context(st->codec, ic->streams[i]->codec);
-
-        if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && !st->stream_copy)
-            choose_sample_fmt(st, codec);
-        else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && !st->stream_copy)
-            choose_pixel_fmt(st, codec);
-
-        if(st->codec->flags & CODEC_FLAG_BITEXACT)
-            nopts = 1;
-    }
-
-    av_close_input_file(ic);
-    return 0;
-}
-
 static double
 get_sync_ipts(const OutputStream *ost)
 {
@@ -1157,58 +1030,14 @@ static void do_subtitle_out(AVFormatContext *s,
 static int bit_buffer_size= 1024*256;
 static uint8_t *bit_buffer= NULL;
 
-static void do_video_out(AVFormatContext *s,
-                         OutputStream *ost,
-                         InputStream *ist,
-                         AVFrame *in_picture,
-                         int *frame_size, float quality)
+static void do_video_resample(OutputStream *ost,
+                              InputStream *ist,
+                              AVFrame *in_picture,
+                              AVFrame **out_picture)
 {
-    int nb_frames, i, ret, resample_changed;
-    AVFrame *final_picture, *formatted_picture;
-    AVCodecContext *enc, *dec;
-    double sync_ipts;
-
-    enc = ost->st->codec;
-    dec = ist->st->codec;
-
-    sync_ipts = get_sync_ipts(ost) / av_q2d(enc->time_base);
-
-    /* by default, we output a single frame */
-    nb_frames = 1;
-
-    *frame_size = 0;
-
-    if(video_sync_method){
-        double vdelta = sync_ipts - ost->sync_opts;
-        //FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c
-        if (vdelta < -1.1)
-            nb_frames = 0;
-        else if (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);
-        }else if (vdelta > 1.1)
-            nb_frames = lrintf(vdelta);
-//fprintf(stderr, "vdelta:%f, ost->sync_opts:%"PRId64", ost->sync_ipts:%f nb_frames:%d\n", vdelta, ost->sync_opts, get_sync_ipts(ost), nb_frames);
-        if (nb_frames == 0){
-            ++nb_frames_drop;
-            if (verbose>2)
-                fprintf(stderr, "*** drop!\n");
-        }else if (nb_frames > 1) {
-            nb_frames_dup += nb_frames - 1;
-            if (verbose>2)
-                fprintf(stderr, "*** %d dup!\n", nb_frames-1);
-        }
-    }else
-        ost->sync_opts= lrintf(sync_ipts);
-
-    nb_frames= FFMIN(nb_frames, max_frames[AVMEDIA_TYPE_VIDEO] - ost->frame_number);
-    if (nb_frames <= 0)
-        return;
-
-    formatted_picture = in_picture;
-    final_picture = formatted_picture;
+    int resample_changed = 0;
+    AVCodecContext *dec = ist->st->codec;
+    *out_picture = in_picture;
 
     resample_changed = ost->resample_width   != dec->width  ||
                        ost->resample_height  != dec->height ||
@@ -1226,7 +1055,7 @@ static void do_video_out(AVFormatContext *s,
 
 #if !CONFIG_AVFILTER
     if (ost->video_resample) {
-        final_picture = &ost->pict_tmp;
+        *out_picture = &ost->pict_tmp;
         if (resample_changed) {
             /* initialize a new scaler context */
             sws_freeContext(ost->img_resample_ctx);
@@ -1243,8 +1072,8 @@ static void do_video_out(AVFormatContext *s,
                 exit_program(1);
             }
         }
-        sws_scale(ost->img_resample_ctx, formatted_picture->data, formatted_picture->linesize,
-              0, ost->resample_height, final_picture->data, final_picture->linesize);
+        sws_scale(ost->img_resample_ctx, in_picture->data, in_picture->linesize,
+              0, ost->resample_height, (*out_picture)->data, (*out_picture)->linesize);
     }
 #else
     if (resample_changed) {
@@ -1260,6 +1089,60 @@ static void do_video_out(AVFormatContext *s,
         ost->resample_height  = dec->height;
         ost->resample_pix_fmt = dec->pix_fmt;
     }
+}
+
+
+static void do_video_out(AVFormatContext *s,
+                         OutputStream *ost,
+                         InputStream *ist,
+                         AVFrame *in_picture,
+                         int *frame_size, float quality)
+{
+    int nb_frames, i, ret;
+    AVFrame *final_picture;
+    AVCodecContext *enc, *dec;
+    double sync_ipts;
+
+    enc = ost->st->codec;
+    dec = ist->st->codec;
+
+    sync_ipts = get_sync_ipts(ost) / av_q2d(enc->time_base);
+
+    /* by default, we output a single frame */
+    nb_frames = 1;
+
+    *frame_size = 0;
+
+    if(video_sync_method){
+        double vdelta = sync_ipts - ost->sync_opts;
+        //FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c
+        if (vdelta < -1.1)
+            nb_frames = 0;
+        else if (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);
+        }else if (vdelta > 1.1)
+            nb_frames = lrintf(vdelta);
+//fprintf(stderr, "vdelta:%f, ost->sync_opts:%"PRId64", ost->sync_ipts:%f nb_frames:%d\n", vdelta, ost->sync_opts, get_sync_ipts(ost), nb_frames);
+        if (nb_frames == 0){
+            ++nb_frames_drop;
+            if (verbose>2)
+                fprintf(stderr, "*** drop!\n");
+        }else if (nb_frames > 1) {
+            nb_frames_dup += nb_frames - 1;
+            if (verbose>2)
+                fprintf(stderr, "*** %d dup!\n", nb_frames-1);
+        }
+    }else
+        ost->sync_opts= lrintf(sync_ipts);
+
+    nb_frames= FFMIN(nb_frames, max_frames[AVMEDIA_TYPE_VIDEO] - ost->frame_number);
+    if (nb_frames <= 0)
+        return;
+
+    do_video_resample(ost, ist, in_picture, &final_picture);
 
     /* duplicates frame if needed */
     for(i=0;i<nb_frames;i++) {
@@ -1925,69 +1808,6 @@ static void print_sdp(AVFormatContext **avc, int n)
     fflush(stdout);
 }
 
-static int copy_chapters(int infile, int outfile)
-{
-    AVFormatContext *is = input_files[infile].ctx;
-    AVFormatContext *os = output_files[outfile];
-    int i;
-
-    for (i = 0; i < is->nb_chapters; i++) {
-        AVChapter *in_ch = is->chapters[i], *out_ch;
-        int64_t ts_off   = av_rescale_q(start_time - input_files[infile].ts_offset,
-                                      AV_TIME_BASE_Q, in_ch->time_base);
-        int64_t rt       = (recording_time == INT64_MAX) ? INT64_MAX :
-                           av_rescale_q(recording_time, AV_TIME_BASE_Q, in_ch->time_base);
-
-
-        if (in_ch->end < ts_off)
-            continue;
-        if (rt != INT64_MAX && in_ch->start > rt + ts_off)
-            break;
-
-        out_ch = av_mallocz(sizeof(AVChapter));
-        if (!out_ch)
-            return AVERROR(ENOMEM);
-
-        out_ch->id        = in_ch->id;
-        out_ch->time_base = in_ch->time_base;
-        out_ch->start     = FFMAX(0,  in_ch->start - ts_off);
-        out_ch->end       = FFMIN(rt, in_ch->end   - ts_off);
-
-        if (metadata_chapters_autocopy)
-            av_dict_copy(&out_ch->metadata, in_ch->metadata, 0);
-
-        os->nb_chapters++;
-        os->chapters = av_realloc(os->chapters, sizeof(AVChapter)*os->nb_chapters);
-        if (!os->chapters)
-            return AVERROR(ENOMEM);
-        os->chapters[os->nb_chapters - 1] = out_ch;
-    }
-    return 0;
-}
-
-static void parse_forced_key_frames(char *kf, OutputStream *ost,
-                                    AVCodecContext *avctx)
-{
-    char *p;
-    int n = 1, i;
-    int64_t t;
-
-    for (p = kf; *p; p++)
-        if (*p == ',')
-            n++;
-    ost->forced_kf_count = n;
-    ost->forced_kf_pts = av_malloc(sizeof(*ost->forced_kf_pts) * n);
-    if (!ost->forced_kf_pts) {
-        av_log(NULL, AV_LOG_FATAL, "Could not allocate forced key frames array.\n");
-        exit_program(1);
-    }
-    for (i = 0; i < n; i++) {
-        p = i ? strchr(p, ',') + 1 : kf;
-        t = parse_time_or_die("force_key_frames", p, 1);
-        ost->forced_kf_pts[i] = av_rescale_q(t, AV_TIME_BASE_Q, avctx->time_base);
-    }
-}
-
 /*
  * The following code is the main loop of the file converter
  */
@@ -2379,6 +2199,8 @@ static int transcode(AVFormatContext **output_files,
                 fprintf(stderr, " [sync #%d.%d]",
                         ost->sync_ist->file_index,
                         ost->sync_ist->st->index);
+            if (ost->st->stream_copy)
+                fprintf(stderr, " (copy)");
             fprintf(stderr, "\n");
         }
     }
@@ -2401,25 +2223,26 @@ static int transcode(AVFormatContext **output_files,
     for(; received_sigterm == 0;) {
         int file_index, ist_index;
         AVPacket pkt;
-        double ipts_min;
+        int64_t ipts_min;
         double opts_min;
 
     redo:
-        ipts_min= 1e100;
+        ipts_min = INT64_MAX;
         opts_min= 1e100;
 
         /* select the stream that we must read now by looking at the
            smallest output pts */
         file_index = -1;
         for(i=0;i<nb_ostreams;i++) {
-            double ipts, opts;
+            int64_t ipts;
+            double  opts;
             ost = ost_table[i];
             os = output_files[ost->file_index];
             ist = &input_streams[ost->source_index];
             if(ist->is_past_recording_time || no_packet[ist->file_index])
                 continue;
                 opts = ost->st->pts.val * av_q2d(ost->st->time_base);
-            ipts = (double)ist->pts;
+            ipts = ist->pts;
             if (!input_files[ist->file_index].eof_reached){
                 if(ipts < ipts_min) {
                     ipts_min = ipts;
@@ -2982,6 +2805,57 @@ static int opt_input_ts_offset(const char *opt, const char *arg)
     return 0;
 }
 
+static enum CodecID find_codec_or_die(const char *name, enum AVMediaType type, int encoder)
+{
+    const char *codec_string = encoder ? "encoder" : "decoder";
+    AVCodec *codec;
+
+    if(!name)
+        return CODEC_ID_NONE;
+    codec = encoder ?
+        avcodec_find_encoder_by_name(name) :
+        avcodec_find_decoder_by_name(name);
+    if(!codec) {
+        av_log(NULL, AV_LOG_ERROR, "Unknown %s '%s'\n", codec_string, name);
+        exit_program(1);
+    }
+    if(codec->type != type) {
+        av_log(NULL, AV_LOG_ERROR, "Invalid %s type '%s'\n", codec_string, name);
+        exit_program(1);
+    }
+    return codec->id;
+}
+
+static AVCodec *choose_codec(AVFormatContext *s, AVStream *st, enum AVMediaType type, AVDictionary *codec_names)
+{
+    AVDictionaryEntry *e = NULL;
+    char *codec_name = NULL;
+    int ret;
+
+    while (e = av_dict_get(codec_names, "", e, AV_DICT_IGNORE_SUFFIX)) {
+        char *p = strchr(e->key, ':');
+
+        if ((ret = check_stream_specifier(s, st, p ? p + 1 : "")) > 0)
+            codec_name = e->value;
+        else if (ret < 0)
+            exit_program(1);
+    }
+
+    if (!codec_name) {
+        if (s->oformat) {
+            st->codec->codec_id = av_guess_codec(s->oformat, NULL, s->filename, NULL, type);
+            return avcodec_find_encoder(st->codec->codec_id);
+        }
+    } else if (!strcmp(codec_name, "copy"))
+        st->stream_copy = 1;
+    else {
+        st->codec->codec_id = find_codec_or_die(codec_name, type, s->iformat == NULL);
+        return s->oformat ? avcodec_find_encoder_by_name(codec_name) :
+                            avcodec_find_decoder_by_name(codec_name);
+    }
+
+    return NULL;
+}
 
 static int opt_input_file(const char *opt, const char *filename)
 {
@@ -3191,13 +3065,74 @@ static int opt_input_file(const char *opt, const char *filename)
     return 0;
 }
 
-static OutputStream *new_video_stream(AVFormatContext *oc, int file_idx)
+static void parse_forced_key_frames(char *kf, OutputStream *ost,
+                                    AVCodecContext *avctx)
+{
+    char *p;
+    int n = 1, i;
+    int64_t t;
+
+    for (p = kf; *p; p++)
+        if (*p == ',')
+            n++;
+    ost->forced_kf_count = n;
+    ost->forced_kf_pts = av_malloc(sizeof(*ost->forced_kf_pts) * n);
+    if (!ost->forced_kf_pts) {
+        av_log(NULL, AV_LOG_FATAL, "Could not allocate forced key frames array.\n");
+        exit_program(1);
+    }
+    for (i = 0; i < n; i++) {
+        p = i ? strchr(p, ',') + 1 : kf;
+        t = parse_time_or_die("force_key_frames", p, 1);
+        ost->forced_kf_pts[i] = av_rescale_q(t, AV_TIME_BASE_Q, avctx->time_base);
+    }
+}
+
+static OutputStream *new_output_stream(AVFormatContext *oc, enum AVMediaType type)
+{
+    OutputStream *ost;
+    AVStream *st = av_new_stream(oc, oc->nb_streams < nb_streamid_map ? streamid_map[oc->nb_streams] : 0);
+    int idx      = oc->nb_streams - 1;
+
+    if (!st) {
+        av_log(NULL, AV_LOG_ERROR, "Could not alloc stream.\n");
+        exit_program(1);
+    }
+
+    output_streams_for_file[nb_output_files] =
+        grow_array(output_streams_for_file[nb_output_files],
+                   sizeof(*output_streams_for_file[nb_output_files]),
+                   &nb_output_streams_for_file[nb_output_files],
+                   oc->nb_streams);
+    ost = output_streams_for_file[nb_output_files][idx] =
+        av_mallocz(sizeof(OutputStream));
+    if (!ost) {
+        fprintf(stderr, "Could not alloc output stream\n");
+        exit_program(1);
+    }
+    ost->file_index = nb_output_files;
+    ost->index = idx;
+    ost->st    = st;
+    st->codec->codec_type = type;
+    ost->enc = choose_codec(oc, st, type, codec_names);
+    if (ost->enc) {
+        ost->opts  = filter_codec_opts(codec_opts, ost->enc->id, oc, st);
+    }
+
+    avcodec_get_context_defaults3(st->codec, ost->enc);
+    st->codec->codec_type = type; // XXX hack, avcodec_get_context_defaults2() sets type to unknown for stream copy
+
+    ost->sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
+    return ost;
+}
+
+static OutputStream *new_video_stream(AVFormatContext *oc)
 {
     AVStream *st;
     OutputStream *ost;
     AVCodecContext *video_enc;
 
-    ost = new_output_stream(oc, file_idx, AVMEDIA_TYPE_VIDEO);
+    ost = new_output_stream(oc, AVMEDIA_TYPE_VIDEO);
     st  = ost->st;
     if (!st->stream_copy) {
         ost->frame_aspect_ratio = frame_aspect_ratio;
@@ -3306,13 +3241,13 @@ static OutputStream *new_video_stream(AVFormatContext *oc, int file_idx)
     return ost;
 }
 
-static OutputStream *new_audio_stream(AVFormatContext *oc, int file_idx)
+static OutputStream *new_audio_stream(AVFormatContext *oc)
 {
     AVStream *st;
     OutputStream *ost;
     AVCodecContext *audio_enc;
 
-    ost = new_output_stream(oc, file_idx, AVMEDIA_TYPE_AUDIO);
+    ost = new_output_stream(oc, AVMEDIA_TYPE_AUDIO);
     st  = ost->st;
 
     ost->bitstream_filters = audio_bitstream_filters;
@@ -3352,13 +3287,13 @@ static OutputStream *new_audio_stream(AVFormatContext *oc, int file_idx)
     return ost;
 }
 
-static OutputStream *new_data_stream(AVFormatContext *oc, int file_idx)
+static OutputStream *new_data_stream(AVFormatContext *oc)
 {
     AVStream *st;
     OutputStream *ost;
     AVCodecContext *data_enc;
 
-    ost = new_output_stream(oc, file_idx, AVMEDIA_TYPE_DATA);
+    ost = new_output_stream(oc, AVMEDIA_TYPE_DATA);
     st  = ost->st;
     data_enc = st->codec;
     if (!st->stream_copy) {
@@ -3377,13 +3312,13 @@ static OutputStream *new_data_stream(AVFormatContext *oc, int file_idx)
     return ost;
 }
 
-static OutputStream *new_subtitle_stream(AVFormatContext *oc, int file_idx)
+static OutputStream *new_subtitle_stream(AVFormatContext *oc)
 {
     AVStream *st;
     OutputStream *ost;
     AVCodecContext *subtitle_enc;
 
-    ost = new_output_stream(oc, file_idx, AVMEDIA_TYPE_SUBTITLE);
+    ost = new_output_stream(oc, AVMEDIA_TYPE_SUBTITLE);
     st  = ost->st;
     subtitle_enc = st->codec;
 
@@ -3430,6 +3365,79 @@ static int opt_streamid(const char *opt, const char *arg)
     return 0;
 }
 
+static int copy_chapters(int infile, int outfile)
+{
+    AVFormatContext *is = input_files[infile].ctx;
+    AVFormatContext *os = output_files[outfile];
+    int i;
+
+    for (i = 0; i < is->nb_chapters; i++) {
+        AVChapter *in_ch = is->chapters[i], *out_ch;
+        int64_t ts_off   = av_rescale_q(start_time - input_files[infile].ts_offset,
+                                      AV_TIME_BASE_Q, in_ch->time_base);
+        int64_t rt       = (recording_time == INT64_MAX) ? INT64_MAX :
+                           av_rescale_q(recording_time, AV_TIME_BASE_Q, in_ch->time_base);
+
+
+        if (in_ch->end < ts_off)
+            continue;
+        if (rt != INT64_MAX && in_ch->start > rt + ts_off)
+            break;
+
+        out_ch = av_mallocz(sizeof(AVChapter));
+        if (!out_ch)
+            return AVERROR(ENOMEM);
+
+        out_ch->id        = in_ch->id;
+        out_ch->time_base = in_ch->time_base;
+        out_ch->start     = FFMAX(0,  in_ch->start - ts_off);
+        out_ch->end       = FFMIN(rt, in_ch->end   - ts_off);
+
+        if (metadata_chapters_autocopy)
+            av_dict_copy(&out_ch->metadata, in_ch->metadata, 0);
+
+        os->nb_chapters++;
+        os->chapters = av_realloc(os->chapters, sizeof(AVChapter)*os->nb_chapters);
+        if (!os->chapters)
+            return AVERROR(ENOMEM);
+        os->chapters[os->nb_chapters - 1] = out_ch;
+    }
+    return 0;
+}
+
+static int read_avserver_streams(AVFormatContext *s, const char *filename)
+{
+    int i, err;
+    AVFormatContext *ic = NULL;
+
+    err = avformat_open_input(&ic, filename, NULL, NULL);
+    if (err < 0)
+        return err;
+    /* copy stream format */
+    for(i=0;i<ic->nb_streams;i++) {
+        AVStream *st;
+        OutputStream *ost;
+        AVCodec *codec;
+
+        codec = avcodec_find_encoder(ic->streams[i]->codec->codec_id);
+        ost   = new_output_stream(s, codec->type);
+        st    = ost->st;
+
+        // FIXME: a more elegant solution is needed
+        memcpy(st, ic->streams[i], sizeof(AVStream));
+        st->info = NULL;
+        avcodec_copy_context(st->codec, ic->streams[i]->codec);
+
+        if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && !st->stream_copy)
+            choose_sample_fmt(st, codec);
+        else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && !st->stream_copy)
+            choose_pixel_fmt(st, codec);
+    }
+
+    av_close_input_file(ic);
+    return 0;
+}
+
 static void opt_output_file(const char *filename)
 {
     AVFormatContext *oc;
@@ -3479,7 +3487,7 @@ static void opt_output_file(const char *filename)
         /* pick the "best" stream of each type */
 #define NEW_STREAM(type, index)\
         if (index >= 0) {\
-            ost = new_ ## type ## _stream(oc, nb_output_files);\
+            ost = new_ ## type ## _stream(oc);\
             ost->source_index = index;\
             ost->sync_ist     = &input_streams[index];\
             input_streams[index].discard = 0;\
@@ -3531,10 +3539,10 @@ static void opt_output_file(const char *filename)
 
             ist = &input_streams[input_files[map->file_index].ist_index + map->stream_index];
             switch (ist->st->codec->codec_type) {
-            case AVMEDIA_TYPE_VIDEO:    ost = new_video_stream(oc, nb_output_files);    break;
-            case AVMEDIA_TYPE_AUDIO:    ost = new_audio_stream(oc, nb_output_files);    break;
-            case AVMEDIA_TYPE_SUBTITLE: ost = new_subtitle_stream(oc, nb_output_files); break;
-            case AVMEDIA_TYPE_DATA:     ost = new_data_stream(oc, nb_output_files);     break;
+            case AVMEDIA_TYPE_VIDEO:    ost = new_video_stream(oc);    break;
+            case AVMEDIA_TYPE_AUDIO:    ost = new_audio_stream(oc);    break;
+            case AVMEDIA_TYPE_SUBTITLE: ost = new_subtitle_stream(oc); break;
+            case AVMEDIA_TYPE_DATA:     ost = new_data_stream(oc);     break;
             default:
                 av_log(NULL, AV_LOG_ERROR, "Cannot map stream #%d.%d - unsupported type.\n",
                        map->file_index, map->stream_index);
@@ -3661,7 +3669,7 @@ static void opt_output_file(const char *filename)
     }
 
     /* copy global metadata by default */
-    if (metadata_global_autocopy)
+    if (metadata_global_autocopy && nb_input_files)
         av_dict_copy(&oc->metadata, input_files[0].ctx->metadata,
                      AV_DICT_DONT_OVERWRITE);
     if (metadata_streams_autocopy)