]> git.sesse.net Git - ffmpeg/blobdiff - libavfilter/vf_tinterlace.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / libavfilter / vf_tinterlace.c
index 8407d1f050a0f4535c6c6abc8e10889e21ae1ad0..b0d04eb41877faea72031ccee131879165af4a0a 100644 (file)
 #include "avfilter.h"
 #include "internal.h"
 
+enum TInterlaceMode {
+    MODE_MERGE = 0,
+    MODE_DROP_EVEN,
+    MODE_DROP_ODD,
+    MODE_PAD,
+    MODE_INTERLEAVE_TOP,
+    MODE_INTERLEAVE_BOTTOM,
+    MODE_INTERLACEX2,
+};
+
+static const char *tinterlace_mode_str[] = {
+    "merge",
+    "drop_even",
+    "drop_odd",
+    "pad",
+    "interleave_top",
+    "interleave_bottom",
+    "interlacex2",
+    NULL
+};
+
 typedef struct {
-    int mode;                   ///< interlace mode selected
+    enum TInterlaceMode mode;   ///< interlace mode selected
     int frame;                  ///< number of the output frame
     int vsub;                   ///< chroma vertical subsampling
     AVFilterBufferRef *cur;
@@ -55,23 +76,39 @@ static int query_formats(AVFilterContext *ctx)
         PIX_FMT_NONE
     };
 
-    avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
+    ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
     return 0;
 }
 
 static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
 {
     TInterlaceContext *tinterlace = ctx->priv;
-    int n;
-    tinterlace->mode = 0;
+    int i;
+    char c;
 
-    if (args) {
-        n = sscanf(args, "%d", &tinterlace->mode);
+    tinterlace->mode = MODE_MERGE;
 
-        if (n != 1 || tinterlace->mode < 0 || tinterlace->mode > 5) {
-            av_log(ctx, AV_LOG_ERROR,
-                   "Invalid mode '%s', use an integer between 0 and 5\n", args);
-            return AVERROR(EINVAL);
+    if (args) {
+        if (sscanf(args, "%d%c", (int *)&tinterlace->mode, &c) == 1) {
+            if (tinterlace->mode > 6) {
+                av_log(ctx, AV_LOG_ERROR,
+                       "Invalid mode '%s', use an integer between 0 and 6\n", args);
+                return AVERROR(EINVAL);
+            }
+
+            av_log(ctx, AV_LOG_WARNING,
+                   "Using numeric constant is deprecated, use symbolic values\n");
+        } else {
+            for (i = 0; tinterlace_mode_str[i]; i++) {
+                if (!strcmp(tinterlace_mode_str[i], args)) {
+                    tinterlace->mode = i;
+                    break;
+                }
+            }
+            if (!tinterlace_mode_str[i]) {
+                av_log(ctx, AV_LOG_ERROR, "Invalid argument '%s'\n", args);
+                return AVERROR(EINVAL);
+            }
         }
     }
 
@@ -82,8 +119,8 @@ static av_cold void uninit(AVFilterContext *ctx)
 {
     TInterlaceContext *tinterlace = ctx->priv;
 
-    if (tinterlace->cur ) avfilter_unref_buffer(tinterlace->cur );
-    if (tinterlace->next) avfilter_unref_buffer(tinterlace->next);
+    if (tinterlace->cur ) avfilter_unref_bufferp(&tinterlace->cur );
+    if (tinterlace->next) avfilter_unref_bufferp(&tinterlace->next);
 
     av_freep(&tinterlace->black_data[0]);
 }
@@ -97,10 +134,10 @@ static int config_out_props(AVFilterLink *outlink)
 
     tinterlace->vsub = desc->log2_chroma_h;
     outlink->w = inlink->w;
-    outlink->h = tinterlace->mode == 0 || tinterlace->mode == 3 ?
+    outlink->h = tinterlace->mode == MODE_MERGE || tinterlace->mode == MODE_PAD ?
         inlink->h*2 : inlink->h;
 
-    if (tinterlace->mode == 3) {
+    if (tinterlace->mode == MODE_PAD) {
         uint8_t black[4] = { 16, 128, 128, 16 };
         int i, ret;
         if (ff_fmt_is_in(outlink->format, full_scale_yuvj_pix_fmts))
@@ -117,8 +154,8 @@ static int config_out_props(AVFilterLink *outlink)
                    tinterlace->black_linesize[i] * h);
         }
     }
-    av_log(ctx, AV_LOG_INFO, "mode:%d h:%d -> h:%d\n",
-           tinterlace->mode, inlink->h, outlink->h);
+    av_log(ctx, AV_LOG_INFO, "mode:%s h:%d -> h:%d\n",
+           tinterlace_mode_str[tinterlace->mode], inlink->h, outlink->h);
 
     return 0;
 }
@@ -131,7 +168,7 @@ static int config_out_props(AVFilterLink *outlink)
  * Copy picture field from src to dst.
  *
  * @param src_field copy from upper, lower field or both
- * @param interleave leave a padding line between each copied field
+ * @param interleave leave a padding line between each copied line
  * @param dst_field copy to upper or lower field,
  *        only meaningful when interleave is selected
  */
@@ -165,8 +202,7 @@ static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
     AVFilterContext *ctx = inlink->dst;
     TInterlaceContext *tinterlace = ctx->priv;
 
-    if (tinterlace->cur)
-        avfilter_unref_buffer(tinterlace->cur);
+    avfilter_unref_buffer(tinterlace->cur);
     tinterlace->cur  = tinterlace->next;
     tinterlace->next = picref;
 }
@@ -186,9 +222,9 @@ static void end_frame(AVFilterLink *inlink)
         return;
 
     switch (tinterlace->mode) {
-    case 0: /* move the odd frame into the upper field of the new image, even into
+    case MODE_MERGE: /* move the odd frame into the upper field of the new image, even into
              * the lower field, generating a double-height video at half framerate */
-        out = avfilter_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+        out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
         avfilter_copy_buffer_ref_props(out, cur);
         out->video->h = outlink->h;
         out->video->interlaced = 1;
@@ -204,20 +240,18 @@ static void end_frame(AVFilterLink *inlink)
                            next->data, next->linesize,
                            inlink->format, inlink->w, inlink->h,
                            FIELD_UPPER_AND_LOWER, 1, FIELD_LOWER);
-        avfilter_unref_buffer(tinterlace->next);
-        tinterlace->next = NULL;
+        avfilter_unref_bufferp(&tinterlace->next);
         break;
 
-    case 1: /* only output even frames, odd  frames are dropped; height unchanged, half framerate */
-    case 2: /* only output odd  frames, even frames are dropped; height unchanged, half framerate */
-        out = avfilter_ref_buffer(tinterlace->mode == 2 ? cur : next, AV_PERM_READ);
-        avfilter_unref_buffer(tinterlace->next);
-        tinterlace->next = NULL;
+    case MODE_DROP_ODD:  /* only output even frames, odd  frames are dropped; height unchanged, half framerate */
+    case MODE_DROP_EVEN: /* only output odd  frames, even frames are dropped; height unchanged, half framerate */
+        out = avfilter_ref_buffer(tinterlace->mode == MODE_DROP_EVEN ? cur : next, AV_PERM_READ);
+        avfilter_unref_bufferp(&tinterlace->next);
         break;
 
-    case 3: /* expand each frame to double height, but pad alternate
-             * lines with black; framerate unchanged */
-        out = avfilter_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    case MODE_PAD: /* expand each frame to double height, but pad alternate
+                    * lines with black; framerate unchanged */
+        out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
         avfilter_copy_buffer_ref_props(out, cur);
         out->video->h = outlink->h;
 
@@ -236,10 +270,10 @@ static void end_frame(AVFilterLink *inlink)
 
         /* interleave upper/lower lines from odd frames with lower/upper lines from even frames,
          * halving the frame rate and preserving image height */
-    case 4: /* top    field first */
-    case 5: /* bottom field first */
-        tff = tinterlace->mode == 4;
-        out = avfilter_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    case MODE_INTERLEAVE_TOP:    /* top    field first */
+    case MODE_INTERLEAVE_BOTTOM: /* bottom field first */
+        tff = tinterlace->mode == MODE_INTERLEAVE_TOP;
+        out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
         avfilter_copy_buffer_ref_props(out, cur);
         out->video->interlaced = 1;
         out->video->top_field_first = tff;
@@ -254,14 +288,39 @@ static void end_frame(AVFilterLink *inlink)
                            next->data, next->linesize,
                            inlink->format, inlink->w, inlink->h,
                            tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER);
-        avfilter_unref_buffer(tinterlace->next);
-        tinterlace->next = NULL;
+        avfilter_unref_bufferp(&tinterlace->next);
+        break;
+    case MODE_INTERLACEX2: /* re-interlace preserving image height, double frame rate */
+        /* output current frame first */
+        out = avfilter_ref_buffer(cur, AV_PERM_READ);
+        out->video->interlaced = 1;
+
+        ff_start_frame(outlink, out);
+        ff_draw_slice(outlink, 0, outlink->h, 1);
+        ff_end_frame(outlink);
+
+        /* output mix of current and next frame */
+        tff = next->video->top_field_first;
+        out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+        avfilter_copy_buffer_ref_props(out, next);
+        out->video->interlaced = 1;
+
+        /* write current frame second field lines into the second field of the new frame */
+        copy_picture_field(out->data, out->linesize,
+                           cur->data, cur->linesize,
+                           inlink->format, inlink->w, inlink->h,
+                           tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER);
+        /* write next frame first field lines into the first field of the new frame */
+        copy_picture_field(out->data, out->linesize,
+                           next->data, next->linesize,
+                           inlink->format, inlink->w, inlink->h,
+                           tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER);
         break;
     }
 
-    avfilter_start_frame(outlink, out);
-    avfilter_draw_slice(outlink, 0, outlink->h, 1);
-    avfilter_end_frame(outlink);
+    ff_start_frame(outlink, out);
+    ff_draw_slice(outlink, 0, outlink->h, 1);
+    ff_end_frame(outlink);
 
     tinterlace->frame++;
 }
@@ -272,12 +331,12 @@ static int poll_frame(AVFilterLink *outlink)
     AVFilterLink *inlink = outlink->src->inputs[0];
     int ret, val;
 
-    val = avfilter_poll_frame(inlink);
+    val = ff_poll_frame(inlink);
 
     if (val == 1 && !tinterlace->next) {
-        if ((ret = avfilter_request_frame(inlink)) < 0)
+        if ((ret = ff_request_frame(inlink)) < 0)
             return ret;
-        val = avfilter_poll_frame(inlink);
+        val = ff_poll_frame(inlink);
     }
     assert(tinterlace->next);
 
@@ -292,7 +351,7 @@ static int request_frame(AVFilterLink *outlink)
     do {
         int ret;
 
-        if ((ret = avfilter_request_frame(inlink)) < 0)
+        if ((ret = ff_request_frame(inlink)) < 0)
             return ret;
     } while (!tinterlace->cur);