mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2026-08-10 07:37:43 +00:00
Tagged experimental for now, as it may see modifications depending on requirements. Signed-off-by: James Almer <jamrial@gmail.com>
149 lines
4.4 KiB
C
149 lines
4.4 KiB
C
/*
|
|
* This file is part of FFmpeg.
|
|
*
|
|
* 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.
|
|
*
|
|
* 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 FFmpeg; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* Packet sink. Heavily based on libavfilter/buffersink.c
|
|
*/
|
|
|
|
#include "libavutil/avassert.h"
|
|
#include "libavutil/opt.h"
|
|
|
|
#include "libavcodec/bsf.h"
|
|
#include "libavcodec/bsf_internal.h"
|
|
#include "libavcodec/packet.h"
|
|
#include "libavcodec/packet_internal.h"
|
|
|
|
typedef struct BufferSinkContext {
|
|
const AVClass *class;
|
|
unsigned warning_limit;
|
|
|
|
AVPacket *peeked_pkt;
|
|
} BufferSinkContext;
|
|
|
|
static int return_or_keep_packet(BufferSinkContext *buf, AVPacket *out, AVPacket *in, int flags)
|
|
{
|
|
if ((flags & AV_BSF_SINK_FLAG_PEEK)) {
|
|
buf->peeked_pkt = in;
|
|
return av_packet_ref(out, in);
|
|
} else {
|
|
buf->peeked_pkt = NULL;
|
|
av_packet_move_ref(out, in);
|
|
av_packet_free(&in);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int attribute_align_arg av_bsf_sink_get_packet(AVBitStreamFilterContext *ctx, AVPacket *pkt, int flags)
|
|
{
|
|
BufferSinkContext *buf = ctx->priv_data;
|
|
AVBitStreamFilterLink *inlink = ctx->inputs[0];
|
|
BitStreamFilterLinkInternal *li = ff_link_internal(inlink);
|
|
int status, ret;
|
|
AVPacket *cur_pkt;
|
|
int64_t pts;
|
|
int buffersrc_empty = 0;
|
|
|
|
if (buf->peeked_pkt)
|
|
return return_or_keep_packet(buf, pkt, buf->peeked_pkt, flags);
|
|
|
|
while (1) {
|
|
ret = ff_bsf_inlink_consume_packet(inlink, &cur_pkt);
|
|
if (ret < 0) {
|
|
return ret;
|
|
} else if (ret) {
|
|
return return_or_keep_packet(buf, pkt, cur_pkt, flags);
|
|
} else if (ff_bsf_inlink_acknowledge_status(inlink, &status, &pts)) {
|
|
return status;
|
|
} else if ((flags & AV_BSF_SINK_FLAG_NO_REQUEST)) {
|
|
return AVERROR(EAGAIN);
|
|
} else if (li->packet_wanted_out) {
|
|
ret = ff_bsf_graph_run_once(ctx->graph);
|
|
if (ret == FFERROR_SOURCE_EMPTY) {
|
|
buffersrc_empty = 1;
|
|
} else if (ret == AVERROR(EAGAIN)) {
|
|
if (buffersrc_empty)
|
|
return ret;
|
|
ff_bsf_inlink_request_packet(inlink);
|
|
} else if (ret < 0) {
|
|
return ret;
|
|
}
|
|
} else {
|
|
ff_bsf_inlink_request_packet(inlink);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int init(AVBitStreamFilterContext *ctx)
|
|
{
|
|
BufferSinkContext *s = ctx->priv_data;
|
|
|
|
s->warning_limit = 100;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void uninit(AVBitStreamFilterContext *ctx)
|
|
{
|
|
BufferSinkContext *buf = ctx->priv_data;
|
|
|
|
av_packet_free(&buf->peeked_pkt);
|
|
}
|
|
|
|
static int activate(AVBitStreamFilterContext *ctx)
|
|
{
|
|
BufferSinkContext *buf = ctx->priv_data;
|
|
BitStreamFilterLinkInternal * const li = ff_link_internal(ctx->inputs[0]);
|
|
|
|
if (buf->warning_limit &&
|
|
av_container_fifo_can_read(li->fifo) >= buf->warning_limit) {
|
|
av_log(ctx, AV_LOG_WARNING,
|
|
"%d buffers queued in %s, something may be wrong.\n",
|
|
buf->warning_limit,
|
|
(char *)av_x_if_null(ctx->name, ctx->filter->name));
|
|
buf->warning_limit *= 10;
|
|
}
|
|
|
|
/* The packet is queued, the rest is up to av_bsf_sink_get_packet */
|
|
return 0;
|
|
}
|
|
|
|
AVRational av_bsf_sink_get_time_base(const AVBitStreamFilterContext *ctx)
|
|
{
|
|
av_assert0(ff_bsf(ctx->filter)->activate == activate);
|
|
return ctx->inputs[0]->time_base;
|
|
}
|
|
|
|
const AVCodecParameters *av_bsf_sink_get_parameters(const AVBitStreamFilterContext *ctx)
|
|
{
|
|
av_assert0(ff_bsf(ctx->filter)->activate == activate);
|
|
return ctx->inputs[0]->par;
|
|
}
|
|
|
|
BSF_DEFINE_CLASS_EXT(sink, "sink", NULL);
|
|
|
|
const FFBitStreamFilter ff_sink_bsf = {
|
|
.p.name = "sink",
|
|
.p.priv_class = &sink_class,
|
|
.priv_data_size = sizeof(BufferSinkContext),
|
|
.init2 = init,
|
|
.uninit = uninit,
|
|
.activate = activate,
|
|
BSFILTER_INPUTS(ff_default_bsf_pad),
|
|
};
|