MythTV  master
filter_fieldorder.c
Go to the documentation of this file.
1 /*
2  * Field-order deinterlacer
3  *
4  * Written by Paul Gardiner (mythtv@glidos.net), based on overal
5  * structure of yadif deinterlacer.
6  */
7 #include <stdlib.h>
8 #include <stdio.h>
9 
10 #include "config.h"
11 #if HAVE_STDINT_H
12 #include <stdint.h>
13 #endif
14 #include <inttypes.h>
15 
16 #include <string.h>
17 #include <math.h>
18 
19 #include "filter.h"
20 #include "mythframe.h"
21 
22 #define NREFS 2
23 #define NCHANS 3
24 
25 typedef struct ThisFilter
26 {
28 
29  long long last_framenr;
30 
31  uint8_t *ref[NREFS + 1][NCHANS];
32  int stride[NCHANS];
33  int8_t got_frames[NREFS + 1];
34 
35  int width;
36  int height;
37 
38  TF_STRUCT;
39 } ThisFilter;
40 
41 
42 static void AllocFilter(ThisFilter* filter, int width, int height)
43 {
44  if ((width != filter->width) || height != filter->height)
45  {
46  for (int i = 0; i < NCHANS * NREFS; i++)
47  {
48  uint8_t **p = &filter->ref[i / NCHANS][i % NCHANS];
49  if (*p) free(*p);
50  *p = NULL;
51  }
52  for (int i = 0; i < NCHANS; i++)
53  {
54  int is_chroma = !!i;
55  int w = ((width + 31) & (~31)) >> is_chroma;
56  int h = ((height + 31) & (~31)) >> is_chroma;
57 
58  filter->stride[i] = w;
59  for (int j = 0; j < NREFS; j++)
60  {
61  filter->ref[j][i] =
62  (uint8_t*)calloc(w * h * sizeof(uint8_t), 1);
63  }
64  }
65  filter->width = width;
66  filter->height = height;
67  memset(filter->got_frames, 0, sizeof(filter->got_frames));
68  }
69 }
70 
71 static inline void * memcpy_pic(void * dst, const void * src,
72  int bytesPerLine, int height,
73  int dstStride, int srcStride)
74 {
75  void *retval = dst;
76 
77  if (dstStride == srcStride)
78  {
79  if (srcStride < 0)
80  {
81  src = (const uint8_t*)src + (height - 1) * srcStride;
82  dst = (uint8_t*)dst + (height - 1) * dstStride;
83  srcStride = -srcStride;
84  }
85  memcpy(dst, src, srcStride * height);
86  }
87  else
88  {
89  for (int i = 0; i < height; i++)
90  {
91  memcpy(dst, src, bytesPerLine);
92  src = (const uint8_t*)src + srcStride;
93  dst = (uint8_t*)dst + dstStride;
94  }
95  }
96  return retval;
97 }
98 
99 static void store_ref(struct ThisFilter *p, uint8_t *src, int src_offsets[3],
100  int src_stride[3], int width, int height)
101 {
102  int i;
103 
104  memcpy (p->ref[NREFS], p->ref[0], sizeof(uint8_t *) * NCHANS);
105  memmove(p->ref[0], p->ref[1], sizeof(uint8_t *) * NREFS * NCHANS);
106  memcpy (&p->got_frames[NREFS], &p->got_frames[0], sizeof(uint8_t));
107  memmove(&p->got_frames[0], &p->got_frames[1], sizeof(uint8_t) * NREFS);
108 
109  for (i = 0; i < NCHANS; i++)
110  {
111  int is_chroma = !!i;
112  memcpy_pic(p->ref[NREFS-1][i], src + src_offsets[i],
113  width >> is_chroma, height >> is_chroma,
114  p->stride[i], src_stride[i]);
115  }
116  p->got_frames[NREFS - 1] = 1;
117 }
118 
119 static void filter_func(struct ThisFilter *p, uint8_t *dst,
120  int dst_offsets[3], const int dst_stride[3], int width,
121  int height, int parity, int tff, int dirty)
122 {
123  int i, y;
124  uint8_t nr_p, nr_c;
125  nr_c = NREFS - 1;
126  nr_p = p->got_frames[NREFS - 2] ? (NREFS - 2) : nr_c;
127 
128  for (i = 0; i < NCHANS; i++)
129  {
130  int is_chroma = !!i;
131  int w = width >> is_chroma;
132  int h = height >> is_chroma;
133  int refs = p->stride[i];
134 
135  for (y = 0; y < h; y++)
136  {
137  int do_copy = dirty;
138  uint8_t *dst2 = dst + dst_offsets[i] + y * dst_stride[i];
139  uint8_t *src = &p->ref[nr_c][i][y * refs];
140  int field = parity ^ tff;
141  if (((y ^ (1 - field)) & 1) && !parity)
142  {
143  src = &p->ref[nr_p][i][y * refs];
144  do_copy = 1;
145  }
146  if (do_copy)
147  memcpy(dst2, src, w);
148  }
149  }
150 }
151 
152 static int FieldorderDeint (VideoFilter * f, VideoFrame * frame, int field)
153 {
154  ThisFilter *filter = (ThisFilter *) f;
155 
156  AllocFilter(filter, frame->width, frame->height);
157 
158  int dirty = 1;
159  if (filter->last_framenr != frame->frameNumber)
160  {
161  if (filter->last_framenr != (frame->frameNumber - 1))
162  {
163  memset(filter->got_frames, 0, sizeof(filter->got_frames));
164  }
165  store_ref(filter, frame->buf, frame->offsets,
166  frame->pitches, frame->width, frame->height);
167  dirty = 0;
168  }
169 
170  filter_func(
171  filter, frame->buf, frame->offsets, frame->pitches,
172  frame->width, frame->height, field, frame->top_field_first,
173  dirty);
174 
175  filter->last_framenr = frame->frameNumber;
176 
177  return 0;
178 }
179 
180 
182 {
183  int i;
184  ThisFilter* f = (ThisFilter*)filter;
185  for (i = 0; i < NCHANS * NREFS; i++)
186  {
187  uint8_t **p= &f->ref[i / NCHANS][i % NCHANS];
188  if (*p) free(*p);
189  *p= NULL;
190  }
191 }
192 
194  VideoFrameType outpixfmt,
195  const int *width, const int *height,
196  const char *options, int threads)
197 {
198  ThisFilter *filter;
199  (void) inpixfmt;
200  (void) outpixfmt;
201  (void) options;
202  (void) threads;
203 
204  filter = (ThisFilter *) malloc (sizeof(ThisFilter));
205  if (filter == NULL)
206  {
207  fprintf (stderr, "FieldorderDeint: failed to allocate memory for filter.\n");
208  return NULL;
209  }
210 
211  filter->width = 0;
212  filter->height = 0;
213  memset(filter->ref, 0, sizeof(filter->ref));
214 
215  AllocFilter(filter, *width, *height);
216 
217  filter->vf.filter = &FieldorderDeint;
219  return (VideoFilter *) filter;
220 }
221 
222 static FmtConv FmtList[] =
223 {
224  { FMT_YV12, FMT_YV12 } ,
225  FMT_NULL
226 };
227 
229 {
230  {
232  .name= (char*)"fieldorderdoubleprocessdeint",
233  .descript= (char*)"avoids synchronisation problems when matching an "
234  "interlaced video mode to an interlaced source",
235  .formats= FmtList,
236  .libname= NULL
237  }, FILT_NULL
238 };
239 
240 /* vim: set expandtab tabstop=4 shiftwidth=4: */
int pitches[3]
Y, U, & V pitches.
Definition: mythframe.h:63
int(* filter)(struct VideoFilter_ *, VideoFrame *, int)
Definition: filter.h:37
init_filter filter_init
Definition: filter.h:28
stderr
Definition: ttvdb.py:1426
#define NCHANS
static VideoFilter * FieldorderDeintFilter(VideoFrameType inpixfmt, VideoFrameType outpixfmt, const int *width, const int *height, const char *options, int threads)
#define NULL
Definition: H264Parser.h:62
void(* cleanup)(struct VideoFilter_ *)
Definition: filter.h:38
enum FrameType_ VideoFrameType
static void store_ref(struct ThisFilter *p, uint8_t *src, int src_offsets[3], int src_stride[3], int width, int height)
int offsets[3]
Y, U, & V offsets.
Definition: mythframe.h:64
static FmtConv FmtList[]
VideoFilter vf
Definition: filter_adjust.c:36
int height
Definition: mythframe.h:42
long long last_framenr
long long frameNumber
Definition: mythframe.h:48
static int FieldorderDeint(VideoFilter *f, VideoFrame *frame, int field)
int top_field_first
1 if top field is first.
Definition: mythframe.h:58
int stride[NCHANS]
static void filter_func(struct ThisFilter *p, uint8_t *dst, int dst_offsets[3], const int dst_stride[3], int width, int height, int parity, int tff, int dirty)
struct ThisFilter ThisFilter
#define FMT_NULL
Definition: filter.h:20
static void AllocFilter(ThisFilter *filter, int width, int height)
int8_t got_frames[NREFS+1]
static void * memcpy_pic(void *dst, const void *src, int bytesPerLine, int height, int dstStride, int srcStride)
#define NREFS
static void CleanupFieldorderDeintFilter(VideoFilter *filter)
uint8_t * ref[NREFS+1][NCHANS]
#define FILT_NULL
Definition: filter.h:47
unsigned char * buf
Definition: mythframe.h:39
const FilterInfo filter_table[]