+ int (*filter_frame)(AVFilterLink *, AVFrame *);
+ AVFilterPad *dst = link->dstpad;
+ AVFrame *out;
+
+ FF_DPRINTF_START(NULL, filter_frame);
+ ff_dlog_link(NULL, link, 1);
+
+ if (!(filter_frame = dst->filter_frame))
+ filter_frame = default_filter_frame;
+
+ /* copy the frame if needed */
+ if (dst->needs_writable && !av_frame_is_writable(frame)) {
+ av_log(link->dst, AV_LOG_DEBUG, "Copying data in avfilter.\n");
+
+ switch (link->type) {
+ case AVMEDIA_TYPE_VIDEO:
+ out = ff_get_video_buffer(link, link->w, link->h);
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ out = ff_get_audio_buffer(link, frame->nb_samples);
+ break;
+ default: return AVERROR(EINVAL);
+ }
+ if (!out) {
+ av_frame_free(&frame);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, frame);
+
+ switch (link->type) {
+ case AVMEDIA_TYPE_VIDEO:
+ av_image_copy(out->data, out->linesize, frame->data, frame->linesize,
+ frame->format, frame->width, frame->height);
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ av_samples_copy(out->extended_data, frame->extended_data,
+ 0, 0, frame->nb_samples,
+ av_get_channel_layout_nb_channels(frame->channel_layout),
+ frame->format);
+ break;
+ default: return AVERROR(EINVAL);
+ }
+
+ av_frame_free(&frame);
+ } else
+ out = frame;
+
+ return filter_frame(link, out);