mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-03-03 14:32:16 +02:00
fftools/ffmpeg_filter: move some functions higher up
Needed by the following commit.
This commit is contained in:
parent
00183880aa
commit
a1061d4bdc
@ -246,240 +246,6 @@ static void choose_channel_layouts(OutputFilter *ofilter, AVBPrint *bprint)
|
|||||||
av_bprint_chars(bprint, ':', 1);
|
av_bprint_chars(bprint, ':', 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static OutputFilter *ofilter_alloc(FilterGraph *fg)
|
|
||||||
{
|
|
||||||
OutputFilter *ofilter;
|
|
||||||
|
|
||||||
ofilter = ALLOC_ARRAY_ELEM(fg->outputs, fg->nb_outputs);
|
|
||||||
ofilter->graph = fg;
|
|
||||||
ofilter->format = -1;
|
|
||||||
ofilter->last_pts = AV_NOPTS_VALUE;
|
|
||||||
|
|
||||||
return ofilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ifilter_bind_ist(InputFilter *ifilter, InputStream *ist)
|
|
||||||
{
|
|
||||||
InputFilterPriv *ifp = ifp_from_ifilter(ifilter);
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = ist_filter_add(ist, ifilter, filtergraph_is_simple(ifilter->graph));
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ifp->ist = ist;
|
|
||||||
ifp->type_src = ist->st->codecpar->codec_type;
|
|
||||||
ifp->type = ifp->type_src == AVMEDIA_TYPE_SUBTITLE ?
|
|
||||||
AVMEDIA_TYPE_VIDEO : ifp->type_src;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static InputFilter *ifilter_alloc(FilterGraph *fg)
|
|
||||||
{
|
|
||||||
InputFilterPriv *ifp = allocate_array_elem(&fg->inputs, sizeof(*ifp),
|
|
||||||
&fg->nb_inputs);
|
|
||||||
InputFilter *ifilter = &ifp->ifilter;
|
|
||||||
|
|
||||||
ifilter->graph = fg;
|
|
||||||
|
|
||||||
ifp->frame = av_frame_alloc();
|
|
||||||
if (!ifp->frame)
|
|
||||||
report_and_exit(AVERROR(ENOMEM));
|
|
||||||
|
|
||||||
ifp->format = -1;
|
|
||||||
ifp->fallback.format = -1;
|
|
||||||
|
|
||||||
ifp->frame_queue = av_fifo_alloc2(8, sizeof(AVFrame*), AV_FIFO_FLAG_AUTO_GROW);
|
|
||||||
if (!ifp->frame_queue)
|
|
||||||
report_and_exit(AVERROR(ENOMEM));
|
|
||||||
|
|
||||||
return ifilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fg_free(FilterGraph **pfg)
|
|
||||||
{
|
|
||||||
FilterGraph *fg = *pfg;
|
|
||||||
FilterGraphPriv *fgp;
|
|
||||||
|
|
||||||
if (!fg)
|
|
||||||
return;
|
|
||||||
fgp = fgp_from_fg(fg);
|
|
||||||
|
|
||||||
avfilter_graph_free(&fg->graph);
|
|
||||||
for (int j = 0; j < fg->nb_inputs; j++) {
|
|
||||||
InputFilter *ifilter = fg->inputs[j];
|
|
||||||
InputFilterPriv *ifp = ifp_from_ifilter(ifilter);
|
|
||||||
InputStream *ist = ifp->ist;
|
|
||||||
|
|
||||||
if (ifp->frame_queue) {
|
|
||||||
AVFrame *frame;
|
|
||||||
while (av_fifo_read(ifp->frame_queue, &frame, 1) >= 0)
|
|
||||||
av_frame_free(&frame);
|
|
||||||
av_fifo_freep2(&ifp->frame_queue);
|
|
||||||
}
|
|
||||||
if (ist->sub2video.sub_queue) {
|
|
||||||
AVSubtitle sub;
|
|
||||||
while (av_fifo_read(ist->sub2video.sub_queue, &sub, 1) >= 0)
|
|
||||||
avsubtitle_free(&sub);
|
|
||||||
av_fifo_freep2(&ist->sub2video.sub_queue);
|
|
||||||
}
|
|
||||||
|
|
||||||
av_channel_layout_uninit(&ifp->fallback.ch_layout);
|
|
||||||
|
|
||||||
av_frame_free(&ifp->frame);
|
|
||||||
|
|
||||||
av_buffer_unref(&ifp->hw_frames_ctx);
|
|
||||||
av_freep(&ifilter->name);
|
|
||||||
av_freep(&fg->inputs[j]);
|
|
||||||
}
|
|
||||||
av_freep(&fg->inputs);
|
|
||||||
for (int j = 0; j < fg->nb_outputs; j++) {
|
|
||||||
OutputFilter *ofilter = fg->outputs[j];
|
|
||||||
|
|
||||||
av_freep(&ofilter->linklabel);
|
|
||||||
av_freep(&ofilter->name);
|
|
||||||
av_channel_layout_uninit(&ofilter->ch_layout);
|
|
||||||
av_freep(&fg->outputs[j]);
|
|
||||||
}
|
|
||||||
av_freep(&fg->outputs);
|
|
||||||
av_freep(&fgp->graph_desc);
|
|
||||||
|
|
||||||
av_frame_free(&fgp->frame);
|
|
||||||
|
|
||||||
av_freep(pfg);
|
|
||||||
}
|
|
||||||
|
|
||||||
FilterGraph *fg_create(char *graph_desc)
|
|
||||||
{
|
|
||||||
FilterGraphPriv *fgp = allocate_array_elem(&filtergraphs, sizeof(*fgp), &nb_filtergraphs);
|
|
||||||
FilterGraph *fg = &fgp->fg;
|
|
||||||
|
|
||||||
fg->index = nb_filtergraphs - 1;
|
|
||||||
fgp->graph_desc = graph_desc;
|
|
||||||
|
|
||||||
fgp->frame = av_frame_alloc();
|
|
||||||
if (!fgp->frame)
|
|
||||||
report_and_exit(AVERROR(ENOMEM));
|
|
||||||
|
|
||||||
return fg;
|
|
||||||
}
|
|
||||||
|
|
||||||
int init_simple_filtergraph(InputStream *ist, OutputStream *ost,
|
|
||||||
char *graph_desc)
|
|
||||||
{
|
|
||||||
FilterGraph *fg;
|
|
||||||
FilterGraphPriv *fgp;
|
|
||||||
OutputFilter *ofilter;
|
|
||||||
InputFilter *ifilter;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
fg = fg_create(graph_desc);
|
|
||||||
if (!fg)
|
|
||||||
report_and_exit(AVERROR(ENOMEM));
|
|
||||||
fgp = fgp_from_fg(fg);
|
|
||||||
|
|
||||||
fgp->is_simple = 1;
|
|
||||||
|
|
||||||
ofilter = ofilter_alloc(fg);
|
|
||||||
ofilter->ost = ost;
|
|
||||||
|
|
||||||
ost->filter = ofilter;
|
|
||||||
|
|
||||||
ifilter = ifilter_alloc(fg);
|
|
||||||
|
|
||||||
ret = ifilter_bind_ist(ifilter, ist);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *describe_filter_link(FilterGraph *fg, AVFilterInOut *inout, int in)
|
|
||||||
{
|
|
||||||
AVFilterContext *ctx = inout->filter_ctx;
|
|
||||||
AVFilterPad *pads = in ? ctx->input_pads : ctx->output_pads;
|
|
||||||
int nb_pads = in ? ctx->nb_inputs : ctx->nb_outputs;
|
|
||||||
char *res;
|
|
||||||
|
|
||||||
if (nb_pads > 1)
|
|
||||||
res = av_strdup(ctx->filter->name);
|
|
||||||
else
|
|
||||||
res = av_asprintf("%s:%s", ctx->filter->name,
|
|
||||||
avfilter_pad_get_name(pads, inout->pad_idx));
|
|
||||||
if (!res)
|
|
||||||
report_and_exit(AVERROR(ENOMEM));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
|
|
||||||
{
|
|
||||||
FilterGraphPriv *fgp = fgp_from_fg(fg);
|
|
||||||
InputStream *ist = NULL;
|
|
||||||
enum AVMediaType type = avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx);
|
|
||||||
InputFilter *ifilter;
|
|
||||||
int i, ret;
|
|
||||||
|
|
||||||
// TODO: support other filter types
|
|
||||||
if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO) {
|
|
||||||
av_log(NULL, AV_LOG_FATAL, "Only video and audio filters supported "
|
|
||||||
"currently.\n");
|
|
||||||
exit_program(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in->name) {
|
|
||||||
AVFormatContext *s;
|
|
||||||
AVStream *st = NULL;
|
|
||||||
char *p;
|
|
||||||
int file_idx = strtol(in->name, &p, 0);
|
|
||||||
|
|
||||||
if (file_idx < 0 || file_idx >= nb_input_files) {
|
|
||||||
av_log(NULL, AV_LOG_FATAL, "Invalid file index %d in filtergraph description %s.\n",
|
|
||||||
file_idx, fgp->graph_desc);
|
|
||||||
exit_program(1);
|
|
||||||
}
|
|
||||||
s = input_files[file_idx]->ctx;
|
|
||||||
|
|
||||||
for (i = 0; i < s->nb_streams; i++) {
|
|
||||||
enum AVMediaType stream_type = s->streams[i]->codecpar->codec_type;
|
|
||||||
if (stream_type != type &&
|
|
||||||
!(stream_type == AVMEDIA_TYPE_SUBTITLE &&
|
|
||||||
type == AVMEDIA_TYPE_VIDEO /* sub2video hack */))
|
|
||||||
continue;
|
|
||||||
if (check_stream_specifier(s, s->streams[i], *p == ':' ? p + 1 : p) == 1) {
|
|
||||||
st = s->streams[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!st) {
|
|
||||||
av_log(NULL, AV_LOG_FATAL, "Stream specifier '%s' in filtergraph description %s "
|
|
||||||
"matches no streams.\n", p, fgp->graph_desc);
|
|
||||||
exit_program(1);
|
|
||||||
}
|
|
||||||
ist = input_files[file_idx]->streams[st->index];
|
|
||||||
} else {
|
|
||||||
ist = ist_find_unused(type);
|
|
||||||
if (!ist) {
|
|
||||||
av_log(NULL, AV_LOG_FATAL, "Cannot find a matching stream for "
|
|
||||||
"unlabeled input pad %d on filter %s\n", in->pad_idx,
|
|
||||||
in->filter_ctx->name);
|
|
||||||
exit_program(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
av_assert0(ist);
|
|
||||||
|
|
||||||
ifilter = ifilter_alloc(fg);
|
|
||||||
ifilter->name = describe_filter_link(fg, in, 1);
|
|
||||||
|
|
||||||
ret = ifilter_bind_ist(ifilter, ist);
|
|
||||||
if (ret < 0) {
|
|
||||||
av_log(NULL, AV_LOG_ERROR,
|
|
||||||
"Error binding an input stream to complex filtergraph input %s.\n",
|
|
||||||
in->name ? in->name : "");
|
|
||||||
exit_program(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int read_binary(const char *path, uint8_t **data, int *len)
|
static int read_binary(const char *path, uint8_t **data, int *len)
|
||||||
{
|
{
|
||||||
AVIOContext *io = NULL;
|
AVIOContext *io = NULL;
|
||||||
@ -650,6 +416,240 @@ fail:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *describe_filter_link(FilterGraph *fg, AVFilterInOut *inout, int in)
|
||||||
|
{
|
||||||
|
AVFilterContext *ctx = inout->filter_ctx;
|
||||||
|
AVFilterPad *pads = in ? ctx->input_pads : ctx->output_pads;
|
||||||
|
int nb_pads = in ? ctx->nb_inputs : ctx->nb_outputs;
|
||||||
|
char *res;
|
||||||
|
|
||||||
|
if (nb_pads > 1)
|
||||||
|
res = av_strdup(ctx->filter->name);
|
||||||
|
else
|
||||||
|
res = av_asprintf("%s:%s", ctx->filter->name,
|
||||||
|
avfilter_pad_get_name(pads, inout->pad_idx));
|
||||||
|
if (!res)
|
||||||
|
report_and_exit(AVERROR(ENOMEM));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OutputFilter *ofilter_alloc(FilterGraph *fg)
|
||||||
|
{
|
||||||
|
OutputFilter *ofilter;
|
||||||
|
|
||||||
|
ofilter = ALLOC_ARRAY_ELEM(fg->outputs, fg->nb_outputs);
|
||||||
|
ofilter->graph = fg;
|
||||||
|
ofilter->format = -1;
|
||||||
|
ofilter->last_pts = AV_NOPTS_VALUE;
|
||||||
|
|
||||||
|
return ofilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ifilter_bind_ist(InputFilter *ifilter, InputStream *ist)
|
||||||
|
{
|
||||||
|
InputFilterPriv *ifp = ifp_from_ifilter(ifilter);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = ist_filter_add(ist, ifilter, filtergraph_is_simple(ifilter->graph));
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ifp->ist = ist;
|
||||||
|
ifp->type_src = ist->st->codecpar->codec_type;
|
||||||
|
ifp->type = ifp->type_src == AVMEDIA_TYPE_SUBTITLE ?
|
||||||
|
AVMEDIA_TYPE_VIDEO : ifp->type_src;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static InputFilter *ifilter_alloc(FilterGraph *fg)
|
||||||
|
{
|
||||||
|
InputFilterPriv *ifp = allocate_array_elem(&fg->inputs, sizeof(*ifp),
|
||||||
|
&fg->nb_inputs);
|
||||||
|
InputFilter *ifilter = &ifp->ifilter;
|
||||||
|
|
||||||
|
ifilter->graph = fg;
|
||||||
|
|
||||||
|
ifp->frame = av_frame_alloc();
|
||||||
|
if (!ifp->frame)
|
||||||
|
report_and_exit(AVERROR(ENOMEM));
|
||||||
|
|
||||||
|
ifp->format = -1;
|
||||||
|
ifp->fallback.format = -1;
|
||||||
|
|
||||||
|
ifp->frame_queue = av_fifo_alloc2(8, sizeof(AVFrame*), AV_FIFO_FLAG_AUTO_GROW);
|
||||||
|
if (!ifp->frame_queue)
|
||||||
|
report_and_exit(AVERROR(ENOMEM));
|
||||||
|
|
||||||
|
return ifilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fg_free(FilterGraph **pfg)
|
||||||
|
{
|
||||||
|
FilterGraph *fg = *pfg;
|
||||||
|
FilterGraphPriv *fgp;
|
||||||
|
|
||||||
|
if (!fg)
|
||||||
|
return;
|
||||||
|
fgp = fgp_from_fg(fg);
|
||||||
|
|
||||||
|
avfilter_graph_free(&fg->graph);
|
||||||
|
for (int j = 0; j < fg->nb_inputs; j++) {
|
||||||
|
InputFilter *ifilter = fg->inputs[j];
|
||||||
|
InputFilterPriv *ifp = ifp_from_ifilter(ifilter);
|
||||||
|
InputStream *ist = ifp->ist;
|
||||||
|
|
||||||
|
if (ifp->frame_queue) {
|
||||||
|
AVFrame *frame;
|
||||||
|
while (av_fifo_read(ifp->frame_queue, &frame, 1) >= 0)
|
||||||
|
av_frame_free(&frame);
|
||||||
|
av_fifo_freep2(&ifp->frame_queue);
|
||||||
|
}
|
||||||
|
if (ist->sub2video.sub_queue) {
|
||||||
|
AVSubtitle sub;
|
||||||
|
while (av_fifo_read(ist->sub2video.sub_queue, &sub, 1) >= 0)
|
||||||
|
avsubtitle_free(&sub);
|
||||||
|
av_fifo_freep2(&ist->sub2video.sub_queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
av_channel_layout_uninit(&ifp->fallback.ch_layout);
|
||||||
|
|
||||||
|
av_frame_free(&ifp->frame);
|
||||||
|
|
||||||
|
av_buffer_unref(&ifp->hw_frames_ctx);
|
||||||
|
av_freep(&ifilter->name);
|
||||||
|
av_freep(&fg->inputs[j]);
|
||||||
|
}
|
||||||
|
av_freep(&fg->inputs);
|
||||||
|
for (int j = 0; j < fg->nb_outputs; j++) {
|
||||||
|
OutputFilter *ofilter = fg->outputs[j];
|
||||||
|
|
||||||
|
av_freep(&ofilter->linklabel);
|
||||||
|
av_freep(&ofilter->name);
|
||||||
|
av_channel_layout_uninit(&ofilter->ch_layout);
|
||||||
|
av_freep(&fg->outputs[j]);
|
||||||
|
}
|
||||||
|
av_freep(&fg->outputs);
|
||||||
|
av_freep(&fgp->graph_desc);
|
||||||
|
|
||||||
|
av_frame_free(&fgp->frame);
|
||||||
|
|
||||||
|
av_freep(pfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterGraph *fg_create(char *graph_desc)
|
||||||
|
{
|
||||||
|
FilterGraphPriv *fgp = allocate_array_elem(&filtergraphs, sizeof(*fgp), &nb_filtergraphs);
|
||||||
|
FilterGraph *fg = &fgp->fg;
|
||||||
|
|
||||||
|
fg->index = nb_filtergraphs - 1;
|
||||||
|
fgp->graph_desc = graph_desc;
|
||||||
|
|
||||||
|
fgp->frame = av_frame_alloc();
|
||||||
|
if (!fgp->frame)
|
||||||
|
report_and_exit(AVERROR(ENOMEM));
|
||||||
|
|
||||||
|
return fg;
|
||||||
|
}
|
||||||
|
|
||||||
|
int init_simple_filtergraph(InputStream *ist, OutputStream *ost,
|
||||||
|
char *graph_desc)
|
||||||
|
{
|
||||||
|
FilterGraph *fg;
|
||||||
|
FilterGraphPriv *fgp;
|
||||||
|
OutputFilter *ofilter;
|
||||||
|
InputFilter *ifilter;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
fg = fg_create(graph_desc);
|
||||||
|
if (!fg)
|
||||||
|
report_and_exit(AVERROR(ENOMEM));
|
||||||
|
fgp = fgp_from_fg(fg);
|
||||||
|
|
||||||
|
fgp->is_simple = 1;
|
||||||
|
|
||||||
|
ofilter = ofilter_alloc(fg);
|
||||||
|
ofilter->ost = ost;
|
||||||
|
|
||||||
|
ost->filter = ofilter;
|
||||||
|
|
||||||
|
ifilter = ifilter_alloc(fg);
|
||||||
|
|
||||||
|
ret = ifilter_bind_ist(ifilter, ist);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
|
||||||
|
{
|
||||||
|
FilterGraphPriv *fgp = fgp_from_fg(fg);
|
||||||
|
InputStream *ist = NULL;
|
||||||
|
enum AVMediaType type = avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx);
|
||||||
|
InputFilter *ifilter;
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
// TODO: support other filter types
|
||||||
|
if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO) {
|
||||||
|
av_log(NULL, AV_LOG_FATAL, "Only video and audio filters supported "
|
||||||
|
"currently.\n");
|
||||||
|
exit_program(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in->name) {
|
||||||
|
AVFormatContext *s;
|
||||||
|
AVStream *st = NULL;
|
||||||
|
char *p;
|
||||||
|
int file_idx = strtol(in->name, &p, 0);
|
||||||
|
|
||||||
|
if (file_idx < 0 || file_idx >= nb_input_files) {
|
||||||
|
av_log(NULL, AV_LOG_FATAL, "Invalid file index %d in filtergraph description %s.\n",
|
||||||
|
file_idx, fgp->graph_desc);
|
||||||
|
exit_program(1);
|
||||||
|
}
|
||||||
|
s = input_files[file_idx]->ctx;
|
||||||
|
|
||||||
|
for (i = 0; i < s->nb_streams; i++) {
|
||||||
|
enum AVMediaType stream_type = s->streams[i]->codecpar->codec_type;
|
||||||
|
if (stream_type != type &&
|
||||||
|
!(stream_type == AVMEDIA_TYPE_SUBTITLE &&
|
||||||
|
type == AVMEDIA_TYPE_VIDEO /* sub2video hack */))
|
||||||
|
continue;
|
||||||
|
if (check_stream_specifier(s, s->streams[i], *p == ':' ? p + 1 : p) == 1) {
|
||||||
|
st = s->streams[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!st) {
|
||||||
|
av_log(NULL, AV_LOG_FATAL, "Stream specifier '%s' in filtergraph description %s "
|
||||||
|
"matches no streams.\n", p, fgp->graph_desc);
|
||||||
|
exit_program(1);
|
||||||
|
}
|
||||||
|
ist = input_files[file_idx]->streams[st->index];
|
||||||
|
} else {
|
||||||
|
ist = ist_find_unused(type);
|
||||||
|
if (!ist) {
|
||||||
|
av_log(NULL, AV_LOG_FATAL, "Cannot find a matching stream for "
|
||||||
|
"unlabeled input pad %d on filter %s\n", in->pad_idx,
|
||||||
|
in->filter_ctx->name);
|
||||||
|
exit_program(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
av_assert0(ist);
|
||||||
|
|
||||||
|
ifilter = ifilter_alloc(fg);
|
||||||
|
ifilter->name = describe_filter_link(fg, in, 1);
|
||||||
|
|
||||||
|
ret = ifilter_bind_ist(ifilter, ist);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(NULL, AV_LOG_ERROR,
|
||||||
|
"Error binding an input stream to complex filtergraph input %s.\n",
|
||||||
|
in->name ? in->name : "");
|
||||||
|
exit_program(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int init_complex_filtergraph(FilterGraph *fg)
|
int init_complex_filtergraph(FilterGraph *fg)
|
||||||
{
|
{
|
||||||
FilterGraphPriv *fgp = fgp_from_fg(fg);
|
FilterGraphPriv *fgp = fgp_from_fg(fg);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user