]> git.sesse.net Git - ffmpeg/blobdiff - avconv.c
Add some more deprecation guards
[ffmpeg] / avconv.c
index 35ea1f501914899cdeffeeea7f896514e8875e59..74459ab6ba2df28415e02a326f1807fb89d50b5c 100644 (file)
--- a/avconv.c
+++ b/avconv.c
@@ -1,6 +1,6 @@
 /*
  * avconv main
- * Copyright (c) 2000-2011 The libav developers.
+ * Copyright (c) 2000-2011 The Libav developers
  *
  * This file is part of Libav.
  *
@@ -175,13 +175,12 @@ static void avconv_cleanup(int ret)
     }
     for (i = 0; i < nb_output_streams; i++) {
         OutputStream *ost = output_streams[i];
-        AVBitStreamFilterContext *bsfc = ost->bitstream_filters;
-        while (bsfc) {
-            AVBitStreamFilterContext *next = bsfc->next;
-            av_bitstream_filter_close(bsfc);
-            bsfc = next;
-        }
-        ost->bitstream_filters = NULL;
+
+        for (j = 0; j < ost->nb_bitstream_filters; j++)
+            av_bsf_free(&ost->bsf_ctx[j]);
+        av_freep(&ost->bsf_ctx);
+        av_freep(&ost->bitstream_filters);
+
         av_frame_free(&ost->filtered_frame);
 
         av_parser_close(ost->parser);
@@ -255,10 +254,9 @@ static void abort_codec_experimental(AVCodec *c, int encoder)
     exit_program(1);
 }
 
-static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
+static void write_packet(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
 {
     AVStream *st = ost->st;
-    AVBitStreamFilterContext *bsfc = ost->bitstream_filters;
     int ret;
 
     /*
@@ -286,32 +284,6 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
         }
     }
 
-    while (bsfc) {
-        AVCodecContext *avctx = ost->encoding_needed ? ost->enc_ctx : ost->st->codec;
-        AVPacket new_pkt = *pkt;
-        int a = av_bitstream_filter_filter(bsfc, avctx, NULL,
-                                           &new_pkt.data, &new_pkt.size,
-                                           pkt->data, pkt->size,
-                                           pkt->flags & AV_PKT_FLAG_KEY);
-        if (a > 0) {
-            av_packet_unref(pkt);
-            new_pkt.buf = av_buffer_create(new_pkt.data, new_pkt.size,
-                                           av_buffer_default_free, NULL, 0);
-            if (!new_pkt.buf)
-                exit_program(1);
-        } else if (a < 0) {
-            av_log(NULL, AV_LOG_ERROR, "%s failed for stream %d, codec %s",
-                   bsfc->filter->name, pkt->stream_index,
-                   avctx->codec ? avctx->codec->name : "copy");
-            print_error("", a);
-            if (exit_on_error)
-                exit_program(1);
-        }
-        *pkt = new_pkt;
-
-        bsfc = bsfc->next;
-    }
-
     if (!(s->oformat->flags & AVFMT_NOTIMESTAMPS) &&
         ost->last_mux_dts != AV_NOPTS_VALUE &&
         pkt->dts < ost->last_mux_dts + !(s->oformat->flags & AVFMT_TS_NONSTRICT)) {
@@ -342,6 +314,49 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
     }
 }
 
+static void output_packet(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
+{
+    int ret = 0;
+
+    /* apply the output bitstream filters, if any */
+    if (ost->nb_bitstream_filters) {
+        int idx;
+
+        ret = av_bsf_send_packet(ost->bsf_ctx[0], pkt);
+        if (ret < 0)
+            goto finish;
+
+        idx = 1;
+        while (idx) {
+            /* get a packet from the previous filter up the chain */
+            ret = av_bsf_receive_packet(ost->bsf_ctx[idx - 1], pkt);
+            if (ret == AVERROR(EAGAIN)) {
+                ret = 0;
+                idx--;
+                continue;
+            } else if (ret < 0)
+                goto finish;
+
+            /* send it to the next filter down the chain or to the muxer */
+            if (idx < ost->nb_bitstream_filters) {
+                ret = av_bsf_send_packet(ost->bsf_ctx[idx], pkt);
+                if (ret < 0)
+                    goto finish;
+                idx++;
+            } else
+                write_packet(s, pkt, ost);
+        }
+    } else
+        write_packet(s, pkt, ost);
+
+finish:
+    if (ret < 0 && ret != AVERROR_EOF) {
+        av_log(NULL, AV_LOG_FATAL, "Error applying bitstream filters to an output "
+               "packet for stream #%d:%d.\n", ost->file_index, ost->index);
+        exit_program(1);
+    }
+}
+
 static int check_recording_time(OutputStream *ost)
 {
     OutputFile *of = output_files[ost->file_index];
@@ -360,7 +375,7 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost,
 {
     AVCodecContext *enc = ost->enc_ctx;
     AVPacket pkt;
-    int got_packet = 0;
+    int ret;
 
     av_init_packet(&pkt);
     pkt.data = NULL;
@@ -373,15 +388,25 @@ static void do_audio_out(AVFormatContext *s, OutputStream *ost,
     ost->samples_encoded += frame->nb_samples;
     ost->frames_encoded++;
 
-    if (avcodec_encode_audio2(enc, &pkt, frame, &got_packet) < 0) {
-        av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
-        exit_program(1);
-    }
+    ret = avcodec_send_frame(enc, frame);
+    if (ret < 0)
+        goto error;
+
+    while (1) {
+        ret = avcodec_receive_packet(enc, &pkt);
+        if (ret == AVERROR(EAGAIN))
+            break;
+        if (ret < 0)
+            goto error;
 
-    if (got_packet) {
         av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
-        write_frame(s, &pkt, ost);
+        output_packet(s, &pkt, ost);
     }
+
+    return;
+error:
+    av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
+    exit_program(1);
 }
 
 static void do_subtitle_out(AVFormatContext *s,
@@ -449,7 +474,7 @@ static void do_subtitle_out(AVFormatContext *s,
             else
                 pkt.pts += 90 * sub->end_display_time;
         }
-        write_frame(s, &pkt, ost);
+        output_packet(s, &pkt, ost);
     }
 }
 
@@ -458,7 +483,7 @@ static void do_video_out(AVFormatContext *s,
                          AVFrame *in_picture,
                          int *frame_size)
 {
-    int ret, format_video_sync, got_packet;
+    int ret, format_video_sync;
     AVPacket pkt;
     AVCodecContext *enc = ost->enc_ctx;
 
@@ -508,36 +533,48 @@ static void do_video_out(AVFormatContext *s,
 
     ost->frames_encoded++;
 
-    ret = avcodec_encode_video2(enc, &pkt, in_picture, &got_packet);
-    if (ret < 0) {
-        av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n");
-        exit_program(1);
-    }
+    ret = avcodec_send_frame(enc, in_picture);
+    if (ret < 0)
+        goto error;
+
+    /*
+     * For video, there may be reordering, so we can't throw away frames on
+     * encoder flush, we need to limit them here, before they go into encoder.
+     */
+    ost->frame_number++;
+
+    while (1) {
+        ret = avcodec_receive_packet(enc, &pkt);
+        if (ret == AVERROR(EAGAIN))
+            break;
+        if (ret < 0)
+            goto error;
 
-    if (got_packet) {
         av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
-        write_frame(s, &pkt, ost);
+        output_packet(s, &pkt, ost);
         *frame_size = pkt.size;
 
         /* if two pass, output log */
         if (ost->logfile && enc->stats_out) {
             fprintf(ost->logfile, "%s", enc->stats_out);
         }
+
+        ost->sync_opts++;
     }
 
-    ost->sync_opts++;
-    /*
-     * For video, number of frames in == number of packets out.
-     * But there may be reordering, so we can't throw away frames on encoder
-     * flush, we need to limit them here, before they go into encoder.
-     */
-    ost->frame_number++;
+    return;
+error:
+    av_assert0(ret != AVERROR(EAGAIN) && ret != AVERROR_EOF);
+    av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n");
+    exit_program(1);
 }
 
+#if FF_API_CODED_FRAME
 static double psnr(double d)
 {
     return -10.0 * log(d) / log(10.0);
 }
+#endif
 
 static void do_video_stats(OutputStream *ost, int frame_size)
 {
@@ -946,44 +983,45 @@ static void flush_encoders(void)
         if (enc->codec_type == AVMEDIA_TYPE_AUDIO && enc->frame_size <= 1)
             continue;
 
+        if (enc->codec_type != AVMEDIA_TYPE_VIDEO && enc->codec_type != AVMEDIA_TYPE_AUDIO)
+            continue;
+
+        avcodec_send_frame(enc, NULL);
+
         for (;;) {
-            int (*encode)(AVCodecContext*, AVPacket*, const AVFrame*, int*) = NULL;
-            const char *desc;
+            const char *desc = NULL;
 
             switch (enc->codec_type) {
             case AVMEDIA_TYPE_AUDIO:
-                encode = avcodec_encode_audio2;
                 desc   = "Audio";
                 break;
             case AVMEDIA_TYPE_VIDEO:
-                encode = avcodec_encode_video2;
                 desc   = "Video";
                 break;
             default:
-                stop_encoding = 1;
+                av_assert0(0);
             }
 
-            if (encode) {
+            if (1) {
                 AVPacket pkt;
-                int got_packet;
                 av_init_packet(&pkt);
                 pkt.data = NULL;
                 pkt.size = 0;
 
-                ret = encode(enc, &pkt, NULL, &got_packet);
-                if (ret < 0) {
+                ret = avcodec_receive_packet(enc, &pkt);
+                if (ret < 0 && ret != AVERROR_EOF) {
                     av_log(NULL, AV_LOG_FATAL, "%s encoding failed\n", desc);
                     exit_program(1);
                 }
                 if (ost->logfile && enc->stats_out) {
                     fprintf(ost->logfile, "%s", enc->stats_out);
                 }
-                if (!got_packet) {
+                if (ret == AVERROR_EOF) {
                     stop_encoding = 1;
                     break;
                 }
                 av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
-                write_frame(os, &pkt, ost);
+                output_packet(os, &pkt, ost);
             }
 
             if (stop_encoding)
@@ -1076,7 +1114,34 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p
         opkt.size = pkt->size;
     }
 
-    write_frame(of->ctx, &opkt, ost);
+    output_packet(of->ctx, &opkt, ost);
+}
+
+// This does not quite work like avcodec_decode_audio4/avcodec_decode_video2.
+// There is the following difference: if you got a frame, you must call
+// it again with pkt=NULL. pkt==NULL is treated differently from pkt.size==0
+// (pkt==NULL means get more output, pkt.size==0 is a flush/drain packet)
+static int decode(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *pkt)
+{
+    int ret;
+
+    *got_frame = 0;
+
+    if (pkt) {
+        ret = avcodec_send_packet(avctx, pkt);
+        // In particular, we don't expect AVERROR(EAGAIN), because we read all
+        // decoded frames with avcodec_receive_frame() until done.
+        if (ret < 0)
+            return ret == AVERROR_EOF ? 0 : ret;
+    }
+
+    ret = avcodec_receive_frame(avctx, frame);
+    if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
+        return ret;
+    if (ret >= 0)
+        *got_frame = 1;
+
+    return 0;
 }
 
 int guess_input_channel_layout(InputStream *ist)
@@ -1091,7 +1156,7 @@ int guess_input_channel_layout(InputStream *ist)
             return 0;
         av_get_channel_layout_string(layout_name, sizeof(layout_name),
                                      dec->channels, dec->channel_layout);
-        av_log(NULL, AV_LOG_WARNING, "Guessed Channel Layout for  Input Stream "
+        av_log(NULL, AV_LOG_WARNING, "Guessed Channel Layout for Input Stream "
                "#%d.%d : %s\n", ist->file_index, ist->st->index, layout_name);
     }
     return 1;
@@ -1109,7 +1174,7 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
         return AVERROR(ENOMEM);
     decoded_frame = ist->decoded_frame;
 
-    ret = avcodec_decode_audio4(avctx, decoded_frame, got_output, pkt);
+    ret = decode(avctx, decoded_frame, got_output, pkt);
     if (!*got_output || ret < 0)
         return ret;
 
@@ -1120,9 +1185,9 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
        the decoder could be delaying output by a packet or more. */
     if (decoded_frame->pts != AV_NOPTS_VALUE)
         ist->next_dts = decoded_frame->pts;
-    else if (pkt->pts != AV_NOPTS_VALUE)
+    else if (pkt && pkt->pts != AV_NOPTS_VALUE) {
         decoded_frame->pts = pkt->pts;
-    pkt->pts           = AV_NOPTS_VALUE;
+    }
 
     resample_changed = ist->resample_sample_fmt     != decoded_frame->format         ||
                        ist->resample_channels       != avctx->channels               ||
@@ -1200,8 +1265,7 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
         return AVERROR(ENOMEM);
     decoded_frame = ist->decoded_frame;
 
-    ret = avcodec_decode_video2(ist->dec_ctx,
-                                decoded_frame, got_output, pkt);
+    ret = decode(ist->dec_ctx, decoded_frame, got_output, pkt);
     if (!*got_output || ret < 0)
         return ret;
 
@@ -1216,7 +1280,6 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
 
     decoded_frame->pts = guess_correct_pts(&ist->pts_ctx, decoded_frame->pkt_pts,
                                            decoded_frame->pkt_dts);
-    pkt->size = 0;
 
     if (ist->st->sample_aspect_ratio.num)
         decoded_frame->sample_aspect_ratio = ist->st->sample_aspect_ratio;
@@ -1311,7 +1374,7 @@ static int send_filter_eof(InputStream *ist)
 static void process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
 {
     int i;
-    int got_output;
+    int repeating = 0;
     AVPacket avpkt;
 
     if (ist->next_dts == AV_NOPTS_VALUE)
@@ -1322,36 +1385,31 @@ static void process_input_packet(InputStream *ist, const AVPacket *pkt, int no_e
         av_init_packet(&avpkt);
         avpkt.data = NULL;
         avpkt.size = 0;
-        goto handle_eof;
     } else {
         avpkt = *pkt;
     }
 
-    if (pkt->dts != AV_NOPTS_VALUE)
+    if (pkt && pkt->dts != AV_NOPTS_VALUE)
         ist->next_dts = ist->last_dts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);
 
     // while we have more to decode or while the decoder did output something on EOF
-    while (ist->decoding_needed && (avpkt.size > 0 || (!pkt && got_output))) {
+    while (ist->decoding_needed && (!pkt || avpkt.size > 0)) {
         int ret = 0;
-    handle_eof:
-
-        ist->last_dts = ist->next_dts;
+        int got_output = 0;
 
-        if (avpkt.size && avpkt.size != pkt->size &&
-            !(ist->dec->capabilities & AV_CODEC_CAP_SUBFRAMES)) {
-            av_log(NULL, ist->showed_multi_packet_warning ? AV_LOG_VERBOSE : AV_LOG_WARNING,
-                   "Multiple frames in a packet from stream %d\n", pkt->stream_index);
-            ist->showed_multi_packet_warning = 1;
-        }
+        if (!repeating)
+            ist->last_dts = ist->next_dts;
 
         switch (ist->dec_ctx->codec_type) {
         case AVMEDIA_TYPE_AUDIO:
-            ret = decode_audio    (ist, &avpkt, &got_output);
+            ret = decode_audio    (ist, repeating ? NULL : &avpkt, &got_output);
             break;
         case AVMEDIA_TYPE_VIDEO:
-            ret = decode_video    (ist, &avpkt, &got_output);
-            if (avpkt.duration)
-                ist->next_dts += av_rescale_q(avpkt.duration, ist->st->time_base, AV_TIME_BASE_Q);
+            ret = decode_video    (ist, repeating ? NULL : &avpkt, &got_output);
+            if (repeating && !got_output)
+                ;
+            else if (pkt && pkt->duration)
+                ist->next_dts += av_rescale_q(pkt->duration, ist->st->time_base, AV_TIME_BASE_Q);
             else if (ist->st->avg_frame_rate.num)
                 ist->next_dts += av_rescale_q(1, av_inv_q(ist->st->avg_frame_rate),
                                               AV_TIME_BASE_Q);
@@ -1362,6 +1420,8 @@ static void process_input_packet(InputStream *ist, const AVPacket *pkt, int no_e
             }
             break;
         case AVMEDIA_TYPE_SUBTITLE:
+            if (repeating)
+                break;
             ret = transcode_subtitles(ist, &avpkt, &got_output);
             break;
         default:
@@ -1376,14 +1436,10 @@ static void process_input_packet(InputStream *ist, const AVPacket *pkt, int no_e
             break;
         }
 
-        // touch data and size only if not EOF
-        if (pkt) {
-            avpkt.data += ret;
-            avpkt.size -= ret;
-        }
-        if (!got_output) {
-            continue;
-        }
+        if (!got_output)
+            break;
+
+        repeating = 1;
     }
 
     /* after flushing, send an EOF on all the filter inputs attached to the stream */
@@ -1561,6 +1617,51 @@ static InputStream *get_input_stream(OutputStream *ost)
     return NULL;
 }
 
+static int init_output_bsfs(OutputStream *ost)
+{
+    AVBSFContext *ctx;
+    int i, ret;
+
+    if (!ost->nb_bitstream_filters)
+        return 0;
+
+    ost->bsf_ctx = av_mallocz_array(ost->nb_bitstream_filters, sizeof(*ost->bsf_ctx));
+    if (!ost->bsf_ctx)
+        return AVERROR(ENOMEM);
+
+    for (i = 0; i < ost->nb_bitstream_filters; i++) {
+        ret = av_bsf_alloc(ost->bitstream_filters[i], &ctx);
+        if (ret < 0) {
+            av_log(NULL, AV_LOG_ERROR, "Error allocating a bitstream filter context\n");
+            return ret;
+        }
+        ost->bsf_ctx[i] = ctx;
+
+        ret = avcodec_parameters_copy(ctx->par_in,
+                                      i ? ost->bsf_ctx[i - 1]->par_out : ost->st->codecpar);
+        if (ret < 0)
+            return ret;
+
+        ctx->time_base_in = i ? ost->bsf_ctx[i - 1]->time_base_out : ost->st->time_base;
+
+        ret = av_bsf_init(ctx);
+        if (ret < 0) {
+            av_log(NULL, AV_LOG_ERROR, "Error initializing bitstream filter: %s\n",
+                   ost->bitstream_filters[i]->name);
+            return ret;
+        }
+    }
+
+    ctx = ost->bsf_ctx[ost->nb_bitstream_filters - 1];
+    ret = avcodec_parameters_copy(ost->st->codecpar, ctx->par_out);
+    if (ret < 0)
+        return ret;
+
+    ost->st->time_base = ctx->time_base_out;
+
+    return 0;
+}
+
 static int init_output_stream(OutputStream *ost, char *error, int error_len)
 {
     int ret = 0;
@@ -1655,6 +1756,13 @@ static int init_output_stream(OutputStream *ost, char *error, int error_len)
             return ret;
     }
 
+    /* initialize bitstream filters for the output stream
+     * needs to be done here, because the codec id for streamcopy is not
+     * known until now */
+    ret = init_output_bsfs(ost);
+    if (ret < 0)
+        return ret;
+
     return ret;
 }
 
@@ -2629,6 +2737,8 @@ static int transcode(void)
         }
     }
 
+    av_buffer_unref(&hw_device_ctx);
+
     /* finished ! */
     ret = 0;