mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
lavfi: unify src_buffer and buffersrc.
Most of the code is moved to buffersrc.c to help Git see the similarities. src_buffer.c still contains the obsolete compatibility functions. The format change detection code was removed as it has been implemented directly in ffmpeg. It can easily be brought back from the history.
This commit is contained in:
parent
7997fc49ef
commit
aa1246ea42
@ -28,6 +28,7 @@ OBJS = allfilters.o \
|
||||
avfiltergraph.o \
|
||||
buffer.o \
|
||||
buffersink.o \
|
||||
buffersrc.o \
|
||||
defaults.o \
|
||||
drawutils.o \
|
||||
formats.o \
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "avfilter.h"
|
||||
#include "buffersrc.h"
|
||||
#include "formats.h"
|
||||
#include "internal.h"
|
||||
#include "vsrc_buffer.h"
|
||||
#include "avcodec.h"
|
||||
|
||||
@ -40,11 +41,13 @@ typedef struct {
|
||||
const AVClass *class;
|
||||
AVFifoBuffer *fifo;
|
||||
AVRational time_base; ///< time_base to set in the output link
|
||||
unsigned nb_failed_requests;
|
||||
|
||||
/* video only */
|
||||
int h, w;
|
||||
enum PixelFormat pix_fmt;
|
||||
AVRational pixel_aspect;
|
||||
char sws_param[256];
|
||||
|
||||
/* audio only */
|
||||
int sample_rate;
|
||||
@ -69,6 +72,44 @@ 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 = avfilter_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
|
||||
static int av_vsrc_buffer_add_frame_alt(AVFilterContext *buffer_filter, AVFrame *frame,
|
||||
int64_t pts, AVRational pixel_aspect)
|
||||
@ -88,59 +129,42 @@ static int av_vsrc_buffer_add_frame_alt(AVFilterContext *buffer_filter, AVFrame
|
||||
}
|
||||
#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 (!frame) /* NULL for EOF */
|
||||
return av_buffersrc_add_ref(buffer_src, NULL, flags);
|
||||
|
||||
if (!av_fifo_space(c->fifo) &&
|
||||
(ret = av_fifo_realloc2(c->fifo, av_fifo_size(c->fifo) +
|
||||
sizeof(buf))) < 0)
|
||||
return ret;
|
||||
|
||||
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 = avfilter_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);
|
||||
return AVERROR(ENOSYS);
|
||||
}
|
||||
|
||||
avfilter_copy_frame_props(buf, frame);
|
||||
|
||||
if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0) {
|
||||
avfilter_unref_buffer(buf);
|
||||
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) {
|
||||
@ -154,6 +178,8 @@ int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf)
|
||||
sizeof(buf))) < 0)
|
||||
return ret;
|
||||
|
||||
if (!(flags & AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT)) {
|
||||
/* TODO reindent */
|
||||
switch (s->outputs[0]->type) {
|
||||
case AVMEDIA_TYPE_VIDEO:
|
||||
CHECK_VIDEO_PARAM_CHANGE(s, c, buf->video->w, buf->video->h, buf->format);
|
||||
@ -165,39 +191,56 @@ int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf)
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
int ret, n = 0;
|
||||
*c->sws_param = 0;
|
||||
|
||||
if (!args ||
|
||||
(n = sscanf(args, "%d:%d:%127[^:]:%d:%d:%d:%d", &c->w, &c->h, pix_fmt_str,
|
||||
(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)) != 7) {
|
||||
av_log(ctx, AV_LOG_ERROR, "Expected 7 arguments, but %d found in '%s'\n", n, args);
|
||||
&c->pixel_aspect.num, &c->pixel_aspect.den, c->sws_param)) < 7) {
|
||||
av_log(ctx, AV_LOG_ERROR, "Expected at least 7 arguments, but only %d found in '%s'\n", n, args);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if ((ret = ff_parse_pixel_format(&c->pix_fmt, pix_fmt_str, ctx)) < 0)
|
||||
return ret;
|
||||
|
||||
if (!(c->fifo = av_fifo_alloc(sizeof(AVFilterBufferRef*))))
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
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 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->pixel_aspect.num, c->pixel_aspect.den, c->sws_param);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -335,6 +378,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);
|
||||
|
@ -27,7 +27,6 @@
|
||||
|
||||
#include "avfilter.h"
|
||||
|
||||
#if 1
|
||||
enum {
|
||||
|
||||
/**
|
||||
@ -63,7 +62,6 @@ int av_buffersrc_add_ref(AVFilterContext *buffer_src,
|
||||
*/
|
||||
unsigned av_buffersrc_get_nb_failed_requests(AVFilterContext *buffer_src);
|
||||
|
||||
#else
|
||||
/**
|
||||
* Add a buffer to the filtergraph s.
|
||||
*
|
||||
@ -83,6 +81,5 @@ int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf);
|
||||
* hit. Use av_buffersrc_buffer() to avoid copying the data.
|
||||
*/
|
||||
int av_buffersrc_write_frame(AVFilterContext *s, AVFrame *frame);
|
||||
#endif
|
||||
|
||||
#endif /* AVFILTER_BUFFERSRC_H */
|
||||
|
@ -61,281 +61,12 @@ typedef struct {
|
||||
AVFilterContext *aresample;
|
||||
} BufferSourceContext;
|
||||
|
||||
#define FIFO_SIZE 8
|
||||
|
||||
#define CHECK_PARAM_CHANGE(s, c, width, height, format)\
|
||||
if (c->w != width || c->h != height || c->pix_fmt != format) {\
|
||||
av_log(s, AV_LOG_ERROR, "Changing frame properties on the fly is not supported.\n");\
|
||||
return AVERROR(EINVAL);\
|
||||
}
|
||||
|
||||
static void buf_free(AVFilterBuffer *ptr)
|
||||
{
|
||||
av_free(ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
static void set_link_source(AVFilterContext *src, AVFilterLink *link)
|
||||
{
|
||||
link->src = src;
|
||||
link->srcpad = &(src->output_pads[0]);
|
||||
src->outputs[0] = link;
|
||||
}
|
||||
|
||||
static int reconfigure_filter(BufferSourceContext *abuffer, AVFilterContext *filt_ctx)
|
||||
{
|
||||
int ret;
|
||||
AVFilterLink * const inlink = filt_ctx->inputs[0];
|
||||
AVFilterLink * const outlink = filt_ctx->outputs[0];
|
||||
|
||||
inlink->format = abuffer->sample_format;
|
||||
inlink->channel_layout = abuffer->channel_layout;
|
||||
inlink->sample_rate = abuffer->sample_rate;
|
||||
|
||||
filt_ctx->filter->uninit(filt_ctx);
|
||||
memset(filt_ctx->priv, 0, filt_ctx->filter->priv_size);
|
||||
if ((ret = filt_ctx->filter->init(filt_ctx, NULL , NULL)) < 0)
|
||||
return ret;
|
||||
if ((ret = inlink->srcpad->config_props(inlink)) < 0)
|
||||
return ret;
|
||||
return outlink->srcpad->config_props(outlink);
|
||||
}
|
||||
|
||||
static int insert_filter(BufferSourceContext *abuffer,
|
||||
AVFilterLink *link, AVFilterContext **filt_ctx,
|
||||
const char *filt_name)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = avfilter_open(filt_ctx, avfilter_get_by_name(filt_name), NULL)) < 0)
|
||||
return ret;
|
||||
|
||||
link->src->outputs[0] = NULL;
|
||||
if ((ret = avfilter_link(link->src, 0, *filt_ctx, 0)) < 0) {
|
||||
link->src->outputs[0] = link;
|
||||
return ret;
|
||||
}
|
||||
|
||||
set_link_source(*filt_ctx, link);
|
||||
|
||||
if ((ret = reconfigure_filter(abuffer, *filt_ctx)) < 0) {
|
||||
avfilter_free(*filt_ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void remove_filter(AVFilterContext **filt_ctx)
|
||||
{
|
||||
AVFilterLink *outlink = (*filt_ctx)->outputs[0];
|
||||
AVFilterContext *src = (*filt_ctx)->inputs[0]->src;
|
||||
|
||||
(*filt_ctx)->outputs[0] = NULL;
|
||||
avfilter_free(*filt_ctx);
|
||||
*filt_ctx = NULL;
|
||||
|
||||
set_link_source(src, outlink);
|
||||
}
|
||||
|
||||
static inline void log_input_change(void *ctx, AVFilterLink *link, AVFilterBufferRef *ref)
|
||||
{
|
||||
char old_layout_str[16], new_layout_str[16];
|
||||
av_get_channel_layout_string(old_layout_str, sizeof(old_layout_str),
|
||||
-1, link->channel_layout);
|
||||
av_get_channel_layout_string(new_layout_str, sizeof(new_layout_str),
|
||||
-1, ref->audio->channel_layout);
|
||||
av_log(ctx, AV_LOG_INFO,
|
||||
"Audio input format changed: "
|
||||
"%s:%s:%d -> %s:%s:%d, normalizing\n",
|
||||
av_get_sample_fmt_name(link->format),
|
||||
old_layout_str, (int)link->sample_rate,
|
||||
av_get_sample_fmt_name(ref->format),
|
||||
new_layout_str, ref->audio->sample_rate);
|
||||
}
|
||||
|
||||
static int check_format_change_video(AVFilterContext *buffer_filter,
|
||||
AVFilterBufferRef *picref)
|
||||
{
|
||||
BufferSourceContext *c = buffer_filter->priv;
|
||||
int ret;
|
||||
|
||||
if (picref->video->w != c->w || picref->video->h != c->h || picref->format != c->pix_fmt) {
|
||||
AVFilterContext *scale = buffer_filter->outputs[0]->dst;
|
||||
AVFilterLink *link;
|
||||
char scale_param[1024];
|
||||
|
||||
av_log(buffer_filter, AV_LOG_INFO,
|
||||
"Buffer video input changed from size:%dx%d fmt:%s to size:%dx%d fmt:%s\n",
|
||||
c->w, c->h, av_pix_fmt_descriptors[c->pix_fmt].name,
|
||||
picref->video->w, picref->video->h, av_pix_fmt_descriptors[picref->format].name);
|
||||
|
||||
if (!scale || strcmp(scale->filter->name, "scale")) {
|
||||
AVFilter *f = avfilter_get_by_name("scale");
|
||||
|
||||
av_log(buffer_filter, AV_LOG_INFO, "Inserting scaler filter\n");
|
||||
if ((ret = avfilter_open(&scale, f, "Input equalizer")) < 0)
|
||||
return ret;
|
||||
|
||||
c->scale = scale;
|
||||
|
||||
snprintf(scale_param, sizeof(scale_param)-1, "%d:%d:%s", c->w, c->h, c->sws_param);
|
||||
if ((ret = avfilter_init_filter(scale, scale_param, NULL)) < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = avfilter_insert_filter(buffer_filter->outputs[0], scale, 0, 0)) < 0) {
|
||||
return ret;
|
||||
}
|
||||
scale->outputs[0]->time_base = scale->inputs[0]->time_base;
|
||||
|
||||
scale->outputs[0]->format= c->pix_fmt;
|
||||
} else if (!strcmp(scale->filter->name, "scale")) {
|
||||
snprintf(scale_param, sizeof(scale_param)-1, "%d:%d:%s",
|
||||
scale->outputs[0]->w, scale->outputs[0]->h, c->sws_param);
|
||||
scale->filter->init(scale, scale_param, NULL);
|
||||
}
|
||||
|
||||
c->pix_fmt = scale->inputs[0]->format = picref->format;
|
||||
c->w = scale->inputs[0]->w = picref->video->w;
|
||||
c->h = scale->inputs[0]->h = picref->video->h;
|
||||
|
||||
link = scale->outputs[0];
|
||||
if ((ret = link->srcpad->config_props(link)) < 0)
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_format_change_audio(AVFilterContext *ctx,
|
||||
AVFilterBufferRef *samplesref)
|
||||
{
|
||||
BufferSourceContext *abuffer = ctx->priv;
|
||||
AVFilterLink *link;
|
||||
int ret, logged = 0;
|
||||
|
||||
link = ctx->outputs[0];
|
||||
if (samplesref->audio->sample_rate != link->sample_rate ||
|
||||
samplesref->format != link->format ||
|
||||
samplesref->audio->channel_layout != link->channel_layout) {
|
||||
|
||||
log_input_change(ctx, link, samplesref);
|
||||
logged = 1;
|
||||
|
||||
abuffer->sample_rate = samplesref->audio->sample_rate;
|
||||
abuffer->sample_format = samplesref->format;
|
||||
abuffer->channel_layout = samplesref->audio->channel_layout;
|
||||
|
||||
if (!abuffer->aresample) {
|
||||
ret = insert_filter(abuffer, link, &abuffer->aresample, "aresample");
|
||||
if (ret < 0) return ret;
|
||||
} else {
|
||||
link = abuffer->aresample->outputs[0];
|
||||
if (samplesref->audio->sample_rate == link->sample_rate &&
|
||||
samplesref->format == link->format &&
|
||||
samplesref->audio->channel_layout == link->channel_layout)
|
||||
remove_filter(&abuffer->aresample);
|
||||
else
|
||||
if ((ret = reconfigure_filter(abuffer, abuffer->aresample)) < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_format_change(AVFilterContext *buffer_filter,
|
||||
AVFilterBufferRef *picref)
|
||||
{
|
||||
switch (buffer_filter->outputs[0]->type) {
|
||||
case AVMEDIA_TYPE_VIDEO:
|
||||
return check_format_change_video(buffer_filter, picref);
|
||||
case AVMEDIA_TYPE_AUDIO:
|
||||
return check_format_change_audio(buffer_filter, picref);
|
||||
default:
|
||||
return AVERROR(ENOSYS);
|
||||
}
|
||||
}
|
||||
|
||||
static AVFilterBufferRef *copy_buffer_ref(AVFilterContext *ctx,
|
||||
AVFilterBufferRef *ref)
|
||||
{
|
||||
AVFilterLink *outlink = ctx->outputs[0];
|
||||
AVFilterBufferRef *buf;
|
||||
int channels, data_size, i;
|
||||
|
||||
switch (outlink->type) {
|
||||
|
||||
case AVMEDIA_TYPE_VIDEO:
|
||||
buf = avfilter_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;
|
||||
}
|
||||
|
||||
int av_buffersrc_add_ref(AVFilterContext *buffer_filter,
|
||||
AVFilterBufferRef *picref, int flags)
|
||||
{
|
||||
BufferSourceContext *c = buffer_filter->priv;
|
||||
AVFilterBufferRef *buf;
|
||||
int ret;
|
||||
|
||||
if (!picref) {
|
||||
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 (!(flags & AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT)) {
|
||||
ret = check_format_change(buffer_filter, picref);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
if (flags & AV_BUFFERSRC_FLAG_NO_COPY)
|
||||
buf = picref;
|
||||
else
|
||||
buf = copy_buffer_ref(buffer_filter, picref);
|
||||
if(!buf)
|
||||
return -1;
|
||||
|
||||
if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0) {
|
||||
if (buf != picref)
|
||||
avfilter_unref_buffer(buf);
|
||||
return ret;
|
||||
}
|
||||
c->nb_failed_requests = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int av_vsrc_buffer_add_video_buffer_ref(AVFilterContext *buffer_filter,
|
||||
AVFilterBufferRef *picref, int flags)
|
||||
{
|
||||
@ -345,33 +76,6 @@ int av_vsrc_buffer_add_video_buffer_ref(AVFilterContext *buffer_filter,
|
||||
#if CONFIG_AVCODEC
|
||||
#include "avcodec.h"
|
||||
|
||||
int av_buffersrc_add_frame(AVFilterContext *buffer_src,
|
||||
const AVFrame *frame, int flags)
|
||||
{
|
||||
AVFilterBufferRef *picref;
|
||||
int ret;
|
||||
|
||||
if (!frame) /* NULL for EOF */
|
||||
return av_buffersrc_add_ref(buffer_src, NULL, flags);
|
||||
|
||||
switch (buffer_src->outputs[0]->type) {
|
||||
case AVMEDIA_TYPE_VIDEO:
|
||||
picref = avfilter_get_video_buffer_ref_from_frame(frame, AV_PERM_WRITE);
|
||||
break;
|
||||
case AVMEDIA_TYPE_AUDIO:
|
||||
picref = avfilter_get_audio_buffer_ref_from_frame(frame, AV_PERM_WRITE);
|
||||
break;
|
||||
default:
|
||||
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;
|
||||
}
|
||||
|
||||
int av_vsrc_buffer_add_frame(AVFilterContext *buffer_src,
|
||||
const AVFrame *frame, int flags)
|
||||
{
|
||||
@ -379,193 +83,11 @@ int av_vsrc_buffer_add_frame(AVFilterContext *buffer_src,
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned av_buffersrc_get_nb_failed_requests(AVFilterContext *buffer_src)
|
||||
{
|
||||
return ((BufferSourceContext *)buffer_src->priv)->nb_failed_requests;
|
||||
}
|
||||
|
||||
unsigned av_vsrc_buffer_get_nb_failed_requests(AVFilterContext *buffer_src)
|
||||
{
|
||||
return ((BufferSourceContext *)buffer_src->priv)->nb_failed_requests;
|
||||
}
|
||||
|
||||
static av_cold int init_video(AVFilterContext *ctx, const char *args, void *opaque)
|
||||
{
|
||||
BufferSourceContext *c = ctx->priv;
|
||||
char pix_fmt_str[128];
|
||||
int ret, n = 0;
|
||||
*c->sws_param = 0;
|
||||
|
||||
if (!args ||
|
||||
(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->sample_aspect_ratio.num, &c->sample_aspect_ratio.den, c->sws_param)) < 7) {
|
||||
av_log(ctx, AV_LOG_ERROR, "Expected at least 7 arguments, but only %d found in '%s'\n", n, args);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
if ((ret = ff_parse_pixel_format(&c->pix_fmt, pix_fmt_str, ctx)) < 0)
|
||||
return ret;
|
||||
|
||||
if (!(c->fifo = av_fifo_alloc(sizeof(AVFilterBufferRef*))))
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
av_log(ctx, AV_LOG_INFO, "w:%d h:%d pixfmt:%s tb:%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->sample_aspect_ratio.num, c->sample_aspect_ratio.den, c->sws_param);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static av_cold int init_audio(AVFilterContext *ctx, const char *args0, void *opaque)
|
||||
{
|
||||
BufferSourceContext *abuffer = ctx->priv;
|
||||
char *arg = NULL, *ptr, chlayout_str[16];
|
||||
char *args = av_strdup(args0);
|
||||
int ret;
|
||||
|
||||
arg = av_strtok(args, ":", &ptr);
|
||||
|
||||
#define ADD_FORMAT(fmt_name) \
|
||||
if (!arg) \
|
||||
goto arg_fail; \
|
||||
if ((ret = ff_parse_##fmt_name(&abuffer->fmt_name, arg, ctx)) < 0) { \
|
||||
av_freep(&args); \
|
||||
return ret; \
|
||||
} \
|
||||
if (*args) \
|
||||
arg = av_strtok(NULL, ":", &ptr)
|
||||
|
||||
ADD_FORMAT(time_base);
|
||||
ADD_FORMAT(sample_rate);
|
||||
ADD_FORMAT(sample_format);
|
||||
ADD_FORMAT(channel_layout);
|
||||
|
||||
abuffer->fifo = av_fifo_alloc(FIFO_SIZE*sizeof(AVFilterBufferRef*));
|
||||
if (!abuffer->fifo) {
|
||||
av_log(ctx, AV_LOG_ERROR, "Failed to allocate fifo, filter init failed.\n");
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
av_get_channel_layout_string(chlayout_str, sizeof(chlayout_str),
|
||||
-1, abuffer->channel_layout);
|
||||
av_log(ctx, AV_LOG_INFO, "format:%s layout:%s rate:%d\n",
|
||||
av_get_sample_fmt_name(abuffer->sample_format), chlayout_str,
|
||||
abuffer->sample_rate);
|
||||
av_freep(&args);
|
||||
|
||||
return 0;
|
||||
|
||||
arg_fail:
|
||||
av_log(ctx, AV_LOG_ERROR, "Invalid arguments, must be of the form "
|
||||
"sample_rate:sample_fmt:channel_layout\n");
|
||||
av_freep(&args);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
static av_cold void uninit(AVFilterContext *ctx)
|
||||
{
|
||||
BufferSourceContext *s = ctx->priv;
|
||||
while (s->fifo && av_fifo_size(s->fifo)) {
|
||||
AVFilterBufferRef *buf;
|
||||
av_fifo_generic_read(s->fifo, &buf, sizeof(buf), NULL);
|
||||
avfilter_unref_buffer(buf);
|
||||
}
|
||||
av_fifo_free(s->fifo);
|
||||
s->fifo = NULL;
|
||||
avfilter_free(s->scale);
|
||||
s->scale = NULL;
|
||||
}
|
||||
|
||||
static int query_formats_video(AVFilterContext *ctx)
|
||||
{
|
||||
BufferSourceContext *c = ctx->priv;
|
||||
enum PixelFormat pix_fmts[] = { c->pix_fmt, PIX_FMT_NONE };
|
||||
|
||||
avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int query_formats_audio(AVFilterContext *ctx)
|
||||
{
|
||||
BufferSourceContext *abuffer = ctx->priv;
|
||||
AVFilterFormats *formats;
|
||||
AVFilterChannelLayouts *layouts;
|
||||
|
||||
formats = NULL;
|
||||
avfilter_add_format(&formats, abuffer->sample_format);
|
||||
avfilter_set_common_sample_formats(ctx, formats);
|
||||
|
||||
formats = NULL;
|
||||
avfilter_add_format(&formats, abuffer->sample_rate);
|
||||
ff_set_common_samplerates(ctx, formats);
|
||||
|
||||
layouts = NULL;
|
||||
ff_add_channel_layout(&layouts, abuffer->channel_layout);
|
||||
ff_set_common_channel_layouts(ctx, layouts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int config_output_video(AVFilterLink *link)
|
||||
{
|
||||
BufferSourceContext *c = link->src->priv;
|
||||
|
||||
link->w = c->w;
|
||||
link->h = c->h;
|
||||
link->sample_aspect_ratio = c->sample_aspect_ratio;
|
||||
link->time_base = c->time_base;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int config_output_audio(AVFilterLink *outlink)
|
||||
{
|
||||
BufferSourceContext *abuffer = outlink->src->priv;
|
||||
outlink->sample_rate = abuffer->sample_rate;
|
||||
outlink->time_base = abuffer->time_base;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int request_frame(AVFilterLink *link)
|
||||
{
|
||||
BufferSourceContext *c = link->src->priv;
|
||||
AVFilterBufferRef *buf;
|
||||
|
||||
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);
|
||||
|
||||
switch (link->type) {
|
||||
case AVMEDIA_TYPE_VIDEO:
|
||||
avfilter_start_frame(link, avfilter_ref_buffer(buf, ~0));
|
||||
avfilter_draw_slice(link, 0, link->h, 1);
|
||||
avfilter_end_frame(link);
|
||||
avfilter_unref_buffer(buf);
|
||||
break;
|
||||
case AVMEDIA_TYPE_AUDIO:
|
||||
ff_filter_samples(link, avfilter_ref_buffer(buf, ~0));
|
||||
avfilter_unref_buffer(buf);
|
||||
break;
|
||||
default:
|
||||
return AVERROR(ENOSYS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int poll_frame(AVFilterLink *link)
|
||||
{
|
||||
BufferSourceContext *c = link->src->priv;
|
||||
int size = av_fifo_size(c->fifo);
|
||||
if (!size && c->eof)
|
||||
return AVERROR_EOF;
|
||||
return size/sizeof(AVFilterBufferRef*);
|
||||
}
|
||||
|
||||
int av_asrc_buffer_add_audio_buffer_ref(AVFilterContext *ctx,
|
||||
AVFilterBufferRef *samplesref,
|
||||
int av_unused flags)
|
||||
@ -619,40 +141,3 @@ int av_asrc_buffer_add_buffer(AVFilterContext *ctx,
|
||||
pts, flags);
|
||||
)
|
||||
}
|
||||
|
||||
AVFilter avfilter_vsrc_buffer = {
|
||||
.name = "buffer",
|
||||
.description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them accessible to the filterchain."),
|
||||
.priv_size = sizeof(BufferSourceContext),
|
||||
.query_formats = query_formats_video,
|
||||
|
||||
.init = init_video,
|
||||
.uninit = uninit,
|
||||
|
||||
.inputs = (const AVFilterPad[]) {{ .name = NULL }},
|
||||
.outputs = (const AVFilterPad[]) {{ .name = "default",
|
||||
.type = AVMEDIA_TYPE_VIDEO,
|
||||
.request_frame = request_frame,
|
||||
.poll_frame = poll_frame,
|
||||
.config_props = config_output_video, },
|
||||
{ .name = NULL}},
|
||||
};
|
||||
|
||||
AVFilter avfilter_asrc_abuffer = {
|
||||
.name = "abuffer",
|
||||
.description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them accessible to the filterchain."),
|
||||
.priv_size = sizeof(BufferSourceContext),
|
||||
.query_formats = query_formats_audio,
|
||||
|
||||
.init = init_audio,
|
||||
.uninit = uninit,
|
||||
|
||||
.inputs = (const AVFilterPad[]) {{ .name = NULL }},
|
||||
.outputs = (const AVFilterPad[]) {{ .name = "default",
|
||||
.type = AVMEDIA_TYPE_AUDIO,
|
||||
.request_frame = request_frame,
|
||||
.poll_frame = poll_frame,
|
||||
.config_props = config_output_audio, },
|
||||
{ .name = NULL}},
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user