|
|
|
@ -202,28 +202,20 @@ void copy_picture_field(uint8_t *dst[4], int dst_linesize[4], |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref) |
|
|
|
|
static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *picref) |
|
|
|
|
{ |
|
|
|
|
AVFilterContext *ctx = inlink->dst; |
|
|
|
|
AVFilterLink *outlink = ctx->outputs[0]; |
|
|
|
|
TInterlaceContext *tinterlace = ctx->priv; |
|
|
|
|
AVFilterBufferRef *cur, *next, *out; |
|
|
|
|
int field, tff, ret; |
|
|
|
|
|
|
|
|
|
avfilter_unref_buffer(tinterlace->cur); |
|
|
|
|
tinterlace->cur = tinterlace->next; |
|
|
|
|
tinterlace->next = picref; |
|
|
|
|
inlink->cur_buf = NULL; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int end_frame(AVFilterLink *inlink) |
|
|
|
|
{ |
|
|
|
|
AVFilterContext *ctx = inlink->dst; |
|
|
|
|
AVFilterLink *outlink = ctx->outputs[0]; |
|
|
|
|
TInterlaceContext *tinterlace = ctx->priv; |
|
|
|
|
AVFilterBufferRef *cur = tinterlace->cur; |
|
|
|
|
AVFilterBufferRef *next = tinterlace->next; |
|
|
|
|
AVFilterBufferRef *out = NULL; |
|
|
|
|
int field, tff; |
|
|
|
|
|
|
|
|
|
cur = tinterlace->cur; |
|
|
|
|
next = tinterlace->next; |
|
|
|
|
/* we need at least two frames */ |
|
|
|
|
if (!tinterlace->cur) |
|
|
|
|
return 0; |
|
|
|
@ -232,6 +224,8 @@ static int end_frame(AVFilterLink *inlink) |
|
|
|
|
case MODE_MERGE: /* move the odd frame into the upper field of the new image, even into
|
|
|
|
|
* the lower field, generating a double-height video at half framerate */ |
|
|
|
|
out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); |
|
|
|
|
if (!out) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
avfilter_copy_buffer_ref_props(out, cur); |
|
|
|
|
out->video->h = outlink->h; |
|
|
|
|
out->video->interlaced = 1; |
|
|
|
@ -281,6 +275,8 @@ static int end_frame(AVFilterLink *inlink) |
|
|
|
|
case MODE_INTERLEAVE_BOTTOM: /* bottom field first */ |
|
|
|
|
tff = tinterlace->mode == MODE_INTERLEAVE_TOP; |
|
|
|
|
out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); |
|
|
|
|
if (!out) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
avfilter_copy_buffer_ref_props(out, cur); |
|
|
|
|
out->video->interlaced = 1; |
|
|
|
|
out->video->top_field_first = tff; |
|
|
|
@ -300,15 +296,18 @@ static int end_frame(AVFilterLink *inlink) |
|
|
|
|
case MODE_INTERLACEX2: /* re-interlace preserving image height, double frame rate */ |
|
|
|
|
/* output current frame first */ |
|
|
|
|
out = avfilter_ref_buffer(cur, ~AV_PERM_WRITE); |
|
|
|
|
if (!out) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
out->video->interlaced = 1; |
|
|
|
|
|
|
|
|
|
ff_start_frame(outlink, out); |
|
|
|
|
ff_draw_slice(outlink, 0, outlink->h, 1); |
|
|
|
|
ff_end_frame(outlink); |
|
|
|
|
if ((ret = ff_filter_frame(outlink, out)) < 0) |
|
|
|
|
return ret; |
|
|
|
|
|
|
|
|
|
/* output mix of current and next frame */ |
|
|
|
|
tff = next->video->top_field_first; |
|
|
|
|
out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); |
|
|
|
|
if (!out) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
avfilter_copy_buffer_ref_props(out, next); |
|
|
|
|
out->video->interlaced = 1; |
|
|
|
|
|
|
|
|
@ -325,13 +324,10 @@ static int end_frame(AVFilterLink *inlink) |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ff_start_frame(outlink, out); |
|
|
|
|
ff_draw_slice(outlink, 0, outlink->h, 1); |
|
|
|
|
ff_end_frame(outlink); |
|
|
|
|
|
|
|
|
|
ret = ff_filter_frame(outlink, out); |
|
|
|
|
tinterlace->frame++; |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int request_frame(AVFilterLink *outlink) |
|
|
|
@ -349,15 +345,11 @@ static int request_frame(AVFilterLink *outlink) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) { return 0; } |
|
|
|
|
|
|
|
|
|
static const AVFilterPad tinterlace_inputs[] = { |
|
|
|
|
{ |
|
|
|
|
.name = "default", |
|
|
|
|
.type = AVMEDIA_TYPE_VIDEO, |
|
|
|
|
.start_frame = start_frame, |
|
|
|
|
.draw_slice = null_draw_slice, |
|
|
|
|
.end_frame = end_frame, |
|
|
|
|
.filter_frame = filter_frame, |
|
|
|
|
}, |
|
|
|
|
{ NULL } |
|
|
|
|
}; |
|
|
|
|