lavfi/avcodec.c: fix copyright
[ffmpeg.git] / libavfilter / vf_tinterlace.c
index 7ba164e..adf10b1 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;
@@ -62,16 +83,32 @@ static int query_formats(AVFilterContext *ctx)
 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 > 4) {
-            av_log(ctx, AV_LOG_ERROR,
-                   "Invalid mode '%s', use an integer between 0 and 4\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;
 }
@@ -179,14 +215,14 @@ static void end_frame(AVFilterLink *inlink)
     AVFilterBufferRef *cur  = tinterlace->cur;
     AVFilterBufferRef *next = tinterlace->next;
     AVFilterBufferRef *out  = NULL;
-    int field;
+    int field, tff;
 
     /* we need at least two frames */
     if (!tinterlace->cur)
         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);
         avfilter_copy_buffer_ref_props(out, cur);
@@ -204,19 +240,17 @@ 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 */
+    case MODE_PAD: /* 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);
         avfilter_copy_buffer_ref_props(out, cur);
         out->video->h = outlink->h;
@@ -234,25 +268,53 @@ static void end_frame(AVFilterLink *inlink)
                            FIELD_UPPER_AND_LOWER, 1, !field);
         break;
 
-    case 4: /* interleave upper lines from odd frames with lower lines from even frames,
-             * halving the frame rate and preserving image height */
+        /* interleave upper/lower lines from odd frames with lower/upper lines from even frames,
+         * halving the frame rate and preserving image height */
+    case MODE_INTERLEAVE_TOP:    /* top    field first */
+    case MODE_INTERLEAVE_BOTTOM: /* bottom field first */
+        tff = tinterlace->mode == MODE_INTERLEAVE_TOP;
         out = avfilter_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 = 1;
+        out->video->top_field_first = tff;
+
+        /* copy upper/lower field from cur */
+        copy_picture_field(out->data, out->linesize,
+                           cur->data, cur->linesize,
+                           inlink->format, inlink->w, inlink->h,
+                           tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER);
+        /* copy lower/upper field from next */
+        copy_picture_field(out->data, out->linesize,
+                           next->data, next->linesize,
+                           inlink->format, inlink->w, inlink->h,
+                           tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER);
+        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;
+
+        avfilter_start_frame(outlink, out);
+        avfilter_draw_slice(outlink, 0, outlink->h, 1);
+        avfilter_end_frame(outlink);
+
+        /* output mix of current and next frame */
+        tff = next->video->top_field_first;
+        out = avfilter_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+        avfilter_copy_buffer_ref_props(out, next);
+        out->video->interlaced = 1;
 
-        /* copy upper field from cur */
+        /* 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,
-                           FIELD_UPPER, 1, FIELD_UPPER);
-        /* copy lower fields from next */
+                           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,
-                           FIELD_LOWER, 1, FIELD_LOWER);
-        avfilter_unref_buffer(tinterlace->next);
-        tinterlace->next = NULL;
+                           tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER);
         break;
     }