padding support in ffmpeg patch by (Todd Kirby <doubleshot at pacbell dot net>)
authorTodd Kirby <doubleshot@pacbell.net>
Thu, 8 Apr 2004 18:54:40 +0000 (18:54 +0000)
committerMichael Niedermayer <michaelni@gmx.at>
Thu, 8 Apr 2004 18:54:40 +0000 (18:54 +0000)
Originally committed as revision 2982 to svn://svn.ffmpeg.org/ffmpeg/trunk

doc/ffmpeg-doc.texi
ffmpeg.c
libavcodec/avcodec.h
libavcodec/imgresample.c

index cae8250..56ee802 100644 (file)
@@ -234,6 +234,18 @@ set bottom crop band size (in pixels)
 set left crop band size (in pixels)
 @item -cropright size
 set right crop band size (in pixels)
+@item -padtop size
+set top pad band size (in pixels)
+@item -padbottom size
+set bottom pad band size (in pixels)
+@item -padleft size
+set left pad band size (in pixels)
+@item -padright size
+set right pad band size (in pixels)
+@item -padcolor color
+set right pad band size (hex). The value for pad color is expressed 
+as a six digit hexidecimal number where the first two digits represent red, 
+middle two digits green and last two digits blue. Defaults to 000000 (black)
 @item -vn
 disable video recording
 @item -bt tolerance       
index e1a2b18..80f9119 100644 (file)
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -72,6 +72,11 @@ static int frame_width  = 160;
 static int frame_height = 128;
 static float frame_aspect_ratio = 0;
 static enum PixelFormat frame_pix_fmt = PIX_FMT_YUV420P;
+static int frame_padtop  = 0;
+static int frame_padbottom = 0;
+static int frame_padleft  = 0;
+static int frame_padright = 0;
+static int padcolor[3] = {16,128,128}; /* default to black */
 static int frame_topBand  = 0;
 static int frame_bottomBand = 0;
 static int frame_leftBand  = 0;
@@ -222,6 +227,12 @@ typedef struct AVOutputStream {
     int topBand;             /* cropping area sizes */
     int leftBand;
     
+    int video_pad;           /* video_resample and video_pad are mutually exclusive */
+    int padtop;              /* padding area sizes */
+    int padbottom;
+    int padleft;
+    int padright;
+    
     /* audio only */
     int audio_resample;
     ReSampleContext *resample; /* for audio resampling */
@@ -497,6 +508,40 @@ static void pre_process_video_frame(AVInputStream *ist, AVPicture *picture, void
 /* we begin to correct av delay at this threshold */
 #define AV_DELAY_MAX 0.100
 
+
+/* Expects img to be yuv420 */
+static void fill_pad_region(AVPicture* img, int height, int width,
+        int padtop, int padbottom, int padleft, int padright, int *color) {
+  
+    int i, y, shift;
+    uint8_t *optr;
+    
+    for (i = 0; i < 3; i++) {
+        shift = (i == 0) ? 0 : 1;
+        
+        if (padtop || padleft) {
+            memset(img->data[i], color[i], (((img->linesize[i] * padtop) + 
+                            padleft) >> shift));
+        }
+
+        if (padleft || padright) {
+            optr = img->data[i] + (img->linesize[i] * (padtop >> shift)) +
+                (img->linesize[i] - (padright >> shift));
+
+            for (y = 0; y < ((height - (padtop + padbottom)) >> shift); y++) {
+                memset(optr, color[i], (padleft + padright) >> shift);
+                optr += img->linesize[i];
+            }
+        }
+      
+        if (padbottom) {
+            optr = img->data[i] + (img->linesize[i] * ((height - padbottom) >> shift));
+            memset(optr, color[i], ((img->linesize[i] * padbottom) >> shift));
+        }
+    }
+}
+
+
 static void do_video_out(AVFormatContext *s, 
                          AVOutputStream *ost, 
                          AVInputStream *ist,
@@ -579,7 +624,8 @@ static void do_video_out(AVFormatContext *s,
         return;
 
     /* convert pixel format if needed */
-    target_pixfmt = ost->video_resample ? PIX_FMT_YUV420P : enc->pix_fmt;
+    target_pixfmt = ost->video_resample || ost->video_pad
+        ? PIX_FMT_YUV420P : enc->pix_fmt;
     if (dec->pix_fmt != target_pixfmt) {
         int size;
 
@@ -601,12 +647,19 @@ static void do_video_out(AVFormatContext *s,
         formatted_picture = (AVPicture *)in_picture;
     }
 
-    /* XXX: resampling could be done before raw format convertion in
+    /* XXX: resampling could be done before raw format conversion in
        some cases to go faster */
     /* XXX: only works for YUV420P */
     if (ost->video_resample) {
         final_picture = &ost->pict_tmp;
         img_resample(ost->img_resample_ctx, final_picture, formatted_picture);
+       
+        if (ost->padtop || ost->padbottom || ost->padleft || ost->padright) {
+            fill_pad_region(final_picture, enc->height, enc->width,
+                    ost->padtop, ost->padbottom, ost->padleft, ost->padright,
+                    padcolor);
+        }
+        
        if (enc->pix_fmt != PIX_FMT_YUV420P) {
             int size;
            
@@ -642,6 +695,51 @@ static void do_video_out(AVFormatContext *s,
         picture_crop_temp.linesize[1] = formatted_picture->linesize[1];
         picture_crop_temp.linesize[2] = formatted_picture->linesize[2];
         final_picture = &picture_crop_temp;
+    } else if (ost->video_pad) {
+        final_picture = &ost->pict_tmp;
+
+        for (i = 0; i < 3; i++) {
+            uint8_t *optr, *iptr;
+            int shift = (i == 0) ? 0 : 1;
+            int y, yheight;
+            
+            /* set offset to start writing image into */
+            optr = final_picture->data[i] + (((final_picture->linesize[i] * 
+                            ost->padtop) + ost->padleft) >> shift);
+            iptr = formatted_picture->data[i];
+
+            yheight = (enc->height - ost->padtop - ost->padbottom) >> shift;
+            for (y = 0; y < yheight; y++) {
+                /* copy unpadded image row into padded image row */
+                memcpy(optr, iptr, formatted_picture->linesize[i]);
+                optr += final_picture->linesize[i];
+                iptr += formatted_picture->linesize[i];
+            }
+        }
+
+        fill_pad_region(final_picture, enc->height, enc->width,
+                ost->padtop, ost->padbottom, ost->padleft, ost->padright,
+                padcolor);
+        
+        if (enc->pix_fmt != PIX_FMT_YUV420P) {
+            int size;
+
+            av_free(buf);
+            /* create temporary picture */
+            size = avpicture_get_size(enc->pix_fmt, enc->width, enc->height);
+            buf = av_malloc(size);
+            if (!buf)
+                return;
+            final_picture = &picture_format_temp;
+            avpicture_fill(final_picture, buf, enc->pix_fmt, enc->width, enc->height);
+
+            if (img_convert(final_picture, enc->pix_fmt, 
+                        &ost->pict_tmp, PIX_FMT_YUV420P, 
+                        enc->width, enc->height) < 0) {
+                fprintf(stderr, "pixel format conversion not handled\n");
+                goto the_end;
+            }
+        }
     } else {
         final_picture = formatted_picture;
     }
@@ -1267,10 +1365,15 @@ static int av_encode(AVFormatContext **output_files,
                     frame_topBand == 0 &&
                     frame_bottomBand == 0 &&
                     frame_leftBand == 0 &&
-                    frame_rightBand == 0)
+                    frame_rightBand == 0 && 
+                    frame_padtop == 0 &&
+                    frame_padbottom == 0 &&
+                    frame_padleft == 0 &&
+                    frame_padright == 0)
                 {
                     ost->video_resample = 0;
                     ost->video_crop = 0;
+                    ost->video_pad = 0;
                 } else if ((codec->width == icodec->width -
                                 (frame_leftBand + frame_rightBand)) &&
                         (codec->height == icodec->height -
@@ -1280,6 +1383,20 @@ static int av_encode(AVFormatContext **output_files,
                     ost->video_crop = 1;
                     ost->topBand = frame_topBand;
                     ost->leftBand = frame_leftBand;
+                } else if ((codec->width == icodec->width + 
+                                (frame_padleft + frame_padright)) &&
+                        (codec->height == icodec->height +
+                                (frame_padtop + frame_padbottom))) {
+                    ost->video_resample = 0;
+                    ost->video_crop = 0;
+                    ost->video_pad = 1;
+                    ost->padtop = frame_padtop;
+                    ost->padleft = frame_padleft;
+                    ost->padbottom = frame_padbottom;
+                    ost->padright = frame_padright;
+                    if( avpicture_alloc( &ost->pict_tmp, PIX_FMT_YUV420P,
+                                codec->width, codec->height ) )
+                        goto fail;
                 } else {
                     ost->video_resample = 1;
                     ost->video_crop = 0; // cropping is handled as part of resample
@@ -1291,7 +1408,15 @@ static int av_encode(AVFormatContext **output_files,
                                       ost->st->codec.width, ost->st->codec.height,
                                       ist->st->codec.width, ist->st->codec.height,
                                       frame_topBand, frame_bottomBand,
-                                      frame_leftBand, frame_rightBand);
+                            frame_leftBand, frame_rightBand, 
+                            frame_padtop, frame_padbottom, 
+                            frame_padleft, frame_padright);
+                    
+                    ost->padtop = frame_padtop;
+                    ost->padleft = frame_padleft;
+                    ost->padbottom = frame_padbottom;
+                    ost->padright = frame_padright;
+                   
                 }
                 ost->encoding_needed = 1;
                 ist->decoding_needed = 1;
@@ -1809,6 +1934,93 @@ static void opt_frame_size(const char *arg)
     }
 }
 
+
+#define SCALEBITS 10
+#define ONE_HALF  (1 << (SCALEBITS - 1))
+#define FIX(x)   ((int) ((x) * (1<<SCALEBITS) + 0.5))
+
+#define RGB_TO_Y(r, g, b) \
+((FIX(0.29900) * (r) + FIX(0.58700) * (g) + \
+  FIX(0.11400) * (b) + ONE_HALF) >> SCALEBITS)
+
+#define RGB_TO_U(r1, g1, b1, shift)\
+(((- FIX(0.16874) * r1 - FIX(0.33126) * g1 +         \
+     FIX(0.50000) * b1 + (ONE_HALF << shift) - 1) >> (SCALEBITS + shift)) + 128)
+
+#define RGB_TO_V(r1, g1, b1, shift)\
+(((FIX(0.50000) * r1 - FIX(0.41869) * g1 -           \
+   FIX(0.08131) * b1 + (ONE_HALF << shift) - 1) >> (SCALEBITS + shift)) + 128)
+
+static void opt_pad_color(const char *arg) {
+    /* Input is expected to be six hex digits similar to
+       how colors are expressed in html tags (but without the #) */
+    int rgb = strtol(arg, NULL, 16);
+    int r,g,b;
+    
+    r = (rgb >> 16); 
+    g = ((rgb >> 8) & 255);
+    b = (rgb & 255);
+
+    padcolor[0] = RGB_TO_Y(r,g,b);
+    padcolor[1] = RGB_TO_U(r,g,b,0);
+    padcolor[2] = RGB_TO_V(r,g,b,0);
+}
+
+static void opt_frame_pad_top(const char *arg)
+{
+    frame_padtop = atoi(arg); 
+    if (frame_padtop < 0) {
+        fprintf(stderr, "Incorrect top pad size\n");
+        exit(1);
+    }
+    if ((frame_padtop % 2) != 0) {
+        fprintf(stderr, "Top pad size must be a multiple of 2\n");
+        exit(1);
+    }
+}
+
+static void opt_frame_pad_bottom(const char *arg)
+{
+    frame_padbottom = atoi(arg); 
+    if (frame_padbottom < 0) {
+        fprintf(stderr, "Incorrect bottom pad size\n");
+        exit(1);
+    }
+    if ((frame_padbottom % 2) != 0) {
+        fprintf(stderr, "Bottom pad size must be a multiple of 2\n");
+        exit(1);
+    }
+}
+
+
+static void opt_frame_pad_left(const char *arg)
+{
+    frame_padleft = atoi(arg); 
+    if (frame_padleft < 0) {
+        fprintf(stderr, "Incorrect left pad size\n");
+        exit(1);
+    }
+    if ((frame_padleft % 2) != 0) {
+        fprintf(stderr, "Left pad size must be a multiple of 2\n");
+        exit(1);
+    }
+}
+
+
+static void opt_frame_pad_right(const char *arg)
+{
+    frame_padright = atoi(arg); 
+    if (frame_padright < 0) {
+        fprintf(stderr, "Incorrect right pad size\n");
+        exit(1);
+    }
+    if ((frame_padright % 2) != 0) {
+        fprintf(stderr, "Right pad size must be a multiple of 2\n");
+        exit(1);
+    }
+}
+
+
 static void opt_frame_pix_fmt(const char *arg)
 {
     frame_pix_fmt = avcodec_get_pix_fmt(arg);
@@ -2237,8 +2449,8 @@ static void opt_input_file(const char *filename)
     ap->channels = audio_channels;
     ap->frame_rate = frame_rate;
     ap->frame_rate_base = frame_rate_base;
-    ap->width = frame_width;
-    ap->height = frame_height;
+    ap->width = frame_width + frame_padleft + frame_padright;
+    ap->height = frame_height + frame_padtop + frame_padbottom;
     ap->image_format = image_format;
     ap->pix_fmt = frame_pix_fmt;
 
@@ -2454,8 +2666,8 @@ static void opt_output_file(const char *filename)
                 video_enc->frame_rate = frame_rate; 
                 video_enc->frame_rate_base = frame_rate_base; 
                 
-                video_enc->width = frame_width;
-                video_enc->height = frame_height;
+                video_enc->width = frame_width + frame_padright + frame_padleft;
+                video_enc->height = frame_height + frame_padtop + frame_padbottom;
                video_enc->sample_aspect_ratio = av_d2q(frame_aspect_ratio*frame_height/frame_width, 255);
                video_enc->pix_fmt = frame_pix_fmt;
 
@@ -3164,6 +3376,11 @@ const OptionDef options[] = {
     { "cropbottom", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_crop_bottom}, "set bottom crop band size (in pixels)", "size" },
     { "cropleft", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_crop_left}, "set left crop band size (in pixels)", "size" },
     { "cropright", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_crop_right}, "set right crop band size (in pixels)", "size" },
+    { "padtop", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_pad_top}, "set top pad band size (in pixels)", "size" },
+    { "padbottom", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_pad_bottom}, "set bottom pad band size (in pixels)", "size" },
+    { "padleft", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_pad_left}, "set left pad band size (in pixels)", "size" },
+    { "padright", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_pad_right}, "set right pad band size (in pixels)", "size" },
+    { "padcolor", HAS_ARG | OPT_VIDEO, {(void*)opt_pad_color}, "set color of pad bands (Hex 000000 thru FFFFFF)", "color" },
     { "g", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_gop_size}, "set the group of picture size", "gop_size" },
     { "intra", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&intra_only}, "use only intra frames"},
     { "vn", OPT_BOOL | OPT_VIDEO, {(void*)&video_disable}, "disable video" },
@@ -3217,7 +3434,7 @@ const OptionDef options[] = {
     { "bug", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_workaround_bugs}, "workaround not auto detected encoder bugs", "param" },
     { "ps", HAS_ARG | OPT_EXPERT, {(void*)opt_packet_size}, "set packet size in bits", "size" },
     { "error", HAS_ARG | OPT_EXPERT, {(void*)opt_error_rate}, "error rate", "rate" },
-    { "strict", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_strict}, "how strictly to follow the standarts", "strictness" },
+    { "strict", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_strict}, "how strictly to follow the standards", "strictness" },
     { "sameq", OPT_BOOL | OPT_VIDEO, {(void*)&same_quality}, 
       "use same video quality as source (implies VBR)" },
     { "pass", HAS_ARG | OPT_VIDEO, {(void*)&opt_pass}, "select the pass number (1 or 2)", "n" },
index 909dec1..10040b2 100644 (file)
@@ -17,7 +17,7 @@ extern "C" {
 
 #define FFMPEG_VERSION_INT     0x000408
 #define FFMPEG_VERSION         "0.4.8"
-#define LIBAVCODEC_BUILD       4707
+#define LIBAVCODEC_BUILD       4708
 
 #define LIBAVCODEC_VERSION_INT FFMPEG_VERSION_INT
 #define LIBAVCODEC_VERSION     FFMPEG_VERSION
@@ -1821,7 +1821,10 @@ ImgReSampleContext *img_resample_init(int output_width, int output_height,
 ImgReSampleContext *img_resample_full_init(int owidth, int oheight,
                                       int iwidth, int iheight,
                                       int topBand, int bottomBand,
-                                      int leftBand, int rightBand);
+                                      int leftBand, int rightBand,
+                                      int padtop, int padbottom,
+                                      int padleft, int padright);
+
 
 void img_resample(ImgReSampleContext *s, 
                   AVPicture *output, const AVPicture *input);
index a18645e..14fdb10 100644 (file)
 #define LINE_BUF_HEIGHT (NB_TAPS * 4)
 
 struct ImgReSampleContext {
-    int iwidth, iheight, owidth, oheight, topBand, bottomBand, leftBand, rightBand;
+    int iwidth, iheight, owidth, oheight;
+    int topBand, bottomBand, leftBand, rightBand;
+    int padtop, padbottom, padleft, padright;
+    int pad_owidth, pad_oheight;
     int h_incr, v_incr;
     int16_t h_filters[NB_PHASES][NB_TAPS] __align8; /* horizontal filters */
     int16_t v_filters[NB_PHASES][NB_TAPS] __align8; /* vertical filters */
@@ -532,6 +535,7 @@ static void component_resample(ImgReSampleContext *s,
                        &s->v_filters[phase_y][0]);
             
         src_y += s->v_incr;
+        
         output += owrap;
     }
 }
@@ -572,13 +576,16 @@ static void build_filter(int16_t *filter, float factor)
 ImgReSampleContext *img_resample_init(int owidth, int oheight,
                                       int iwidth, int iheight)
 {
-       return img_resample_full_init(owidth, oheight, iwidth, iheight, 0, 0, 0, 0);
+    return img_resample_full_init(owidth, oheight, iwidth, iheight, 
+            0, 0, 0, 0, 0, 0, 0, 0);
 }
 
 ImgReSampleContext *img_resample_full_init(int owidth, int oheight,
                                       int iwidth, int iheight,
                                       int topBand, int bottomBand,
-                                      int leftBand, int rightBand)
+        int leftBand, int rightBand,
+        int padtop, int padbottom,
+        int padleft, int padright)
 {
     ImgReSampleContext *s;
 
@@ -593,19 +600,30 @@ ImgReSampleContext *img_resample_full_init(int owidth, int oheight,
     s->oheight = oheight;
     s->iwidth = iwidth;
     s->iheight = iheight;
+  
     s->topBand = topBand;
     s->bottomBand = bottomBand;
     s->leftBand = leftBand;
     s->rightBand = rightBand;
     
-    s->h_incr = ((iwidth - leftBand - rightBand) * POS_FRAC) / owidth;
-    s->v_incr = ((iheight - topBand - bottomBand) * POS_FRAC) / oheight;
-    
-    build_filter(&s->h_filters[0][0], (float) owidth  / (float) (iwidth - leftBand - rightBand));
-    build_filter(&s->v_filters[0][0], (float) oheight / (float) (iheight - topBand - bottomBand));
+    s->padtop = padtop;
+    s->padbottom = padbottom;
+    s->padleft = padleft;
+    s->padright = padright;
+
+    s->pad_owidth = owidth - (padleft + padright);
+    s->pad_oheight = oheight - (padtop + padbottom);
+
+    s->h_incr = ((iwidth - leftBand - rightBand) * POS_FRAC) / s->pad_owidth;
+    s->v_incr = ((iheight - topBand - bottomBand) * POS_FRAC) / s->pad_oheight; 
+
+    build_filter(&s->h_filters[0][0], (float) s->pad_owidth  / 
+            (float) (iwidth - leftBand - rightBand));
+    build_filter(&s->v_filters[0][0], (float) s->pad_oheight / 
+            (float) (iheight - topBand - bottomBand));
 
     return s;
- fail:
+fail:
     av_free(s);
     return NULL;
 }
@@ -614,13 +632,20 @@ void img_resample(ImgReSampleContext *s,
                   AVPicture *output, const AVPicture *input)
 {
     int i, shift;
+    uint8_t* optr;
 
-    for(i=0;i<3;i++) {
+    for (i=0;i<3;i++) {
         shift = (i == 0) ? 0 : 1;
-        component_resample(s, output->data[i], output->linesize[i], 
-                           s->owidth >> shift, s->oheight >> shift,
-                           input->data[i] + (input->linesize[i] * (s->topBand >> shift)) + (s->leftBand >> shift),
-                           input->linesize[i], ((s->iwidth - s->leftBand - s->rightBand) >> shift),
+
+        optr = output->data[i] + (((output->linesize[i] * 
+                        s->padtop) + s->padleft) >> shift);
+
+        component_resample(s, optr, output->linesize[i], 
+                s->pad_owidth >> shift, s->pad_oheight >> shift,
+                input->data[i] + (input->linesize[i] * 
+                    (s->topBand >> shift)) + (s->leftBand >> shift),
+                input->linesize[i], ((s->iwidth - s->leftBand - 
+                        s->rightBand) >> shift),
                            (s->iheight - s->topBand - s->bottomBand) >> shift);
     }
 }