ffmpeg-devel
Threads by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
January 2022
- 93 participants
- 351 discussions
[PATCH v5 1/7] avcodec/v4l2_context: don't reinit output queue when dynamic resolution change
by Ming Qian 04 Apr '22
by Ming Qian 04 Apr '22
04 Apr '22
in the v4l2 stateful video document, we can see the following
description:
During the resolution change sequence, the OUTPUT queue must remain
streaming. Calling VIDIOC_STREAMOFF() on the OUTPUT queue would
abort the sequence and initiate a seek.
In principle, the OUTPUT queue operates separately from the CAPTURE
queue and this remains true for the duration of the entire
resolution change sequence as well.
so don't reinit the output queue when handling the resolution change
event
Signed-off-by: Ming Qian <ming.qian(a)nxp.com>
---
libavcodec/v4l2_context.c | 27 ++-------------------------
1 file changed, 2 insertions(+), 25 deletions(-)
diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c
index ff1ea8e57b08..dda5157698c3 100644
--- a/libavcodec/v4l2_context.c
+++ b/libavcodec/v4l2_context.c
@@ -162,9 +162,8 @@ static int v4l2_handle_event(V4L2Context *ctx)
{
V4L2m2mContext *s = ctx_to_m2mctx(ctx);
struct v4l2_format cap_fmt = s->capture.format;
- struct v4l2_format out_fmt = s->output.format;
struct v4l2_event evt = { 0 };
- int full_reinit, reinit, ret;
+ int reinit, ret;
ret = ioctl(s->fd, VIDIOC_DQEVENT, &evt);
if (ret < 0) {
@@ -180,25 +179,12 @@ static int v4l2_handle_event(V4L2Context *ctx)
if (evt.type != V4L2_EVENT_SOURCE_CHANGE)
return 0;
- ret = ioctl(s->fd, VIDIOC_G_FMT, &out_fmt);
- if (ret) {
- av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_G_FMT\n", s->output.name);
- return 0;
- }
-
ret = ioctl(s->fd, VIDIOC_G_FMT, &cap_fmt);
if (ret) {
av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_G_FMT\n", s->capture.name);
return 0;
}
- full_reinit = v4l2_resolution_changed(&s->output, &out_fmt);
- if (full_reinit) {
- s->output.height = v4l2_get_height(&out_fmt);
- s->output.width = v4l2_get_width(&out_fmt);
- s->output.sample_aspect_ratio = v4l2_get_sar(&s->output);
- }
-
reinit = v4l2_resolution_changed(&s->capture, &cap_fmt);
if (reinit) {
s->capture.height = v4l2_get_height(&cap_fmt);
@@ -206,18 +192,9 @@ static int v4l2_handle_event(V4L2Context *ctx)
s->capture.sample_aspect_ratio = v4l2_get_sar(&s->capture);
}
- if (full_reinit || reinit)
+ if (reinit)
s->reinit = 1;
- if (full_reinit) {
- ret = ff_v4l2_m2m_codec_full_reinit(s);
- if (ret) {
- av_log(logger(ctx), AV_LOG_ERROR, "v4l2_m2m_codec_full_reinit\n");
- return AVERROR(EINVAL);
- }
- goto reinit_run;
- }
-
if (reinit) {
if (s->avctx)
ret = ff_set_dimensions(s->avctx, s->capture.width, s->capture.height);
--
2.33.0
3
15
Calculate Spatial Info (SI) and Temporal Info (TI) scores for a video, as defined
in ITU-T P.910: Subjective video quality assessment methods for multimedia
applications.
---
Changelog | 1 +
doc/filters.texi | 25 ++++
libavfilter/Makefile | 1 +
libavfilter/allfilters.c | 1 +
libavfilter/version.h | 2 +-
libavfilter/vf_siti.c | 359 +++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 388 insertions(+), 1 deletion(-)
create mode 100644 libavfilter/vf_siti.c
diff --git a/Changelog b/Changelog
index dcb80e0ed9..9ca79a12aa 100644
--- a/Changelog
+++ b/Changelog
@@ -55,6 +55,7 @@ version <next>:
- asuperpass and asuperstop filter
- shufflepixels filter
- tmidequalizer filter
+- siti filter
version 4.3:
diff --git a/doc/filters.texi b/doc/filters.texi
index 813e35c2f9..eb1f23128c 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -18158,6 +18158,31 @@ ffmpeg -i input1.mkv -i input2.mkv -filter_complex "[0:v][1:v] signature=nb_inpu
@end itemize
+@anchor{siti}
+@section siti
+
+Calculate Spatial Info (SI) and Temporal Info (TI) scores for a video, as defined
+in ITU-T P.910: Subjective video quality assessment methods for multimedia
+applications. Available PDF at @url{https://www.itu.int/rec/T-REC-P.910-199909-S/en }.
+Per frame metrics can be written into a file in csv format.
+
+It accepts the following option:
+
+@table @option
+@item stats_file
+Set the path to the file where per frame SI and TI metrics will be written. If no file
+is specified, only summary statistics will be printed to the console.
+@end table
+
+@subsection Examples
+@itemize
+@item
+To calculate SI/TI metrics and store per frame data to stats.csv:
+@example
+ffmpeg -i input.mp4 -vf siti=stats_file='siti.csv' -f null -
+@end example
+@end itemize
+
@anchor{smartblur}
@section smartblur
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index ad1046d526..5514536463 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -413,6 +413,7 @@ OBJS-$(CONFIG_SMARTBLUR_FILTER) += vf_smartblur.o
OBJS-$(CONFIG_SOBEL_FILTER) += vf_convolution.o
OBJS-$(CONFIG_SOBEL_OPENCL_FILTER) += vf_convolution_opencl.o opencl.o \
opencl/convolution.o
+OBJS-$(CONFIG_SITI_FILTER) += vf_siti.o
OBJS-$(CONFIG_SPLIT_FILTER) += split.o
OBJS-$(CONFIG_SPP_FILTER) += vf_spp.o qp_table.o
OBJS-$(CONFIG_SR_FILTER) += vf_sr.o
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index ce317dfa1c..0aef9fdcef 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -393,6 +393,7 @@ extern AVFilter ff_vf_signature;
extern AVFilter ff_vf_smartblur;
extern AVFilter ff_vf_sobel;
extern AVFilter ff_vf_sobel_opencl;
+extern AVFilter ff_vf_siti;
extern AVFilter ff_vf_split;
extern AVFilter ff_vf_spp;
extern AVFilter ff_vf_sr;
diff --git a/libavfilter/version.h b/libavfilter/version.h
index fbe2ed62b2..2136235e54 100644
--- a/libavfilter/version.h
+++ b/libavfilter/version.h
@@ -30,7 +30,7 @@
#include "libavutil/version.h"
#define LIBAVFILTER_VERSION_MAJOR 7
-#define LIBAVFILTER_VERSION_MINOR 95
+#define LIBAVFILTER_VERSION_MINOR 96
#define LIBAVFILTER_VERSION_MICRO 100
diff --git a/libavfilter/vf_siti.c b/libavfilter/vf_siti.c
new file mode 100644
index 0000000000..e8b6142ae7
--- /dev/null
+++ b/libavfilter/vf_siti.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2002 A'rpi
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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
+ * Calculate Spatial Info (SI) and Temporal Info (TI) scores
+ */
+
+#include <math.h>
+
+#include "libavutil/imgutils.h"
+#include "libavutil/internal.h"
+#include "libavutil/opt.h"
+
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+static const int X_FILTER[9] = {
+ 1, 0, -1,
+ 2, 0, -2,
+ 1, 0, -1
+};
+
+static const int Y_FILTER[9] = {
+ 1, 2, 1,
+ 0, 0, 0,
+ -1, -2, -1
+};
+
+typedef struct SiTiContext {
+ const AVClass *class;
+ int pixel_depth;
+ int width, height;
+ int nb_frames;
+ unsigned char *prev_frame;
+ double max_si;
+ double max_ti;
+ double min_si;
+ double min_ti;
+ double sum_si;
+ double sum_ti;
+ FILE *stats_file;
+ char *stats_file_str;
+ int full_range;
+} SiTiContext;
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P,
+ AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P,
+ AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ // User options but no input data
+ SiTiContext *s = ctx->priv;
+ s->max_si = 0;
+ if (s->stats_file_str) {
+ s->stats_file = fopen(s->stats_file_str, "w");
+ if (!s->stats_file) {
+ int err = AVERROR(errno);
+ char buf[128];
+ av_strerror(err, buf, sizeof(buf));
+ av_log(ctx, AV_LOG_ERROR, "Could not open stats file %s: %s\n",
+ s->stats_file_str, buf);
+ return err;
+ }
+ fprintf(s->stats_file, "Frame,SI,TI\n");
+ }
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ SiTiContext *s = ctx->priv;
+
+ double avg_si = s->sum_si / s->nb_frames;
+ double avg_ti = s->sum_ti / s->nb_frames;
+ av_log(ctx, AV_LOG_INFO,
+ "Summary:\nTotal frames: %d\n\n"
+ "Spatial Information:\nAverage: %f\nMax: %f\nMin: %f\n\n"
+ "Temporal Information:\nAverage: %f\nMax: %f\nMin: %f\n",
+ s->nb_frames, avg_si, s->max_si, s->min_si, avg_ti, s->max_ti, s->min_ti
+ );
+
+ if (s->stats_file && s->stats_file != stdout)
+ fclose(s->stats_file);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ // Video input data avilable
+ AVFilterContext *ctx = inlink->dst;
+ SiTiContext *s = ctx->priv;
+ int max_pixsteps[4];
+
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ av_image_fill_max_pixsteps(max_pixsteps, NULL, desc);
+
+ s->pixel_depth = max_pixsteps[0];
+ s->width = inlink->w;
+ s->height = inlink->h;
+ size_t pixel_sz = s->pixel_depth==1? (size_t) sizeof(uint8_t) : (size_t) sizeof(uint16_t);
+ size_t data_sz = (size_t) s->width * pixel_sz * s->height;
+ s->prev_frame = av_malloc(data_sz);
+
+ return 0;
+}
+
+// Get frame data handling 8 and 10 bit formats
+static uint16_t get_frame_data(const unsigned char* src, int pixel_depth, int index)
+{
+ const uint16_t *src16 = (const uint16_t *)src;
+ if (pixel_depth == 2)
+ {
+ return src16[index];
+ }
+ return (uint16_t) src[index];
+}
+
+// Set frame data handling 8 and 10 bit formats
+static void set_frame_data(unsigned char* dst, int pixel_depth, int index, uint16_t data)
+{
+ uint16_t *dst16 = (uint16_t *)dst;
+ if (pixel_depth == 2)
+ {
+ dst16[index] = data;
+ }
+ else
+ {
+ dst[index] = (uint8_t) data;
+ }
+}
+
+// Determine whether the video is in full or limited range. If not defined, assume limited.
+static int is_full_range(AVFrame* frame)
+{
+ if (frame->color_range == AVCOL_RANGE_UNSPECIFIED || frame->color_range == AVCOL_RANGE_NB)
+ {
+ // If color range not specified, fallback to pixel format
+ return frame->format == AV_PIX_FMT_YUVJ420P || frame->format == AV_PIX_FMT_YUVJ422P;
+ }
+ return frame->color_range == AVCOL_RANGE_JPEG;
+}
+
+// Check frame's color range and convert to full range if needed
+static uint16_t convert_full_range(uint16_t y, SiTiContext *s)
+{
+ if (s->full_range == 1)
+ {
+ return y;
+ }
+
+ // For 8 bits, limited range goes from 16 to 235, for 10 bits the range is multiplied by 4
+ double factor = s->pixel_depth == 1? 1 : 4;
+ double shift = 16 * factor;
+ double limit_upper = 235 * factor - shift;
+ double full_upper = 256 * factor - 1;
+ double limit_y = fmin(fmax(y - shift, 0), limit_upper);
+ return (uint16_t) (full_upper * limit_y / limit_upper);
+}
+
+// Applies sobel convolution
+static void convolve_sobel(const unsigned char* src, double* dst, int linesize, SiTiContext *s)
+{
+ int filter_width = 3;
+ int filter_size = filter_width * filter_width;
+ for (int j=1; j<s->height-1; j++)
+ {
+ for (int i=1; i<s->width-1; i++)
+ {
+ double x_conv_sum = 0, y_conv_sum = 0;
+ for (int k=0; k<filter_size; k++)
+ {
+ int ki = k % filter_width - 1;
+ int kj = floor(k / filter_width) - 1;
+ int index = (j + kj) * (linesize / s->pixel_depth) + (i + ki);
+ uint16_t data = convert_full_range(get_frame_data(src, s->pixel_depth, index), s);
+ x_conv_sum += data * X_FILTER[k];
+ y_conv_sum += data * Y_FILTER[k];
+ }
+ double gradient = sqrt(x_conv_sum * x_conv_sum + y_conv_sum * y_conv_sum);
+ // Dst matrix is smaller than src since we ignore edges that can't be convolved
+ dst[(j - 1) * (s->width - 2) + (i - 1)] = gradient;
+ }
+ }
+}
+
+// Calculate pixel difference between current and previous frame, and update previous
+static void calculate_motion(const unsigned char* curr, double* motion_matrix,
+ int linesize, SiTiContext *s)
+{
+ for (int j=0; j<s->height; j++)
+ {
+ for (int i=0; i<s->width; i++)
+ {
+ double motion = 0;
+ int curr_index = j * (linesize / s->pixel_depth) + i;
+ int prev_index = j * s->width + i;
+ uint16_t curr_data = convert_full_range(get_frame_data(curr, s->pixel_depth, curr_index), s);
+
+ if (s->nb_frames > 1)
+ {
+ // Previous frame is already converted to full range
+ motion = curr_data - get_frame_data(s->prev_frame, s->pixel_depth, prev_index);
+ }
+ set_frame_data(s->prev_frame, s->pixel_depth, prev_index, curr_data);
+ motion_matrix[j * s->width + i] = motion;
+ }
+ }
+}
+
+static double std_deviation(double* img_metrics, int width, int height)
+{
+ double size = height * width;
+
+ double mean_sum = 0;
+ for (int j=0; j<height; j++)
+ {
+ for (int i=0; i<width; i++)
+ {
+ mean_sum += img_metrics[j * width + i];
+ }
+ }
+ double mean = mean_sum / size;
+
+ double sqr_diff_sum = 0;
+ for (int j=0; j<height; j++)
+ {
+ for (int i=0; i<width; i++)
+ {
+ double mean_diff = img_metrics[j * width + i] - mean;
+ sqr_diff_sum += (mean_diff * mean_diff);
+ }
+ }
+ double variance = sqr_diff_sum / size;
+ return sqrt(variance);
+}
+
+static void set_meta(AVDictionary **metadata, const char *key, float d)
+{
+ char value[128];
+ snprintf(value, sizeof(value), "%0.2f", d);
+ av_dict_set(metadata, key, value, 0);
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ AVFilterContext *ctx = inlink->dst;
+ SiTiContext *s = ctx->priv;
+
+ // Gradient matrix will not include the input frame's edges
+ size_t gradient_data_sz = (size_t) (s->width - 2) * sizeof(double) * (s->height - 2);
+ double *gradient_matrix = av_malloc(gradient_data_sz);
+ size_t motion_data_sz = (size_t) s->width * sizeof(double) * s->height;
+ double *motion_matrix = av_malloc(motion_data_sz);
+ if (!gradient_matrix || !motion_matrix) {
+ av_frame_free(&frame);
+ return AVERROR(ENOMEM);
+ }
+
+ s->full_range = is_full_range(frame);
+ s->nb_frames++;
+
+ // Calculate si and ti
+ convolve_sobel(frame->data[0], gradient_matrix, frame->linesize[0], s);
+ calculate_motion(frame->data[0], motion_matrix, frame->linesize[0], s);
+ double si = std_deviation(gradient_matrix, s->width - 2, s->height - 2);
+ double ti = std_deviation(motion_matrix, s->width, s->height);
+
+ // Calculate statistics
+ s->max_si = fmax(si, s->max_si);
+ s->max_ti = fmax(ti, s->max_ti);
+ s->sum_si += si;
+ s->sum_ti += ti;
+ s->min_si = s->nb_frames == 1? si : fmin(si, s->min_si);
+ s->min_ti = s->nb_frames == 1? ti : fmin(ti, s->min_ti);
+
+ // Set si ti information in frame metadata
+ set_meta(&frame->metadata, "lavfi.siti.si", si);
+ set_meta(&frame->metadata, "lavfi.siti.ti", ti);
+
+ // Print per frame csv data to file
+ if (s->stats_file)
+ {
+ fprintf(s->stats_file, "%d,%f,%f\n", s->nb_frames, si, ti);
+ }
+
+ av_free(gradient_matrix);
+ return ff_filter_frame(inlink->dst->outputs[0], frame);
+}
+
+#define OFFSET(x) offsetof(SiTiContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption siti_options[] = {
+ {"stats_file", "Set file where to store per-frame si-ti scores", OFFSET(stats_file_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(siti);
+
+static const AVFilterPad avfilter_vf_siti_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad avfilter_vf_siti_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_siti = {
+ .name = "siti",
+ .description = NULL_IF_CONFIG_SMALL("Calculate spatial info (SI)."),
+ .priv_size = sizeof(SiTiContext),
+ .priv_class = &siti_class,
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = avfilter_vf_siti_inputs,
+ .outputs = avfilter_vf_siti_outputs,
+};
--
2.13.5
8
39
The upper limit of strlen(streamid) is 512. Use a larger buffer for
future proof, for example, deal with percent-encoding.
---
libavformat/libsrt.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libavformat/libsrt.c b/libavformat/libsrt.c
index e5701625b8..a66c85d3a2 100644
--- a/libavformat/libsrt.c
+++ b/libavformat/libsrt.c
@@ -513,7 +513,7 @@ static int libsrt_open(URLContext *h, const char *uri, int flags)
{
SRTContext *s = h->priv_data;
const char * p;
- char buf[256];
+ char buf[1024];
int ret = 0;
if (srt_startup() < 0) {
--
2.31.1
4
3
[PATCH 1/5] avformat/movenc: remove unused argument from get_sample_flags()
by Zhao Zhili 29 Mar '22
by Zhao Zhili 29 Mar '22
29 Mar '22
---
libavformat/movenc.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 38ff90833a..634a829f28 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -4427,7 +4427,7 @@ static int mov_write_mfhd_tag(AVIOContext *pb, MOVMuxContext *mov)
return 0;
}
-static uint32_t get_sample_flags(MOVTrack *track, MOVIentry *entry)
+static uint32_t get_sample_flags(MOVIentry *entry)
{
return entry->flags & MOV_SYNC_SAMPLE ? MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO :
(MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC);
@@ -4487,7 +4487,7 @@ static int mov_write_tfhd_tag(AVIOContext *pb, MOVMuxContext *mov,
/* Set the default flags based on the second sample, if available.
* If the first sample is different, that can be signaled via a separate field. */
if (track->entry > 1)
- track->default_sample_flags = get_sample_flags(track, &track->cluster[1]);
+ track->default_sample_flags = get_sample_flags(&track->cluster[1]);
else
track->default_sample_flags =
track->par->codec_type == AVMEDIA_TYPE_VIDEO ?
@@ -4512,11 +4512,11 @@ static int mov_write_trun_tag(AVIOContext *pb, MOVMuxContext *mov,
flags |= MOV_TRUN_SAMPLE_DURATION;
if (track->cluster[i].size != track->default_size)
flags |= MOV_TRUN_SAMPLE_SIZE;
- if (i > first && get_sample_flags(track, &track->cluster[i]) != track->default_sample_flags)
+ if (i > first && get_sample_flags(&track->cluster[i]) != track->default_sample_flags)
flags |= MOV_TRUN_SAMPLE_FLAGS;
}
if (!(flags & MOV_TRUN_SAMPLE_FLAGS) && track->entry > 0 &&
- get_sample_flags(track, &track->cluster[0]) != track->default_sample_flags)
+ get_sample_flags(&track->cluster[0]) != track->default_sample_flags)
flags |= MOV_TRUN_FIRST_SAMPLE_FLAGS;
if (track->flags & MOV_TRACK_CTTS)
flags |= MOV_TRUN_SAMPLE_CTS;
@@ -4538,7 +4538,7 @@ static int mov_write_trun_tag(AVIOContext *pb, MOVMuxContext *mov,
avio_wb32(pb, moof_size + 8 + track->data_offset +
track->cluster[first].pos); /* data offset */
if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS)
- avio_wb32(pb, get_sample_flags(track, &track->cluster[first]));
+ avio_wb32(pb, get_sample_flags(&track->cluster[first]));
for (i = first; i < end; i++) {
if (flags & MOV_TRUN_SAMPLE_DURATION)
@@ -4546,7 +4546,7 @@ static int mov_write_trun_tag(AVIOContext *pb, MOVMuxContext *mov,
if (flags & MOV_TRUN_SAMPLE_SIZE)
avio_wb32(pb, track->cluster[i].size);
if (flags & MOV_TRUN_SAMPLE_FLAGS)
- avio_wb32(pb, get_sample_flags(track, &track->cluster[i]));
+ avio_wb32(pb, get_sample_flags(&track->cluster[i]));
if (flags & MOV_TRUN_SAMPLE_CTS)
avio_wb32(pb, track->cluster[i].cts);
}
--
2.31.1
2
3
[PATCH v3 1/4] avformat/movenc: fix assert failure in get_cluster_duration()
by Zhao Zhili 29 Mar '22
by Zhao Zhili 29 Mar '22
29 Mar '22
When editlist is disabled, the workaournd method of shift dts to
zero and increase the first sample duration doesn't work if the
timestamp is larger than mp4 spec restriction (e.g., sample_delta
in stts entry). Further more, it triggers get_cluster_duration()
assert failure. This patch will drop large offsets between
multiple tracks.
---
libavformat/movenc.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 0f912dd012..f5bb785b01 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -5917,7 +5917,18 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
* to signal the difference in starting time without an edit list.
* Thus move the timestamp for this first sample to 0, increasing
* its duration instead. */
- trk->cluster[trk->entry].dts = trk->start_dts = 0;
+ if (pkt->dts + pkt->duration <= INT32_MAX) {
+ trk->cluster[trk->entry].dts = trk->start_dts = 0;
+ } else {
+ /* Impossible to write a sample duration >= UINT32_MAX.
+ * Use INT32_MAX as a tight restriction.
+ */
+ trk->start_dts = pkt->dts;
+ av_log(s, AV_LOG_WARNING,
+ "Track %d starts with a nonzero dts %" PRId64
+ " which will be shifted to zero\n",
+ pkt->stream_index, pkt->dts);
+ }
}
if (trk->start_dts == AV_NOPTS_VALUE) {
trk->start_dts = pkt->dts;
--
2.31.1
4
5
Fixes: Fixes infinite loop
Fixes: 26575/clusterfuzz-testcase-minimized-ffmpeg_dem_AIFF_fuzzer-5727522236661760
Signed-off-by: Michael Niedermayer <michael(a)niedermayer.cc>
---
libavformat/aiffdec.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/libavformat/aiffdec.c b/libavformat/aiffdec.c
index c650e9074d..15733478e1 100644
--- a/libavformat/aiffdec.c
+++ b/libavformat/aiffdec.c
@@ -406,6 +406,8 @@ static int aiff_read_packet(AVFormatContext *s,
break;
default:
size = st->codecpar->block_align ? (MAX_SIZE / st->codecpar->block_align) * st->codecpar->block_align : MAX_SIZE;
+ if (!size)
+ return AVERROR_INVALIDDATA;
}
size = FFMIN(max_size, size);
res = av_get_packet(s->pb, pkt, size);
--
2.17.1
2
8
Signed-off-by: Michael Niedermayer <michael(a)niedermayer.cc>
---
libavcodec/ass.c | 33 +++++++++++++++++++++++++++------
libavcodec/ass.h | 7 +++++++
2 files changed, 34 insertions(+), 6 deletions(-)
diff --git a/libavcodec/ass.c b/libavcodec/ass.c
index 725e4d42ba1..06714678722 100644
--- a/libavcodec/ass.c
+++ b/libavcodec/ass.c
@@ -114,17 +114,31 @@ char *ff_ass_get_dialog(int readorder, int layer, const char *style,
speaker ? speaker : "", text);
}
-int ff_ass_add_rect(AVSubtitle *sub, const char *dialog,
+int ff_ass_add_rect2(AVSubtitle *sub, const char *dialog,
int readorder, int layer, const char *style,
- const char *speaker)
+ const char *speaker, unsigned *nb_rect_allocated)
{
- AVSubtitleRect **rects, *rect;
+ AVSubtitleRect **rects = sub->rects, *rect;
char *ass_str;
+ uint64_t new_nb = 0;
- rects = av_realloc_array(sub->rects, sub->num_rects+1, sizeof(*sub->rects));
- if (!rects)
+ if (sub->num_rects >= UINT_MAX)
return AVERROR(ENOMEM);
- sub->rects = rects;
+
+ if (nb_rect_allocated && *nb_rect_allocated <= sub->num_rects) {
+ new_nb = FFMIN(sub->num_rects + sub->num_rects/16LL + 1, UINT_MAX);
+ } else if (!nb_rect_allocated)
+ new_nb = sub->num_rects + 1LL;
+
+ if (new_nb) {
+ rects = av_realloc_array(rects, new_nb, sizeof(*sub->rects));
+ if (!rects)
+ return AVERROR(ENOMEM);
+ if (nb_rect_allocated)
+ *nb_rect_allocated = new_nb;
+ sub->rects = rects;
+ }
+
rect = av_mallocz(sizeof(*rect));
if (!rect)
return AVERROR(ENOMEM);
@@ -137,6 +151,13 @@ int ff_ass_add_rect(AVSubtitle *sub, const char *dialog,
return 0;
}
+int ff_ass_add_rect(AVSubtitle *sub, const char *dialog,
+ int readorder, int layer, const char *style,
+ const char *speaker)
+{
+ return ff_ass_add_rect2(sub, dialog, readorder, layer, style, speaker, NULL);
+}
+
void ff_ass_decoder_flush(AVCodecContext *avctx)
{
FFASSDecoderContext *s = avctx->priv_data;
diff --git a/libavcodec/ass.h b/libavcodec/ass.h
index 2c260e4e785..4dffe923d9f 100644
--- a/libavcodec/ass.h
+++ b/libavcodec/ass.h
@@ -118,6 +118,13 @@ int ff_ass_add_rect(AVSubtitle *sub, const char *dialog,
int readorder, int layer, const char *style,
const char *speaker);
+/**
+ * Add an ASS dialog to a subtitle.
+ */
+int ff_ass_add_rect2(AVSubtitle *sub, const char *dialog,
+ int readorder, int layer, const char *style,
+ const char *speaker, unsigned *nb_rect_allocated);
+
/**
* Helper to flush a text subtitles decoder making use of the
* FFASSDecoderContext.
--
2.17.1
3
8
Signed-off-by: Michael Niedermayer <michael(a)niedermayer.cc>
---
libavcodec/ass.c | 36 ++++++++++++++++++++++++++++++------
libavcodec/ass.h | 7 +++++++
2 files changed, 37 insertions(+), 6 deletions(-)
diff --git a/libavcodec/ass.c b/libavcodec/ass.c
index 725e4d42ba1..a1e560d7ff6 100644
--- a/libavcodec/ass.c
+++ b/libavcodec/ass.c
@@ -114,17 +114,34 @@ char *ff_ass_get_dialog(int readorder, int layer, const char *style,
speaker ? speaker : "", text);
}
-int ff_ass_add_rect(AVSubtitle *sub, const char *dialog,
+int ff_ass_add_rect2(AVSubtitle *sub, const char *dialog,
int readorder, int layer, const char *style,
- const char *speaker)
+ const char *speaker, unsigned *nb_rect_allocated)
{
- AVSubtitleRect **rects, *rect;
+ AVSubtitleRect **rects = sub->rects, *rect;
char *ass_str;
+ uint64_t new_nb = 0;
- rects = av_realloc_array(sub->rects, sub->num_rects+1, sizeof(*sub->rects));
- if (!rects)
+ if (sub->num_rects >= UINT_MAX)
return AVERROR(ENOMEM);
- sub->rects = rects;
+
+ if (nb_rect_allocated && *nb_rect_allocated <= sub->num_rects) {
+ if (sub->num_rects < UINT_MAX / 17 * 16) {
+ new_nb = sub->num_rects + sub->num_rects/16 + 1;
+ } else
+ new_nb = UINT_MAX;
+ } else if (!nb_rect_allocated)
+ new_nb = sub->num_rects + 1;
+
+ if (new_nb) {
+ rects = av_realloc_array(rects, new_nb, sizeof(*sub->rects));
+ if (!rects)
+ return AVERROR(ENOMEM);
+ if (nb_rect_allocated)
+ *nb_rect_allocated = new_nb;
+ sub->rects = rects;
+ }
+
rect = av_mallocz(sizeof(*rect));
if (!rect)
return AVERROR(ENOMEM);
@@ -137,6 +154,13 @@ int ff_ass_add_rect(AVSubtitle *sub, const char *dialog,
return 0;
}
+int ff_ass_add_rect(AVSubtitle *sub, const char *dialog,
+ int readorder, int layer, const char *style,
+ const char *speaker)
+{
+ return ff_ass_add_rect2(sub, dialog, readorder, layer, style, speaker, NULL);
+}
+
void ff_ass_decoder_flush(AVCodecContext *avctx)
{
FFASSDecoderContext *s = avctx->priv_data;
diff --git a/libavcodec/ass.h b/libavcodec/ass.h
index 2c260e4e785..4dffe923d9f 100644
--- a/libavcodec/ass.h
+++ b/libavcodec/ass.h
@@ -118,6 +118,13 @@ int ff_ass_add_rect(AVSubtitle *sub, const char *dialog,
int readorder, int layer, const char *style,
const char *speaker);
+/**
+ * Add an ASS dialog to a subtitle.
+ */
+int ff_ass_add_rect2(AVSubtitle *sub, const char *dialog,
+ int readorder, int layer, const char *style,
+ const char *speaker, unsigned *nb_rect_allocated);
+
/**
* Helper to flush a text subtitles decoder making use of the
* FFASSDecoderContext.
--
2.17.1
1
1
17 Mar '22
From: Anton Khirnov <anton(a)khirnov.net>
The new API is more extensible and allows for custom layouts.
More accurate information is exported, eg for decoders that do not
set a channel layout, lavc will not make one up for them.
Deprecate the old API working with just uint64_t bitmasks.
Expanded and completed by Vittorio Giovara <vittorio.giovara(a)gmail.com>
and James Almer <jamrial(a)gmail.com>.
Signed-off-by: Vittorio Giovara <vittorio.giovara(a)gmail.com>
Signed-off-by: James Almer <jamrial(a)gmail.com>
---
Changes since last version:
*Both av_channel_layout_describe() and av_channel_layout_from_string() now
support a "2 channels (FL+LFE)" syntax, to signal native (usually
non-standard) or custom order layouts.
*a single decimal value is now interpreted as a mask by
av_channel_layout_from_string(), same as a single hexadecimal value.
*De-duplicated code by simplifying av_channel_layout_channel_from_string().
The entire set can still be found in
https://github.com/jamrial/FFmpeg/commits/channel_layout4
libavutil/channel_layout.c | 661 +++++++++++++++++++++++++++++++++----
libavutil/channel_layout.h | 551 +++++++++++++++++++++++++++++--
libavutil/version.h | 1 +
3 files changed, 1110 insertions(+), 103 deletions(-)
diff --git a/libavutil/channel_layout.c b/libavutil/channel_layout.c
index ac773a9e63..fe3e94ee86 100644
--- a/libavutil/channel_layout.c
+++ b/libavutil/channel_layout.c
@@ -30,6 +30,7 @@
#include "channel_layout.h"
#include "bprint.h"
#include "common.h"
+#include "opt.h"
struct channel_name {
const char *name;
@@ -37,81 +38,147 @@ struct channel_name {
};
static const struct channel_name channel_names[] = {
- [0] = { "FL", "front left" },
- [1] = { "FR", "front right" },
- [2] = { "FC", "front center" },
- [3] = { "LFE", "low frequency" },
- [4] = { "BL", "back left" },
- [5] = { "BR", "back right" },
- [6] = { "FLC", "front left-of-center" },
- [7] = { "FRC", "front right-of-center" },
- [8] = { "BC", "back center" },
- [9] = { "SL", "side left" },
- [10] = { "SR", "side right" },
- [11] = { "TC", "top center" },
- [12] = { "TFL", "top front left" },
- [13] = { "TFC", "top front center" },
- [14] = { "TFR", "top front right" },
- [15] = { "TBL", "top back left" },
- [16] = { "TBC", "top back center" },
- [17] = { "TBR", "top back right" },
- [29] = { "DL", "downmix left" },
- [30] = { "DR", "downmix right" },
- [31] = { "WL", "wide left" },
- [32] = { "WR", "wide right" },
- [33] = { "SDL", "surround direct left" },
- [34] = { "SDR", "surround direct right" },
- [35] = { "LFE2", "low frequency 2" },
- [36] = { "TSL", "top side left" },
- [37] = { "TSR", "top side right" },
- [38] = { "BFC", "bottom front center" },
- [39] = { "BFL", "bottom front left" },
- [40] = { "BFR", "bottom front right" },
+ [AV_CHAN_FRONT_LEFT ] = { "FL", "front left" },
+ [AV_CHAN_FRONT_RIGHT ] = { "FR", "front right" },
+ [AV_CHAN_FRONT_CENTER ] = { "FC", "front center" },
+ [AV_CHAN_LOW_FREQUENCY ] = { "LFE", "low frequency" },
+ [AV_CHAN_BACK_LEFT ] = { "BL", "back left" },
+ [AV_CHAN_BACK_RIGHT ] = { "BR", "back right" },
+ [AV_CHAN_FRONT_LEFT_OF_CENTER ] = { "FLC", "front left-of-center" },
+ [AV_CHAN_FRONT_RIGHT_OF_CENTER] = { "FRC", "front right-of-center" },
+ [AV_CHAN_BACK_CENTER ] = { "BC", "back center" },
+ [AV_CHAN_SIDE_LEFT ] = { "SL", "side left" },
+ [AV_CHAN_SIDE_RIGHT ] = { "SR", "side right" },
+ [AV_CHAN_TOP_CENTER ] = { "TC", "top center" },
+ [AV_CHAN_TOP_FRONT_LEFT ] = { "TFL", "top front left" },
+ [AV_CHAN_TOP_FRONT_CENTER ] = { "TFC", "top front center" },
+ [AV_CHAN_TOP_FRONT_RIGHT ] = { "TFR", "top front right" },
+ [AV_CHAN_TOP_BACK_LEFT ] = { "TBL", "top back left" },
+ [AV_CHAN_TOP_BACK_CENTER ] = { "TBC", "top back center" },
+ [AV_CHAN_TOP_BACK_RIGHT ] = { "TBR", "top back right" },
+ [AV_CHAN_STEREO_LEFT ] = { "DL", "downmix left" },
+ [AV_CHAN_STEREO_RIGHT ] = { "DR", "downmix right" },
+ [AV_CHAN_WIDE_LEFT ] = { "WL", "wide left" },
+ [AV_CHAN_WIDE_RIGHT ] = { "WR", "wide right" },
+ [AV_CHAN_SURROUND_DIRECT_LEFT ] = { "SDL", "surround direct left" },
+ [AV_CHAN_SURROUND_DIRECT_RIGHT] = { "SDR", "surround direct right" },
+ [AV_CHAN_LOW_FREQUENCY_2 ] = { "LFE2", "low frequency 2" },
+ [AV_CHAN_TOP_SIDE_LEFT ] = { "TSL", "top side left" },
+ [AV_CHAN_TOP_SIDE_RIGHT ] = { "TSR", "top side right" },
+ [AV_CHAN_BOTTOM_FRONT_CENTER ] = { "BFC", "bottom front center" },
+ [AV_CHAN_BOTTOM_FRONT_LEFT ] = { "BFL", "bottom front left" },
+ [AV_CHAN_BOTTOM_FRONT_RIGHT ] = { "BFR", "bottom front right" },
};
-static const char *get_channel_name(int channel_id)
+static const char *get_channel_name(enum AVChannel channel_id)
{
- if (channel_id < 0 || channel_id >= FF_ARRAY_ELEMS(channel_names))
+ if ((unsigned) channel_id >= FF_ARRAY_ELEMS(channel_names) ||
+ !channel_names[channel_id].name)
return NULL;
return channel_names[channel_id].name;
}
-static const struct {
+void av_channel_name_bprint(AVBPrint *bp, enum AVChannel channel_id)
+{
+ if ((unsigned)channel_id < FF_ARRAY_ELEMS(channel_names))
+ av_bprintf(bp, "%s", channel_names[channel_id].name);
+ else
+ av_bprintf(bp, "USR%d", channel_id);
+}
+
+int av_channel_name(char *buf, size_t buf_size, enum AVChannel channel_id)
+{
+ AVBPrint bp;
+
+ if (!buf && buf_size)
+ return AVERROR(EINVAL);
+
+ av_bprint_init_for_buffer(&bp, buf, buf_size);
+ av_channel_name_bprint(&bp, channel_id);
+
+ return bp.len;
+}
+
+void av_channel_description_bprint(AVBPrint *bp, enum AVChannel channel_id)
+{
+ if ((unsigned)channel_id < FF_ARRAY_ELEMS(channel_names))
+ av_bprintf(bp, "%s", channel_names[channel_id].description);
+ else
+ av_bprintf(bp, "user %d", channel_id);
+}
+
+int av_channel_description(char *buf, size_t buf_size, enum AVChannel channel_id)
+{
+ AVBPrint bp;
+
+ if (!buf && buf_size)
+ return AVERROR(EINVAL);
+
+ av_bprint_init_for_buffer(&bp, buf, buf_size);
+ av_channel_description_bprint(&bp, channel_id);
+
+ return bp.len;
+}
+
+enum AVChannel av_channel_from_string(const char *str)
+{
+ int i;
+ char *endptr = (char *)str;
+ enum AVChannel id = AV_CHAN_NONE;
+ for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++) {
+ if (channel_names[i].name && !strcmp(str, channel_names[i].name))
+ return i;
+ }
+ if (!strncmp(str, "USR", 3)) {
+ const char *p = str + 3;
+ id = strtol(p, &endptr, 0);
+ }
+ if (id >= 0 && !*endptr)
+ return id;
+
+ return AV_CHAN_NONE;
+}
+
+struct channel_layout_name {
const char *name;
- int nb_channels;
- uint64_t layout;
-} channel_layout_map[] = {
- { "mono", 1, AV_CH_LAYOUT_MONO },
- { "stereo", 2, AV_CH_LAYOUT_STEREO },
- { "2.1", 3, AV_CH_LAYOUT_2POINT1 },
- { "3.0", 3, AV_CH_LAYOUT_SURROUND },
- { "3.0(back)", 3, AV_CH_LAYOUT_2_1 },
- { "4.0", 4, AV_CH_LAYOUT_4POINT0 },
- { "quad", 4, AV_CH_LAYOUT_QUAD },
- { "quad(side)", 4, AV_CH_LAYOUT_2_2 },
- { "3.1", 4, AV_CH_LAYOUT_3POINT1 },
- { "5.0", 5, AV_CH_LAYOUT_5POINT0_BACK },
- { "5.0(side)", 5, AV_CH_LAYOUT_5POINT0 },
- { "4.1", 5, AV_CH_LAYOUT_4POINT1 },
- { "5.1", 6, AV_CH_LAYOUT_5POINT1_BACK },
- { "5.1(side)", 6, AV_CH_LAYOUT_5POINT1 },
- { "6.0", 6, AV_CH_LAYOUT_6POINT0 },
- { "6.0(front)", 6, AV_CH_LAYOUT_6POINT0_FRONT },
- { "hexagonal", 6, AV_CH_LAYOUT_HEXAGONAL },
- { "6.1", 7, AV_CH_LAYOUT_6POINT1 },
- { "6.1(back)", 7, AV_CH_LAYOUT_6POINT1_BACK },
- { "6.1(front)", 7, AV_CH_LAYOUT_6POINT1_FRONT },
- { "7.0", 7, AV_CH_LAYOUT_7POINT0 },
- { "7.0(front)", 7, AV_CH_LAYOUT_7POINT0_FRONT },
- { "7.1", 8, AV_CH_LAYOUT_7POINT1 },
- { "7.1(wide)", 8, AV_CH_LAYOUT_7POINT1_WIDE_BACK },
- { "7.1(wide-side)", 8, AV_CH_LAYOUT_7POINT1_WIDE },
- { "octagonal", 8, AV_CH_LAYOUT_OCTAGONAL },
- { "hexadecagonal", 16, AV_CH_LAYOUT_HEXADECAGONAL },
- { "downmix", 2, AV_CH_LAYOUT_STEREO_DOWNMIX, },
- { "22.2", 24, AV_CH_LAYOUT_22POINT2, },
+ AVChannelLayout layout;
};
+static const struct channel_layout_name channel_layout_map[] = {
+ { "mono", AV_CHANNEL_LAYOUT_MONO },
+ { "stereo", AV_CHANNEL_LAYOUT_STEREO },
+ { "stereo", AV_CHANNEL_LAYOUT_STEREO_DOWNMIX },
+ { "2.1", AV_CHANNEL_LAYOUT_2POINT1 },
+ { "3.0", AV_CHANNEL_LAYOUT_SURROUND },
+ { "3.0(back)", AV_CHANNEL_LAYOUT_2_1 },
+ { "4.0", AV_CHANNEL_LAYOUT_4POINT0 },
+ { "quad", AV_CHANNEL_LAYOUT_QUAD },
+ { "quad(side)", AV_CHANNEL_LAYOUT_2_2 },
+ { "3.1", AV_CHANNEL_LAYOUT_3POINT1 },
+ { "5.0", AV_CHANNEL_LAYOUT_5POINT0_BACK },
+ { "5.0(side)", AV_CHANNEL_LAYOUT_5POINT0 },
+ { "4.1", AV_CHANNEL_LAYOUT_4POINT1 },
+ { "5.1", AV_CHANNEL_LAYOUT_5POINT1_BACK },
+ { "5.1(side)", AV_CHANNEL_LAYOUT_5POINT1 },
+ { "6.0", AV_CHANNEL_LAYOUT_6POINT0 },
+ { "6.0(front)", AV_CHANNEL_LAYOUT_6POINT0_FRONT },
+ { "hexagonal", AV_CHANNEL_LAYOUT_HEXAGONAL },
+ { "6.1", AV_CHANNEL_LAYOUT_6POINT1 },
+ { "6.1(back)", AV_CHANNEL_LAYOUT_6POINT1_BACK },
+ { "6.1(front)", AV_CHANNEL_LAYOUT_6POINT1_FRONT },
+ { "7.0", AV_CHANNEL_LAYOUT_7POINT0 },
+ { "7.0(front)", AV_CHANNEL_LAYOUT_7POINT0_FRONT },
+ { "7.1", AV_CHANNEL_LAYOUT_7POINT1 },
+ { "7.1(wide)", AV_CHANNEL_LAYOUT_7POINT1_WIDE_BACK },
+ { "7.1(wide-side)", AV_CHANNEL_LAYOUT_7POINT1_WIDE },
+ { "octagonal", AV_CHANNEL_LAYOUT_OCTAGONAL },
+ { "hexadecagonal", AV_CHANNEL_LAYOUT_HEXADECAGONAL },
+ { "downmix", AV_CHANNEL_LAYOUT_STEREO_DOWNMIX, },
+ { "22.2", AV_CHANNEL_LAYOUT_22POINT2, },
+};
+
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
static uint64_t get_channel_layout_single(const char *name, int name_len)
{
int i;
@@ -121,7 +188,7 @@ static uint64_t get_channel_layout_single(const char *name, int name_len)
for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) {
if (strlen(channel_layout_map[i].name) == name_len &&
!memcmp(channel_layout_map[i].name, name, name_len))
- return channel_layout_map[i].layout;
+ return channel_layout_map[i].layout.u.mask;
}
for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++)
if (channel_names[i].name &&
@@ -189,8 +256,8 @@ void av_bprint_channel_layout(struct AVBPrint *bp,
nb_channels = av_get_channel_layout_nb_channels(channel_layout);
for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
- if (nb_channels == channel_layout_map[i].nb_channels &&
- channel_layout == channel_layout_map[i].layout) {
+ if (nb_channels == channel_layout_map[i].layout.nb_channels &&
+ channel_layout == channel_layout_map[i].layout.u.mask) {
av_bprintf(bp, "%s", channel_layout_map[i].name);
return;
}
@@ -231,8 +298,8 @@ int av_get_channel_layout_nb_channels(uint64_t channel_layout)
int64_t av_get_default_channel_layout(int nb_channels) {
int i;
for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
- if (nb_channels == channel_layout_map[i].nb_channels)
- return channel_layout_map[i].layout;
+ if (nb_channels == channel_layout_map[i].layout.nb_channels)
+ return channel_layout_map[i].layout.u.mask;
return 0;
}
@@ -287,7 +354,459 @@ int av_get_standard_channel_layout(unsigned index, uint64_t *layout,
{
if (index >= FF_ARRAY_ELEMS(channel_layout_map))
return AVERROR_EOF;
- if (layout) *layout = channel_layout_map[index].layout;
+ if (layout) *layout = channel_layout_map[index].layout.u.mask;
if (name) *name = channel_layout_map[index].name;
return 0;
}
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+
+int av_channel_layout_from_mask(AVChannelLayout *channel_layout,
+ uint64_t mask)
+{
+ if (!mask)
+ return AVERROR(EINVAL);
+
+ channel_layout->order = AV_CHANNEL_ORDER_NATIVE;
+ channel_layout->nb_channels = av_popcount64(mask);
+ channel_layout->u.mask = mask;
+
+ return 0;
+}
+
+int av_channel_layout_from_string(AVChannelLayout *channel_layout,
+ const char *str)
+{
+ int i;
+ int channels = 0, nb_channels = 0, native = 1;
+ enum AVChannel highest_channel = AV_CHAN_NONE;
+ const char *dup;
+ char *chlist, *end;
+ uint64_t mask = 0;
+
+ /* channel layout names */
+ for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) {
+ if (channel_layout_map[i].name && !strcmp(str, channel_layout_map[i].name)) {
+ *channel_layout = channel_layout_map[i].layout;
+ return 0;
+ }
+ }
+
+ chlist = av_strdup(str);
+ if (!chlist)
+ return AVERROR(ENOMEM);
+
+ /* channel names */
+ av_sscanf(str, "%d channels (%[^)]", &nb_channels, chlist);
+ end = strchr(str, ')');
+
+ dup = chlist;
+ while (*dup) {
+ char *channel, *chname;
+ int ret = av_opt_get_key_value(&dup, "@", "+", AV_OPT_FLAG_IMPLICIT_KEY, &channel, &chname);
+ if (ret < 0) {
+ av_free(chlist);
+ return ret;
+ }
+ if (*dup)
+ dup++; // skip separator
+ if (channel && !*channel)
+ av_freep(&channel);
+ for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++) {
+ if (channel_names[i].name && !strcmp(channel ? channel : chname, channel_names[i].name)) {
+ if (channel || i < highest_channel || mask & (1ULL << i))
+ native = 0; // Not a native layout, use a custom one
+ highest_channel = i;
+ mask |= 1ULL << i;
+ break;
+ }
+ }
+
+ if (!channel && i >= FF_ARRAY_ELEMS(channel_names)) {
+ char *endptr = chname;
+ enum AVChannel id = AV_CHAN_NONE;
+
+ if (!strncmp(chname, "USR", 3)) {
+ const char *p = chname + 3;
+ id = strtol(p, &endptr, 0);
+ }
+ if (id < 0 || *endptr) {
+ native = 0; // Unknown channel name
+ channels = 0;
+ mask = 0;
+ av_free(chname);
+ break;
+ }
+ if (id > 63)
+ native = 0; // Not a native layout, use a custom one
+ else {
+ if (id < highest_channel || mask & (1ULL << id))
+ native = 0; // Not a native layout, use a custom one
+ highest_channel = id;
+ mask |= 1ULL << id;
+ }
+ }
+ channels++;
+ av_free(channel);
+ av_free(chname);
+ }
+
+ if (mask && native) {
+ av_free(chlist);
+ if (nb_channels && ((nb_channels != channels) || (!end || *++end)))
+ return AVERROR(EINVAL);
+ av_channel_layout_from_mask(channel_layout, mask);
+ return 0;
+ }
+
+ /* custom layout of channel names */
+ if (channels && !native) {
+ int idx = 0;
+
+ if (nb_channels && ((nb_channels != channels) || (!end || *++end))) {
+ av_free(chlist);
+ return AVERROR(EINVAL);
+ }
+
+ channel_layout->u.map = av_calloc(channels, sizeof(*channel_layout->u.map));
+ if (!channel_layout->u.map) {
+ av_free(chlist);
+ return AVERROR(ENOMEM);
+ }
+
+ channel_layout->order = AV_CHANNEL_ORDER_CUSTOM;
+ channel_layout->nb_channels = channels;
+
+ dup = chlist;
+ while (*dup) {
+ char *channel, *chname;
+ int ret = av_opt_get_key_value(&dup, "@", "+", AV_OPT_FLAG_IMPLICIT_KEY, &channel, &chname);
+ if (ret < 0) {
+ av_freep(&channel_layout->u.map);
+ av_free(chlist);
+ return ret;
+ }
+ if (*dup)
+ dup++; // skip separator
+ for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++) {
+ if (channel_names[i].name && !strcmp(channel ? channel : chname, channel_names[i].name)) {
+ channel_layout->u.map[idx].id = i;
+ if (channel)
+ av_strlcpy(channel_layout->u.map[idx].name, chname, sizeof(channel_layout->u.map[idx].name));
+ idx++;
+ break;
+ }
+ }
+ if (i >= FF_ARRAY_ELEMS(channel_names)) {
+ const char *p = (channel ? channel : chname) + 3;
+ channel_layout->u.map[idx].id = strtol(p, NULL, 0);
+ if (channel)
+ av_strlcpy(channel_layout->u.map[idx].name, chname, sizeof(channel_layout->u.map[idx].name));
+ idx++;
+ }
+ av_free(channel);
+ av_free(chname);
+ }
+
+ return 0;
+ }
+ av_freep(&chlist);
+
+ errno = 0;
+ mask = strtoull(str, &end, 0);
+
+ /* channel layout mask */
+ if (!errno && !*end && !strchr(str, '-') && mask) {
+ av_channel_layout_from_mask(channel_layout, mask);
+ return 0;
+ }
+
+ errno = 0;
+ channels = strtol(str, &end, 10);
+
+ /* number of channels */
+ if (!errno && !strcmp(end, "c") && channels > 0) {
+ av_channel_layout_default(channel_layout, channels);
+ if (channel_layout->order == AV_CHANNEL_ORDER_NATIVE)
+ return 0;
+ }
+
+ /* number of unordered channels */
+ if (!errno && (!strcmp(end, "C") || !strcmp(end, " channels"))
+ && channels > 0) {
+ channel_layout->order = AV_CHANNEL_ORDER_UNSPEC;
+ channel_layout->nb_channels = channels;
+ return 0;
+ }
+
+ return AVERROR(EINVAL);
+}
+
+void av_channel_layout_uninit(AVChannelLayout *channel_layout)
+{
+ if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM)
+ av_freep(&channel_layout->u.map);
+ memset(channel_layout, 0, sizeof(*channel_layout));
+}
+
+int av_channel_layout_copy(AVChannelLayout *dst, const AVChannelLayout *src)
+{
+ av_channel_layout_uninit(dst);
+ *dst = *src;
+ if (src->order == AV_CHANNEL_ORDER_CUSTOM) {
+ dst->u.map = av_malloc_array(src->nb_channels, sizeof(*dst->u.map));
+ if (!dst->u.map)
+ return AVERROR(ENOMEM);
+ memcpy(dst->u.map, src->u.map, src->nb_channels * sizeof(*src->u.map));
+ }
+ return 0;
+}
+
+int av_channel_layout_describe_bprint(const AVChannelLayout *channel_layout,
+ AVBPrint *bp)
+{
+ int i;
+
+ switch (channel_layout->order) {
+ case AV_CHANNEL_ORDER_NATIVE:
+ for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
+ if (channel_layout->u.mask == channel_layout_map[i].layout.u.mask) {
+ av_bprintf(bp, "%s", channel_layout_map[i].name);
+ return 0;
+ }
+ // fall-through
+ case AV_CHANNEL_ORDER_CUSTOM:
+ if (channel_layout->nb_channels)
+ av_bprintf(bp, "%d channels (", channel_layout->nb_channels);
+ for (i = 0; i < channel_layout->nb_channels; i++) {
+ enum AVChannel ch = av_channel_layout_channel_from_index(channel_layout, i);
+ const char *channel = get_channel_name(ch);
+
+ if (i)
+ av_bprintf(bp, "+");
+ if (channel)
+ av_bprintf(bp, "%s", channel);
+ else
+ av_bprintf(bp, "USR%d", ch);
+ if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM &&
+ channel_layout->u.map[i].name[0])
+ av_bprintf(bp, "@%s", channel_layout->u.map[i].name);
+ }
+ if (channel_layout->nb_channels) {
+ av_bprintf(bp, ")");
+ return 0;
+ }
+ // fall-through
+ case AV_CHANNEL_ORDER_UNSPEC:
+ av_bprintf(bp, "%d channels", channel_layout->nb_channels);
+ return 0;
+ default:
+ return AVERROR(EINVAL);
+ }
+}
+
+int av_channel_layout_describe(const AVChannelLayout *channel_layout,
+ char *buf, size_t buf_size)
+{
+ AVBPrint bp;
+ int ret;
+
+ if (!buf && buf_size)
+ return AVERROR(EINVAL);
+
+ av_bprint_init_for_buffer(&bp, buf, buf_size);
+ ret = av_channel_layout_describe_bprint(channel_layout, &bp);
+ if (ret < 0)
+ return ret;
+
+ return bp.len;
+}
+
+enum AVChannel
+av_channel_layout_channel_from_index(const AVChannelLayout *channel_layout,
+ unsigned int idx)
+{
+ int i;
+
+ if (idx >= channel_layout->nb_channels)
+ return AV_CHAN_NONE;
+
+ switch (channel_layout->order) {
+ case AV_CHANNEL_ORDER_CUSTOM:
+ return channel_layout->u.map[idx].id;
+ case AV_CHANNEL_ORDER_NATIVE:
+ for (i = 0; i < 64; i++) {
+ if ((1ULL << i) & channel_layout->u.mask && !idx--)
+ return i;
+ }
+ default:
+ return AV_CHAN_NONE;
+ }
+}
+
+enum AVChannel
+av_channel_layout_channel_from_string(const AVChannelLayout *channel_layout,
+ const char *str)
+{
+ int index = av_channel_layout_index_from_string(channel_layout, str);
+
+ if (index < 0)
+ return AV_CHAN_NONE;
+
+ return av_channel_layout_channel_from_index(channel_layout, index);
+}
+
+int av_channel_layout_index_from_channel(const AVChannelLayout *channel_layout,
+ enum AVChannel channel)
+{
+ int i;
+
+ if (channel == AV_CHAN_NONE)
+ return AVERROR(EINVAL);
+
+ switch (channel_layout->order) {
+ case AV_CHANNEL_ORDER_CUSTOM:
+ for (i = 0; i < channel_layout->nb_channels; i++)
+ if (channel_layout->u.map[i].id == channel)
+ return i;
+ return AVERROR(EINVAL);
+ case AV_CHANNEL_ORDER_NATIVE: {
+ uint64_t mask = channel_layout->u.mask;
+ if ((unsigned)channel > 63 || !(mask & (1ULL << channel)))
+ return AVERROR(EINVAL);
+ mask &= (1ULL << channel) - 1;
+ return av_popcount64(mask);
+ }
+ default:
+ return AVERROR(EINVAL);
+ }
+}
+
+int av_channel_layout_index_from_string(const AVChannelLayout *channel_layout,
+ const char *str)
+{
+ char *chname;
+ enum AVChannel ch = AV_CHAN_NONE;
+
+ switch (channel_layout->order) {
+ case AV_CHANNEL_ORDER_CUSTOM:
+ chname = strstr(str, "@");
+ if (chname) {
+ char buf[16];
+ chname++;
+ av_strlcpy(buf, str, FFMIN(sizeof(buf), chname - str));
+ if (!*chname)
+ chname = NULL;
+ ch = av_channel_from_string(buf);
+ if (ch == AV_CHAN_NONE && *buf)
+ return AVERROR(EINVAL);
+ }
+ for (int i = 0; chname && i < channel_layout->nb_channels; i++) {
+ if (!strcmp(chname, channel_layout->u.map[i].name) &&
+ (ch == AV_CHAN_NONE || ch == channel_layout->u.map[i].id))
+ return i;
+ }
+ // fall-through
+ case AV_CHANNEL_ORDER_NATIVE:
+ ch = av_channel_from_string(str);
+ if (ch == AV_CHAN_NONE)
+ return AVERROR(EINVAL);
+ return av_channel_layout_index_from_channel(channel_layout, ch);
+ }
+
+ return AVERROR(EINVAL);
+}
+
+int av_channel_layout_check(const AVChannelLayout *channel_layout)
+{
+ if (channel_layout->nb_channels <= 0)
+ return 0;
+
+ switch (channel_layout->order) {
+ case AV_CHANNEL_ORDER_NATIVE:
+ return av_popcount64(channel_layout->u.mask) == channel_layout->nb_channels;
+ case AV_CHANNEL_ORDER_CUSTOM:
+ if (!channel_layout->u.map)
+ return 0;
+ for (int i = 0; i < channel_layout->nb_channels; i++) {
+ if (channel_layout->u.map[i].id == AV_CHAN_NONE)
+ return 0;
+ }
+ return 1;
+ case AV_CHANNEL_ORDER_UNSPEC:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int av_channel_layout_compare(const AVChannelLayout *chl, const AVChannelLayout *chl1)
+{
+ int i;
+
+ /* different channel counts -> not equal */
+ if (chl->nb_channels != chl1->nb_channels)
+ return 1;
+
+ /* if only one is unspecified -> not equal */
+ if ((chl->order == AV_CHANNEL_ORDER_UNSPEC) !=
+ (chl1->order == AV_CHANNEL_ORDER_UNSPEC))
+ return 1;
+ /* both are unspecified -> equal */
+ else if (chl->order == AV_CHANNEL_ORDER_UNSPEC)
+ return 0;
+
+ /* can compare masks directly */
+ if (chl->order != AV_CHANNEL_ORDER_CUSTOM &&
+ chl->order == chl1->order)
+ return chl->u.mask != chl1->u.mask;
+
+ /* compare channel by channel */
+ for (i = 0; i < chl->nb_channels; i++)
+ if (av_channel_layout_channel_from_index(chl, i) !=
+ av_channel_layout_channel_from_index(chl1, i))
+ return 1;
+ return 0;
+}
+
+void av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels)
+{
+ int i;
+ for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
+ if (nb_channels == channel_layout_map[i].layout.nb_channels) {
+ *ch_layout = channel_layout_map[i].layout;
+ return;
+ }
+
+ ch_layout->order = AV_CHANNEL_ORDER_UNSPEC;
+ ch_layout->nb_channels = nb_channels;
+}
+
+const AVChannelLayout *av_channel_layout_standard(void **opaque)
+{
+ uintptr_t i = (uintptr_t)*opaque;
+ const AVChannelLayout *ch_layout = NULL;
+
+ if (i < FF_ARRAY_ELEMS(channel_layout_map)) {
+ ch_layout = &channel_layout_map[i].layout;
+ *opaque = (void*)(i + 1);
+ }
+
+ return ch_layout;
+}
+
+uint64_t av_channel_layout_subset(const AVChannelLayout *channel_layout,
+ uint64_t mask)
+{
+ uint64_t ret = 0;
+ int i;
+
+ if (channel_layout->order == AV_CHANNEL_ORDER_NATIVE)
+ return channel_layout->u.mask & mask;
+
+ for (i = 0; i < 64; i++)
+ if (mask & (1ULL << i) && av_channel_layout_index_from_channel(channel_layout, i) >= 0)
+ ret |= (1ULL << i);
+
+ return ret;
+}
diff --git a/libavutil/channel_layout.h b/libavutil/channel_layout.h
index d39ae1177a..51e4ea3804 100644
--- a/libavutil/channel_layout.h
+++ b/libavutil/channel_layout.h
@@ -23,6 +23,10 @@
#define AVUTIL_CHANNEL_LAYOUT_H
#include <stdint.h>
+#include <stdlib.h>
+
+#include "version.h"
+#include "attributes.h"
/**
* @file
@@ -34,6 +38,71 @@
* @{
*/
+enum AVChannel {
+ ///< Invalid channel index
+ AV_CHAN_NONE = -1,
+ AV_CHAN_FRONT_LEFT,
+ AV_CHAN_FRONT_RIGHT,
+ AV_CHAN_FRONT_CENTER,
+ AV_CHAN_LOW_FREQUENCY,
+ AV_CHAN_BACK_LEFT,
+ AV_CHAN_BACK_RIGHT,
+ AV_CHAN_FRONT_LEFT_OF_CENTER,
+ AV_CHAN_FRONT_RIGHT_OF_CENTER,
+ AV_CHAN_BACK_CENTER,
+ AV_CHAN_SIDE_LEFT,
+ AV_CHAN_SIDE_RIGHT,
+ AV_CHAN_TOP_CENTER,
+ AV_CHAN_TOP_FRONT_LEFT,
+ AV_CHAN_TOP_FRONT_CENTER,
+ AV_CHAN_TOP_FRONT_RIGHT,
+ AV_CHAN_TOP_BACK_LEFT,
+ AV_CHAN_TOP_BACK_CENTER,
+ AV_CHAN_TOP_BACK_RIGHT,
+ /** Stereo downmix. */
+ AV_CHAN_STEREO_LEFT = 29,
+ /** See above. */
+ AV_CHAN_STEREO_RIGHT,
+ AV_CHAN_WIDE_LEFT,
+ AV_CHAN_WIDE_RIGHT,
+ AV_CHAN_SURROUND_DIRECT_LEFT,
+ AV_CHAN_SURROUND_DIRECT_RIGHT,
+ AV_CHAN_LOW_FREQUENCY_2,
+ AV_CHAN_TOP_SIDE_LEFT,
+ AV_CHAN_TOP_SIDE_RIGHT,
+ AV_CHAN_BOTTOM_FRONT_CENTER,
+ AV_CHAN_BOTTOM_FRONT_LEFT,
+ AV_CHAN_BOTTOM_FRONT_RIGHT,
+
+ /** Channel is empty can be safely skipped. */
+ AV_CHAN_UNUSED = 0x200,
+
+ /** Channel contains data, but its position is unknown. */
+ AV_CHAN_UNKWNOWN = 0x300,
+};
+
+enum AVChannelOrder {
+ /**
+ * Only the channel count is specified, without any further information
+ * about the channel order.
+ */
+ AV_CHANNEL_ORDER_UNSPEC,
+ /**
+ * The native channel order, i.e. the channels are in the same order in
+ * which they are defined in the AVChannel enum. This supports up to 63
+ * different channels.
+ */
+ AV_CHANNEL_ORDER_NATIVE,
+ /**
+ * The channel order does not correspond to any other predefined order and
+ * is stored as an explicit map. For example, this could be used to support
+ * layouts with 64 or more channels, or with empty/skipped (AV_CHAN_SILENCE)
+ * channels at arbitrary positions.
+ */
+ AV_CHANNEL_ORDER_CUSTOM,
+};
+
+
/**
* @defgroup channel_masks Audio channel masks
*
@@ -46,41 +115,46 @@
*
* @{
*/
-#define AV_CH_FRONT_LEFT 0x00000001
-#define AV_CH_FRONT_RIGHT 0x00000002
-#define AV_CH_FRONT_CENTER 0x00000004
-#define AV_CH_LOW_FREQUENCY 0x00000008
-#define AV_CH_BACK_LEFT 0x00000010
-#define AV_CH_BACK_RIGHT 0x00000020
-#define AV_CH_FRONT_LEFT_OF_CENTER 0x00000040
-#define AV_CH_FRONT_RIGHT_OF_CENTER 0x00000080
-#define AV_CH_BACK_CENTER 0x00000100
-#define AV_CH_SIDE_LEFT 0x00000200
-#define AV_CH_SIDE_RIGHT 0x00000400
-#define AV_CH_TOP_CENTER 0x00000800
-#define AV_CH_TOP_FRONT_LEFT 0x00001000
-#define AV_CH_TOP_FRONT_CENTER 0x00002000
-#define AV_CH_TOP_FRONT_RIGHT 0x00004000
-#define AV_CH_TOP_BACK_LEFT 0x00008000
-#define AV_CH_TOP_BACK_CENTER 0x00010000
-#define AV_CH_TOP_BACK_RIGHT 0x00020000
-#define AV_CH_STEREO_LEFT 0x20000000 ///< Stereo downmix.
-#define AV_CH_STEREO_RIGHT 0x40000000 ///< See AV_CH_STEREO_LEFT.
-#define AV_CH_WIDE_LEFT 0x0000000080000000ULL
-#define AV_CH_WIDE_RIGHT 0x0000000100000000ULL
-#define AV_CH_SURROUND_DIRECT_LEFT 0x0000000200000000ULL
-#define AV_CH_SURROUND_DIRECT_RIGHT 0x0000000400000000ULL
-#define AV_CH_LOW_FREQUENCY_2 0x0000000800000000ULL
-#define AV_CH_TOP_SIDE_LEFT 0x0000001000000000ULL
-#define AV_CH_TOP_SIDE_RIGHT 0x0000002000000000ULL
-#define AV_CH_BOTTOM_FRONT_CENTER 0x0000004000000000ULL
-#define AV_CH_BOTTOM_FRONT_LEFT 0x0000008000000000ULL
-#define AV_CH_BOTTOM_FRONT_RIGHT 0x0000010000000000ULL
+#define AV_CH_FRONT_LEFT (1ULL << AV_CHAN_FRONT_LEFT )
+#define AV_CH_FRONT_RIGHT (1ULL << AV_CHAN_FRONT_RIGHT )
+#define AV_CH_FRONT_CENTER (1ULL << AV_CHAN_FRONT_CENTER )
+#define AV_CH_LOW_FREQUENCY (1ULL << AV_CHAN_LOW_FREQUENCY )
+#define AV_CH_BACK_LEFT (1ULL << AV_CHAN_BACK_LEFT )
+#define AV_CH_BACK_RIGHT (1ULL << AV_CHAN_BACK_RIGHT )
+#define AV_CH_FRONT_LEFT_OF_CENTER (1ULL << AV_CHAN_FRONT_LEFT_OF_CENTER )
+#define AV_CH_FRONT_RIGHT_OF_CENTER (1ULL << AV_CHAN_FRONT_RIGHT_OF_CENTER)
+#define AV_CH_BACK_CENTER (1ULL << AV_CHAN_BACK_CENTER )
+#define AV_CH_SIDE_LEFT (1ULL << AV_CHAN_SIDE_LEFT )
+#define AV_CH_SIDE_RIGHT (1ULL << AV_CHAN_SIDE_RIGHT )
+#define AV_CH_TOP_CENTER (1ULL << AV_CHAN_TOP_CENTER )
+#define AV_CH_TOP_FRONT_LEFT (1ULL << AV_CHAN_TOP_FRONT_LEFT )
+#define AV_CH_TOP_FRONT_CENTER (1ULL << AV_CHAN_TOP_FRONT_CENTER )
+#define AV_CH_TOP_FRONT_RIGHT (1ULL << AV_CHAN_TOP_FRONT_RIGHT )
+#define AV_CH_TOP_BACK_LEFT (1ULL << AV_CHAN_TOP_BACK_LEFT )
+#define AV_CH_TOP_BACK_CENTER (1ULL << AV_CHAN_TOP_BACK_CENTER )
+#define AV_CH_TOP_BACK_RIGHT (1ULL << AV_CHAN_TOP_BACK_RIGHT )
+#define AV_CH_STEREO_LEFT (1ULL << AV_CHAN_STEREO_LEFT )
+#define AV_CH_STEREO_RIGHT (1ULL << AV_CHAN_STEREO_RIGHT )
+#define AV_CH_WIDE_LEFT (1ULL << AV_CHAN_WIDE_LEFT )
+#define AV_CH_WIDE_RIGHT (1ULL << AV_CHAN_WIDE_RIGHT )
+#define AV_CH_SURROUND_DIRECT_LEFT (1ULL << AV_CHAN_SURROUND_DIRECT_LEFT )
+#define AV_CH_SURROUND_DIRECT_RIGHT (1ULL << AV_CHAN_SURROUND_DIRECT_RIGHT)
+#define AV_CH_LOW_FREQUENCY_2 (1ULL << AV_CHAN_LOW_FREQUENCY_2 )
+#define AV_CH_TOP_SIDE_LEFT (1ULL << AV_CHAN_TOP_SIDE_LEFT )
+#define AV_CH_TOP_SIDE_RIGHT (1ULL << AV_CHAN_TOP_SIDE_RIGHT )
+#define AV_CH_BOTTOM_FRONT_CENTER (1ULL << AV_CHAN_BOTTOM_FRONT_CENTER )
+#define AV_CH_BOTTOM_FRONT_LEFT (1ULL << AV_CHAN_BOTTOM_FRONT_LEFT )
+#define AV_CH_BOTTOM_FRONT_RIGHT (1ULL << AV_CHAN_BOTTOM_FRONT_RIGHT )
+#if FF_API_OLD_CHANNEL_LAYOUT
/** Channel mask value used for AVCodecContext.request_channel_layout
to indicate that the user requests the channel order of the decoder output
- to be the native codec channel order. */
+ to be the native codec channel order.
+ @deprecated channel order is now indicated in a special field in
+ AVChannelLayout
+ */
#define AV_CH_LAYOUT_NATIVE 0x8000000000000000ULL
+#endif
/**
* @}
@@ -128,6 +202,167 @@ enum AVMatrixEncoding {
AV_MATRIX_ENCODING_NB
};
+/**
+ * @}
+ */
+
+/**
+ * An AVChannelCustom defines a single channel within a custom order layout
+ *
+ * Unlike most structures in FFmpeg, sizeof(AVChannelCustom) is a part of the
+ * public ABI.
+ *
+ * No new fields may be added to it without a major version bump.
+ */
+typedef struct AVChannelCustom {
+ enum AVChannel id;
+ char name[16];
+ void *opaque;
+} AVChannelCustom;
+
+/**
+ * An AVChannelLayout holds information about the channel layout of audio data.
+ *
+ * A channel layout here is defined as a set of channels ordered in a specific
+ * way (unless the channel order is AV_CHANNEL_ORDER_UNSPEC, in which case an
+ * AVChannelLayout carries only the channel count).
+ *
+ * Unlike most structures in Libav, sizeof(AVChannelLayout) is a part of the
+ * public ABI and may be used by the caller. E.g. it may be allocated on stack
+ * or embedded in caller-defined structs.
+ *
+ * AVChannelLayout can be initialized as follows:
+ * - default initialization with {0}, followed by setting all used fields
+ * correctly;
+ * - by assigning one of the predefined AV_CHANNEL_LAYOUT_* initializers;
+ * - with a constructor function, such as av_channel_layout_default(),
+ * av_channel_layout_from_mask() or av_channel_layout_from_string().
+ *
+ * The channel layout must be unitialized with av_channel_layout_uninit()
+ *
+ * Copying an AVChannelLayout via assigning is forbidden,
+ * av_channel_layout_copy() must be used. instead (and its return value should
+ * be checked)
+ *
+ * No new fields may be added to it without a major version bump, except for
+ * new elements of the union fitting in sizeof(uint64_t).
+ */
+typedef struct AVChannelLayout {
+ /**
+ * Channel order used in this layout.
+ * This is a mandatory field.
+ */
+ enum AVChannelOrder order;
+
+ /**
+ * Number of channels in this layout. Mandatory field.
+ */
+ int nb_channels;
+
+ /**
+ * Details about which channels are present in this layout.
+ * For AV_CHANNEL_ORDER_UNSPEC, this field is undefined and must not be
+ * used.
+ */
+ union {
+ /**
+ * This member must be used for AV_CHANNEL_ORDER_NATIVE.
+ * It is a bitmask, where the position of each set bit means that the
+ * AVChannel with the corresponding value is present.
+ *
+ * I.e. when (mask & (1 << AV_CHAN_FOO)) is non-zero, then AV_CHAN_FOO
+ * is present in the layout. Otherwise it is not present.
+ *
+ * @note when a channel layout using a bitmask is constructed or
+ * modified manually (i.e. not using any of the av_channel_layout_*
+ * functions), the code doing it must ensure that the number of set bits
+ * is equal to nb_channels.
+ */
+ uint64_t mask;
+ /**
+ * This member must be used when the channel order is
+ * AV_CHANNEL_ORDER_CUSTOM. It is a nb_channels-sized array, with each
+ * element signalling the presence of the AVChannel with the
+ * corresponding value in map[i].id.
+ *
+ * I.e. when map[i].id is equal to AV_CHAN_FOO, then AV_CH_FOO is the
+ * i-th channel in the audio data.
+ *
+ * map[i].name may be filled with a 0-terminated string, in which case
+ * it will be used for the purpose of identifying the channel with the
+ * convenience functions below. Otherise it must be zeroed.
+ */
+ AVChannelCustom *map;
+ } u;
+
+ /**
+ * For some private data of the user.
+ */
+ void *opaque;
+} AVChannelLayout;
+
+#define AV_CHANNEL_LAYOUT_MONO \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 1, .u = { .mask = AV_CH_LAYOUT_MONO }}
+#define AV_CHANNEL_LAYOUT_STEREO \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 2, .u = { .mask = AV_CH_LAYOUT_STEREO }}
+#define AV_CHANNEL_LAYOUT_2POINT1 \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 3, .u = { .mask = AV_CH_LAYOUT_2POINT1 }}
+#define AV_CHANNEL_LAYOUT_2_1 \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 3, .u = { .mask = AV_CH_LAYOUT_2_1 }}
+#define AV_CHANNEL_LAYOUT_SURROUND \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 3, .u = { .mask = AV_CH_LAYOUT_SURROUND }}
+#define AV_CHANNEL_LAYOUT_3POINT1 \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 4, .u = { .mask = AV_CH_LAYOUT_3POINT1 }}
+#define AV_CHANNEL_LAYOUT_4POINT0 \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 4, .u = { .mask = AV_CH_LAYOUT_4POINT0 }}
+#define AV_CHANNEL_LAYOUT_4POINT1 \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 5, .u = { .mask = AV_CH_LAYOUT_4POINT1 }}
+#define AV_CHANNEL_LAYOUT_2_2 \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 4, .u = { .mask = AV_CH_LAYOUT_2_2 }}
+#define AV_CHANNEL_LAYOUT_QUAD \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 4, .u = { .mask = AV_CH_LAYOUT_QUAD }}
+#define AV_CHANNEL_LAYOUT_5POINT0 \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 5, .u = { .mask = AV_CH_LAYOUT_5POINT0 }}
+#define AV_CHANNEL_LAYOUT_5POINT1 \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 6, .u = { .mask = AV_CH_LAYOUT_5POINT1 }}
+#define AV_CHANNEL_LAYOUT_5POINT0_BACK \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 5, .u = { .mask = AV_CH_LAYOUT_5POINT0_BACK }}
+#define AV_CHANNEL_LAYOUT_5POINT1_BACK \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 6, .u = { .mask = AV_CH_LAYOUT_5POINT1_BACK }}
+#define AV_CHANNEL_LAYOUT_6POINT0 \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 6, .u = { .mask = AV_CH_LAYOUT_6POINT0 }}
+#define AV_CHANNEL_LAYOUT_6POINT0_FRONT \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 6, .u = { .mask = AV_CH_LAYOUT_6POINT0_FRONT }}
+#define AV_CHANNEL_LAYOUT_HEXAGONAL \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 6, .u = { .mask = AV_CH_LAYOUT_HEXAGONAL }}
+#define AV_CHANNEL_LAYOUT_6POINT1 \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 7, .u = { .mask = AV_CH_LAYOUT_6POINT1 }}
+#define AV_CHANNEL_LAYOUT_6POINT1_BACK \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 7, .u = { .mask = AV_CH_LAYOUT_6POINT1_BACK }}
+#define AV_CHANNEL_LAYOUT_6POINT1_FRONT \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 7, .u = { .mask = AV_CH_LAYOUT_6POINT1_FRONT }}
+#define AV_CHANNEL_LAYOUT_7POINT0 \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 7, .u = { .mask = AV_CH_LAYOUT_7POINT0 }}
+#define AV_CHANNEL_LAYOUT_7POINT0_FRONT \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 7, .u = { .mask = AV_CH_LAYOUT_7POINT0_FRONT }}
+#define AV_CHANNEL_LAYOUT_7POINT1 \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 8, .u = { .mask = AV_CH_LAYOUT_7POINT1 }}
+#define AV_CHANNEL_LAYOUT_7POINT1_WIDE \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 8, .u = { .mask = AV_CH_LAYOUT_7POINT1_WIDE }}
+#define AV_CHANNEL_LAYOUT_7POINT1_WIDE_BACK \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 8, .u = { .mask = AV_CH_LAYOUT_7POINT1_WIDE_BACK }}
+#define AV_CHANNEL_LAYOUT_OCTAGONAL \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 8, .u = { .mask = AV_CH_LAYOUT_OCTAGONAL }}
+#define AV_CHANNEL_LAYOUT_HEXADECAGONAL \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 16, .u = { .mask = AV_CH_LAYOUT_HEXAGONAL }}
+#define AV_CHANNEL_LAYOUT_STEREO_DOWNMIX \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 2, .u = { .mask = AV_CH_LAYOUT_STEREO_DOWNMIX }}
+#define AV_CHANNEL_LAYOUT_22POINT2 \
+ { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 24, .u = { .mask = AV_CH_LAYOUT_22POINT2 }}
+
+struct AVBPrint;
+
+#if FF_API_OLD_CHANNEL_LAYOUT
/**
* Return a channel layout id that matches name, or 0 if no match is found.
*
@@ -144,7 +379,10 @@ enum AVMatrixEncoding {
* AV_CH_* macros).
*
* Example: "stereo+FC" = "2c+FC" = "2c+1c" = "0x7"
+ *
+ * @deprecated use av_channel_layout_from_string()
*/
+attribute_deprecated
uint64_t av_get_channel_layout(const char *name);
/**
@@ -158,7 +396,9 @@ uint64_t av_get_channel_layout(const char *name);
* @param[out] nb_channels number of channels
*
* @return 0 on success, AVERROR(EINVAL) if the parsing fails.
+ * @deprecated use av_channel_layout_from_string()
*/
+attribute_deprecated
int av_get_extended_channel_layout(const char *name, uint64_t* channel_layout, int* nb_channels);
/**
@@ -167,23 +407,31 @@ int av_get_extended_channel_layout(const char *name, uint64_t* channel_layout, i
*
* @param buf put here the string containing the channel layout
* @param buf_size size in bytes of the buffer
+ * @deprecated use av_channel_layout_describe()
*/
+attribute_deprecated
void av_get_channel_layout_string(char *buf, int buf_size, int nb_channels, uint64_t channel_layout);
-struct AVBPrint;
/**
* Append a description of a channel layout to a bprint buffer.
+ * @deprecated use av_channel_layout_describe()
*/
+attribute_deprecated
void av_bprint_channel_layout(struct AVBPrint *bp, int nb_channels, uint64_t channel_layout);
/**
* Return the number of channels in the channel layout.
+ * @deprecated use AVChannelLayout.nb_channels
*/
+attribute_deprecated
int av_get_channel_layout_nb_channels(uint64_t channel_layout);
/**
* Return default channel layout for a given number of channels.
+ *
+ * @deprecated use av_channel_layout_default()
*/
+attribute_deprecated
int64_t av_get_default_channel_layout(int nb_channels);
/**
@@ -194,20 +442,28 @@ int64_t av_get_default_channel_layout(int nb_channels);
*
* @return index of channel in channel_layout on success, a negative AVERROR
* on error.
+ *
+ * @deprecated use av_channel_layout_index_from_channel()
*/
+attribute_deprecated
int av_get_channel_layout_channel_index(uint64_t channel_layout,
uint64_t channel);
/**
* Get the channel with the given index in channel_layout.
+ * @deprecated use av_channel_layout_channel_from_index()
*/
+attribute_deprecated
uint64_t av_channel_layout_extract_channel(uint64_t channel_layout, int index);
/**
* Get the name of a given channel.
*
* @return channel name on success, NULL on error.
+ *
+ * @deprecated use av_channel_name()
*/
+attribute_deprecated
const char *av_get_channel_name(uint64_t channel);
/**
@@ -215,7 +471,9 @@ const char *av_get_channel_name(uint64_t channel);
*
* @param channel a channel layout with a single channel
* @return channel description on success, NULL on error
+ * @deprecated use av_channel_description()
*/
+attribute_deprecated
const char *av_get_channel_description(uint64_t channel);
/**
@@ -226,9 +484,238 @@ const char *av_get_channel_description(uint64_t channel);
* @param[out] name name of the layout
* @return 0 if the layout exists,
* <0 if index is beyond the limits
+ * @deprecated use av_channel_layout_standard()
*/
+attribute_deprecated
int av_get_standard_channel_layout(unsigned index, uint64_t *layout,
const char **name);
+#endif
+
+/**
+ * Get a human readable string in an abbreviated form describing a given channel,
+ * or "?" if not found.
+ * This is the inverse function of @ref av_channel_from_string().
+ *
+ * @param buf pre-allocated buffer where to put the generated string
+ * @param buf_size size in bytes of the buffer.
+ * @return amount of bytes needed to hold the output string, or a negative AVERROR
+ * on failure. If the returned value is bigger than buf_size, then the
+ * string was truncated.
+ */
+int av_channel_name(char *buf, size_t buf_size, enum AVChannel channel);
+
+/**
+ * bprint variant of av_channel_name().
+ *
+ * @note the string will be appended to the bprint buffer.
+ */
+void av_channel_name_bprint(struct AVBPrint *bp, enum AVChannel channel_id);
+
+/**
+ * Get a human readable string describing a given channel, or "?" if not found.
+ *
+ * @param buf pre-allocated buffer where to put the generated string
+ * @param buf_size size in bytes of the buffer.
+ * @return amount of bytes needed to hold the output string, or a negative AVERROR
+ * on failure. If the returned value is bigger than buf_size, then the
+ * string was truncated.
+ */
+int av_channel_description(char *buf, size_t buf_size, enum AVChannel channel);
+
+/**
+ * bprint variant of av_channel_description().
+ *
+ * @note the string will be appended to the bprint buffer.
+ */
+void av_channel_description_bprint(struct AVBPrint *bp, enum AVChannel channel_id);
+
+/**
+ * This is the inverse function of @ref av_channel_name().
+ *
+ * @return the channel with the given name
+ * AV_CHAN_NONE when name does not identify a known channel
+ */
+enum AVChannel av_channel_from_string(const char *name);
+
+/**
+ * Initialize a native channel layout from a bitmask indicating which channels
+ * are present.
+ *
+ * @param channel_layout the layout structure to be initialized
+ * @param mask bitmask describing the channel layout
+ *
+ * @return 0 on success
+ * AVERROR(EINVAL) for invalid mask values
+ */
+int av_channel_layout_from_mask(AVChannelLayout *channel_layout, uint64_t mask);
+
+/**
+ * Initialize a channel layout from a given string description.
+ * The input string can be represented by:
+ * - the formal channel layout name (returned by av_channel_layout_describe())
+ * - single or multiple channel names (returned by av_channel_name(), eg. "FL",
+ * or concatenated with "+", each optionally containing a custom name after
+ * a "@", eg. "FL@Left+FR@Right+LFE")
+ * - a decimal or hexadecimal value of a native channel layout (eg. "4" or "0x4")
+ * - the number of channels with default layout (eg. "4c")
+ * - the number of unordered channels (eg. "4C" or "4 channels")
+ *
+ * @param channel_layout input channel layout
+ * @param str string describing the channel layout
+ * @return 0 channel layout was detected, AVERROR_INVALIDATATA otherwise
+ */
+int av_channel_layout_from_string(AVChannelLayout *channel_layout,
+ const char *str);
+
+/**
+ * Get the default channel layout for a given number of channels.
+ *
+ * @param channel_layout the layout structure to be initialized
+ * @param nb_channels number of channels
+ */
+void av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels);
+
+/**
+ * Iterate over all standard channel layouts.
+ *
+ * @param opaque a pointer where libavutil will store the iteration state. Must
+ * point to NULL to start the iteration.
+ *
+ * @return the standard channel layout or NULL when the iteration is
+ * finished
+ */
+const AVChannelLayout *av_channel_layout_standard(void **opaque);
+
+/**
+ * Free any allocated data in the channel layout and reset the channel
+ * count to 0.
+ *
+ * @param channel_layout the layout structure to be uninitialized
+ */
+void av_channel_layout_uninit(AVChannelLayout *channel_layout);
+
+/**
+ * Make a copy of a channel layout. This differs from just assigning src to dst
+ * in that it allocates and copies the map for AV_CHANNEL_ORDER_CUSTOM.
+ *
+ * @note the destination channel_layout will be always uninitialized before copy.
+ *
+ * @param dst destination channel layout
+ * @param src source channel layout
+ * @return 0 on success, a negative AVERROR on error.
+ */
+int av_channel_layout_copy(AVChannelLayout *dst, const AVChannelLayout *src);
+
+/**
+ * Get a human-readable string describing the channel layout properties.
+ * The string will be in the same format that is accepted by
+ * @ref av_channel_layout_from_string().
+ *
+ * @param channel_layout channel layout to be described
+ * @param buf pre-allocated buffer where to put the generated string
+ * @param buf_size size in bytes of the buffer.
+ * @return amount of bytes needed to hold the output string, or a negative AVERROR
+ * on failure. If the returned value is bigger than buf_size, then the
+ * string was truncated.
+ */
+int av_channel_layout_describe(const AVChannelLayout *channel_layout,
+ char *buf, size_t buf_size);
+
+/**
+ * bprint variant of av_channel_layout_describe().
+ *
+ * @note the string will be appended to the bprint buffer.
+ * @return 0 on success, or a negative AVERROR value on failure.
+ */
+int av_channel_layout_describe_bprint(const AVChannelLayout *channel_layout,
+ struct AVBPrint *bp);
+
+/**
+ * Get the channel with the given index in a channel layout.
+ *
+ * @param channel_layout input channel layout
+ * @return channel with the index idx in channel_layout on success or
+ * AV_CHAN_NONE on failure (if idx is not valid or the channel order is
+ * unspecified)
+ */
+enum AVChannel
+av_channel_layout_channel_from_index(const AVChannelLayout *channel_layout, unsigned int idx);
+
+/**
+ * Get the index of a given channel in a channel layout. In case multiple
+ * channels are found, only the first match will be returned.
+ *
+ * @param channel_layout input channel layout
+ * @return index of channel in channel_layout on success or a negative number if
+ * channel is not present in channel_layout.
+ */
+int av_channel_layout_index_from_channel(const AVChannelLayout *channel_layout,
+ enum AVChannel channel);
+
+/**
+ * Get the index in a channel layout of a channel described by the given string.
+ * In case multiple channels are found, only the first match will be returned.
+ *
+ * This function accepts channel names in the same format as
+ * @ref av_channel_from_string().
+ *
+ * @param channel_layout input channel layout
+ * @return a channel index described by the given string, or a negative AVERROR
+ * value.
+ */
+int av_channel_layout_index_from_string(const AVChannelLayout *channel_layout,
+ const char *name);
+
+/**
+ * Get a channel described by the given string.
+ *
+ * This function accepts channel names in the same format as
+ * @ref av_channel_from_string().
+ *
+ * @param channel_layout input channel layout
+ * @return a channel described by the given string in channel_layout on success
+ * or AV_CHAN_NONE on failure (if the string is not valid or the channel
+ * order is unspecified)
+ */
+enum AVChannel
+av_channel_layout_channel_from_string(const AVChannelLayout *channel_layout,
+ const char *name);
+
+/**
+ * Find out what channels from a given set are present in a channel layout,
+ * without regard for their positions.
+ *
+ * @param channel_layout input channel layout
+ * @param mask a combination of AV_CH_* representing a set of channels
+ * @return a bitfield representing all the channels from mask that are present
+ * in channel_layout
+ */
+uint64_t av_channel_layout_subset(const AVChannelLayout *channel_layout,
+ uint64_t mask);
+
+/**
+ * Check whether a channel layout is valid, i.e. can possibly describe audio
+ * data.
+ *
+ * @param channel_layout input channel layout
+ * @return 1 if channel_layout is valid, 0 otherwise.
+ */
+int av_channel_layout_check(const AVChannelLayout *channel_layout);
+
+/**
+ * Check whether two channel layouts are semantically the same, i.e. the same
+ * channels are present on the same positions in both.
+ *
+ * If one of the channel layouts is AV_CHANNEL_ORDER_UNSPEC, while the other is
+ * not, they are considered to be unequal. If both are AV_CHANNEL_ORDER_UNSPEC,
+ * they are considered equal iff the channel counts are the same in both.
+ *
+ * @param chl input channel layout
+ * @param chl1 input channel layout
+ * @return 0 if chl and chl1 are equal, 1 if they are not equal. A negative
+ * AVERROR code if one or both are invalid.
+ */
+int av_channel_layout_compare(const AVChannelLayout *chl, const AVChannelLayout *chl1);
/**
* @}
diff --git a/libavutil/version.h b/libavutil/version.h
index 953aac9d94..4da667b923 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -110,6 +110,7 @@
#define FF_API_COLORSPACE_NAME (LIBAVUTIL_VERSION_MAJOR < 58)
#define FF_API_AV_MALLOCZ_ARRAY (LIBAVUTIL_VERSION_MAJOR < 58)
#define FF_API_FIFO_PEEK2 (LIBAVUTIL_VERSION_MAJOR < 58)
+#define FF_API_OLD_CHANNEL_LAYOUT (LIBAVUTIL_VERSION_MAJOR < 58)
/**
* @}
--
2.34.1
5
9
The oneAPI Video Processing Library (oneVPL) is a single interface for
encode, decode and video processing[1]. oneVPL is a successor to Intel(R) Media
SDK, but removed obsolete features. Intel(R) Media SDK lifetime comes to an
end now, new features for new Intel Gen platforms will be supported in oneVPL
only[2].
It is recommended to use oneVPL for new work, even for currently available
hardwares[3]. Hence, this patchset added a new option --enable-onevpl to bring
the support for oneVPL in QSV. New features for oneVPL will be implemented in
other patchset. --enble-libmfx option still works with Intel(R) Media SDK.
Note user can't enable onevpl and libmfx together.
oneVPL dispatcher source code:
https://github.com/oneapi-src/oneVPL
oneVPL GPU runtime for new Intel Gen platforms:
https://github.com/oneapi-src/oneVPL-intel-gpu
v6:
- Use ${libmfx_incdir} in configure
- Don't define mfx related function in an exported header
- Rebased this patchset against the latest master and fixed bugs
[1] https://spec.oneapi.io/versions/latest/elements/oneVPL/source/index.html
[2] https://github.com/Intel-Media-SDK/MediaSDK/#media-sdk-support-matrix
[3] https://software.intel.com/content/www/us/en/develop/articles/upgrading-fro…
Haihao Xiang (10):
configure: ensure --enable-libmfx uses libmfx 1.x
configure: fix the check for MFX_CODEC_VP9
qsv: remove mfx/ prefix from mfx headers
qsv: load user plugin for MFX_VERSION < 2.0
qsv: build audio related code when MFX_VERSION < 2.0
qsvenc: support multi-frame encode when MFX_VERSION < 2.0
qsvenc: support MFX_RATECONTROL_LA_EXT when MFX_VERSION < 2.0
qsv: support OPAQUE memory when MFX_VERSION < 2.0
qsv: use a new method to create mfx session when using oneVPL
configure: add --enable-libvpl option
configure | 29 ++-
libavcodec/qsv.c | 220 ++++++++++++++--
libavcodec/qsv.h | 4 +-
libavcodec/qsv_internal.h | 6 +-
libavcodec/qsvdec.c | 21 +-
libavcodec/qsvenc.c | 25 +-
libavcodec/qsvenc.h | 9 +-
libavcodec/qsvenc_h264.c | 3 +-
libavcodec/qsvenc_hevc.c | 3 +-
libavcodec/qsvenc_jpeg.c | 3 +-
libavcodec/qsvenc_mpeg2.c | 3 +-
libavcodec/qsvenc_vp9.c | 3 +-
libavfilter/qsvvpp.c | 145 ++++++++++-
libavfilter/qsvvpp.h | 12 +-
libavfilter/vf_deinterlace_qsv.c | 73 +++---
libavfilter/vf_scale_qsv.c | 88 ++++---
libavutil/hwcontext_d3d11va.c | 13 +
libavutil/hwcontext_d3d11va.h | 5 +
libavutil/hwcontext_dxva2.c | 8 +
libavutil/hwcontext_dxva2.h | 4 +
libavutil/hwcontext_opencl.c | 2 +-
libavutil/hwcontext_qsv.c | 423 +++++++++++++++++++++++++++----
libavutil/hwcontext_qsv.h | 3 +-
libavutil/hwcontext_vaapi.c | 13 +
libavutil/hwcontext_vaapi.h | 4 +
25 files changed, 934 insertions(+), 188 deletions(-)
--
2.17.1
4
17