[FFmpeg-devel] [PATCH] make sure blending the subtitle does not write outside buffer

Reimar Döffinger Reimar.Doeffinger
Wed Aug 8 15:51:26 CEST 2007


Hello,
On Wed, Aug 08, 2007 at 03:50:22PM +0200, Reimar D?ffinger wrote:
> On Sun, Aug 05, 2007 at 12:12:26PM +0200, Michael Niedermayer wrote:
> > On Sun, Aug 05, 2007 at 11:00:04AM +0200, Reimar D?ffinger wrote:
> > > attached patch fixes the subtitle rectangles so they do not lie outside
> > > the video, which can cause crashes.
> > 
> > hmm, this seems like a hack to me
> > shouldnt blend_subrect "skip" the parts of a rectange which are outside
> > of the image?
> > 
> > that said blend_subrect() needs a cleanup, theres no need to have 9 cases
> > handled like that, a generic and a fast one for the middle would do
> 
> Does something like this look okay? I can of course split it into two
> parts, on that makes sure we do not get outside the bounds of the
> destination image and one that "scales" the x and y positions, but then
> someone absolutely must suggest a better name for "scaledx/y/w/h" ;-)
> Btw. the picture blend_subrect creates when x, y or x+w or y+h is odd is
> still completely broken, IMO we should remove the "if (rect->x & 1) {"
> etc. cases and just do x &= ~1; w &= ~1; etc.

Patch...
-------------- next part --------------
diff --git a/ffplay.c b/ffplay.c
index 9af066e..3329b38 100644
--- a/ffplay.c
+++ b/ffplay.c
@@ -422,31 +422,37 @@ void fill_border(VideoState *s, int x, int y, int w, int h, int color)
 
 #define BPP 1
 
-static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect)
+static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, int imgh,
+                          float scalex, float scaley)
 {
     int wrap, wrap3, width2, skip2;
     int y, u, v, a, u1, v1, a1, w, h;
     uint8_t *lum, *cb, *cr;
     const uint8_t *p;
     const uint32_t *pal;
-
-    lum = dst->data[0] + rect->y * dst->linesize[0];
-    cb = dst->data[1] + (rect->y >> 1) * dst->linesize[1];
-    cr = dst->data[2] + (rect->y >> 1) * dst->linesize[2];
-
-    width2 = (rect->w + 1) >> 1;
-    skip2 = rect->x >> 1;
+    int scaledx, scaledy, scaledw, scaledh;
+
+    scaledx = FFMIN(scalex * rect->x, imgw);
+    scaledw = FFMIN(rect->w, imgw - scaledx);
+    scaledy = FFMIN(scaley * rect->y, imgh);
+    scaledh = FFMIN(rect->h, imgh - scaledy);
+    lum = dst->data[0] + scaledy * dst->linesize[0];
+    cb = dst->data[1] + (scaledy >> 1) * dst->linesize[1];
+    cr = dst->data[2] + (scaledy >> 1) * dst->linesize[2];
+
+    width2 = (scaledw + 1) >> 1;
+    skip2 = scaledx >> 1;
     wrap = dst->linesize[0];
     wrap3 = rect->linesize;
     p = rect->bitmap;
     pal = rect->rgba_palette;  /* Now in YCrCb! */
 
-    if (rect->y & 1) {
-        lum += rect->x;
+    if (scaledy & 1) {
+        lum += scaledx;
         cb += skip2;
         cr += skip2;
 
-        if (rect->x & 1) {
+        if (scaledx & 1) {
             YUVA_IN(y, u, v, a, p, pal);
             lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
             cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
@@ -456,7 +462,7 @@ static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect)
             lum++;
             p += BPP;
         }
-        for(w = rect->w - (rect->x & 1); w >= 2; w -= 2) {
+        for(w = scaledw - (scaledx & 1); w >= 2; w -= 2) {
             YUVA_IN(y, u, v, a, p, pal);
             u1 = u;
             v1 = v;
@@ -481,17 +487,17 @@ static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect)
             cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
             cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
         }
-        p += wrap3 + (wrap3 - rect->w * BPP);
-        lum += wrap + (wrap - rect->w - rect->x);
+        p += wrap3 + (wrap3 - scaledw * BPP);
+        lum += wrap + (wrap - scaledw - scaledx);
         cb += dst->linesize[1] - width2 - skip2;
         cr += dst->linesize[2] - width2 - skip2;
     }
-    for(h = rect->h - (rect->y & 1); h >= 2; h -= 2) {
-        lum += rect->x;
+    for(h = scaledh - (scaledy & 1); h >= 2; h -= 2) {
+        lum += scaledx;
         cb += skip2;
         cr += skip2;
 
-        if (rect->x & 1) {
+        if (scaledx & 1) {
             YUVA_IN(y, u, v, a, p, pal);
             u1 = u;
             v1 = v;
@@ -511,7 +517,7 @@ static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect)
             p += -wrap3 + BPP;
             lum += -wrap + 1;
         }
-        for(w = rect->w - (rect->x & 1); w >= 2; w -= 2) {
+        for(w = scaledw - (scaledx & 1); w >= 2; w -= 2) {
             YUVA_IN(y, u, v, a, p, pal);
             u1 = u;
             v1 = v;
@@ -566,18 +572,18 @@ static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect)
             p += -wrap3 + BPP;
             lum += -wrap + 1;
         }
-        p += wrap3 + (wrap3 - rect->w * BPP);
-        lum += wrap + (wrap - rect->w - rect->x);
+        p += wrap3 + (wrap3 - scaledw * BPP);
+        lum += wrap + (wrap - scaledw - scaledx);
         cb += dst->linesize[1] - width2 - skip2;
         cr += dst->linesize[2] - width2 - skip2;
     }
     /* handle odd height */
     if (h) {
-        lum += rect->x;
+        lum += scaledx;
         cb += skip2;
         cr += skip2;
 
-        if (rect->x & 1) {
+        if (scaledx & 1) {
             YUVA_IN(y, u, v, a, p, pal);
             lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
             cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
@@ -587,7 +593,7 @@ static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect)
             lum++;
             p += BPP;
         }
-        for(w = rect->w - (rect->x & 1); w >= 2; w -= 2) {
+        for(w = scaledw - (scaledx & 1); w >= 2; w -= 2) {
             YUVA_IN(y, u, v, a, p, pal);
             u1 = u;
             v1 = v;
@@ -694,6 +700,7 @@ static void video_image_display(VideoState *is)
 
                 if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000))
                 {
+                    float scalex = 1, scaley = 1;
                     SDL_LockYUVOverlay (vp->bmp);
 
                     pict.data[0] = vp->bmp->pixels[0];
@@ -704,8 +711,13 @@ static void video_image_display(VideoState *is)
                     pict.linesize[1] = vp->bmp->pitches[2];
                     pict.linesize[2] = vp->bmp->pitches[1];
 
+                    if (is->subtitle_st->codec->width)
+                        scalex = (float)vp->bmp->w / is->subtitle_st->codec->width;
+                    if (is->subtitle_st->codec->height)
+                        scaley = (float)vp->bmp->h / is->subtitle_st->codec->height;
                     for (i = 0; i < sp->sub.num_rects; i++)
-                        blend_subrect(&pict, &sp->sub.rects[i]);
+                        blend_subrect(&pict, &sp->sub.rects[i],
+                                      vp->bmp->w, vp->bmp->h, scalex, scaley);
 
                     SDL_UnlockYUVOverlay (vp->bmp);
                 }



More information about the ffmpeg-devel mailing list