mirror of https://github.com/FFmpeg/FFmpeg.git
parent
5fa252b212
commit
ec34963276
5 changed files with 1 additions and 367 deletions
@ -1,362 +0,0 @@ |
||||
/*
|
||||
* Copyright (C) 2006 Michael Niedermayer <michaelni@gmx.at> |
||||
* |
||||
* 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. |
||||
*/ |
||||
|
||||
|
||||
/*
|
||||
Known Issues: |
||||
* The motion estimation is somewhat at the mercy of the input, if the input |
||||
frames are created purely based on spatial interpolation then for example |
||||
a thin black line or another random and not interpolateable pattern |
||||
will cause problems |
||||
Note: completly ignoring the "unavailable" lines during motion estimation |
||||
didnt look any better, so the most obvious solution would be to improve |
||||
tfields or penalize problematic motion vectors ... |
||||
|
||||
* If non iterative ME is used then snow currently ignores the OBMC window |
||||
and as a result sometimes creates artifacts |
||||
|
||||
* only past frames are used, we should ideally use future frames too, something |
||||
like filtering the whole movie in forward and then backward direction seems |
||||
like a interresting idea but the current filter framework is FAR from |
||||
supporting such things |
||||
|
||||
* combining the motion compensated image with the input image also isnt |
||||
as trivial as it seems, simple blindly taking even lines from one and |
||||
odd ones from the other doesnt work at all as ME/MC sometimes simple |
||||
has nothing in the previous frames which matches the current, the current |
||||
algo has been found by trial and error and almost certainly can be |
||||
improved ... |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <inttypes.h> |
||||
#include <math.h> |
||||
|
||||
#include "mp_msg.h" |
||||
#include "cpudetect.h" |
||||
|
||||
#include "libavutil/common.h" |
||||
#include "libavutil/internal.h" |
||||
#include "libavutil/intreadwrite.h" |
||||
#include "libavcodec/avcodec.h" |
||||
#include "libavcodec/dsputil.h" |
||||
|
||||
#undef fprintf |
||||
#undef free |
||||
#undef malloc |
||||
|
||||
#include "img_format.h" |
||||
#include "mp_image.h" |
||||
#include "vf.h" |
||||
#include "av_helpers.h" |
||||
|
||||
#define MIN(a,b) ((a) > (b) ? (b) : (a)) |
||||
#define MAX(a,b) ((a) < (b) ? (b) : (a)) |
||||
#define ABS(a) ((a) > 0 ? (a) : (-(a))) |
||||
|
||||
//===========================================================================//
|
||||
|
||||
struct vf_priv_s { |
||||
int mode; |
||||
int qp; |
||||
int parity; |
||||
#if 0 |
||||
int temp_stride[3]; |
||||
uint8_t *src[3]; |
||||
int16_t *temp[3]; |
||||
#endif |
||||
int outbuf_size; |
||||
uint8_t *outbuf; |
||||
AVCodecContext *avctx_enc; |
||||
AVFrame *frame; |
||||
AVFrame *frame_dec; |
||||
}; |
||||
|
||||
static void filter(struct vf_priv_s *p, uint8_t *dst[3], uint8_t *src[3], int dst_stride[3], int src_stride[3], int width, int height){ |
||||
int x, y, i; |
||||
|
||||
for(i=0; i<3; i++){ |
||||
p->frame->data[i]= src[i]; |
||||
p->frame->linesize[i]= src_stride[i]; |
||||
} |
||||
|
||||
p->avctx_enc->me_cmp= |
||||
p->avctx_enc->me_sub_cmp= FF_CMP_SAD /*| (p->parity ? FF_CMP_ODD : FF_CMP_EVEN)*/; |
||||
p->frame->quality= p->qp*FF_QP2LAMBDA; |
||||
avcodec_encode_video(p->avctx_enc, p->outbuf, p->outbuf_size, p->frame); |
||||
p->frame_dec = p->avctx_enc->coded_frame; |
||||
|
||||
for(i=0; i<3; i++){ |
||||
int is_chroma= !!i; |
||||
int w= width >>is_chroma; |
||||
int h= height>>is_chroma; |
||||
int fils= p->frame_dec->linesize[i]; |
||||
int srcs= src_stride[i]; |
||||
|
||||
for(y=0; y<h; y++){ |
||||
if((y ^ p->parity) & 1){ |
||||
for(x=0; x<w; x++){ |
||||
if(y>0 && y<h-1){ |
||||
int is_edge= x<3 || x>w-4; |
||||
uint8_t *filp= &p->frame_dec->data[i][x + y*fils]; |
||||
uint8_t *srcp= &src[i][x + y*srcs]; |
||||
int diff0= filp[-fils] - srcp[-srcs]; |
||||
int diff1= filp[+fils] - srcp[+srcs]; |
||||
int temp= filp[0]; |
||||
|
||||
#define DELTA(j) av_clip(j, -x, w-1-x) |
||||
|
||||
#define GET_SCORE_EDGE(j)\ |
||||
ABS(srcp[-srcs+DELTA(-1+(j))] - srcp[+srcs+DELTA(-1-(j))])+\
|
||||
ABS(srcp[-srcs+DELTA(j) ] - srcp[+srcs+DELTA( -(j))])+\
|
||||
ABS(srcp[-srcs+DELTA(1+(j)) ] - srcp[+srcs+DELTA( 1-(j))]) |
||||
|
||||
#define GET_SCORE(j)\ |
||||
ABS(srcp[-srcs-1+(j)] - srcp[+srcs-1-(j)])+\
|
||||
ABS(srcp[-srcs +(j)] - srcp[+srcs -(j)])+\
|
||||
ABS(srcp[-srcs+1+(j)] - srcp[+srcs+1-(j)]) |
||||
|
||||
#define CHECK_EDGE(j)\ |
||||
{ int score= GET_SCORE_EDGE(j);\
|
||||
if(score < spatial_score){\
|
||||
spatial_score= score;\
|
||||
diff0= filp[-fils+DELTA(j)] - srcp[-srcs+DELTA(j)];\
|
||||
diff1= filp[+fils+DELTA(-(j))] - srcp[+srcs+DELTA(-(j))];\
|
||||
|
||||
#define CHECK(j)\ |
||||
{ int score= GET_SCORE(j);\
|
||||
if(score < spatial_score){\
|
||||
spatial_score= score;\
|
||||
diff0= filp[-fils+(j)] - srcp[-srcs+(j)];\
|
||||
diff1= filp[+fils-(j)] - srcp[+srcs-(j)];\
|
||||
|
||||
if (is_edge) { |
||||
int spatial_score= GET_SCORE_EDGE(0)-1; |
||||
CHECK_EDGE(-1) CHECK_EDGE(-2) }} }} |
||||
CHECK_EDGE( 1) CHECK_EDGE( 2) }} }} |
||||
} else { |
||||
int spatial_score= GET_SCORE(0)-1; |
||||
CHECK(-1) CHECK(-2) }} }} |
||||
CHECK( 1) CHECK( 2) }} }} |
||||
} |
||||
#if 0 |
||||
if((diff0 ^ diff1) > 0){ |
||||
int mindiff= ABS(diff0) > ABS(diff1) ? diff1 : diff0; |
||||
temp-= mindiff; |
||||
} |
||||
#elif 1 |
||||
if(diff0 + diff1 > 0) |
||||
temp-= (diff0 + diff1 - ABS( ABS(diff0) - ABS(diff1) )/2)/2; |
||||
else |
||||
temp-= (diff0 + diff1 + ABS( ABS(diff0) - ABS(diff1) )/2)/2; |
||||
#else |
||||
temp-= (diff0 + diff1)/2; |
||||
#endif |
||||
#if 1 |
||||
filp[0]= |
||||
dst[i][x + y*dst_stride[i]]= temp > 255U ? ~(temp>>31) : temp; |
||||
#else |
||||
dst[i][x + y*dst_stride[i]]= filp[0]; |
||||
filp[0]= temp > 255U ? ~(temp>>31) : temp; |
||||
#endif |
||||
}else |
||||
dst[i][x + y*dst_stride[i]]= p->frame_dec->data[i][x + y*fils]; |
||||
} |
||||
} |
||||
} |
||||
for(y=0; y<h; y++){ |
||||
if(!((y ^ p->parity) & 1)){ |
||||
for(x=0; x<w; x++){ |
||||
#if 1 |
||||
p->frame_dec->data[i][x + y*fils]= |
||||
dst[i][x + y*dst_stride[i]]= src[i][x + y*srcs]; |
||||
#else |
||||
dst[i][x + y*dst_stride[i]]= p->frame_dec->data[i][x + y*fils]; |
||||
p->frame_dec->data[i][x + y*fils]= src[i][x + y*srcs]; |
||||
#endif |
||||
} |
||||
} |
||||
} |
||||
} |
||||
p->parity ^= 1; |
||||
|
||||
} |
||||
|
||||
static int config(struct vf_instance *vf, |
||||
int width, int height, int d_width, int d_height, |
||||
unsigned int flags, unsigned int outfmt){ |
||||
int i; |
||||
AVCodec *enc= avcodec_find_encoder(AV_CODEC_ID_SNOW); |
||||
|
||||
for(i=0; i<3; i++){ |
||||
AVCodecContext *avctx_enc; |
||||
AVDictionary *opts = NULL; |
||||
#if 0 |
||||
int is_chroma= !!i; |
||||
int w= ((width + 31) & (~31))>>is_chroma; |
||||
int h= ((height + 31) & (~31))>>is_chroma; |
||||
|
||||
vf->priv->temp_stride[i]= w; |
||||
vf->priv->temp[i]= malloc(vf->priv->temp_stride[i]*h*sizeof(int16_t)); |
||||
vf->priv->src [i]= malloc(vf->priv->temp_stride[i]*h*sizeof(uint8_t)); |
||||
#endif |
||||
avctx_enc= |
||||
vf->priv->avctx_enc= avcodec_alloc_context3(enc); |
||||
avctx_enc->width = width; |
||||
avctx_enc->height = height; |
||||
avctx_enc->time_base= (AVRational){1,25}; // meaningless
|
||||
avctx_enc->gop_size = 300; |
||||
avctx_enc->max_b_frames= 0; |
||||
avctx_enc->pix_fmt = AV_PIX_FMT_YUV420P; |
||||
avctx_enc->flags = CODEC_FLAG_QSCALE | CODEC_FLAG_LOW_DELAY; |
||||
avctx_enc->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; |
||||
avctx_enc->global_quality= 1; |
||||
av_dict_set(&opts, "memc_only", "1", 0); |
||||
avctx_enc->me_cmp= |
||||
avctx_enc->me_sub_cmp= FF_CMP_SAD; //SSE;
|
||||
avctx_enc->mb_cmp= FF_CMP_SSE; |
||||
|
||||
switch(vf->priv->mode){ |
||||
case 3: |
||||
avctx_enc->refs= 3; |
||||
case 2: |
||||
avctx_enc->me_method= ME_ITER; |
||||
case 1: |
||||
avctx_enc->flags |= CODEC_FLAG_4MV; |
||||
avctx_enc->dia_size=2; |
||||
// avctx_enc->mb_decision = MB_DECISION_RD;
|
||||
case 0: |
||||
avctx_enc->flags |= CODEC_FLAG_QPEL; |
||||
} |
||||
|
||||
avcodec_open2(avctx_enc, enc, &opts); |
||||
av_dict_free(&opts); |
||||
|
||||
} |
||||
vf->priv->frame= avcodec_alloc_frame(); |
||||
|
||||
vf->priv->outbuf_size= width*height*10; |
||||
vf->priv->outbuf= malloc(vf->priv->outbuf_size); |
||||
|
||||
return ff_vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); |
||||
} |
||||
|
||||
static void get_image(struct vf_instance *vf, mp_image_t *mpi){ |
||||
if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change
|
||||
return; //caused problems, dunno why
|
||||
// ok, we can do pp in-place (or pp disabled):
|
||||
vf->dmpi=ff_vf_get_image(vf->next,mpi->imgfmt, |
||||
mpi->type, mpi->flags | MP_IMGFLAG_READABLE, mpi->width, mpi->height); |
||||
mpi->planes[0]=vf->dmpi->planes[0]; |
||||
mpi->stride[0]=vf->dmpi->stride[0]; |
||||
mpi->width=vf->dmpi->width; |
||||
if(mpi->flags&MP_IMGFLAG_PLANAR){ |
||||
mpi->planes[1]=vf->dmpi->planes[1]; |
||||
mpi->planes[2]=vf->dmpi->planes[2]; |
||||
mpi->stride[1]=vf->dmpi->stride[1]; |
||||
mpi->stride[2]=vf->dmpi->stride[2]; |
||||
} |
||||
mpi->flags|=MP_IMGFLAG_DIRECT; |
||||
} |
||||
|
||||
static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ |
||||
mp_image_t *dmpi; |
||||
|
||||
if(!(mpi->flags&MP_IMGFLAG_DIRECT)){ |
||||
// no DR, so get a new image! hope we'll get DR buffer:
|
||||
dmpi=ff_vf_get_image(vf->next,mpi->imgfmt, |
||||
MP_IMGTYPE_TEMP, |
||||
MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE, |
||||
mpi->width,mpi->height); |
||||
ff_vf_clone_mpi_attributes(dmpi, mpi); |
||||
}else{ |
||||
dmpi=vf->dmpi; |
||||
} |
||||
|
||||
filter(vf->priv, dmpi->planes, mpi->planes, dmpi->stride, mpi->stride, mpi->w, mpi->h); |
||||
|
||||
return ff_vf_next_put_image(vf,dmpi, pts); |
||||
} |
||||
|
||||
static void uninit(struct vf_instance *vf){ |
||||
if(!vf->priv) return; |
||||
|
||||
#if 0 |
||||
for(i=0; i<3; i++){ |
||||
free(vf->priv->temp[i]); |
||||
vf->priv->temp[i]= NULL; |
||||
free(vf->priv->src[i]); |
||||
vf->priv->src[i]= NULL; |
||||
} |
||||
#endif |
||||
if (vf->priv->avctx_enc) { |
||||
avcodec_close(vf->priv->avctx_enc); |
||||
av_freep(&vf->priv->avctx_enc); |
||||
} |
||||
|
||||
free(vf->priv->outbuf); |
||||
free(vf->priv); |
||||
vf->priv=NULL; |
||||
} |
||||
|
||||
//===========================================================================//
|
||||
static int query_format(struct vf_instance *vf, unsigned int fmt){ |
||||
switch(fmt){ |
||||
case IMGFMT_YV12: |
||||
case IMGFMT_I420: |
||||
case IMGFMT_IYUV: |
||||
case IMGFMT_Y800: |
||||
case IMGFMT_Y8: |
||||
return ff_vf_next_query_format(vf,fmt); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int vf_open(vf_instance_t *vf, char *args){ |
||||
|
||||
vf->config=config; |
||||
vf->put_image=put_image; |
||||
vf->get_image=get_image; |
||||
vf->query_format=query_format; |
||||
vf->uninit=uninit; |
||||
vf->priv=malloc(sizeof(struct vf_priv_s)); |
||||
memset(vf->priv, 0, sizeof(struct vf_priv_s)); |
||||
|
||||
ff_init_avcodec(); |
||||
|
||||
vf->priv->mode=0; |
||||
vf->priv->parity= -1; |
||||
vf->priv->qp=1; |
||||
|
||||
if (args) sscanf(args, "%d:%d:%d", &vf->priv->mode, &vf->priv->parity, &vf->priv->qp); |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
const vf_info_t ff_vf_info_mcdeint = { |
||||
"motion compensating deinterlacer", |
||||
"mcdeint", |
||||
"Michael Niedermayer", |
||||
"", |
||||
vf_open, |
||||
NULL |
||||
}; |
Loading…
Reference in new issue