2010-01-30 16:57:40 +00:00
|
|
|
/*
|
|
|
|
* This file is part of MPlayer.
|
|
|
|
*
|
|
|
|
* MPlayer is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* MPlayer is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*/
|
|
|
|
|
2004-04-17 17:08:31 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
2005-11-18 14:39:25 +00:00
|
|
|
#include "config.h"
|
2013-08-06 20:41:30 +00:00
|
|
|
#include "mpvcore/mp_msg.h"
|
|
|
|
#include "mpvcore/cpudetect.h"
|
2006-11-29 15:02:45 +00:00
|
|
|
#include "libavutil/common.h"
|
2012-11-09 00:06:43 +00:00
|
|
|
#include "compat/mpbswap.h"
|
2004-04-17 17:08:31 +00:00
|
|
|
|
2012-11-09 00:06:43 +00:00
|
|
|
#include "video/img_format.h"
|
|
|
|
#include "video/mp_image.h"
|
2004-04-17 17:08:31 +00:00
|
|
|
#include "vf.h"
|
|
|
|
|
2012-11-09 00:06:43 +00:00
|
|
|
#include "video/memcpy_pic.h"
|
2004-04-17 17:08:31 +00:00
|
|
|
|
2007-12-02 14:57:15 +00:00
|
|
|
const vf_info_t vf_info_divtc;
|
2004-04-17 17:08:31 +00:00
|
|
|
|
|
|
|
struct vf_priv_s
|
|
|
|
{
|
|
|
|
int deghost, pass, phase, window, fcount, bcount, frameno, misscount,
|
|
|
|
ocount, sum[5];
|
|
|
|
double threshold;
|
|
|
|
FILE *file;
|
2011-05-30 21:16:37 +00:00
|
|
|
int8_t *bdata;
|
2004-04-17 17:08:31 +00:00
|
|
|
unsigned int *csdata;
|
|
|
|
int *history;
|
vf_*: fix pts values passed to the next filter
Many video filters failed to calculate or even just pass through pts
values for their output frames. Fix this, and also make the two
remaining filters that called vf_next_put_image() twice for the same
input frame (vf_softpulldown, vf_telecine) use vf_queue_frame() so
that e.g. framestepping properly sees both frames.
Changed filters: vf_bmovl, vf_detc, vf_divtc, vf_filmdint, vf_ivtc,
vf_lavc, vf_phase, vf_pullup, vf_softpulldown, vf_telecine, vf_tile,
vf_tinterlace.
2011-04-23 16:56:47 +00:00
|
|
|
struct vf_detc_pts_buf ptsbuf;
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
struct mp_image *buffer;
|
2004-04-17 17:08:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* diff_MMX and diff_C stolen from vf_decimate.c
|
|
|
|
*/
|
|
|
|
|
2009-03-13 17:12:40 +00:00
|
|
|
#if HAVE_MMX && HAVE_EBX_AVAILABLE
|
2004-04-17 17:08:31 +00:00
|
|
|
static int diff_MMX(unsigned char *old, unsigned char *new, int os, int ns)
|
|
|
|
{
|
|
|
|
volatile short out[4];
|
2008-10-16 18:59:27 +00:00
|
|
|
__asm__ (
|
2004-04-17 17:08:31 +00:00
|
|
|
"movl $8, %%ecx \n\t"
|
|
|
|
"pxor %%mm4, %%mm4 \n\t"
|
|
|
|
"pxor %%mm7, %%mm7 \n\t"
|
|
|
|
|
configure: remove check for .align semantics
The check determined whether the argument for .align is in bytes, or
log2(bytes). Apparently it's always in bytes for ELF i386 systems, and
this check is used for x86 inline assembler only. Even if this
assumption should be wrong, it likely won't cause much damage: the
existing code uses it only in the form ".align 4", which means in the
worst case it will try to align to 16 bytes, which doesn't cause any
problems (unless the object file format does not support such a high
alignment).
Update the filters that used this.
Quoting the GNU as manual:
For other systems, including ppc, i386 using a.out format, arm and
strongarm, it is the number of low-order zero bits the location counter
must have after advancement. For example `.align 3' advances the
location counter until it a multiple of 8. If the location counter is
already a multiple of 8, no change is needed.
2013-01-13 13:10:43 +00:00
|
|
|
".align 4 \n\t"
|
2004-04-17 17:08:31 +00:00
|
|
|
"1: \n\t"
|
|
|
|
|
2004-10-21 11:55:20 +00:00
|
|
|
"movq (%%"REG_S"), %%mm0 \n\t"
|
|
|
|
"movq (%%"REG_S"), %%mm2 \n\t"
|
|
|
|
"add %%"REG_a", %%"REG_S" \n\t"
|
|
|
|
"movq (%%"REG_D"), %%mm1 \n\t"
|
|
|
|
"add %%"REG_b", %%"REG_D" \n\t"
|
2004-04-17 17:08:31 +00:00
|
|
|
"psubusb %%mm1, %%mm2 \n\t"
|
|
|
|
"psubusb %%mm0, %%mm1 \n\t"
|
|
|
|
"movq %%mm2, %%mm0 \n\t"
|
|
|
|
"movq %%mm1, %%mm3 \n\t"
|
|
|
|
"punpcklbw %%mm7, %%mm0 \n\t"
|
|
|
|
"punpcklbw %%mm7, %%mm1 \n\t"
|
|
|
|
"punpckhbw %%mm7, %%mm2 \n\t"
|
|
|
|
"punpckhbw %%mm7, %%mm3 \n\t"
|
|
|
|
"paddw %%mm0, %%mm4 \n\t"
|
|
|
|
"paddw %%mm1, %%mm4 \n\t"
|
|
|
|
"paddw %%mm2, %%mm4 \n\t"
|
|
|
|
"paddw %%mm3, %%mm4 \n\t"
|
|
|
|
|
|
|
|
"decl %%ecx \n\t"
|
|
|
|
"jnz 1b \n\t"
|
2004-10-21 11:55:20 +00:00
|
|
|
"movq %%mm4, (%%"REG_d") \n\t"
|
2004-04-17 17:08:31 +00:00
|
|
|
"emms \n\t"
|
|
|
|
:
|
2004-10-21 11:55:20 +00:00
|
|
|
: "S" (old), "D" (new), "a" ((long)os), "b" ((long)ns), "d" (out)
|
2009-03-13 17:02:15 +00:00
|
|
|
: "%ecx", "memory"
|
2004-04-17 17:08:31 +00:00
|
|
|
);
|
|
|
|
return out[0]+out[1]+out[2]+out[3];
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int diff_C(unsigned char *old, unsigned char *new, int os, int ns)
|
|
|
|
{
|
|
|
|
int x, y, d=0;
|
|
|
|
|
|
|
|
for(y=8; y; y--, new+=ns, old+=os)
|
|
|
|
for(x=8; x; x--)
|
|
|
|
d+=abs(new[x]-old[x]);
|
|
|
|
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int (*diff)(unsigned char *, unsigned char *, int, int);
|
|
|
|
|
|
|
|
static int diff_plane(unsigned char *old, unsigned char *new,
|
|
|
|
int w, int h, int os, int ns, int arg)
|
|
|
|
{
|
|
|
|
int x, y, d, max=0, sum=0, n=0;
|
|
|
|
|
|
|
|
for(y=0; y<h-7; y+=8)
|
|
|
|
{
|
|
|
|
for(x=0; x<w-7; x+=8)
|
|
|
|
{
|
|
|
|
d=diff(old+x+y*os, new+x+y*ns, os, ns);
|
|
|
|
if(d>max) max=d;
|
|
|
|
sum+=d;
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (sum+n*max)/2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
static unsigned int checksum_plane(unsigned char *p, unsigned char *z,
|
|
|
|
int w, int h, int s, int zs, int arg)
|
|
|
|
{
|
|
|
|
unsigned int shift, sum;
|
|
|
|
unsigned char *e;
|
|
|
|
|
|
|
|
for(sum=0; h; h--, p+=s-w)
|
|
|
|
for(e=p+w, shift=32; p<e;)
|
|
|
|
sum^=(*p++)<<(shift=(shift-8)&31);
|
|
|
|
|
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
static unsigned int checksum_plane(unsigned char *p, unsigned char *z,
|
|
|
|
int w, int h, int s, int zs, int arg)
|
|
|
|
{
|
|
|
|
unsigned int shift;
|
|
|
|
uint32_t sum, t;
|
|
|
|
unsigned char *e, *e2;
|
2009-04-25 19:09:54 +00:00
|
|
|
#if HAVE_FAST_64BIT
|
2004-04-17 17:08:31 +00:00
|
|
|
typedef uint64_t wsum_t;
|
|
|
|
#else
|
|
|
|
typedef uint32_t wsum_t;
|
|
|
|
#endif
|
|
|
|
wsum_t wsum;
|
|
|
|
|
|
|
|
for(sum=0; h; h--, p+=s-w)
|
|
|
|
{
|
2011-04-28 07:36:00 +00:00
|
|
|
for(shift=0, e=p+w; (size_t)p&(sizeof(wsum_t)-1) && p<e;)
|
2004-04-17 17:08:31 +00:00
|
|
|
sum^=*p++<<(shift=(shift-8)&31);
|
|
|
|
|
|
|
|
for(wsum=0, e2=e-sizeof(wsum_t)+1; p<e2; p+=sizeof(wsum_t))
|
|
|
|
wsum^=*(wsum_t *)p;
|
|
|
|
|
2009-04-25 19:09:54 +00:00
|
|
|
#if HAVE_FAST_64BIT
|
2004-04-17 17:08:31 +00:00
|
|
|
t=be2me_32((uint32_t)(wsum>>32^wsum));
|
|
|
|
#else
|
|
|
|
t=be2me_32(wsum);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for(sum^=(t<<shift|t>>(32-shift)); p<e;)
|
|
|
|
sum^=*p++<<(shift=(shift-8)&31);
|
|
|
|
}
|
|
|
|
|
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int deghost_plane(unsigned char *d, unsigned char *s,
|
|
|
|
int w, int h, int ds, int ss, int threshold)
|
|
|
|
{
|
|
|
|
int t;
|
|
|
|
unsigned char *e;
|
|
|
|
|
|
|
|
for(; h; h--, s+=ss-w, d+=ds-w)
|
|
|
|
for(e=d+w; d<e; d++, s++)
|
|
|
|
if(abs(*d-*s)>=threshold)
|
|
|
|
*d=(t=(*d<<1)-*s)<0?0:t>255?255:t;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-06-28 11:24:12 +00:00
|
|
|
static int copyop(unsigned char *d, unsigned char *s, int bpl, int h, int dstride, int sstride, int dummy) {
|
|
|
|
memcpy_pic(d, s, bpl, h, dstride, sstride);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-04-17 17:08:31 +00:00
|
|
|
static int imgop(int(*planeop)(unsigned char *, unsigned char *,
|
|
|
|
int, int, int, int, int),
|
|
|
|
mp_image_t *dst, mp_image_t *src, int arg)
|
|
|
|
{
|
2012-12-26 20:24:00 +00:00
|
|
|
int sum = 0;
|
|
|
|
for (int p = 0; p < dst->num_planes; p++) {
|
|
|
|
sum += planeop(dst->planes[p], src ? src->planes[p] : NULL,
|
2013-04-09 22:10:59 +00:00
|
|
|
(dst->w * dst->fmt.bytes[p]) >> dst->fmt.xs[p],
|
|
|
|
dst->plane_h[p], dst->stride[p],
|
|
|
|
src ? src->stride[p] : 0, arg);
|
2012-12-26 20:24:00 +00:00
|
|
|
}
|
|
|
|
return sum;
|
2004-04-17 17:08:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find the phase in which the telecine pattern fits best to the
|
|
|
|
* given 5 frame slice of frame difference measurements.
|
|
|
|
*
|
|
|
|
* If phase1 and phase2 are not negative, only the two specified
|
|
|
|
* phases are tested.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int match(struct vf_priv_s *p, int *diffs,
|
|
|
|
int phase1, int phase2, double *strength)
|
|
|
|
{
|
2008-04-26 13:36:16 +00:00
|
|
|
const int pattern1[]={ -4, 1, 1, 1, 1 },
|
2004-04-17 17:08:31 +00:00
|
|
|
pattern2[]={ -2, -3, 4, 4, -3 }, *pattern;
|
|
|
|
int f, m, n, t[5];
|
|
|
|
|
|
|
|
pattern=p->deghost>0?pattern2:pattern1;
|
|
|
|
|
|
|
|
for(f=0; f<5; f++)
|
|
|
|
{
|
|
|
|
if(phase1<0 || phase2<0 || f==phase1 || f==phase2)
|
|
|
|
{
|
|
|
|
for(n=t[f]=0; n<5; n++)
|
|
|
|
t[f]+=diffs[n]*pattern[(n-f+5)%5];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
t[f]=INT_MIN;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find the best match */
|
|
|
|
for(m=0, n=1; n<5; n++)
|
|
|
|
if(t[n]>t[m]) m=n;
|
|
|
|
|
|
|
|
if(strength)
|
|
|
|
{
|
|
|
|
/* the second best match */
|
|
|
|
for(f=m?0:1, n=f+1; n<5; n++)
|
|
|
|
if(n!=m && t[n]>t[f]) f=n;
|
|
|
|
|
|
|
|
*strength=(t[m]>0?(double)(t[m]-t[f])/t[m]:0.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
static struct mp_image *filter(struct vf_instance *vf, struct mp_image *mpi)
|
2004-04-17 17:08:31 +00:00
|
|
|
{
|
|
|
|
int n, m, f, newphase;
|
|
|
|
struct vf_priv_s *p=vf->priv;
|
|
|
|
unsigned int checksum;
|
|
|
|
double d;
|
|
|
|
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
if (!p->buffer || p->buffer->w != mpi->w || p->buffer->h != mpi->h ||
|
|
|
|
p->buffer->imgfmt != mpi->imgfmt)
|
|
|
|
{
|
|
|
|
mp_image_unrefp(&p->buffer);
|
|
|
|
p->buffer = mp_image_alloc(mpi->imgfmt, mpi->w, mpi->h);
|
|
|
|
talloc_steal(vf, p->buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct mp_image *dmpi = p->buffer;
|
|
|
|
double pts = mpi->pts;
|
2004-04-17 17:08:31 +00:00
|
|
|
|
|
|
|
newphase=p->phase;
|
|
|
|
|
|
|
|
switch(p->pass)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
fprintf(p->file, "%08x %d\n",
|
|
|
|
(unsigned int)imgop((void *)checksum_plane, mpi, 0, 0),
|
|
|
|
p->frameno?imgop(diff_plane, dmpi, mpi, 0):0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
if(p->frameno/5>p->bcount)
|
|
|
|
{
|
|
|
|
mp_msg(MSGT_VFILTER, MSGL_ERR,
|
|
|
|
"\n%s: Log file ends prematurely! "
|
|
|
|
"Switching to one pass mode.\n", vf->info->name);
|
|
|
|
p->pass=0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
checksum=(unsigned int)imgop((void *)checksum_plane, mpi, 0, 0);
|
|
|
|
|
|
|
|
if(checksum!=p->csdata[p->frameno])
|
|
|
|
{
|
|
|
|
for(f=0; f<100; f++)
|
|
|
|
if(p->frameno+f<p->fcount && p->csdata[p->frameno+f]==checksum)
|
|
|
|
break;
|
|
|
|
else if(p->frameno-f>=0 && p->csdata[p->frameno-f]==checksum)
|
|
|
|
{
|
|
|
|
f=-f;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(f<100)
|
|
|
|
{
|
|
|
|
mp_msg(MSGT_VFILTER, MSGL_INFO,
|
|
|
|
"\n%s: Mismatch with pass-1: %+d frame(s).\n",
|
|
|
|
vf->info->name, f);
|
|
|
|
|
|
|
|
p->frameno+=f;
|
|
|
|
p->misscount=0;
|
|
|
|
}
|
|
|
|
else if(p->misscount++>=30)
|
|
|
|
{
|
|
|
|
mp_msg(MSGT_VFILTER, MSGL_ERR,
|
|
|
|
"\n%s: Sync with pass-1 lost! "
|
|
|
|
"Switching to one pass mode.\n", vf->info->name);
|
|
|
|
p->pass=0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
n=(p->frameno)/5;
|
|
|
|
if(n>=p->bcount) n=p->bcount-1;
|
|
|
|
|
|
|
|
newphase=p->bdata[n];
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if(p->frameno)
|
|
|
|
{
|
|
|
|
int *sump=p->sum+p->frameno%5,
|
|
|
|
*histp=p->history+p->frameno%p->window;
|
|
|
|
|
|
|
|
*sump-=*histp;
|
|
|
|
*sump+=(*histp=imgop(diff_plane, dmpi, mpi, 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
m=match(p, p->sum, -1, -1, &d);
|
|
|
|
|
|
|
|
if(d>=p->threshold)
|
|
|
|
newphase=m;
|
|
|
|
}
|
|
|
|
|
|
|
|
n=p->ocount++%5;
|
|
|
|
|
|
|
|
if(newphase!=p->phase && ((p->phase+4)%5<n)==((newphase+4)%5<n))
|
|
|
|
{
|
|
|
|
p->phase=newphase;
|
|
|
|
mp_msg(MSGT_VFILTER, MSGL_STATUS,
|
|
|
|
"\n%s: Telecine phase %d.\n", vf->info->name, p->phase);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch((p->frameno++-p->phase+10)%5)
|
|
|
|
{
|
|
|
|
case 0:
|
2007-06-28 11:24:12 +00:00
|
|
|
imgop(copyop, dmpi, mpi, 0);
|
vf_*: fix pts values passed to the next filter
Many video filters failed to calculate or even just pass through pts
values for their output frames. Fix this, and also make the two
remaining filters that called vf_next_put_image() twice for the same
input frame (vf_softpulldown, vf_telecine) use vf_queue_frame() so
that e.g. framestepping properly sees both frames.
Changed filters: vf_bmovl, vf_detc, vf_divtc, vf_filmdint, vf_ivtc,
vf_lavc, vf_phase, vf_pullup, vf_softpulldown, vf_telecine, vf_tile,
vf_tinterlace.
2011-04-23 16:56:47 +00:00
|
|
|
vf_detc_adjust_pts(&p->ptsbuf, pts, 0, 1);
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
talloc_free(mpi);
|
2004-04-17 17:08:31 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
case 4:
|
|
|
|
if(p->deghost>0)
|
|
|
|
{
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
imgop(copyop, dmpi, mpi, 0);
|
|
|
|
vf_make_out_image_writeable(vf, mpi);
|
|
|
|
|
|
|
|
imgop(deghost_plane, mpi, dmpi, p->deghost);
|
|
|
|
mpi->pts = vf_detc_adjust_pts(&p->ptsbuf, pts, 0, 0);
|
|
|
|
return mpi;
|
2004-04-17 17:08:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-28 11:24:12 +00:00
|
|
|
imgop(copyop, dmpi, mpi, 0);
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
mpi->pts = vf_detc_adjust_pts(&p->ptsbuf, pts, 0, 0);
|
|
|
|
return mpi;
|
2004-04-17 17:08:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int analyze(struct vf_priv_s *p)
|
|
|
|
{
|
|
|
|
int *buf=0, *bp, bufsize=0, n, b, f, i, j, m, s;
|
|
|
|
unsigned int *cbuf=0, *cp;
|
2011-05-30 21:16:37 +00:00
|
|
|
int8_t *pbuf;
|
|
|
|
int8_t lbuf[256];
|
2004-04-17 17:08:31 +00:00
|
|
|
int sum[5];
|
|
|
|
double d;
|
|
|
|
|
|
|
|
/* read the file */
|
|
|
|
|
|
|
|
n=15;
|
|
|
|
while(fgets(lbuf, 256, p->file))
|
|
|
|
{
|
|
|
|
if(n>=bufsize-19)
|
|
|
|
{
|
|
|
|
bufsize=bufsize?bufsize*2:30000;
|
|
|
|
if((bp=realloc(buf, bufsize*sizeof *buf))) buf=bp;
|
|
|
|
if((cp=realloc(cbuf, bufsize*sizeof *cbuf))) cbuf=cp;
|
|
|
|
|
|
|
|
if(!bp || !cp)
|
|
|
|
{
|
|
|
|
mp_msg(MSGT_VFILTER, MSGL_FATAL, "%s: Not enough memory.\n",
|
|
|
|
vf_info_divtc.name);
|
|
|
|
free(buf);
|
|
|
|
free(cbuf);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sscanf(lbuf, "%x %d", cbuf+n, buf+n);
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
|
2012-10-26 18:05:30 +00:00
|
|
|
if(n <= 15)
|
2004-04-17 17:08:31 +00:00
|
|
|
{
|
|
|
|
mp_msg(MSGT_VFILTER, MSGL_FATAL, "%s: Empty 2-pass log file.\n",
|
|
|
|
vf_info_divtc.name);
|
|
|
|
free(buf);
|
|
|
|
free(cbuf);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* generate some dummy data past the beginning and end of the array */
|
|
|
|
|
|
|
|
buf+=15, cbuf+=15;
|
|
|
|
n-=15;
|
|
|
|
|
|
|
|
memcpy(buf-15, buf, 15*sizeof *buf);
|
|
|
|
memset(cbuf-15, 0, 15*sizeof *cbuf);
|
|
|
|
|
|
|
|
while(n%5)
|
|
|
|
buf[n]=buf[n-5], cbuf[n]=0, n++;
|
|
|
|
|
|
|
|
memcpy(buf+n, buf+n-15, 15*sizeof *buf);
|
|
|
|
memset(cbuf+n, 0, 15*sizeof *cbuf);
|
|
|
|
|
|
|
|
p->csdata=cbuf;
|
|
|
|
p->fcount=n;
|
|
|
|
|
|
|
|
/* array with one slot for each slice of 5 frames */
|
|
|
|
|
|
|
|
p->bdata=pbuf=malloc(p->bcount=b=(n/5));
|
|
|
|
memset(pbuf, 255, b);
|
|
|
|
|
|
|
|
/* resolve the automatic mode */
|
|
|
|
|
|
|
|
if(p->deghost<0)
|
|
|
|
{
|
|
|
|
int deghost=-p->deghost;
|
|
|
|
double s0=0.0, s1=0.0;
|
|
|
|
|
|
|
|
for(f=0; f<n; f+=5)
|
|
|
|
{
|
|
|
|
p->deghost=0; match(p, buf+f, -1, -1, &d); s0+=d;
|
|
|
|
p->deghost=1; match(p, buf+f, -1, -1, &d); s1+=d;
|
|
|
|
}
|
|
|
|
|
|
|
|
p->deghost=s1>s0?deghost:0;
|
|
|
|
|
|
|
|
mp_msg(MSGT_VFILTER, MSGL_INFO,
|
|
|
|
"%s: Deghosting %-3s (relative pattern strength %+.2fdB).\n",
|
|
|
|
vf_info_divtc.name,
|
|
|
|
p->deghost?"ON":"OFF",
|
|
|
|
10.0*log10(s1/s0));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* analyze the data */
|
|
|
|
|
|
|
|
for(f=0; f<5; f++)
|
|
|
|
for(sum[f]=0, n=-15; n<20; n+=5)
|
|
|
|
sum[f]+=buf[n+f];
|
|
|
|
|
|
|
|
for(f=0; f<b; f++)
|
|
|
|
{
|
|
|
|
m=match(p, sum, -1, -1, &d);
|
|
|
|
|
|
|
|
if(d>=p->threshold)
|
|
|
|
pbuf[f]=m;
|
|
|
|
|
|
|
|
if(f<b-1)
|
|
|
|
for(n=0; n<5; n++)
|
|
|
|
sum[n]=sum[n]-buf[5*(f-3)+n]+buf[5*(f+4)+n];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fill in the gaps */
|
|
|
|
|
|
|
|
/* the beginning */
|
|
|
|
for(f=0; f<b && pbuf[f]==-1; f++);
|
|
|
|
|
|
|
|
if(f==b)
|
|
|
|
{
|
|
|
|
free(buf-15);
|
|
|
|
mp_msg(MSGT_VFILTER, MSGL_FATAL, "%s: No telecine pattern found!\n",
|
|
|
|
vf_info_divtc.name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(n=0; n<f; pbuf[n++]=pbuf[f]);
|
|
|
|
|
|
|
|
/* the end */
|
|
|
|
for(f=b-1; pbuf[f]==-1; f--);
|
|
|
|
for(n=f+1; n<b; pbuf[n++]=pbuf[f]);
|
|
|
|
|
|
|
|
/* the rest */
|
|
|
|
for(f=0;;)
|
|
|
|
{
|
|
|
|
while(f<b && pbuf[f]!=-1) f++;
|
|
|
|
if(f==b) break;
|
|
|
|
for(n=f; pbuf[n]==-1; n++);
|
|
|
|
|
|
|
|
if(pbuf[f-1]==pbuf[n])
|
|
|
|
{
|
|
|
|
/* just a gap */
|
|
|
|
while(f<n) pbuf[f++]=pbuf[n];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* phase change, reanalyze the original data in the gap with zero
|
|
|
|
threshold for only the two phases that appear at the ends */
|
|
|
|
|
|
|
|
for(i=0; i<5; i++)
|
|
|
|
for(sum[i]=0, j=5*f-15; j<5*f; j+=5)
|
|
|
|
sum[i]+=buf[i+j];
|
|
|
|
|
|
|
|
for(i=f; i<n; i++)
|
|
|
|
{
|
|
|
|
pbuf[i]=match(p, sum, pbuf[f-1], pbuf[n], 0);
|
|
|
|
|
|
|
|
for(j=0; j<5; j++)
|
|
|
|
sum[j]=sum[j]-buf[5*(i-3)+j]+buf[5*(i+4)+j];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* estimate the transition point by dividing the gap
|
|
|
|
in the same proportion as the number of matches of each kind */
|
|
|
|
|
|
|
|
for(i=f, m=f; i<n; i++)
|
|
|
|
if(pbuf[i]==pbuf[f-1]) m++;
|
|
|
|
|
|
|
|
/* find the transition of the right direction nearest to the
|
|
|
|
estimated point */
|
|
|
|
|
|
|
|
if(m>f && m<n)
|
|
|
|
{
|
|
|
|
for(j=m; j>f; j--)
|
|
|
|
if(pbuf[j-1]==pbuf[f-1] && pbuf[j]==pbuf[n]) break;
|
|
|
|
for(s=m; s<n; s++)
|
|
|
|
if(pbuf[s-1]==pbuf[f-1] && pbuf[s]==pbuf[n]) break;
|
|
|
|
|
|
|
|
m=(s-m<m-j)?s:j;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* and rewrite the data to allow only this one transition */
|
|
|
|
|
|
|
|
for(i=f; i<m; i++)
|
|
|
|
pbuf[i]=pbuf[f-1];
|
|
|
|
|
|
|
|
for(; i<n; i++)
|
|
|
|
pbuf[i]=pbuf[n];
|
|
|
|
|
|
|
|
f=n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(buf-15);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-05-29 14:15:55 +00:00
|
|
|
static int query_format(struct vf_instance *vf, unsigned int fmt)
|
2004-04-17 17:08:31 +00:00
|
|
|
{
|
|
|
|
switch(fmt)
|
|
|
|
{
|
video: decouple internal pixel formats from FourCCs
mplayer's video chain traditionally used FourCCs for pixel formats. For
example, it used IMGFMT_YV12 for 4:2:0 YUV, which was defined to the
string 'YV12' interpreted as unsigned int. Additionally, it used to
encode information into the numeric values of some formats. The RGB
formats had their bit depth and endian encoded into the least
significant byte. Extended planar formats (420P10 etc.) had chroma
shift, endian, and component bit depth encoded. (This has been removed
in recent commits.)
Replace the FourCC mess with a simple enum. Remove all the redundant
formats like YV12/I420/IYUV. Replace some image format names by
something more intuitive, most importantly IMGFMT_YV12 -> IMGFMT_420P.
Add img_fourcc.h, which contains the old IDs for code that actually uses
FourCCs. Change the way demuxers, that output raw video, identify the
video format: they set either MP_FOURCC_RAWVIDEO or MP_FOURCC_IMGFMT to
request the rawvideo decoder, and sh_video->imgfmt specifies the pixel
format. Like the previous hack, this is supposed to avoid the need for
a complete codecs.cfg entry per format, or other lookup tables. (Note
that the RGB raw video FourCCs mostly rely on ffmpeg's mappings for NUT
raw video, but this is still considered better than adding a raw video
decoder - even if trivial, it would be full of annoying lookup tables.)
The TV code has not been tested.
Some corrective changes regarding endian and other image format flags
creep in.
2012-12-23 19:03:30 +00:00
|
|
|
case IMGFMT_444P: case IMGFMT_RGB24:
|
2004-04-17 17:08:31 +00:00
|
|
|
case IMGFMT_422P: case IMGFMT_UYVY: case IMGFMT_BGR24:
|
video: decouple internal pixel formats from FourCCs
mplayer's video chain traditionally used FourCCs for pixel formats. For
example, it used IMGFMT_YV12 for 4:2:0 YUV, which was defined to the
string 'YV12' interpreted as unsigned int. Additionally, it used to
encode information into the numeric values of some formats. The RGB
formats had their bit depth and endian encoded into the least
significant byte. Extended planar formats (420P10 etc.) had chroma
shift, endian, and component bit depth encoded. (This has been removed
in recent commits.)
Replace the FourCC mess with a simple enum. Remove all the redundant
formats like YV12/I420/IYUV. Replace some image format names by
something more intuitive, most importantly IMGFMT_YV12 -> IMGFMT_420P.
Add img_fourcc.h, which contains the old IDs for code that actually uses
FourCCs. Change the way demuxers, that output raw video, identify the
video format: they set either MP_FOURCC_RAWVIDEO or MP_FOURCC_IMGFMT to
request the rawvideo decoder, and sh_video->imgfmt specifies the pixel
format. Like the previous hack, this is supposed to avoid the need for
a complete codecs.cfg entry per format, or other lookup tables. (Note
that the RGB raw video FourCCs mostly rely on ffmpeg's mappings for NUT
raw video, but this is still considered better than adding a raw video
decoder - even if trivial, it would be full of annoying lookup tables.)
The TV code has not been tested.
Some corrective changes regarding endian and other image format flags
creep in.
2012-12-23 19:03:30 +00:00
|
|
|
case IMGFMT_411P: case IMGFMT_YUYV: case IMGFMT_410P:
|
|
|
|
case IMGFMT_420P: case IMGFMT_Y8:
|
2004-04-17 17:08:31 +00:00
|
|
|
return vf_next_query_format(vf,fmt);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-05-29 14:15:55 +00:00
|
|
|
static void uninit(struct vf_instance *vf)
|
2004-04-17 17:08:31 +00:00
|
|
|
{
|
|
|
|
if(vf->priv)
|
|
|
|
{
|
|
|
|
if(vf->priv->file) fclose(vf->priv->file);
|
|
|
|
if(vf->priv->csdata) free(vf->priv->csdata-15);
|
|
|
|
free(vf->priv->bdata);
|
|
|
|
free(vf->priv->history);
|
|
|
|
free(vf->priv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-20 02:03:40 +00:00
|
|
|
static int control(vf_instance_t *vf, int request, void *data)
|
|
|
|
{
|
|
|
|
switch (request) {
|
|
|
|
case VFCTRL_SEEK_RESET:
|
|
|
|
vf_detc_init_pts_buf(&vf->priv->ptsbuf);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return vf_next_control(vf, request, data);
|
|
|
|
}
|
|
|
|
|
2010-02-21 13:40:49 +00:00
|
|
|
static int vf_open(vf_instance_t *vf, char *args)
|
2004-04-17 17:08:31 +00:00
|
|
|
{
|
|
|
|
struct vf_priv_s *p;
|
|
|
|
char *filename="framediff.log", *ap, *q, *a;
|
|
|
|
|
|
|
|
if(args && !(args=strdup(args)))
|
|
|
|
{
|
|
|
|
nomem:
|
|
|
|
mp_msg(MSGT_VFILTER, MSGL_FATAL,
|
|
|
|
"%s: Not enough memory.\n", vf->info->name);
|
|
|
|
fail:
|
|
|
|
uninit(vf);
|
|
|
|
free(args);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
video/filter: change filter API, use refcounting, remove filter DR
Change the entire filter API to use reference counted images instead
of vf_get_image().
Remove filter "direct rendering". This was useful for vf_expand and (in
rare cases) vf_sub: DR allowed these filters to pass a cropped image to
the filters before them. Then, on filtering, the image was "uncropped",
so that black bars could be added around the image without copying. This
means that in some cases, vf_expand will be slower (-vf gradfun,expand
for example).
Note that another form of DR used for in-place filters has been replaced
by simpler logic. Instead of trying to do DR, filters can check if the
image is writeable (with mp_image_is_writeable()), and do true in-place
if that's the case. This affects filters like vf_gradfun and vf_sub.
Everything has to support strides now. If something doesn't, making a
copy of the image data is required.
2012-11-05 13:25:04 +00:00
|
|
|
vf->filter=filter;
|
2004-04-17 17:08:31 +00:00
|
|
|
vf->uninit=uninit;
|
|
|
|
vf->query_format=query_format;
|
2013-01-20 02:03:40 +00:00
|
|
|
vf->control=control;
|
2004-04-17 17:08:31 +00:00
|
|
|
if(!(vf->priv=p=calloc(1, sizeof(struct vf_priv_s))))
|
|
|
|
goto nomem;
|
|
|
|
|
|
|
|
p->phase=5;
|
|
|
|
p->threshold=0.5;
|
|
|
|
p->window=30;
|
|
|
|
|
|
|
|
if((ap=args))
|
|
|
|
while(*ap)
|
|
|
|
{
|
|
|
|
q=ap;
|
|
|
|
if((ap=strchr(q, ':'))) *ap++=0; else ap=q+strlen(q);
|
|
|
|
if((a=strchr(q, '='))) *a++=0; else a=q+strlen(q);
|
|
|
|
|
|
|
|
switch(*q)
|
|
|
|
{
|
|
|
|
case 0: break;
|
|
|
|
case 'f': filename=a; break;
|
|
|
|
case 't': p->threshold=atof(a); break;
|
|
|
|
case 'w': p->window=5*(atoi(a)+4)/5; break;
|
|
|
|
case 'd': p->deghost=atoi(a); break;
|
|
|
|
case 'p':
|
|
|
|
if(q[1]=='h') p->phase=atoi(a);
|
|
|
|
else p->pass=atoi(a);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'h':
|
|
|
|
mp_msg(MSGT_VFILTER, MSGL_INFO,
|
|
|
|
"\n%s options:\n\n"
|
|
|
|
"pass=1|2 - Use 2-pass mode.\n"
|
|
|
|
"file=filename - Set the 2-pass log file name "
|
|
|
|
"(default %s).\n"
|
|
|
|
"threshold=value - Set the pattern recognition "
|
|
|
|
"sensitivity (default %g).\n"
|
|
|
|
"deghost=value - Select deghosting threshold "
|
|
|
|
"(default %d).\n"
|
|
|
|
"window=numframes - Set the statistics window "
|
|
|
|
"for 1-pass mode (default %d).\n"
|
|
|
|
"phase=0|1|2|3|4 - Set the initial phase "
|
|
|
|
"for 1-pass mode (default %d).\n\n"
|
|
|
|
"The option names can be abbreviated to the shortest "
|
|
|
|
"unique prefix.\n\n",
|
|
|
|
vf->info->name, filename, p->threshold, p->deghost,
|
|
|
|
p->window, p->phase%5);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
mp_msg(MSGT_VFILTER, MSGL_FATAL,
|
|
|
|
"%s: Unknown argument %s.\n", vf->info->name, q);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(p->pass)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
if(!(p->file=fopen(filename, "w")))
|
|
|
|
{
|
|
|
|
mp_msg(MSGT_VFILTER, MSGL_FATAL,
|
|
|
|
"%s: Can't create file %s.\n", vf->info->name, filename);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
if(!(p->file=fopen(filename, "r")))
|
|
|
|
{
|
|
|
|
mp_msg(MSGT_VFILTER, MSGL_FATAL,
|
|
|
|
"%s: Can't open file %s.\n", vf->info->name, filename);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!analyze(p))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
fclose(p->file);
|
|
|
|
p->file=0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(p->window<5) p->window=5;
|
|
|
|
if(!(p->history=calloc(sizeof *p->history, p->window)))
|
|
|
|
goto nomem;
|
|
|
|
|
2009-03-13 17:09:39 +00:00
|
|
|
diff = diff_C;
|
2009-03-13 17:12:40 +00:00
|
|
|
#if HAVE_MMX && HAVE_EBX_AVAILABLE
|
2009-03-13 17:09:39 +00:00
|
|
|
if(gCpuCaps.hasMMX) diff = diff_MMX;
|
2004-04-17 17:08:31 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
free(args);
|
vf_*: fix pts values passed to the next filter
Many video filters failed to calculate or even just pass through pts
values for their output frames. Fix this, and also make the two
remaining filters that called vf_next_put_image() twice for the same
input frame (vf_softpulldown, vf_telecine) use vf_queue_frame() so
that e.g. framestepping properly sees both frames.
Changed filters: vf_bmovl, vf_detc, vf_divtc, vf_filmdint, vf_ivtc,
vf_lavc, vf_phase, vf_pullup, vf_softpulldown, vf_telecine, vf_tile,
vf_tinterlace.
2011-04-23 16:56:47 +00:00
|
|
|
vf_detc_init_pts_buf(&p->ptsbuf);
|
2004-04-17 17:08:31 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2007-12-02 14:57:15 +00:00
|
|
|
const vf_info_t vf_info_divtc =
|
2004-04-17 17:08:31 +00:00
|
|
|
{
|
2013-10-23 17:06:42 +00:00
|
|
|
.description = "inverse telecine for deinterlaced video",
|
|
|
|
.name = "divtc",
|
|
|
|
.open = vf_open,
|
2004-04-17 17:08:31 +00:00
|
|
|
};
|