/* * ffmpeg filter configuration * * 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 */ #include <stdint.h> #include "ffmpeg.h" #include "libavfilter/avfilter.h"#include "libavfilter/buffersink.h"#include "libavfilter/buffersrc.h" #include "libavutil/avassert.h"#include "libavutil/avstring.h"#include "libavutil/bprint.h"#include "libavutil/channel_layout.h"#include "libavutil/downmix_info.h"#include "libavutil/mem.h"#include "libavutil/opt.h"#include "libavutil/pixdesc.h"#include "libavutil/pixfmt.h"#include "libavutil/samplefmt.h"#include "libavutil/time.h"#include "libavutil/timestamp.h" // FIXME private header, used for mid_pred()#include "libavcodec/mathops.h" typedef struct FilterGraphPriv { FilterGraph fg; // name used for logging char log_name[32]; int is_simple; // true when the filtergraph contains only meta filters // that do not modify the frame data int is_meta; // source filters are present in the graph int have_sources; int disable_conversions; unsigned nb_outputs_done; const char *graph_desc; char *nb_threads; // frame for temporarily holding output from the filtergraph AVFrame *frame; // frame for sending output to the encoder AVFrame *frame_enc; Scheduler *sch; unsigned sch_idx;} FilterGraphPriv; static FilterGraphPriv *fgp_from_fg(FilterGraph *fg){ return (FilterGraphPriv*)fg;} static const FilterGraphPriv *cfgp_from_cfg(const FilterGraph *fg){ return (const FilterGraphPriv*)fg;} // data that is local to the filter thread and not visible outside of ittypedef struct FilterGraphThread { AVFilterGraph *graph; AVFrame *frame; // Temporary buffer for output frames, since on filtergraph reset // we cannot send them to encoders immediately. // The output index is stored in frame opaque. AVFifo *frame_queue_out; // index of the next input to request from the scheduler unsigned next_in; // set to 1 after at least one frame passed through this output int got_frame; // EOF status of each input/output, as received by the thread uint8_t *eof_in; uint8_t *eof_out;} FilterGraphThread; typedef struct InputFilterPriv { InputFilter ifilter; InputFilterOptions opts; int index; AVFilterContext *filter; // used to hold submitted input AVFrame *frame; /* for filters that are not yet bound to an input stream, * this stores the input linklabel, if any */ uint8_t *linklabel; // filter data type enum AVMediaType type; // source data type: AVMEDIA_TYPE_SUBTITLE for sub2video, // same as type otherwise enum AVMediaType type_src; int eof; int bound; // parameters configured for this input int format; int width, height; AVRational sample_aspect_ratio; enum AVColorSpace color_space; enum AVColorRange color_range; int sample_rate; AVChannelLayout ch_layout; AVRational time_base; AVFrameSideData **side_data; int nb_side_data; AVFifo *frame_queue; AVBufferRef *hw_frames_ctx; int displaymatrix_present; int displaymatrix_applied; int32_t displaymatrix[9]; int downmixinfo_present; AVDownmixInfo downmixinfo; struct { AVFrame *frame; int64_t last_pts; int64_t end_pts; ///< marks if sub2video_update should force an initialization unsigned int initialize; } sub2video;} InputFilterPriv; static InputFilterPriv *ifp_from_ifilter(InputFilter *ifilter){ return (InputFilterPriv*)ifilter;} typedef struct FPSConvContext { AVFrame *last_frame; /* number of frames emitted by the video-encoding sync code */ int64_t frame_number; /* history of nb_frames_prev, i.e. the number of times the * previous frame was duplicated by vsync code in recent * do_video_out() calls */ int64_t frames_prev_hist[3]; uint64_t dup_warning; int last_dropped; int dropped_keyframe; enum VideoSyncMethod vsync_method; AVRational framerate; AVRational framerate_max; const AVRational *framerate_supported; int framerate_clip;} FPSConvContext; typedef struct OutputFilterPriv { OutputFilter ofilter; int index; void *log_parent; char log_name[32]; char *name; AVFilterContext *filter; /* desired output stream properties */ int format; int width, height; int sample_rate; AVChannelLayout ch_layout; enum AVColorSpace color_space; enum AVColorRange color_range; AVFrameSideData **side_data; int nb_side_data; // time base in which the output is sent to our downstream // does not need to match the filtersink's timebase AVRational tb_out; // at least one frame with the above timebase was sent // to our downstream, so it cannot change anymore int tb_out_locked; AVRational sample_aspect_ratio; AVDictionary *sws_opts; AVDictionary *swr_opts; // those are only set if no format is specified and the encoder gives us multiple options // They point directly to the relevant lists of the encoder. const int *formats; const AVChannelLayout *ch_layouts; const int *sample_rates; const enum AVColorSpace *color_spaces; const enum AVColorRange *color_ranges; AVRational enc_timebase; int64_t trim_start_us; int64_t trim_duration_us; // offset for output timestamps, in AV_TIME_BASE_Q int64_t ts_offset; int64_t next_pts; FPSConvContext fps; unsigned flags;} OutputFilterPriv; static OutputFilterPriv *ofp_from_ofilter(OutputFilter *ofilter){ return (OutputFilterPriv*)ofilter;} typedef struct FilterCommand { char *target; char *command; char *arg; double time; int all_filters;} FilterCommand; static void filter_command_free(void *opaque, uint8_t *data){ FilterCommand *fc = (FilterCommand*)data; av_freep(&fc->target); av_freep(&fc->command); av_freep(&fc->arg); av_free(data);} static int sub2video_get_blank_frame(InputFilterPriv *ifp){ AVFrame *frame = ifp->sub2video.frame; int ret; av_frame_unref(frame); frame->width = ifp->width; frame->height = ifp->height; frame->format = ifp->format; frame->colorspace = ifp->color_space; frame->color_range = ifp->color_range; ret = av_frame_get_buffer(frame, 0); if (ret < 0) return ret; memset(frame->data[0], 0, frame->height * frame->linesize[0]); return 0;} static void sub2video_copy_rect(uint8_t *dst, int dst_linesize, int w, int h, AVSubtitleRect *r){ uint32_t *pal, *dst2; uint8_t *src, *src2; int x, y; if (r->type != SUBTITLE_BITMAP) { av_log(NULL, AV_LOG_WARNING, "sub2video: non-bitmap subtitle\n"); return; } if (r->x < 0 || r->x + r->w > w || r->y < 0 || r->y + r->h > h) { av_log(NULL, AV_LOG_WARNING, "sub2video: rectangle (%d %d %d %d) overflowing %d %d\n", r->x, r->y, r->w, r->h, w, h ); return; } dst += r->y * dst_linesize + r->x * 4; src = r->data[0]; pal = (uint32_t *)r->data[1]; for (y = 0; y < r->h; y++) { dst2 = (uint32_t *)dst; src2 = src; for (x = 0; x < r->w; x++) *(dst2++) = pal[*(src2++)]; dst += dst_linesize; src += r->linesize[0]; }} static void sub2video_push_ref(InputFilterPriv *ifp, int64_t pts){ AVFrame *frame = ifp->sub2video.frame; int ret; av_assert1(frame->data[0]); ifp->sub2video.last_pts = frame->pts = pts; ret = av_buffersrc_add_frame_flags(ifp->filter, frame, AV_BUFFERSRC_FLAG_KEEP_REF | AV_BUFFERSRC_FLAG_PUSH); if (ret != AVERROR_EOF && ret < 0) av_log(ifp->ifilter.graph, AV_LOG_WARNING, "Error while add the frame to buffer source(%s).\n", av_err2str(ret));} static void sub2video_update(InputFilterPriv *ifp, int64_t heartbeat_pts, const AVSubtitle *sub){ AVFrame *frame = ifp->sub2video.frame; int8_t *dst; int dst_linesize; int num_rects; int64_t pts, end_pts; if (sub) { pts = av_rescale_q(sub->pts + sub->start_display_time * 1000LL, AV_TIME_BASE_Q, ifp->time_base); end_pts = av_rescale_q(sub->pts + sub->end_display_time * 1000LL, AV_TIME_BASE_Q, ifp->time_base); num_rects = sub->num_rects; } else { /* If we are initializing the system, utilize current heartbeat PTS as the start time, and show until the following subpicture is received. Otherwise, utilize the previous subpicture's end time as the fall-back value. */ pts = ifp->sub2video.initialize ? heartbeat_pts : ifp->sub2video.end_pts; end_pts = INT64_MAX; num_rects = 0; } if (sub2video_get_blank_frame(ifp) < 0) { av_log(ifp->ifilter.graph, AV_LOG_ERROR, "Impossible to get a blank canvas.\n"); return; } dst = frame->data [0]; dst_linesize = frame->linesize[0]; for (int i = 0; i < num_rects; i++) sub2video_copy_rect(dst, dst_linesize, frame->width, frame->height, sub->rects[i]); sub2video_push_ref(ifp, pts); ifp->sub2video.end_pts = end_pts; ifp->sub2video.initialize = 0;} /* Define a function for appending a list of allowed formats * to an AVBPrint. If nonempty, the list will have a header. */#define DEF_CHOOSE_FORMAT(name, type, var, supported_list, none, printf_format, get_name) \static void choose_ ## name (OutputFilterPriv *ofp, AVBPrint *bprint) \{ \ if (ofp->var == none && !ofp->supported_list) \ return; \ av_bprintf(bprint, #name "="); \ if (ofp->var != none) { \ av_bprintf(bprint, printf_format, get_name(ofp->var)); \ } else { \ const type *p; \ \ for (p = ofp->supported_list; *p != none; p++) { \ av_bprintf(bprint, printf_format "|", get_name(*p)); \ } \ if (bprint->len > 0) \ bprint->str[--bprint->len] = '\0'; \ } \ av_bprint_chars(bprint, ':', 1); \} DEF_CHOOSE_FORMAT(pix_fmts, enum AVPixelFormat, format, formats, AV_PIX_FMT_NONE, "%s", av_get_pix_fmt_name) DEF_CHOOSE_FORMAT(sample_fmts, enum AVSampleFormat, format, formats, AV_SAMPLE_FMT_NONE, "%s", av_get_sample_fmt_name) DEF_CHOOSE_FORMAT(sample_rates, int, sample_rate, sample_rates, 0, "%d", ) DEF_CHOOSE_FORMAT(color_spaces, enum AVColorSpace, color_space, color_spaces, AVCOL_SPC_UNSPECIFIED, "%s", av_color_space_name); DEF_CHOOSE_FORMAT(color_ranges, enum AVColorRange, color_range, color_ranges, AVCOL_RANGE_UNSPECIFIED, "%s", av_color_range_name); static void choose_channel_layouts(OutputFilterPriv *ofp, AVBPrint *bprint){ if (av_channel_layout_check(&ofp->ch_layout)) { av_bprintf(bprint, "channel_layouts="); av_channel_layout_describe_bprint(&ofp->ch_layout, bprint); } else if (ofp->ch_layouts) { const AVChannelLayout *p; av_bprintf(bprint, "channel_layouts="); for (p = ofp->ch_layouts; p->nb_channels; p++) { av_channel_layout_describe_bprint(p, bprint); av_bprintf(bprint, "|"); } if (bprint->len > 0) bprint->str[--bprint->len] = '\0'; } else return; av_bprint_chars(bprint, ':', 1);} static int read_binary(void *logctx, const char *path, uint8_t **data, int *len){ AVIOContext *io = NULL; int64_t fsize; int ret; *data = NULL; *len = 0; ret = avio_open2(&io, path, AVIO_FLAG_READ, &int_cb, NULL); if (ret < 0) { av_log(logctx, AV_LOG_ERROR, "Cannot open file '%s': %s\n", path, av_err2str(ret)); return ret; } fsize = avio_size(io); if (fsize < 0 || fsize > INT_MAX) { av_log(logctx, AV_LOG_ERROR, "Cannot obtain size of file %s\n", path); ret = AVERROR(EIO); goto fail; } *data = av_malloc(fsize); if (!*data) { ret = AVERROR(ENOMEM); goto fail; } ret = avio_read(io, *data, fsize); if (ret != fsize) { av_log(logctx, AV_LOG_ERROR, "Error reading file %s\n", path); ret = ret < 0 ? ret : AVERROR(EIO); goto fail; } *len = fsize; ret = 0;fail: avio_close(io); if (ret < 0) { av_freep(data); *len = 0; } return ret;} static int filter_opt_apply(void *logctx, AVFilterContext *f, const char *key, const char *val){ const AVOption *o = NULL; int ret; ret = av_opt_set(f, key, val, AV_OPT_SEARCH_CHILDREN); if (ret >= 0) return 0; if (ret == AVERROR_OPTION_NOT_FOUND && key[0] == '/') o = av_opt_find(f, key + 1, NULL, 0, AV_OPT_SEARCH_CHILDREN); if (!o)Lines 1–500 of 3204. Load more
/* * ffmpeg filter configuration * * 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 */ #include <stdint.h> #include "ffmpeg.h" #include "libavfilter/avfilter.h" #include "libavfilter/buffersink.h" #include "libavfilter/buffersrc.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/bprint.h" #include "libavutil/channel_layout.h" #include "libavutil/downmix_info.h" #include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/pixfmt.h" #include "libavutil/samplefmt.h" #include "libavutil/time.h" #include "libavutil/timestamp.h" // FIXME private header, used for mid_pred() #include "libavcodec/mathops.h" typedef struct FilterGraphPriv { FilterGraph fg; // name used for logging char log_name[32]; int is_simple; // true when the filtergraph contains only meta filters // that do not modify the frame data int is_meta; // source filters are present in the graph int have_sources; int disable_conversions; unsigned nb_outputs_done; const char *graph_desc; char *nb_threads; // frame for temporarily holding output from the filtergraph AVFrame *frame; // frame for sending output to the encoder AVFrame *frame_enc; Scheduler *sch; unsigned sch_idx; } FilterGraphPriv; static FilterGraphPriv *fgp_from_fg(FilterGraph *fg) { return (FilterGraphPriv*)fg; } static const FilterGraphPriv *cfgp_from_cfg(const FilterGraph *fg) { return (const FilterGraphPriv*)fg; } // data that is local to the filter thread and not visible outside of it typedef struct FilterGraphThread { AVFilterGraph *graph; AVFrame *frame; // Temporary buffer for output frames, since on filtergraph reset // we cannot send them to encoders immediately. // The output index is stored in frame opaque. AVFifo *frame_queue_out; // index of the next input to request from the scheduler unsigned next_in; // set to 1 after at least one frame passed through this output int got_frame; // EOF status of each input/output, as received by the thread uint8_t *eof_in; uint8_t *eof_out; } FilterGraphThread; typedef struct InputFilterPriv { InputFilter ifilter; InputFilterOptions opts; int index; AVFilterContext *filter; // used to hold submitted input AVFrame *frame; /* for filters that are not yet bound to an input stream, * this stores the input linklabel, if any */ uint8_t *linklabel; // filter data type enum AVMediaType type; // source data type: AVMEDIA_TYPE_SUBTITLE for sub2video, // same as type otherwise enum AVMediaType type_src; int eof; int bound; // parameters configured for this input int format; int width, height; AVRational sample_aspect_ratio; enum AVColorSpace color_space; enum AVColorRange color_range; int sample_rate; AVChannelLayout ch_layout; AVRational time_base; AVFrameSideData **side_data; int nb_side_data; AVFifo *frame_queue; AVBufferRef *hw_frames_ctx; int displaymatrix_present; int displaymatrix_applied; int32_t displaymatrix[9]; int downmixinfo_present; AVDownmixInfo downmixinfo; struct { AVFrame *frame; int64_t last_pts; int64_t end_pts; ///< marks if sub2video_update should force an initialization unsigned int initialize; } sub2video; } InputFilterPriv; static InputFilterPriv *ifp_from_ifilter(InputFilter *ifilter) { return (InputFilterPriv*)ifilter; } typedef struct FPSConvContext { AVFrame *last_frame; /* number of frames emitted by the video-encoding sync code */ int64_t frame_number; /* history of nb_frames_prev, i.e. the number of times the * previous frame was duplicated by vsync code in recent * do_video_out() calls */ int64_t frames_prev_hist[3]; uint64_t dup_warning; int last_dropped; int dropped_keyframe; enum VideoSyncMethod vsync_method; AVRational framerate; AVRational framerate_max; const AVRational *framerate_supported; int framerate_clip; } FPSConvContext; typedef struct OutputFilterPriv { OutputFilter ofilter; int index; void *log_parent; char log_name[32]; char *name; AVFilterContext *filter; /* desired output stream properties */ int format; int width, height; int sample_rate; AVChannelLayout ch_layout; enum AVColorSpace color_space; enum AVColorRange color_range; AVFrameSideData **side_data; int nb_side_data; // time base in which the output is sent to our downstream // does not need to match the filtersink's timebase AVRational tb_out; // at least one frame with the above timebase was sent // to our downstream, so it cannot change anymore int tb_out_locked; AVRational sample_aspect_ratio; AVDictionary *sws_opts; AVDictionary *swr_opts; // those are only set if no format is specified and the encoder gives us multiple options // They point directly to the relevant lists of the encoder. const int *formats; const AVChannelLayout *ch_layouts; const int *sample_rates; const enum AVColorSpace *color_spaces; const enum AVColorRange *color_ranges; AVRational enc_timebase; int64_t trim_start_us; int64_t trim_duration_us; // offset for output timestamps, in AV_TIME_BASE_Q int64_t ts_offset; int64_t next_pts; FPSConvContext fps; unsigned flags; } OutputFilterPriv; static OutputFilterPriv *ofp_from_ofilter(OutputFilter *ofilter) { return (OutputFilterPriv*)ofilter; } typedef struct FilterCommand { char *target; char *command; char *arg; double time; int all_filters; } FilterCommand; static void filter_command_free(void *opaque, uint8_t *data) { FilterCommand *fc = (FilterCommand*)data; av_freep(&fc->target); av_freep(&fc->command); av_freep(&fc->arg); av_free(data); } static int sub2video_get_blank_frame(InputFilterPriv *ifp) { AVFrame *frame = ifp->sub2video.frame; int ret; av_frame_unref(frame); frame->width = ifp->width; frame->height = ifp->height; frame->format = ifp->format; frame->colorspace = ifp->color_space; frame->color_range = ifp->color_range; ret = av_frame_get_buffer(frame, 0); if (ret < 0) return ret; memset(frame->data[0], 0, frame->height * frame->linesize[0]); return 0; } static void sub2video_copy_rect(uint8_t *dst, int dst_linesize, int w, int h, AVSubtitleRect *r) { uint32_t *pal, *dst2; uint8_t *src, *src2; int x, y; if (r->type != SUBTITLE_BITMAP) { av_log(NULL, AV_LOG_WARNING, "sub2video: non-bitmap subtitle\n"); return; } if (r->x < 0 || r->x + r->w > w || r->y < 0 || r->y + r->h > h) { av_log(NULL, AV_LOG_WARNING, "sub2video: rectangle (%d %d %d %d) overflowing %d %d\n", r->x, r->y, r->w, r->h, w, h ); return; } dst += r->y * dst_linesize + r->x * 4; src = r->data[0]; pal = (uint32_t *)r->data[1]; for (y = 0; y < r->h; y++) { dst2 = (uint32_t *)dst; src2 = src; for (x = 0; x < r->w; x++) *(dst2++) = pal[*(src2++)]; dst += dst_linesize; src += r->linesize[0]; } } static void sub2video_push_ref(InputFilterPriv *ifp, int64_t pts) { AVFrame *frame = ifp->sub2video.frame; int ret; av_assert1(frame->data[0]); ifp->sub2video.last_pts = frame->pts = pts; ret = av_buffersrc_add_frame_flags(ifp->filter, frame, AV_BUFFERSRC_FLAG_KEEP_REF | AV_BUFFERSRC_FLAG_PUSH); if (ret != AVERROR_EOF && ret < 0) av_log(ifp->ifilter.graph, AV_LOG_WARNING, "Error while add the frame to buffer source(%s).\n", av_err2str(ret)); } static void sub2video_update(InputFilterPriv *ifp, int64_t heartbeat_pts, const AVSubtitle *sub) { AVFrame *frame = ifp->sub2video.frame; int8_t *dst; int dst_linesize; int num_rects; int64_t pts, end_pts; if (sub) { pts = av_rescale_q(sub->pts + sub->start_display_time * 1000LL, AV_TIME_BASE_Q, ifp->time_base); end_pts = av_rescale_q(sub->pts + sub->end_display_time * 1000LL, AV_TIME_BASE_Q, ifp->time_base); num_rects = sub->num_rects; } else { /* If we are initializing the system, utilize current heartbeat PTS as the start time, and show until the following subpicture is received. Otherwise, utilize the previous subpicture's end time as the fall-back value. */ pts = ifp->sub2video.initialize ? heartbeat_pts : ifp->sub2video.end_pts; end_pts = INT64_MAX; num_rects = 0; } if (sub2video_get_blank_frame(ifp) < 0) { av_log(ifp->ifilter.graph, AV_LOG_ERROR, "Impossible to get a blank canvas.\n"); return; } dst = frame->data [0]; dst_linesize = frame->linesize[0]; for (int i = 0; i < num_rects; i++) sub2video_copy_rect(dst, dst_linesize, frame->width, frame->height, sub->rects[i]); sub2video_push_ref(ifp, pts); ifp->sub2video.end_pts = end_pts; ifp->sub2video.initialize = 0; } /* Define a function for appending a list of allowed formats * to an AVBPrint. If nonempty, the list will have a header. */ #define DEF_CHOOSE_FORMAT(name, type, var, supported_list, none, printf_format, get_name) \ static void choose_ ## name (OutputFilterPriv *ofp, AVBPrint *bprint) \ { \ if (ofp->var == none && !ofp->supported_list) \ return; \ av_bprintf(bprint, #name "="); \ if (ofp->var != none) { \ av_bprintf(bprint, printf_format, get_name(ofp->var)); \ } else { \ const type *p; \ \ for (p = ofp->supported_list; *p != none; p++) { \ av_bprintf(bprint, printf_format "|", get_name(*p)); \ } \ if (bprint->len > 0) \ bprint->str[--bprint->len] = '\0'; \ } \ av_bprint_chars(bprint, ':', 1); \ } DEF_CHOOSE_FORMAT(pix_fmts, enum AVPixelFormat, format, formats, AV_PIX_FMT_NONE, "%s", av_get_pix_fmt_name) DEF_CHOOSE_FORMAT(sample_fmts, enum AVSampleFormat, format, formats, AV_SAMPLE_FMT_NONE, "%s", av_get_sample_fmt_name) DEF_CHOOSE_FORMAT(sample_rates, int, sample_rate, sample_rates, 0, "%d", ) DEF_CHOOSE_FORMAT(color_spaces, enum AVColorSpace, color_space, color_spaces, AVCOL_SPC_UNSPECIFIED, "%s", av_color_space_name); DEF_CHOOSE_FORMAT(color_ranges, enum AVColorRange, color_range, color_ranges, AVCOL_RANGE_UNSPECIFIED, "%s", av_color_range_name); static void choose_channel_layouts(OutputFilterPriv *ofp, AVBPrint *bprint) { if (av_channel_layout_check(&ofp->ch_layout)) { av_bprintf(bprint, "channel_layouts="); av_channel_layout_describe_bprint(&ofp->ch_layout, bprint); } else if (ofp->ch_layouts) { const AVChannelLayout *p; av_bprintf(bprint, "channel_layouts="); for (p = ofp->ch_layouts; p->nb_channels; p++) { av_channel_layout_describe_bprint(p, bprint); av_bprintf(bprint, "|"); } if (bprint->len > 0) bprint->str[--bprint->len] = '\0'; } else return; av_bprint_chars(bprint, ':', 1); } static int read_binary(void *logctx, const char *path, uint8_t **data, int *len) { AVIOContext *io = NULL; int64_t fsize; int ret; *data = NULL; *len = 0; ret = avio_open2(&io, path, AVIO_FLAG_READ, &int_cb, NULL); if (ret < 0) { av_log(logctx, AV_LOG_ERROR, "Cannot open file '%s': %s\n", path, av_err2str(ret)); return ret; } fsize = avio_size(io); if (fsize < 0 || fsize > INT_MAX) { av_log(logctx, AV_LOG_ERROR, "Cannot obtain size of file %s\n", path); ret = AVERROR(EIO); goto fail; } *data = av_malloc(fsize); if (!*data) { ret = AVERROR(ENOMEM); goto fail; } ret = avio_read(io, *data, fsize); if (ret != fsize) { av_log(logctx, AV_LOG_ERROR, "Error reading file %s\n", path); ret = ret < 0 ? ret : AVERROR(EIO); goto fail; } *len = fsize; ret = 0; fail: avio_close(io); if (ret < 0) { av_freep(data); *len = 0; } return ret; } static int filter_opt_apply(void *logctx, AVFilterContext *f, const char *key, const char *val) { const AVOption *o = NULL; int ret; ret = av_opt_set(f, key, val, AV_OPT_SEARCH_CHILDREN); if (ret >= 0) return 0; if (ret == AVERROR_OPTION_NOT_FOUND && key[0] == '/') o = av_opt_find(f, key + 1, NULL, 0, AV_OPT_SEARCH_CHILDREN); if (!o)