Any alleged performance benefits gained from the split are purely mythological and do not justify added code complexity.tags/n1.1
| @@ -314,7 +314,7 @@ static int output_frame(AVFilterLink *outlink, int nb_samples) | |||||
| if (s->next_pts != AV_NOPTS_VALUE) | if (s->next_pts != AV_NOPTS_VALUE) | ||||
| s->next_pts += nb_samples; | s->next_pts += nb_samples; | ||||
| return ff_filter_samples(outlink, out_buf); | |||||
| return ff_filter_frame(outlink, out_buf); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -455,7 +455,7 @@ static int request_frame(AVFilterLink *outlink) | |||||
| return output_frame(outlink, available_samples); | return output_frame(outlink, available_samples); | ||||
| } | } | ||||
| static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf) | |||||
| { | { | ||||
| AVFilterContext *ctx = inlink->dst; | AVFilterContext *ctx = inlink->dst; | ||||
| MixContext *s = ctx->priv; | MixContext *s = ctx->priv; | ||||
| @@ -509,7 +509,7 @@ static int init(AVFilterContext *ctx, const char *args) | |||||
| snprintf(name, sizeof(name), "input%d", i); | snprintf(name, sizeof(name), "input%d", i); | ||||
| pad.type = AVMEDIA_TYPE_AUDIO; | pad.type = AVMEDIA_TYPE_AUDIO; | ||||
| pad.name = av_strdup(name); | pad.name = av_strdup(name); | ||||
| pad.filter_samples = filter_samples; | |||||
| pad.filter_frame = filter_frame; | |||||
| ff_insert_inpad(ctx, i, &pad); | ff_insert_inpad(ctx, i, &pad); | ||||
| } | } | ||||
| @@ -34,6 +34,7 @@ | |||||
| #include "audio.h" | #include "audio.h" | ||||
| #include "avfilter.h" | #include "avfilter.h" | ||||
| #include "internal.h" | |||||
| typedef struct AShowInfoContext { | typedef struct AShowInfoContext { | ||||
| /** | /** | ||||
| @@ -64,7 +65,7 @@ static void uninit(AVFilterContext *ctx) | |||||
| av_freep(&s->plane_checksums); | av_freep(&s->plane_checksums); | ||||
| } | } | ||||
| static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf) | |||||
| { | { | ||||
| AVFilterContext *ctx = inlink->dst; | AVFilterContext *ctx = inlink->dst; | ||||
| AShowInfoContext *s = ctx->priv; | AShowInfoContext *s = ctx->priv; | ||||
| @@ -103,7 +104,7 @@ static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) | |||||
| av_log(ctx, AV_LOG_INFO, "]\n"); | av_log(ctx, AV_LOG_INFO, "]\n"); | ||||
| s->frame++; | s->frame++; | ||||
| return ff_filter_samples(inlink->dst->outputs[0], buf); | |||||
| return ff_filter_frame(inlink->dst->outputs[0], buf); | |||||
| } | } | ||||
| static const AVFilterPad inputs[] = { | static const AVFilterPad inputs[] = { | ||||
| @@ -112,7 +113,7 @@ static const AVFilterPad inputs[] = { | |||||
| .type = AVMEDIA_TYPE_AUDIO, | .type = AVMEDIA_TYPE_AUDIO, | ||||
| .get_audio_buffer = ff_null_get_audio_buffer, | .get_audio_buffer = ff_null_get_audio_buffer, | ||||
| .config_props = config_input, | .config_props = config_input, | ||||
| .filter_samples = filter_samples, | |||||
| .filter_frame = filter_frame, | |||||
| .min_perms = AV_PERM_READ, | .min_perms = AV_PERM_READ, | ||||
| }, | }, | ||||
| { NULL }, | { NULL }, | ||||
| @@ -39,7 +39,7 @@ typedef struct ASyncContext { | |||||
| float min_delta_sec; | float min_delta_sec; | ||||
| int max_comp; | int max_comp; | ||||
| /* set by filter_samples() to signal an output frame to request_frame() */ | |||||
| /* set by filter_frame() to signal an output frame to request_frame() */ | |||||
| int got_output; | int got_output; | ||||
| } ASyncContext; | } ASyncContext; | ||||
| @@ -141,7 +141,7 @@ static int request_frame(AVFilterLink *link) | |||||
| } | } | ||||
| buf->pts = s->pts; | buf->pts = s->pts; | ||||
| return ff_filter_samples(link, buf); | |||||
| return ff_filter_frame(link, buf); | |||||
| } | } | ||||
| return ret; | return ret; | ||||
| @@ -161,7 +161,7 @@ static int64_t get_delay(ASyncContext *s) | |||||
| return avresample_available(s->avr) + avresample_get_delay(s->avr); | return avresample_available(s->avr) + avresample_get_delay(s->avr); | ||||
| } | } | ||||
| static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf) | |||||
| { | { | ||||
| AVFilterContext *ctx = inlink->dst; | AVFilterContext *ctx = inlink->dst; | ||||
| ASyncContext *s = ctx->priv; | ASyncContext *s = ctx->priv; | ||||
| @@ -217,7 +217,7 @@ static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) | |||||
| av_samples_set_silence(buf_out->extended_data, out_size - delta, | av_samples_set_silence(buf_out->extended_data, out_size - delta, | ||||
| delta, nb_channels, buf->format); | delta, nb_channels, buf->format); | ||||
| } | } | ||||
| ret = ff_filter_samples(outlink, buf_out); | |||||
| ret = ff_filter_frame(outlink, buf_out); | |||||
| if (ret < 0) | if (ret < 0) | ||||
| goto fail; | goto fail; | ||||
| s->got_output = 1; | s->got_output = 1; | ||||
| @@ -243,7 +243,7 @@ static const AVFilterPad avfilter_af_asyncts_inputs[] = { | |||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_AUDIO, | .type = AVMEDIA_TYPE_AUDIO, | ||||
| .filter_samples = filter_samples | |||||
| .filter_frame = filter_frame, | |||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| }; | }; | ||||
| @@ -313,7 +313,7 @@ static int channelmap_query_formats(AVFilterContext *ctx) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int channelmap_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) | |||||
| static int channelmap_filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf) | |||||
| { | { | ||||
| AVFilterContext *ctx = inlink->dst; | AVFilterContext *ctx = inlink->dst; | ||||
| AVFilterLink *outlink = ctx->outputs[0]; | AVFilterLink *outlink = ctx->outputs[0]; | ||||
| @@ -355,7 +355,7 @@ static int channelmap_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *bu | |||||
| memcpy(buf->data, buf->extended_data, | memcpy(buf->data, buf->extended_data, | ||||
| FFMIN(FF_ARRAY_ELEMS(buf->data), nch_out) * sizeof(buf->data[0])); | FFMIN(FF_ARRAY_ELEMS(buf->data), nch_out) * sizeof(buf->data[0])); | ||||
| return ff_filter_samples(outlink, buf); | |||||
| return ff_filter_frame(outlink, buf); | |||||
| } | } | ||||
| static int channelmap_config_input(AVFilterLink *inlink) | static int channelmap_config_input(AVFilterLink *inlink) | ||||
| @@ -389,7 +389,7 @@ static const AVFilterPad avfilter_af_channelmap_inputs[] = { | |||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_AUDIO, | .type = AVMEDIA_TYPE_AUDIO, | ||||
| .filter_samples = channelmap_filter_samples, | |||||
| .filter_frame = channelmap_filter_frame, | |||||
| .config_props = channelmap_config_input | .config_props = channelmap_config_input | ||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| @@ -111,7 +111,7 @@ static int query_formats(AVFilterContext *ctx) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf) | |||||
| { | { | ||||
| AVFilterContext *ctx = inlink->dst; | AVFilterContext *ctx = inlink->dst; | ||||
| int i, ret = 0; | int i, ret = 0; | ||||
| @@ -128,7 +128,7 @@ static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) | |||||
| buf_out->audio->channel_layout = | buf_out->audio->channel_layout = | ||||
| av_channel_layout_extract_channel(buf->audio->channel_layout, i); | av_channel_layout_extract_channel(buf->audio->channel_layout, i); | ||||
| ret = ff_filter_samples(ctx->outputs[i], buf_out); | |||||
| ret = ff_filter_frame(ctx->outputs[i], buf_out); | |||||
| if (ret < 0) | if (ret < 0) | ||||
| break; | break; | ||||
| } | } | ||||
| @@ -140,7 +140,7 @@ static const AVFilterPad avfilter_af_channelsplit_inputs[] = { | |||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_AUDIO, | .type = AVMEDIA_TYPE_AUDIO, | ||||
| .filter_samples = filter_samples, | |||||
| .filter_frame = filter_frame, | |||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| }; | }; | ||||
| @@ -93,7 +93,7 @@ static const AVClass join_class = { | |||||
| .version = LIBAVUTIL_VERSION_INT, | .version = LIBAVUTIL_VERSION_INT, | ||||
| }; | }; | ||||
| static int filter_samples(AVFilterLink *link, AVFilterBufferRef *buf) | |||||
| static int filter_frame(AVFilterLink *link, AVFilterBufferRef *buf) | |||||
| { | { | ||||
| AVFilterContext *ctx = link->dst; | AVFilterContext *ctx = link->dst; | ||||
| JoinContext *s = ctx->priv; | JoinContext *s = ctx->priv; | ||||
| @@ -230,7 +230,7 @@ static int join_init(AVFilterContext *ctx, const char *args) | |||||
| snprintf(name, sizeof(name), "input%d", i); | snprintf(name, sizeof(name), "input%d", i); | ||||
| pad.type = AVMEDIA_TYPE_AUDIO; | pad.type = AVMEDIA_TYPE_AUDIO; | ||||
| pad.name = av_strdup(name); | pad.name = av_strdup(name); | ||||
| pad.filter_samples = filter_samples; | |||||
| pad.filter_frame = filter_frame; | |||||
| pad.needs_fifo = 1; | pad.needs_fifo = 1; | ||||
| @@ -471,7 +471,7 @@ static int join_request_frame(AVFilterLink *outlink) | |||||
| priv->nb_in_buffers = ctx->nb_inputs; | priv->nb_in_buffers = ctx->nb_inputs; | ||||
| buf->buf->priv = priv; | buf->buf->priv = priv; | ||||
| ret = ff_filter_samples(outlink, buf); | |||||
| ret = ff_filter_frame(outlink, buf); | |||||
| memset(s->input_frames, 0, sizeof(*s->input_frames) * ctx->nb_inputs); | memset(s->input_frames, 0, sizeof(*s->input_frames) * ctx->nb_inputs); | ||||
| @@ -40,7 +40,7 @@ typedef struct ResampleContext { | |||||
| int64_t next_pts; | int64_t next_pts; | ||||
| /* set by filter_samples() to signal an output frame to request_frame() */ | |||||
| /* set by filter_frame() to signal an output frame to request_frame() */ | |||||
| int got_output; | int got_output; | ||||
| } ResampleContext; | } ResampleContext; | ||||
| @@ -162,12 +162,12 @@ static int request_frame(AVFilterLink *outlink) | |||||
| } | } | ||||
| buf->pts = s->next_pts; | buf->pts = s->next_pts; | ||||
| return ff_filter_samples(outlink, buf); | |||||
| return ff_filter_frame(outlink, buf); | |||||
| } | } | ||||
| return ret; | return ret; | ||||
| } | } | ||||
| static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf) | |||||
| { | { | ||||
| AVFilterContext *ctx = inlink->dst; | AVFilterContext *ctx = inlink->dst; | ||||
| ResampleContext *s = ctx->priv; | ResampleContext *s = ctx->priv; | ||||
| @@ -224,7 +224,7 @@ static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) | |||||
| s->next_pts = buf_out->pts + buf_out->audio->nb_samples; | s->next_pts = buf_out->pts + buf_out->audio->nb_samples; | ||||
| ret = ff_filter_samples(outlink, buf_out); | |||||
| ret = ff_filter_frame(outlink, buf_out); | |||||
| s->got_output = 1; | s->got_output = 1; | ||||
| } | } | ||||
| @@ -232,7 +232,7 @@ fail: | |||||
| avfilter_unref_buffer(buf); | avfilter_unref_buffer(buf); | ||||
| } else { | } else { | ||||
| buf->format = outlink->format; | buf->format = outlink->format; | ||||
| ret = ff_filter_samples(outlink, buf); | |||||
| ret = ff_filter_frame(outlink, buf); | |||||
| s->got_output = 1; | s->got_output = 1; | ||||
| } | } | ||||
| @@ -243,7 +243,7 @@ static const AVFilterPad avfilter_af_resample_inputs[] = { | |||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_AUDIO, | .type = AVMEDIA_TYPE_AUDIO, | ||||
| .filter_samples = filter_samples, | |||||
| .filter_frame = filter_frame, | |||||
| .min_perms = AV_PERM_READ | .min_perms = AV_PERM_READ | ||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| @@ -20,7 +20,7 @@ | |||||
| #include "avfilter.h" | #include "avfilter.h" | ||||
| #include "internal.h" | #include "internal.h" | ||||
| static int null_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref) | |||||
| static int null_filter_frame(AVFilterLink *link, AVFilterBufferRef *samplesref) | |||||
| { | { | ||||
| avfilter_unref_bufferp(&samplesref); | avfilter_unref_bufferp(&samplesref); | ||||
| return 0; | return 0; | ||||
| @@ -30,7 +30,7 @@ static const AVFilterPad avfilter_asink_anullsink_inputs[] = { | |||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_AUDIO, | .type = AVMEDIA_TYPE_AUDIO, | ||||
| .filter_samples = null_filter_samples, | |||||
| .filter_frame = null_filter_frame, | |||||
| }, | }, | ||||
| { NULL }, | { NULL }, | ||||
| }; | }; | ||||
| @@ -146,50 +146,3 @@ fail: | |||||
| av_freep(&samples); | av_freep(&samples); | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| static int default_filter_samples(AVFilterLink *link, | |||||
| AVFilterBufferRef *samplesref) | |||||
| { | |||||
| return ff_filter_samples(link->dst->outputs[0], samplesref); | |||||
| } | |||||
| int ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref) | |||||
| { | |||||
| int (*filter_samples)(AVFilterLink *, AVFilterBufferRef *); | |||||
| AVFilterPad *dst = link->dstpad; | |||||
| AVFilterBufferRef *buf_out; | |||||
| FF_DPRINTF_START(NULL, filter_samples); ff_dlog_link(NULL, link, 1); | |||||
| if (!(filter_samples = dst->filter_samples)) | |||||
| filter_samples = default_filter_samples; | |||||
| /* prepare to copy the samples if the buffer has insufficient permissions */ | |||||
| if ((dst->min_perms & samplesref->perms) != dst->min_perms || | |||||
| dst->rej_perms & samplesref->perms) { | |||||
| av_log(link->dst, AV_LOG_DEBUG, | |||||
| "Copying audio data in avfilter (have perms %x, need %x, reject %x)\n", | |||||
| samplesref->perms, link->dstpad->min_perms, link->dstpad->rej_perms); | |||||
| buf_out = ff_default_get_audio_buffer(link, dst->min_perms, | |||||
| samplesref->audio->nb_samples); | |||||
| if (!buf_out) { | |||||
| avfilter_unref_buffer(samplesref); | |||||
| return AVERROR(ENOMEM); | |||||
| } | |||||
| buf_out->pts = samplesref->pts; | |||||
| buf_out->audio->sample_rate = samplesref->audio->sample_rate; | |||||
| /* Copy actual data into new samples buffer */ | |||||
| av_samples_copy(buf_out->extended_data, samplesref->extended_data, | |||||
| 0, 0, samplesref->audio->nb_samples, | |||||
| av_get_channel_layout_nb_channels(link->channel_layout), | |||||
| link->format); | |||||
| avfilter_unref_buffer(samplesref); | |||||
| } else | |||||
| buf_out = samplesref; | |||||
| return filter_samples(link, buf_out); | |||||
| } | |||||
| @@ -42,17 +42,4 @@ AVFilterBufferRef *ff_null_get_audio_buffer(AVFilterLink *link, int perms, | |||||
| AVFilterBufferRef *ff_get_audio_buffer(AVFilterLink *link, int perms, | AVFilterBufferRef *ff_get_audio_buffer(AVFilterLink *link, int perms, | ||||
| int nb_samples); | int nb_samples); | ||||
| /** | |||||
| * Send a buffer of audio samples to the next filter. | |||||
| * | |||||
| * @param link the output link over which the audio samples are being sent | |||||
| * @param samplesref a reference to the buffer of audio samples being sent. The | |||||
| * receiving filter will free this reference when it no longer | |||||
| * needs it or pass it on to the next filter. | |||||
| * | |||||
| * @return >= 0 on success, a negative AVERROR on error. The receiving filter | |||||
| * is responsible for unreferencing samplesref in case of error. | |||||
| */ | |||||
| int ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref); | |||||
| #endif /* AVFILTER_AUDIO_H */ | #endif /* AVFILTER_AUDIO_H */ | ||||
| @@ -23,12 +23,16 @@ | |||||
| #include "libavutil/channel_layout.h" | #include "libavutil/channel_layout.h" | ||||
| #include "libavutil/common.h" | #include "libavutil/common.h" | ||||
| #include "libavutil/imgutils.h" | |||||
| #include "libavutil/pixdesc.h" | #include "libavutil/pixdesc.h" | ||||
| #include "libavutil/rational.h" | #include "libavutil/rational.h" | ||||
| #include "libavutil/samplefmt.h" | |||||
| #include "audio.h" | |||||
| #include "avfilter.h" | #include "avfilter.h" | ||||
| #include "formats.h" | #include "formats.h" | ||||
| #include "internal.h" | #include "internal.h" | ||||
| #include "video.h" | |||||
| unsigned avfilter_version(void) { | unsigned avfilter_version(void) { | ||||
| return LIBAVFILTER_VERSION_INT; | return LIBAVFILTER_VERSION_INT; | ||||
| @@ -446,3 +450,68 @@ enum AVMediaType avfilter_pad_get_type(AVFilterPad *pads, int pad_idx) | |||||
| { | { | ||||
| return pads[pad_idx].type; | return pads[pad_idx].type; | ||||
| } | } | ||||
| static int default_filter_frame(AVFilterLink *link, AVFilterBufferRef *frame) | |||||
| { | |||||
| return ff_filter_frame(link->dst->outputs[0], frame); | |||||
| } | |||||
| int ff_filter_frame(AVFilterLink *link, AVFilterBufferRef *frame) | |||||
| { | |||||
| int (*filter_frame)(AVFilterLink *, AVFilterBufferRef *); | |||||
| AVFilterPad *dst = link->dstpad; | |||||
| AVFilterBufferRef *out; | |||||
| int perms = frame->perms; | |||||
| FF_DPRINTF_START(NULL, filter_frame); | |||||
| ff_dlog_link(NULL, link, 1); | |||||
| if (!(filter_frame = dst->filter_frame)) | |||||
| filter_frame = default_filter_frame; | |||||
| if (frame->linesize[0] < 0) | |||||
| perms |= AV_PERM_NEG_LINESIZES; | |||||
| /* prepare to copy the frame if the buffer has insufficient permissions */ | |||||
| if ((dst->min_perms & perms) != dst->min_perms || | |||||
| dst->rej_perms & perms) { | |||||
| av_log(link->dst, AV_LOG_DEBUG, | |||||
| "Copying data in avfilter (have perms %x, need %x, reject %x)\n", | |||||
| perms, link->dstpad->min_perms, link->dstpad->rej_perms); | |||||
| switch (link->type) { | |||||
| case AVMEDIA_TYPE_VIDEO: | |||||
| out = ff_get_video_buffer(link, dst->min_perms, | |||||
| link->w, link->h); | |||||
| break; | |||||
| case AVMEDIA_TYPE_AUDIO: | |||||
| out = ff_get_audio_buffer(link, dst->min_perms, | |||||
| frame->audio->nb_samples); | |||||
| break; | |||||
| default: return AVERROR(EINVAL); | |||||
| } | |||||
| if (!out) { | |||||
| avfilter_unref_buffer(frame); | |||||
| return AVERROR(ENOMEM); | |||||
| } | |||||
| avfilter_copy_buffer_ref_props(out, frame); | |||||
| switch (link->type) { | |||||
| case AVMEDIA_TYPE_VIDEO: | |||||
| av_image_copy(out->data, out->linesize, frame->data, frame->linesize, | |||||
| frame->format, frame->video->w, frame->video->h); | |||||
| break; | |||||
| case AVMEDIA_TYPE_AUDIO: | |||||
| av_samples_copy(out->extended_data, frame->extended_data, | |||||
| 0, 0, frame->audio->nb_samples, | |||||
| av_get_channel_layout_nb_channels(frame->audio->channel_layout), | |||||
| frame->format); | |||||
| break; | |||||
| default: return AVERROR(EINVAL); | |||||
| } | |||||
| avfilter_unref_buffer(frame); | |||||
| } else | |||||
| out = frame; | |||||
| return filter_frame(link, out); | |||||
| } | |||||
| @@ -253,14 +253,7 @@ struct AVFilterPad { | |||||
| int rej_perms; | int rej_perms; | ||||
| /** | /** | ||||
| * Callback called before passing the first slice of a new frame. If | |||||
| * NULL, the filter layer will default to storing a reference to the | |||||
| * picture inside the link structure. | |||||
| * | |||||
| * Input video pads only. | |||||
| * | |||||
| * @return >= 0 on success, a negative AVERROR on error. picref will be | |||||
| * unreferenced by the caller in case of error. | |||||
| * @deprecated unused | |||||
| */ | */ | ||||
| int (*start_frame)(AVFilterLink *link, AVFilterBufferRef *picref); | int (*start_frame)(AVFilterLink *link, AVFilterBufferRef *picref); | ||||
| @@ -282,37 +275,26 @@ struct AVFilterPad { | |||||
| int nb_samples); | int nb_samples); | ||||
| /** | /** | ||||
| * Callback called after the slices of a frame are completely sent. If | |||||
| * NULL, the filter layer will default to releasing the reference stored | |||||
| * in the link structure during start_frame(). | |||||
| * | |||||
| * Input video pads only. | |||||
| * | |||||
| * @return >= 0 on success, a negative AVERROR on error. | |||||
| * @deprecated unused | |||||
| */ | */ | ||||
| int (*end_frame)(AVFilterLink *link); | int (*end_frame)(AVFilterLink *link); | ||||
| /** | /** | ||||
| * Slice drawing callback. This is where a filter receives video data | |||||
| * and should do its processing. | |||||
| * | |||||
| * Input video pads only. | |||||
| * | |||||
| * @return >= 0 on success, a negative AVERROR on error. | |||||
| * @deprecated unused | |||||
| */ | */ | ||||
| int (*draw_slice)(AVFilterLink *link, int y, int height, int slice_dir); | int (*draw_slice)(AVFilterLink *link, int y, int height, int slice_dir); | ||||
| /** | /** | ||||
| * Samples filtering callback. This is where a filter receives audio data | |||||
| * and should do its processing. | |||||
| * Filtering callback. This is where a filter receives a frame with | |||||
| * audio/video data and should do its processing. | |||||
| * | * | ||||
| * Input audio pads only. | |||||
| * Input pads only. | |||||
| * | * | ||||
| * @return >= 0 on success, a negative AVERROR on error. This function | * @return >= 0 on success, a negative AVERROR on error. This function | ||||
| * must ensure that samplesref is properly unreferenced on error if it | * must ensure that samplesref is properly unreferenced on error if it | ||||
| * hasn't been passed on to another filter. | * hasn't been passed on to another filter. | ||||
| */ | */ | ||||
| int (*filter_samples)(AVFilterLink *link, AVFilterBufferRef *samplesref); | |||||
| int (*filter_frame)(AVFilterLink *link, AVFilterBufferRef *frame); | |||||
| /** | /** | ||||
| * Frame poll callback. This returns the number of immediately available | * Frame poll callback. This returns the number of immediately available | ||||
| @@ -531,18 +513,6 @@ struct AVFilterLink { | |||||
| AVLINK_STARTINIT, ///< started, but incomplete | AVLINK_STARTINIT, ///< started, but incomplete | ||||
| AVLINK_INIT ///< complete | AVLINK_INIT ///< complete | ||||
| } init_state; | } init_state; | ||||
| /** | |||||
| * The buffer reference currently being sent across the link by the source | |||||
| * filter. This is used internally by the filter system to allow | |||||
| * automatic copying of buffers which do not have sufficient permissions | |||||
| * for the destination. This should not be accessed directly by the | |||||
| * filters. | |||||
| */ | |||||
| AVFilterBufferRef *src_buf; | |||||
| AVFilterBufferRef *cur_buf; | |||||
| AVFilterBufferRef *out_buf; | |||||
| }; | }; | ||||
| /** | /** | ||||
| @@ -48,13 +48,12 @@ static av_cold void uninit(AVFilterContext *ctx) | |||||
| av_audio_fifo_free(sink->audio_fifo); | av_audio_fifo_free(sink->audio_fifo); | ||||
| } | } | ||||
| static int start_frame(AVFilterLink *link, AVFilterBufferRef *buf) | |||||
| static int filter_frame(AVFilterLink *link, AVFilterBufferRef *buf) | |||||
| { | { | ||||
| BufferSinkContext *s = link->dst->priv; | BufferSinkContext *s = link->dst->priv; | ||||
| av_assert0(!s->cur_buf); | av_assert0(!s->cur_buf); | ||||
| s->cur_buf = buf; | s->cur_buf = buf; | ||||
| link->cur_buf = NULL; | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -144,7 +143,7 @@ static const AVFilterPad avfilter_vsink_buffer_inputs[] = { | |||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .start_frame = start_frame, | |||||
| .filter_frame = filter_frame, | |||||
| .min_perms = AV_PERM_READ, | .min_perms = AV_PERM_READ, | ||||
| .needs_fifo = 1 | .needs_fifo = 1 | ||||
| }, | }, | ||||
| @@ -165,7 +164,7 @@ static const AVFilterPad avfilter_asink_abuffer_inputs[] = { | |||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_AUDIO, | .type = AVMEDIA_TYPE_AUDIO, | ||||
| .filter_samples = start_frame, | |||||
| .filter_frame = filter_frame, | |||||
| .min_perms = AV_PERM_READ, | .min_perms = AV_PERM_READ, | ||||
| .needs_fifo = 1 | .needs_fifo = 1 | ||||
| }, | }, | ||||
| @@ -327,20 +327,7 @@ static int request_frame(AVFilterLink *link) | |||||
| } | } | ||||
| av_fifo_generic_read(c->fifo, &buf, sizeof(buf), NULL); | av_fifo_generic_read(c->fifo, &buf, sizeof(buf), NULL); | ||||
| switch (link->type) { | |||||
| case AVMEDIA_TYPE_VIDEO: | |||||
| if ((ret = ff_start_frame(link, buf)) < 0 || | |||||
| (ret = ff_draw_slice(link, 0, link->h, 1)) < 0 || | |||||
| (ret = ff_end_frame(link)) < 0) | |||||
| return ret; | |||||
| break; | |||||
| case AVMEDIA_TYPE_AUDIO: | |||||
| ret = ff_filter_samples(link, buf); | |||||
| break; | |||||
| default: | |||||
| avfilter_unref_bufferp(&buf); | |||||
| return AVERROR(EINVAL); | |||||
| } | |||||
| ff_filter_frame(link, buf); | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| @@ -77,7 +77,6 @@ static int add_to_queue(AVFilterLink *inlink, AVFilterBufferRef *buf) | |||||
| { | { | ||||
| FifoContext *fifo = inlink->dst->priv; | FifoContext *fifo = inlink->dst->priv; | ||||
| inlink->cur_buf = NULL; | |||||
| fifo->last->next = av_mallocz(sizeof(Buf)); | fifo->last->next = av_mallocz(sizeof(Buf)); | ||||
| if (!fifo->last->next) { | if (!fifo->last->next) { | ||||
| avfilter_unref_buffer(buf); | avfilter_unref_buffer(buf); | ||||
| @@ -99,16 +98,6 @@ static void queue_pop(FifoContext *s) | |||||
| s->root.next = tmp; | s->root.next = tmp; | ||||
| } | } | ||||
| static int end_frame(AVFilterLink *inlink) | |||||
| { | |||||
| return 0; | |||||
| } | |||||
| static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) | |||||
| { | |||||
| return 0; | |||||
| } | |||||
| /** | /** | ||||
| * Move data pointers and pts offset samples forward. | * Move data pointers and pts offset samples forward. | ||||
| */ | */ | ||||
| @@ -228,7 +217,7 @@ static int return_audio_frame(AVFilterContext *ctx) | |||||
| buf_out = s->buf_out; | buf_out = s->buf_out; | ||||
| s->buf_out = NULL; | s->buf_out = NULL; | ||||
| } | } | ||||
| return ff_filter_samples(link, buf_out); | |||||
| return ff_filter_frame(link, buf_out); | |||||
| } | } | ||||
| static int request_frame(AVFilterLink *outlink) | static int request_frame(AVFilterLink *outlink) | ||||
| @@ -241,27 +230,11 @@ static int request_frame(AVFilterLink *outlink) | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| /* by doing this, we give ownership of the reference to the next filter, | |||||
| * so we don't have to worry about dereferencing it ourselves. */ | |||||
| switch (outlink->type) { | |||||
| case AVMEDIA_TYPE_VIDEO: | |||||
| if ((ret = ff_start_frame(outlink, fifo->root.next->buf)) < 0 || | |||||
| (ret = ff_draw_slice(outlink, 0, outlink->h, 1)) < 0 || | |||||
| (ret = ff_end_frame(outlink)) < 0) | |||||
| return ret; | |||||
| if (outlink->request_samples) { | |||||
| return return_audio_frame(outlink->src); | |||||
| } else { | |||||
| ret = ff_filter_frame(outlink, fifo->root.next->buf); | |||||
| queue_pop(fifo); | queue_pop(fifo); | ||||
| break; | |||||
| case AVMEDIA_TYPE_AUDIO: | |||||
| if (outlink->request_samples) { | |||||
| return return_audio_frame(outlink->src); | |||||
| } else { | |||||
| ret = ff_filter_samples(outlink, fifo->root.next->buf); | |||||
| queue_pop(fifo); | |||||
| } | |||||
| break; | |||||
| default: | |||||
| return AVERROR(EINVAL); | |||||
| } | } | ||||
| return ret; | return ret; | ||||
| @@ -272,9 +245,7 @@ static const AVFilterPad avfilter_vf_fifo_inputs[] = { | |||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .get_video_buffer = ff_null_get_video_buffer, | .get_video_buffer = ff_null_get_video_buffer, | ||||
| .start_frame = add_to_queue, | |||||
| .draw_slice = draw_slice, | |||||
| .end_frame = end_frame, | |||||
| .filter_frame = add_to_queue, | |||||
| .rej_perms = AV_PERM_REUSE2, | .rej_perms = AV_PERM_REUSE2, | ||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| @@ -307,7 +278,7 @@ static const AVFilterPad avfilter_af_afifo_inputs[] = { | |||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_AUDIO, | .type = AVMEDIA_TYPE_AUDIO, | ||||
| .get_audio_buffer = ff_null_get_audio_buffer, | .get_audio_buffer = ff_null_get_audio_buffer, | ||||
| .filter_samples = add_to_queue, | |||||
| .filter_frame = add_to_queue, | |||||
| .rej_perms = AV_PERM_REUSE2, | .rej_perms = AV_PERM_REUSE2, | ||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| @@ -63,18 +63,6 @@ struct AVFilterPad { | |||||
| */ | */ | ||||
| int rej_perms; | int rej_perms; | ||||
| /** | |||||
| * Callback called before passing the first slice of a new frame. If | |||||
| * NULL, the filter layer will default to storing a reference to the | |||||
| * picture inside the link structure. | |||||
| * | |||||
| * Input video pads only. | |||||
| * | |||||
| * @return >= 0 on success, a negative AVERROR on error. picref will be | |||||
| * unreferenced by the caller in case of error. | |||||
| */ | |||||
| void (*start_frame)(AVFilterLink *link, AVFilterBufferRef *picref); | |||||
| /** | /** | ||||
| * Callback function to get a video buffer. If NULL, the filter system will | * Callback function to get a video buffer. If NULL, the filter system will | ||||
| * use avfilter_default_get_video_buffer(). | * use avfilter_default_get_video_buffer(). | ||||
| @@ -93,37 +81,16 @@ struct AVFilterPad { | |||||
| int nb_samples); | int nb_samples); | ||||
| /** | /** | ||||
| * Callback called after the slices of a frame are completely sent. If | |||||
| * NULL, the filter layer will default to releasing the reference stored | |||||
| * in the link structure during start_frame(). | |||||
| * Filtering callback. This is where a filter receives a frame with | |||||
| * audio/video data and should do its processing. | |||||
| * | * | ||||
| * Input video pads only. | |||||
| * | |||||
| * @return >= 0 on success, a negative AVERROR on error. | |||||
| */ | |||||
| int (*end_frame)(AVFilterLink *link); | |||||
| /** | |||||
| * Slice drawing callback. This is where a filter receives video data | |||||
| * and should do its processing. | |||||
| * | |||||
| * Input video pads only. | |||||
| * | |||||
| * @return >= 0 on success, a negative AVERROR on error. | |||||
| */ | |||||
| int (*draw_slice)(AVFilterLink *link, int y, int height, int slice_dir); | |||||
| /** | |||||
| * Samples filtering callback. This is where a filter receives audio data | |||||
| * and should do its processing. | |||||
| * | |||||
| * Input audio pads only. | |||||
| * Input pads only. | |||||
| * | * | ||||
| * @return >= 0 on success, a negative AVERROR on error. This function | * @return >= 0 on success, a negative AVERROR on error. This function | ||||
| * must ensure that samplesref is properly unreferenced on error if it | * must ensure that samplesref is properly unreferenced on error if it | ||||
| * hasn't been passed on to another filter. | * hasn't been passed on to another filter. | ||||
| */ | */ | ||||
| int (*filter_samples)(AVFilterLink *link, AVFilterBufferRef *samplesref); | |||||
| int (*filter_frame)(AVFilterLink *link, AVFilterBufferRef *frame); | |||||
| /** | /** | ||||
| * Frame poll callback. This returns the number of immediately available | * Frame poll callback. This returns the number of immediately available | ||||
| @@ -237,4 +204,17 @@ int ff_poll_frame(AVFilterLink *link); | |||||
| */ | */ | ||||
| int ff_request_frame(AVFilterLink *link); | int ff_request_frame(AVFilterLink *link); | ||||
| /** | |||||
| * Send a frame of data to the next filter. | |||||
| * | |||||
| * @param link the output link over which the data is being sent | |||||
| * @param frame a reference to the buffer of data being sent. The | |||||
| * receiving filter will free this reference when it no longer | |||||
| * needs it or pass it on to the next filter. | |||||
| * | |||||
| * @return >= 0 on success, a negative AVERROR on error. The receiving filter | |||||
| * is responsible for unreferencing frame in case of error. | |||||
| */ | |||||
| int ff_filter_frame(AVFilterLink *link, AVFilterBufferRef *frame); | |||||
| #endif /* AVFILTER_INTERNAL_H */ | #endif /* AVFILTER_INTERNAL_H */ | ||||
| @@ -67,46 +67,23 @@ static void split_uninit(AVFilterContext *ctx) | |||||
| av_freep(&ctx->output_pads[i].name); | av_freep(&ctx->output_pads[i].name); | ||||
| } | } | ||||
| static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame) | |||||
| { | { | ||||
| AVFilterContext *ctx = inlink->dst; | AVFilterContext *ctx = inlink->dst; | ||||
| int i, ret = 0; | int i, ret = 0; | ||||
| for (i = 0; i < ctx->nb_outputs; i++) { | for (i = 0; i < ctx->nb_outputs; i++) { | ||||
| AVFilterBufferRef *buf_out = avfilter_ref_buffer(picref, ~AV_PERM_WRITE); | |||||
| if (!buf_out) | |||||
| return AVERROR(ENOMEM); | |||||
| ret = ff_start_frame(ctx->outputs[i], buf_out); | |||||
| if (ret < 0) | |||||
| break; | |||||
| } | |||||
| return ret; | |||||
| } | |||||
| static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) | |||||
| { | |||||
| AVFilterContext *ctx = inlink->dst; | |||||
| int i, ret = 0; | |||||
| for (i = 0; i < ctx->nb_outputs; i++) { | |||||
| ret = ff_draw_slice(ctx->outputs[i], y, h, slice_dir); | |||||
| if (ret < 0) | |||||
| AVFilterBufferRef *buf_out = avfilter_ref_buffer(frame, ~AV_PERM_WRITE); | |||||
| if (!buf_out) { | |||||
| ret = AVERROR(ENOMEM); | |||||
| break; | break; | ||||
| } | |||||
| return ret; | |||||
| } | |||||
| static int end_frame(AVFilterLink *inlink) | |||||
| { | |||||
| AVFilterContext *ctx = inlink->dst; | |||||
| int i, ret = 0; | |||||
| } | |||||
| for (i = 0; i < ctx->nb_outputs; i++) { | |||||
| ret = ff_end_frame(ctx->outputs[i]); | |||||
| ret = ff_filter_frame(ctx->outputs[i], buf_out); | |||||
| if (ret < 0) | if (ret < 0) | ||||
| break; | break; | ||||
| } | } | ||||
| avfilter_unref_bufferp(&frame); | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| @@ -115,9 +92,7 @@ static const AVFilterPad avfilter_vf_split_inputs[] = { | |||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .get_video_buffer = ff_null_get_video_buffer, | .get_video_buffer = ff_null_get_video_buffer, | ||||
| .start_frame = start_frame, | |||||
| .draw_slice = draw_slice, | |||||
| .end_frame = end_frame, | |||||
| .filter_frame = filter_frame, | |||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| }; | }; | ||||
| @@ -133,33 +108,12 @@ AVFilter avfilter_vf_split = { | |||||
| .outputs = NULL, | .outputs = NULL, | ||||
| }; | }; | ||||
| static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *samplesref) | |||||
| { | |||||
| AVFilterContext *ctx = inlink->dst; | |||||
| int i, ret = 0; | |||||
| for (i = 0; i < ctx->nb_outputs; i++) { | |||||
| AVFilterBufferRef *buf_out = avfilter_ref_buffer(samplesref, | |||||
| ~AV_PERM_WRITE); | |||||
| if (!buf_out) { | |||||
| ret = AVERROR(ENOMEM); | |||||
| break; | |||||
| } | |||||
| ret = ff_filter_samples(inlink->dst->outputs[i], buf_out); | |||||
| if (ret < 0) | |||||
| break; | |||||
| } | |||||
| avfilter_unref_buffer(samplesref); | |||||
| return ret; | |||||
| } | |||||
| static const AVFilterPad avfilter_af_asplit_inputs[] = { | static const AVFilterPad avfilter_af_asplit_inputs[] = { | ||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_AUDIO, | .type = AVMEDIA_TYPE_AUDIO, | ||||
| .get_audio_buffer = ff_null_get_audio_buffer, | .get_audio_buffer = ff_null_get_audio_buffer, | ||||
| .filter_samples = filter_samples | |||||
| .filter_frame = filter_frame, | |||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| }; | }; | ||||
| @@ -65,13 +65,12 @@ static av_cold int init(AVFilterContext *ctx, const char *args) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int start_frame(AVFilterLink *link, AVFilterBufferRef *picref) | |||||
| static int filter_frame(AVFilterLink *link, AVFilterBufferRef *frame) | |||||
| { | { | ||||
| AspectContext *aspect = link->dst->priv; | AspectContext *aspect = link->dst->priv; | ||||
| picref->video->pixel_aspect = aspect->aspect; | |||||
| link->cur_buf = NULL; | |||||
| return ff_start_frame(link->dst->outputs[0], picref); | |||||
| frame->video->pixel_aspect = aspect->aspect; | |||||
| return ff_filter_frame(link->dst->outputs[0], frame); | |||||
| } | } | ||||
| #if CONFIG_SETDAR_FILTER | #if CONFIG_SETDAR_FILTER | ||||
| @@ -99,8 +98,7 @@ static const AVFilterPad avfilter_vf_setdar_inputs[] = { | |||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .config_props = setdar_config_props, | .config_props = setdar_config_props, | ||||
| .get_video_buffer = ff_null_get_video_buffer, | .get_video_buffer = ff_null_get_video_buffer, | ||||
| .start_frame = start_frame, | |||||
| .end_frame = ff_null_end_frame | |||||
| .filter_frame = filter_frame, | |||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| }; | }; | ||||
| @@ -144,8 +142,7 @@ static const AVFilterPad avfilter_vf_setsar_inputs[] = { | |||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .config_props = setsar_config_props, | .config_props = setsar_config_props, | ||||
| .get_video_buffer = ff_null_get_video_buffer, | .get_video_buffer = ff_null_get_video_buffer, | ||||
| .start_frame = start_frame, | |||||
| .end_frame = ff_null_end_frame | |||||
| .filter_frame = filter_frame, | |||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| }; | }; | ||||
| @@ -78,49 +78,37 @@ static av_cold int init(AVFilterContext *ctx, const char *args) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame) | |||||
| { | { | ||||
| AVFilterContext *ctx = inlink->dst; | AVFilterContext *ctx = inlink->dst; | ||||
| BlackFrameContext *blackframe = ctx->priv; | BlackFrameContext *blackframe = ctx->priv; | ||||
| AVFilterBufferRef *picref = inlink->cur_buf; | |||||
| int x, i; | int x, i; | ||||
| uint8_t *p = picref->data[0] + y * picref->linesize[0]; | |||||
| int pblack = 0; | |||||
| uint8_t *p = frame->data[0]; | |||||
| for (i = 0; i < h; i++) { | |||||
| for (i = 0; i < frame->video->h; i++) { | |||||
| for (x = 0; x < inlink->w; x++) | for (x = 0; x < inlink->w; x++) | ||||
| blackframe->nblack += p[x] < blackframe->bthresh; | blackframe->nblack += p[x] < blackframe->bthresh; | ||||
| p += picref->linesize[0]; | |||||
| p += frame->linesize[0]; | |||||
| } | } | ||||
| return ff_draw_slice(ctx->outputs[0], y, h, slice_dir); | |||||
| } | |||||
| static int end_frame(AVFilterLink *inlink) | |||||
| { | |||||
| AVFilterContext *ctx = inlink->dst; | |||||
| BlackFrameContext *blackframe = ctx->priv; | |||||
| AVFilterBufferRef *picref = inlink->cur_buf; | |||||
| int pblack = 0; | |||||
| pblack = blackframe->nblack * 100 / (inlink->w * inlink->h); | pblack = blackframe->nblack * 100 / (inlink->w * inlink->h); | ||||
| if (pblack >= blackframe->bamount) | if (pblack >= blackframe->bamount) | ||||
| av_log(ctx, AV_LOG_INFO, "frame:%u pblack:%u pos:%"PRId64" pts:%"PRId64" t:%f\n", | av_log(ctx, AV_LOG_INFO, "frame:%u pblack:%u pos:%"PRId64" pts:%"PRId64" t:%f\n", | ||||
| blackframe->frame, pblack, picref->pos, picref->pts, | |||||
| picref->pts == AV_NOPTS_VALUE ? -1 : picref->pts * av_q2d(inlink->time_base)); | |||||
| blackframe->frame, pblack, frame->pos, frame->pts, | |||||
| frame->pts == AV_NOPTS_VALUE ? -1 : frame->pts * av_q2d(inlink->time_base)); | |||||
| blackframe->frame++; | blackframe->frame++; | ||||
| blackframe->nblack = 0; | blackframe->nblack = 0; | ||||
| return ff_end_frame(inlink->dst->outputs[0]); | |||||
| return ff_filter_frame(inlink->dst->outputs[0], frame); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_blackframe_inputs[] = { | static const AVFilterPad avfilter_vf_blackframe_inputs[] = { | ||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .draw_slice = draw_slice, | |||||
| .get_video_buffer = ff_null_get_video_buffer, | .get_video_buffer = ff_null_get_video_buffer, | ||||
| .start_frame = ff_null_start_frame, | |||||
| .end_frame = end_frame, | |||||
| .filter_frame = filter_frame, | |||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| }; | }; | ||||
| @@ -307,31 +307,39 @@ static void vblur(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_li | |||||
| h, radius, power, temp); | h, radius, power, temp); | ||||
| } | } | ||||
| static int draw_slice(AVFilterLink *inlink, int y0, int h0, int slice_dir) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in) | |||||
| { | { | ||||
| AVFilterContext *ctx = inlink->dst; | AVFilterContext *ctx = inlink->dst; | ||||
| BoxBlurContext *boxblur = ctx->priv; | BoxBlurContext *boxblur = ctx->priv; | ||||
| AVFilterLink *outlink = inlink->dst->outputs[0]; | AVFilterLink *outlink = inlink->dst->outputs[0]; | ||||
| AVFilterBufferRef *inpicref = inlink ->cur_buf; | |||||
| AVFilterBufferRef *outpicref = outlink->out_buf; | |||||
| AVFilterBufferRef *out; | |||||
| int plane; | int plane; | ||||
| int cw = inlink->w >> boxblur->hsub, ch = h0 >> boxblur->vsub; | |||||
| int cw = inlink->w >> boxblur->hsub, ch = in->video->h >> boxblur->vsub; | |||||
| int w[4] = { inlink->w, cw, cw, inlink->w }; | int w[4] = { inlink->w, cw, cw, inlink->w }; | ||||
| int h[4] = { h0, ch, ch, h0 }; | |||||
| int h[4] = { in->video->h, ch, ch, in->video->h }; | |||||
| for (plane = 0; inpicref->data[plane] && plane < 4; plane++) | |||||
| hblur(outpicref->data[plane], outpicref->linesize[plane], | |||||
| inpicref ->data[plane], inpicref ->linesize[plane], | |||||
| out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); | |||||
| if (!out) { | |||||
| avfilter_unref_bufferp(&in); | |||||
| return AVERROR(ENOMEM); | |||||
| } | |||||
| avfilter_copy_buffer_ref_props(out, in); | |||||
| for (plane = 0; in->data[plane] && plane < 4; plane++) | |||||
| hblur(out->data[plane], out->linesize[plane], | |||||
| in ->data[plane], in ->linesize[plane], | |||||
| w[plane], h[plane], boxblur->radius[plane], boxblur->power[plane], | w[plane], h[plane], boxblur->radius[plane], boxblur->power[plane], | ||||
| boxblur->temp); | boxblur->temp); | ||||
| for (plane = 0; inpicref->data[plane] && plane < 4; plane++) | |||||
| vblur(outpicref->data[plane], outpicref->linesize[plane], | |||||
| outpicref->data[plane], outpicref->linesize[plane], | |||||
| for (plane = 0; in->data[plane] && plane < 4; plane++) | |||||
| vblur(out->data[plane], out->linesize[plane], | |||||
| out->data[plane], out->linesize[plane], | |||||
| w[plane], h[plane], boxblur->radius[plane], boxblur->power[plane], | w[plane], h[plane], boxblur->radius[plane], boxblur->power[plane], | ||||
| boxblur->temp); | boxblur->temp); | ||||
| return ff_draw_slice(outlink, y0, h0, slice_dir); | |||||
| avfilter_unref_bufferp(&in); | |||||
| return ff_filter_frame(outlink, out); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_boxblur_inputs[] = { | static const AVFilterPad avfilter_vf_boxblur_inputs[] = { | ||||
| @@ -339,7 +347,7 @@ static const AVFilterPad avfilter_vf_boxblur_inputs[] = { | |||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .config_props = config_input, | .config_props = config_input, | ||||
| .draw_slice = draw_slice, | |||||
| .filter_frame = filter_frame, | |||||
| .min_perms = AV_PERM_READ | .min_perms = AV_PERM_READ | ||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| @@ -31,8 +31,6 @@ static const AVFilterPad avfilter_vf_copy_inputs[] = { | |||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .get_video_buffer = ff_null_get_video_buffer, | .get_video_buffer = ff_null_get_video_buffer, | ||||
| .start_frame = ff_null_start_frame, | |||||
| .end_frame = ff_null_end_frame, | |||||
| .rej_perms = ~0 | .rej_perms = ~0 | ||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| @@ -243,24 +243,19 @@ static int config_output(AVFilterLink *link) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int start_frame(AVFilterLink *link, AVFilterBufferRef *picref) | |||||
| static int filter_frame(AVFilterLink *link, AVFilterBufferRef *frame) | |||||
| { | { | ||||
| AVFilterContext *ctx = link->dst; | AVFilterContext *ctx = link->dst; | ||||
| CropContext *crop = ctx->priv; | CropContext *crop = ctx->priv; | ||||
| AVFilterBufferRef *ref2; | |||||
| const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format); | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format); | ||||
| int i; | int i; | ||||
| ref2 = avfilter_ref_buffer(picref, ~0); | |||||
| if (!ref2) | |||||
| return AVERROR(ENOMEM); | |||||
| frame->video->w = crop->w; | |||||
| frame->video->h = crop->h; | |||||
| ref2->video->w = crop->w; | |||||
| ref2->video->h = crop->h; | |||||
| crop->var_values[VAR_T] = picref->pts == AV_NOPTS_VALUE ? | |||||
| NAN : picref->pts * av_q2d(link->time_base); | |||||
| crop->var_values[VAR_POS] = picref->pos == -1 ? NAN : picref->pos; | |||||
| crop->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ? | |||||
| NAN : frame->pts * av_q2d(link->time_base); | |||||
| crop->var_values[VAR_POS] = frame->pos == -1 ? NAN : frame->pos; | |||||
| crop->var_values[VAR_X] = av_expr_eval(crop->x_pexpr, crop->var_values, NULL); | crop->var_values[VAR_X] = av_expr_eval(crop->x_pexpr, crop->var_values, NULL); | ||||
| crop->var_values[VAR_Y] = av_expr_eval(crop->y_pexpr, crop->var_values, NULL); | crop->var_values[VAR_Y] = av_expr_eval(crop->y_pexpr, crop->var_values, NULL); | ||||
| crop->var_values[VAR_X] = av_expr_eval(crop->x_pexpr, crop->var_values, NULL); | crop->var_values[VAR_X] = av_expr_eval(crop->x_pexpr, crop->var_values, NULL); | ||||
| @@ -279,60 +274,34 @@ static int start_frame(AVFilterLink *link, AVFilterBufferRef *picref) | |||||
| (int)crop->var_values[VAR_N], crop->var_values[VAR_T], crop->x, | (int)crop->var_values[VAR_N], crop->var_values[VAR_T], crop->x, | ||||
| crop->y, crop->x+crop->w, crop->y+crop->h); | crop->y, crop->x+crop->w, crop->y+crop->h); | ||||
| ref2->data[0] += crop->y * ref2->linesize[0]; | |||||
| ref2->data[0] += crop->x * crop->max_step[0]; | |||||
| frame->data[0] += crop->y * frame->linesize[0]; | |||||
| frame->data[0] += crop->x * crop->max_step[0]; | |||||
| if (!(desc->flags & PIX_FMT_PAL || desc->flags & PIX_FMT_PSEUDOPAL)) { | if (!(desc->flags & PIX_FMT_PAL || desc->flags & PIX_FMT_PSEUDOPAL)) { | ||||
| for (i = 1; i < 3; i ++) { | for (i = 1; i < 3; i ++) { | ||||
| if (ref2->data[i]) { | |||||
| ref2->data[i] += (crop->y >> crop->vsub) * ref2->linesize[i]; | |||||
| ref2->data[i] += (crop->x * crop->max_step[i]) >> crop->hsub; | |||||
| if (frame->data[i]) { | |||||
| frame->data[i] += (crop->y >> crop->vsub) * frame->linesize[i]; | |||||
| frame->data[i] += (crop->x * crop->max_step[i]) >> crop->hsub; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* alpha plane */ | /* alpha plane */ | ||||
| if (ref2->data[3]) { | |||||
| ref2->data[3] += crop->y * ref2->linesize[3]; | |||||
| ref2->data[3] += crop->x * crop->max_step[3]; | |||||
| if (frame->data[3]) { | |||||
| frame->data[3] += crop->y * frame->linesize[3]; | |||||
| frame->data[3] += crop->x * crop->max_step[3]; | |||||
| } | } | ||||
| return ff_start_frame(link->dst->outputs[0], ref2); | |||||
| } | |||||
| static int draw_slice(AVFilterLink *link, int y, int h, int slice_dir) | |||||
| { | |||||
| AVFilterContext *ctx = link->dst; | |||||
| CropContext *crop = ctx->priv; | |||||
| if (y >= crop->y + crop->h || y + h <= crop->y) | |||||
| return 0; | |||||
| if (y < crop->y) { | |||||
| h -= crop->y - y; | |||||
| y = crop->y; | |||||
| } | |||||
| if (y + h > crop->y + crop->h) | |||||
| h = crop->y + crop->h - y; | |||||
| return ff_draw_slice(ctx->outputs[0], y - crop->y, h, slice_dir); | |||||
| } | |||||
| static int end_frame(AVFilterLink *link) | |||||
| { | |||||
| CropContext *crop = link->dst->priv; | |||||
| crop->var_values[VAR_N] += 1.0; | crop->var_values[VAR_N] += 1.0; | ||||
| return ff_end_frame(link->dst->outputs[0]); | |||||
| return ff_filter_frame(link->dst->outputs[0], frame); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_crop_inputs[] = { | static const AVFilterPad avfilter_vf_crop_inputs[] = { | ||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .start_frame = start_frame, | |||||
| .draw_slice = draw_slice, | |||||
| .end_frame = end_frame, | |||||
| .filter_frame = filter_frame, | |||||
| .get_video_buffer = ff_null_get_video_buffer, | .get_video_buffer = ff_null_get_video_buffer, | ||||
| .config_props = config_input, | .config_props = config_input, | ||||
| }, | }, | ||||
| @@ -117,11 +117,10 @@ static int config_input(AVFilterLink *inlink) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int end_frame(AVFilterLink *inlink) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame) | |||||
| { | { | ||||
| AVFilterContext *ctx = inlink->dst; | AVFilterContext *ctx = inlink->dst; | ||||
| CropDetectContext *cd = ctx->priv; | CropDetectContext *cd = ctx->priv; | ||||
| AVFilterBufferRef *picref = inlink->cur_buf; | |||||
| int bpp = cd->max_pixsteps[0]; | int bpp = cd->max_pixsteps[0]; | ||||
| int w, h, x, y, shrink_by; | int w, h, x, y, shrink_by; | ||||
| @@ -129,36 +128,36 @@ static int end_frame(AVFilterLink *inlink) | |||||
| if (++cd->frame_nb > 0) { | if (++cd->frame_nb > 0) { | ||||
| // Reset the crop area every reset_count frames, if reset_count is > 0 | // Reset the crop area every reset_count frames, if reset_count is > 0 | ||||
| if (cd->reset_count > 0 && cd->frame_nb > cd->reset_count) { | if (cd->reset_count > 0 && cd->frame_nb > cd->reset_count) { | ||||
| cd->x1 = picref->video->w-1; | |||||
| cd->y1 = picref->video->h-1; | |||||
| cd->x1 = frame->video->w-1; | |||||
| cd->y1 = frame->video->h-1; | |||||
| cd->x2 = 0; | cd->x2 = 0; | ||||
| cd->y2 = 0; | cd->y2 = 0; | ||||
| cd->frame_nb = 1; | cd->frame_nb = 1; | ||||
| } | } | ||||
| for (y = 0; y < cd->y1; y++) { | for (y = 0; y < cd->y1; y++) { | ||||
| if (checkline(ctx, picref->data[0] + picref->linesize[0] * y, bpp, picref->video->w, bpp) > cd->limit) { | |||||
| if (checkline(ctx, frame->data[0] + frame->linesize[0] * y, bpp, frame->video->w, bpp) > cd->limit) { | |||||
| cd->y1 = y; | cd->y1 = y; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| for (y = picref->video->h-1; y > cd->y2; y--) { | |||||
| if (checkline(ctx, picref->data[0] + picref->linesize[0] * y, bpp, picref->video->w, bpp) > cd->limit) { | |||||
| for (y = frame->video->h-1; y > cd->y2; y--) { | |||||
| if (checkline(ctx, frame->data[0] + frame->linesize[0] * y, bpp, frame->video->w, bpp) > cd->limit) { | |||||
| cd->y2 = y; | cd->y2 = y; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| for (y = 0; y < cd->x1; y++) { | for (y = 0; y < cd->x1; y++) { | ||||
| if (checkline(ctx, picref->data[0] + bpp*y, picref->linesize[0], picref->video->h, bpp) > cd->limit) { | |||||
| if (checkline(ctx, frame->data[0] + bpp*y, frame->linesize[0], frame->video->h, bpp) > cd->limit) { | |||||
| cd->x1 = y; | cd->x1 = y; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| for (y = picref->video->w-1; y > cd->x2; y--) { | |||||
| if (checkline(ctx, picref->data[0] + bpp*y, picref->linesize[0], picref->video->h, bpp) > cd->limit) { | |||||
| for (y = frame->video->w-1; y > cd->x2; y--) { | |||||
| if (checkline(ctx, frame->data[0] + bpp*y, frame->linesize[0], frame->video->h, bpp) > cd->limit) { | |||||
| cd->x2 = y; | cd->x2 = y; | ||||
| break; | break; | ||||
| } | } | ||||
| @@ -189,12 +188,12 @@ static int end_frame(AVFilterLink *inlink) | |||||
| av_log(ctx, AV_LOG_INFO, | av_log(ctx, AV_LOG_INFO, | ||||
| "x1:%d x2:%d y1:%d y2:%d w:%d h:%d x:%d y:%d pos:%"PRId64" pts:%"PRId64" t:%f crop=%d:%d:%d:%d\n", | "x1:%d x2:%d y1:%d y2:%d w:%d h:%d x:%d y:%d pos:%"PRId64" pts:%"PRId64" t:%f crop=%d:%d:%d:%d\n", | ||||
| cd->x1, cd->x2, cd->y1, cd->y2, w, h, x, y, picref->pos, picref->pts, | |||||
| picref->pts == AV_NOPTS_VALUE ? -1 : picref->pts * av_q2d(inlink->time_base), | |||||
| cd->x1, cd->x2, cd->y1, cd->y2, w, h, x, y, frame->pos, frame->pts, | |||||
| frame->pts == AV_NOPTS_VALUE ? -1 : frame->pts * av_q2d(inlink->time_base), | |||||
| w, h, x, y); | w, h, x, y); | ||||
| } | } | ||||
| return ff_end_frame(inlink->dst->outputs[0]); | |||||
| return ff_filter_frame(inlink->dst->outputs[0], frame); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_cropdetect_inputs[] = { | static const AVFilterPad avfilter_vf_cropdetect_inputs[] = { | ||||
| @@ -203,8 +202,7 @@ static const AVFilterPad avfilter_vf_cropdetect_inputs[] = { | |||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .config_props = config_input, | .config_props = config_input, | ||||
| .get_video_buffer = ff_null_get_video_buffer, | .get_video_buffer = ff_null_get_video_buffer, | ||||
| .start_frame = ff_null_start_frame, | |||||
| .end_frame = end_frame, | |||||
| .filter_frame = filter_frame, | |||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| }; | }; | ||||
| @@ -215,30 +215,38 @@ static av_cold int init(AVFilterContext *ctx, const char *args) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) | |||||
| { | |||||
| return 0; | |||||
| } | |||||
| static int end_frame(AVFilterLink *inlink) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in) | |||||
| { | { | ||||
| DelogoContext *delogo = inlink->dst->priv; | DelogoContext *delogo = inlink->dst->priv; | ||||
| AVFilterLink *outlink = inlink->dst->outputs[0]; | AVFilterLink *outlink = inlink->dst->outputs[0]; | ||||
| AVFilterBufferRef *inpicref = inlink ->cur_buf; | |||||
| AVFilterBufferRef *outpicref = outlink->out_buf; | |||||
| const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); | ||||
| int direct = inpicref->buf == outpicref->buf; | |||||
| AVFilterBufferRef *out; | |||||
| int hsub0 = desc->log2_chroma_w; | int hsub0 = desc->log2_chroma_w; | ||||
| int vsub0 = desc->log2_chroma_h; | int vsub0 = desc->log2_chroma_h; | ||||
| int direct; | |||||
| int plane; | int plane; | ||||
| int ret; | |||||
| for (plane = 0; plane < 4 && inpicref->data[plane]; plane++) { | |||||
| if ((in->perms & AV_PERM_WRITE) && !(in->perms & AV_PERM_PRESERVE)) { | |||||
| direct = 1; | |||||
| out = in; | |||||
| } else { | |||||
| out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); | |||||
| if (!out) { | |||||
| avfilter_unref_bufferp(&in); | |||||
| return AVERROR(ENOMEM); | |||||
| } | |||||
| avfilter_copy_buffer_ref_props(out, in); | |||||
| out->video->w = outlink->w; | |||||
| out->video->h = outlink->h; | |||||
| } | |||||
| for (plane = 0; plane < 4 && in->data[plane]; plane++) { | |||||
| int hsub = plane == 1 || plane == 2 ? hsub0 : 0; | int hsub = plane == 1 || plane == 2 ? hsub0 : 0; | ||||
| int vsub = plane == 1 || plane == 2 ? vsub0 : 0; | int vsub = plane == 1 || plane == 2 ? vsub0 : 0; | ||||
| apply_delogo(outpicref->data[plane], outpicref->linesize[plane], | |||||
| inpicref ->data[plane], inpicref ->linesize[plane], | |||||
| apply_delogo(out->data[plane], out->linesize[plane], | |||||
| in ->data[plane], in ->linesize[plane], | |||||
| inlink->w>>hsub, inlink->h>>vsub, | inlink->w>>hsub, inlink->h>>vsub, | ||||
| delogo->x>>hsub, delogo->y>>vsub, | delogo->x>>hsub, delogo->y>>vsub, | ||||
| delogo->w>>hsub, delogo->h>>vsub, | delogo->w>>hsub, delogo->h>>vsub, | ||||
| @@ -246,10 +254,10 @@ static int end_frame(AVFilterLink *inlink) | |||||
| delogo->show, direct); | delogo->show, direct); | ||||
| } | } | ||||
| if ((ret = ff_draw_slice(outlink, 0, inlink->h, 1)) < 0 || | |||||
| (ret = ff_end_frame(outlink)) < 0) | |||||
| return ret; | |||||
| return 0; | |||||
| if (!direct) | |||||
| avfilter_unref_bufferp(&in); | |||||
| return ff_filter_frame(outlink, out); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_delogo_inputs[] = { | static const AVFilterPad avfilter_vf_delogo_inputs[] = { | ||||
| @@ -257,9 +265,7 @@ static const AVFilterPad avfilter_vf_delogo_inputs[] = { | |||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .get_video_buffer = ff_null_get_video_buffer, | .get_video_buffer = ff_null_get_video_buffer, | ||||
| .start_frame = ff_inplace_start_frame, | |||||
| .draw_slice = null_draw_slice, | |||||
| .end_frame = end_frame, | |||||
| .filter_frame = filter_frame, | |||||
| .min_perms = AV_PERM_WRITE | AV_PERM_READ, | .min_perms = AV_PERM_WRITE | AV_PERM_READ, | ||||
| .rej_perms = AV_PERM_PRESERVE | .rej_perms = AV_PERM_PRESERVE | ||||
| }, | }, | ||||
| @@ -96,21 +96,20 @@ static int config_input(AVFilterLink *inlink) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int draw_slice(AVFilterLink *inlink, int y0, int h, int slice_dir) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame) | |||||
| { | { | ||||
| DrawBoxContext *drawbox = inlink->dst->priv; | DrawBoxContext *drawbox = inlink->dst->priv; | ||||
| int plane, x, y, xb = drawbox->x, yb = drawbox->y; | int plane, x, y, xb = drawbox->x, yb = drawbox->y; | ||||
| unsigned char *row[4]; | unsigned char *row[4]; | ||||
| AVFilterBufferRef *picref = inlink->cur_buf; | |||||
| for (y = FFMAX(yb, y0); y < (y0 + h) && y < (yb + drawbox->h); y++) { | |||||
| row[0] = picref->data[0] + y * picref->linesize[0]; | |||||
| for (y = FFMAX(yb, 0); y < frame->video->h && y < (yb + drawbox->h); y++) { | |||||
| row[0] = frame->data[0] + y * frame->linesize[0]; | |||||
| for (plane = 1; plane < 3; plane++) | for (plane = 1; plane < 3; plane++) | ||||
| row[plane] = picref->data[plane] + | |||||
| picref->linesize[plane] * (y >> drawbox->vsub); | |||||
| row[plane] = frame->data[plane] + | |||||
| frame->linesize[plane] * (y >> drawbox->vsub); | |||||
| for (x = FFMAX(xb, 0); x < (xb + drawbox->w) && x < picref->video->w; x++) { | |||||
| for (x = FFMAX(xb, 0); x < (xb + drawbox->w) && x < frame->video->w; x++) { | |||||
| double alpha = (double)drawbox->yuv_color[A] / 255; | double alpha = (double)drawbox->yuv_color[A] / 255; | ||||
| if ((y - yb < 3) || (yb + drawbox->h - y < 4) || | if ((y - yb < 3) || (yb + drawbox->h - y < 4) || | ||||
| @@ -122,7 +121,7 @@ static int draw_slice(AVFilterLink *inlink, int y0, int h, int slice_dir) | |||||
| } | } | ||||
| } | } | ||||
| return ff_draw_slice(inlink->dst->outputs[0], y0, h, 1); | |||||
| return ff_filter_frame(inlink->dst->outputs[0], frame); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_drawbox_inputs[] = { | static const AVFilterPad avfilter_vf_drawbox_inputs[] = { | ||||
| @@ -131,9 +130,7 @@ static const AVFilterPad avfilter_vf_drawbox_inputs[] = { | |||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .config_props = config_input, | .config_props = config_input, | ||||
| .get_video_buffer = ff_null_get_video_buffer, | .get_video_buffer = ff_null_get_video_buffer, | ||||
| .start_frame = ff_null_start_frame, | |||||
| .draw_slice = draw_slice, | |||||
| .end_frame = ff_null_end_frame, | |||||
| .filter_frame = filter_frame, | |||||
| .min_perms = AV_PERM_WRITE | AV_PERM_READ, | .min_perms = AV_PERM_WRITE | AV_PERM_READ, | ||||
| .rej_perms = AV_PERM_PRESERVE | .rej_perms = AV_PERM_PRESERVE | ||||
| }, | }, | ||||
| @@ -792,11 +792,6 @@ static int draw_text(AVFilterContext *ctx, AVFilterBufferRef *picref, | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) | |||||
| { | |||||
| return 0; | |||||
| } | |||||
| static inline int normalize_double(int *n, double d) | static inline int normalize_double(int *n, double d) | ||||
| { | { | ||||
| int ret = 0; | int ret = 0; | ||||
| @@ -812,20 +807,20 @@ static inline int normalize_double(int *n, double d) | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame) | |||||
| { | { | ||||
| AVFilterContext *ctx = inlink->dst; | AVFilterContext *ctx = inlink->dst; | ||||
| DrawTextContext *dtext = ctx->priv; | DrawTextContext *dtext = ctx->priv; | ||||
| AVFilterBufferRef *buf_out; | |||||
| int ret = 0; | int ret = 0; | ||||
| if ((ret = dtext_prepare_text(ctx)) < 0) { | if ((ret = dtext_prepare_text(ctx)) < 0) { | ||||
| av_log(ctx, AV_LOG_ERROR, "Can't draw text\n"); | av_log(ctx, AV_LOG_ERROR, "Can't draw text\n"); | ||||
| avfilter_unref_bufferp(&frame); | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| dtext->var_values[VAR_T] = inpicref->pts == AV_NOPTS_VALUE ? | |||||
| NAN : inpicref->pts * av_q2d(inlink->time_base); | |||||
| dtext->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ? | |||||
| NAN : frame->pts * av_q2d(inlink->time_base); | |||||
| dtext->var_values[VAR_X] = | dtext->var_values[VAR_X] = | ||||
| av_expr_eval(dtext->x_pexpr, dtext->var_values, &dtext->prng); | av_expr_eval(dtext->x_pexpr, dtext->var_values, &dtext->prng); | ||||
| dtext->var_values[VAR_Y] = | dtext->var_values[VAR_Y] = | ||||
| @@ -854,29 +849,12 @@ static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref) | |||||
| (int)dtext->var_values[VAR_N], dtext->var_values[VAR_T], | (int)dtext->var_values[VAR_N], dtext->var_values[VAR_T], | ||||
| dtext->x, dtext->y, dtext->x+dtext->w, dtext->y+dtext->h); | dtext->x, dtext->y, dtext->x+dtext->w, dtext->y+dtext->h); | ||||
| buf_out = avfilter_ref_buffer(inpicref, ~0); | |||||
| if (!buf_out) | |||||
| return AVERROR(ENOMEM); | |||||
| return ff_start_frame(inlink->dst->outputs[0], buf_out); | |||||
| } | |||||
| static int end_frame(AVFilterLink *inlink) | |||||
| { | |||||
| AVFilterLink *outlink = inlink->dst->outputs[0]; | |||||
| AVFilterBufferRef *picref = inlink->cur_buf; | |||||
| DrawTextContext *dtext = inlink->dst->priv; | |||||
| int ret; | |||||
| if (dtext->draw) | if (dtext->draw) | ||||
| draw_text(inlink->dst, picref, picref->video->w, picref->video->h); | |||||
| draw_text(inlink->dst, frame, frame->video->w, frame->video->h); | |||||
| dtext->var_values[VAR_N] += 1.0; | dtext->var_values[VAR_N] += 1.0; | ||||
| if ((ret = ff_draw_slice(outlink, 0, picref->video->h, 1)) < 0 || | |||||
| (ret = ff_end_frame(outlink)) < 0) | |||||
| return ret; | |||||
| return 0; | |||||
| return ff_filter_frame(inlink->dst->outputs[0], frame); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_drawtext_inputs[] = { | static const AVFilterPad avfilter_vf_drawtext_inputs[] = { | ||||
| @@ -884,9 +862,7 @@ static const AVFilterPad avfilter_vf_drawtext_inputs[] = { | |||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .get_video_buffer = ff_null_get_video_buffer, | .get_video_buffer = ff_null_get_video_buffer, | ||||
| .start_frame = start_frame, | |||||
| .draw_slice = null_draw_slice, | |||||
| .end_frame = end_frame, | |||||
| .filter_frame = filter_frame, | |||||
| .config_props = config_input, | .config_props = config_input, | ||||
| .min_perms = AV_PERM_WRITE | | .min_perms = AV_PERM_WRITE | | ||||
| AV_PERM_READ, | AV_PERM_READ, | ||||
| @@ -98,17 +98,16 @@ static int config_props(AVFilterLink *inlink) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame) | |||||
| { | { | ||||
| FadeContext *fade = inlink->dst->priv; | FadeContext *fade = inlink->dst->priv; | ||||
| AVFilterBufferRef *outpic = inlink->cur_buf; | |||||
| uint8_t *p; | uint8_t *p; | ||||
| int i, j, plane; | int i, j, plane; | ||||
| if (fade->factor < UINT16_MAX) { | if (fade->factor < UINT16_MAX) { | ||||
| /* luma or rgb plane */ | /* luma or rgb plane */ | ||||
| for (i = 0; i < h; i++) { | |||||
| p = outpic->data[0] + (y+i) * outpic->linesize[0]; | |||||
| for (i = 0; i < frame->video->h; i++) { | |||||
| p = frame->data[0] + i * frame->linesize[0]; | |||||
| for (j = 0; j < inlink->w * fade->bpp; j++) { | for (j = 0; j < inlink->w * fade->bpp; j++) { | ||||
| /* fade->factor is using 16 lower-order bits for decimal | /* fade->factor is using 16 lower-order bits for decimal | ||||
| * places. 32768 = 1 << 15, it is an integer representation | * places. 32768 = 1 << 15, it is an integer representation | ||||
| @@ -118,11 +117,11 @@ static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) | |||||
| } | } | ||||
| } | } | ||||
| if (outpic->data[1] && outpic->data[2]) { | |||||
| if (frame->data[1] && frame->data[2]) { | |||||
| /* chroma planes */ | /* chroma planes */ | ||||
| for (plane = 1; plane < 3; plane++) { | for (plane = 1; plane < 3; plane++) { | ||||
| for (i = 0; i < h; i++) { | |||||
| p = outpic->data[plane] + ((y+i) >> fade->vsub) * outpic->linesize[plane]; | |||||
| for (i = 0; i < frame->video->h; i++) { | |||||
| p = frame->data[plane] + (i >> fade->vsub) * frame->linesize[plane]; | |||||
| for (j = 0; j < inlink->w >> fade->hsub; j++) { | for (j = 0; j < inlink->w >> fade->hsub; j++) { | ||||
| /* 8421367 = ((128 << 1) + 1) << 15. It is an integer | /* 8421367 = ((128 << 1) + 1) << 15. It is an integer | ||||
| * representation of 128.5. The .5 is for rounding | * representation of 128.5. The .5 is for rounding | ||||
| @@ -135,23 +134,13 @@ static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) | |||||
| } | } | ||||
| } | } | ||||
| return ff_draw_slice(inlink->dst->outputs[0], y, h, slice_dir); | |||||
| } | |||||
| static int end_frame(AVFilterLink *inlink) | |||||
| { | |||||
| FadeContext *fade = inlink->dst->priv; | |||||
| int ret; | |||||
| ret = ff_end_frame(inlink->dst->outputs[0]); | |||||
| if (fade->frame_index >= fade->start_frame && | if (fade->frame_index >= fade->start_frame && | ||||
| fade->frame_index <= fade->stop_frame) | fade->frame_index <= fade->stop_frame) | ||||
| fade->factor += fade->fade_per_frame; | fade->factor += fade->fade_per_frame; | ||||
| fade->factor = av_clip_uint16(fade->factor); | fade->factor = av_clip_uint16(fade->factor); | ||||
| fade->frame_index++; | fade->frame_index++; | ||||
| return ret; | |||||
| return ff_filter_frame(inlink->dst->outputs[0], frame); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_fade_inputs[] = { | static const AVFilterPad avfilter_vf_fade_inputs[] = { | ||||
| @@ -160,9 +149,7 @@ static const AVFilterPad avfilter_vf_fade_inputs[] = { | |||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .config_props = config_props, | .config_props = config_props, | ||||
| .get_video_buffer = ff_null_get_video_buffer, | .get_video_buffer = ff_null_get_video_buffer, | ||||
| .start_frame = ff_null_start_frame, | |||||
| .draw_slice = draw_slice, | |||||
| .end_frame = end_frame, | |||||
| .filter_frame = filter_frame, | |||||
| .min_perms = AV_PERM_READ | AV_PERM_WRITE, | .min_perms = AV_PERM_READ | AV_PERM_WRITE, | ||||
| .rej_perms = AV_PERM_PRESERVE, | .rej_perms = AV_PERM_PRESERVE, | ||||
| }, | }, | ||||
| @@ -121,90 +121,39 @@ static AVFilterBufferRef *get_video_buffer(AVFilterLink *inlink, int perms, int | |||||
| return ff_get_video_buffer(outlink, perms, w, h); | return ff_get_video_buffer(outlink, perms, w, h); | ||||
| } | } | ||||
| static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame) | |||||
| { | { | ||||
| AVFilterContext *ctx = inlink->dst; | |||||
| AVFilterLink *outlink = ctx->outputs[0]; | |||||
| AVFilterBufferRef *outpicref, *for_next_filter; | |||||
| int ret = 0; | |||||
| outpicref = avfilter_ref_buffer(inpicref, ~0); | |||||
| if (!outpicref) | |||||
| return AVERROR(ENOMEM); | |||||
| for_next_filter = avfilter_ref_buffer(outpicref, ~0); | |||||
| if (!for_next_filter) { | |||||
| avfilter_unref_bufferp(&outpicref); | |||||
| return AVERROR(ENOMEM); | |||||
| } | |||||
| ret = ff_start_frame(outlink, for_next_filter); | |||||
| if (ret < 0) { | |||||
| avfilter_unref_bufferp(&outpicref); | |||||
| return ret; | |||||
| } | |||||
| outlink->out_buf = outpicref; | |||||
| return 0; | |||||
| } | |||||
| static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) | |||||
| { | |||||
| AVFilterContext *ctx = inlink->dst; | |||||
| FieldOrderContext *fieldorder = ctx->priv; | |||||
| AVFilterLink *outlink = ctx->outputs[0]; | |||||
| AVFilterBufferRef *inpicref = inlink->cur_buf; | |||||
| AVFilterContext *ctx = inlink->dst; | |||||
| FieldOrderContext *s = ctx->priv; | |||||
| AVFilterLink *outlink = ctx->outputs[0]; | |||||
| int h, plane, line_step, line_size, line; | |||||
| uint8_t *data; | |||||
| /** can only currently do slices if this filter is doing nothing | |||||
| * because this filter is moving picture content, the output | |||||
| * slice will contain different video lines than the input slice | |||||
| * and that complexity will be added later */ | |||||
| if ( !inpicref->video->interlaced | |||||
| || inpicref->video->top_field_first == fieldorder->dst_tff) { | |||||
| return ff_draw_slice(outlink, y, h, slice_dir); | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| if (!frame->video->interlaced || | |||||
| frame->video->top_field_first == s->dst_tff) | |||||
| return ff_filter_frame(outlink, frame); | |||||
| static int end_frame(AVFilterLink *inlink) | |||||
| { | |||||
| AVFilterContext *ctx = inlink->dst; | |||||
| FieldOrderContext *fieldorder = ctx->priv; | |||||
| AVFilterLink *outlink = ctx->outputs[0]; | |||||
| AVFilterBufferRef *inpicref = inlink->cur_buf; | |||||
| AVFilterBufferRef *outpicref = outlink->out_buf; | |||||
| int h, plane, line_step, line_size, line; | |||||
| uint8_t *cpy_src, *cpy_dst; | |||||
| if ( inpicref->video->interlaced | |||||
| && inpicref->video->top_field_first != fieldorder->dst_tff) { | |||||
| av_dlog(ctx, | av_dlog(ctx, | ||||
| "picture will move %s one line\n", | "picture will move %s one line\n", | ||||
| fieldorder->dst_tff ? "up" : "down"); | |||||
| h = inpicref->video->h; | |||||
| for (plane = 0; plane < 4 && inpicref->data[plane]; plane++) { | |||||
| line_step = inpicref->linesize[plane]; | |||||
| line_size = fieldorder->line_size[plane]; | |||||
| cpy_src = inpicref->data[plane]; | |||||
| cpy_dst = outpicref->data[plane]; | |||||
| if (fieldorder->dst_tff) { | |||||
| s->dst_tff ? "up" : "down"); | |||||
| h = frame->video->h; | |||||
| for (plane = 0; plane < 4 && frame->data[plane]; plane++) { | |||||
| line_step = frame->linesize[plane]; | |||||
| line_size = s->line_size[plane]; | |||||
| data = frame->data[plane]; | |||||
| if (s->dst_tff) { | |||||
| /** Move every line up one line, working from | /** Move every line up one line, working from | ||||
| * the top to the bottom of the frame. | * the top to the bottom of the frame. | ||||
| * The original top line is lost. | * The original top line is lost. | ||||
| * The new last line is created as a copy of the | * The new last line is created as a copy of the | ||||
| * penultimate line from that field. */ | * penultimate line from that field. */ | ||||
| for (line = 0; line < h; line++) { | for (line = 0; line < h; line++) { | ||||
| if (1 + line < outpicref->video->h) { | |||||
| memcpy(cpy_dst, cpy_src + line_step, line_size); | |||||
| if (1 + line < frame->video->h) { | |||||
| memcpy(data, data + line_step, line_size); | |||||
| } else { | } else { | ||||
| memcpy(cpy_dst, cpy_src - line_step - line_step, line_size); | |||||
| memcpy(data, data - line_step - line_step, line_size); | |||||
| } | } | ||||
| cpy_src += line_step; | |||||
| cpy_dst += line_step; | |||||
| data += line_step; | |||||
| } | } | ||||
| } else { | } else { | ||||
| /** Move every line down one line, working from | /** Move every line down one line, working from | ||||
| @@ -212,27 +161,20 @@ static int end_frame(AVFilterLink *inlink) | |||||
| * The original bottom line is lost. | * The original bottom line is lost. | ||||
| * The new first line is created as a copy of the | * The new first line is created as a copy of the | ||||
| * second line from that field. */ | * second line from that field. */ | ||||
| cpy_src += (h - 1) * line_step; | |||||
| cpy_dst += (h - 1) * line_step; | |||||
| data += (h - 1) * line_step; | |||||
| for (line = h - 1; line >= 0 ; line--) { | for (line = h - 1; line >= 0 ; line--) { | ||||
| if (line > 0) { | if (line > 0) { | ||||
| memcpy(cpy_dst, cpy_src - line_step, line_size); | |||||
| memcpy(data, data - line_step, line_size); | |||||
| } else { | } else { | ||||
| memcpy(cpy_dst, cpy_src + line_step + line_step, line_size); | |||||
| memcpy(data, data + line_step + line_step, line_size); | |||||
| } | } | ||||
| cpy_src -= line_step; | |||||
| cpy_dst -= line_step; | |||||
| data -= line_step; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| outpicref->video->top_field_first = fieldorder->dst_tff; | |||||
| ff_draw_slice(outlink, 0, h, 1); | |||||
| } else { | |||||
| av_dlog(ctx, | |||||
| "not interlaced or field order already correct\n"); | |||||
| } | |||||
| frame->video->top_field_first = s->dst_tff; | |||||
| return ff_end_frame(outlink); | |||||
| return ff_filter_frame(outlink, frame); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_fieldorder_inputs[] = { | static const AVFilterPad avfilter_vf_fieldorder_inputs[] = { | ||||
| @@ -240,10 +182,8 @@ static const AVFilterPad avfilter_vf_fieldorder_inputs[] = { | |||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .config_props = config_input, | .config_props = config_input, | ||||
| .start_frame = start_frame, | |||||
| .get_video_buffer = get_video_buffer, | .get_video_buffer = get_video_buffer, | ||||
| .draw_slice = draw_slice, | |||||
| .end_frame = end_frame, | |||||
| .filter_frame = filter_frame, | |||||
| .min_perms = AV_PERM_READ, | .min_perms = AV_PERM_READ, | ||||
| .rej_perms = AV_PERM_REUSE2 | AV_PERM_PRESERVE, | .rej_perms = AV_PERM_REUSE2 | AV_PERM_PRESERVE, | ||||
| }, | }, | ||||
| @@ -104,9 +104,6 @@ static const AVFilterPad avfilter_vf_format_inputs[] = { | |||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .get_video_buffer = ff_null_get_video_buffer, | .get_video_buffer = ff_null_get_video_buffer, | ||||
| .start_frame = ff_null_start_frame, | |||||
| .draw_slice = ff_null_draw_slice, | |||||
| .end_frame = ff_null_end_frame, | |||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| }; | }; | ||||
| @@ -146,9 +143,6 @@ static const AVFilterPad avfilter_vf_noformat_inputs[] = { | |||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .get_video_buffer = ff_null_get_video_buffer, | .get_video_buffer = ff_null_get_video_buffer, | ||||
| .start_frame = ff_null_start_frame, | |||||
| .draw_slice = ff_null_draw_slice, | |||||
| .end_frame = ff_null_end_frame, | |||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| }; | }; | ||||
| @@ -144,9 +144,7 @@ static int request_frame(AVFilterLink *outlink) | |||||
| buf->pts = av_rescale_q(s->first_pts, ctx->inputs[0]->time_base, | buf->pts = av_rescale_q(s->first_pts, ctx->inputs[0]->time_base, | ||||
| outlink->time_base) + s->frames_out; | outlink->time_base) + s->frames_out; | ||||
| if ((ret = ff_start_frame(outlink, buf)) < 0 || | |||||
| (ret = ff_draw_slice(outlink, 0, outlink->h, 1)) < 0 || | |||||
| (ret = ff_end_frame(outlink)) < 0) | |||||
| if ((ret = ff_filter_frame(outlink, buf)) < 0) | |||||
| return ret; | return ret; | ||||
| s->frames_out++; | s->frames_out++; | ||||
| @@ -171,16 +169,14 @@ static int write_to_fifo(AVFifoBuffer *fifo, AVFilterBufferRef *buf) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int end_frame(AVFilterLink *inlink) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf) | |||||
| { | { | ||||
| AVFilterContext *ctx = inlink->dst; | AVFilterContext *ctx = inlink->dst; | ||||
| FPSContext *s = ctx->priv; | FPSContext *s = ctx->priv; | ||||
| AVFilterLink *outlink = ctx->outputs[0]; | AVFilterLink *outlink = ctx->outputs[0]; | ||||
| AVFilterBufferRef *buf = inlink->cur_buf; | |||||
| int64_t delta; | int64_t delta; | ||||
| int i, ret; | int i, ret; | ||||
| inlink->cur_buf = NULL; | |||||
| s->frames_in++; | s->frames_in++; | ||||
| /* discard frames until we get the first timestamp */ | /* discard frames until we get the first timestamp */ | ||||
| if (s->pts == AV_NOPTS_VALUE) { | if (s->pts == AV_NOPTS_VALUE) { | ||||
| @@ -251,9 +247,7 @@ static int end_frame(AVFilterLink *inlink) | |||||
| buf_out->pts = av_rescale_q(s->first_pts, inlink->time_base, | buf_out->pts = av_rescale_q(s->first_pts, inlink->time_base, | ||||
| outlink->time_base) + s->frames_out; | outlink->time_base) + s->frames_out; | ||||
| if ((ret = ff_start_frame(outlink, buf_out)) < 0 || | |||||
| (ret = ff_draw_slice(outlink, 0, outlink->h, 1)) < 0 || | |||||
| (ret = ff_end_frame(outlink)) < 0) { | |||||
| if ((ret = ff_filter_frame(outlink, buf_out)) < 0) { | |||||
| avfilter_unref_bufferp(&buf); | avfilter_unref_bufferp(&buf); | ||||
| return ret; | return ret; | ||||
| } | } | ||||
| @@ -268,23 +262,11 @@ static int end_frame(AVFilterLink *inlink) | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| static int null_start_frame(AVFilterLink *link, AVFilterBufferRef *buf) | |||||
| { | |||||
| return 0; | |||||
| } | |||||
| static int null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) | |||||
| { | |||||
| return 0; | |||||
| } | |||||
| static const AVFilterPad avfilter_vf_fps_inputs[] = { | static const AVFilterPad avfilter_vf_fps_inputs[] = { | ||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .start_frame = null_start_frame, | |||||
| .draw_slice = null_draw_slice, | |||||
| .end_frame = end_frame, | |||||
| .filter_frame = filter_frame, | |||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| }; | }; | ||||
| @@ -346,35 +346,34 @@ static int query_formats(AVFilterContext *ctx) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int null_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) | |||||
| { | |||||
| return 0; | |||||
| } | |||||
| static int end_frame(AVFilterLink *inlink) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in) | |||||
| { | { | ||||
| Frei0rContext *frei0r = inlink->dst->priv; | Frei0rContext *frei0r = inlink->dst->priv; | ||||
| AVFilterLink *outlink = inlink->dst->outputs[0]; | AVFilterLink *outlink = inlink->dst->outputs[0]; | ||||
| AVFilterBufferRef *inpicref = inlink->cur_buf; | |||||
| AVFilterBufferRef *outpicref = outlink->out_buf; | |||||
| int ret; | |||||
| frei0r->update(frei0r->instance, inpicref->pts * av_q2d(inlink->time_base) * 1000, | |||||
| (const uint32_t *)inpicref->data[0], | |||||
| (uint32_t *)outpicref->data[0]); | |||||
| if ((ret = ff_draw_slice(outlink, 0, outlink->h, 1)) || | |||||
| (ret = ff_end_frame(outlink)) < 0) | |||||
| return ret; | |||||
| return 0; | |||||
| AVFilterBufferRef *out; | |||||
| out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); | |||||
| if (!out) { | |||||
| avfilter_unref_bufferp(&in); | |||||
| return AVERROR(ENOMEM); | |||||
| } | |||||
| avfilter_copy_buffer_ref_props(out, in); | |||||
| frei0r->update(frei0r->instance, in->pts * av_q2d(inlink->time_base) * 1000, | |||||
| (const uint32_t *)in->data[0], | |||||
| (uint32_t *)out->data[0]); | |||||
| avfilter_unref_bufferp(&in); | |||||
| return ff_filter_frame(outlink, out); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_frei0r_inputs[] = { | static const AVFilterPad avfilter_vf_frei0r_inputs[] = { | ||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .draw_slice = null_draw_slice, | |||||
| .config_props = config_input_props, | .config_props = config_input_props, | ||||
| .end_frame = end_frame, | |||||
| .filter_frame = filter_frame, | |||||
| .min_perms = AV_PERM_READ | .min_perms = AV_PERM_READ | ||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| @@ -456,8 +455,6 @@ static int source_request_frame(AVFilterLink *outlink) | |||||
| { | { | ||||
| Frei0rContext *frei0r = outlink->src->priv; | Frei0rContext *frei0r = outlink->src->priv; | ||||
| AVFilterBufferRef *picref = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); | AVFilterBufferRef *picref = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); | ||||
| AVFilterBufferRef *buf_out; | |||||
| int ret; | |||||
| if (!picref) | if (!picref) | ||||
| return AVERROR(ENOMEM); | return AVERROR(ENOMEM); | ||||
| @@ -466,28 +463,10 @@ static int source_request_frame(AVFilterLink *outlink) | |||||
| picref->pts = frei0r->pts++; | picref->pts = frei0r->pts++; | ||||
| picref->pos = -1; | picref->pos = -1; | ||||
| buf_out = avfilter_ref_buffer(picref, ~0); | |||||
| if (!buf_out) { | |||||
| ret = AVERROR(ENOMEM); | |||||
| goto fail; | |||||
| } | |||||
| ret = ff_start_frame(outlink, buf_out); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| frei0r->update(frei0r->instance, av_rescale_q(picref->pts, frei0r->time_base, (AVRational){1,1000}), | frei0r->update(frei0r->instance, av_rescale_q(picref->pts, frei0r->time_base, (AVRational){1,1000}), | ||||
| NULL, (uint32_t *)picref->data[0]); | NULL, (uint32_t *)picref->data[0]); | ||||
| ret = ff_draw_slice(outlink, 0, outlink->h, 1); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| ret = ff_end_frame(outlink); | |||||
| fail: | |||||
| avfilter_unref_buffer(picref); | |||||
| return ret; | |||||
| return ff_filter_frame(outlink, picref); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vsrc_frei0r_src_outputs[] = { | static const AVFilterPad avfilter_vsrc_frei0r_src_outputs[] = { | ||||
| @@ -182,20 +182,29 @@ static int config_input(AVFilterLink *inlink) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) | |||||
| { | |||||
| return 0; | |||||
| } | |||||
| static int end_frame(AVFilterLink *inlink) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in) | |||||
| { | { | ||||
| GradFunContext *gf = inlink->dst->priv; | GradFunContext *gf = inlink->dst->priv; | ||||
| AVFilterBufferRef *inpic = inlink->cur_buf; | |||||
| AVFilterLink *outlink = inlink->dst->outputs[0]; | AVFilterLink *outlink = inlink->dst->outputs[0]; | ||||
| AVFilterBufferRef *outpic = outlink->out_buf; | |||||
| int p, ret; | |||||
| AVFilterBufferRef *out; | |||||
| int p, direct; | |||||
| if ((in->perms & AV_PERM_WRITE) && !(in->perms & AV_PERM_PRESERVE)) { | |||||
| direct = 1; | |||||
| out = in; | |||||
| } else { | |||||
| out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); | |||||
| if (!out) { | |||||
| avfilter_unref_bufferp(&in); | |||||
| return AVERROR(ENOMEM); | |||||
| } | |||||
| avfilter_copy_buffer_ref_props(out, in); | |||||
| out->video->w = outlink->w; | |||||
| out->video->h = outlink->h; | |||||
| } | |||||
| for (p = 0; p < 4 && inpic->data[p]; p++) { | |||||
| for (p = 0; p < 4 && in->data[p]; p++) { | |||||
| int w = inlink->w; | int w = inlink->w; | ||||
| int h = inlink->h; | int h = inlink->h; | ||||
| int r = gf->radius; | int r = gf->radius; | ||||
| @@ -206,15 +215,15 @@ static int end_frame(AVFilterLink *inlink) | |||||
| } | } | ||||
| if (FFMIN(w, h) > 2 * r) | if (FFMIN(w, h) > 2 * r) | ||||
| filter(gf, outpic->data[p], inpic->data[p], w, h, outpic->linesize[p], inpic->linesize[p], r); | |||||
| else if (outpic->data[p] != inpic->data[p]) | |||||
| av_image_copy_plane(outpic->data[p], outpic->linesize[p], inpic->data[p], inpic->linesize[p], w, h); | |||||
| filter(gf, out->data[p], in->data[p], w, h, out->linesize[p], in->linesize[p], r); | |||||
| else if (out->data[p] != in->data[p]) | |||||
| av_image_copy_plane(out->data[p], out->linesize[p], in->data[p], in->linesize[p], w, h); | |||||
| } | } | ||||
| if ((ret = ff_draw_slice(outlink, 0, inlink->h, 1)) < 0 || | |||||
| (ret = ff_end_frame(outlink)) < 0) | |||||
| return ret; | |||||
| return 0; | |||||
| if (!direct) | |||||
| avfilter_unref_bufferp(&in); | |||||
| return ff_filter_frame(outlink, out); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_gradfun_inputs[] = { | static const AVFilterPad avfilter_vf_gradfun_inputs[] = { | ||||
| @@ -222,9 +231,7 @@ static const AVFilterPad avfilter_vf_gradfun_inputs[] = { | |||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .config_props = config_input, | .config_props = config_input, | ||||
| .start_frame = ff_inplace_start_frame, | |||||
| .draw_slice = null_draw_slice, | |||||
| .end_frame = end_frame, | |||||
| .filter_frame = filter_frame, | |||||
| .min_perms = AV_PERM_READ, | .min_perms = AV_PERM_READ, | ||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| @@ -84,22 +84,30 @@ static int config_props(AVFilterLink *inlink) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in) | |||||
| { | { | ||||
| FlipContext *flip = inlink->dst->priv; | |||||
| AVFilterBufferRef *inpic = inlink->cur_buf; | |||||
| AVFilterBufferRef *outpic = inlink->dst->outputs[0]->out_buf; | |||||
| AVFilterContext *ctx = inlink->dst; | |||||
| FlipContext *flip = ctx->priv; | |||||
| AVFilterLink *outlink = ctx->outputs[0]; | |||||
| AVFilterBufferRef *out; | |||||
| uint8_t *inrow, *outrow; | uint8_t *inrow, *outrow; | ||||
| int i, j, plane, step, hsub, vsub; | int i, j, plane, step, hsub, vsub; | ||||
| for (plane = 0; plane < 4 && inpic->data[plane]; plane++) { | |||||
| out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); | |||||
| if (!out) { | |||||
| avfilter_unref_bufferp(&in); | |||||
| return AVERROR(ENOMEM); | |||||
| } | |||||
| avfilter_copy_buffer_ref_props(out, in); | |||||
| for (plane = 0; plane < 4 && in->data[plane]; plane++) { | |||||
| step = flip->max_step[plane]; | step = flip->max_step[plane]; | ||||
| hsub = (plane == 1 || plane == 2) ? flip->hsub : 0; | hsub = (plane == 1 || plane == 2) ? flip->hsub : 0; | ||||
| vsub = (plane == 1 || plane == 2) ? flip->vsub : 0; | vsub = (plane == 1 || plane == 2) ? flip->vsub : 0; | ||||
| outrow = outpic->data[plane] + (y>>vsub) * outpic->linesize[plane]; | |||||
| inrow = inpic ->data[plane] + (y>>vsub) * inpic ->linesize[plane] + ((inlink->w >> hsub) - 1) * step; | |||||
| for (i = 0; i < h>>vsub; i++) { | |||||
| outrow = out->data[plane]; | |||||
| inrow = in ->data[plane] + ((inlink->w >> hsub) - 1) * step; | |||||
| for (i = 0; i < in->video->h >> vsub; i++) { | |||||
| switch (step) { | switch (step) { | ||||
| case 1: | case 1: | ||||
| for (j = 0; j < (inlink->w >> hsub); j++) | for (j = 0; j < (inlink->w >> hsub); j++) | ||||
| @@ -140,19 +148,20 @@ static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) | |||||
| memcpy(outrow + j*step, inrow - j*step, step); | memcpy(outrow + j*step, inrow - j*step, step); | ||||
| } | } | ||||
| inrow += inpic ->linesize[plane]; | |||||
| outrow += outpic->linesize[plane]; | |||||
| inrow += in ->linesize[plane]; | |||||
| outrow += out->linesize[plane]; | |||||
| } | } | ||||
| } | } | ||||
| return ff_draw_slice(inlink->dst->outputs[0], y, h, slice_dir); | |||||
| avfilter_unref_bufferp(&in); | |||||
| return ff_filter_frame(outlink, out); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_hflip_inputs[] = { | static const AVFilterPad avfilter_vf_hflip_inputs[] = { | ||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .draw_slice = draw_slice, | |||||
| .filter_frame = filter_frame, | |||||
| .config_props = config_props, | .config_props = config_props, | ||||
| .min_perms = AV_PERM_READ, | .min_perms = AV_PERM_READ, | ||||
| }, | }, | ||||
| @@ -322,42 +322,49 @@ static int config_input(AVFilterLink *inlink) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) | |||||
| { | |||||
| return 0; | |||||
| } | |||||
| static int end_frame(AVFilterLink *inlink) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in) | |||||
| { | { | ||||
| HQDN3DContext *hqdn3d = inlink->dst->priv; | HQDN3DContext *hqdn3d = inlink->dst->priv; | ||||
| AVFilterLink *outlink = inlink->dst->outputs[0]; | AVFilterLink *outlink = inlink->dst->outputs[0]; | ||||
| AVFilterBufferRef *inpic = inlink ->cur_buf; | |||||
| AVFilterBufferRef *outpic = outlink->out_buf; | |||||
| int ret, c; | |||||
| AVFilterBufferRef *out; | |||||
| int direct, c; | |||||
| if ((in->perms & AV_PERM_WRITE) && !(in->perms & AV_PERM_PRESERVE)) { | |||||
| direct = 1; | |||||
| out = in; | |||||
| } else { | |||||
| out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); | |||||
| if (!out) { | |||||
| avfilter_unref_bufferp(&in); | |||||
| return AVERROR(ENOMEM); | |||||
| } | |||||
| avfilter_copy_buffer_ref_props(out, in); | |||||
| out->video->w = outlink->w; | |||||
| out->video->h = outlink->h; | |||||
| } | |||||
| for (c = 0; c < 3; c++) { | for (c = 0; c < 3; c++) { | ||||
| denoise(hqdn3d, inpic->data[c], outpic->data[c], | |||||
| denoise(hqdn3d, in->data[c], out->data[c], | |||||
| hqdn3d->line, &hqdn3d->frame_prev[c], | hqdn3d->line, &hqdn3d->frame_prev[c], | ||||
| inpic->video->w >> (!!c * hqdn3d->hsub), | |||||
| inpic->video->h >> (!!c * hqdn3d->vsub), | |||||
| inpic->linesize[c], outpic->linesize[c], | |||||
| in->video->w >> (!!c * hqdn3d->hsub), | |||||
| in->video->h >> (!!c * hqdn3d->vsub), | |||||
| in->linesize[c], out->linesize[c], | |||||
| hqdn3d->coefs[c?2:0], hqdn3d->coefs[c?3:1]); | hqdn3d->coefs[c?2:0], hqdn3d->coefs[c?3:1]); | ||||
| } | } | ||||
| if ((ret = ff_draw_slice(outlink, 0, inpic->video->h, 1)) < 0 || | |||||
| (ret = ff_end_frame(outlink)) < 0) | |||||
| return ret; | |||||
| return 0; | |||||
| if (!direct) | |||||
| avfilter_unref_bufferp(&in); | |||||
| return ff_filter_frame(outlink, out); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_hqdn3d_inputs[] = { | static const AVFilterPad avfilter_vf_hqdn3d_inputs[] = { | ||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .start_frame = ff_inplace_start_frame, | |||||
| .draw_slice = null_draw_slice, | |||||
| .config_props = config_input, | .config_props = config_input, | ||||
| .end_frame = end_frame | |||||
| .filter_frame = filter_frame, | |||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| }; | }; | ||||
| @@ -32,6 +32,7 @@ | |||||
| #include "libavutil/file.h" | #include "libavutil/file.h" | ||||
| #include "avfilter.h" | #include "avfilter.h" | ||||
| #include "formats.h" | #include "formats.h" | ||||
| #include "internal.h" | |||||
| #include "video.h" | #include "video.h" | ||||
| static void fill_iplimage_from_picref(IplImage *img, const AVFilterBufferRef *picref, enum AVPixelFormat pixfmt) | static void fill_iplimage_from_picref(IplImage *img, const AVFilterBufferRef *picref, enum AVPixelFormat pixfmt) | ||||
| @@ -68,11 +69,6 @@ static int query_formats(AVFilterContext *ctx) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) | |||||
| { | |||||
| return 0; | |||||
| } | |||||
| typedef struct { | typedef struct { | ||||
| const char *name; | const char *name; | ||||
| int (*init)(AVFilterContext *ctx, const char *args); | int (*init)(AVFilterContext *ctx, const char *args); | ||||
| @@ -355,33 +351,36 @@ static av_cold void uninit(AVFilterContext *ctx) | |||||
| memset(ocv, 0, sizeof(*ocv)); | memset(ocv, 0, sizeof(*ocv)); | ||||
| } | } | ||||
| static int end_frame(AVFilterLink *inlink) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in) | |||||
| { | { | ||||
| AVFilterContext *ctx = inlink->dst; | AVFilterContext *ctx = inlink->dst; | ||||
| OCVContext *ocv = ctx->priv; | OCVContext *ocv = ctx->priv; | ||||
| AVFilterLink *outlink= inlink->dst->outputs[0]; | AVFilterLink *outlink= inlink->dst->outputs[0]; | ||||
| AVFilterBufferRef *inpicref = inlink ->cur_buf; | |||||
| AVFilterBufferRef *outpicref = outlink->out_buf; | |||||
| AVFilterBufferRef *out; | |||||
| IplImage inimg, outimg; | IplImage inimg, outimg; | ||||
| int ret; | |||||
| fill_iplimage_from_picref(&inimg , inpicref , inlink->format); | |||||
| fill_iplimage_from_picref(&outimg, outpicref, inlink->format); | |||||
| out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); | |||||
| if (!out) { | |||||
| avfilter_unref_bufferp(&in); | |||||
| return AVERROR(ENOMEM); | |||||
| } | |||||
| avfilter_copy_buffer_ref_props(out, in); | |||||
| fill_iplimage_from_picref(&inimg , in , inlink->format); | |||||
| fill_iplimage_from_picref(&outimg, out, inlink->format); | |||||
| ocv->end_frame_filter(ctx, &inimg, &outimg); | ocv->end_frame_filter(ctx, &inimg, &outimg); | ||||
| fill_picref_from_iplimage(outpicref, &outimg, inlink->format); | |||||
| fill_picref_from_iplimage(out, &outimg, inlink->format); | |||||
| if ((ret = ff_draw_slice(outlink, 0, outlink->h, 1)) < 0 || | |||||
| (ret = ff_end_frame(outlink)) < 0) | |||||
| return ret; | |||||
| return 0; | |||||
| avfilter_unref_bufferp(&in); | |||||
| return ff_filter_frame(outlink, out); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_ocv_inputs[] = { | static const AVFilterPad avfilter_vf_ocv_inputs[] = { | ||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .draw_slice = null_draw_slice, | |||||
| .end_frame = end_frame, | |||||
| .filter_frame = filter_frame, | |||||
| .min_perms = AV_PERM_READ | .min_perms = AV_PERM_READ | ||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| @@ -295,22 +295,28 @@ static int config_props(AVFilterLink *inlink) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in) | |||||
| { | { | ||||
| AVFilterContext *ctx = inlink->dst; | AVFilterContext *ctx = inlink->dst; | ||||
| LutContext *lut = ctx->priv; | LutContext *lut = ctx->priv; | ||||
| AVFilterLink *outlink = ctx->outputs[0]; | AVFilterLink *outlink = ctx->outputs[0]; | ||||
| AVFilterBufferRef *inpic = inlink ->cur_buf; | |||||
| AVFilterBufferRef *outpic = outlink->out_buf; | |||||
| AVFilterBufferRef *out; | |||||
| uint8_t *inrow, *outrow, *inrow0, *outrow0; | uint8_t *inrow, *outrow, *inrow0, *outrow0; | ||||
| int i, j, k, plane; | int i, j, k, plane; | ||||
| out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); | |||||
| if (!out) { | |||||
| avfilter_unref_bufferp(&in); | |||||
| return AVERROR(ENOMEM); | |||||
| } | |||||
| avfilter_copy_buffer_ref_props(out, in); | |||||
| if (lut->is_rgb) { | if (lut->is_rgb) { | ||||
| /* packed */ | /* packed */ | ||||
| inrow0 = inpic ->data[0] + y * inpic ->linesize[0]; | |||||
| outrow0 = outpic->data[0] + y * outpic->linesize[0]; | |||||
| inrow0 = in ->data[0]; | |||||
| outrow0 = out->data[0]; | |||||
| for (i = 0; i < h; i ++) { | |||||
| for (i = 0; i < in->video->h; i ++) { | |||||
| inrow = inrow0; | inrow = inrow0; | ||||
| outrow = outrow0; | outrow = outrow0; | ||||
| for (j = 0; j < inlink->w; j++) { | for (j = 0; j < inlink->w; j++) { | ||||
| @@ -319,34 +325,35 @@ static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) | |||||
| outrow += lut->step; | outrow += lut->step; | ||||
| inrow += lut->step; | inrow += lut->step; | ||||
| } | } | ||||
| inrow0 += inpic ->linesize[0]; | |||||
| outrow0 += outpic->linesize[0]; | |||||
| inrow0 += in ->linesize[0]; | |||||
| outrow0 += out->linesize[0]; | |||||
| } | } | ||||
| } else { | } else { | ||||
| /* planar */ | /* planar */ | ||||
| for (plane = 0; plane < 4 && inpic->data[plane]; plane++) { | |||||
| for (plane = 0; plane < 4 && in->data[plane]; plane++) { | |||||
| int vsub = plane == 1 || plane == 2 ? lut->vsub : 0; | int vsub = plane == 1 || plane == 2 ? lut->vsub : 0; | ||||
| int hsub = plane == 1 || plane == 2 ? lut->hsub : 0; | int hsub = plane == 1 || plane == 2 ? lut->hsub : 0; | ||||
| inrow = inpic ->data[plane] + (y>>vsub) * inpic ->linesize[plane]; | |||||
| outrow = outpic->data[plane] + (y>>vsub) * outpic->linesize[plane]; | |||||
| inrow = in ->data[plane]; | |||||
| outrow = out->data[plane]; | |||||
| for (i = 0; i < h>>vsub; i ++) { | |||||
| for (i = 0; i < in->video->h >> vsub; i ++) { | |||||
| for (j = 0; j < inlink->w>>hsub; j++) | for (j = 0; j < inlink->w>>hsub; j++) | ||||
| outrow[j] = lut->lut[plane][inrow[j]]; | outrow[j] = lut->lut[plane][inrow[j]]; | ||||
| inrow += inpic ->linesize[plane]; | |||||
| outrow += outpic->linesize[plane]; | |||||
| inrow += in ->linesize[plane]; | |||||
| outrow += out->linesize[plane]; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return ff_draw_slice(outlink, y, h, slice_dir); | |||||
| avfilter_unref_bufferp(&in); | |||||
| return ff_filter_frame(outlink, out); | |||||
| } | } | ||||
| static const AVFilterPad inputs[] = { | static const AVFilterPad inputs[] = { | ||||
| { .name = "default", | { .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .draw_slice = draw_slice, | |||||
| .filter_frame = filter_frame, | |||||
| .config_props = config_props, | .config_props = config_props, | ||||
| .min_perms = AV_PERM_READ, }, | .min_perms = AV_PERM_READ, }, | ||||
| { .name = NULL} | { .name = NULL} | ||||
| @@ -31,8 +31,6 @@ static const AVFilterPad avfilter_vf_null_inputs[] = { | |||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .get_video_buffer = ff_null_get_video_buffer, | .get_video_buffer = ff_null_get_video_buffer, | ||||
| .start_frame = ff_null_start_frame, | |||||
| .end_frame = ff_null_end_frame | |||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| }; | }; | ||||
| @@ -269,34 +269,22 @@ static void blend_frame(AVFilterContext *ctx, | |||||
| } | } | ||||
| } | } | ||||
| static int null_start_frame(AVFilterLink *inlink, AVFilterBufferRef *buf) | |||||
| { | |||||
| return 0; | |||||
| } | |||||
| static int null_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) | |||||
| { | |||||
| return 0; | |||||
| } | |||||
| static int end_frame_main(AVFilterLink *inlink) | |||||
| static int filter_frame_main(AVFilterLink *inlink, AVFilterBufferRef *frame) | |||||
| { | { | ||||
| OverlayContext *s = inlink->dst->priv; | OverlayContext *s = inlink->dst->priv; | ||||
| av_assert0(!s->main); | av_assert0(!s->main); | ||||
| s->main = inlink->cur_buf; | |||||
| inlink->cur_buf = NULL; | |||||
| s->main = frame; | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int end_frame_overlay(AVFilterLink *inlink) | |||||
| static int filter_frame_overlay(AVFilterLink *inlink, AVFilterBufferRef *frame) | |||||
| { | { | ||||
| OverlayContext *s = inlink->dst->priv; | OverlayContext *s = inlink->dst->priv; | ||||
| av_assert0(!s->over_next); | av_assert0(!s->over_next); | ||||
| s->over_next = inlink->cur_buf; | |||||
| inlink->cur_buf = NULL; | |||||
| s->over_next = frame; | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -305,11 +293,7 @@ static int output_frame(AVFilterContext *ctx) | |||||
| { | { | ||||
| OverlayContext *s = ctx->priv; | OverlayContext *s = ctx->priv; | ||||
| AVFilterLink *outlink = ctx->outputs[0]; | AVFilterLink *outlink = ctx->outputs[0]; | ||||
| int ret = ff_start_frame(outlink, s->main); | |||||
| if (ret >= 0) | |||||
| ret = ff_draw_slice(outlink, 0, outlink->h, 1); | |||||
| if (ret >= 0) | |||||
| ret = ff_end_frame(outlink); | |||||
| int ret = ff_filter_frame(outlink, s->main); | |||||
| s->main = NULL; | s->main = NULL; | ||||
| return ret; | return ret; | ||||
| @@ -378,10 +362,8 @@ static const AVFilterPad avfilter_vf_overlay_inputs[] = { | |||||
| { | { | ||||
| .name = "main", | .name = "main", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .start_frame = null_start_frame, | |||||
| .config_props = config_input_main, | .config_props = config_input_main, | ||||
| .draw_slice = null_draw_slice, | |||||
| .end_frame = end_frame_main, | |||||
| .filter_frame = filter_frame_main, | |||||
| .min_perms = AV_PERM_READ, | .min_perms = AV_PERM_READ, | ||||
| .rej_perms = AV_PERM_REUSE2 | AV_PERM_PRESERVE, | .rej_perms = AV_PERM_REUSE2 | AV_PERM_PRESERVE, | ||||
| .needs_fifo = 1, | .needs_fifo = 1, | ||||
| @@ -389,10 +371,8 @@ static const AVFilterPad avfilter_vf_overlay_inputs[] = { | |||||
| { | { | ||||
| .name = "overlay", | .name = "overlay", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .start_frame = null_start_frame, | |||||
| .config_props = config_input_overlay, | .config_props = config_input_overlay, | ||||
| .draw_slice = null_draw_slice, | |||||
| .end_frame = end_frame_overlay, | |||||
| .filter_frame = filter_frame_overlay, | |||||
| .min_perms = AV_PERM_READ, | .min_perms = AV_PERM_READ, | ||||
| .rej_perms = AV_PERM_REUSE2, | .rej_perms = AV_PERM_REUSE2, | ||||
| .needs_fifo = 1, | .needs_fifo = 1, | ||||
| @@ -106,7 +106,6 @@ typedef struct { | |||||
| uint8_t *line[4]; | uint8_t *line[4]; | ||||
| int line_step[4]; | int line_step[4]; | ||||
| int hsub, vsub; ///< chroma subsampling values | int hsub, vsub; ///< chroma subsampling values | ||||
| int needs_copy; | |||||
| } PadContext; | } PadContext; | ||||
| static av_cold int init(AVFilterContext *ctx, const char *args) | static av_cold int init(AVFilterContext *ctx, const char *args) | ||||
| @@ -303,135 +302,85 @@ static int does_clip(PadContext *pad, AVFilterBufferRef *outpicref, int plane, i | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in) | |||||
| { | { | ||||
| PadContext *pad = inlink->dst->priv; | PadContext *pad = inlink->dst->priv; | ||||
| AVFilterBufferRef *outpicref = avfilter_ref_buffer(inpicref, ~0); | |||||
| AVFilterBufferRef *for_next_filter; | |||||
| int plane, ret = 0; | |||||
| AVFilterBufferRef *out = avfilter_ref_buffer(in, ~0); | |||||
| int plane, needs_copy; | |||||
| if (!outpicref) | |||||
| if (!out) { | |||||
| avfilter_unref_bufferp(&in); | |||||
| return AVERROR(ENOMEM); | return AVERROR(ENOMEM); | ||||
| } | |||||
| for (plane = 0; plane < 4 && outpicref->data[plane]; plane++) { | |||||
| for (plane = 0; plane < 4 && out->data[plane]; plane++) { | |||||
| int hsub = (plane == 1 || plane == 2) ? pad->hsub : 0; | int hsub = (plane == 1 || plane == 2) ? pad->hsub : 0; | ||||
| int vsub = (plane == 1 || plane == 2) ? pad->vsub : 0; | int vsub = (plane == 1 || plane == 2) ? pad->vsub : 0; | ||||
| av_assert0(outpicref->buf->w>0 && outpicref->buf->h>0); | |||||
| av_assert0(out->buf->w > 0 && out->buf->h > 0); | |||||
| if(outpicref->format != outpicref->buf->format) //unsupported currently | |||||
| if (out->format != out->buf->format) //unsupported currently | |||||
| break; | break; | ||||
| outpicref->data[plane] -= (pad->x >> hsub) * pad ->line_step[plane] | |||||
| + (pad->y >> vsub) * outpicref->linesize [plane]; | |||||
| out->data[plane] -= (pad->x >> hsub) * pad->line_step[plane] + | |||||
| (pad->y >> vsub) * out->linesize [plane]; | |||||
| if( does_clip(pad, outpicref, plane, hsub, vsub, 0, 0) | |||||
| || does_clip(pad, outpicref, plane, hsub, vsub, 0, pad->h-1) | |||||
| || does_clip(pad, outpicref, plane, hsub, vsub, pad->w-1, 0) | |||||
| || does_clip(pad, outpicref, plane, hsub, vsub, pad->w-1, pad->h-1) | |||||
| ) | |||||
| if (does_clip(pad, out, plane, hsub, vsub, 0, 0) || | |||||
| does_clip(pad, out, plane, hsub, vsub, 0, pad->h - 1) || | |||||
| does_clip(pad, out, plane, hsub, vsub, pad->w - 1, 0) || | |||||
| does_clip(pad, out, plane, hsub, vsub, pad->w - 1, pad->h - 1)) | |||||
| break; | break; | ||||
| } | } | ||||
| pad->needs_copy= plane < 4 && outpicref->data[plane]; | |||||
| if(pad->needs_copy){ | |||||
| needs_copy = plane < 4 && out->data[plane]; | |||||
| if (needs_copy) { | |||||
| av_log(inlink->dst, AV_LOG_DEBUG, "Direct padding impossible allocating new frame\n"); | av_log(inlink->dst, AV_LOG_DEBUG, "Direct padding impossible allocating new frame\n"); | ||||
| avfilter_unref_buffer(outpicref); | |||||
| outpicref = ff_get_video_buffer(inlink->dst->outputs[0], AV_PERM_WRITE | AV_PERM_NEG_LINESIZES, | |||||
| FFMAX(inlink->w, pad->w), | |||||
| FFMAX(inlink->h, pad->h)); | |||||
| if (!outpicref) | |||||
| avfilter_unref_buffer(out); | |||||
| out = ff_get_video_buffer(inlink->dst->outputs[0], AV_PERM_WRITE | AV_PERM_NEG_LINESIZES, | |||||
| FFMAX(inlink->w, pad->w), | |||||
| FFMAX(inlink->h, pad->h)); | |||||
| if (!out) { | |||||
| avfilter_unref_bufferp(&in); | |||||
| return AVERROR(ENOMEM); | return AVERROR(ENOMEM); | ||||
| } | |||||
| avfilter_copy_buffer_ref_props(outpicref, inpicref); | |||||
| } | |||||
| outpicref->video->w = pad->w; | |||||
| outpicref->video->h = pad->h; | |||||
| for_next_filter = avfilter_ref_buffer(outpicref, ~0); | |||||
| if (!for_next_filter) { | |||||
| ret = AVERROR(ENOMEM); | |||||
| goto fail; | |||||
| avfilter_copy_buffer_ref_props(out, in); | |||||
| } | } | ||||
| ret = ff_start_frame(inlink->dst->outputs[0], for_next_filter); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| inlink->dst->outputs[0]->out_buf = outpicref; | |||||
| return 0; | |||||
| fail: | |||||
| avfilter_unref_bufferp(&outpicref); | |||||
| return ret; | |||||
| } | |||||
| static int end_frame(AVFilterLink *link) | |||||
| { | |||||
| return ff_end_frame(link->dst->outputs[0]); | |||||
| } | |||||
| out->video->w = pad->w; | |||||
| out->video->h = pad->h; | |||||
| static int draw_send_bar_slice(AVFilterLink *link, int y, int h, int slice_dir, int before_slice) | |||||
| { | |||||
| PadContext *pad = link->dst->priv; | |||||
| int bar_y, bar_h = 0, ret = 0; | |||||
| if (slice_dir * before_slice == 1 && y == pad->y) { | |||||
| /* top bar */ | |||||
| bar_y = 0; | |||||
| bar_h = pad->y; | |||||
| } else if (slice_dir * before_slice == -1 && (y + h) == (pad->y + pad->in_h)) { | |||||
| /* bottom bar */ | |||||
| bar_y = pad->y + pad->in_h; | |||||
| bar_h = pad->h - pad->in_h - pad->y; | |||||
| /* top bar */ | |||||
| if (pad->y) { | |||||
| ff_draw_rectangle(out->data, out->linesize, | |||||
| pad->line, pad->line_step, pad->hsub, pad->vsub, | |||||
| 0, 0, pad->w, pad->y); | |||||
| } | } | ||||
| if (bar_h) { | |||||
| ff_draw_rectangle(link->dst->outputs[0]->out_buf->data, | |||||
| link->dst->outputs[0]->out_buf->linesize, | |||||
| /* bottom bar */ | |||||
| if (pad->h > pad->y + pad->in_h) { | |||||
| ff_draw_rectangle(out->data, out->linesize, | |||||
| pad->line, pad->line_step, pad->hsub, pad->vsub, | pad->line, pad->line_step, pad->hsub, pad->vsub, | ||||
| 0, bar_y, pad->w, bar_h); | |||||
| ret = ff_draw_slice(link->dst->outputs[0], bar_y, bar_h, slice_dir); | |||||
| 0, pad->y + pad->in_h, pad->w, pad->h - pad->y - pad->in_h); | |||||
| } | } | ||||
| return ret; | |||||
| } | |||||
| static int draw_slice(AVFilterLink *link, int y, int h, int slice_dir) | |||||
| { | |||||
| PadContext *pad = link->dst->priv; | |||||
| AVFilterBufferRef *outpic = link->dst->outputs[0]->out_buf; | |||||
| AVFilterBufferRef *inpic = link->cur_buf; | |||||
| int ret; | |||||
| y += pad->y; | |||||
| y &= ~((1 << pad->vsub) - 1); | |||||
| h &= ~((1 << pad->vsub) - 1); | |||||
| if (!h) | |||||
| return 0; | |||||
| draw_send_bar_slice(link, y, h, slice_dir, 1); | |||||
| /* left border */ | /* left border */ | ||||
| ff_draw_rectangle(outpic->data, outpic->linesize, pad->line, pad->line_step, | |||||
| pad->hsub, pad->vsub, 0, y, pad->x, h); | |||||
| if(pad->needs_copy){ | |||||
| ff_copy_rectangle(outpic->data, outpic->linesize, | |||||
| inpic->data, inpic->linesize, pad->line_step, | |||||
| pad->hsub, pad->vsub, | |||||
| pad->x, y, y-pad->y, inpic->video->w, h); | |||||
| ff_draw_rectangle(out->data, out->linesize, pad->line, pad->line_step, | |||||
| pad->hsub, pad->vsub, 0, pad->y, pad->x, in->video->h); | |||||
| if (needs_copy) { | |||||
| ff_copy_rectangle(out->data, out->linesize, in->data, in->linesize, | |||||
| pad->line_step, pad->hsub, pad->vsub, | |||||
| pad->x, pad->y, 0, in->video->w, in->video->h); | |||||
| } | } | ||||
| /* right border */ | /* right border */ | ||||
| ff_draw_rectangle(outpic->data, outpic->linesize, | |||||
| ff_draw_rectangle(out->data, out->linesize, | |||||
| pad->line, pad->line_step, pad->hsub, pad->vsub, | pad->line, pad->line_step, pad->hsub, pad->vsub, | ||||
| pad->x + pad->in_w, y, pad->w - pad->x - pad->in_w, h); | |||||
| ret = ff_draw_slice(link->dst->outputs[0], y, h, slice_dir); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| pad->x + pad->in_w, pad->y, pad->w - pad->x - pad->in_w, | |||||
| in->video->h); | |||||
| return draw_send_bar_slice(link, y, h, slice_dir, -1); | |||||
| avfilter_unref_bufferp(&in); | |||||
| return ff_filter_frame(inlink->dst->outputs[0], out); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_pad_inputs[] = { | static const AVFilterPad avfilter_vf_pad_inputs[] = { | ||||
| @@ -440,9 +389,7 @@ static const AVFilterPad avfilter_vf_pad_inputs[] = { | |||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .config_props = config_input, | .config_props = config_input, | ||||
| .get_video_buffer = get_video_buffer, | .get_video_buffer = get_video_buffer, | ||||
| .start_frame = start_frame, | |||||
| .draw_slice = draw_slice, | |||||
| .end_frame = end_frame, | |||||
| .filter_frame = filter_frame, | |||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| }; | }; | ||||
| @@ -52,86 +52,65 @@ static int config_props(AVFilterLink *inlink) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in) | |||||
| { | { | ||||
| PixdescTestContext *priv = inlink->dst->priv; | PixdescTestContext *priv = inlink->dst->priv; | ||||
| AVFilterLink *outlink = inlink->dst->outputs[0]; | AVFilterLink *outlink = inlink->dst->outputs[0]; | ||||
| AVFilterBufferRef *outpicref, *for_next_filter; | |||||
| int i, ret = 0; | |||||
| AVFilterBufferRef *out; | |||||
| int i, c, w = inlink->w, h = inlink->h; | |||||
| outpicref = ff_get_video_buffer(outlink, AV_PERM_WRITE, | |||||
| outlink->w, outlink->h); | |||||
| if (!outpicref) | |||||
| out = ff_get_video_buffer(outlink, AV_PERM_WRITE, | |||||
| outlink->w, outlink->h); | |||||
| if (!out) { | |||||
| avfilter_unref_bufferp(&in); | |||||
| return AVERROR(ENOMEM); | return AVERROR(ENOMEM); | ||||
| } | |||||
| avfilter_copy_buffer_ref_props(outpicref, picref); | |||||
| avfilter_copy_buffer_ref_props(out, in); | |||||
| for (i = 0; i < 4; i++) { | for (i = 0; i < 4; i++) { | ||||
| int h = outlink->h; | int h = outlink->h; | ||||
| h = i == 1 || i == 2 ? h>>priv->pix_desc->log2_chroma_h : h; | h = i == 1 || i == 2 ? h>>priv->pix_desc->log2_chroma_h : h; | ||||
| if (outpicref->data[i]) { | |||||
| uint8_t *data = outpicref->data[i] + | |||||
| (outpicref->linesize[i] > 0 ? 0 : outpicref->linesize[i] * (h-1)); | |||||
| memset(data, 0, FFABS(outpicref->linesize[i]) * h); | |||||
| if (out->data[i]) { | |||||
| uint8_t *data = out->data[i] + | |||||
| (out->linesize[i] > 0 ? 0 : out->linesize[i] * (h-1)); | |||||
| memset(data, 0, FFABS(out->linesize[i]) * h); | |||||
| } | } | ||||
| } | } | ||||
| /* copy palette */ | /* copy palette */ | ||||
| if (priv->pix_desc->flags & PIX_FMT_PAL || | if (priv->pix_desc->flags & PIX_FMT_PAL || | ||||
| priv->pix_desc->flags & PIX_FMT_PSEUDOPAL) | priv->pix_desc->flags & PIX_FMT_PSEUDOPAL) | ||||
| memcpy(outpicref->data[1], outpicref->data[1], 256*4); | |||||
| for_next_filter = avfilter_ref_buffer(outpicref, ~0); | |||||
| if (for_next_filter) | |||||
| ret = ff_start_frame(outlink, for_next_filter); | |||||
| else | |||||
| ret = AVERROR(ENOMEM); | |||||
| if (ret < 0) { | |||||
| avfilter_unref_bufferp(&outpicref); | |||||
| return ret; | |||||
| } | |||||
| outlink->out_buf = outpicref; | |||||
| return 0; | |||||
| } | |||||
| static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) | |||||
| { | |||||
| PixdescTestContext *priv = inlink->dst->priv; | |||||
| AVFilterBufferRef *inpic = inlink->cur_buf; | |||||
| AVFilterBufferRef *outpic = inlink->dst->outputs[0]->out_buf; | |||||
| int i, c, w = inlink->w; | |||||
| memcpy(out->data[1], in->data[1], 256*4); | |||||
| for (c = 0; c < priv->pix_desc->nb_components; c++) { | for (c = 0; c < priv->pix_desc->nb_components; c++) { | ||||
| int w1 = c == 1 || c == 2 ? w>>priv->pix_desc->log2_chroma_w : w; | int w1 = c == 1 || c == 2 ? w>>priv->pix_desc->log2_chroma_w : w; | ||||
| int h1 = c == 1 || c == 2 ? h>>priv->pix_desc->log2_chroma_h : h; | int h1 = c == 1 || c == 2 ? h>>priv->pix_desc->log2_chroma_h : h; | ||||
| int y1 = c == 1 || c == 2 ? y>>priv->pix_desc->log2_chroma_h : y; | |||||
| for (i = y1; i < y1 + h1; i++) { | |||||
| for (i = 0; i < h1; i++) { | |||||
| av_read_image_line(priv->line, | av_read_image_line(priv->line, | ||||
| inpic->data, | |||||
| inpic->linesize, | |||||
| in->data, | |||||
| in->linesize, | |||||
| priv->pix_desc, | priv->pix_desc, | ||||
| 0, i, c, w1, 0); | 0, i, c, w1, 0); | ||||
| av_write_image_line(priv->line, | av_write_image_line(priv->line, | ||||
| outpic->data, | |||||
| outpic->linesize, | |||||
| out->data, | |||||
| out->linesize, | |||||
| priv->pix_desc, | priv->pix_desc, | ||||
| 0, i, c, w1); | 0, i, c, w1); | ||||
| } | } | ||||
| } | } | ||||
| return ff_draw_slice(inlink->dst->outputs[0], y, h, slice_dir); | |||||
| avfilter_unref_bufferp(&in); | |||||
| return ff_filter_frame(outlink, out); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_pixdesctest_inputs[] = { | static const AVFilterPad avfilter_vf_pixdesctest_inputs[] = { | ||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .start_frame = start_frame, | |||||
| .draw_slice = draw_slice, | |||||
| .filter_frame = filter_frame, | |||||
| .config_props = config_props, | .config_props = config_props, | ||||
| .min_perms = AV_PERM_READ, | .min_perms = AV_PERM_READ, | ||||
| }, | }, | ||||
| @@ -257,93 +257,46 @@ fail: | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| static int start_frame(AVFilterLink *link, AVFilterBufferRef *picref) | |||||
| static int filter_frame(AVFilterLink *link, AVFilterBufferRef *in) | |||||
| { | { | ||||
| ScaleContext *scale = link->dst->priv; | ScaleContext *scale = link->dst->priv; | ||||
| AVFilterLink *outlink = link->dst->outputs[0]; | AVFilterLink *outlink = link->dst->outputs[0]; | ||||
| AVFilterBufferRef *outpicref, *for_next_filter; | |||||
| AVFilterBufferRef *out; | |||||
| const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format); | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format); | ||||
| int ret = 0; | |||||
| if (!scale->sws) { | |||||
| outpicref = avfilter_ref_buffer(picref, ~0); | |||||
| if (!outpicref) | |||||
| return AVERROR(ENOMEM); | |||||
| return ff_start_frame(outlink, outpicref); | |||||
| } | |||||
| if (!scale->sws) | |||||
| return ff_filter_frame(outlink, in); | |||||
| scale->hsub = desc->log2_chroma_w; | scale->hsub = desc->log2_chroma_w; | ||||
| scale->vsub = desc->log2_chroma_h; | scale->vsub = desc->log2_chroma_h; | ||||
| outpicref = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); | |||||
| if (!outpicref) | |||||
| out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); | |||||
| if (!out) { | |||||
| avfilter_unref_bufferp(&in); | |||||
| return AVERROR(ENOMEM); | return AVERROR(ENOMEM); | ||||
| avfilter_copy_buffer_ref_props(outpicref, picref); | |||||
| outpicref->video->w = outlink->w; | |||||
| outpicref->video->h = outlink->h; | |||||
| av_reduce(&outpicref->video->pixel_aspect.num, &outpicref->video->pixel_aspect.den, | |||||
| (int64_t)picref->video->pixel_aspect.num * outlink->h * link->w, | |||||
| (int64_t)picref->video->pixel_aspect.den * outlink->w * link->h, | |||||
| INT_MAX); | |||||
| scale->slice_y = 0; | |||||
| for_next_filter = avfilter_ref_buffer(outpicref, ~0); | |||||
| if (for_next_filter) | |||||
| ret = ff_start_frame(outlink, for_next_filter); | |||||
| else | |||||
| ret = AVERROR(ENOMEM); | |||||
| if (ret < 0) { | |||||
| avfilter_unref_bufferp(&outpicref); | |||||
| return ret; | |||||
| } | } | ||||
| outlink->out_buf = outpicref; | |||||
| return 0; | |||||
| } | |||||
| avfilter_copy_buffer_ref_props(out, in); | |||||
| out->video->w = outlink->w; | |||||
| out->video->h = outlink->h; | |||||
| static int draw_slice(AVFilterLink *link, int y, int h, int slice_dir) | |||||
| { | |||||
| ScaleContext *scale = link->dst->priv; | |||||
| int out_h, ret; | |||||
| AVFilterBufferRef *cur_pic = link->cur_buf; | |||||
| const uint8_t *data[4]; | |||||
| av_reduce(&out->video->pixel_aspect.num, &out->video->pixel_aspect.den, | |||||
| (int64_t)in->video->pixel_aspect.num * outlink->h * link->w, | |||||
| (int64_t)in->video->pixel_aspect.den * outlink->w * link->h, | |||||
| INT_MAX); | |||||
| if (!scale->sws) { | |||||
| return ff_draw_slice(link->dst->outputs[0], y, h, slice_dir); | |||||
| } | |||||
| sws_scale(scale->sws, in->data, in->linesize, 0, in->video->h, | |||||
| out->data, out->linesize); | |||||
| if (scale->slice_y == 0 && slice_dir == -1) | |||||
| scale->slice_y = link->dst->outputs[0]->h; | |||||
| data[0] = cur_pic->data[0] + y * cur_pic->linesize[0]; | |||||
| data[1] = scale->input_is_pal ? | |||||
| cur_pic->data[1] : | |||||
| cur_pic->data[1] + (y>>scale->vsub) * cur_pic->linesize[1]; | |||||
| data[2] = cur_pic->data[2] + (y>>scale->vsub) * cur_pic->linesize[2]; | |||||
| data[3] = cur_pic->data[3] + y * cur_pic->linesize[3]; | |||||
| out_h = sws_scale(scale->sws, data, cur_pic->linesize, y, h, | |||||
| link->dst->outputs[0]->out_buf->data, | |||||
| link->dst->outputs[0]->out_buf->linesize); | |||||
| if (slice_dir == -1) | |||||
| scale->slice_y -= out_h; | |||||
| ret = ff_draw_slice(link->dst->outputs[0], scale->slice_y, out_h, slice_dir); | |||||
| if (slice_dir == 1) | |||||
| scale->slice_y += out_h; | |||||
| return ret; | |||||
| avfilter_unref_bufferp(&in); | |||||
| return ff_filter_frame(outlink, out); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_scale_inputs[] = { | static const AVFilterPad avfilter_vf_scale_inputs[] = { | ||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .start_frame = start_frame, | |||||
| .draw_slice = draw_slice, | |||||
| .filter_frame = filter_frame, | |||||
| .min_perms = AV_PERM_READ, | .min_perms = AV_PERM_READ, | ||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| @@ -228,50 +228,27 @@ static int select_frame(AVFilterContext *ctx, AVFilterBufferRef *picref) | |||||
| return res; | return res; | ||||
| } | } | ||||
| static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame) | |||||
| { | { | ||||
| SelectContext *select = inlink->dst->priv; | SelectContext *select = inlink->dst->priv; | ||||
| select->select = select_frame(inlink->dst, picref); | |||||
| select->select = select_frame(inlink->dst, frame); | |||||
| if (select->select) { | if (select->select) { | ||||
| AVFilterBufferRef *buf_out; | |||||
| /* frame was requested through poll_frame */ | /* frame was requested through poll_frame */ | ||||
| if (select->cache_frames) { | if (select->cache_frames) { | ||||
| if (!av_fifo_space(select->pending_frames)) | |||||
| if (!av_fifo_space(select->pending_frames)) { | |||||
| av_log(inlink->dst, AV_LOG_ERROR, | av_log(inlink->dst, AV_LOG_ERROR, | ||||
| "Buffering limit reached, cannot cache more frames\n"); | "Buffering limit reached, cannot cache more frames\n"); | ||||
| else | |||||
| av_fifo_generic_write(select->pending_frames, &picref, | |||||
| sizeof(picref), NULL); | |||||
| avfilter_unref_bufferp(&frame); | |||||
| } else | |||||
| av_fifo_generic_write(select->pending_frames, &frame, | |||||
| sizeof(frame), NULL); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| buf_out = avfilter_ref_buffer(picref, ~0); | |||||
| if (!buf_out) | |||||
| return AVERROR(ENOMEM); | |||||
| return ff_start_frame(inlink->dst->outputs[0], buf_out); | |||||
| return ff_filter_frame(inlink->dst->outputs[0], frame); | |||||
| } | } | ||||
| return 0; | |||||
| } | |||||
| static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) | |||||
| { | |||||
| SelectContext *select = inlink->dst->priv; | |||||
| if (select->select && !select->cache_frames) | |||||
| return ff_draw_slice(inlink->dst->outputs[0], y, h, slice_dir); | |||||
| return 0; | |||||
| } | |||||
| static int end_frame(AVFilterLink *inlink) | |||||
| { | |||||
| SelectContext *select = inlink->dst->priv; | |||||
| if (select->select) { | |||||
| if (select->cache_frames) | |||||
| return 0; | |||||
| return ff_end_frame(inlink->dst->outputs[0]); | |||||
| } | |||||
| avfilter_unref_bufferp(&frame); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -284,14 +261,9 @@ static int request_frame(AVFilterLink *outlink) | |||||
| if (av_fifo_size(select->pending_frames)) { | if (av_fifo_size(select->pending_frames)) { | ||||
| AVFilterBufferRef *picref; | AVFilterBufferRef *picref; | ||||
| int ret; | |||||
| av_fifo_generic_read(select->pending_frames, &picref, sizeof(picref), NULL); | av_fifo_generic_read(select->pending_frames, &picref, sizeof(picref), NULL); | ||||
| if ((ret = ff_start_frame(outlink, picref)) < 0 || | |||||
| (ret = ff_draw_slice(outlink, 0, outlink->h, 1)) < 0 || | |||||
| (ret = ff_end_frame(outlink)) < 0); | |||||
| return ret; | |||||
| return ff_filter_frame(outlink, picref); | |||||
| } | } | ||||
| while (!select->select) { | while (!select->select) { | ||||
| @@ -346,9 +318,7 @@ static const AVFilterPad avfilter_vf_select_inputs[] = { | |||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .get_video_buffer = ff_null_get_video_buffer, | .get_video_buffer = ff_null_get_video_buffer, | ||||
| .config_props = config_input, | .config_props = config_input, | ||||
| .start_frame = start_frame, | |||||
| .draw_slice = draw_slice, | |||||
| .end_frame = end_frame | |||||
| .filter_frame = filter_frame, | |||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| }; | }; | ||||
| @@ -102,39 +102,36 @@ static int config_input(AVFilterLink *inlink) | |||||
| #define D2TS(d) (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d)) | #define D2TS(d) (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d)) | ||||
| #define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts)) | #define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts)) | ||||
| static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame) | |||||
| { | { | ||||
| SetPTSContext *setpts = inlink->dst->priv; | SetPTSContext *setpts = inlink->dst->priv; | ||||
| int64_t in_pts = frame->pts; | |||||
| double d; | double d; | ||||
| AVFilterBufferRef *outpicref = avfilter_ref_buffer(inpicref, ~0); | |||||
| if (!outpicref) | |||||
| return AVERROR(ENOMEM); | |||||
| if (isnan(setpts->var_values[VAR_STARTPTS])) | if (isnan(setpts->var_values[VAR_STARTPTS])) | ||||
| setpts->var_values[VAR_STARTPTS] = TS2D(inpicref->pts); | |||||
| setpts->var_values[VAR_STARTPTS] = TS2D(frame->pts); | |||||
| setpts->var_values[VAR_INTERLACED] = inpicref->video->interlaced; | |||||
| setpts->var_values[VAR_PTS ] = TS2D(inpicref->pts); | |||||
| setpts->var_values[VAR_POS ] = inpicref->pos == -1 ? NAN : inpicref->pos; | |||||
| setpts->var_values[VAR_INTERLACED] = frame->video->interlaced; | |||||
| setpts->var_values[VAR_PTS ] = TS2D(frame->pts); | |||||
| setpts->var_values[VAR_POS ] = frame->pos == -1 ? NAN : frame->pos; | |||||
| d = av_expr_eval(setpts->expr, setpts->var_values, NULL); | d = av_expr_eval(setpts->expr, setpts->var_values, NULL); | ||||
| outpicref->pts = D2TS(d); | |||||
| frame->pts = D2TS(d); | |||||
| #ifdef DEBUG | #ifdef DEBUG | ||||
| av_log(inlink->dst, AV_LOG_DEBUG, | av_log(inlink->dst, AV_LOG_DEBUG, | ||||
| "n:%"PRId64" interlaced:%d pos:%"PRId64" pts:%"PRId64" t:%f -> pts:%"PRId64" t:%f\n", | "n:%"PRId64" interlaced:%d pos:%"PRId64" pts:%"PRId64" t:%f -> pts:%"PRId64" t:%f\n", | ||||
| (int64_t)setpts->var_values[VAR_N], | (int64_t)setpts->var_values[VAR_N], | ||||
| (int)setpts->var_values[VAR_INTERLACED], | (int)setpts->var_values[VAR_INTERLACED], | ||||
| inpicref ->pos, | |||||
| inpicref ->pts, inpicref ->pts * av_q2d(inlink->time_base), | |||||
| outpicref->pts, outpicref->pts * av_q2d(inlink->time_base)); | |||||
| frame->pos, in_pts, in_pts * av_q2d(inlink->time_base), | |||||
| frame->pts, frame->pts * av_q2d(inlink->time_base)); | |||||
| #endif | #endif | ||||
| setpts->var_values[VAR_N] += 1.0; | setpts->var_values[VAR_N] += 1.0; | ||||
| setpts->var_values[VAR_PREV_INPTS ] = TS2D(inpicref ->pts); | |||||
| setpts->var_values[VAR_PREV_OUTPTS] = TS2D(outpicref->pts); | |||||
| return ff_start_frame(inlink->dst->outputs[0], outpicref); | |||||
| setpts->var_values[VAR_PREV_INPTS ] = TS2D(in_pts); | |||||
| setpts->var_values[VAR_PREV_OUTPTS] = TS2D(frame->pts); | |||||
| return ff_filter_frame(inlink->dst->outputs[0], frame); | |||||
| } | } | ||||
| static av_cold void uninit(AVFilterContext *ctx) | static av_cold void uninit(AVFilterContext *ctx) | ||||
| @@ -150,7 +147,7 @@ static const AVFilterPad avfilter_vf_setpts_inputs[] = { | |||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .get_video_buffer = ff_null_get_video_buffer, | .get_video_buffer = ff_null_get_video_buffer, | ||||
| .config_props = config_input, | .config_props = config_input, | ||||
| .start_frame = start_frame, | |||||
| .filter_frame = filter_frame, | |||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| }; | }; | ||||
| @@ -108,21 +108,20 @@ static int config_output_props(AVFilterLink *outlink) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame) | |||||
| { | { | ||||
| AVFilterContext *ctx = inlink->dst; | AVFilterContext *ctx = inlink->dst; | ||||
| AVFilterLink *outlink = ctx->outputs[0]; | AVFilterLink *outlink = ctx->outputs[0]; | ||||
| if (av_cmp_q(inlink->time_base, outlink->time_base)) { | if (av_cmp_q(inlink->time_base, outlink->time_base)) { | ||||
| int64_t orig_pts = picref->pts; | |||||
| picref->pts = av_rescale_q(picref->pts, inlink->time_base, outlink->time_base); | |||||
| int64_t orig_pts = frame->pts; | |||||
| frame->pts = av_rescale_q(frame->pts, inlink->time_base, outlink->time_base); | |||||
| av_log(ctx, AV_LOG_DEBUG, "tb:%d/%d pts:%"PRId64" -> tb:%d/%d pts:%"PRId64"\n", | av_log(ctx, AV_LOG_DEBUG, "tb:%d/%d pts:%"PRId64" -> tb:%d/%d pts:%"PRId64"\n", | ||||
| inlink ->time_base.num, inlink ->time_base.den, orig_pts, | inlink ->time_base.num, inlink ->time_base.den, orig_pts, | ||||
| outlink->time_base.num, outlink->time_base.den, picref->pts); | |||||
| outlink->time_base.num, outlink->time_base.den, frame->pts); | |||||
| } | } | ||||
| inlink->cur_buf = NULL; | |||||
| return ff_start_frame(outlink, picref); | |||||
| return ff_filter_frame(outlink, frame); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_settb_inputs[] = { | static const AVFilterPad avfilter_vf_settb_inputs[] = { | ||||
| @@ -130,8 +129,7 @@ static const AVFilterPad avfilter_vf_settb_inputs[] = { | |||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .get_video_buffer = ff_null_get_video_buffer, | .get_video_buffer = ff_null_get_video_buffer, | ||||
| .start_frame = start_frame, | |||||
| .end_frame = ff_null_end_frame | |||||
| .filter_frame = filter_frame, | |||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| }; | }; | ||||
| @@ -41,24 +41,23 @@ static av_cold int init(AVFilterContext *ctx, const char *args) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int end_frame(AVFilterLink *inlink) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame) | |||||
| { | { | ||||
| AVFilterContext *ctx = inlink->dst; | AVFilterContext *ctx = inlink->dst; | ||||
| ShowInfoContext *showinfo = ctx->priv; | ShowInfoContext *showinfo = ctx->priv; | ||||
| AVFilterBufferRef *picref = inlink->cur_buf; | |||||
| const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); | ||||
| uint32_t plane_checksum[4] = {0}, checksum = 0; | uint32_t plane_checksum[4] = {0}, checksum = 0; | ||||
| int i, plane, vsub = desc->log2_chroma_h; | int i, plane, vsub = desc->log2_chroma_h; | ||||
| for (plane = 0; picref->data[plane] && plane < 4; plane++) { | |||||
| size_t linesize = av_image_get_linesize(picref->format, picref->video->w, plane); | |||||
| uint8_t *data = picref->data[plane]; | |||||
| for (plane = 0; frame->data[plane] && plane < 4; plane++) { | |||||
| size_t linesize = av_image_get_linesize(frame->format, frame->video->w, plane); | |||||
| uint8_t *data = frame->data[plane]; | |||||
| int h = plane == 1 || plane == 2 ? inlink->h >> vsub : inlink->h; | int h = plane == 1 || plane == 2 ? inlink->h >> vsub : inlink->h; | ||||
| for (i = 0; i < h; i++) { | for (i = 0; i < h; i++) { | ||||
| plane_checksum[plane] = av_adler32_update(plane_checksum[plane], data, linesize); | plane_checksum[plane] = av_adler32_update(plane_checksum[plane], data, linesize); | ||||
| checksum = av_adler32_update(checksum, data, linesize); | checksum = av_adler32_update(checksum, data, linesize); | ||||
| data += picref->linesize[plane]; | |||||
| data += frame->linesize[plane]; | |||||
| } | } | ||||
| } | } | ||||
| @@ -67,18 +66,18 @@ static int end_frame(AVFilterLink *inlink) | |||||
| "fmt:%s sar:%d/%d s:%dx%d i:%c iskey:%d type:%c " | "fmt:%s sar:%d/%d s:%dx%d i:%c iskey:%d type:%c " | ||||
| "checksum:%u plane_checksum:[%u %u %u %u]\n", | "checksum:%u plane_checksum:[%u %u %u %u]\n", | ||||
| showinfo->frame, | showinfo->frame, | ||||
| picref->pts, picref->pts * av_q2d(inlink->time_base), picref->pos, | |||||
| frame->pts, frame->pts * av_q2d(inlink->time_base), frame->pos, | |||||
| desc->name, | desc->name, | ||||
| picref->video->pixel_aspect.num, picref->video->pixel_aspect.den, | |||||
| picref->video->w, picref->video->h, | |||||
| !picref->video->interlaced ? 'P' : /* Progressive */ | |||||
| picref->video->top_field_first ? 'T' : 'B', /* Top / Bottom */ | |||||
| picref->video->key_frame, | |||||
| av_get_picture_type_char(picref->video->pict_type), | |||||
| frame->video->pixel_aspect.num, frame->video->pixel_aspect.den, | |||||
| frame->video->w, frame->video->h, | |||||
| !frame->video->interlaced ? 'P' : /* Progressive */ | |||||
| frame->video->top_field_first ? 'T' : 'B', /* Top / Bottom */ | |||||
| frame->video->key_frame, | |||||
| av_get_picture_type_char(frame->video->pict_type), | |||||
| checksum, plane_checksum[0], plane_checksum[1], plane_checksum[2], plane_checksum[3]); | checksum, plane_checksum[0], plane_checksum[1], plane_checksum[2], plane_checksum[3]); | ||||
| showinfo->frame++; | showinfo->frame++; | ||||
| return ff_end_frame(inlink->dst->outputs[0]); | |||||
| return ff_filter_frame(inlink->dst->outputs[0], frame); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_showinfo_inputs[] = { | static const AVFilterPad avfilter_vf_showinfo_inputs[] = { | ||||
| @@ -86,8 +85,7 @@ static const AVFilterPad avfilter_vf_showinfo_inputs[] = { | |||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .get_video_buffer = ff_null_get_video_buffer, | .get_video_buffer = ff_null_get_video_buffer, | ||||
| .start_frame = ff_null_start_frame, | |||||
| .end_frame = end_frame, | |||||
| .filter_frame = filter_frame, | |||||
| .min_perms = AV_PERM_READ, | .min_perms = AV_PERM_READ, | ||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| @@ -121,100 +121,88 @@ static int config_props_output(AVFilterLink *outlink) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref) | |||||
| static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in) | |||||
| { | { | ||||
| AVFilterLink *outlink = inlink->dst->outputs[0]; | AVFilterLink *outlink = inlink->dst->outputs[0]; | ||||
| AVFilterBufferRef *buf_out; | |||||
| TransContext *trans = inlink->dst->priv; | |||||
| AVFilterBufferRef *out; | |||||
| int plane; | |||||
| outlink->out_buf = ff_get_video_buffer(outlink, AV_PERM_WRITE, | |||||
| outlink->w, outlink->h); | |||||
| if (!outlink->out_buf) | |||||
| out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); | |||||
| if (!out) { | |||||
| avfilter_unref_bufferp(&in); | |||||
| return AVERROR(ENOMEM); | return AVERROR(ENOMEM); | ||||
| } | |||||
| outlink->out_buf->pts = picref->pts; | |||||
| out->pts = in->pts; | |||||
| if (picref->video->pixel_aspect.num == 0) { | |||||
| outlink->out_buf->video->pixel_aspect = picref->video->pixel_aspect; | |||||
| if (in->video->pixel_aspect.num == 0) { | |||||
| out->video->pixel_aspect = in->video->pixel_aspect; | |||||
| } else { | } else { | ||||
| outlink->out_buf->video->pixel_aspect.num = picref->video->pixel_aspect.den; | |||||
| outlink->out_buf->video->pixel_aspect.den = picref->video->pixel_aspect.num; | |||||
| out->video->pixel_aspect.num = in->video->pixel_aspect.den; | |||||
| out->video->pixel_aspect.den = in->video->pixel_aspect.num; | |||||
| } | } | ||||
| buf_out = avfilter_ref_buffer(outlink->out_buf, ~0); | |||||
| if (!buf_out) | |||||
| return AVERROR(ENOMEM); | |||||
| return ff_start_frame(outlink, buf_out); | |||||
| } | |||||
| static int end_frame(AVFilterLink *inlink) | |||||
| { | |||||
| TransContext *trans = inlink->dst->priv; | |||||
| AVFilterBufferRef *inpic = inlink->cur_buf; | |||||
| AVFilterBufferRef *outpic = inlink->dst->outputs[0]->out_buf; | |||||
| AVFilterLink *outlink = inlink->dst->outputs[0]; | |||||
| int plane, ret; | |||||
| for (plane = 0; outpic->data[plane]; plane++) { | |||||
| for (plane = 0; out->data[plane]; plane++) { | |||||
| int hsub = plane == 1 || plane == 2 ? trans->hsub : 0; | int hsub = plane == 1 || plane == 2 ? trans->hsub : 0; | ||||
| int vsub = plane == 1 || plane == 2 ? trans->vsub : 0; | int vsub = plane == 1 || plane == 2 ? trans->vsub : 0; | ||||
| int pixstep = trans->pixsteps[plane]; | int pixstep = trans->pixsteps[plane]; | ||||
| int inh = inpic->video->h>>vsub; | |||||
| int outw = outpic->video->w>>hsub; | |||||
| int outh = outpic->video->h>>vsub; | |||||
| uint8_t *out, *in; | |||||
| int outlinesize, inlinesize; | |||||
| int inh = in->video->h>>vsub; | |||||
| int outw = out->video->w>>hsub; | |||||
| int outh = out->video->h>>vsub; | |||||
| uint8_t *dst, *src; | |||||
| int dstlinesize, srclinesize; | |||||
| int x, y; | int x, y; | ||||
| out = outpic->data[plane]; outlinesize = outpic->linesize[plane]; | |||||
| in = inpic ->data[plane]; inlinesize = inpic ->linesize[plane]; | |||||
| dst = out->data[plane]; | |||||
| dstlinesize = out->linesize[plane]; | |||||
| src = in->data[plane]; | |||||
| srclinesize = in->linesize[plane]; | |||||
| if (trans->dir&1) { | if (trans->dir&1) { | ||||
| in += inpic->linesize[plane] * (inh-1); | |||||
| inlinesize *= -1; | |||||
| src += in->linesize[plane] * (inh-1); | |||||
| srclinesize *= -1; | |||||
| } | } | ||||
| if (trans->dir&2) { | if (trans->dir&2) { | ||||
| out += outpic->linesize[plane] * (outh-1); | |||||
| outlinesize *= -1; | |||||
| dst += out->linesize[plane] * (outh-1); | |||||
| dstlinesize *= -1; | |||||
| } | } | ||||
| for (y = 0; y < outh; y++) { | for (y = 0; y < outh; y++) { | ||||
| switch (pixstep) { | switch (pixstep) { | ||||
| case 1: | case 1: | ||||
| for (x = 0; x < outw; x++) | for (x = 0; x < outw; x++) | ||||
| out[x] = in[x*inlinesize + y]; | |||||
| dst[x] = src[x*srclinesize + y]; | |||||
| break; | break; | ||||
| case 2: | case 2: | ||||
| for (x = 0; x < outw; x++) | for (x = 0; x < outw; x++) | ||||
| *((uint16_t *)(out + 2*x)) = *((uint16_t *)(in + x*inlinesize + y*2)); | |||||
| *((uint16_t *)(dst + 2*x)) = *((uint16_t *)(src + x*srclinesize + y*2)); | |||||
| break; | break; | ||||
| case 3: | case 3: | ||||
| for (x = 0; x < outw; x++) { | for (x = 0; x < outw; x++) { | ||||
| int32_t v = AV_RB24(in + x*inlinesize + y*3); | |||||
| AV_WB24(out + 3*x, v); | |||||
| int32_t v = AV_RB24(src + x*srclinesize + y*3); | |||||
| AV_WB24(dst + 3*x, v); | |||||
| } | } | ||||
| break; | break; | ||||
| case 4: | case 4: | ||||
| for (x = 0; x < outw; x++) | for (x = 0; x < outw; x++) | ||||
| *((uint32_t *)(out + 4*x)) = *((uint32_t *)(in + x*inlinesize + y*4)); | |||||
| *((uint32_t *)(dst + 4*x)) = *((uint32_t *)(src + x*srclinesize + y*4)); | |||||
| break; | break; | ||||
| } | } | ||||
| out += outlinesize; | |||||
| dst += dstlinesize; | |||||
| } | } | ||||
| } | } | ||||
| if ((ret = ff_draw_slice(outlink, 0, outpic->video->h, 1)) < 0 || | |||||
| (ret = ff_end_frame(outlink)) < 0) | |||||
| return ret; | |||||
| return 0; | |||||
| avfilter_unref_bufferp(&in); | |||||
| return ff_filter_frame(outlink, out); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_transpose_inputs[] = { | static const AVFilterPad avfilter_vf_transpose_inputs[] = { | ||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .start_frame = start_frame, | |||||
| .end_frame = end_frame, | |||||
| .filter_frame = filter_frame, | |||||
| .min_perms = AV_PERM_READ, | .min_perms = AV_PERM_READ, | ||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| @@ -214,36 +214,34 @@ static av_cold void uninit(AVFilterContext *ctx) | |||||
| free_filter_param(&unsharp->chroma); | free_filter_param(&unsharp->chroma); | ||||
| } | } | ||||
| static int end_frame(AVFilterLink *link) | |||||
| static int filter_frame(AVFilterLink *link, AVFilterBufferRef *in) | |||||
| { | { | ||||
| UnsharpContext *unsharp = link->dst->priv; | UnsharpContext *unsharp = link->dst->priv; | ||||
| AVFilterBufferRef *in = link->cur_buf; | |||||
| AVFilterBufferRef *out = link->dst->outputs[0]->out_buf; | |||||
| AVFilterLink *outlink = link->dst->outputs[0]; | |||||
| AVFilterBufferRef *out; | |||||
| int cw = SHIFTUP(link->w, unsharp->hsub); | int cw = SHIFTUP(link->w, unsharp->hsub); | ||||
| int ch = SHIFTUP(link->h, unsharp->vsub); | int ch = SHIFTUP(link->h, unsharp->vsub); | ||||
| int ret; | |||||
| out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); | |||||
| if (!out) { | |||||
| avfilter_unref_bufferp(&in); | |||||
| return AVERROR(ENOMEM); | |||||
| } | |||||
| avfilter_copy_buffer_ref_props(out, in); | |||||
| apply_unsharp(out->data[0], out->linesize[0], in->data[0], in->linesize[0], link->w, link->h, &unsharp->luma); | apply_unsharp(out->data[0], out->linesize[0], in->data[0], in->linesize[0], link->w, link->h, &unsharp->luma); | ||||
| apply_unsharp(out->data[1], out->linesize[1], in->data[1], in->linesize[1], cw, ch, &unsharp->chroma); | apply_unsharp(out->data[1], out->linesize[1], in->data[1], in->linesize[1], cw, ch, &unsharp->chroma); | ||||
| apply_unsharp(out->data[2], out->linesize[2], in->data[2], in->linesize[2], cw, ch, &unsharp->chroma); | apply_unsharp(out->data[2], out->linesize[2], in->data[2], in->linesize[2], cw, ch, &unsharp->chroma); | ||||
| if ((ret = ff_draw_slice(link->dst->outputs[0], 0, link->h, 1)) < 0 || | |||||
| (ret = ff_end_frame(link->dst->outputs[0])) < 0) | |||||
| return ret; | |||||
| return 0; | |||||
| } | |||||
| static int draw_slice(AVFilterLink *link, int y, int h, int slice_dir) | |||||
| { | |||||
| return 0; | |||||
| avfilter_unref_bufferp(&in); | |||||
| return ff_filter_frame(outlink, out); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_unsharp_inputs[] = { | static const AVFilterPad avfilter_vf_unsharp_inputs[] = { | ||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .draw_slice = draw_slice, | |||||
| .end_frame = end_frame, | |||||
| .filter_frame = filter_frame, | |||||
| .config_props = config_props, | .config_props = config_props, | ||||
| .min_perms = AV_PERM_READ, | .min_perms = AV_PERM_READ, | ||||
| }, | }, | ||||
| @@ -69,41 +69,28 @@ static AVFilterBufferRef *get_video_buffer(AVFilterLink *link, int perms, | |||||
| return picref; | return picref; | ||||
| } | } | ||||
| static int start_frame(AVFilterLink *link, AVFilterBufferRef *inpicref) | |||||
| static int filter_frame(AVFilterLink *link, AVFilterBufferRef *frame) | |||||
| { | { | ||||
| FlipContext *flip = link->dst->priv; | FlipContext *flip = link->dst->priv; | ||||
| AVFilterBufferRef *outpicref = avfilter_ref_buffer(inpicref, ~0); | |||||
| int i; | int i; | ||||
| if (!outpicref) | |||||
| return AVERROR(ENOMEM); | |||||
| for (i = 0; i < 4; i ++) { | for (i = 0; i < 4; i ++) { | ||||
| int vsub = i == 1 || i == 2 ? flip->vsub : 0; | int vsub = i == 1 || i == 2 ? flip->vsub : 0; | ||||
| if (outpicref->data[i]) { | |||||
| outpicref->data[i] += ((link->h >> vsub)-1) * outpicref->linesize[i]; | |||||
| outpicref->linesize[i] = -outpicref->linesize[i]; | |||||
| if (frame->data[i]) { | |||||
| frame->data[i] += ((link->h >> vsub)-1) * frame->linesize[i]; | |||||
| frame->linesize[i] = -frame->linesize[i]; | |||||
| } | } | ||||
| } | } | ||||
| return ff_start_frame(link->dst->outputs[0], outpicref); | |||||
| } | |||||
| static int draw_slice(AVFilterLink *link, int y, int h, int slice_dir) | |||||
| { | |||||
| AVFilterContext *ctx = link->dst; | |||||
| return ff_draw_slice(ctx->outputs[0], link->h - (y+h), h, -1 * slice_dir); | |||||
| return ff_filter_frame(link->dst->outputs[0], frame); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vf_vflip_inputs[] = { | static const AVFilterPad avfilter_vf_vflip_inputs[] = { | ||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .get_video_buffer = get_video_buffer, | .get_video_buffer = get_video_buffer, | ||||
| .start_frame = start_frame, | |||||
| .draw_slice = draw_slice, | |||||
| .filter_frame = filter_frame, | |||||
| .config_props = config_input, | .config_props = config_input, | ||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| @@ -202,19 +202,14 @@ static int return_frame(AVFilterContext *ctx, int is_second) | |||||
| } else { | } else { | ||||
| yadif->out->pts = AV_NOPTS_VALUE; | yadif->out->pts = AV_NOPTS_VALUE; | ||||
| } | } | ||||
| ret = ff_start_frame(ctx->outputs[0], yadif->out); | |||||
| if (ret < 0) | |||||
| return ret; | |||||
| } | } | ||||
| if ((ret = ff_draw_slice(ctx->outputs[0], 0, link->h, 1)) < 0 || | |||||
| (ret = ff_end_frame(ctx->outputs[0])) < 0) | |||||
| return ret; | |||||
| ret = ff_filter_frame(ctx->outputs[0], yadif->out); | |||||
| yadif->frame_pending = (yadif->mode&1) && !is_second; | yadif->frame_pending = (yadif->mode&1) && !is_second; | ||||
| return 0; | |||||
| return ret; | |||||
| } | } | ||||
| static int start_frame(AVFilterLink *link, AVFilterBufferRef *picref) | |||||
| static int filter_frame(AVFilterLink *link, AVFilterBufferRef *picref) | |||||
| { | { | ||||
| AVFilterContext *ctx = link->dst; | AVFilterContext *ctx = link->dst; | ||||
| YADIFContext *yadif = ctx->priv; | YADIFContext *yadif = ctx->priv; | ||||
| @@ -227,7 +222,6 @@ static int start_frame(AVFilterLink *link, AVFilterBufferRef *picref) | |||||
| yadif->prev = yadif->cur; | yadif->prev = yadif->cur; | ||||
| yadif->cur = yadif->next; | yadif->cur = yadif->next; | ||||
| yadif->next = picref; | yadif->next = picref; | ||||
| link->cur_buf = NULL; | |||||
| if (!yadif->cur) | if (!yadif->cur) | ||||
| return 0; | return 0; | ||||
| @@ -240,7 +234,7 @@ static int start_frame(AVFilterLink *link, AVFilterBufferRef *picref) | |||||
| avfilter_unref_bufferp(&yadif->prev); | avfilter_unref_bufferp(&yadif->prev); | ||||
| if (yadif->out->pts != AV_NOPTS_VALUE) | if (yadif->out->pts != AV_NOPTS_VALUE) | ||||
| yadif->out->pts *= 2; | yadif->out->pts *= 2; | ||||
| return ff_start_frame(ctx->outputs[0], yadif->out); | |||||
| return ff_filter_frame(ctx->outputs[0], yadif->out); | |||||
| } | } | ||||
| if (!yadif->prev && | if (!yadif->prev && | ||||
| @@ -258,26 +252,7 @@ static int start_frame(AVFilterLink *link, AVFilterBufferRef *picref) | |||||
| if (yadif->out->pts != AV_NOPTS_VALUE) | if (yadif->out->pts != AV_NOPTS_VALUE) | ||||
| yadif->out->pts *= 2; | yadif->out->pts *= 2; | ||||
| return ff_start_frame(ctx->outputs[0], yadif->out); | |||||
| } | |||||
| static int end_frame(AVFilterLink *link) | |||||
| { | |||||
| AVFilterContext *ctx = link->dst; | |||||
| YADIFContext *yadif = ctx->priv; | |||||
| if (!yadif->out) | |||||
| return 0; | |||||
| if (yadif->auto_enable && !yadif->cur->video->interlaced) { | |||||
| int ret = ff_draw_slice(ctx->outputs[0], 0, link->h, 1); | |||||
| if (ret >= 0) | |||||
| ret = ff_end_frame(ctx->outputs[0]); | |||||
| return ret; | |||||
| } | |||||
| return_frame(ctx, 0); | |||||
| return 0; | |||||
| return return_frame(ctx, 0); | |||||
| } | } | ||||
| static int request_frame(AVFilterLink *link) | static int request_frame(AVFilterLink *link) | ||||
| @@ -307,8 +282,7 @@ static int request_frame(AVFilterLink *link) | |||||
| next->pts = yadif->next->pts * 2 - yadif->cur->pts; | next->pts = yadif->next->pts * 2 - yadif->cur->pts; | ||||
| start_frame(link->src->inputs[0], next); | |||||
| end_frame(link->src->inputs[0]); | |||||
| filter_frame(link->src->inputs[0], next); | |||||
| yadif->eof = 1; | yadif->eof = 1; | ||||
| } else if (ret < 0) { | } else if (ret < 0) { | ||||
| return ret; | return ret; | ||||
| @@ -409,11 +383,6 @@ static av_cold int init(AVFilterContext *ctx, const char *args) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) | |||||
| { | |||||
| return 0; | |||||
| } | |||||
| static int config_props(AVFilterLink *link) | static int config_props(AVFilterLink *link) | ||||
| { | { | ||||
| link->time_base.num = link->src->inputs[0]->time_base.num; | link->time_base.num = link->src->inputs[0]->time_base.num; | ||||
| @@ -428,10 +397,8 @@ static const AVFilterPad avfilter_vf_yadif_inputs[] = { | |||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .start_frame = start_frame, | |||||
| .get_video_buffer = get_video_buffer, | .get_video_buffer = get_video_buffer, | ||||
| .draw_slice = null_draw_slice, | |||||
| .end_frame = end_frame, | |||||
| .filter_frame = filter_frame, | |||||
| }, | }, | ||||
| { NULL } | { NULL } | ||||
| }; | }; | ||||
| @@ -163,213 +163,3 @@ AVFilterBufferRef *ff_get_video_buffer(AVFilterLink *link, int perms, int w, int | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| int ff_null_start_frame(AVFilterLink *link, AVFilterBufferRef *picref) | |||||
| { | |||||
| AVFilterBufferRef *buf_out = avfilter_ref_buffer(picref, ~0); | |||||
| if (!buf_out) | |||||
| return AVERROR(ENOMEM); | |||||
| return ff_start_frame(link->dst->outputs[0], buf_out); | |||||
| } | |||||
| // for filters that support (but don't require) outpic==inpic | |||||
| int ff_inplace_start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref) | |||||
| { | |||||
| AVFilterLink *outlink = inlink->dst->outputs[0]; | |||||
| AVFilterBufferRef *outpicref = NULL, *for_next_filter; | |||||
| int ret = 0; | |||||
| if ((inpicref->perms & AV_PERM_WRITE) && !(inpicref->perms & AV_PERM_PRESERVE)) { | |||||
| outpicref = avfilter_ref_buffer(inpicref, ~0); | |||||
| if (!outpicref) | |||||
| return AVERROR(ENOMEM); | |||||
| } else { | |||||
| outpicref = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); | |||||
| if (!outpicref) | |||||
| return AVERROR(ENOMEM); | |||||
| avfilter_copy_buffer_ref_props(outpicref, inpicref); | |||||
| outpicref->video->w = outlink->w; | |||||
| outpicref->video->h = outlink->h; | |||||
| } | |||||
| for_next_filter = avfilter_ref_buffer(outpicref, ~0); | |||||
| if (for_next_filter) | |||||
| ret = ff_start_frame(outlink, for_next_filter); | |||||
| else | |||||
| ret = AVERROR(ENOMEM); | |||||
| if (ret < 0) { | |||||
| avfilter_unref_bufferp(&outpicref); | |||||
| return ret; | |||||
| } | |||||
| outlink->out_buf = outpicref; | |||||
| return 0; | |||||
| } | |||||
| static int default_start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref) | |||||
| { | |||||
| AVFilterLink *outlink = NULL; | |||||
| if (inlink->dst->nb_outputs) | |||||
| outlink = inlink->dst->outputs[0]; | |||||
| if (outlink) { | |||||
| AVFilterBufferRef *buf_out; | |||||
| outlink->out_buf = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); | |||||
| if (!outlink->out_buf) | |||||
| return AVERROR(ENOMEM); | |||||
| avfilter_copy_buffer_ref_props(outlink->out_buf, picref); | |||||
| buf_out = avfilter_ref_buffer(outlink->out_buf, ~0); | |||||
| if (!buf_out) | |||||
| return AVERROR(ENOMEM); | |||||
| return ff_start_frame(outlink, buf_out); | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| static void clear_link(AVFilterLink *link) | |||||
| { | |||||
| avfilter_unref_bufferp(&link->cur_buf); | |||||
| avfilter_unref_bufferp(&link->src_buf); | |||||
| avfilter_unref_bufferp(&link->out_buf); | |||||
| } | |||||
| /* XXX: should we do the duplicating of the picture ref here, instead of | |||||
| * forcing the source filter to do it? */ | |||||
| int ff_start_frame(AVFilterLink *link, AVFilterBufferRef *picref) | |||||
| { | |||||
| int (*start_frame)(AVFilterLink *, AVFilterBufferRef *); | |||||
| AVFilterPad *dst = link->dstpad; | |||||
| int ret, perms = picref->perms; | |||||
| FF_DPRINTF_START(NULL, start_frame); ff_dlog_link(NULL, link, 0); av_dlog(NULL, " "); ff_dlog_ref(NULL, picref, 1); | |||||
| if (!(start_frame = dst->start_frame)) | |||||
| start_frame = default_start_frame; | |||||
| if (picref->linesize[0] < 0) | |||||
| perms |= AV_PERM_NEG_LINESIZES; | |||||
| /* prepare to copy the picture if it has insufficient permissions */ | |||||
| if ((dst->min_perms & perms) != dst->min_perms || dst->rej_perms & perms) { | |||||
| av_log(link->dst, AV_LOG_DEBUG, | |||||
| "frame copy needed (have perms %x, need %x, reject %x)\n", | |||||
| picref->perms, | |||||
| link->dstpad->min_perms, link->dstpad->rej_perms); | |||||
| link->cur_buf = ff_get_video_buffer(link, dst->min_perms, link->w, link->h); | |||||
| if (!link->cur_buf) { | |||||
| avfilter_unref_bufferp(&picref); | |||||
| return AVERROR(ENOMEM); | |||||
| } | |||||
| link->src_buf = picref; | |||||
| avfilter_copy_buffer_ref_props(link->cur_buf, link->src_buf); | |||||
| } | |||||
| else | |||||
| link->cur_buf = picref; | |||||
| ret = start_frame(link, link->cur_buf); | |||||
| if (ret < 0) | |||||
| clear_link(link); | |||||
| return ret; | |||||
| } | |||||
| int ff_null_end_frame(AVFilterLink *link) | |||||
| { | |||||
| return ff_end_frame(link->dst->outputs[0]); | |||||
| } | |||||
| static int default_end_frame(AVFilterLink *inlink) | |||||
| { | |||||
| AVFilterLink *outlink = NULL; | |||||
| if (inlink->dst->nb_outputs) | |||||
| outlink = inlink->dst->outputs[0]; | |||||
| if (outlink) { | |||||
| return ff_end_frame(outlink); | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| int ff_end_frame(AVFilterLink *link) | |||||
| { | |||||
| int (*end_frame)(AVFilterLink *); | |||||
| int ret; | |||||
| if (!(end_frame = link->dstpad->end_frame)) | |||||
| end_frame = default_end_frame; | |||||
| ret = end_frame(link); | |||||
| clear_link(link); | |||||
| return ret; | |||||
| } | |||||
| int ff_null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) | |||||
| { | |||||
| return ff_draw_slice(link->dst->outputs[0], y, h, slice_dir); | |||||
| } | |||||
| static int default_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) | |||||
| { | |||||
| AVFilterLink *outlink = NULL; | |||||
| if (inlink->dst->nb_outputs) | |||||
| outlink = inlink->dst->outputs[0]; | |||||
| if (outlink) | |||||
| return ff_draw_slice(outlink, y, h, slice_dir); | |||||
| return 0; | |||||
| } | |||||
| int ff_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) | |||||
| { | |||||
| uint8_t *src[4], *dst[4]; | |||||
| int i, j, vsub, ret; | |||||
| int (*draw_slice)(AVFilterLink *, int, int, int); | |||||
| FF_DPRINTF_START(NULL, draw_slice); ff_dlog_link(NULL, link, 0); av_dlog(NULL, " y:%d h:%d dir:%d\n", y, h, slice_dir); | |||||
| /* copy the slice if needed for permission reasons */ | |||||
| if (link->src_buf) { | |||||
| const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format); | |||||
| vsub = desc->log2_chroma_h; | |||||
| for (i = 0; i < 4; i++) { | |||||
| if (link->src_buf->data[i]) { | |||||
| src[i] = link->src_buf-> data[i] + | |||||
| (y >> (i==1 || i==2 ? vsub : 0)) * link->src_buf-> linesize[i]; | |||||
| dst[i] = link->cur_buf->data[i] + | |||||
| (y >> (i==1 || i==2 ? vsub : 0)) * link->cur_buf->linesize[i]; | |||||
| } else | |||||
| src[i] = dst[i] = NULL; | |||||
| } | |||||
| for (i = 0; i < 4; i++) { | |||||
| int planew = | |||||
| av_image_get_linesize(link->format, link->cur_buf->video->w, i); | |||||
| if (!src[i]) continue; | |||||
| for (j = 0; j < h >> (i==1 || i==2 ? vsub : 0); j++) { | |||||
| memcpy(dst[i], src[i], planew); | |||||
| src[i] += link->src_buf->linesize[i]; | |||||
| dst[i] += link->cur_buf->linesize[i]; | |||||
| } | |||||
| } | |||||
| } | |||||
| if (!(draw_slice = link->dstpad->draw_slice)) | |||||
| draw_slice = default_draw_slice; | |||||
| ret = draw_slice(link, y, h, slice_dir); | |||||
| if (ret < 0) | |||||
| clear_link(link); | |||||
| return ret; | |||||
| } | |||||
| @@ -39,51 +39,4 @@ AVFilterBufferRef *ff_null_get_video_buffer(AVFilterLink *link, int perms, int w | |||||
| AVFilterBufferRef *ff_get_video_buffer(AVFilterLink *link, int perms, | AVFilterBufferRef *ff_get_video_buffer(AVFilterLink *link, int perms, | ||||
| int w, int h); | int w, int h); | ||||
| int ff_inplace_start_frame(AVFilterLink *link, AVFilterBufferRef *picref); | |||||
| int ff_null_start_frame(AVFilterLink *link, AVFilterBufferRef *picref); | |||||
| int ff_null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir); | |||||
| int ff_null_end_frame(AVFilterLink *link); | |||||
| /** | |||||
| * Notify the next filter of the start of a frame. | |||||
| * | |||||
| * @param link the output link the frame will be sent over | |||||
| * @param picref A reference to the frame about to be sent. The data for this | |||||
| * frame need only be valid once draw_slice() is called for that | |||||
| * portion. The receiving filter will free this reference when | |||||
| * it no longer needs it. | |||||
| * | |||||
| * @return >= 0 on success, a negative AVERROR on error. This function will | |||||
| * unreference picref in case of error. | |||||
| */ | |||||
| int ff_start_frame(AVFilterLink *link, AVFilterBufferRef *picref); | |||||
| /** | |||||
| * Notify the next filter that the current frame has finished. | |||||
| * | |||||
| * @param link the output link the frame was sent over | |||||
| * | |||||
| * @return >= 0 on success, a negative AVERROR on error | |||||
| */ | |||||
| int ff_end_frame(AVFilterLink *link); | |||||
| /** | |||||
| * Send a slice to the next filter. | |||||
| * | |||||
| * Slices have to be provided in sequential order, either in | |||||
| * top-bottom or bottom-top order. If slices are provided in | |||||
| * non-sequential order the behavior of the function is undefined. | |||||
| * | |||||
| * @param link the output link over which the frame is being sent | |||||
| * @param y offset in pixels from the top of the image for this slice | |||||
| * @param h height of this slice in pixels | |||||
| * @param slice_dir the assumed direction for sending slices, | |||||
| * from the top slice to the bottom slice if the value is 1, | |||||
| * from the bottom slice to the top slice if the value is -1, | |||||
| * for other values the behavior of the function is undefined. | |||||
| * | |||||
| * @return >= 0 on success, a negative AVERROR on error. | |||||
| */ | |||||
| int ff_draw_slice(AVFilterLink *link, int y, int h, int slice_dir); | |||||
| #endif /* AVFILTER_VIDEO_H */ | #endif /* AVFILTER_VIDEO_H */ | ||||
| @@ -20,13 +20,9 @@ | |||||
| #include "internal.h" | #include "internal.h" | ||||
| #include "libavutil/internal.h" | #include "libavutil/internal.h" | ||||
| static int start_frame(AVFilterLink *link, AVFilterBufferRef *picref) | |||||
| { | |||||
| return 0; | |||||
| } | |||||
| static int end_frame(AVFilterLink *link) | |||||
| static int filter_frame(AVFilterLink *link, AVFilterBufferRef *frame) | |||||
| { | { | ||||
| avfilter_unref_bufferp(&frame); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -34,8 +30,7 @@ static const AVFilterPad avfilter_vsink_nullsink_inputs[] = { | |||||
| { | { | ||||
| .name = "default", | .name = "default", | ||||
| .type = AVMEDIA_TYPE_VIDEO, | .type = AVMEDIA_TYPE_VIDEO, | ||||
| .start_frame = start_frame, | |||||
| .end_frame = end_frame, | |||||
| .filter_frame = filter_frame, | |||||
| }, | }, | ||||
| { NULL }, | { NULL }, | ||||
| }; | }; | ||||
| @@ -147,8 +147,6 @@ static int color_request_frame(AVFilterLink *link) | |||||
| { | { | ||||
| ColorContext *color = link->src->priv; | ColorContext *color = link->src->priv; | ||||
| AVFilterBufferRef *picref = ff_get_video_buffer(link, AV_PERM_WRITE, color->w, color->h); | AVFilterBufferRef *picref = ff_get_video_buffer(link, AV_PERM_WRITE, color->w, color->h); | ||||
| AVFilterBufferRef *buf_out; | |||||
| int ret; | |||||
| if (!picref) | if (!picref) | ||||
| return AVERROR(ENOMEM); | return AVERROR(ENOMEM); | ||||
| @@ -157,29 +155,10 @@ static int color_request_frame(AVFilterLink *link) | |||||
| picref->pts = color->pts++; | picref->pts = color->pts++; | ||||
| picref->pos = -1; | picref->pos = -1; | ||||
| buf_out = avfilter_ref_buffer(picref, ~0); | |||||
| if (!buf_out) { | |||||
| ret = AVERROR(ENOMEM); | |||||
| goto fail; | |||||
| } | |||||
| ret = ff_start_frame(link, buf_out); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| ff_draw_rectangle(picref->data, picref->linesize, | ff_draw_rectangle(picref->data, picref->linesize, | ||||
| color->line, color->line_step, color->hsub, color->vsub, | color->line, color->line_step, color->hsub, color->vsub, | ||||
| 0, 0, color->w, color->h); | 0, 0, color->w, color->h); | ||||
| ret = ff_draw_slice(link, 0, color->h, 1); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| ret = ff_end_frame(link); | |||||
| fail: | |||||
| avfilter_unref_buffer(picref); | |||||
| return ret; | |||||
| return ff_filter_frame(link, picref); | |||||
| } | } | ||||
| static const AVFilterPad avfilter_vsrc_color_outputs[] = { | static const AVFilterPad avfilter_vsrc_color_outputs[] = { | ||||
| @@ -279,7 +279,6 @@ static int movie_get_frame(AVFilterLink *outlink) | |||||
| static int request_frame(AVFilterLink *outlink) | static int request_frame(AVFilterLink *outlink) | ||||
| { | { | ||||
| AVFilterBufferRef *outpicref; | |||||
| MovieContext *movie = outlink->src->priv; | MovieContext *movie = outlink->src->priv; | ||||
| int ret; | int ret; | ||||
| @@ -288,23 +287,8 @@ static int request_frame(AVFilterLink *outlink) | |||||
| if ((ret = movie_get_frame(outlink)) < 0) | if ((ret = movie_get_frame(outlink)) < 0) | ||||
| return ret; | return ret; | ||||
| outpicref = avfilter_ref_buffer(movie->picref, ~0); | |||||
| if (!outpicref) { | |||||
| ret = AVERROR(ENOMEM); | |||||
| goto fail; | |||||
| } | |||||
| ret = ff_start_frame(outlink, outpicref); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| ret = ff_draw_slice(outlink, 0, outlink->h, 1); | |||||
| if (ret < 0) | |||||
| goto fail; | |||||
| ret = ff_end_frame(outlink); | |||||
| fail: | |||||
| avfilter_unref_bufferp(&movie->picref); | |||||
| ret = ff_filter_frame(outlink, movie->picref); | |||||
| movie->picref = NULL; | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| @@ -131,7 +131,6 @@ static int request_frame(AVFilterLink *outlink) | |||||
| { | { | ||||
| TestSourceContext *test = outlink->src->priv; | TestSourceContext *test = outlink->src->priv; | ||||
| AVFilterBufferRef *picref; | AVFilterBufferRef *picref; | ||||
| int ret; | |||||
| if (test->max_pts >= 0 && test->pts > test->max_pts) | if (test->max_pts >= 0 && test->pts > test->max_pts) | ||||
| return AVERROR_EOF; | return AVERROR_EOF; | ||||
| @@ -148,12 +147,7 @@ static int request_frame(AVFilterLink *outlink) | |||||
| test->nb_frame++; | test->nb_frame++; | ||||
| test->fill_picture_fn(outlink->src, picref); | test->fill_picture_fn(outlink->src, picref); | ||||
| if ((ret = ff_start_frame(outlink, picref)) < 0 || | |||||
| (ret = ff_draw_slice(outlink, 0, test->h, 1)) < 0 || | |||||
| (ret = ff_end_frame(outlink)) < 0) | |||||
| return ret; | |||||
| return 0; | |||||
| return ff_filter_frame(outlink, picref); | |||||
| } | } | ||||
| #if CONFIG_TESTSRC_FILTER | #if CONFIG_TESTSRC_FILTER | ||||