[FFmpeg-devel,3/3] lavfi: add a framework to fix alignment problems.

Submitted by Nicolas George on May 18, 2017, 8:11 a.m.

Details

Message ID 20170518081114.21425-3-george@nsup.org
State New
Headers show

Commit Message

Nicolas George May 18, 2017, 8:11 a.m.
A lot of filters require aligned frame data, but do not document it.
It can result in crashes with perfectly valid uses of the API.
For now, the default alignment is not set.

Signed-off-by: Nicolas George <george@nsup.org>
---
 libavfilter/avfilter.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++
 libavfilter/avfilter.h |  9 +++++++++
 2 files changed, 60 insertions(+)

Patch hide | download patch | download mbox

diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index 08b86b010d..ff49e80289 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -166,6 +166,7 @@  int avfilter_link(AVFilterContext *src, unsigned srcpad,
     link->type    = src->output_pads[srcpad].type;
     av_assert0(AV_PIX_FMT_NONE == -1 && AV_SAMPLE_FMT_NONE == -1);
     link->format  = -1;
+    link->alignment = 1;
     ff_framequeue_init(&link->fifo, &src->graph->internal->frame_queues);
 
     return 0;
@@ -1515,15 +1516,60 @@  static void consume_update(AVFilterLink *link, const AVFrame *frame)
     link->frame_count_out++;
 }
 
+static int frame_realign(AVFilterLink *link, AVFrame *frame)
+{
+    AVFrame *tmp;
+    int ret;
+
+    if (!frame || av_frame_check_align(frame, link->alignment))
+        return 0;
+
+    switch (link->type) {
+    case AVMEDIA_TYPE_VIDEO:
+        tmp = ff_get_video_buffer(link, link->w, link->h);
+        break;
+    case AVMEDIA_TYPE_AUDIO:
+        tmp = ff_get_audio_buffer(link, frame->nb_samples);
+        break;
+    default:
+        av_assert0(!"reached");
+    }
+    if (!tmp)
+        return AVERROR(ENOMEM);
+
+    if (ret < 0)
+        goto fail;
+    ret = av_frame_copy(tmp, frame);
+    if (ret < 0)
+        return ret;
+    ret = av_frame_copy_props(tmp, frame);
+    if (ret < 0)
+        return ret;
+    av_frame_unref(frame);
+    av_frame_move_ref(frame, tmp);
+    av_frame_free(&tmp);
+    return 0;
+
+fail:
+    av_frame_free(&tmp);
+    return ret;
+}
+
 int ff_inlink_consume_frame(AVFilterLink *link, AVFrame **rframe)
 {
     AVFrame *frame;
+    int ret;
 
     *rframe = NULL;
     if (!ff_inlink_check_available_frame(link))
         return 0;
     frame = ff_framequeue_take(&link->fifo);
     consume_update(link, frame);
+    ret = frame_realign(link, frame);
+    if (ret < 0) {
+        av_frame_free(&frame);
+        return ret;
+    }
     *rframe = frame;
     return 1;
 }
@@ -1544,6 +1590,11 @@  int ff_inlink_consume_samples(AVFilterLink *link, unsigned min, unsigned max,
     if (ret < 0)
         return ret;
     consume_update(link, frame);
+    ret = frame_realign(link, frame);
+    if (ret < 0) {
+        av_frame_free(&frame);
+        return ret;
+    }
     *rframe = frame;
     return 1;
 }
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index 60662c19ac..16543a666e 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -569,6 +569,15 @@  struct AVFilterLink {
      */
     AVBufferRef *hw_frames_ctx;
 
+    /**
+     * Minimum alignment of frame data required by the destination filter.
+     * All frame data pointers must have the alignment lower bits cleared,
+     * i.e. be a multiple of alignment.
+     * Frames with insufficient alignment will be realigned by the
+     * framework.
+     */
+    unsigned alignment;
+
 #ifndef FF_INTERNAL_FIELDS
 
     /**