Imported Debian version 2.5.0~trusty1.1
[deb_ffmpeg.git] / ffmpeg / libavfilter / af_aresample.c
index 5f34321fe8534f972f1520432efc85a3ce7b6513..57ac3978be2a9b6ae60e553eaa00562eb43b6eb9 100644 (file)
@@ -41,6 +41,7 @@ typedef struct {
     struct SwrContext *swr;
     int64_t next_pts;
     int req_fullfilled;
+    int more_data;
 } AResampleContext;
 
 static av_cold int init_dict(AVFilterContext *ctx, AVDictionary **opts)
@@ -103,6 +104,11 @@ static int query_formats(AVFilterContext *ctx)
     } else {
         out_samplerates = ff_all_samplerates();
     }
+    if (!out_samplerates) {
+        av_log(ctx, AV_LOG_ERROR, "Cannot allocate output samplerates.\n");
+        return AVERROR(ENOMEM);
+    }
+
     ff_formats_ref(out_samplerates, &outlink->in_samplerates);
 
     if(out_format != AV_SAMPLE_FMT_NONE) {
@@ -181,7 +187,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref)
 
     delay = swr_get_delay(aresample->swr, outlink->sample_rate);
     if (delay > 0)
-        n_out += delay;
+        n_out += FFMIN(delay, FFMAX(4096, n_out));
 
     outsamplesref = ff_get_audio_buffer(outlink, n_out);
 
@@ -210,6 +216,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref)
         return 0;
     }
 
+    aresample->more_data = outsamplesref->nb_samples == n_out; // Indicate that there is probably more data in our buffers
+
     outsamplesref->nb_samples  = n_out;
 
     ret = ff_filter_frame(outlink, outsamplesref);
@@ -218,40 +226,65 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref)
     return ret;
 }
 
-static int request_frame(AVFilterLink *outlink)
+static int flush_frame(AVFilterLink *outlink, int final, AVFrame **outsamplesref_ret)
 {
     AVFilterContext *ctx = outlink->src;
     AResampleContext *aresample = ctx->priv;
     AVFilterLink *const inlink = outlink->src->inputs[0];
+    AVFrame *outsamplesref;
+    int n_out = 4096;
+    int64_t pts;
+
+    outsamplesref = ff_get_audio_buffer(outlink, n_out);
+    *outsamplesref_ret = outsamplesref;
+    if (!outsamplesref)
+        return AVERROR(ENOMEM);
+
+    pts = swr_next_pts(aresample->swr, INT64_MIN);
+    pts = ROUNDED_DIV(pts, inlink->sample_rate);
+
+    n_out = swr_convert(aresample->swr, outsamplesref->extended_data, n_out, final ? NULL : (void*)outsamplesref->extended_data, 0);
+    if (n_out <= 0) {
+        av_frame_free(&outsamplesref);
+        return (n_out == 0) ? AVERROR_EOF : n_out;
+    }
+
+    outsamplesref->sample_rate = outlink->sample_rate;
+    outsamplesref->nb_samples  = n_out;
+
+    outsamplesref->pts = pts;
+
+    return 0;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+    AVFilterContext *ctx = outlink->src;
+    AResampleContext *aresample = ctx->priv;
     int ret;
 
+    // First try to get data from the internal buffers
+    if (aresample->more_data) {
+        AVFrame *outsamplesref;
+
+        if (flush_frame(outlink, 0, &outsamplesref) >= 0) {
+            return ff_filter_frame(outlink, outsamplesref);
+        }
+    }
+    aresample->more_data = 0;
+
+    // Second request more data from the input
     aresample->req_fullfilled = 0;
     do{
         ret = ff_request_frame(ctx->inputs[0]);
     }while(!aresample->req_fullfilled && ret>=0);
 
+    // Third if we hit the end flush
     if (ret == AVERROR_EOF) {
         AVFrame *outsamplesref;
-        int n_out = 4096;
-        int64_t pts;
-
-        outsamplesref = ff_get_audio_buffer(outlink, n_out);
-        if (!outsamplesref)
-            return AVERROR(ENOMEM);
-
-        pts = swr_next_pts(aresample->swr, INT64_MIN);
-        pts = ROUNDED_DIV(pts, inlink->sample_rate);
-
-        n_out = swr_convert(aresample->swr, outsamplesref->extended_data, n_out, 0, 0);
-        if (n_out <= 0) {
-            av_frame_free(&outsamplesref);
-            return (n_out == 0) ? AVERROR_EOF : n_out;
-        }
-
-        outsamplesref->sample_rate = outlink->sample_rate;
-        outsamplesref->nb_samples  = n_out;
 
-        outsamplesref->pts = pts;
+        if ((ret = flush_frame(outlink, 1, &outsamplesref)) < 0)
+            return ret;
 
         return ff_filter_frame(outlink, outsamplesref);
     }