00001
00002
00003
00004
00005
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