Browse code

Implement interlaced scaling. Fixes issue2632 if interl=1 is used or the automatic interlace detection is enabled and works. This has the advantage compared to the patch in issue2632 that it causes no speed loss and it also works when scaling is used. The disadvantage is that interlacing autodetection does not yet work very well it seems. This is the same method mplayer uses

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>

Michael Niedermayer authored on 2011/03/28 07:09:58
Showing 1 changed files
... ...
@@ -25,10 +25,12 @@
25 25
 
26 26
 #include "avfilter.h"
27 27
 #include "libavutil/pixdesc.h"
28
+#include "libavutil/avassert.h"
28 29
 #include "libswscale/swscale.h"
29 30
 
30 31
 typedef struct {
31 32
     struct SwsContext *sws;     ///< software scaler context
33
+    struct SwsContext *isws[2]; ///< software scaler context for interlaced material
32 34
 
33 35
     /**
34 36
      * New dimensions. Special values are:
... ...
@@ -41,6 +43,7 @@ typedef struct {
41 41
     int hsub, vsub;             ///< chroma subsampling
42 42
     int slice_y;                ///< top of current output slice
43 43
     int input_is_pal;           ///< set to 1 if the input format is paletted
44
+    int interlaced;
44 45
 } ScaleContext;
45 46
 
46 47
 static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
... ...
@@ -53,6 +56,10 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
53 53
         sscanf(args, "%d:%d", &scale->w, &scale->h);
54 54
         p = strstr(args,"flags=");
55 55
         if (p) scale->flags = strtoul(p+6, NULL, 0);
56
+        if(strstr(args,"interl=1")){
57
+            scale->interlaced=1;
58
+        }else if(strstr(args,"interl=-1"))
59
+            scale->interlaced=-1;
56 60
     }
57 61
 
58 62
     /* sanity check params */
... ...
@@ -70,6 +77,8 @@ static av_cold void uninit(AVFilterContext *ctx)
70 70
 {
71 71
     ScaleContext *scale = ctx->priv;
72 72
     sws_freeContext(scale->sws);
73
+    sws_freeContext(scale->isws[0]);
74
+    sws_freeContext(scale->isws[1]);
73 75
     scale->sws = NULL;
74 76
 }
75 77
 
... ...
@@ -138,6 +147,12 @@ static int config_props(AVFilterLink *outlink)
138 138
     scale->sws = sws_getContext(inlink ->w, inlink ->h, inlink ->format,
139 139
                                 outlink->w, outlink->h, outlink->format,
140 140
                                 scale->flags, NULL, NULL, NULL);
141
+    scale->isws[0] = sws_getContext(inlink ->w, inlink ->h/2, inlink ->format,
142
+                                    outlink->w, outlink->h/2, outlink->format,
143
+                                    scale->flags, NULL, NULL, NULL);
144
+    scale->isws[1] = sws_getContext(inlink ->w, inlink ->h/2, inlink ->format,
145
+                                    outlink->w, outlink->h/2, outlink->format,
146
+                                    scale->flags, NULL, NULL, NULL);
141 147
     if (!scale->sws)
142 148
         return AVERROR(EINVAL);
143 149
 
... ...
@@ -169,26 +184,46 @@ static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
169 169
     avfilter_start_frame(outlink, avfilter_ref_buffer(outpicref, ~0));
170 170
 }
171 171
 
172
+static int scale_slice(AVFilterLink *link, struct SwsContext *sws, int y, int h, int mul, int field)
173
+{
174
+    ScaleContext *scale = link->dst->priv;
175
+    AVFilterBufferRef *cur_pic = link->cur_buf;
176
+    AVFilterBufferRef *out_buf = link->dst->outputs[0]->out_buf;
177
+    const uint8_t *in[4], *out[4];
178
+    int in_stride[4],out_stride[4];
179
+    int i;
180
+
181
+    for(i=0; i<4; i++){
182
+        int vsub= ((i+1)&2) ? scale->vsub : 0;
183
+         in_stride[i] = cur_pic->linesize[i] * mul;
184
+        out_stride[i] = out_buf->linesize[i] * mul;
185
+         in[i] = cur_pic->data[i] + ((y>>vsub)+field) * cur_pic->linesize[i];
186
+        out[i] = out_buf->data[i] +            field  * out_buf->linesize[i];
187
+    }
188
+    if(scale->input_is_pal){
189
+         in[1] = cur_pic->data[1];
190
+        out[1] = out_buf->data[1];
191
+    }
192
+
193
+    return sws_scale(sws, in, in_stride, y/mul, h,
194
+                         out,out_stride);
195
+}
196
+
172 197
 static void draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
173 198
 {
174 199
     ScaleContext *scale = link->dst->priv;
175 200
     int out_h;
176
-    AVFilterBufferRef *cur_pic = link->cur_buf;
177
-    const uint8_t *data[4];
178 201
 
179 202
     if (scale->slice_y == 0 && slice_dir == -1)
180 203
         scale->slice_y = link->dst->outputs[0]->h;
181 204
 
182
-    data[0] = cur_pic->data[0] +  y               * cur_pic->linesize[0];
183
-    data[1] = scale->input_is_pal ?
184
-              cur_pic->data[1] :
185
-              cur_pic->data[1] + (y>>scale->vsub) * cur_pic->linesize[1];
186
-    data[2] = cur_pic->data[2] + (y>>scale->vsub) * cur_pic->linesize[2];
187
-    data[3] = cur_pic->data[3] +  y               * cur_pic->linesize[3];
188
-
189
-    out_h = sws_scale(scale->sws, data, cur_pic->linesize, y, h,
190
-                      link->dst->outputs[0]->out_buf->data,
191
-                      link->dst->outputs[0]->out_buf->linesize);
205
+    if(scale->interlaced>0 || (scale->interlaced<0 && link->cur_buf->video->interlaced)){
206
+        av_assert0(y%4 == 0);
207
+        out_h = scale_slice(link, scale->isws[0], y, (h+1)/2, 2, 0);
208
+        out_h+= scale_slice(link, scale->isws[1], y,  h   /2, 2, 1);
209
+    }else{
210
+        out_h = scale_slice(link, scale->sws, y, h, 1, 0);
211
+    }
192 212
 
193 213
     if (slice_dir == -1)
194 214
         scale->slice_y -= out_h;