MythTV  0.26-pre
filter_fieldorder.c
Go to the documentation of this file.
00001 /*
00002  * Field-order deinterlacer
00003  *
00004  * Written by Paul Gardiner (mythtv@glidos.net), based on overal
00005  * structure of yadif deinterlacer.
00006  */
00007 #include <stdlib.h>
00008 #include <stdio.h>
00009 
00010 #include "config.h"
00011 #if HAVE_STDINT_H
00012 #include <stdint.h>
00013 #endif
00014 #include <inttypes.h>
00015 
00016 #include <string.h>
00017 #include <math.h>
00018 
00019 #include "filter.h"
00020 #include "frame.h"
00021 
00022 #define NREFS 2
00023 #define NCHANS 3
00024 
00025 typedef struct ThisFilter
00026 {
00027     VideoFilter vf;
00028 
00029     long long last_framenr;
00030 
00031     uint8_t *ref[NREFS + 1][NCHANS];
00032     int stride[NCHANS];
00033     int8_t got_frames[NREFS + 1];
00034 
00035     int width;
00036     int height;
00037 
00038     TF_STRUCT;
00039 } ThisFilter;
00040 
00041 
00042 static void AllocFilter(ThisFilter* filter, int width, int height)
00043 {
00044     int i, j;
00045     if ((width != filter->width) || height != filter->height)
00046     {
00047         for (i = 0; i < NCHANS * NREFS; i++)
00048         {
00049             uint8_t **p = &filter->ref[i / NCHANS][i % NCHANS];
00050             if (*p) free(*p);
00051             *p = NULL;
00052         }
00053         for (i = 0; i < NCHANS; i++)
00054         {
00055             int is_chroma = !!i;
00056             int w = ((width   + 31) & (~31)) >> is_chroma;
00057             int h = ((height  + 31) & (~31)) >> is_chroma;
00058 
00059             filter->stride[i] = w;
00060             for (j = 0; j < NREFS; j++) 
00061             {
00062                 filter->ref[j][i] =
00063                     (uint8_t*)calloc(w * h * sizeof(uint8_t), 1);
00064             }
00065         }
00066         filter->width  = width;
00067         filter->height = height;
00068         memset(filter->got_frames, 0, sizeof(filter->got_frames));
00069     }
00070 }
00071 
00072 static inline void * memcpy_pic(void * dst, const void * src,
00073                                 int bytesPerLine, int height,
00074                                 int dstStride, int srcStride)
00075 {
00076     int i;
00077     void *retval = dst;
00078 
00079     if (dstStride == srcStride)
00080     {
00081         if (srcStride < 0)
00082         {
00083             src = (const uint8_t*)src + (height - 1) * srcStride;
00084             dst = (uint8_t*)dst + (height - 1) * dstStride;
00085             srcStride = -srcStride;
00086         }
00087         memcpy(dst, src, srcStride * height);
00088     }
00089     else
00090     {
00091         for (i = 0; i < height; i++)
00092         {
00093             memcpy(dst, src, bytesPerLine);
00094             src = (const uint8_t*)src + srcStride;
00095             dst = (uint8_t*)dst + dstStride;
00096         }
00097     }
00098     return retval;
00099 }
00100 
00101 static void store_ref(struct ThisFilter *p, uint8_t *src, int src_offsets[3],
00102                       int src_stride[3], int width, int height)
00103 {
00104     int i;
00105 
00106     memcpy (p->ref[NREFS], p->ref[0], sizeof(uint8_t *) * NCHANS);
00107     memmove(p->ref[0], p->ref[1], sizeof(uint8_t *) * NREFS * NCHANS);
00108     memcpy (&p->got_frames[NREFS], &p->got_frames[0], sizeof(uint8_t));
00109     memmove(&p->got_frames[0], &p->got_frames[1], sizeof(uint8_t) * NREFS);
00110 
00111     for (i = 0; i < NCHANS; i++)
00112     {
00113         int is_chroma = !!i;
00114         memcpy_pic(p->ref[NREFS-1][i], src + src_offsets[i],
00115                    width >> is_chroma, height >> is_chroma,
00116                    p->stride[i], src_stride[i]);
00117     }
00118     p->got_frames[NREFS - 1] = 1;
00119 }
00120 
00121 static void filter_func(struct ThisFilter *p, uint8_t *dst,
00122                         int dst_offsets[3], int dst_stride[3], int width,
00123                         int height, int parity, int tff, int dirty)
00124 {
00125     int i, y;
00126     uint8_t nr_p, nr_c;
00127     nr_c = NREFS - 1;
00128     nr_p = p->got_frames[NREFS - 2] ? (NREFS - 2) : nr_c;
00129 
00130     for (i = 0; i < NCHANS; i++)
00131     {
00132         int is_chroma = !!i;
00133         int w    = width  >> is_chroma;
00134         int h    = height >> is_chroma;
00135         int refs = p->stride[i];
00136 
00137         for (y = 0; y < h; y++)
00138         {
00139             int do_copy = dirty;
00140             uint8_t *dst2 = dst + dst_offsets[i] + y * dst_stride[i];
00141             uint8_t *src  = &p->ref[nr_c][i][y * refs];
00142             int     field = parity ^ tff;
00143             if (((y ^ (1 - field)) & 1) && !parity)
00144             {
00145                 src = &p->ref[nr_p][i][y * refs];
00146                 do_copy = 1;
00147             }
00148             if (do_copy)
00149                 memcpy(dst2, src, w);
00150         }
00151     }
00152 }
00153 
00154 static int FieldorderDeint (VideoFilter * f, VideoFrame * frame, int field)
00155 {
00156     ThisFilter *filter = (ThisFilter *) f;
00157     TF_VARS;
00158 
00159     AllocFilter(filter, frame->width, frame->height);
00160 
00161     int dirty = 1;
00162     if (filter->last_framenr != frame->frameNumber)
00163     {
00164         if (filter->last_framenr != (frame->frameNumber - 1))
00165         {
00166             memset(filter->got_frames, 0, sizeof(filter->got_frames));
00167         }
00168         store_ref(filter, frame->buf,  frame->offsets,
00169                   frame->pitches, frame->width, frame->height);
00170         dirty = 0;
00171     }
00172 
00173     filter_func(
00174         filter, frame->buf, frame->offsets, frame->pitches,
00175         frame->width, frame->height, field, frame->top_field_first,
00176         dirty);
00177 
00178     filter->last_framenr = frame->frameNumber;
00179 
00180     return 0;
00181 }
00182 
00183 
00184 static void CleanupFieldorderDeintFilter(VideoFilter * filter)
00185 {
00186     int i;
00187     ThisFilter* f = (ThisFilter*)filter;
00188     for (i = 0; i < NCHANS * NREFS; i++)
00189     {
00190         uint8_t **p= &f->ref[i / NCHANS][i % NCHANS];
00191         if (*p) free(*p);
00192         *p= NULL;
00193     }
00194 }
00195 
00196 static VideoFilter *FieldorderDeintFilter(VideoFrameType inpixfmt,
00197                                           VideoFrameType outpixfmt,
00198                                           int *width, int *height,
00199                                           char *options, int threads)
00200 {
00201     ThisFilter *filter;
00202     (void) height;
00203     (void) options;
00204 
00205     filter = (ThisFilter *) malloc (sizeof(ThisFilter));
00206     if (filter == NULL)
00207     {
00208         fprintf (stderr, "FieldorderDeint: failed to allocate memory for filter.\n");
00209         return NULL;
00210     }
00211 
00212     filter->width = 0;
00213     filter->height = 0;
00214     memset(filter->ref, 0, sizeof(filter->ref));
00215 
00216     AllocFilter(filter, *width, *height);
00217 
00218     filter->vf.filter = &FieldorderDeint;
00219     filter->vf.cleanup = &CleanupFieldorderDeintFilter;
00220     return (VideoFilter *) filter;
00221 }
00222 
00223 static FmtConv FmtList[] =
00224 {
00225     { FMT_YV12, FMT_YV12 } ,
00226     FMT_NULL
00227 };
00228 
00229 ConstFilterInfo filter_table[] =
00230 {
00231     {
00232         filter_init: &FieldorderDeintFilter,
00233         name:       "fieldorderdoubleprocessdeint",
00234         descript:   "avoids synchronisation problems when matching an "
00235                     "interlaced video mode to an interlaced source",
00236         formats:    FmtList,
00237         libname:    NULL
00238     }, FILT_NULL
00239 };
00240 
00241 /* vim: set expandtab tabstop=4 shiftwidth=4: */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends