diff mbox series

[FFmpeg-devel,6/8] lavfi/vf_scale: convert to the frame-based sws API

Message ID 20210712110709.15532-7-anton@khirnov.net
State New
Headers show
Series [FFmpeg-devel,1/8] tools/venc_data_dump: factor out demux/decode code
Related show

Checks

Context Check Description
andriy/x86_make success Make finished
andriy/x86_make_fate success Make fate finished
andriy/PPC64_make success Make finished
andriy/PPC64_make_fate success Make fate finished

Commit Message

Anton Khirnov July 12, 2021, 11:07 a.m. UTC
---
 libavfilter/vf_scale.c | 73 ++++++++++++++++++++++++++++--------------
 1 file changed, 49 insertions(+), 24 deletions(-)

Comments

Michael Niedermayer July 12, 2021, 7:39 p.m. UTC | #1
On Mon, Jul 12, 2021 at 01:07:07PM +0200, Anton Khirnov wrote:
> ---
>  libavfilter/vf_scale.c | 73 ++++++++++++++++++++++++++++--------------
>  1 file changed, 49 insertions(+), 24 deletions(-)

crashes:

 ./ffmpeg  -i ~/tickets/5264/gbrap16.tif -vf format=yuva444p,scale=alphablend=checkerboard,format=yuv420p -y file.png

 Stream mapping:
  Stream #0:0 -> #0:0 (tiff (native) -> png (native))
Press [q] to stop, [?] for help
==19419== Invalid read of size 4
==19419==    at 0x1223964: av_frame_ref (frame.c:330)
==19419==    by 0x1190B34: sws_frame_start (swscale.c:1069)
==19419==    by 0x1190EA4: sws_scale_frame (swscale.c:1153)
==19419==    by 0x3E7493: scale_frame (vf_scale.c:821)
==19419==    by 0x3E752D: filter_frame (vf_scale.c:837)
==19419==    by 0x29B314: ff_filter_frame_framed (avfilter.c:969)
==19419==    by 0x29BBCF: ff_filter_frame_to_filter (avfilter.c:1117)
==19419==    by 0x29BDDF: ff_filter_activate_default (avfilter.c:1166)
==19419==    by 0x29C003: ff_filter_activate (avfilter.c:1324)
==19419==    by 0x2A0EBB: ff_filter_graph_run_once (avfiltergraph.c:1400)
==19419==    by 0x2A2139: push_frame (buffersrc.c:157)
==19419==    by 0x2A26B6: av_buffersrc_add_frame_flags (buffersrc.c:225)
==19419==    by 0x24FC90: ifilter_send_frame (ffmpeg.c:2241)
==19419==    by 0x24FF72: send_frame_to_filters (ffmpeg.c:2315)
==19419==    by 0x250D26: decode_video (ffmpeg.c:2512)
==19419==    by 0x2517BA: process_input_packet (ffmpeg.c:2674)
==19419==    by 0x25799F: process_input (ffmpeg.c:4403)
==19419==    by 0x2599A4: transcode_step (ffmpeg.c:4758)
==19419==    by 0x259B0C: transcode (ffmpeg.c:4812)
==19419==    by 0x25A470: main (ffmpeg.c:5017)
==19419==  Address 0x68 is not stack'd, malloc'd or (recently) free'd
==19419== 
==19419== 
 

[...]
James Almer July 12, 2021, 8:21 p.m. UTC | #2
On 7/12/2021 4:39 PM, Michael Niedermayer wrote:
> On Mon, Jul 12, 2021 at 01:07:07PM +0200, Anton Khirnov wrote:
>> ---
>>   libavfilter/vf_scale.c | 73 ++++++++++++++++++++++++++++--------------
>>   1 file changed, 49 insertions(+), 24 deletions(-)
> 
> crashes:
> 
>   ./ffmpeg  -i ~/tickets/5264/gbrap16.tif -vf format=yuva444p,scale=alphablend=checkerboard,format=yuv420p -y file.png
> 
>   Stream mapping:
>    Stream #0:0 -> #0:0 (tiff (native) -> png (native))
> Press [q] to stop, [?] for help
> ==19419== Invalid read of size 4
> ==19419==    at 0x1223964: av_frame_ref (frame.c:330)
> ==19419==    by 0x1190B34: sws_frame_start (swscale.c:1069)
> ==19419==    by 0x1190EA4: sws_scale_frame (swscale.c:1153)
> ==19419==    by 0x3E7493: scale_frame (vf_scale.c:821)
> ==19419==    by 0x3E752D: filter_frame (vf_scale.c:837)
> ==19419==    by 0x29B314: ff_filter_frame_framed (avfilter.c:969)
> ==19419==    by 0x29BBCF: ff_filter_frame_to_filter (avfilter.c:1117)
> ==19419==    by 0x29BDDF: ff_filter_activate_default (avfilter.c:1166)
> ==19419==    by 0x29C003: ff_filter_activate (avfilter.c:1324)
> ==19419==    by 0x2A0EBB: ff_filter_graph_run_once (avfiltergraph.c:1400)
> ==19419==    by 0x2A2139: push_frame (buffersrc.c:157)
> ==19419==    by 0x2A26B6: av_buffersrc_add_frame_flags (buffersrc.c:225)
> ==19419==    by 0x24FC90: ifilter_send_frame (ffmpeg.c:2241)
> ==19419==    by 0x24FF72: send_frame_to_filters (ffmpeg.c:2315)
> ==19419==    by 0x250D26: decode_video (ffmpeg.c:2512)
> ==19419==    by 0x2517BA: process_input_packet (ffmpeg.c:2674)
> ==19419==    by 0x25799F: process_input (ffmpeg.c:4403)
> ==19419==    by 0x2599A4: transcode_step (ffmpeg.c:4758)
> ==19419==    by 0x259B0C: transcode (ffmpeg.c:4812)
> ==19419==    by 0x25A470: main (ffmpeg.c:5017)
> ==19419==  Address 0x68 is not stack'd, malloc'd or (recently) free'd
> ==19419==
> ==19419==

Both c->frame_src and c->frame_dst need to be allocated earlier in 
sws_init_context(). There seem to be some cases where that function will 
return early with a success code.
diff mbox series

Patch

diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
index 39ab3a4b28..cdff3ab7ed 100644
--- a/libavfilter/vf_scale.c
+++ b/libavfilter/vf_scale.c
@@ -620,29 +620,54 @@  static int request_frame_ref(AVFilterLink *outlink)
     return ff_request_frame(outlink->src->inputs[1]);
 }
 
-static int scale_slice(ScaleContext *scale, AVFrame *out_buf, AVFrame *cur_pic, struct SwsContext *sws, int y, int h, int mul, int field)
+static void frame_offset(AVFrame *frame, int dir, int is_pal)
 {
-    const uint8_t *in[4];
-    uint8_t *out[4];
-    int in_stride[4],out_stride[4];
-    int i;
-
-    for (i=0; i<4; i++) {
-        int vsub= ((i+1)&2) ? scale->vsub : 0;
-        ptrdiff_t  in_offset = ((y>>vsub)+field) * cur_pic->linesize[i];
-        ptrdiff_t out_offset =            field  * out_buf->linesize[i];
-         in_stride[i] = cur_pic->linesize[i] * mul;
-        out_stride[i] = out_buf->linesize[i] * mul;
-         in[i] = FF_PTR_ADD(cur_pic->data[i],  in_offset);
-        out[i] = FF_PTR_ADD(out_buf->data[i], out_offset);
-    }
-    if (scale->input_is_pal)
-         in[1] = cur_pic->data[1];
-    if (scale->output_is_pal)
-        out[1] = out_buf->data[1];
+    for (int i = 0; i < 4 && frame->data[i]; i++) {
+        if (i == 1 && is_pal)
+            break;
+        frame->data[i] += frame->linesize[i] * dir;
+    }
+}
+
+static int scale_field(ScaleContext *scale, AVFrame *dst, AVFrame *src,
+                       int field)
+{
+    int orig_h_src = src->height;
+    int orig_h_dst = dst->height;
+    int ret;
+
+    // offset the data pointers for the bottom field
+    if (field) {
+        frame_offset(src, 1, scale->input_is_pal);
+        frame_offset(dst, 1, scale->output_is_pal);
+    }
+
+    // take every second line
+    for (int i = 0; i < 4; i++) {
+        src->linesize[i] *= 2;
+        dst->linesize[i] *= 2;
+    }
+    src->height /= 2;
+    dst->height /= 2;
 
-    return sws_scale(sws, in, in_stride, y/mul, h,
-                         out,out_stride);
+    ret = sws_scale_frame(scale->isws[field], dst, src);
+    if (ret < 0)
+        return ret;
+
+    // undo the changes we made above
+    for (int i = 0; i < 4; i++) {
+        src->linesize[i] /= 2;
+        dst->linesize[i] /= 2;
+    }
+    src->height = orig_h_src;
+    dst->height = orig_h_dst;
+
+    if (field) {
+        frame_offset(src, -1, scale->input_is_pal);
+        frame_offset(dst, -1, scale->output_is_pal);
+    }
+
+    return 0;
 }
 
 static int scale_frame(AVFilterLink *link, AVFrame *in, AVFrame **frame_out)
@@ -789,11 +814,11 @@  scale:
               INT_MAX);
 
     if (scale->interlaced>0 || (scale->interlaced<0 && in->interlaced_frame)) {
-        ret = scale_slice(scale, out, in, scale->isws[0], 0, (link->h+1)/2, 2, 0);
+        ret = scale_field(scale, out, in, 0);
         if (ret >= 0)
-            ret = scale_slice(scale, out, in, scale->isws[1], 0,  link->h   /2, 2, 1);
+            ret = scale_field(scale, out, in, 1);
     } else {
-        ret = scale_slice(scale, out, in, scale->sws, 0, link->h, 1, 0);
+        ret = sws_scale_frame(scale->sws, out, in);
     }
 
     av_frame_free(&in);