00001
00002
00003
00004
00005 #include <stdlib.h>
00006 #include <stdio.h>
00007
00008 #ifdef HAVE_STDINT_H
00009 #include <stdint.h>
00010 #endif
00011
00012 #include <string.h>
00013
00014 #include "config.h"
00015 #include "filter.h"
00016 #include "frame.h"
00017
00018 #include "pullup.h"
00019
00020 typedef struct ThisFilter
00021 {
00022 VideoFilter vf;
00023
00024 struct pullup_context *context;
00025 int height;
00026 int width;
00027 int progressive_frame_seen;
00028 int interlaced_frame_seen;
00029 int apply_filter;
00030 } ThisFilter;
00031
00032 static void SetupFilter(ThisFilter *vf, int width, int height, int *pitches);
00033
00034 static inline void * memcpy_pic(void * dst, const void * src, int height, int dstStride, int srcStride)
00035 {
00036 void *retval=dst;
00037
00038 if (dstStride == srcStride)
00039 {
00040 memcpy(dst, src, srcStride*height);
00041 }
00042
00043 return retval;
00044 }
00045
00046 static int
00047 IvtcFilter (VideoFilter *vf, VideoFrame *frame, int field)
00048 {
00049 (void)field;
00050 ThisFilter *filter = (ThisFilter *) vf;
00051
00052 if (!frame->interlaced_frame)
00053 {
00054 filter->progressive_frame_seen = 1;
00055 }
00056
00057 if (filter->progressive_frame_seen &&
00058 frame->interlaced_frame)
00059 {
00060 filter->interlaced_frame_seen = 1;
00061 }
00062
00063 if (!frame->interlaced_frame &&
00064 !filter->apply_filter &&
00065 filter->interlaced_frame_seen &&
00066 filter->progressive_frame_seen)
00067 {
00068 fprintf(stderr,"turning on inverse telecine filter");
00069 filter->apply_filter = 1;
00070 }
00071
00072 if (!filter->apply_filter)
00073 return 1;
00074
00075 SetupFilter(filter, frame->width, frame->height, (int*)frame->pitches);
00076
00077 struct pullup_buffer *b;
00078 struct pullup_frame *f;
00079 int ypitch = filter->context->stride[0];
00080 int height = filter->height;
00081 int cpitch = filter->context->stride[1];
00082 int cheight = filter->height >> 1;
00083 int p = frame->top_field_first ^ 1;
00084
00085 struct pullup_context *c = filter->context;
00086 if (c->bpp[0] == 0)
00087 c->bpp[0] = c->bpp[1] = c->bpp[2] = frame->bpp;
00088
00089 b = pullup_get_buffer(c,2);
00090 if (!b)
00091 {
00092 f = pullup_get_frame(c);
00093 pullup_release_frame(f);
00094 return 0;
00095 }
00096
00097 memcpy_pic(b->planes[0], frame->buf + frame->offsets[0],
00098 height, ypitch, ypitch);
00099 memcpy_pic(b->planes[1], frame->buf + frame->offsets[1],
00100 cheight, cpitch, cpitch);
00101 memcpy_pic(b->planes[2], frame->buf + frame->offsets[2],
00102 cheight, cpitch, cpitch);
00103
00104 pullup_submit_field(c, b, p);
00105 pullup_submit_field(c, b, p^1);
00106 if (frame->repeat_pict)
00107 pullup_submit_field(c, b, p);
00108
00109 pullup_release_buffer(b, 2);
00110
00111 f = pullup_get_frame(c);
00112
00113 if (!f)
00114 return 0;
00115
00116
00117 if (f->length < 2)
00118 {
00119 pullup_release_frame(f);
00120 f = pullup_get_frame(c);
00121 if (!f)
00122 return 0;
00123 if (f->length < 2)
00124 {
00125 pullup_release_frame(f);
00126 if (!frame->repeat_pict)
00127 return 0;
00128 f = pullup_get_frame(c);
00129 if (!f)
00130 return 0;
00131 if (f->length < 2)
00132 {
00133 pullup_release_frame(f);
00134 return 0;
00135 }
00136 }
00137 }
00138
00139 if (!f->buffer)
00140 {
00141 pullup_pack_frame(c, f);
00142 }
00143
00144 if (!f->buffer)
00145 return 0;
00146
00147 memcpy_pic(frame->buf + frame->offsets[0], f->buffer->planes[0],
00148 height, ypitch, ypitch);
00149 memcpy_pic(frame->buf + frame->offsets[1], f->buffer->planes[1],
00150 cheight, cpitch, cpitch);
00151 memcpy_pic(frame->buf + frame->offsets[2], f->buffer->planes[2],
00152 cheight, cpitch, cpitch);
00153
00154 pullup_release_frame(f);
00155
00156 return 1;
00157 }
00158
00159 static void
00160 IvtcFilterCleanup( VideoFilter * filter)
00161 {
00162 pullup_free_context((((ThisFilter *)filter)->context));
00163 }
00164
00165 static void SetupFilter(ThisFilter *vf, int width, int height, int *pitches)
00166 {
00167 if (vf->width == width &&
00168 vf->height == height &&
00169 vf->context->stride[0] == pitches[0] &&
00170 vf->context->stride[1] == pitches[1] &&
00171 vf->context->stride[2] == pitches[2])
00172 {
00173 return;
00174 }
00175
00176 vf->width = width;
00177 vf->height = height;
00178
00179 vf->context->w[0] = width;
00180 vf->context->w[1] = width >> 1;
00181 vf->context->w[2] = width >> 1;
00182 vf->context->w[3] = 0;
00183 vf->context->h[0] = height;
00184 vf->context->h[1] = height >> 1;
00185 vf->context->h[2] = height >> 1;
00186 vf->context->h[3] = 0;
00187 vf->context->stride[0] = pitches[0];
00188 vf->context->stride[1] = pitches[1];
00189 vf->context->stride[2] = pitches[2];
00190 vf->context->stride[3] = 0;
00191 }
00192
00193 static VideoFilter *NewIvtcFilter(VideoFrameType inpixfmt,
00194 VideoFrameType outpixfmt,
00195 int *width, int *height, char *options,
00196 int threads)
00197 {
00198 (void) threads;
00199
00200 ThisFilter *filter;
00201
00202 options = NULL;
00203 if (inpixfmt != FMT_YV12)
00204 return NULL;
00205 if (outpixfmt != FMT_YV12)
00206 return NULL;
00207
00208 filter = malloc (sizeof (ThisFilter));
00209
00210 if (filter == NULL)
00211 {
00212 fprintf (stderr, "Ivtc: failed to allocate memory for filter\n");
00213 return NULL;
00214 }
00215
00216 memset(filter, 0, sizeof(ThisFilter));
00217 filter->progressive_frame_seen = 0;
00218 filter->interlaced_frame_seen = 0;
00219 filter->apply_filter = 0;
00220 filter->context = pullup_alloc_context();
00221 struct pullup_context *c = filter->context;
00222 c->metric_plane = 0;
00223 c->strict_breaks = 0;
00224 c->junk_left = c->junk_right = 1;
00225 c->junk_top = c->junk_bottom = 4;
00226 c->verbose = 0;
00227 c->format = PULLUP_FMT_Y;
00228 c->nplanes = 4;
00229 pullup_preinit_context(c);
00230 c->bpp[0] = c->bpp[1] = c->bpp[2] = 0;
00231 c->background[1] = c->background[2] = 128;
00232
00233 int pitches[3] = { *width, *width >> 1, *width >> 1 };
00234 SetupFilter(filter, *width, *height, pitches);
00235
00236 #if HAVE_MMX
00237 c->cpu |= PULLUP_CPU_MMX;
00238 #endif
00239
00240 pullup_init_context(c);
00241 filter->vf.filter = &IvtcFilter;
00242 filter->vf.cleanup = &IvtcFilterCleanup;
00243 return (VideoFilter *) filter;
00244 }
00245
00246 static FmtConv FmtList[] =
00247 {
00248 { FMT_YV12, FMT_YV12 },
00249 FMT_NULL
00250 };
00251
00252 ConstFilterInfo filter_table[] =
00253 {
00254 {
00255 filter_init: &NewIvtcFilter,
00256 name: "ivtc",
00257 descript: "inverse telecine filter",
00258 formats: FmtList,
00259 libname: NULL
00260 },
00261 FILT_NULL
00262 };
00263