summaryrefslogtreecommitdiffstats
path: root/libavfilter/buffersrc.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavfilter/buffersrc.c')
-rw-r--r--libavfilter/buffersrc.c239
1 files changed, 167 insertions, 72 deletions
diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c
index ad9f45b..b50a5e1 100644
--- a/libavfilter/buffersrc.c
+++ b/libavfilter/buffersrc.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2008 Vitor Sessak
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,6 +30,7 @@
#include "internal.h"
#include "video.h"
#include "vsrc_buffer.h"
+#include "avcodec.h"
#include "libavutil/audioconvert.h"
#include "libavutil/fifo.h"
@@ -41,11 +42,14 @@ typedef struct {
const AVClass *class;
AVFifoBuffer *fifo;
AVRational time_base; ///< time_base to set in the output link
+ AVRational frame_rate; ///< frame_rate to set in the output link
+ unsigned nb_failed_requests;
/* video only */
- int h, w;
+ int w, h;
enum PixelFormat pix_fmt;
AVRational pixel_aspect;
+ char *sws_param;
/* audio only */
int sample_rate;
@@ -70,8 +74,46 @@ typedef struct {
return AVERROR(EINVAL);\
}
+static AVFilterBufferRef *copy_buffer_ref(AVFilterContext *ctx,
+ AVFilterBufferRef *ref)
+{
+ AVFilterLink *outlink = ctx->outputs[0];
+ AVFilterBufferRef *buf;
+ int channels;
+
+ switch (outlink->type) {
+
+ case AVMEDIA_TYPE_VIDEO:
+ buf = ff_get_video_buffer(outlink, AV_PERM_WRITE,
+ ref->video->w, ref->video->h);
+ if(!buf)
+ return NULL;
+ av_image_copy(buf->data, buf->linesize,
+ (void*)ref->data, ref->linesize,
+ ref->format, ref->video->w, ref->video->h);
+ break;
+
+ case AVMEDIA_TYPE_AUDIO:
+ buf = ff_get_audio_buffer(outlink, AV_PERM_WRITE,
+ ref->audio->nb_samples);
+ if(!buf)
+ return NULL;
+ channels = av_get_channel_layout_nb_channels(ref->audio->channel_layout);
+ av_samples_copy(buf->extended_data, ref->buf->extended_data,
+ 0, 0, ref->audio->nb_samples,
+ channels,
+ ref->format);
+ break;
+
+ default:
+ return NULL;
+ }
+ avfilter_copy_buffer_ref_props(buf, ref);
+ return buf;
+}
+
#if FF_API_VSRC_BUFFER_ADD_FRAME
-int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame,
+static int av_vsrc_buffer_add_frame_alt(AVFilterContext *buffer_filter, AVFrame *frame,
int64_t pts, AVRational pixel_aspect)
{
int64_t orig_pts = frame->pts;
@@ -89,59 +131,42 @@ int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame,
}
#endif
-int av_buffersrc_write_frame(AVFilterContext *buffer_filter, AVFrame *frame)
+int av_buffersrc_add_frame(AVFilterContext *buffer_src,
+ const AVFrame *frame, int flags)
{
- BufferSourceContext *c = buffer_filter->priv;
- AVFilterBufferRef *buf;
+ AVFilterBufferRef *picref;
int ret;
- if (!frame) {
- c->eof = 1;
- return 0;
- } else if (c->eof)
- return AVERROR(EINVAL);
-
- if (!av_fifo_space(c->fifo) &&
- (ret = av_fifo_realloc2(c->fifo, av_fifo_size(c->fifo) +
- sizeof(buf))) < 0)
- return ret;
+ if (!frame) /* NULL for EOF */
+ return av_buffersrc_add_ref(buffer_src, NULL, flags);
- switch (buffer_filter->outputs[0]->type) {
+ switch (buffer_src->outputs[0]->type) {
case AVMEDIA_TYPE_VIDEO:
- CHECK_VIDEO_PARAM_CHANGE(buffer_filter, c, frame->width, frame->height,
- frame->format);
- buf = ff_get_video_buffer(buffer_filter->outputs[0], AV_PERM_WRITE,
- c->w, c->h);
- av_image_copy(buf->data, buf->linesize, frame->data, frame->linesize,
- c->pix_fmt, c->w, c->h);
+ picref = avfilter_get_video_buffer_ref_from_frame(frame, AV_PERM_WRITE);
break;
case AVMEDIA_TYPE_AUDIO:
- CHECK_AUDIO_PARAM_CHANGE(buffer_filter, c, frame->sample_rate, frame->channel_layout,
- frame->format);
- buf = ff_get_audio_buffer(buffer_filter->outputs[0], AV_PERM_WRITE,
- frame->nb_samples);
- av_samples_copy(buf->extended_data, frame->extended_data,
- 0, 0, frame->nb_samples,
- av_get_channel_layout_nb_channels(frame->channel_layout),
- frame->format);
+ picref = avfilter_get_audio_buffer_ref_from_frame(frame, AV_PERM_WRITE);
break;
default:
- return AVERROR(EINVAL);
- }
-
- avfilter_copy_frame_props(buf, frame);
-
- if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0) {
- avfilter_unref_buffer(buf);
- return ret;
+ return AVERROR(ENOSYS);
}
+ if (!picref)
+ return AVERROR(ENOMEM);
+ ret = av_buffersrc_add_ref(buffer_src, picref, flags);
+ picref->buf->data[0] = NULL;
+ avfilter_unref_buffer(picref);
+ return ret;
+}
- return 0;
+int av_buffersrc_write_frame(AVFilterContext *buffer_filter, AVFrame *frame)
+{
+ return av_buffersrc_add_frame(buffer_filter, frame, 0);
}
-int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf)
+int av_buffersrc_add_ref(AVFilterContext *s, AVFilterBufferRef *buf, int flags)
{
BufferSourceContext *c = s->priv;
+ AVFilterBufferRef *to_free = NULL;
int ret;
if (!buf) {
@@ -155,54 +180,120 @@ int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf)
sizeof(buf))) < 0)
return ret;
- switch (s->outputs[0]->type) {
- case AVMEDIA_TYPE_VIDEO:
- CHECK_VIDEO_PARAM_CHANGE(s, c, buf->video->w, buf->video->h, buf->format);
- break;
- case AVMEDIA_TYPE_AUDIO:
- CHECK_AUDIO_PARAM_CHANGE(s, c, buf->audio->sample_rate, buf->audio->channel_layout,
- buf->format);
- break;
- default:
- return AVERROR(EINVAL);
+ if (!(flags & AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT)) {
+ switch (s->outputs[0]->type) {
+ case AVMEDIA_TYPE_VIDEO:
+ CHECK_VIDEO_PARAM_CHANGE(s, c, buf->video->w, buf->video->h, buf->format);
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ CHECK_AUDIO_PARAM_CHANGE(s, c, buf->audio->sample_rate, buf->audio->channel_layout,
+ buf->format);
+ break;
+ default:
+ return AVERROR(EINVAL);
+ }
}
+ if (!(flags & AV_BUFFERSRC_FLAG_NO_COPY))
+ to_free = buf = copy_buffer_ref(s, buf);
+ if(!buf)
+ return -1;
- if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0)
+ if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0) {
+ avfilter_unref_buffer(to_free);
return ret;
+ }
+ c->nb_failed_requests = 0;
return 0;
}
+int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf)
+{
+ return av_buffersrc_add_ref(s, buf, AV_BUFFERSRC_FLAG_NO_COPY);
+}
+
+unsigned av_buffersrc_get_nb_failed_requests(AVFilterContext *buffer_src)
+{
+ return ((BufferSourceContext *)buffer_src->priv)->nb_failed_requests;
+}
+
+#define OFFSET(x) offsetof(BufferSourceContext, x)
+#define V AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption video_options[] = {
+ { "time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, { 0 }, 0, INT_MAX, V },
+ { "frame_rate", NULL, OFFSET(frame_rate), AV_OPT_TYPE_RATIONAL, { 0 }, 0, INT_MAX, V },
+ { "video_size", NULL, OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, .flags = V },
+ { "pix_fmt", NULL, OFFSET(pix_fmt), AV_OPT_TYPE_PIXEL_FMT, .flags = V },
+ { "pixel_aspect", NULL, OFFSET(pixel_aspect), AV_OPT_TYPE_RATIONAL, { 0 }, 0, INT_MAX, V },
+ { "sws_param", NULL, OFFSET(sws_param), AV_OPT_TYPE_STRING, .flags = V },
+ { NULL },
+};
+#undef V
+
+static const AVClass vbuffer_class = {
+ .class_name = "vbuffer source",
+ .item_name = av_default_item_name,
+ .option = video_options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_FILTER,
+};
+
static av_cold int init_video(AVFilterContext *ctx, const char *args, void *opaque)
{
BufferSourceContext *c = ctx->priv;
- char pix_fmt_str[128];
- int n = 0;
+ char pix_fmt_str[128], sws_param[256] = "", *colon, *equal;
+ int ret, n = 0;
- if (!args ||
- (n = sscanf(args, "%d:%d:%127[^:]:%d:%d:%d:%d", &c->w, &c->h, pix_fmt_str,
- &c->time_base.num, &c->time_base.den,
- &c->pixel_aspect.num, &c->pixel_aspect.den)) != 7) {
- av_log(ctx, AV_LOG_ERROR, "Expected 7 arguments, but %d found in '%s'\n", n, args);
+ c->class = &vbuffer_class;
+
+ if (!args) {
+ av_log(ctx, AV_LOG_ERROR, "Arguments required\n");
return AVERROR(EINVAL);
}
- if ((c->pix_fmt = av_get_pix_fmt(pix_fmt_str)) == PIX_FMT_NONE) {
- char *tail;
- c->pix_fmt = strtol(pix_fmt_str, &tail, 10);
- if (*tail || c->pix_fmt < 0 || c->pix_fmt >= PIX_FMT_NB) {
- av_log(ctx, AV_LOG_ERROR, "Invalid pixel format string '%s'\n", pix_fmt_str);
- return AVERROR(EINVAL);
+ colon = strchr(args, ':');
+ equal = strchr(args, '=');
+ if (equal && (!colon || equal < colon)) {
+ av_opt_set_defaults(c);
+ ret = av_set_options_string(c, args, "=", ":");
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Error parsing options string: %s.\n", args);
+ goto fail;
}
+ } else {
+ if ((n = sscanf(args, "%d:%d:%127[^:]:%d:%d:%d:%d:%255c", &c->w, &c->h, pix_fmt_str,
+ &c->time_base.num, &c->time_base.den,
+ &c->pixel_aspect.num, &c->pixel_aspect.den, sws_param)) < 7) {
+ av_log(ctx, AV_LOG_ERROR, "Expected at least 7 arguments, but only %d found in '%s'\n", n, args);
+ ret = AVERROR(EINVAL);
+ goto fail;
}
+ av_log(ctx, AV_LOG_WARNING, "Flat options syntax is deprecated, use key=value pairs.\n");
- if (!(c->fifo = av_fifo_alloc(sizeof(AVFilterBufferRef*))))
- return AVERROR(ENOMEM);
+ if ((ret = ff_parse_pixel_format(&c->pix_fmt, pix_fmt_str, ctx)) < 0)
+ goto fail;
+ c->sws_param = av_strdup(sws_param);
+ if (!c->sws_param) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ }
+
+ if (!(c->fifo = av_fifo_alloc(sizeof(AVFilterBufferRef*)))) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
- av_log(ctx, AV_LOG_INFO, "w:%d h:%d pixfmt:%s\n", c->w, c->h, av_pix_fmt_descriptors[c->pix_fmt].name);
+ av_log(ctx, AV_LOG_INFO, "w:%d h:%d pixfmt:%s tb:%d/%d fr:%d/%d sar:%d/%d sws_param:%s\n",
+ c->w, c->h, av_pix_fmt_descriptors[c->pix_fmt].name,
+ c->time_base.num, c->time_base.den, c->frame_rate.num, c->frame_rate.den,
+ c->pixel_aspect.num, c->pixel_aspect.den, (char *)av_x_if_null(c->sws_param, ""));
return 0;
+
+fail:
+ av_opt_free(c);
+ return ret;
}
-#define OFFSET(x) offsetof(BufferSourceContext, x)
#define A AV_OPT_FLAG_AUDIO_PARAM
static const AVOption audio_options[] = {
{ "time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, { 0 }, 0, INT_MAX, A },
@@ -217,6 +308,7 @@ static const AVClass abuffer_class = {
.item_name = av_default_item_name,
.option = audio_options,
.version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_FILTER,
};
static av_cold int init_audio(AVFilterContext *ctx, const char *args, void *opaque)
@@ -275,6 +367,7 @@ static av_cold void uninit(AVFilterContext *ctx)
}
av_fifo_free(s->fifo);
s->fifo = NULL;
+ av_freep(&s->sws_param);
}
static int query_formats(AVFilterContext *ctx)
@@ -325,6 +418,7 @@ static int config_props(AVFilterLink *link)
}
link->time_base = c->time_base;
+ link->frame_rate = c->frame_rate;
return 0;
}
@@ -336,6 +430,7 @@ static int request_frame(AVFilterLink *link)
if (!av_fifo_size(c->fifo)) {
if (c->eof)
return AVERROR_EOF;
+ c->nb_failed_requests++;
return AVERROR(EAGAIN);
}
av_fifo_generic_read(c->fifo, &buf, sizeof(buf), NULL);
OpenPOWER on IntegriCloud