mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2026-08-09 17:39:08 +00:00
225 lines
5.7 KiB
C
225 lines
5.7 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 source. Heavily based on libavfilter/buffersrc.c
|
|
*/
|
|
|
|
#include <float.h>
|
|
|
|
#include "libavutil/container_fifo.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 SourceContext {
|
|
const AVClass *class;
|
|
AVCodecParameters *par;
|
|
AVRational time_base; ///< time_base to set in the output link
|
|
|
|
unsigned nb_failed_requests;
|
|
unsigned warning_limit;
|
|
|
|
int eof;
|
|
int64_t last_pts;
|
|
} SourceContext;
|
|
|
|
int av_bsf_source_parameters_set(AVBitStreamFilterContext *ctx, const AVCodecParameters *par)
|
|
{
|
|
SourceContext *s = ctx->priv_data;
|
|
|
|
return avcodec_parameters_copy(s->par, par);
|
|
}
|
|
|
|
static int push_packet(AVBitStreamFilterGraph *graph)
|
|
{
|
|
int ret;
|
|
|
|
while (1) {
|
|
ret = ff_bsf_graph_run_once(graph);
|
|
if (ret == AVERROR(EAGAIN))
|
|
break;
|
|
if (ret < 0 && ret != FFERROR_SOURCE_EMPTY)
|
|
return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int attribute_align_arg av_bsf_source_add_packet(AVBitStreamFilterContext *ctx, AVPacket *pkt, int flags)
|
|
{
|
|
SourceContext *s = ctx->priv_data;
|
|
AVPacket *copy;
|
|
int ret;
|
|
|
|
s->nb_failed_requests = 0;
|
|
|
|
if (!pkt || AVPACKET_IS_EMPTY(pkt))
|
|
return av_bsf_source_close(ctx, s->last_pts, flags);
|
|
if (s->eof)
|
|
return AVERROR_EOF;
|
|
|
|
s->last_pts = pkt->pts + pkt->duration;
|
|
|
|
copy = av_packet_alloc();
|
|
if (!copy)
|
|
return AVERROR(ENOMEM);
|
|
|
|
if ((flags & AV_BSF_SOURCE_FLAG_KEEP_REF)) {
|
|
ret = av_packet_ref(copy, pkt);
|
|
if (ret < 0) {
|
|
av_packet_free(©);
|
|
return ret;
|
|
}
|
|
} else
|
|
av_packet_move_ref(copy, pkt);
|
|
|
|
ret = ff_bsf_filter_packet(ctx->outputs[0], copy);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
if ((flags & AV_BSF_SOURCE_FLAG_PUSH)) {
|
|
ret = push_packet(ctx->graph);
|
|
if (ret < 0)
|
|
return ret;
|
|
}
|
|
|
|
BitStreamFilterLinkInternal *const li = ff_link_internal(ctx->outputs[0]);
|
|
if (s->warning_limit &&
|
|
av_container_fifo_can_read(li->fifo) >= s->warning_limit) {
|
|
av_log(s, AV_LOG_WARNING,
|
|
"%d buffers queued in %s, something may be wrong.\n",
|
|
s->warning_limit,
|
|
(char *)av_x_if_null(ctx->name, ctx->filter->name));
|
|
s->warning_limit *= 10;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int av_bsf_source_close(AVBitStreamFilterContext *ctx, int64_t pts, unsigned flags)
|
|
{
|
|
SourceContext *s = ctx->priv_data;
|
|
|
|
s->eof = 1;
|
|
ff_bsf_link_set_in_status(ctx->outputs[0], AVERROR_EOF, pts);
|
|
return 0;
|
|
}
|
|
|
|
int av_bsf_source_get_status(AVBitStreamFilterContext *ctx)
|
|
{
|
|
SourceContext *s = ctx->priv_data;
|
|
|
|
if (!s->eof && ff_bsf_outlink_get_status(ctx->outputs[0]))
|
|
s->eof = 1;
|
|
|
|
return s->eof ? AVERROR(EOF) : 0;
|
|
}
|
|
|
|
static av_cold int preinit(AVBitStreamFilterContext *ctx)
|
|
{
|
|
SourceContext *c = ctx->priv_data;
|
|
|
|
c->par = avcodec_parameters_alloc();
|
|
if (!c->par)
|
|
return AVERROR(ENOMEM);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static av_cold int init(AVBitStreamFilterContext *ctx)
|
|
{
|
|
SourceContext *c = ctx->priv_data;
|
|
|
|
if (av_q2d(c->time_base) <= 0) {
|
|
av_log(ctx, AV_LOG_ERROR, "Invalid time base %d/%d\n", c->time_base.num, c->time_base.den);
|
|
return AVERROR(EINVAL);
|
|
}
|
|
|
|
c->warning_limit = 100;
|
|
return 0;
|
|
}
|
|
|
|
unsigned ff_bsf_source_get_nb_failed_requests(const AVBitStreamFilterContext *buffer_src)
|
|
{
|
|
return ((SourceContext *)buffer_src->priv_data)->nb_failed_requests;
|
|
}
|
|
|
|
#define OFFSET(x) offsetof(SourceContext, x)
|
|
#define FLAGS (AV_OPT_FLAG_BSF_PARAM|AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_VIDEO_PARAM)
|
|
static const AVOption buffer_options[] = {
|
|
{ "time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, DBL_MAX, FLAGS },
|
|
{ NULL },
|
|
};
|
|
|
|
BSF_DEFINE_CLASS(buffer);
|
|
|
|
static av_cold void uninit(AVBitStreamFilterContext *ctx)
|
|
{
|
|
SourceContext *s = ctx->priv_data;
|
|
avcodec_parameters_free(&s->par);
|
|
}
|
|
|
|
static int config_props(AVBitStreamFilterLink *link)
|
|
{
|
|
SourceContext *c = link->src->priv_data;
|
|
|
|
link->time_base = c->time_base;
|
|
return avcodec_parameters_copy(link->par, c->par);
|
|
}
|
|
|
|
static int activate(AVBitStreamFilterContext *ctx)
|
|
{
|
|
AVBitStreamFilterLink *outlink = ctx->outputs[0];
|
|
SourceContext *c = ctx->priv_data;
|
|
|
|
if (!c->eof && ff_bsf_outlink_get_status(outlink)) {
|
|
c->eof = 1;
|
|
return 0;
|
|
}
|
|
|
|
if (c->eof) {
|
|
ff_bsf_link_set_in_status(outlink, AVERROR_EOF, c->last_pts);
|
|
return 0;
|
|
}
|
|
c->nb_failed_requests++;
|
|
return FFERROR_SOURCE_EMPTY;
|
|
}
|
|
|
|
static const AVBitStreamFilterPad source_outputs[] = {
|
|
{
|
|
.name = "default",
|
|
.config_props = config_props,
|
|
},
|
|
};
|
|
|
|
const FFBitStreamFilter ff_source_bsf = {
|
|
.p.name = "source",
|
|
.p.priv_class = &buffer_class,
|
|
.priv_data_size = sizeof(SourceContext),
|
|
.activate = activate,
|
|
.preinit = preinit,
|
|
.init2 = init,
|
|
.uninit = uninit,
|
|
|
|
BSFILTER_OUTPUTS(source_outputs),
|
|
};
|