diff --git a/include/meson.build b/include/meson.build index e9b434f4a632d7b234cccd86f815a63128230eb1..a534bcd119435fc58562019d935b2b060e89c5c5 100644 --- a/include/meson.build +++ b/include/meson.build @@ -31,6 +31,7 @@ install_headers( 'vlc_block_helper.h', 'vlc_boxes.h', 'vlc_charset.h', + 'vlc_chroma_probe.h', 'vlc_codec.h', 'vlc_codecs.h', 'vlc_common.h', diff --git a/include/vlc_chroma_probe.h b/include/vlc_chroma_probe.h new file mode 100644 index 0000000000000000000000000000000000000000..9f3a70733412dd380623d7361aa131c4eccd79c6 --- /dev/null +++ b/include/vlc_chroma_probe.h @@ -0,0 +1,259 @@ +/***************************************************************************** + * vlc_chroma_probe.h: chroma conversion probing + ***************************************************************************** + * Copyright (C) 2025 VLC authors and VideoLAN + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifndef VLC_CHROMA_PROBE_H +#define VLC_CHROMA_PROBE_H 1 + +#include <vlc_common.h> +#include <vlc_vector.h> + +/** + * \defgroup chroma_probe Chroma conversion probing + * \ingroup filter + * @{ + * \file + * Chroma conversion probing + * + * \defgroup chroma_probe_api Chroma probing API + * \ingroup chroma_probe + * + * @{ + */ + +#define VLC_CHROMA_CONV_MAX_INDIRECT_STEPS 1 +#define VLC_CHROMA_CONV_CHAIN_COUNT_MAX (2 /* in + out */ + VLC_CHROMA_CONV_MAX_INDIRECT_STEPS) + +/** + * Chroma conversion result structure + */ +struct vlc_chroma_conv_result +{ + /** + * Array of chromas used to achieve the conversion + * + * 'chain[0]' is always equals to the 'in' argument of the + * vlc_chroma_conv_Probe() function. + * + * if the out argument of the vlc_chroma_conv_Probe() is valid, + * chain[chain_count - 1] is equals to 'out' + */ + vlc_fourcc_t chain[VLC_CHROMA_CONV_CHAIN_COUNT_MAX]; + + /** Number of chromas in the chain */ + size_t chain_count; + + /** + * Cost of the full conversion, lower is better. + */ + unsigned cost; + + /** + * Quality of the conversion, higher is better. + * + * A quality of 100 means there are no quality loss: same color size and + * same vlc_chroma_subtype (or same YUV subsampling for video). + */ + unsigned quality; +}; + +/** Only accept YUV output chromas (the input chroma can be RGB) */ +#define VLC_CHROMA_CONV_FLAG_ONLY_YUV 0x1 +/** Only accept RGB output chromas (the input chroma can be YUV) */ +#define VLC_CHROMA_CONV_FLAG_ONLY_RGB 0x2 +/** Sort results by cost instead of quality */ +#define VLC_CHROMA_CONV_FLAG_SORT_COST 0x4 + +/** + * Probe possible chroma conversions + + * Results are sorted by quality, unless VLC_CHROMA_CONV_FLAG_SORT_COST is + * specified in flags. + + * @param in the input chroma to convert from, must be valid + * @param out the output chroma to convert to, if 0, the function will find all + * possible conversion from in to x + * @param width video width, used for finer cost calculation, can be 0 + * @param height video height, used for finer cost calculation, can be 0 + * @param max_indirect_steps maximum number of indirect conversion steps, must + * be lower or equal to @ref VLC_CHROMA_CONV_MAX_INDIRECT_STEPS, if in and out + * chromas are CPU chromas, the steps will be automatically lowered to 0 + * @param flags bitwise flags, cf. VLC_CHROMA_CONV_FLAG_* + * @param count pointer to the number of results, must be valid + * @return a pointer to an array of results, must be released with free(), can + * be NULL + */ +VLC_API struct vlc_chroma_conv_result * +vlc_chroma_conv_Probe(vlc_fourcc_t in, vlc_fourcc_t out, + unsigned width, unsigned height, + unsigned max_indirect_steps, int flags, size_t *count); + +/** + * Get a string representing the result + * + * @param res pointer to a valid result + * @return a string or NULL, must be released with free() + */ +VLC_API char * +vlc_chroma_conv_result_ToString(const struct vlc_chroma_conv_result *res); + +/** + * @} + * + * \defgroup chroma_probe_module Chroma probing module implementation + * \ingroup chroma_probe + * + * @{ + */ + +/** + * Chroma conversion entry structure + */ +struct vlc_chroma_conv_entry +{ + /** Cost factor, 0.25 for GPU<->GPU conversions, 0.75 for SIMD, 1 for CPU */ + float cost_factor; + /** input chroma */ + vlc_fourcc_t in; + /** output chroma */ + vlc_fourcc_t out; +}; +typedef struct VLC_VECTOR(struct vlc_chroma_conv_entry) vlc_chroma_conv_vec; + +/** + * Module probe function signature + * + * @param vec pointer to an allocated vector + * @return a VLC error code + */ +typedef void (*vlc_chroma_conv_probe)(vlc_chroma_conv_vec *vec); + +#define set_callback_chroma_conv_probe(activate) \ + { \ + vlc_chroma_conv_probe activate__ = activate; \ + (void) activate__; \ + set_callback(activate) \ + } \ + set_capability("chroma probe", 100) + +/** + * Helper that add a chroma conversion + * + * Must be called inside vlc_chroma_conv_probe() + * + * @param vec pointer to the vector of chromas + * @param cost_factor cf. vlc_chroma_conv_entry.cost_factor + * @param in cf. vlc_chroma_conv_entry.in + * @param out cf. vlc_chroma_conv_entry.out + * @param twoway if true, 'out' can also be converted to 'in' + */ +static inline void +vlc_chroma_conv_add(vlc_chroma_conv_vec *vec, float cost_factor, + vlc_fourcc_t in, vlc_fourcc_t out, bool twoway) +{ + { + const struct vlc_chroma_conv_entry entry = { + cost_factor, in, out + }; + vlc_vector_push(vec, entry); + } + + if (twoway) + { + const struct vlc_chroma_conv_entry entry = { + cost_factor, out, in + }; + vlc_vector_push(vec, entry); + } +} + +/** + * Helper that add an array of out chroma conversions + * + * Must be called inside vlc_chroma_conv_probe() + * + * @param vec pointer to the vector of chromas + * @param cost_factor cf. vlc_chroma_conv_entry.cost_factor + * @param in cf. vlc_chroma_conv_entry.in + * @param out_array a list of out chromas + * @param out_count number of elements in the out_array + */ +static inline void +vlc_chroma_conv_add_in_outarray(vlc_chroma_conv_vec *vec, float cost_factor, + vlc_fourcc_t in, + const vlc_fourcc_t *out_array, size_t out_count) +{ + for (size_t i = 0; i < out_count; i++) + { + const struct vlc_chroma_conv_entry entry = { + cost_factor, in, out_array[i], + }; + vlc_vector_push(vec, entry); + } +} + +/** + * Helper that add a list of out chroma conversions + */ +#define vlc_chroma_conv_add_in_outlist(vec, cost_factor, in, ...) do { \ + static const vlc_fourcc_t out_array[] = { __VA_ARGS__ }; \ + size_t count = ARRAY_SIZE(out_array); \ + vlc_chroma_conv_add_in_outarray(vec, cost_factor, in, out_array, count); \ +} while(0) + +/** + * Helper that add an array of in chroma conversions + * + * Must be called inside vlc_chroma_conv_probe() + * + * @param vec pointer to the vector of chromas + * @param cost_factor cf. vlc_chroma_conv_entry.cost_factor + * @param out cf. vlc_chroma_conv_entry.out + * @param in_array a list of out chromas + * @param in_count number of elements in the in_array + */ +static inline void +vlc_chroma_conv_add_out_inarray(vlc_chroma_conv_vec *vec, float cost_factor, + vlc_fourcc_t out, + const vlc_fourcc_t *in_array, size_t in_count) +{ + for (size_t i = 0; i < in_count; i++) + { + const struct vlc_chroma_conv_entry entry = { + cost_factor, in_array[i], out, + }; + vlc_vector_push(vec, entry); + } +} + +/** + * Helper that add a list of in chroma conversions + */ +#define vlc_chroma_conv_add_out_inlist(vec, cost_factor, out, ...) do { \ + static const vlc_fourcc_t in_array[] = { __VA_ARGS__ }; \ + size_t count = ARRAY_SIZE(in_array); \ + vlc_chroma_conv_add_out_inarray(vec, cost_factor, out, in_array, count); \ +} while(0) + +/** + * @} + * @} + */ + +#endif /* VLC_CHROMA_PROBE_H */ diff --git a/include/vlc_fourcc.h b/include/vlc_fourcc.h index 045e5e24c6ad7067b36f2262260b742b8e2dd322..e42c2c9233be0fcdcb2e2e42870aac1218758a5b 100644 --- a/include/vlc_fourcc.h +++ b/include/vlc_fourcc.h @@ -777,37 +777,50 @@ VLC_API const char * vlc_fourcc_GetDescription( int i_cat, vlc_fourcc_t i_fourcc * It returns a list (terminated with the value 0) of YUV fourccs in * decreasing priority order for the given chroma. * - * It will always return a non NULL pointer that must not be freed. + * It can return a NULL pointer, it must be freed. */ -VLC_API const vlc_fourcc_t * vlc_fourcc_GetYUVFallback( vlc_fourcc_t ); +VLC_API vlc_fourcc_t * vlc_fourcc_GetYUVFallback( vlc_fourcc_t ); /** * It returns a list (terminated with the value 0) of RGB fourccs in * decreasing priority order for the given chroma. * - * It will always return a non NULL pointer that must not be freed. + * It can return a NULL pointer, it must be freed. */ -VLC_API const vlc_fourcc_t * vlc_fourcc_GetRGBFallback( vlc_fourcc_t ); +VLC_API vlc_fourcc_t * vlc_fourcc_GetRGBFallback( vlc_fourcc_t ); /** * It returns a list (terminated with the value 0) of fourccs in decreasing * priority order for the given chroma. It will return either YUV or RGB * fallbacks depending on whether or not the fourcc given is YUV. * - * It will always return a non NULL pointer that must not be freed. + * It can return a NULL pointer, it must be freed. */ -VLC_API const vlc_fourcc_t * vlc_fourcc_GetFallback( vlc_fourcc_t ); +VLC_API vlc_fourcc_t * vlc_fourcc_GetFallback( vlc_fourcc_t ); /** - * It returns true if the given fourcc is YUV and false otherwise. + * Chroma subtype */ -VLC_API bool vlc_fourcc_IsYUV( vlc_fourcc_t ); +enum vlc_chroma_subtype +{ + VLC_CHROMA_SUBTYPE_OTHER, + VLC_CHROMA_SUBTYPE_YUV444, + VLC_CHROMA_SUBTYPE_YUV440, + VLC_CHROMA_SUBTYPE_YUV422, + VLC_CHROMA_SUBTYPE_YUV420, + VLC_CHROMA_SUBTYPE_YUV411, + VLC_CHROMA_SUBTYPE_YUV410, + VLC_CHROMA_SUBTYPE_YUV211, + VLC_CHROMA_SUBTYPE_RGB, + VLC_CHROMA_SUBTYPE_GREY, +}; /** * Chroma related information. */ typedef struct { vlc_fourcc_t fcc; + enum vlc_chroma_subtype subtype; unsigned plane_count; struct { vlc_rational_t w; @@ -815,6 +828,7 @@ typedef struct { } p[4]; unsigned pixel_size; /* Number of bytes per pixel for a plane */ unsigned pixel_bits; /* Number of bits actually used bits per pixel for a plane */ + float color_bits; /* Average number of bits used by one color */ } vlc_chroma_description_t; /** @@ -823,6 +837,36 @@ typedef struct { */ VLC_API const vlc_chroma_description_t * vlc_fourcc_GetChromaDescription( vlc_fourcc_t fourcc ) VLC_USED; +/** + * Returns true if the chroma description is YUV + */ +static inline bool +vlc_chroma_description_IsYUV(const vlc_chroma_description_t *desc) +{ + switch (desc->subtype) + { + case VLC_CHROMA_SUBTYPE_YUV444: + case VLC_CHROMA_SUBTYPE_YUV440: + case VLC_CHROMA_SUBTYPE_YUV422: + case VLC_CHROMA_SUBTYPE_YUV420: + case VLC_CHROMA_SUBTYPE_YUV410: + case VLC_CHROMA_SUBTYPE_YUV411: + case VLC_CHROMA_SUBTYPE_YUV211: + return true; + default: + return false; + } +} + +/** + * It returns true if the given fourcc is YUV and false otherwise. + */ +static inline bool vlc_fourcc_IsYUV(vlc_fourcc_t fcc) +{ + const vlc_chroma_description_t *desc = vlc_fourcc_GetChromaDescription(fcc); + return desc == NULL ? false : vlc_chroma_description_IsYUV(desc); +} + /** * Get the average usable bits per pixel for a chroma. * \note it may return 0 for opaque or compressed vlc_fourcc_t diff --git a/modules/codec/avcodec/chroma.c b/modules/codec/avcodec/chroma.c index cfd61a311dd91e55777dc4dff4f2c650e49226e8..520f36d8349d486be7443a9bc2fd894df8541dbb 100644 --- a/modules/codec/avcodec/chroma.c +++ b/modules/codec/avcodec/chroma.c @@ -38,13 +38,7 @@ /***************************************************************************** * Chroma fourcc -> libavutil pixfmt mapping *****************************************************************************/ -static const struct -{ - vlc_fourcc_t i_chroma; - enum AVPixelFormat i_chroma_id; - video_color_range_t range; - -} chroma_table[] = +static const struct vlc_chroma_ffmpeg chroma_table[] = { /* Planar YUV formats */ {VLC_CODEC_I444, AV_PIX_FMT_YUV444P, COLOR_RANGE_UNDEF }, @@ -208,6 +202,13 @@ static const struct {VLC_CODEC_XYZ_12B, AV_PIX_FMT_XYZ12BE, COLOR_RANGE_UNDEF }, }; + +const struct vlc_chroma_ffmpeg *GetVlcChromaFfmpegTable( size_t *count ) +{ + *count = ARRAY_SIZE(chroma_table); + return chroma_table; +} + int GetVlcChroma( video_format_t *fmt, enum AVPixelFormat i_ffmpeg_chroma ) { for( size_t i = 0; i < ARRAY_SIZE(chroma_table); i++ ) diff --git a/modules/codec/avcodec/chroma.h b/modules/codec/avcodec/chroma.h index 7edbaa5209e727ef386ff7ed47f0e2d4ca7159f7..4372d4a0aeb51fe4b1079447832b42bb1c5a034a 100644 --- a/modules/codec/avcodec/chroma.h +++ b/modules/codec/avcodec/chroma.h @@ -27,6 +27,15 @@ #include <libavutil/pixfmt.h> +struct vlc_chroma_ffmpeg +{ + vlc_fourcc_t i_chroma; + enum AVPixelFormat i_chroma_id; + video_color_range_t range; +}; + +const struct vlc_chroma_ffmpeg *GetVlcChromaFfmpegTable( size_t *count ); + enum AVPixelFormat FindFfmpegChroma( vlc_fourcc_t, bool *uv_flipped ); int GetVlcChroma( video_format_t *fmt, enum AVPixelFormat i_ffmpeg_chroma ); diff --git a/modules/hw/d3d11/d3d11_filters.c b/modules/hw/d3d11/d3d11_filters.c index 27a52cb35d8b245bac90eec05c662901ac9fe67a..905a6d4b20701e2985e653a4954ad7909833902f 100644 --- a/modules/hw/d3d11/d3d11_filters.c +++ b/modules/hw/d3d11/d3d11_filters.c @@ -34,6 +34,7 @@ #include <vlc_filter.h> #include <vlc_picture.h> #include <vlc_codec.h> +#include <vlc_chroma_probe.h> #define COBJMACROS #include <d3d11.h> @@ -543,6 +544,26 @@ error: return VLC_EGENERIC; } +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ +#define OUT_GPU_CHROMAS VLC_CODEC_D3D11_OPAQUE, VLC_CODEC_D3D11_OPAQUE_10B + + vlc_chroma_conv_add_in_outlist(vec, 1.1, VLC_CODEC_D3D11_OPAQUE, VLC_CODEC_I420, + VLC_CODEC_YV12, VLC_CODEC_NV12); + vlc_chroma_conv_add_in_outlist(vec, 1.1, VLC_CODEC_D3D11_OPAQUE_10B, + VLC_CODEC_I420_10L, VLC_CODEC_P010); + vlc_chroma_conv_add_in_outlist(vec, 1.1, VLC_CODEC_D3D11_OPAQUE_RGBA, + VLC_CODEC_RGBA); + vlc_chroma_conv_add_in_outlist(vec, 1.1, VLC_CODEC_D3D11_OPAQUE_BGRA, + VLC_CODEC_BGRA); + + vlc_chroma_conv_add_in_outlist(vec, 1.1, VLC_CODEC_I420, OUT_GPU_CHROMAS); + vlc_chroma_conv_add_in_outlist(vec, 1.1, VLC_CODEC_I420_10L, OUT_GPU_CHROMAS); + vlc_chroma_conv_add_in_outlist(vec, 1.1, VLC_CODEC_YV12, OUT_GPU_CHROMAS); + vlc_chroma_conv_add_in_outlist(vec, 1.1, VLC_CODEC_NV12, OUT_GPU_CHROMAS); + vlc_chroma_conv_add_in_outlist(vec, 1.1, VLC_CODEC_P010, OUT_GPU_CHROMAS); +} + vlc_module_begin() set_description(N_("Direct3D11 adjust filter")) set_subcategory( SUBCAT_VIDEO_VFILTER ) @@ -589,4 +610,6 @@ vlc_module_begin() set_callbacks( D3D11OpenBlockDecoder, D3D11CloseBlockDecoder ) set_capability( "video decoder", 90 ) + add_submodule() + set_callback_chroma_conv_probe(ProbeChroma) vlc_module_end() diff --git a/modules/hw/d3d9/d3d9_filters.c b/modules/hw/d3d9/d3d9_filters.c index f7ba764ca670c7852db4d7591e23d4a125eeb805..309001359d4e64e0b1fabb5091e8246bb9747b0b 100644 --- a/modules/hw/d3d9/d3d9_filters.c +++ b/modules/hw/d3d9/d3d9_filters.c @@ -34,6 +34,7 @@ #include <vlc_filter.h> #include <vlc_picture.h> #include <vlc_codec.h> +#include <vlc_chroma_probe.h> #define COBJMACROS #include <initguid.h> @@ -457,6 +458,20 @@ error: return VLC_EGENERIC; } +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ +#define OUT_GPU_CHROMAS VLC_CODEC_D3D9_OPAQUE, VLC_CODEC_D3D9_OPAQUE_10B + vlc_chroma_conv_add_in_outlist(vec, 1.1, VLC_CODEC_D3D9_OPAQUE, VLC_CODEC_I420, + VLC_CODEC_YV12, VLC_CODEC_NV12); + vlc_chroma_conv_add_in_outlist(vec, 1.1, VLC_CODEC_D3D9_OPAQUE_10B, + VLC_CODEC_I420_10L, VLC_CODEC_P010); + + vlc_chroma_conv_add_in_outlist(vec, 1.1, VLC_CODEC_I420, OUT_GPU_CHROMAS); + vlc_chroma_conv_add_in_outlist(vec, 1.1, VLC_CODEC_YV12, OUT_GPU_CHROMAS); + vlc_chroma_conv_add_in_outlist(vec, 1.1, VLC_CODEC_I420_10L, OUT_GPU_CHROMAS); + vlc_chroma_conv_add_in_outlist(vec, 1.1, VLC_CODEC_P010, OUT_GPU_CHROMAS); +} + vlc_module_begin() set_description(N_("Direct3D9 adjust filter")) set_subcategory(SUBCAT_VIDEO_VFILTER) @@ -493,4 +508,6 @@ vlc_module_begin() set_description(N_("Direct3D9")) set_callback_dec_device( D3D9OpenDecoderDevice, 10 ) add_shortcut ("dxva2") + add_submodule() + set_callback_chroma_conv_probe(ProbeChroma) vlc_module_end() diff --git a/modules/hw/mmal/converter.c b/modules/hw/mmal/converter.c index cbdc2b4b70cdafb8ebbae5cdc4f87da188c058f0..5dda06e4b6e1204c9bcd1aab7192afe7ca339b37 100644 --- a/modules/hw/mmal/converter.c +++ b/modules/hw/mmal/converter.c @@ -32,6 +32,7 @@ #include <vlc_codec.h> #include <vlc_filter.h> #include <vlc_plugin.h> +#include <vlc_chroma_probe.h> #include <interface/mmal/mmal.h> #include <interface/mmal/util/mmal_util.h> @@ -65,6 +66,20 @@ static const char * const ppsz_converter_text[] = { static int OpenConverter(filter_t *); +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ +#define OUT_CHROMAS \ + VLC_CODEC_BGRX, VLC_CODEC_RGBX, VLC_CODEC_XBGR, \ + VLC_CODEC_XRGB, VLC_CODEC_RGB565BE, VLC_CODEC_RGBA, \ + VLC_CODEC_BGRA, VLC_CODEC_ARGB, VLC_CODEC_ABGR + + vlc_chroma_conv_add_in_outlist(vec, 1, VLC_CODEC_I420_10L, OUT_CHROMAS); + vlc_chroma_conv_add_in_outlist(vec, 1, VLC_CODEC_I420, OUT_CHROMAS); + vlc_chroma_conv_add_in_outlist(vec, 1.1, VLC_CODEC_MMAL_OPAQUE, OUT_CHROMAS); + vlc_chroma_conv_add_in_outlist(vec, 1.1, VLC_CODEC_I420_10L, VLC_CODEC_MMAL_OPAQUE); + vlc_chroma_conv_add_in_outlist(vec, 1.1, VLC_CODEC_I420, VLC_CODEC_MMAL_OPAQUE); +} + vlc_module_begin() set_subcategory( SUBCAT_VIDEO_VFILTER ) set_shortname(N_("MMAL resizer")) @@ -75,6 +90,8 @@ vlc_module_begin() change_integer_list( pi_converter_modes, ppsz_converter_text ) #endif set_callback_video_converter(OpenConverter, 900) + add_submodule() + set_callback_chroma_conv_probe(ProbeChroma) vlc_module_end() #define MMAL_SLICE_HEIGHT 16 diff --git a/modules/hw/nvdec/chroma.c b/modules/hw/nvdec/chroma.c index 5739f5886b4b932f869de717a194e74dc6d8a3dc..d8bc4fac61c0407517900e815f92de3e970c8fd0 100644 --- a/modules/hw/nvdec/chroma.c +++ b/modules/hw/nvdec/chroma.c @@ -28,17 +28,34 @@ #include <vlc_plugin.h> #include <vlc_filter.h> #include <vlc_codec.h> +#include <vlc_chroma_probe.h> #include "nvdec_fmt.h" #include "nvdec_priv.h" static int OpenCUDAToCPU( filter_t * ); +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_NVDEC_OPAQUE, VLC_CODEC_NV12, + false); + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_NVDEC_OPAQUE_10B, VLC_CODEC_P010, + false); + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_NVDEC_OPAQUE_16B, VLC_CODEC_P016, + false); + vlc_chroma_conv_add_in_outlist(vec, 1.1, VLC_CODEC_NVDEC_OPAQUE_444, + VLC_CODEC_I444, VLC_CODEC_YUVA); + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_NVDEC_OPAQUE_444_16B, VLC_CODEC_I444_16L, + false); +} + vlc_module_begin() set_shortname(N_("CUDA converter")) set_description(N_("CUDA/NVDEC Chroma Converter filter")) set_subcategory(SUBCAT_VIDEO_VFILTER) set_callback_video_converter(OpenCUDAToCPU, 10) + add_submodule() + set_callback_chroma_conv_probe(ProbeChroma) vlc_module_end() #define CALL_CUDA(func, ...) CudaCheckErr(VLC_OBJECT(p_filter), devsys->cudaFunctions, devsys->cudaFunctions->func(__VA_ARGS__), #func) diff --git a/modules/hw/vaapi/filters.c b/modules/hw/vaapi/filters.c index a0b4fc3f833d7477782d3beb3625ca9d854e5e05..40369b8929c4091a1c8ec29a8840a70d930a98e4 100644 --- a/modules/hw/vaapi/filters.c +++ b/modules/hw/vaapi/filters.c @@ -30,6 +30,7 @@ #include <vlc_common.h> #include <vlc_filter.h> #include <vlc_plugin.h> +#include <vlc_chroma_probe.h> #include "filters.h" /******************************** @@ -1118,6 +1119,15 @@ error: * Module descriptor * *********************/ +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_VAAPI_420, VLC_CODEC_I420, true); + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_VAAPI_420_10BPP, VLC_CODEC_P010, true); + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_VAAPI_420_10BPP, VLC_CODEC_I420_10L, true); + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_VAAPI_420_12BPP, VLC_CODEC_P012, true); + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_VAAPI_420_12BPP, VLC_CODEC_I420_12L, true); +} + vlc_module_begin() set_shortname(N_("VAAPI filters")) set_description(N_("Video Accelerated API filters")) @@ -1144,4 +1154,7 @@ vlc_module_begin() add_submodule() set_callback_video_converter(vlc_vaapi_OpenChroma, 10) + + add_submodule() + set_callback_chroma_conv_probe(ProbeChroma) vlc_module_end() diff --git a/modules/hw/vdpau/chroma.c b/modules/hw/vdpau/chroma.c index b492be1ace8b5a637871adfa3a83e4c03f4acbc2..83fb18a01fe4878831edc1622a631abe42f23027 100644 --- a/modules/hw/vdpau/chroma.c +++ b/modules/hw/vdpau/chroma.c @@ -31,6 +31,7 @@ #include <vlc_filter.h> #include <vlc_picture.h> #include <vlc_picture_pool.h> +#include <vlc_chroma_probe.h> #include "vlc_vdpau.h" /* Picture history as recommended by VDPAU documentation */ @@ -787,6 +788,16 @@ static const char *const algo_names[] = { N_("Bob"), N_("Temporal"), N_("Temporal-spatial"), }; +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ + vlc_chroma_conv_add(vec, 0.25, VLC_CODEC_VDPAU_VIDEO, + VLC_CODEC_VDPAU_OUTPUT, false); + + vlc_chroma_conv_add_in_outlist(vec, 1.1, VLC_CODEC_VDPAU_VIDEO, VLC_CODEC_I420, + VLC_CODEC_YV12, VLC_CODEC_NV12, VLC_CODEC_I422, VLC_CODEC_NV16, + VLC_CODEC_YUYV, VLC_CODEC_UYVY, VLC_CODEC_I444, VLC_CODEC_NV24); +} + vlc_module_begin() set_shortname(N_("VDPAU")) set_description(N_("VDPAU surface conversions")) @@ -809,4 +820,6 @@ vlc_module_begin() add_submodule() set_callback_video_converter(YCbCrOpen, 10) + add_submodule() + set_callback_chroma_conv_probe(ProbeChroma) vlc_module_end() diff --git a/modules/isa/arm/neon/chroma_yuv.c b/modules/isa/arm/neon/chroma_yuv.c index 9b26fdfb6560ae3bbdea96972b6e9b53110c6493..b2e744b45e3867da4a17151cf8bb8d4641c46692 100644 --- a/modules/isa/arm/neon/chroma_yuv.c +++ b/modules/isa/arm/neon/chroma_yuv.c @@ -26,14 +26,35 @@ #include <vlc_plugin.h> #include <vlc_filter.h> #include <vlc_picture.h> +#include <vlc_chroma_probe.h> #include <vlc_cpu.h> #include "chroma_neon.h" static int Open (filter_t *); +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ +#define PACKED_CHROMAS VLC_CODEC_YUYV, VLC_CODEC_UYVY, VLC_CODEC_YVYU, VLC_CODEC_VYUY + + vlc_chroma_conv_add_in_outlist(vec, 0.75, VLC_CODEC_I420, PACKED_CHROMAS); + vlc_chroma_conv_add_in_outlist(vec, 0.75, VLC_CODEC_YV12, PACKED_CHROMAS); + vlc_chroma_conv_add_in_outlist(vec, 0.75, VLC_CODEC_I422, PACKED_CHROMAS); + + vlc_chroma_conv_add_in_outlist(vec, 0.75, VLC_CODEC_NV12, VLC_CODEC_I420, + VLC_CODEC_YV12); + vlc_chroma_conv_add_in_outlist(vec, 0.75, VLC_CODEC_NV21, VLC_CODEC_I420, + VLC_CODEC_YV12); + + vlc_chroma_conv_add(vec, 0.75, VLC_CODEC_NV24, VLC_CODEC_I444, false); + + vlc_chroma_conv_add_out_inlist(vec, 0.75, VLC_CODEC_I422, VLC_CODEC_NV16, + PACKED_CHROMAS); +} vlc_module_begin () set_description (N_("ARM NEON video chroma conversions")) set_callback_video_converter(Open, 250) + add_submodule() + set_callback_chroma_conv_probe(ProbeChroma) vlc_module_end () #define DEFINE_PACK(pack, pict) \ diff --git a/modules/isa/arm/neon/yuv_rgb.c b/modules/isa/arm/neon/yuv_rgb.c index 67a8e559685251eb7122e80814a29ea5b2d688f7..251c6e6760b173cff3175ed6a438b18795c13599 100644 --- a/modules/isa/arm/neon/yuv_rgb.c +++ b/modules/isa/arm/neon/yuv_rgb.c @@ -27,14 +27,26 @@ #include <vlc_plugin.h> #include <vlc_filter.h> #include <vlc_picture.h> +#include <vlc_chroma_probe.h> #include <vlc_cpu.h> #include "chroma_neon.h" static int Open (filter_t *); +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ + vlc_chroma_conv_add(vec, 0.75, VLC_CODEC_I420, VLC_CODEC_RGB565LE, false); + vlc_chroma_conv_add(vec, 0.75, VLC_CODEC_I420, VLC_CODEC_XBGR, false); + vlc_chroma_conv_add(vec, 0.75, VLC_CODEC_YV12, VLC_CODEC_XBGR, false); + vlc_chroma_conv_add(vec, 0.75, VLC_CODEC_NV21, VLC_CODEC_XBGR, false); + vlc_chroma_conv_add(vec, 0.75, VLC_CODEC_NV12, VLC_CODEC_XBGR, false); +} + vlc_module_begin () set_description (N_("ARM NEON video chroma YUV->RGBA")) set_callback_video_converter(Open, 250) + add_submodule() + set_callback_chroma_conv_probe(ProbeChroma) vlc_module_end () /* diff --git a/modules/video_chroma/chain.c b/modules/video_chroma/chain.c index 34957d9a8212deaad88b24e07c35fe8294bbadcc..43de130f571e97ba62dee1c1eb333ce9c7bd14d0 100644 --- a/modules/video_chroma/chain.c +++ b/modules/video_chroma/chain.c @@ -33,6 +33,7 @@ #include <vlc_filter.h> #include <vlc_mouse.h> #include <vlc_picture.h> +#include <vlc_chroma_probe.h> /***************************************************************************** * Module descriptor @@ -66,80 +67,6 @@ static void EsFormatMergeSize( es_format_t *p_dst, const es_format_t *p_base, const es_format_t *p_size ); -#define ALLOWED_CHROMAS_YUV10 \ - VLC_CODEC_I420_10L, \ - VLC_CODEC_I420_10B, \ - VLC_CODEC_I420_12B, \ - VLC_CODEC_I420_12L, \ - VLC_CODEC_I420_16L \ - -static const vlc_fourcc_t pi_allowed_chromas_yuv[] = { - VLC_CODEC_I420, - VLC_CODEC_I422, - ALLOWED_CHROMAS_YUV10, - VLC_CODEC_XRGB, - VLC_CODEC_BGRX, - VLC_CODEC_RGB24, - VLC_CODEC_BGR24, - VLC_CODEC_BGRA, - 0 -}; - -static const vlc_fourcc_t pi_allowed_chromas_yuv10[] = { - ALLOWED_CHROMAS_YUV10, - VLC_CODEC_I420, - VLC_CODEC_I422, - VLC_CODEC_XRGB, - VLC_CODEC_BGRX, - VLC_CODEC_RGB24, - VLC_CODEC_BGR24, - VLC_CODEC_BGRA, - 0 -}; - -static const vlc_fourcc_t pi_allowed_chromas_yuv444[] = { - VLC_CODEC_RGBA, - VLC_CODEC_BGRA, - VLC_CODEC_I422, - VLC_CODEC_I420, - 0 -}; - -static const vlc_fourcc_t pi_allowed_chromas_yuv444_10[] = { - VLC_CODEC_RGBA10LE, - VLC_CODEC_RGBA64, - ALLOWED_CHROMAS_YUV10, - VLC_CODEC_I422, - VLC_CODEC_I420, - 0 -}; - -static const vlc_fourcc_t *get_allowed_chromas( filter_t *p_filter ) -{ - switch (p_filter->fmt_out.video.i_chroma) - { - case VLC_CODEC_I420_10L: - case VLC_CODEC_I420_10B: - case VLC_CODEC_I420_12L: - case VLC_CODEC_I420_12B: - case VLC_CODEC_I420_16L: - case VLC_CODEC_CVPX_P010: - case VLC_CODEC_D3D9_OPAQUE_10B: - case VLC_CODEC_D3D11_OPAQUE_10B: - case VLC_CODEC_VAAPI_420_10BPP: - case VLC_CODEC_VAAPI_420_12BPP: - return pi_allowed_chromas_yuv10; - case VLC_CODEC_I444: - return pi_allowed_chromas_yuv444; - case VLC_CODEC_I444_10L: - case VLC_CODEC_I444_12L: - case VLC_CODEC_I444_16L: - return pi_allowed_chromas_yuv444_10; - default: - return pi_allowed_chromas_yuv; - } -} - typedef struct { filter_chain_t *p_chain; @@ -212,21 +139,7 @@ static int Activate( filter_t *p_filter, int (*pf_build)(filter_t *) ) return VLC_EGENERIC; } - int type = VLC_VAR_INTEGER; - if( var_Type( vlc_object_parent(p_filter), "chain-level" ) != 0 ) - type |= VLC_VAR_DOINHERIT; - - var_Create( p_filter, "chain-level", type ); - /* Note: atomicity is not actually needed here. */ - var_IncInteger( p_filter, "chain-level" ); - - int level = var_GetInteger( p_filter, "chain-level" ); - if( level < 0 || level > CHAIN_LEVEL_MAX ) - msg_Err( p_filter, "Too high level of recursion (%d)", level ); - else - i_ret = pf_build( p_filter ); - - var_Destroy( p_filter, "chain-level" ); + i_ret = pf_build( p_filter ); if( i_ret ) { @@ -263,9 +176,16 @@ static int ActivateConverter( filter_t *p_filter ) if( !b_chroma && !b_chroma_resize && !b_transform) return VLC_EGENERIC; - return Activate( p_filter, b_transform ? BuildTransformChain : - b_chroma_resize ? BuildChromaResize : - BuildChromaChain ); + if( var_Type( vlc_object_parent(p_filter), "chain-level" ) != 0 ) + return VLC_EGENERIC; + var_Create( p_filter, "chain-level", VLC_VAR_INTEGER ); + + int ret = Activate( p_filter, b_transform ? BuildTransformChain : + b_chroma_resize ? BuildChromaResize : + BuildChromaChain ); + + var_Destroy( p_filter, "chain-level" ); + return ret; } static int ActivateFilter( filter_t *p_filter ) @@ -273,14 +193,14 @@ static int ActivateFilter( filter_t *p_filter ) if( !p_filter->b_allow_fmt_out_change || p_filter->psz_name == NULL ) return VLC_EGENERIC; - if( var_Type( vlc_object_parent(p_filter), "chain-filter-level" ) != 0 ) + if( var_Type( vlc_object_parent(p_filter), "chain-level" ) != 0 ) return VLC_EGENERIC; + var_Create( p_filter, "chain-level", VLC_VAR_INTEGER ); - var_Create( p_filter, "chain-filter-level", VLC_VAR_INTEGER ); - int i_ret = Activate( p_filter, BuildFilterChain ); - var_Destroy( p_filter, "chain-filter-level" ); + int ret = Activate( p_filter, BuildFilterChain ); - return i_ret; + var_Destroy( p_filter, "chain-level" ); + return ret; } static void Destroy( filter_t *p_filter ) @@ -361,33 +281,66 @@ static int BuildChromaResize( filter_t *p_filter ) return VLC_EGENERIC; } -static int BuildChromaChain( filter_t *p_filter ) +static int AppendChromaChain( filter_t *p_filter, const vlc_fourcc_t *chromas, + size_t chroma_count ) { + filter_sys_t *p_sys = p_filter->p_sys; es_format_t fmt_mid; - int i_ret = VLC_EGENERIC; - /* Now try chroma format list */ - const vlc_fourcc_t *pi_allowed_chromas = get_allowed_chromas( p_filter ); - for( int i = 0; pi_allowed_chromas[i]; i++ ) + for( size_t i = 0; i < chroma_count; ++i ) { - const vlc_fourcc_t i_chroma = pi_allowed_chromas[i]; - if( i_chroma == p_filter->fmt_in.i_codec || - i_chroma == p_filter->fmt_out.i_codec ) - continue; - - msg_Dbg( p_filter, "Trying to use chroma %4.4s as middle man", - (char*)&i_chroma ); - es_format_Copy( &fmt_mid, &p_filter->fmt_in ); - fmt_mid.i_codec = - fmt_mid.video.i_chroma = i_chroma; + fmt_mid.i_codec = fmt_mid.video.i_chroma = chromas[i]; - i_ret = CreateChain( p_filter, &fmt_mid ); + int i_ret = filter_chain_AppendConverter( p_sys->p_chain, &fmt_mid ); es_format_Clean( &fmt_mid ); + if ( i_ret != VLC_SUCCESS ) + return i_ret; + } + + return VLC_SUCCESS; +} + +static int BuildChromaChain( filter_t *p_filter ) +{ + filter_sys_t *p_sys = p_filter->p_sys; + int i_ret = VLC_EGENERIC; + size_t res_count; + struct vlc_chroma_conv_result *results = + vlc_chroma_conv_Probe( p_filter->fmt_in.video.i_chroma, + p_filter->fmt_out.video.i_chroma, + p_filter->fmt_in.video.i_width, + p_filter->fmt_in.video.i_height, 1, + 0, &res_count ); + if( results == NULL ) + return i_ret; + + /* Now try chroma format list */ + for( size_t i = 0; i < res_count; ++i ) + { + const struct vlc_chroma_conv_result *res = &results[i]; + char *res_str = vlc_chroma_conv_result_ToString( res ); + if( res_str == NULL ) + { + i_ret = VLC_ENOMEM; + break; + } + msg_Info( p_filter, "Trying to use chroma_chain: %s...", res_str); + free(res_str); + + filter_chain_Reset( p_sys->p_chain, &p_filter->fmt_in, p_filter->vctx_in, + &p_filter->fmt_out ); + + i_ret = AppendChromaChain( p_filter, &res->chain[1], res->chain_count - 1); if( i_ret == VLC_SUCCESS ) + { + p_filter->vctx_out = filter_chain_GetVideoCtxOut( p_sys->p_chain ); + msg_Info( p_filter, "success"); break; + } } + free( results ); return i_ret; } @@ -399,54 +352,91 @@ static int ChainMouse( filter_t *p_filter, vlc_mouse_t *p_mouse, return filter_chain_MouseFilter( p_sys->p_chain, p_mouse, p_old ); } +static bool +CheckFilterChroma( filter_t *p_filter, vlc_fourcc_t chroma, const char *name ) +{ + filter_t *test = vlc_object_create( p_filter, sizeof(filter_t) ); + if (test == NULL) + return false; + + es_format_t fmt = p_filter->fmt_out; + fmt.i_codec = fmt.video.i_chroma = chroma; + test->fmt_in = fmt; + test->fmt_out = fmt; + + test->p_module = vlc_filter_LoadModule( test, "video filter", name, true ); + bool success = test->p_module != NULL; + vlc_filter_Delete( test ); + return success; +} + static int BuildFilterChain( filter_t *p_filter ) { - es_format_t fmt_mid; - es_format_Init(&fmt_mid, p_filter->fmt_in.i_cat, p_filter->fmt_in.i_codec); + filter_sys_t *p_sys = p_filter->p_sys; int i_ret = VLC_EGENERIC; - filter_sys_t *p_sys = p_filter->p_sys; + assert( p_filter->b_allow_fmt_out_change ); - /* Now try chroma format list */ - const vlc_fourcc_t *pi_allowed_chromas = get_allowed_chromas( p_filter ); - for( int i = 0; pi_allowed_chromas[i]; i++ ) - { - filter_chain_Reset( p_sys->p_chain, &p_filter->fmt_in, p_filter->vctx_in, &p_filter->fmt_out ); + /* Search for in -> x conversion */ + size_t res_count; + struct vlc_chroma_conv_result *results = + vlc_chroma_conv_Probe( p_filter->fmt_in.video.i_chroma, 0, + p_filter->fmt_in.video.i_width, + p_filter->fmt_in.video.i_height, 1, + 0, &res_count ); + if( results == NULL ) + return i_ret; - const vlc_fourcc_t i_chroma = pi_allowed_chromas[i]; - if( i_chroma == p_filter->fmt_in.i_codec || - i_chroma == p_filter->fmt_out.i_codec ) + for( size_t i = 0; i < res_count; ++i ) + { + const struct vlc_chroma_conv_result *res = &results[i]; + assert(res->chain_count >= 2); + + /* Check first if the filter could accept the new output format. This + * might be faster to fail now than failing after creating the whole + * chroma chain */ + if( !CheckFilterChroma( p_filter, res->chain[res->chain_count - 1], + p_filter->psz_name ) ) continue; - msg_Dbg( p_filter, "Trying to use chroma %4.4s as middle man in chain (%p)", - (char*)&i_chroma, (void*)p_sys->p_chain ); + char *res_str = vlc_chroma_conv_result_ToString( res ); + if( res_str == NULL ) + { + i_ret = VLC_ENOMEM; + break; + } - es_format_Clean( &fmt_mid ); - es_format_Copy( &fmt_mid, &p_filter->fmt_in ); - fmt_mid.i_codec = - fmt_mid.video.i_chroma = i_chroma; + msg_Info( p_filter, "Trying to use chain: %s -> %s", + res_str, p_filter->psz_name ); - if( filter_chain_AppendConverter( p_sys->p_chain, - &fmt_mid ) != VLC_SUCCESS ) + free( res_str ); + + filter_chain_Reset( p_sys->p_chain, &p_filter->fmt_in, p_filter->vctx_in, + &p_filter->fmt_out ); + + i_ret = AppendChromaChain( p_filter, &res->chain[1], + res->chain_count - 1 ); + if( i_ret != VLC_SUCCESS ) continue; p_sys->p_video_filter = filter_chain_AppendFilter( p_sys->p_chain, p_filter->psz_name, p_filter->p_cfg, - &fmt_mid ); + filter_chain_GetFmtOut( p_sys->p_chain ) ); if( p_sys->p_video_filter == NULL) + { + i_ret = VLC_EGENERIC; continue; + } filter_AddProxyCallbacks( p_filter, p_sys->p_video_filter, RestartFilterCallback ); - i_ret = VLC_SUCCESS; p_filter->vctx_out = filter_chain_GetVideoCtxOut( p_sys->p_chain ); break; } - - es_format_Clean( &fmt_mid ); + free( results ); if( i_ret != VLC_SUCCESS ) filter_chain_Reset( p_sys->p_chain, &p_filter->fmt_in, p_filter->vctx_in, &p_filter->fmt_out ); diff --git a/modules/video_chroma/copy.h b/modules/video_chroma/copy.h index 7158a703e73dec16669acafb2e465e81e53980af..08136f27d4f016960ab455065c4d6ae02ca38ff1 100644 --- a/modules/video_chroma/copy.h +++ b/modules/video_chroma/copy.h @@ -29,6 +29,13 @@ extern "C" { #endif +#ifdef CAN_COMPILE_SSE2 +#define COPY_COST 0.75 +#else +#define COPY_COST 1 +#endif + + typedef struct { # ifdef CAN_COMPILE_SSE2 uint8_t *buffer; diff --git a/modules/video_chroma/cvpx.c b/modules/video_chroma/cvpx.c index 9ecf5b050734807529373fd17b31e7557981a684..1d16158f5a04c314fe2d8049c5d17f3269955bd8 100644 --- a/modules/video_chroma/cvpx.c +++ b/modules/video_chroma/cvpx.c @@ -33,6 +33,7 @@ #include <vlc_plugin.h> #include <vlc_filter.h> #include <vlc_picture.h> +#include <vlc_chroma_probe.h> #include <vlc_modules.h> #include "../codec/vt_utils.h" #include "../video_chroma/copy.h" @@ -64,6 +65,31 @@ typedef struct }; } filter_sys_t; +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ + vlc_chroma_conv_add(vec, 0.25, VLC_CODEC_CVPX_BGRA, VLC_CODEC_CVPX_I420, true); + vlc_chroma_conv_add(vec, 0.25, VLC_CODEC_CVPX_BGRA, VLC_CODEC_CVPX_NV12, true); + vlc_chroma_conv_add(vec, 0.25, VLC_CODEC_CVPX_BGRA, VLC_CODEC_CVPX_P010, true); + vlc_chroma_conv_add(vec, 0.25, VLC_CODEC_CVPX_BGRA, VLC_CODEC_CVPX_UYVY, true); + + vlc_chroma_conv_add(vec, 0.25, VLC_CODEC_CVPX_I420, VLC_CODEC_CVPX_NV12, true); + vlc_chroma_conv_add(vec, 0.25, VLC_CODEC_CVPX_I420, VLC_CODEC_CVPX_P010, true); + vlc_chroma_conv_add(vec, 0.25, VLC_CODEC_CVPX_I420, VLC_CODEC_CVPX_UYVY, true); + + vlc_chroma_conv_add(vec, 0.25, VLC_CODEC_CVPX_NV12, VLC_CODEC_CVPX_P010, true); + vlc_chroma_conv_add(vec, 0.25, VLC_CODEC_CVPX_NV12, VLC_CODEC_CVPX_UYVY, true); + + vlc_chroma_conv_add(vec, 0.25, VLC_CODEC_CVPX_P010, VLC_CODEC_CVPX_UYVY, true); + + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_CVPX_NV12, VLC_CODEC_NV12, true); + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_CVPX_NV12, VLC_CODEC_I420, true); + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_CVPX_P010, VLC_CODEC_P010, true); + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_CVPX_P010, VLC_CODEC_I420_10L, true); + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_CVPX_UYVY, VLC_CODEC_UYVY, true); + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_CVPX_I420, VLC_CODEC_I420, true); + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_CVPX_BGRA, VLC_CODEC_BGRA, true); +} + vlc_module_begin () set_description("Conversions from/to CoreVideo buffers") set_callback_video_converter(Open, 10) @@ -76,6 +102,8 @@ vlc_module_begin () set_description("Fast CoreVideo resize+conversion") set_callback_video_converter(Open_chain_CVPX, 11) #endif + add_submodule() + set_callback_chroma_conv_probe(ProbeChroma) vlc_module_end () diff --git a/modules/video_chroma/grey_yuv.c b/modules/video_chroma/grey_yuv.c index 1339362ae89e94e18981cef6a3e5bbcdc56e72f5..907d53023eb1f5b9331ff7a0300f2ee01eaadbf4 100644 --- a/modules/video_chroma/grey_yuv.c +++ b/modules/video_chroma/grey_yuv.c @@ -32,6 +32,7 @@ #include <vlc_plugin.h> #include <vlc_filter.h> #include <vlc_picture.h> +#include <vlc_chroma_probe.h> #define SRC_FOURCC "GREY" #define DEST_FOURCC "I420,YUY2" @@ -44,9 +45,17 @@ static int Activate ( filter_t * ); /***************************************************************************** * Module descriptor. *****************************************************************************/ +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ + vlc_chroma_conv_add_in_outlist(vec, 1, VLC_CODEC_GREY, VLC_CODEC_I420, + VLC_CODEC_YUYV); +} + vlc_module_begin () set_description( N_("Conversions from " SRC_FOURCC " to " DEST_FOURCC) ) set_callback_video_converter( Activate, 80 ) + add_submodule() + set_callback_chroma_conv_probe(ProbeChroma) vlc_module_end () VIDEO_FILTER_WRAPPER( GREY_I420 ) diff --git a/modules/video_chroma/gst_mem.c b/modules/video_chroma/gst_mem.c index 775ad7307faa63c51169abe4bd73913dcf0cb1fc..e1c13654b6e50ba269b730da7f28fee9d0ca809e 100644 --- a/modules/video_chroma/gst_mem.c +++ b/modules/video_chroma/gst_mem.c @@ -32,6 +32,7 @@ #include <vlc_plugin.h> #include <vlc_filter.h> #include <vlc_picture.h> +#include <vlc_chroma_probe.h> #include "../codec/gstreamer/gstcopypicture.h" #include "../codec/gstreamer/gst_mem.h" @@ -110,9 +111,16 @@ static int Open(filter_t *p_filter) return VLC_SUCCESS; } +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_GST_MEM_OPAQUE, VLC_CODEC_NV12, false); +} + vlc_module_begin() set_shortname(N_("GST_MEM converter")) set_description(N_("GST_MEM Chroma Converter filter")) set_subcategory(SUBCAT_VIDEO_VFILTER) set_callback_video_converter(Open, 10) + add_submodule() + set_callback_chroma_conv_probe(ProbeChroma) vlc_module_end() diff --git a/modules/video_chroma/i420_nv12.c b/modules/video_chroma/i420_nv12.c index 1f0758c548050cc2691c908984577d9634a80e73..b89231492bddd69758937e605f494640c52d94de 100644 --- a/modules/video_chroma/i420_nv12.c +++ b/modules/video_chroma/i420_nv12.c @@ -32,6 +32,7 @@ #include <vlc_plugin.h> #include <vlc_filter.h> #include <vlc_picture.h> +#include <vlc_chroma_probe.h> #include "copy.h" typedef struct @@ -227,7 +228,16 @@ static int Create( filter_t *p_filter ) /***************************************************************************** * Module descriptor *****************************************************************************/ +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ + vlc_chroma_conv_add(vec, COPY_COST, VLC_CODEC_I420, VLC_CODEC_NV12, true); + vlc_chroma_conv_add(vec, COPY_COST, VLC_CODEC_YV12, VLC_CODEC_NV12, true); + vlc_chroma_conv_add(vec, COPY_COST, VLC_CODEC_I420_10L, VLC_CODEC_P010, true); +} + vlc_module_begin () set_description( N_("YUV planar to semiplanar conversions") ) set_callback_video_converter( Create, 160 ) + add_submodule() + set_callback_chroma_conv_probe(ProbeChroma) vlc_module_end () diff --git a/modules/video_chroma/i420_rgb.c b/modules/video_chroma/i420_rgb.c index 3c7e617712865fbe2471cc1a61df6e503563bbab..aba01915763daabb3c2b661e5e2add207e516591 100644 --- a/modules/video_chroma/i420_rgb.c +++ b/modules/video_chroma/i420_rgb.c @@ -34,6 +34,7 @@ #include <vlc_filter.h> #include <vlc_picture.h> #include <vlc_cpu.h> +#include <vlc_chroma_probe.h> #include "i420_rgb.h" #include "../video_filter/filter_picture.h" @@ -58,6 +59,28 @@ static void Set8bppPalette( filter_t *, uint8_t * ); static int Activate ( filter_t * ); static void Deactivate ( filter_t * ); +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ +#define OUT_CHROMAS_COMMON VLC_CODEC_RGB565, VLC_CODEC_RGB555, VLC_CODEC_XRGB, \ + VLC_CODEC_RGBX, VLC_CODEC_BGRX, VLC_CODEC_XBGR + +#ifndef PLUGIN_PLAIN +#define OUT_CHROMAS OUT_CHROMAS_COMMON +#else +#define OUT_CHROMAS OUT_CHROMAS_COMMON, VLC_CODEC_RGB233, VLC_CODEC_RGB332, \ + VLC_CODEC_BGR233, VLC_CODEC_BGR565, VLC_CODEC_BGR555 +#endif + +#if defined (PLUGIN_SSE2) +#define COST 0.75 +#else +#define COST 1 +#endif + + vlc_chroma_conv_add_in_outlist(vec, COST, VLC_CODEC_YV12, OUT_CHROMAS); + vlc_chroma_conv_add_in_outlist(vec, COST, VLC_CODEC_I420, OUT_CHROMAS); +} + vlc_module_begin () #if defined (PLUGIN_SSE2) set_description( N_( "SSE2 I420,IYUV,YV12 to " @@ -70,6 +93,8 @@ vlc_module_begin () set_callback_video_converter( Activate, 80 ) # define vlc_CPU_capable() (true) #endif + add_submodule() + set_callback_chroma_conv_probe(ProbeChroma) vlc_module_end () #ifndef PLUGIN_PLAIN diff --git a/modules/video_chroma/i420_yuy2.c b/modules/video_chroma/i420_yuy2.c index 982043238496cc6a57797c525e3aa6b716efef0c..8af14a3ef0568676a458003bea1a57f9d9f3a65e 100644 --- a/modules/video_chroma/i420_yuy2.c +++ b/modules/video_chroma/i420_yuy2.c @@ -33,6 +33,7 @@ #include <vlc_plugin.h> #include <vlc_filter.h> #include <vlc_picture.h> +#include <vlc_chroma_probe.h> #include <vlc_cpu.h> #if defined (PLUGIN_ALTIVEC) && defined(HAVE_ALTIVEC_H) @@ -46,13 +47,16 @@ #if defined (PLUGIN_SSE2) # define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422" # define VLC_TARGET VLC_SSE +# define COST 0.75 #elif defined (PLUGIN_ALTIVEC) # define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422" # define VLC_TARGET VLC_ALTIVEC +# define COST 0.75 #else # define PLUGIN_PLAIN # define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,Y211" # define VLC_TARGET +# define COST 1 #endif /***************************************************************************** @@ -63,6 +67,15 @@ static int Activate ( filter_t * ); /***************************************************************************** * Module descriptor. *****************************************************************************/ +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ + vlc_chroma_conv_add_in_outlist(vec, COST, VLC_CODEC_I420, VLC_CODEC_YUYV, + VLC_CODEC_YVYU, VLC_CODEC_UYVY); +#ifdef PLUGIN_PLAIN + vlc_chroma_conv_add(vec, COST, VLC_CODEC_I420, VLC_CODEC_Y211, false); +#endif +} + vlc_module_begin () #if defined (PLUGIN_PLAIN) set_description( N_("Conversions from " SRC_FOURCC " to " DEST_FOURCC) ) @@ -77,6 +90,8 @@ vlc_module_begin () set_callback_video_converter( Activate, 250 ) # define vlc_CPU_capable() vlc_CPU_ALTIVEC() #endif + add_submodule() + set_callback_chroma_conv_probe(ProbeChroma) vlc_module_end () VIDEO_FILTER_WRAPPER( I420_YUY2 ) diff --git a/modules/video_chroma/i422_i420.c b/modules/video_chroma/i422_i420.c index 8d09c5c5d8ece031bd6a3f7303dc7dff4ba69c5d..258e977c585e82b4a0296bc40e6b4e0c97f3fbdb 100644 --- a/modules/video_chroma/i422_i420.c +++ b/modules/video_chroma/i422_i420.c @@ -33,6 +33,7 @@ #include <vlc_plugin.h> #include <vlc_filter.h> #include <vlc_picture.h> +#include <vlc_chroma_probe.h> #define SRC_FOURCC "I422,J422" #define DEST_FOURCC "I420,IYUV,J420,YV12,YUVA" @@ -45,9 +46,17 @@ static int Activate ( filter_t * ); /***************************************************************************** * Module descriptor *****************************************************************************/ +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ + vlc_chroma_conv_add_in_outlist(vec, 1, VLC_CODEC_I422, VLC_CODEC_I420, + VLC_CODEC_YV12, VLC_CODEC_YUV420A); +} + vlc_module_begin () set_description( N_("Conversions from " SRC_FOURCC " to " DEST_FOURCC) ) set_callback_video_converter( Activate, 60 ) + add_submodule() + set_callback_chroma_conv_probe(ProbeChroma) vlc_module_end () VIDEO_FILTER_WRAPPER( I422_I420 ) diff --git a/modules/video_chroma/i422_yuy2.c b/modules/video_chroma/i422_yuy2.c index 8077897652221e9043e851220fbbb8496b7e0aff..a047bd2cf9dfb0a30000a4d588483d0785bb1c04 100644 --- a/modules/video_chroma/i422_yuy2.c +++ b/modules/video_chroma/i422_yuy2.c @@ -33,6 +33,7 @@ #include <vlc_plugin.h> #include <vlc_filter.h> #include <vlc_picture.h> +#include <vlc_chroma_probe.h> #include <vlc_cpu.h> #include "i422_yuy2.h" @@ -40,8 +41,10 @@ #define SRC_FOURCC "I422" #if !defined (PLUGIN_SSE2) # define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422,Y211" +# define COST 0.75 #else # define DEST_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422" +# define COST 1 #endif /***************************************************************************** @@ -52,6 +55,15 @@ static int Activate ( filter_t * ); /***************************************************************************** * Module descriptor *****************************************************************************/ +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ + vlc_chroma_conv_add_in_outlist(vec, COST, VLC_CODEC_I422, VLC_CODEC_YUYV, + VLC_CODEC_YVYU, VLC_CODEC_UYVY); +#ifdef PLUGIN_PLAIN + vlc_chroma_conv_add(vec, COST, VLC_CODEC_I422, VLC_CODEC_Y211, false); +#endif +} + vlc_module_begin () #if defined (PLUGIN_SSE2) set_description( N_("SSE2 conversions from " SRC_FOURCC " to " DEST_FOURCC) ) @@ -65,6 +77,8 @@ vlc_module_begin () # define vlc_CPU_capable() (true) # define VLC_TARGET #endif + add_submodule() + set_callback_chroma_conv_probe(ProbeChroma) vlc_module_end () diff --git a/modules/video_chroma/rv32.c b/modules/video_chroma/rv32.c index 5c8a8172f713b3cce742f902677762bb917735b3..9be8ab10e5e3b86d376d9b8613bd37cbd372e95e 100644 --- a/modules/video_chroma/rv32.c +++ b/modules/video_chroma/rv32.c @@ -31,6 +31,7 @@ #include <vlc_plugin.h> #include <vlc_filter.h> #include <vlc_picture.h> +#include <vlc_chroma_probe.h> /**************************************************************************** * Local prototypes @@ -41,9 +42,16 @@ static picture_t *Filter( filter_t *, picture_t * ); /***************************************************************************** * Module descriptor *****************************************************************************/ +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ + vlc_chroma_conv_add(vec, 1, VLC_CODEC_BGR24, VLC_CODEC_RGBA, false); +} + vlc_module_begin () set_description( N_("RV32 conversion filter") ) set_callback_video_converter( OpenFilter, 1 ) + add_submodule() + set_callback_chroma_conv_probe(ProbeChroma) vlc_module_end () static const struct vlc_filter_operations filter_ops = { diff --git a/modules/video_chroma/swscale.c b/modules/video_chroma/swscale.c index 17f66d5325dcf3e5e6c6cf09de801abb2d743573..8bbb0edafab59a9c407af605c26bfe51a4e84ac0 100644 --- a/modules/video_chroma/swscale.c +++ b/modules/video_chroma/swscale.c @@ -33,6 +33,7 @@ #include <vlc_plugin.h> #include <vlc_filter.h> #include <vlc_picture.h> +#include <vlc_chroma_probe.h> #include <vlc_cpu.h> #include <libswscale/swscale.h> @@ -60,6 +61,57 @@ static const char *const ppsz_mode_descriptions[] = N_("Area"), N_("Luma bicubic / chroma bilinear"), N_("Gauss"), N_("SincR"), N_("Lanczos"), N_("Bicubic spline") }; +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ +#define COST_FACTOR 1 + size_t count; + const struct vlc_chroma_ffmpeg *table = GetVlcChromaFfmpegTable(&count); + assert(table != NULL && count > 0); + + for (size_t i = 0; i < count; i++) + { + vlc_fourcc_t cur_chroma = table[i].i_chroma; + enum AVPixelFormat cur_avpf = table[i].i_chroma_id; + bool cur_supported_input = sws_isSupportedInput(cur_avpf); + bool cur_supported_output = sws_isSupportedOutput(cur_avpf); + + if (!cur_supported_input && !cur_supported_output) + continue; + + for (size_t j = i + 1; j < count; j++) + { + vlc_fourcc_t next_chroma = table[j].i_chroma; + + if (next_chroma == cur_chroma) + continue; + + enum AVPixelFormat next_avpf = table[j].i_chroma_id; + bool next_supported_input = sws_isSupportedInput(next_avpf); + bool next_supported_output = sws_isSupportedOutput(next_avpf); + + if (!next_supported_input && !next_supported_output) + continue; + + if (cur_supported_input && cur_supported_output + && next_supported_input && next_supported_output) + { + /* Likely case: add in <-> out two way conversion */ + vlc_chroma_conv_add(vec, COST_FACTOR, cur_chroma, next_chroma, + true); + } + else + { + if (cur_supported_input && next_supported_output) + vlc_chroma_conv_add(vec, COST_FACTOR, cur_chroma, next_chroma, + false); + else if (cur_supported_output && next_supported_input) + vlc_chroma_conv_add(vec, COST_FACTOR, next_chroma, cur_chroma, + false); + } + } + } +} + vlc_module_begin () set_description( N_("Video scaling filter") ) set_shortname( N_("Swscale" ) ) @@ -67,6 +119,8 @@ vlc_module_begin () set_callback_video_converter( OpenScaler, 150 ) add_integer( "swscale-mode", 2, SCALEMODE_TEXT, SCALEMODE_LONGTEXT ) change_integer_list( pi_mode_values, ppsz_mode_descriptions ) + add_submodule() + set_callback_chroma_conv_probe(ProbeChroma) vlc_module_end () /* Version checking */ diff --git a/modules/video_chroma/yuvp.c b/modules/video_chroma/yuvp.c index eedc932165e28651ede522505fec8ff14b1cba59..32fa798f6f924c4943b9765387485b2c92a49ae8 100644 --- a/modules/video_chroma/yuvp.c +++ b/modules/video_chroma/yuvp.c @@ -31,6 +31,7 @@ #include <vlc_plugin.h> #include <vlc_filter.h> #include <vlc_picture.h> +#include <vlc_chroma_probe.h> #include <assert.h> #include "../video_filter/filter_picture.h" @@ -43,9 +44,17 @@ *****************************************************************************/ static int Open ( filter_t * ); +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ + vlc_chroma_conv_add_in_outlist(vec, 1, VLC_CODEC_YUVP, VLC_CODEC_RGBA, + VLC_CODEC_ARGB, VLC_CODEC_BGRA, VLC_CODEC_ABGR, VLC_CODEC_YUVA); +} + vlc_module_begin () set_description( N_("YUVP converter") ) set_callback_video_converter( Open, 10 ) + add_submodule() + set_callback_chroma_conv_probe(ProbeChroma) vlc_module_end () /**************************************************************************** diff --git a/modules/video_chroma/yuy2_i420.c b/modules/video_chroma/yuy2_i420.c index 2ed4d660611dc933149d8ce9c988b7a59dc848f3..c69866ed7fc5d25f75e1bd9d6ca5c5ce2d7cbc42 100644 --- a/modules/video_chroma/yuy2_i420.c +++ b/modules/video_chroma/yuy2_i420.c @@ -32,6 +32,7 @@ #include <vlc_plugin.h> #include <vlc_filter.h> #include <vlc_picture.h> +#include <vlc_chroma_probe.h> #define SRC_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422" #define DEST_FOURCC "I420" @@ -44,9 +45,19 @@ static int Activate ( filter_t * ); /***************************************************************************** * Module descriptor *****************************************************************************/ + +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ + vlc_chroma_conv_add(vec, 1, VLC_CODEC_YUYV, VLC_CODEC_I420, false); + vlc_chroma_conv_add(vec, 1, VLC_CODEC_YVYU, VLC_CODEC_I420, false); + vlc_chroma_conv_add(vec, 1, VLC_CODEC_UYVY, VLC_CODEC_I420, false); +} + vlc_module_begin () set_description( N_("Conversions from " SRC_FOURCC " to " DEST_FOURCC) ) set_callback_video_converter( Activate, 80 ) + add_submodule() + set_callback_chroma_conv_probe(ProbeChroma) vlc_module_end () VIDEO_FILTER_WRAPPER( YUY2_I420 ) diff --git a/modules/video_chroma/yuy2_i422.c b/modules/video_chroma/yuy2_i422.c index 9b9b97bb16cc3b59bb29955c29a368205d644740..feb289187ffbd866b904d526e54e7dbbb3dc11a1 100644 --- a/modules/video_chroma/yuy2_i422.c +++ b/modules/video_chroma/yuy2_i422.c @@ -32,6 +32,7 @@ #include <vlc_plugin.h> #include <vlc_filter.h> #include <vlc_picture.h> +#include <vlc_chroma_probe.h> #define SRC_FOURCC "YUY2,YUNV,YVYU,UYVY,UYNV,Y422" #define DEST_FOURCC "I422" @@ -44,9 +45,19 @@ static int Activate ( filter_t * ); /***************************************************************************** * Module descriptor *****************************************************************************/ + +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ + vlc_chroma_conv_add(vec, 1, VLC_CODEC_YUYV, VLC_CODEC_I422, false); + vlc_chroma_conv_add(vec, 1, VLC_CODEC_YVYU, VLC_CODEC_I422, false); + vlc_chroma_conv_add(vec, 1, VLC_CODEC_UYVY, VLC_CODEC_I422, false); +} + vlc_module_begin () set_description( N_("Conversions from " SRC_FOURCC " to " DEST_FOURCC) ) set_callback_video_converter( Activate, 80 ) + add_submodule() + set_callback_chroma_conv_probe(ProbeChroma) vlc_module_end () VIDEO_FILTER_WRAPPER( YUY2_I422 ) diff --git a/modules/video_output/drm/planes.c b/modules/video_output/drm/planes.c index d96232a184bba9016b00e9cb1c14b6186acfffdd..1277d25fb30a4740a4e133fe7edde260d1656e1b 100644 --- a/modules/video_output/drm/planes.c +++ b/modules/video_output/drm/planes.c @@ -243,14 +243,16 @@ uint_fast32_t vlc_drm_find_best_format(int fd, uint_fast32_t plane_id, if (nfmt > plane.count_format_types) nfmt = plane.count_format_types; + vlc_fourcc_t *list = NULL; /* Look for an exact match first */ uint_fast32_t drm_fourcc = vlc_drm_find_format(chroma, nfmt, fmts); if (drm_fourcc != 0) goto out; /* Fallback to decreasingly optimal formats */ - const vlc_fourcc_t *list = vlc_fourcc_GetFallback(chroma); - assert(list != NULL); + list = vlc_fourcc_GetFallback(chroma); + if (list == NULL) + goto out; for (size_t i = 0; list[i] != 0; i++) { drm_fourcc = vlc_drm_find_format(list[i], nfmt, fmts); @@ -259,6 +261,7 @@ uint_fast32_t vlc_drm_find_best_format(int fd, uint_fast32_t plane_id, } errno = ENOTSUP; out: + free(list); free(fmts); return drm_fourcc; } diff --git a/modules/video_output/kva.c b/modules/video_output/kva.c index 532daf43360679411230de83ca1b1765bcb0e288..ca3ee4d11a7d55ddb801fbdd01eb57f5bb4445c1 100644 --- a/modules/video_output/kva.c +++ b/modules/video_output/kva.c @@ -446,7 +446,7 @@ static int Control( vout_display_t *vd, int query ) static int OpenDisplay( vout_display_t *vd, video_format_t *fmt ) { vout_display_sys_t * sys = vd->sys; - const vlc_fourcc_t *fallback; + vlc_fourcc_t *fallback; bool b_hw_accel = 0; FOURCC i_kva_fourcc; int i_chroma_shift = 0; @@ -458,6 +458,8 @@ static int OpenDisplay( vout_display_t *vd, video_format_t *fmt ) { fallback = ( pass == 0 ) ? vlc_fourcc_GetYUVFallback( fmt->i_chroma ) : vlc_fourcc_GetRGBFallback( fmt->i_chroma ); + if( fallback == NULL ) + continue; for( int i = 0; fallback[ i ]; i++ ) { @@ -512,6 +514,7 @@ static int OpenDisplay( vout_display_t *vd, video_format_t *fmt ) fmt->i_chroma = fallback[ i ]; break; } + free( fallback ); } } diff --git a/modules/video_output/libplacebo/display.c b/modules/video_output/libplacebo/display.c index fd84160a4a697633f0e11e8be1f896ef2fb85ddc..f2f12ed298869267024669d68bed1ee895a81043 100644 --- a/modules/video_output/libplacebo/display.c +++ b/modules/video_output/libplacebo/display.c @@ -136,12 +136,16 @@ static int Open(vout_display_t *vd, fmt->i_chroma = vd->source->i_chroma; } else { fmt->i_chroma = 0; - const vlc_fourcc_t *fcc; - for (fcc = vlc_fourcc_GetFallback(vd->source->i_chroma); *fcc; fcc++) { - if (vlc_placebo_FormatSupported(gpu, *fcc)) { - fmt->i_chroma = *fcc; - break; + vlc_fourcc_t *list = vlc_fourcc_GetFallback(vd->source->i_chroma); + if (list != NULL) + { + for (const vlc_fourcc_t *fcc = list; *fcc; fcc++) { + if (vlc_placebo_FormatSupported(gpu, *fcc)) { + fmt->i_chroma = *fcc; + break; + } } + free(list); } if (fmt->i_chroma == 0) { diff --git a/modules/video_output/opengl/interop_sw.c b/modules/video_output/opengl/interop_sw.c index e039e34861bcb34cda05ac1e41133a887f32f004..b6867b9a6a65e31173e42d0a804d48b6afe00335 100644 --- a/modules/video_output/opengl/interop_sw.c +++ b/modules/video_output/opengl/interop_sw.c @@ -792,7 +792,6 @@ opengl_interop_generic_init(struct vlc_gl_interop *interop, bool allow_dr) || vlc_gl_HasExtension(&extension_vt, "GL_EXT_texture_integer")); video_color_space_t space; - const vlc_fourcc_t *list; const bool is_yup = vlc_fourcc_IsYUV(interop->fmt_in.i_chroma); if (is_yup) @@ -802,19 +801,10 @@ opengl_interop_generic_init(struct vlc_gl_interop *interop, bool allow_dr) if (max_texture_units < 3) goto error; - list = vlc_fourcc_GetYUVFallback(interop->fmt_in.i_chroma); space = interop->fmt_in.space; } - else if (interop->fmt_in.i_chroma == VLC_CODEC_XYZ_12B) - { - list = NULL; - space = COLOR_SPACE_UNDEF; - } else - { - list = vlc_fourcc_GetRGBFallback(interop->fmt_in.i_chroma); space = COLOR_SPACE_UNDEF; - } /* The pictures are uploaded upside-down */ video_format_TransformBy(&interop->fmt_out, TRANSFORM_VFLIP); @@ -833,24 +823,30 @@ opengl_interop_generic_init(struct vlc_gl_interop *interop, bool allow_dr) goto interop_init; } + vlc_fourcc_t *list = NULL; + if (is_yup) + list = vlc_fourcc_GetYUVFallback(interop->fmt_in.i_chroma); + else if (interop->fmt_in.i_chroma != VLC_CODEC_XYZ_12B) + list = vlc_fourcc_GetRGBFallback(interop->fmt_in.i_chroma); + if (list == NULL) goto error; /* Check whether any fallback for the chroma is translatable to OpenGL. */ - while (*list) + for (const vlc_fourcc_t *fcc = list; *fcc; fcc++) { - ret = opengl_interop_init(interop, *list, space); + ret = opengl_interop_init(interop, *fcc, space); if (ret == VLC_SUCCESS) { - i_chroma = *list; + i_chroma = *fcc; msg_Warn(interop->gl, "direct rendering failed for %4.4s, " "fallback to %4.4s", (const char *)&interop->fmt_in.i_chroma, (const char *)&i_chroma); goto interop_init; } - list++; } + free(list); goto error; diff --git a/modules/video_output/win32/direct3d11.cpp b/modules/video_output/win32/direct3d11.cpp index 309ae47a42f7d2fec050e5c2922f80c7657401c0..336c3d4e88c1796cdbad14ef22b5a34729557ecc 100644 --- a/modules/video_output/win32/direct3d11.cpp +++ b/modules/video_output/win32/direct3d11.cpp @@ -1083,14 +1083,18 @@ static int Direct3D11Open(vout_display_t *vd, video_format_t *fmtp, vlc_video_co #endif ) { - const vlc_fourcc_t *list = vlc_fourcc_GetFallback(vd->source->i_chroma); - for (unsigned i = 0; list[i] != 0; i++) { - if (list[i] == vd->source->i_chroma) - continue; - fmt.i_chroma = list[i]; - err = SetupOutputFormat(vd, &fmt, nullptr, &sys->picQuad.quad_fmt); - if (err == VLC_SUCCESS) - break; + vlc_fourcc_t *list = vlc_fourcc_GetFallback(vd->source->i_chroma); + if (list != NULL) + { + for (unsigned i = 0; list[i] != 0; i++) { + if (list[i] == vd->source->i_chroma) + continue; + fmt.i_chroma = list[i]; + err = SetupOutputFormat(vd, &fmt, nullptr, &sys->picQuad.quad_fmt); + if (err == VLC_SUCCESS) + break; + } + free(list); } } if (err != VLC_SUCCESS) diff --git a/modules/video_output/win32/direct3d9.c b/modules/video_output/win32/direct3d9.c index 597030691758b3b6c4c0cebc868ea39d2bc2bda9..ac49bdaf1d90efbbcad0addde169fd45a6f112ba 100644 --- a/modules/video_output/win32/direct3d9.c +++ b/modules/video_output/win32/direct3d9.c @@ -1351,7 +1351,8 @@ static const d3d9_format_t *Direct3DFindFormat(vout_display_t *vd, const video_f msg_Warn( vd, "Disabling hardware chroma conversion due to odd dimensions" ); for (unsigned pass = 0; pass < 2; pass++) { - const vlc_fourcc_t *list; + const vlc_fourcc_t *list = NULL; + vlc_fourcc_t *fallback_list = NULL; const vlc_fourcc_t dxva_chroma[] = {fmt->i_chroma, 0}; D3DFORMAT decoder_format = D3DFMT_UNKNOWN; @@ -1364,10 +1365,11 @@ static const d3d9_format_t *Direct3DFindFormat(vout_display_t *vd, const video_f msg_Dbg(vd, "favor decoder format: %4.4s (%d)", (const char*)&decoder_format, decoder_format); } else if (pass == 0 && hardware_scale_ok && sys->allow_hw_yuv && vlc_fourcc_IsYUV(fmt->i_chroma)) - list = vlc_fourcc_GetYUVFallback(fmt->i_chroma); + list = fallback_list = vlc_fourcc_GetYUVFallback(fmt->i_chroma); else if (pass == 1) - list = vlc_fourcc_GetRGBFallback(fmt->i_chroma); - else + list = fallback_list = vlc_fourcc_GetRGBFallback(fmt->i_chroma); + + if (list == NULL) continue; for (unsigned i = 0; list[i] != 0; i++) { @@ -1381,9 +1383,13 @@ static const d3d9_format_t *Direct3DFindFormat(vout_display_t *vd, const video_f msg_Dbg(vd, "trying surface pixel format: %s", format->name); if (!Direct3D9CheckConversion(vd, format->format)) + { + free(fallback_list); return format; + } } } + free(fallback_list); } return NULL; } diff --git a/src/Makefile.am b/src/Makefile.am index c2742fddca3b64011f37ca7c92bb99edfda7d644..e9721d7404b84903e8978f48c862a7aa1942495f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -43,6 +43,7 @@ pluginsinclude_HEADERS.h = \ ../include/vlc_configuration.h \ ../include/vlc_cpu.h \ ../include/vlc_clock.h \ + ../include/vlc_chroma_probe.h \ ../include/vlc_decoder.h \ ../include/vlc_demux.h \ ../include/vlc_dialog.h \ @@ -380,6 +381,7 @@ libvlccore_la_SOURCES = \ misc/actions.c \ misc/ancillary.h \ misc/ancillary.c \ + misc/chroma_probe.c \ misc/executor.c \ misc/md5.c \ misc/probe.c \ diff --git a/src/libvlccore.sym b/src/libvlccore.sym index ff8bb77ffcb7a4fb48c48ae051a8d24ac3ed215b..b8c9c3cca7a0accd3eaadc1de2d7ef9d9ea5c057 100644 --- a/src/libvlccore.sym +++ b/src/libvlccore.sym @@ -58,6 +58,8 @@ vlc_frame_shm_Alloc vlc_frame_Realloc vlc_frame_Release vlc_frame_TryRealloc +vlc_chroma_conv_Probe +vlc_chroma_conv_result_ToString config_AddIntf config_ChainCreate config_ChainDestroy @@ -590,7 +592,6 @@ vlc_fourcc_GetCodecAudio vlc_fourcc_GetCodecFromString vlc_fourcc_GetDescription vlc_fourcc_GetChromaDescription -vlc_fourcc_IsYUV vlc_fourcc_GetRGBFallback vlc_fourcc_GetYUVFallback vlc_fourcc_GetFallback diff --git a/src/meson.build b/src/meson.build index 8e420f121956c0889d59e27aa9b7730d87e45027..18f680b7ef6998a2705f0f96573cd88584c559ca 100644 --- a/src/meson.build +++ b/src/meson.build @@ -231,6 +231,7 @@ libvlccore_sources_base = files( 'text/iso-639_def.h', 'misc/actions.c', 'misc/ancillary.c', + 'misc/chroma_probe.c', 'misc/executor.c', 'misc/md5.c', 'misc/probe.c', diff --git a/src/misc/chroma_probe.c b/src/misc/chroma_probe.c new file mode 100644 index 0000000000000000000000000000000000000000..fff486c3d81e4cb38ea554386acc81468a3b52ad --- /dev/null +++ b/src/misc/chroma_probe.c @@ -0,0 +1,475 @@ +/***************************************************************************** + * chroma_probe.c: chroma conversion probing + ***************************************************************************** + * Copyright (C) 2025 VLC authors and VideoLAN + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <vlc_chroma_probe.h> +#include <vlc_fourcc.h> +#include <vlc_threads.h> +#include <vlc_modules.h> +#include <vlc_sort.h> +#include <vlc_memstream.h> + +static int +modules_Probe(vlc_chroma_conv_vec *chroma_table) +{ + module_t **mods; + ssize_t total = vlc_module_match("chroma probe", NULL, false, &mods, NULL); + if (total == -1) + return -ENOENT; + + for (ssize_t i = 0; i < total; ++i) + { + vlc_chroma_conv_probe fn = vlc_module_map(NULL, mods[i]); + if (fn == NULL) + continue; + fn(chroma_table); + } + free(mods); + return 0; +} + +/* Breadth First Search (BFS) node */ +struct bfs_node +{ + vlc_fourcc_t chain[VLC_CHROMA_CONV_CHAIN_COUNT_MAX]; + unsigned depth; /* Max deep is VLC_CHROMA_CONV_CHAIN_COUNT_MAX -1 */ + float cost_factor; +}; +typedef struct VLC_VECTOR(struct bfs_node) bfs_queue_vec; + +static int +bfs_Run(vlc_fourcc_t chroma_from, vlc_fourcc_t chroma_to, unsigned max_depth, + const vlc_chroma_conv_vec *chroma_table, int flags, + bfs_queue_vec *queue) +{ + struct bfs_node start = { + .chain[0] = chroma_from, + .cost_factor = 1, + .depth = 0, + }; + bool success = vlc_vector_push(queue, start); + if (!success) + return -ENOMEM; + + for (size_t queue_idx = 0; queue_idx < queue->size; queue_idx++) + { + const struct bfs_node current = queue->data[queue_idx]; + vlc_fourcc_t current_chroma = current.chain[current.depth]; + + if (chroma_to != 0 && current_chroma == chroma_to) + continue; /* Found a path to 'chroma_to' */ + + if (current.depth == max_depth) + continue; + + /* Enqueue neighbors */ + for (size_t chroma_idx = 0; chroma_idx < chroma_table->size; chroma_idx++) + { + struct vlc_chroma_conv_entry *entry = &chroma_table->data[chroma_idx]; + vlc_fourcc_t from = entry->in; + vlc_fourcc_t to = entry->out; + float cost_factor = entry->cost_factor; + + if (from == current_chroma) + { + vlc_fourcc_t next_chroma = to; + + /* Apply filters from flags */ + if (flags & VLC_CHROMA_CONV_FLAG_ONLY_YUV) + { + if (!vlc_fourcc_IsYUV(next_chroma)) + continue; + } + else if (flags & VLC_CHROMA_CONV_FLAG_ONLY_RGB) + { + const vlc_chroma_description_t *desc = + vlc_fourcc_GetChromaDescription(next_chroma); + if (desc == NULL || desc->subtype != VLC_CHROMA_SUBTYPE_RGB) + continue; + } + + /* If next_chroma is already in the chain at any previous step, + * we've encountered a cycle or a duplicate. */ + bool already_visited = false; + for (size_t i = 0; i < current.depth; ++i) + if (current.chain[i] == next_chroma) + { + already_visited = true; + break; + } + if (already_visited) + continue; + + struct bfs_node next = current; + next.depth = current.depth + 1; + next.cost_factor = current.cost_factor * cost_factor; + + next.chain[next.depth] = next_chroma; + success = vlc_vector_push(queue, next); + if (!success) + return -ENOMEM; + } + } + } + return 0; +} + +static uint64_t +GetChromaBits(const vlc_chroma_description_t *desc, + unsigned width, unsigned height) +{ + if (desc->plane_count == 0) + { + /* Fallback to the size of the subtype */ + switch (desc->subtype) + { + case VLC_CHROMA_SUBTYPE_OTHER: + return 0; + case VLC_CHROMA_SUBTYPE_YUV444: + return width * height * 3 * desc->color_bits; + case VLC_CHROMA_SUBTYPE_YUV440: + case VLC_CHROMA_SUBTYPE_YUV422: + return width * height * 2 * desc->color_bits; + case VLC_CHROMA_SUBTYPE_YUV420: + case VLC_CHROMA_SUBTYPE_YUV411: + return width * height * 1.5 * desc->color_bits; + case VLC_CHROMA_SUBTYPE_YUV410: + return width * height * 1.125 * desc->color_bits; + case VLC_CHROMA_SUBTYPE_YUV211: + case VLC_CHROMA_SUBTYPE_GREY: + return width * height * desc->color_bits; + case VLC_CHROMA_SUBTYPE_RGB: + return width * height * 4 * desc->color_bits; + default: + vlc_assert_unreachable(); + } + } + + uint64_t total_bits = 0; + for (unsigned i = 0; i < desc->plane_count; i++) + { + const vlc_rational_t rw = desc->p[i].w; + const vlc_rational_t rh = desc->p[i].h; + + unsigned plane_width = width * rw.num / rw.den; + unsigned plane_height = height * rh.num / rh.den; + + uint64_t plane_pixels = plane_width * plane_height; + uint64_t plane_bits = plane_pixels * desc->pixel_bits; + + total_bits += plane_bits; + } + + return total_bits; +} + +static float +GetColorRatio(enum vlc_chroma_subtype subtype) +{ + switch (subtype) + { + case VLC_CHROMA_SUBTYPE_YUV444: + case VLC_CHROMA_SUBTYPE_RGB: + return 1.f; + case VLC_CHROMA_SUBTYPE_YUV422: + return 0.67; + case VLC_CHROMA_SUBTYPE_YUV440: + return 0.5; /* should be like YUV422, but it is less common */ + case VLC_CHROMA_SUBTYPE_YUV420: + return 0.5; + case VLC_CHROMA_SUBTYPE_YUV411: + return 0.33; + case VLC_CHROMA_SUBTYPE_YUV410: + return 0.25; + case VLC_CHROMA_SUBTYPE_YUV211: + case VLC_CHROMA_SUBTYPE_OTHER: + return 0.2; + case VLC_CHROMA_SUBTYPE_GREY: + return 0.1; + default: + vlc_assert_unreachable(); + } +} + +static float +CompareDescs(const vlc_chroma_description_t *in_desc, + const vlc_chroma_description_t *out_desc) +{ + /* Compare color bits */ + float bits_ratio; + if (in_desc->color_bits == 0 || out_desc->color_bits == 0) + bits_ratio = 1.f; + else + { + bits_ratio = out_desc->color_bits / in_desc->color_bits; + if (bits_ratio > 1.f) + bits_ratio = 1.f; + } + + /* Compare color ratios, favor same or near subtype */ + if (in_desc->subtype == out_desc->subtype) + return bits_ratio; + + float color_ratio = GetColorRatio(out_desc->subtype) + / GetColorRatio(in_desc->subtype); + if (color_ratio > 1.f) + color_ratio = 1.f; + + /* Malus for CPU YUV <-> Other. Favor staying in the same color model. */ + bool in_is_yuv = vlc_chroma_description_IsYUV(in_desc); + bool out_is_yuv = vlc_chroma_description_IsYUV(out_desc); + if ((in_desc->plane_count != 0 && out_desc->plane_count != 0) + && (in_is_yuv || out_is_yuv) && (in_is_yuv != out_is_yuv)) + color_ratio *= 0.9; + + return color_ratio * bits_ratio; +} + +static void +vlc_chroma_conv_result_FromNode(struct vlc_chroma_conv_result *res, + const struct bfs_node *node, + unsigned width, unsigned height) +{ + res->chain_count = node->depth + 1; + res->cost = 0; + + uint64_t total_cost = 0; + float total_quality = 1.f; + for (size_t i = 0; i < res->chain_count; ++i) + { + res->chain[i] = node->chain[i]; + + if (i > 0) + { + const vlc_chroma_description_t *from_desc = + vlc_fourcc_GetChromaDescription(res->chain[i - 1]); + const vlc_chroma_description_t *to_desc = + vlc_fourcc_GetChromaDescription(res->chain[i]); + + if (from_desc == NULL || to_desc == NULL) + { + /* Unlikely, fallback for a big cost */ + total_cost += width * height * 4 * 8 * node->cost_factor; + continue; + } + + uint64_t from_bits = GetChromaBits(from_desc, width, height); + uint64_t to_bits = GetChromaBits(to_desc, width, height); + + /* Unlikely case */ + if (from_bits == 0) /* OTHER -> ANY */ + from_bits = to_bits; + else if (to_bits == 0) /* ANY -> OTHER */ + to_bits = from_bits; + + total_cost += (from_bits + to_bits) * node->cost_factor; + + float quality = CompareDescs(from_desc, to_desc); + assert(quality > 0.f && quality <= 1.f); + + total_quality *= quality; + } + } + res->cost = total_cost / width / height; + res->quality = 100 * total_quality; +} + +static int +SortResults(const void *a, const void *b, void *arg) +{ + const struct vlc_chroma_conv_result *ra = a; + const struct vlc_chroma_conv_result *rb = b; + bool *sort_by_quality = arg; + + int cost_score = 0, quality_score = 0; + + /* Lower cost is better */ + if (ra->cost < rb->cost) + cost_score = -1; + else if (ra->cost > rb->cost) + cost_score = 1; + + /* Higher Quality is better */ + if (ra->quality > rb->quality) + quality_score = -1; + else if (ra->quality < rb->quality) + quality_score = 1; + + /* Fallback to secondary score in same score */ + if (*sort_by_quality) + return quality_score != 0 ? quality_score : cost_score; + else + return cost_score != 0 ? cost_score : quality_score; +} + +static bool +bfs_node_IsResult(const struct bfs_node *node, vlc_fourcc_t to) +{ + vlc_fourcc_t current_chroma = node->chain[node->depth]; + return to == 0 || current_chroma == to; +} + +static bool +vlc_chroma_conv_result_Equals(struct vlc_chroma_conv_result *a, + struct vlc_chroma_conv_result *b) +{ + if (a->chain_count != b->chain_count) + return false; + if (a->quality != b->quality) + return false; + /* Don't check cost since we want to merge results with different costs */ + for (size_t i = 0; i < a->chain_count; ++i) + if (a->chain[i] != b->chain[i]) + return false; + return true; +} + +struct vlc_chroma_conv_result * +vlc_chroma_conv_Probe(vlc_fourcc_t from, vlc_fourcc_t to, + unsigned width, unsigned height, + unsigned max_indirect_steps, int flags, size_t *count) +{ + assert(from != 0); + assert(max_indirect_steps <= VLC_CHROMA_CONV_MAX_INDIRECT_STEPS); + vlc_chroma_conv_vec chroma_table; + vlc_vector_init(&chroma_table); + + if (width == 0 || height == 0) + { + width = 3840; + height = 2160; + } + + if (max_indirect_steps > 0) + { + /* Allow indirect steps only when converting from/to a GPU chroma */ + bool from_cpu = vlc_fourcc_GetChromaBPP(from) != 0; + bool to_cpu = to == 0 ? true : vlc_fourcc_GetChromaBPP(to) != 0; + if (from_cpu && to_cpu) + max_indirect_steps--; + } + + /* Probe modules */ + int ret = modules_Probe(&chroma_table); + if (ret != 0 || chroma_table.size == 0) + { + vlc_vector_destroy(&chroma_table); + return NULL; + } + + /* Run tree search */ + bfs_queue_vec bfs_queue; + vlc_vector_init(&bfs_queue); + ret = bfs_Run(from, to, max_indirect_steps + 1 , &chroma_table, flags, + &bfs_queue); + + vlc_vector_destroy(&chroma_table); + + size_t result_count = 0; + for (size_t i = 1 /* skip start node */; i < bfs_queue.size; ++i) + if (bfs_node_IsResult(&bfs_queue.data[i], to)) + result_count++; + + if (unlikely(ret != 0) || result_count == 0) + { + vlc_vector_destroy(&bfs_queue); + return NULL; + } + + /* Allocate the result array */ + struct VLC_VECTOR(struct vlc_chroma_conv_result) result_vec = + VLC_VECTOR_INITIALIZER; + bool success = vlc_vector_push_hole(&result_vec, result_count); + if (!success) + { + vlc_vector_destroy(&bfs_queue); + return NULL; + } + + /* Fill the result from the tree search */ + size_t res_idx = 0; + for (size_t i = 1 /* skip start node */; i < bfs_queue.size; ++i) + { + const struct bfs_node *node = &bfs_queue.data[i]; + if (!bfs_node_IsResult(node, to)) + continue; + + assert(res_idx < result_count); + struct vlc_chroma_conv_result *res = &result_vec.data[res_idx++]; + vlc_chroma_conv_result_FromNode(res, node, width, height); + } + assert(res_idx == result_count); + + vlc_vector_destroy(&bfs_queue); + + /* Sort */ + bool sort_by_quality = (flags & VLC_CHROMA_CONV_FLAG_SORT_COST) == 0; + vlc_qsort(result_vec.data, result_count, + sizeof(struct vlc_chroma_conv_result), SortResults, + &sort_by_quality); + + /* Remove duplicate entries, it can happen when more the 2 modules probe + * the same conversion. They are not necessarily one after the other as + * they might have different quality. */ + for (size_t i = 0; i < result_vec.size - 1; ++ i) + { + struct vlc_chroma_conv_result *cur = &result_vec.data[i]; + + size_t j = i + 1; + while (j < result_vec.size) + { + struct vlc_chroma_conv_result *next = &result_vec.data[j]; + if (vlc_chroma_conv_result_Equals(cur, next)) + { + /* Keep the lowest cost */ + if (next->cost < cur->cost) + cur->cost = next->cost; + vlc_vector_remove(&result_vec, j); + } + else + j++; + } + } + + *count = result_vec.size; + return result_vec.data; +} + +char * +vlc_chroma_conv_result_ToString(const struct vlc_chroma_conv_result *res) +{ + struct vlc_memstream ms; + int ret = vlc_memstream_open(&ms); + if (ret != 0) + return NULL; + vlc_memstream_printf(&ms, "[c=%u|q=%u] ", res->cost, res->quality); + + for (size_t i = 0; i < res->chain_count; ++i) + { + vlc_memstream_printf(&ms, "%4.4s", (const char *) &res->chain[i]); + if (i != res->chain_count - 1) + vlc_memstream_puts(&ms, " -> "); + } + ret = vlc_memstream_close(&ms); + return ret == 0 ? ms.ptr : NULL; +} diff --git a/src/misc/fourcc.c b/src/misc/fourcc.c index 636d096345369efd0924043a5853900fadee2742..bd74d6abe03697158b943e2483506b89dfd4cab8 100644 --- a/src/misc/fourcc.c +++ b/src/misc/fourcc.c @@ -31,6 +31,7 @@ #include <vlc_common.h> #include <vlc_fourcc.h> #include <vlc_es.h> +#include <vlc_chroma_probe.h> #include <assert.h> #include "fourcc_tables.h" @@ -206,656 +207,236 @@ const char *vlc_fourcc_GetDescription(int cat, vlc_fourcc_t fourcc) return LookupCat(fourcc, &ret, cat) ? ret : ""; } - -/* */ -#define VLC_CODEC_YUV_PLANAR_420 \ - VLC_CODEC_I420, VLC_CODEC_YV12 - -#define VLC_CODEC_YUV_SEMIPLANAR_420 \ - VLC_CODEC_NV12, VLC_CODEC_NV21 - -#define VLC_CODEC_YUV_PLANAR_420_16 \ - VLC_CODEC_I420_16L, VLC_CODEC_I420_16B, VLC_CODEC_I420_12L, VLC_CODEC_I420_12B, VLC_CODEC_I420_10L, VLC_CODEC_I420_10B, VLC_CODEC_I420_9L, VLC_CODEC_I420_9B - -#define VLC_CODEC_YUV_SEMIPLANAR_420_16 \ - VLC_CODEC_P010, VLC_CODEC_P012 ,VLC_CODEC_P016 - -#define VLC_CODEC_YUV_SEMIPLANAR_422 \ - VLC_CODEC_NV16, VLC_CODEC_NV61 - -#define VLC_CODEC_YUV_PLANAR_422_16 \ - VLC_CODEC_I422_12L, VLC_CODEC_I422_12B, VLC_CODEC_I422_10L, VLC_CODEC_I422_10B, VLC_CODEC_I422_9L, VLC_CODEC_I422_9B - -#define VLC_CODEC_YUV_PLANAR_444_ALPHA \ - VLC_CODEC_YUVA, VLC_CODEC_YUVA_444_10L, VLC_CODEC_YUVA_444_10B, VLC_CODEC_YUVA_444_12L, VLC_CODEC_YUVA_444_12B - -#define VLC_CODEC_YUV_SEMIPLANAR_444 \ - VLC_CODEC_NV24, VLC_CODEC_NV42 - -#define VLC_CODEC_YUV_PLANAR_444_16 \ - VLC_CODEC_I444_10L, VLC_CODEC_I444_10B, VLC_CODEC_I444_9L, VLC_CODEC_I444_9B, \ - VLC_CODEC_I444_16L, VLC_CODEC_I444_16B, VLC_CODEC_I444_12L, VLC_CODEC_I444_12B - -#define VLC_CODEC_YUV_PACKED \ - VLC_CODEC_YUYV, VLC_CODEC_YVYU, \ - VLC_CODEC_UYVY, VLC_CODEC_VYUY, \ - VLC_CODEC_VUYA, VLC_CODEC_Y210, \ - VLC_CODEC_Y410 - -#define VLC_CODEC_FALLBACK_420 \ - VLC_CODEC_I422, VLC_CODEC_YUV_PACKED, \ - VLC_CODEC_I444, VLC_CODEC_I440, \ - VLC_CODEC_I411, VLC_CODEC_I410, VLC_CODEC_Y211 - -static const vlc_fourcc_t p_I420_fallback[] = { - VLC_CODEC_I420, VLC_CODEC_YV12, VLC_CODEC_FALLBACK_420, 0 -}; -static const vlc_fourcc_t p_YV12_fallback[] = { - VLC_CODEC_YV12, VLC_CODEC_I420, VLC_CODEC_FALLBACK_420, 0 -}; -static const vlc_fourcc_t p_NV12_fallback[] = { - VLC_CODEC_NV12, VLC_CODEC_I420, VLC_CODEC_FALLBACK_420, 0 -}; - -#define VLC_CODEC_FALLBACK_420_16 \ - VLC_CODEC_I420, VLC_CODEC_YV12, VLC_CODEC_FALLBACK_420 - -static const vlc_fourcc_t p_I420_9L_fallback[] = { - VLC_CODEC_I420_9L, VLC_CODEC_I420_9B, VLC_CODEC_FALLBACK_420_16, 0 -}; -static const vlc_fourcc_t p_I420_9B_fallback[] = { - VLC_CODEC_I420_9B, VLC_CODEC_I420_9L, VLC_CODEC_FALLBACK_420_16, 0 -}; -static const vlc_fourcc_t p_I420_10L_fallback[] = { - VLC_CODEC_I420_10L, VLC_CODEC_I420_10B, VLC_CODEC_FALLBACK_420_16, 0 -}; -static const vlc_fourcc_t p_I420_10B_fallback[] = { - VLC_CODEC_I420_10B, VLC_CODEC_I420_10L, VLC_CODEC_FALLBACK_420_16, 0 -}; -static const vlc_fourcc_t p_I420_12L_fallback[] = { - VLC_CODEC_I420_12L, VLC_CODEC_I420_12B, VLC_CODEC_FALLBACK_420_16, 0 -}; -static const vlc_fourcc_t p_I420_12B_fallback[] = { - VLC_CODEC_I420_12B, VLC_CODEC_I420_12L, VLC_CODEC_FALLBACK_420_16, 0 -}; -static const vlc_fourcc_t p_I420_16L_fallback[] = { - VLC_CODEC_I420_16L, VLC_CODEC_I420_16B, VLC_CODEC_FALLBACK_420_16, 0 -}; -static const vlc_fourcc_t p_I420_16B_fallback[] = { - VLC_CODEC_I420_16B, VLC_CODEC_I420_16L, VLC_CODEC_FALLBACK_420_16, 0 -}; -static const vlc_fourcc_t p_P010_fallback[] = { - VLC_CODEC_P010, VLC_CODEC_FALLBACK_420_16, 0 -}; - - -#define VLC_CODEC_FALLBACK_422 \ - VLC_CODEC_YUV_PACKED, VLC_CODEC_YUV_PLANAR_420, \ - VLC_CODEC_I444, VLC_CODEC_I440, \ - VLC_CODEC_I411, VLC_CODEC_I410, VLC_CODEC_Y211 - -static const vlc_fourcc_t p_I422_fallback[] = { - VLC_CODEC_I422, VLC_CODEC_FALLBACK_422, 0 -}; - -#define VLC_CODEC_FALLBACK_422_16 \ - VLC_CODEC_I422, VLC_CODEC_FALLBACK_422 - -static const vlc_fourcc_t p_I422_9L_fallback[] = { - VLC_CODEC_I422_9L, VLC_CODEC_I422_9B, VLC_CODEC_FALLBACK_422_16, 0 -}; -static const vlc_fourcc_t p_I422_9B_fallback[] = { - VLC_CODEC_I422_9B, VLC_CODEC_I422_9L, VLC_CODEC_FALLBACK_422_16, 0 -}; -static const vlc_fourcc_t p_I422_10L_fallback[] = { - VLC_CODEC_I422_10L, VLC_CODEC_I422_10B, VLC_CODEC_FALLBACK_422_16, 0 -}; -static const vlc_fourcc_t p_I422_10B_fallback[] = { - VLC_CODEC_I422_10B, VLC_CODEC_I422_10L, VLC_CODEC_FALLBACK_422_16, 0 -}; -static const vlc_fourcc_t p_I422_12L_fallback[] = { - VLC_CODEC_I422_12L, VLC_CODEC_I422_12B, VLC_CODEC_FALLBACK_422_16, 0 -}; -static const vlc_fourcc_t p_I422_12B_fallback[] = { - VLC_CODEC_I422_12B, VLC_CODEC_I422_12L, VLC_CODEC_FALLBACK_422_16, 0 -}; - -#define VLC_CODEC_FALLBACK_444 \ - VLC_CODEC_I422, VLC_CODEC_YUV_PACKED, \ - VLC_CODEC_YUV_PLANAR_420, VLC_CODEC_I440, \ - VLC_CODEC_I411, VLC_CODEC_I410, VLC_CODEC_Y211 - -static const vlc_fourcc_t p_I444_fallback[] = { - VLC_CODEC_I444, VLC_CODEC_FALLBACK_444, 0 -}; - -#define VLC_CODEC_FALLBACK_444_16 \ - VLC_CODEC_I444, VLC_CODEC_FALLBACK_444 - -static const vlc_fourcc_t p_I444_9L_fallback[] = { - VLC_CODEC_I444_9L, VLC_CODEC_I444_9B, VLC_CODEC_FALLBACK_444_16, 0 -}; -static const vlc_fourcc_t p_I444_9B_fallback[] = { - VLC_CODEC_I444_9B, VLC_CODEC_I444_9L, VLC_CODEC_FALLBACK_444_16, 0 -}; -static const vlc_fourcc_t p_I444_10L_fallback[] = { - VLC_CODEC_I444_10L, VLC_CODEC_I444_10B, VLC_CODEC_FALLBACK_444_16, 0 -}; -static const vlc_fourcc_t p_I444_10B_fallback[] = { - VLC_CODEC_I444_10B, VLC_CODEC_I444_10L, VLC_CODEC_FALLBACK_444_16, 0 -}; -static const vlc_fourcc_t p_I444_12L_fallback[] = { - VLC_CODEC_I444_12L, VLC_CODEC_I444_12B, VLC_CODEC_FALLBACK_444_16, 0 -}; -static const vlc_fourcc_t p_I444_12B_fallback[] = { - VLC_CODEC_I444_12B, VLC_CODEC_I444_12L, VLC_CODEC_FALLBACK_444_16, 0 -}; -static const vlc_fourcc_t p_I444_16L_fallback[] = { - VLC_CODEC_I444_16L, VLC_CODEC_I444_16B, VLC_CODEC_FALLBACK_444_16, 0 -}; -static const vlc_fourcc_t p_I444_16B_fallback[] = { - VLC_CODEC_I444_16B, VLC_CODEC_I444_16L, VLC_CODEC_FALLBACK_444_16, 0 -}; - - -/* Fallbacks for cvpx */ -static const vlc_fourcc_t p_CVPX_VIDEO_NV12_fallback[] = { - VLC_CODEC_CVPX_NV12, VLC_CODEC_NV12, VLC_CODEC_I420, 0, -}; -static const vlc_fourcc_t p_CVPX_VIDEO_UYVY_fallback[] = { - VLC_CODEC_CVPX_UYVY, VLC_CODEC_UYVY, 0, -}; -static const vlc_fourcc_t p_CVPX_VIDEO_I420_fallback[] = { - VLC_CODEC_CVPX_I420, VLC_CODEC_I420, 0, -}; -static const vlc_fourcc_t p_CVPX_VIDEO_BGRA_fallback[] = { - VLC_CODEC_CVPX_BGRA, VLC_CODEC_BGRA, 0, -}; -static const vlc_fourcc_t p_CVPX_VIDEO_P010_fallback[] = { - VLC_CODEC_CVPX_P010, VLC_CODEC_P010, VLC_CODEC_I420_10L, 0 -}; - -static const vlc_fourcc_t p_VAAPI_420_fallback[] = { - VLC_CODEC_VAAPI_420, VLC_CODEC_I420, 0, -}; - -static const vlc_fourcc_t p_VAAPI_420_10BPP_fallback[] = { - VLC_CODEC_VAAPI_420_10BPP, VLC_CODEC_P010, VLC_CODEC_I420_10L, 0, -}; - -static const vlc_fourcc_t p_VAAPI_420_12BPP_fallback[] = { - VLC_CODEC_VAAPI_420_12BPP, VLC_CODEC_P012, VLC_CODEC_I420_12L, 0, -}; - -static const vlc_fourcc_t p_D3D9_OPAQUE_fallback[] = { - VLC_CODEC_D3D9_OPAQUE, VLC_CODEC_I420, 0, -}; - -static const vlc_fourcc_t p_D3D9_OPAQUE_10B_fallback[] = { - VLC_CODEC_D3D9_OPAQUE_10B, VLC_CODEC_P010, VLC_CODEC_I420_10L, 0, -}; - -static const vlc_fourcc_t p_D3D11_OPAQUE_fallback[] = { - VLC_CODEC_D3D11_OPAQUE, VLC_CODEC_NV12, 0, -}; - -static const vlc_fourcc_t p_D3D11_OPAQUE_10B_fallback[] = { - VLC_CODEC_D3D11_OPAQUE_10B, VLC_CODEC_P010, VLC_CODEC_I420_10L, 0, -}; - -static const vlc_fourcc_t p_D3D11_OPAQUE_RGBA_fallback[] = { - VLC_CODEC_D3D11_OPAQUE_RGBA, VLC_CODEC_RGBA, 0, -}; - -static const vlc_fourcc_t p_NVDEC_OPAQUE_fallback[] = { - VLC_CODEC_NVDEC_OPAQUE, VLC_CODEC_NV12, 0, -}; - -static const vlc_fourcc_t p_NVDEC_OPAQUE_10B_fallback[] = { - VLC_CODEC_NVDEC_OPAQUE_10B, - VLC_CODEC_P010, - VLC_CODEC_I420_10L, 0, -}; - -static const vlc_fourcc_t p_NVDEC_OPAQUE_16B_fallback[] = { - VLC_CODEC_NVDEC_OPAQUE_16B, - VLC_CODEC_P016, VLC_CODEC_P010, - VLC_CODEC_I420_16L, VLC_CODEC_I420_12L, VLC_CODEC_I420_10L, 0, -}; - -static const vlc_fourcc_t p_I440_fallback[] = { - VLC_CODEC_I440, - VLC_CODEC_YUV_PLANAR_420, - VLC_CODEC_I422, - VLC_CODEC_I444, - VLC_CODEC_YUV_PACKED, - VLC_CODEC_I411, VLC_CODEC_I410, VLC_CODEC_Y211, 0 -}; - -#define VLC_CODEC_FALLBACK_PACKED \ - VLC_CODEC_I422, VLC_CODEC_YUV_PLANAR_420, \ - VLC_CODEC_I444, VLC_CODEC_I440, \ - VLC_CODEC_I411, VLC_CODEC_I410, VLC_CODEC_Y211 - -static const vlc_fourcc_t p_YUYV_fallback[] = { - VLC_CODEC_YUYV, - VLC_CODEC_YVYU, - VLC_CODEC_UYVY, - VLC_CODEC_VYUY, - VLC_CODEC_FALLBACK_PACKED, 0 -}; -static const vlc_fourcc_t p_YVYU_fallback[] = { - VLC_CODEC_YVYU, - VLC_CODEC_YUYV, - VLC_CODEC_UYVY, - VLC_CODEC_VYUY, - VLC_CODEC_FALLBACK_PACKED, 0 -}; -static const vlc_fourcc_t p_UYVY_fallback[] = { - VLC_CODEC_UYVY, - VLC_CODEC_VYUY, - VLC_CODEC_YUYV, - VLC_CODEC_YVYU, - VLC_CODEC_FALLBACK_PACKED, 0 -}; -static const vlc_fourcc_t p_VYUY_fallback[] = { - VLC_CODEC_VYUY, - VLC_CODEC_UYVY, - VLC_CODEC_YUYV, - VLC_CODEC_YVYU, - VLC_CODEC_FALLBACK_PACKED, 0 -}; - -static const vlc_fourcc_t *const pp_YUV_fallback[] = { - p_YV12_fallback, - p_I420_fallback, - p_I420_9L_fallback, - p_I420_9B_fallback, - p_I420_10L_fallback, - p_I420_10B_fallback, - p_I420_12L_fallback, - p_I420_12B_fallback, - p_I420_16L_fallback, - p_I420_16B_fallback, - p_I422_fallback, - p_I422_9L_fallback, - p_I422_9B_fallback, - p_I422_10L_fallback, - p_I422_10B_fallback, - p_I422_12L_fallback, - p_I422_12B_fallback, - p_I444_fallback, - p_I444_9L_fallback, - p_I444_9B_fallback, - p_I444_10L_fallback, - p_I444_10B_fallback, - p_I444_12L_fallback, - p_I444_12B_fallback, - p_I444_16L_fallback, - p_I444_16B_fallback, - p_I440_fallback, - p_YUYV_fallback, - p_YVYU_fallback, - p_UYVY_fallback, - p_VYUY_fallback, - p_NV12_fallback, - p_P010_fallback, - p_CVPX_VIDEO_NV12_fallback, - p_CVPX_VIDEO_UYVY_fallback, - p_CVPX_VIDEO_I420_fallback, - p_CVPX_VIDEO_P010_fallback, - p_VAAPI_420_fallback, - p_VAAPI_420_10BPP_fallback, - p_VAAPI_420_12BPP_fallback, - p_D3D9_OPAQUE_fallback, - p_D3D9_OPAQUE_10B_fallback, - p_D3D11_OPAQUE_fallback, - p_D3D11_OPAQUE_10B_fallback, - p_NVDEC_OPAQUE_fallback, - p_NVDEC_OPAQUE_10B_fallback, - p_NVDEC_OPAQUE_16B_fallback, - NULL, -}; - -static const vlc_fourcc_t p_list_YUV[] = { - VLC_CODEC_YUV_PLANAR_420, - VLC_CODEC_YUV_SEMIPLANAR_420, - VLC_CODEC_I422, - VLC_CODEC_YUV_SEMIPLANAR_422, - VLC_CODEC_I440, - VLC_CODEC_I444, - VLC_CODEC_YUV_PLANAR_444_ALPHA, - VLC_CODEC_YUV_SEMIPLANAR_444, - VLC_CODEC_YUV_PACKED, - VLC_CODEC_I411, VLC_CODEC_I410, VLC_CODEC_Y211, - VLC_CODEC_YUV_PLANAR_420_16, - VLC_CODEC_YUV_SEMIPLANAR_420_16, - VLC_CODEC_YUV_PLANAR_422_16, - VLC_CODEC_YUV_PLANAR_444_16, - VLC_CODEC_VDPAU_VIDEO, - VLC_CODEC_CVPX_NV12, - VLC_CODEC_CVPX_UYVY, - VLC_CODEC_CVPX_I420, - VLC_CODEC_CVPX_P010, - VLC_CODEC_VAAPI_420, - VLC_CODEC_VAAPI_420_10BPP, - VLC_CODEC_D3D9_OPAQUE, - VLC_CODEC_D3D9_OPAQUE_10B, - VLC_CODEC_D3D11_OPAQUE, - VLC_CODEC_D3D11_OPAQUE_10B, - VLC_CODEC_D3D11_OPAQUE_ALPHA, - VLC_CODEC_NVDEC_OPAQUE, - VLC_CODEC_NVDEC_OPAQUE_10B, - VLC_CODEC_NVDEC_OPAQUE_16B, - VLC_CODEC_NVDEC_OPAQUE_444, - VLC_CODEC_NVDEC_OPAQUE_444_16B, - VLC_CODEC_YUV420A, - VLC_CODEC_YUV422A, - 0, -}; - -static const vlc_fourcc_t p_list_YUV_no_fallback[] = { - VLC_CODEC_V308, -}; - -/* */ -static const vlc_fourcc_t p_RGB32_fallback[] = { - VLC_CODEC_XRGB, - VLC_CODEC_BGRX, - VLC_CODEC_RGB24, - VLC_CODEC_BGR24, - VLC_CODEC_RGB565LE, - VLC_CODEC_RGB555LE, - VLC_CODEC_RGB233, - VLC_CODEC_BGR233, - VLC_CODEC_RGB332, - 0, -}; -static const vlc_fourcc_t p_RGB24_fallback[] = { - VLC_CODEC_RGB24, - VLC_CODEC_BGR24, - VLC_CODEC_XRGB, - VLC_CODEC_BGRX, - VLC_CODEC_RGB565LE, - VLC_CODEC_RGB555LE, - VLC_CODEC_RGB233, - VLC_CODEC_BGR233, - VLC_CODEC_RGB332, - 0, -}; -static const vlc_fourcc_t p_RGB16_fallback[] = { - VLC_CODEC_RGB565LE, - VLC_CODEC_RGB24, - VLC_CODEC_BGR24, - VLC_CODEC_XRGB, - VLC_CODEC_BGRX, - VLC_CODEC_RGB555LE, - VLC_CODEC_RGB233, - VLC_CODEC_BGR233, - VLC_CODEC_RGB332, - 0, -}; -static const vlc_fourcc_t p_RGB15_fallback[] = { - VLC_CODEC_RGB555LE, - VLC_CODEC_RGB565LE, - VLC_CODEC_RGB24, - VLC_CODEC_BGR24, - VLC_CODEC_XRGB, - VLC_CODEC_BGRX, - VLC_CODEC_RGB233, - VLC_CODEC_BGR233, - VLC_CODEC_RGB332, - 0, -}; -static const vlc_fourcc_t p_RGB8_fallback[] = { - VLC_CODEC_RGB233, - VLC_CODEC_BGR233, - VLC_CODEC_RGB332, - VLC_CODEC_RGB555LE, - VLC_CODEC_RGB565LE, - VLC_CODEC_RGB24, - VLC_CODEC_BGR24, - VLC_CODEC_XRGB, - VLC_CODEC_BGRX, - 0, -}; -static const vlc_fourcc_t *const pp_RGB_fallback[] = { - p_RGB32_fallback, - p_RGB24_fallback, - p_RGB16_fallback, - p_RGB15_fallback, - p_RGB8_fallback, - p_CVPX_VIDEO_BGRA_fallback, - p_D3D11_OPAQUE_RGBA_fallback, - - NULL, -}; - - -/* */ -static const vlc_fourcc_t *GetFallback( vlc_fourcc_t i_fourcc, - const vlc_fourcc_t *const *pp_fallback, - const vlc_fourcc_t p_list[] ) +static vlc_fourcc_t *GetFallback( vlc_fourcc_t i_fourcc, int flags ) { - for( unsigned i = 0; pp_fallback[i]; i++ ) + size_t count; + struct vlc_chroma_conv_result *results = + vlc_chroma_conv_Probe(i_fourcc, 0, 0, 0, 0, flags, &count); + if (results == NULL) + return NULL; + + vlc_fourcc_t *list = vlc_alloc(count + 1, sizeof(vlc_fourcc_t)); + if (list == NULL) { - if( pp_fallback[i][0] == i_fourcc ) - return pp_fallback[i]; + free(results); + return NULL; } - return p_list; + + for (size_t i = 0; i < count; ++i) + { + struct vlc_chroma_conv_result *res = &results[i]; + assert(res->chain_count == 2); + + list[i] = res->chain[1]; + } + list[count] = 0; + free(results); + return list; } -const vlc_fourcc_t *vlc_fourcc_GetYUVFallback( vlc_fourcc_t i_fourcc ) +vlc_fourcc_t *vlc_fourcc_GetYUVFallback( vlc_fourcc_t i_fourcc ) { - return GetFallback( i_fourcc, pp_YUV_fallback, p_list_YUV ); + return GetFallback( i_fourcc, VLC_CHROMA_CONV_FLAG_ONLY_YUV ); } -const vlc_fourcc_t *vlc_fourcc_GetRGBFallback( vlc_fourcc_t i_fourcc ) +vlc_fourcc_t *vlc_fourcc_GetRGBFallback( vlc_fourcc_t i_fourcc ) { - return GetFallback( i_fourcc, pp_RGB_fallback, p_RGB32_fallback ); + return GetFallback( i_fourcc, VLC_CHROMA_CONV_FLAG_ONLY_RGB ); } -const vlc_fourcc_t *vlc_fourcc_GetFallback( vlc_fourcc_t i_fourcc ) +vlc_fourcc_t *vlc_fourcc_GetFallback( vlc_fourcc_t i_fourcc ) { return vlc_fourcc_IsYUV( i_fourcc) ? vlc_fourcc_GetYUVFallback( i_fourcc ) : vlc_fourcc_GetRGBFallback( i_fourcc ); } -bool vlc_fourcc_IsYUV(vlc_fourcc_t fcc) -{ - for( unsigned i = 0; p_list_YUV[i]; i++ ) - { - if( p_list_YUV[i] == fcc ) - return true; - } - - for (size_t i = 0; i < ARRAY_SIZE(p_list_YUV_no_fallback); i++) - { - if (p_list_YUV_no_fallback[i] == fcc) - return true; - } - return false; -} - -#define PLANAR(n, w_den, h_den, bits) \ +#define PLANAR(subtype_, n, w_den, h_den, bits) \ + .subtype = VLC_CHROMA_SUBTYPE_##subtype_, \ .plane_count = n, \ .p = { {.w = {1, 1}, .h = {1, 1}}, \ {.w = {1,w_den}, .h = {1,h_den}}, \ {.w = {1,w_den}, .h = {1,h_den}}, \ {.w = {1, 1}, .h = {1, 1}} }, \ .pixel_size = ((bits + 7) / 8), \ - .pixel_bits = bits + .pixel_bits = bits, \ + .color_bits = bits -#define PLANAR_8(n, w_den, h_den) PLANAR(n, w_den, h_den, 8) -#define PLANAR_16(n, w_den, h_den, bits) PLANAR(n, w_den, h_den, bits) +#define PLANAR_8(subtype_, n, w_den, h_den) PLANAR(subtype_, n, w_den, h_den, 8) +#define PLANAR_16(subtype_, n, w_den, h_den, bits) PLANAR(subtype_, n, w_den, h_den, bits) -#define SEMIPLANAR(w_den, h_den, bits) \ +#define SEMIPLANAR(subtype_, w_den, h_den, bits) \ + .subtype = VLC_CHROMA_SUBTYPE_##subtype_, \ .plane_count = 2, \ .p = { {.w = {1, 1}, .h = {1, 1}}, \ {.w = {2,w_den}, .h = {1,h_den}} }, \ .pixel_size = ((bits + 7) / 8), \ - .pixel_bits = bits + .pixel_bits = bits, \ + .color_bits = bits -#define PACKED_FMT(size, bits) \ +#define PACKED_FMT(subtype_, size, bits, color_bits_) \ + .subtype = VLC_CHROMA_SUBTYPE_##subtype_, \ .plane_count = 1, \ .p = { {.w = {1,1}, .h = {1,1}} }, \ .pixel_size = size, \ - .pixel_bits = bits + .pixel_bits = bits, \ + .color_bits = color_bits_ /* Zero planes for hardware picture handles. Cannot be manipulated directly. */ -#define FAKE_FMT() \ +#define GPU_FMT(subtype_, color_bits_) \ + .subtype = VLC_CHROMA_SUBTYPE_##subtype_, \ .plane_count = 0, \ .p = { {.w = {1,1}, .h = {1,1}} }, \ .pixel_size = 0, \ - .pixel_bits = 0 + .pixel_bits = 0, \ + .color_bits = color_bits_ static const vlc_chroma_description_t p_list_chroma_description[] = { - { VLC_CODEC_I411, PLANAR_8(3, 4, 1) }, - { VLC_CODEC_I410, PLANAR_8(3, 4, 4) }, - { VLC_CODEC_I420, PLANAR_8(3, 2, 2) }, - { VLC_CODEC_YV12, PLANAR_8(3, 2, 2) }, - { VLC_CODEC_NV12, SEMIPLANAR(2, 2, 8) }, - { VLC_CODEC_NV21, SEMIPLANAR(2, 2, 8) }, - { VLC_CODEC_I422, PLANAR_8(3, 2, 1) }, - { VLC_CODEC_NV16, SEMIPLANAR(2, 1, 8) }, - { VLC_CODEC_NV61, SEMIPLANAR(2, 1, 8) }, - { VLC_CODEC_I440, PLANAR_8(3, 1, 2) }, - { VLC_CODEC_I444, PLANAR_8(3, 1, 1) }, - { VLC_CODEC_NV24, SEMIPLANAR(1, 1, 8) }, - { VLC_CODEC_NV42, SEMIPLANAR(1, 1, 8) }, - { VLC_CODEC_YUVA, PLANAR_8(4, 1, 1) }, - { VLC_CODEC_YUV420A, PLANAR_8(4, 2, 2) }, - { VLC_CODEC_YUV422A, PLANAR_8(4, 2, 1) }, - - { VLC_CODEC_GBR_PLANAR, PLANAR_8(3, 1, 1) }, - { VLC_CODEC_GBR_PLANAR_9L, PLANAR_16(3, 1, 1, 9) }, - { VLC_CODEC_GBR_PLANAR_9B, PLANAR_16(3, 1, 1, 9) }, - { VLC_CODEC_GBR_PLANAR_10L, PLANAR_16(3, 1, 1, 10) }, - { VLC_CODEC_GBR_PLANAR_10B, PLANAR_16(3, 1, 1, 10) }, - { VLC_CODEC_GBR_PLANAR_12L, PLANAR_16(3, 1, 1, 12) }, - { VLC_CODEC_GBR_PLANAR_12B, PLANAR_16(3, 1, 1, 12) }, - { VLC_CODEC_GBR_PLANAR_14L, PLANAR_16(3, 1, 1, 14) }, - { VLC_CODEC_GBR_PLANAR_14B, PLANAR_16(3, 1, 1, 14) }, - { VLC_CODEC_GBR_PLANAR_16L, PLANAR_16(3, 1, 1, 16) }, - { VLC_CODEC_GBR_PLANAR_16B, PLANAR_16(3, 1, 1, 16) }, - { VLC_CODEC_GBRA_PLANAR, PLANAR_8(4, 1, 1) }, - { VLC_CODEC_GBRA_PLANAR_10L, PLANAR_16(4, 1, 1, 10) }, - { VLC_CODEC_GBRA_PLANAR_10B, PLANAR_16(4, 1, 1, 10) }, - { VLC_CODEC_GBRA_PLANAR_12L, PLANAR_16(4, 1, 1, 12) }, - { VLC_CODEC_GBRA_PLANAR_12B, PLANAR_16(4, 1, 1, 12) }, - { VLC_CODEC_GBRA_PLANAR_16L, PLANAR_16(4, 1, 1, 16) }, - { VLC_CODEC_GBRA_PLANAR_16B, PLANAR_16(4, 1, 1, 16) }, - - { VLC_CODEC_I420_16L, PLANAR_16(3, 2, 2, 16) }, - { VLC_CODEC_I420_16B, PLANAR_16(3, 2, 2, 16) }, - { VLC_CODEC_I420_12L, PLANAR_16(3, 2, 2, 12) }, - { VLC_CODEC_I420_12B, PLANAR_16(3, 2, 2, 12) }, - { VLC_CODEC_I420_10L, PLANAR_16(3, 2, 2, 10) }, - { VLC_CODEC_I420_10B, PLANAR_16(3, 2, 2, 10) }, - { VLC_CODEC_I420_9L, PLANAR_16(3, 2, 2, 9) }, - { VLC_CODEC_I420_9B, PLANAR_16(3, 2, 2, 9) }, - { VLC_CODEC_I422_16L, PLANAR_16(3, 2, 1, 16) }, - { VLC_CODEC_I422_16B, PLANAR_16(3, 2, 1, 16) }, - { VLC_CODEC_I422_12L, PLANAR_16(3, 2, 1, 12) }, - { VLC_CODEC_I422_12B, PLANAR_16(3, 2, 1, 12) }, - { VLC_CODEC_I422_10L, PLANAR_16(3, 2, 1, 10) }, - { VLC_CODEC_I422_10B, PLANAR_16(3, 2, 1, 10) }, - { VLC_CODEC_I422_9L, PLANAR_16(3, 2, 1, 9) }, - { VLC_CODEC_I422_9B, PLANAR_16(3, 2, 1, 9) }, - { VLC_CODEC_I444_12L, PLANAR_16(3, 1, 1, 12) }, - { VLC_CODEC_I444_12B, PLANAR_16(3, 1, 1, 12) }, - { VLC_CODEC_I444_10L, PLANAR_16(3, 1, 1, 10) }, - { VLC_CODEC_I444_10B, PLANAR_16(3, 1, 1, 10) }, - { VLC_CODEC_I444_9L, PLANAR_16(3, 1, 1, 9) }, - { VLC_CODEC_I444_9B, PLANAR_16(3, 1, 1, 9) }, - { VLC_CODEC_I444_16L, PLANAR_16(3, 1, 1, 16) }, - { VLC_CODEC_I444_16B, PLANAR_16(3, 1, 1, 16) }, - { VLC_CODEC_YUVA_444_10L, PLANAR_16(4, 1, 1, 10) }, - { VLC_CODEC_YUVA_444_10B, PLANAR_16(4, 1, 1, 10) }, - { VLC_CODEC_YUVA_444_12L, PLANAR_16(4, 1, 1, 12) }, - { VLC_CODEC_YUVA_444_12B, PLANAR_16(4, 1, 1, 12) }, - { VLC_CODEC_P010, SEMIPLANAR(2, 2, 10) }, - { VLC_CODEC_P012, SEMIPLANAR(2, 2, 12) }, - { VLC_CODEC_P016, SEMIPLANAR(2, 2, 16) }, - - { VLC_CODEC_V308, PACKED_FMT(1, 24) }, - { VLC_CODEC_YUYV, PACKED_FMT(2, 16) }, - { VLC_CODEC_YVYU, PACKED_FMT(2, 16) }, - { VLC_CODEC_UYVY, PACKED_FMT(2, 16) }, - { VLC_CODEC_VYUY, PACKED_FMT(2, 16) }, - { VLC_CODEC_YUV2, PACKED_FMT(2, 16) }, - { VLC_CODEC_RGB233, PACKED_FMT(1, 8) }, - { VLC_CODEC_BGR233, PACKED_FMT(1, 8) }, - { VLC_CODEC_RGB332, PACKED_FMT(1, 8) }, - { VLC_CODEC_YUVP, PACKED_FMT(1, 8) }, - { VLC_CODEC_RGBP, PACKED_FMT(1, 8) }, - { VLC_CODEC_GREY, PACKED_FMT(1, 8) }, - { VLC_CODEC_GREY_10L, PACKED_FMT(2, 10) }, - { VLC_CODEC_GREY_10B, PACKED_FMT(2, 10) }, - { VLC_CODEC_GREY_12L, PACKED_FMT(2, 12) }, - { VLC_CODEC_GREY_12B, PACKED_FMT(2, 12) }, - { VLC_CODEC_GREY_16L, PACKED_FMT(2, 16) }, - { VLC_CODEC_GREY_16B, PACKED_FMT(2, 16) }, - - { VLC_CODEC_RGB555BE, PACKED_FMT(2, 15) }, - { VLC_CODEC_RGB555LE, PACKED_FMT(2, 15) }, - { VLC_CODEC_BGR555LE, PACKED_FMT(2, 15) }, - { VLC_CODEC_BGR555BE, PACKED_FMT(2, 15) }, - { VLC_CODEC_RGB565LE, PACKED_FMT(2, 16) }, - { VLC_CODEC_RGB565BE, PACKED_FMT(2, 16) }, - { VLC_CODEC_BGR565LE, PACKED_FMT(2, 16) }, - { VLC_CODEC_BGR565BE, PACKED_FMT(2, 16) }, - { VLC_CODEC_RGB24, PACKED_FMT(3, 24) }, - { VLC_CODEC_BGR24, PACKED_FMT(3, 24) }, - { VLC_CODEC_RGBX, PACKED_FMT(4, 24) }, - { VLC_CODEC_XRGB, PACKED_FMT(4, 24) }, - { VLC_CODEC_BGRX, PACKED_FMT(4, 24) }, - { VLC_CODEC_XBGR, PACKED_FMT(4, 24) }, - { VLC_CODEC_RGBA, PACKED_FMT(4, 32) }, - { VLC_CODEC_ARGB, PACKED_FMT(4, 32) }, - { VLC_CODEC_BGRA, PACKED_FMT(4, 32) }, - { VLC_CODEC_ABGR, PACKED_FMT(4, 32) }, - { VLC_CODEC_RGBA10LE, PACKED_FMT(4, 32) }, - { VLC_CODEC_RGBA64, PACKED_FMT(8, 64) }, - { VLC_CODEC_VUYA, PACKED_FMT(4, 32) }, - { VLC_CODEC_Y210, PACKED_FMT(4, 32) }, - { VLC_CODEC_Y410, PACKED_FMT(4, 32) }, - - { VLC_CODEC_Y211, 1, { {{1,4}, {1,1}} }, 4, 32 }, - { VLC_CODEC_XYZ_12L, PACKED_FMT(6, 48) }, - { VLC_CODEC_XYZ_12B, PACKED_FMT(6, 48) }, - - { VLC_CODEC_VDPAU_VIDEO, FAKE_FMT() }, - { VLC_CODEC_VDPAU_OUTPUT, FAKE_FMT() }, - { VLC_CODEC_ANDROID_OPAQUE, FAKE_FMT() }, - { VLC_CODEC_MMAL_OPAQUE, FAKE_FMT() }, - { VLC_CODEC_D3D9_OPAQUE, FAKE_FMT() }, - { VLC_CODEC_D3D11_OPAQUE, FAKE_FMT() }, - { VLC_CODEC_D3D9_OPAQUE_10B, FAKE_FMT() }, - { VLC_CODEC_D3D11_OPAQUE_10B, FAKE_FMT() }, - { VLC_CODEC_D3D11_OPAQUE_RGBA, FAKE_FMT() }, - { VLC_CODEC_D3D11_OPAQUE_BGRA, FAKE_FMT() }, - { VLC_CODEC_D3D11_OPAQUE_ALPHA, FAKE_FMT() }, - - { VLC_CODEC_NVDEC_OPAQUE_16B, FAKE_FMT() }, - { VLC_CODEC_NVDEC_OPAQUE_10B, FAKE_FMT() }, - { VLC_CODEC_NVDEC_OPAQUE, FAKE_FMT() }, - - { VLC_CODEC_NVDEC_OPAQUE_444, FAKE_FMT() }, - { VLC_CODEC_NVDEC_OPAQUE_444_16B, FAKE_FMT() }, - - { VLC_CODEC_CVPX_NV12, FAKE_FMT() }, - { VLC_CODEC_CVPX_UYVY, FAKE_FMT() }, - { VLC_CODEC_CVPX_I420, FAKE_FMT() }, - { VLC_CODEC_CVPX_BGRA, FAKE_FMT() }, - - { VLC_CODEC_CVPX_P010, FAKE_FMT() }, - - { VLC_CODEC_GST_MEM_OPAQUE, FAKE_FMT() }, - - { VLC_CODEC_VAAPI_420, FAKE_FMT() }, - { VLC_CODEC_VAAPI_420_10BPP, FAKE_FMT() }, - { VLC_CODEC_VAAPI_420_12BPP, FAKE_FMT() }, + { VLC_CODEC_I411, PLANAR_8(YUV411, 3, 4, 1) }, + { VLC_CODEC_I410, PLANAR_8(YUV411, 3, 4, 4) }, + { VLC_CODEC_I420, PLANAR_8(YUV420, 3, 2, 2) }, + { VLC_CODEC_YV12, PLANAR_8(YUV420, 3, 2, 2) }, + { VLC_CODEC_NV12, SEMIPLANAR(YUV420, 2, 2, 8) }, + { VLC_CODEC_NV21, SEMIPLANAR(YUV420, 2, 2, 8) }, + { VLC_CODEC_I422, PLANAR_8(YUV422, 3, 2, 1) }, + { VLC_CODEC_NV16, SEMIPLANAR(YUV422, 2, 1, 8) }, + { VLC_CODEC_NV61, SEMIPLANAR(YUV422, 2, 1, 8) }, + { VLC_CODEC_I440, PLANAR_8(YUV440, 3, 1, 2) }, + { VLC_CODEC_I444, PLANAR_8(YUV444, 3, 1, 1) }, + { VLC_CODEC_NV24, SEMIPLANAR(YUV444, 1, 1, 8) }, + { VLC_CODEC_NV42, SEMIPLANAR(YUV444, 1, 1, 8) }, + { VLC_CODEC_YUVA, PLANAR_8(YUV444, 4, 1, 1) }, + { VLC_CODEC_YUV420A, PLANAR_8(YUV420, 4, 2, 2) }, + { VLC_CODEC_YUV422A, PLANAR_8(YUV422, 4, 2, 1) }, + + { VLC_CODEC_GBR_PLANAR, PLANAR_8(RGB, 3, 1, 1) }, + { VLC_CODEC_GBR_PLANAR_9L, PLANAR_16(RGB, 3, 1, 1, 9) }, + { VLC_CODEC_GBR_PLANAR_9B, PLANAR_16(RGB, 3, 1, 1, 9) }, + { VLC_CODEC_GBR_PLANAR_10L, PLANAR_16(RGB, 3, 1, 1, 10) }, + { VLC_CODEC_GBR_PLANAR_10B, PLANAR_16(RGB, 3, 1, 1, 10) }, + { VLC_CODEC_GBR_PLANAR_12L, PLANAR_16(RGB, 3, 1, 1, 12) }, + { VLC_CODEC_GBR_PLANAR_12B, PLANAR_16(RGB, 3, 1, 1, 12) }, + { VLC_CODEC_GBR_PLANAR_14L, PLANAR_16(RGB, 3, 1, 1, 14) }, + { VLC_CODEC_GBR_PLANAR_14B, PLANAR_16(RGB, 3, 1, 1, 14) }, + { VLC_CODEC_GBR_PLANAR_16L, PLANAR_16(RGB, 3, 1, 1, 16) }, + { VLC_CODEC_GBR_PLANAR_16B, PLANAR_16(RGB, 3, 1, 1, 16) }, + { VLC_CODEC_GBRA_PLANAR, PLANAR_8(RGB, 4, 1, 1) }, + { VLC_CODEC_GBRA_PLANAR_10L, PLANAR_16(RGB, 4, 1, 1, 10) }, + { VLC_CODEC_GBRA_PLANAR_10B, PLANAR_16(RGB, 4, 1, 1, 10) }, + { VLC_CODEC_GBRA_PLANAR_12L, PLANAR_16(RGB, 4, 1, 1, 12) }, + { VLC_CODEC_GBRA_PLANAR_12B, PLANAR_16(RGB, 4, 1, 1, 12) }, + { VLC_CODEC_GBRA_PLANAR_16L, PLANAR_16(RGB, 4, 1, 1, 16) }, + { VLC_CODEC_GBRA_PLANAR_16B, PLANAR_16(RGB, 4, 1, 1, 16) }, + + { VLC_CODEC_I420_16L, PLANAR_16(YUV420, 3, 2, 2, 16) }, + { VLC_CODEC_I420_16B, PLANAR_16(YUV420, 3, 2, 2, 16) }, + { VLC_CODEC_I420_12L, PLANAR_16(YUV420, 3, 2, 2, 12) }, + { VLC_CODEC_I420_12B, PLANAR_16(YUV420, 3, 2, 2, 12) }, + { VLC_CODEC_I420_10L, PLANAR_16(YUV420, 3, 2, 2, 10) }, + { VLC_CODEC_I420_10B, PLANAR_16(YUV420, 3, 2, 2, 10) }, + { VLC_CODEC_I420_9L, PLANAR_16(YUV420, 3, 2, 2, 9) }, + { VLC_CODEC_I420_9B, PLANAR_16(YUV420, 3, 2, 2, 9) }, + { VLC_CODEC_I422_16L, PLANAR_16(YUV422, 3, 2, 1, 16) }, + { VLC_CODEC_I422_16B, PLANAR_16(YUV422, 3, 2, 1, 16) }, + { VLC_CODEC_I422_12L, PLANAR_16(YUV422, 3, 2, 1, 12) }, + { VLC_CODEC_I422_12B, PLANAR_16(YUV422, 3, 2, 1, 12) }, + { VLC_CODEC_I422_10L, PLANAR_16(YUV422, 3, 2, 1, 10) }, + { VLC_CODEC_I422_10B, PLANAR_16(YUV422, 3, 2, 1, 10) }, + { VLC_CODEC_I422_9L, PLANAR_16(YUV422, 3, 2, 1, 9) }, + { VLC_CODEC_I422_9B, PLANAR_16(YUV422, 3, 2, 1, 9) }, + { VLC_CODEC_I444_12L, PLANAR_16(YUV444, 3, 1, 1, 12) }, + { VLC_CODEC_I444_12B, PLANAR_16(YUV444, 3, 1, 1, 12) }, + { VLC_CODEC_I444_10L, PLANAR_16(YUV444, 3, 1, 1, 10) }, + { VLC_CODEC_I444_10B, PLANAR_16(YUV444, 3, 1, 1, 10) }, + { VLC_CODEC_I444_9L, PLANAR_16(YUV444, 3, 1, 1, 9) }, + { VLC_CODEC_I444_9B, PLANAR_16(YUV444, 3, 1, 1, 9) }, + { VLC_CODEC_I444_16L, PLANAR_16(YUV444, 3, 1, 1, 16) }, + { VLC_CODEC_I444_16B, PLANAR_16(YUV444, 3, 1, 1, 16) }, + { VLC_CODEC_YUVA_444_10L, PLANAR_16(YUV444, 4, 1, 1, 10) }, + { VLC_CODEC_YUVA_444_10B, PLANAR_16(YUV444, 4, 1, 1, 10) }, + { VLC_CODEC_YUVA_444_12L, PLANAR_16(YUV444, 4, 1, 1, 12) }, + { VLC_CODEC_YUVA_444_12B, PLANAR_16(YUV444, 4, 1, 1, 12) }, + { VLC_CODEC_P010, SEMIPLANAR(YUV420, 2, 2, 10) }, + { VLC_CODEC_P012, SEMIPLANAR(YUV420, 2, 2, 12) }, + { VLC_CODEC_P016, SEMIPLANAR(YUV420, 2, 2, 16) }, + + { VLC_CODEC_V308, PACKED_FMT(YUV444, 1, 24, 8) }, + { VLC_CODEC_YUYV, PACKED_FMT(YUV422, 2, 16, 8) }, + { VLC_CODEC_YVYU, PACKED_FMT(YUV422, 2, 16, 8) }, + { VLC_CODEC_UYVY, PACKED_FMT(YUV422, 2, 16, 8) }, + { VLC_CODEC_VYUY, PACKED_FMT(YUV422, 2, 16, 8) }, + { VLC_CODEC_YUV2, PACKED_FMT(YUV422, 2, 16, 8) }, + { VLC_CODEC_RGB233, PACKED_FMT(RGB, 1, 8, 2.6) }, + { VLC_CODEC_BGR233, PACKED_FMT(RGB, 1, 8, 2.6) }, + { VLC_CODEC_RGB332, PACKED_FMT(RGB, 1, 8, 2.6) }, + { VLC_CODEC_YUVP, PACKED_FMT(OTHER, 1, 8, 0) }, + { VLC_CODEC_RGBP, PACKED_FMT(OTHER, 1, 8, 0) }, + { VLC_CODEC_GREY, PACKED_FMT(GREY, 1, 8, 8) }, + { VLC_CODEC_GREY_10L, PACKED_FMT(GREY, 2, 10, 10) }, + { VLC_CODEC_GREY_10B, PACKED_FMT(GREY, 2, 10, 10) }, + { VLC_CODEC_GREY_12L, PACKED_FMT(GREY, 2, 12, 12) }, + { VLC_CODEC_GREY_12B, PACKED_FMT(GREY, 2, 12, 12) }, + { VLC_CODEC_GREY_16L, PACKED_FMT(GREY, 2, 16, 16) }, + { VLC_CODEC_GREY_16B, PACKED_FMT(GREY, 2, 16, 16) }, + + { VLC_CODEC_RGB555BE, PACKED_FMT(RGB, 2, 15, 5) }, + { VLC_CODEC_RGB555LE, PACKED_FMT(RGB, 2, 15, 5) }, + { VLC_CODEC_BGR555LE, PACKED_FMT(RGB, 2, 15, 5) }, + { VLC_CODEC_BGR555BE, PACKED_FMT(RGB, 2, 15, 5) }, + { VLC_CODEC_RGB565LE, PACKED_FMT(RGB, 2, 16, 5.3) }, + { VLC_CODEC_RGB565BE, PACKED_FMT(RGB, 2, 16, 5.3) }, + { VLC_CODEC_BGR565LE, PACKED_FMT(RGB, 2, 16, 5.3), }, + { VLC_CODEC_BGR565BE, PACKED_FMT(RGB, 2, 16, 5.3) }, + { VLC_CODEC_RGB24, PACKED_FMT(RGB, 3, 24, 8) }, + { VLC_CODEC_BGR24, PACKED_FMT(RGB, 3, 24, 8) }, + { VLC_CODEC_RGBX, PACKED_FMT(RGB, 4, 24, 8) }, + { VLC_CODEC_XRGB, PACKED_FMT(RGB, 4, 24, 8) }, + { VLC_CODEC_BGRX, PACKED_FMT(RGB, 4, 24, 8) }, + { VLC_CODEC_XBGR, PACKED_FMT(RGB, 4, 24, 8) }, + { VLC_CODEC_RGBA, PACKED_FMT(RGB, 4, 32, 8) }, + { VLC_CODEC_ARGB, PACKED_FMT(RGB, 4, 32, 8) }, + { VLC_CODEC_BGRA, PACKED_FMT(RGB, 4, 32, 8) }, + { VLC_CODEC_ABGR, PACKED_FMT(RGB, 4, 32, 8) }, + { VLC_CODEC_RGBA10LE, PACKED_FMT(RGB, 4, 32, 10) }, + { VLC_CODEC_RGBA64, PACKED_FMT(RGB, 8, 64, 16) }, + { VLC_CODEC_VUYA, PACKED_FMT(YUV444, 4, 32, 8) }, + { VLC_CODEC_Y210, PACKED_FMT(YUV422, 4, 32, 10) }, + { VLC_CODEC_Y410, PACKED_FMT(YUV444, 4, 32, 10) }, + + { VLC_CODEC_Y211, VLC_CHROMA_SUBTYPE_YUV211,1, { {{1,4}, {1,1}} }, 4, 32, 8 }, + { VLC_CODEC_XYZ_12L, PACKED_FMT(OTHER, 6, 48, 12) }, + { VLC_CODEC_XYZ_12B, PACKED_FMT(OTHER, 6, 48, 12) }, + + { VLC_CODEC_VDPAU_VIDEO, GPU_FMT(YUV420, 8) }, + { VLC_CODEC_VDPAU_OUTPUT, GPU_FMT(RGB, 8) }, + { VLC_CODEC_ANDROID_OPAQUE, GPU_FMT(OTHER, 0) }, + { VLC_CODEC_MMAL_OPAQUE, GPU_FMT(OTHER, 0) }, + { VLC_CODEC_D3D9_OPAQUE, GPU_FMT(YUV420, 8) }, + { VLC_CODEC_D3D11_OPAQUE, GPU_FMT(YUV420, 8) }, + { VLC_CODEC_D3D9_OPAQUE_10B, GPU_FMT(YUV420, 10) }, + { VLC_CODEC_D3D11_OPAQUE_10B, GPU_FMT(YUV420, 10) }, + { VLC_CODEC_D3D11_OPAQUE_RGBA, GPU_FMT(RGB, 8) }, + { VLC_CODEC_D3D11_OPAQUE_BGRA, GPU_FMT(RGB, 8) }, + { VLC_CODEC_D3D11_OPAQUE_ALPHA, GPU_FMT(YUV420, 8) }, + + { VLC_CODEC_NVDEC_OPAQUE_16B, GPU_FMT(YUV420, 16) }, + { VLC_CODEC_NVDEC_OPAQUE_10B, GPU_FMT(YUV420, 10) }, + { VLC_CODEC_NVDEC_OPAQUE, GPU_FMT(YUV420, 8) }, + + { VLC_CODEC_NVDEC_OPAQUE_444, GPU_FMT(YUV444, 8) }, + { VLC_CODEC_NVDEC_OPAQUE_444_16B, GPU_FMT(YUV444, 16) }, + + { VLC_CODEC_CVPX_NV12, GPU_FMT(YUV420, 8) }, + { VLC_CODEC_CVPX_UYVY, GPU_FMT(YUV422, 8) }, + { VLC_CODEC_CVPX_I420, GPU_FMT(YUV420, 8) }, + { VLC_CODEC_CVPX_BGRA, GPU_FMT(RGB, 8) }, + + { VLC_CODEC_CVPX_P010, GPU_FMT(YUV420, 10) }, + + { VLC_CODEC_GST_MEM_OPAQUE, GPU_FMT(OTHER, 0) }, + + { VLC_CODEC_VAAPI_420, GPU_FMT(YUV420, 8) }, + { VLC_CODEC_VAAPI_420_10BPP, GPU_FMT(YUV420, 10) }, + { VLC_CODEC_VAAPI_420_12BPP, GPU_FMT(YUV420, 12) }, }; #undef PACKED_FMT diff --git a/test/Makefile.am b/test/Makefile.am index ac13c9c6366413f4d3e3a9cc8e3b0be8afe4eb97..ac59418b15090f4ede571d9a2016bc7b342702a1 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -37,6 +37,7 @@ check_PROGRAMS = \ test_src_interface_dialog \ test_src_media_source \ test_src_misc_bits \ + test_src_misc_chroma_probe \ test_src_misc_epg \ test_src_misc_keystore \ test_src_misc_image \ @@ -219,6 +220,9 @@ test_src_input_decoder_SOURCES = \ src/input/decoder/input_decoder_scenarios.c test_src_input_decoder_LDADD = $(LIBVLCCORE) $(LIBVLC) +test_src_misc_chroma_probe_SOURCES = src/misc/chroma_probe.c +test_src_misc_chroma_probe_LDADD = $(LIBVLCCORE) $(LIBVLC) + test_src_misc_image_SOURCES = src/misc/image.c test_src_misc_image_LDADD = $(LIBVLCCORE) $(LIBVLC) diff --git a/test/src/misc/chroma_probe.c b/test/src/misc/chroma_probe.c new file mode 100644 index 0000000000000000000000000000000000000000..f2849baca0a8e9fb347a209980355f3588483b9f --- /dev/null +++ b/test/src/misc/chroma_probe.c @@ -0,0 +1,379 @@ +/***************************************************************************** + * chroma_probe.c: test for chroma_probe + ***************************************************************************** + * Copyright (C) 2025 VLC authors and VideoLAN + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +/* Define a builtin module for mocked parts */ +#define MODULE_NAME test_chroma_probe +#undef VLC_DYNAMIC_PLUGIN +#include "../../libvlc/test.h" + +#include <vlc/vlc.h> + +#include <vlc_common.h> +#include <vlc_plugin.h> +#include <vlc_chroma_probe.h> +#include <vlc_fourcc.h> + +#include <assert.h> + +const char vlc_module_name[] = MODULE_STRING; + +#define RESULT_MAX 6 +struct scenario_result +{ + unsigned cost; + unsigned quality; + vlc_fourcc_t chain[VLC_CHROMA_CONV_CHAIN_COUNT_MAX - 1 /* exclude 'from' */]; +}; + +struct scenario +{ + unsigned max_indirect_steps; + int flags; + vlc_fourcc_t in; + vlc_fourcc_t out; + struct scenario_result results[RESULT_MAX]; + size_t result_count; +}; + +static const struct scenario scenario_array[] = +{ +#define COST VLC_CHROMA_CONV_FLAG_SORT_COST +#define ONLY_YUV VLC_CHROMA_CONV_FLAG_ONLY_YUV +#define ONLY_RGB VLC_CHROMA_CONV_FLAG_ONLY_RGB +#define RESULT(cost, quality, chain0, chain1 ) \ + { cost, quality, { chain0, chain1 } } + +#define SCENARIO0(max_indirect_steps_, from, to) { \ + .max_indirect_steps = max_indirect_steps_, \ + .flags = 0, \ + .in = from, .out = to, \ + .result_count = 0, \ +} + +#define SCENARIO1(max_indirect_steps_, sort_, from, to, cost, quality, chain0) { \ + .max_indirect_steps = max_indirect_steps_, \ + .flags = sort_, \ + .in = from, .out = to, \ + .results = { RESULT(cost, quality, chain0, 0) }, \ + .result_count = 1, \ +} + +#define SCENARIO2(max_indirect_steps_, sort_, from, to, \ + result0_cost, result0_quality, result0_chain0, \ + result1_cost, result1_quality, result1_chain0) { \ + .max_indirect_steps = max_indirect_steps_, \ + .flags = sort_, \ + .in = from, .out = to, \ + .results = { RESULT(result0_cost, result0_quality, result0_chain0, 0), \ + RESULT(result1_cost, result1_quality, result1_chain0, 0), }, \ + .result_count = 2, \ +} + +#define SCENARIOX(max_indirect_steps_, sort_, from, to, count, ...) { \ + .max_indirect_steps = max_indirect_steps_, \ + .flags = sort_, \ + .in = from, .out = to, \ + .results = { __VA_ARGS__ }, \ + .result_count = count, \ +} + + /* Success with a depth of 0 (Direct conversion) */ + SCENARIO1(0, 0, VLC_CODEC_VAAPI_420, VLC_CODEC_I420, 26, 100, 0), + + /* Success with a depth of 1 */ + SCENARIO1(1, 0, VLC_CODEC_VAAPI_420_10BPP, VLC_CODEC_I420, + 47, 80, VLC_CODEC_P010), + + /* Fail because it require a depth of 1 */ + SCENARIO0(0, VLC_CODEC_VAAPI_420_10BPP, VLC_CODEC_I420), + + /* Check duplicated entries are removed and that we keep the lowest cost */ + SCENARIO1(1, 0, VLC_CODEC_NV12, VLC_CODEC_I420, + 18, 100, 0), + + /* Check two_way is doing as expected */ + SCENARIO1(1, 0, VLC_CODEC_I420, VLC_CODEC_VAAPI_420_10BPP, + 47, 100, VLC_CODEC_P010), + + /* Fail because it requires a depth of 2 */ + SCENARIO0(1, VLC_CODEC_CVPX_P010, VLC_CODEC_P010), + + /* Fail because conversion is not two-way */ + SCENARIO0(1, VLC_CODEC_P010, VLC_CODEC_CVPX_P010), + + /* Check low cost of GPU <-> GPU */ + SCENARIO1(1, 0, VLC_CODEC_CVPX_P010, VLC_CODEC_CVPX_BGRA, 11, 80, 0), + + /* Check cost and quality of direct conversion */ + SCENARIO1(0, 0, VLC_CODEC_YUVA_444_12L, VLC_CODEC_I420, 60, 33, 0), + + /* Check 1 depth conversions are correctly sorted */ + SCENARIOX(1, 0, VLC_CODEC_VAAPI_420_10BPP, 0, 6, + RESULT(33, 100, VLC_CODEC_P010, 0), + RESULT(33, 100, VLC_CODEC_I420_10L, 0), + RESULT(66, 100, VLC_CODEC_P010, VLC_CODEC_I420_10L), + RESULT(66, 100, VLC_CODEC_I420_10L, VLC_CODEC_P010), + RESULT(47, 80, VLC_CODEC_P010, VLC_CODEC_I420), + RESULT(84, 72, VLC_CODEC_P010, VLC_CODEC_RGBA)), + + /* Check default QUALITY order */ + SCENARIOX(0, 0, VLC_CODEC_YUVA_444_12L, 0, 4, + RESULT(112, 90, VLC_CODEC_RGBA64, 0), + RESULT(88, 83, VLC_CODEC_YUVA_444_10L, 0), + RESULT(80, 60, VLC_CODEC_RGBA, 0), + RESULT(60, 33, VLC_CODEC_I420, 0)), + + /* Check ONLY_YUV */ + SCENARIOX(0, ONLY_YUV, VLC_CODEC_YUVA_444_12L, 0, 2, + RESULT(88, 83, VLC_CODEC_YUVA_444_10L, 0), + RESULT(60, 33, VLC_CODEC_I420, 0)), + + /* Check ONLY_RGB */ + SCENARIOX(0, ONLY_RGB, VLC_CODEC_YUVA_444_12L, 0, 2, + RESULT(112, 90, VLC_CODEC_RGBA64, 0), + RESULT(80, 60, VLC_CODEC_RGBA, 0)), + + /* Check COST order */ + SCENARIOX(0, COST, VLC_CODEC_YUVA_444_12L, 0, 4, + RESULT(60, 33, VLC_CODEC_I420, 0), + RESULT(80, 60, VLC_CODEC_RGBA, 0), + RESULT(88, 83, VLC_CODEC_YUVA_444_10L, 0), + RESULT(112, 90, VLC_CODEC_RGBA64, 0)), + + /* Check VLC_CHROMA_CONV_ADD_IN_OUTTLIST, and quality order with smaller + * RGB chromas */ + SCENARIOX(0, 0, VLC_CODEC_YV12, 0, 5, + RESULT(36, 90, VLC_CODEC_XRGB, 0), + RESULT(28, 59, VLC_CODEC_RGB565, 0), + RESULT(28, 59, VLC_CODEC_BGR565, 0), + RESULT(27, 56, VLC_CODEC_RGB555, 0), + RESULT(27, 56, VLC_CODEC_BGR555, 0)), + + /* Check VLC_CHROMA_CONV_ADD_OUT_INLIST */ + SCENARIO1(0, 0, VLC_CODEC_NV16, VLC_CODEC_I422, 32, 100, 0), + SCENARIO1(0, 0, VLC_CODEC_YUYV, VLC_CODEC_I422, 32, 100, 0), + SCENARIO1(0, 0, VLC_CODEC_UYVY, VLC_CODEC_I422, 32, 100, 0), + + /* Check VLC_CHROMA_CONV_ADD_ALL */ + SCENARIO1(1, 0, VLC_CODEC_I444_12L, VLC_CODEC_I444, 60, 66, 0), + SCENARIO1(1, 0, VLC_CODEC_I444, VLC_CODEC_I444_12L, 60, 100, 0), + SCENARIO1(1, 0, VLC_CODEC_I444_12L, VLC_CODEC_I444_10L, 66, 83, 0), + SCENARIO1(1, 0, VLC_CODEC_I444_10L, VLC_CODEC_I444_12L, 66, 100, 0), +}; + +static void ProbeChroma(vlc_chroma_conv_vec *vec) +{ + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_VAAPI_420, VLC_CODEC_I420, true); + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_VAAPI_420_10BPP, VLC_CODEC_P010, true); + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_VAAPI_420_10BPP, VLC_CODEC_I420_10L, true); + + vlc_chroma_conv_add(vec, 0.75, VLC_CODEC_I420, VLC_CODEC_NV12, true); + vlc_chroma_conv_add(vec, 0.75, VLC_CODEC_I420, VLC_CODEC_P010, true); + vlc_chroma_conv_add(vec, 1, VLC_CODEC_I420_10L, VLC_CODEC_P010, true); + vlc_chroma_conv_add(vec, 1, VLC_CODEC_RGBA, VLC_CODEC_P010, true); + vlc_chroma_conv_add(vec, 1, VLC_CODEC_RGBA, VLC_CODEC_NV12, true); + + /* Test duplicated entries are removed */ + vlc_chroma_conv_add(vec, 1.0, VLC_CODEC_I420, VLC_CODEC_NV12, true); + + /* Don't change this order as this is used to test to cost sort + * (we don't want the result to be naturally sorted) */ + vlc_chroma_conv_add(vec, 1, VLC_CODEC_YUVA_444_12L, VLC_CODEC_RGBA, true); + vlc_chroma_conv_add(vec, 1, VLC_CODEC_YUVA_444_12L, VLC_CODEC_I420, true); + + vlc_chroma_conv_add(vec, 1, VLC_CODEC_YUVA_444_12L, VLC_CODEC_YUVA_444_10L, true); + vlc_chroma_conv_add(vec, 1, VLC_CODEC_YUVA_444_12L, VLC_CODEC_RGBA64, true); + + vlc_chroma_conv_add(vec, 0.25, VLC_CODEC_CVPX_NV12, VLC_CODEC_CVPX_BGRA, false); + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_CVPX_NV12, VLC_CODEC_NV12, false); + vlc_chroma_conv_add(vec, 0.25, VLC_CODEC_CVPX_P010, VLC_CODEC_CVPX_BGRA, false); + vlc_chroma_conv_add(vec, 1.1, VLC_CODEC_CVPX_BGRA, VLC_CODEC_RGBA, false); + + vlc_chroma_conv_add_in_outlist(vec, 1, VLC_CODEC_YV12, VLC_CODEC_XRGB, + VLC_CODEC_RGB565, VLC_CODEC_BGR565, + VLC_CODEC_RGB555, VLC_CODEC_BGR555); + + vlc_chroma_conv_add_out_inlist(vec, 1, VLC_CODEC_I422, VLC_CODEC_NV16, + VLC_CODEC_YUYV, VLC_CODEC_UYVY); + + vlc_chroma_conv_add(vec, 1, VLC_CODEC_I444, VLC_CODEC_I444_10L, true); + vlc_chroma_conv_add(vec, 1, VLC_CODEC_I444, VLC_CODEC_I444_12L, true); + vlc_chroma_conv_add(vec, 1, VLC_CODEC_I444_10L, VLC_CODEC_I444_12L, true); + + /* Test duplicated entries are removed */ + vlc_chroma_conv_add(vec, 1.0, VLC_CODEC_I420, VLC_CODEC_NV12, true); +} + +vlc_module_begin() + set_callback_chroma_conv_probe(ProbeChroma) +vlc_module_end() + +VLC_EXPORT vlc_plugin_cb vlc_static_modules[] = { + VLC_SYMBOL(vlc_entry), + NULL +}; + +static void +print_results(const struct vlc_chroma_conv_result *array, size_t count) +{ + for (size_t i = 0; i < count; ++i) + { + const struct vlc_chroma_conv_result *res = &array[i]; + char *res_str = vlc_chroma_conv_result_ToString(res); + assert(res_str != NULL); + fprintf(stderr, "\tres[%zu]: %s\n", i, res_str); + free(res_str); + } +} + +static void +check_results(const struct scenario *scr, + const struct vlc_chroma_conv_result *results) +{ + for (size_t i = 0; i < scr->result_count; ++i) + { + const struct vlc_chroma_conv_result *result = &results[i]; + const struct scenario_result *scr_result = &scr->results[i]; + + assert(result->chain_count > 1); + assert(result->chain_count <= VLC_CHROMA_CONV_CHAIN_COUNT_MAX); + + /* Reconstruct the expected fourcc array from the scenario */ + vlc_fourcc_t scr_chain[VLC_CHROMA_CONV_CHAIN_COUNT_MAX]; + bool end_reached = false; + size_t scr_count = 1; + scr_chain[0] = scr->in; + for (size_t j = 1; j < VLC_CHROMA_CONV_CHAIN_COUNT_MAX; ++j) + { + if (end_reached) + { + scr_chain[j] = 0; + continue; + } + + if (scr_result->chain[j - 1] != 0) + { + scr_chain[j] = scr_result->chain[j - 1]; + scr_count++; + } + else + { + if (scr->out != 0) + { + scr_chain[j] = scr->out; + scr_count++; + } + end_reached = true; + } + } + + assert(scr_count == result->chain_count); + size_t j; + for (j = 0; j < result->chain_count; ++j) + assert(result->chain[j] == scr_chain[j]); + for (; j < VLC_CHROMA_CONV_CHAIN_COUNT_MAX - 1; ++j) + assert(scr_result->chain[j - 1] == 0); + + assert(result->cost == scr_result->cost); + assert(result->quality == scr_result->quality); + } +} + +int main(int argc, const char *argv[]) +{ + test_init(); + + if (argc > 1 && strlen(argv[1]) >= 4) + { + /* Disable test module (use all VLC modules) */ + vlc_static_modules[0] = NULL; + + unsigned max_indirect_steps = 1; + if (argc > 2) + max_indirect_steps = atoi(argv[2]); + + int flags = 0; + if (argc > 3) + flags = atoi(argv[3]); + + const char *f = argv[1]; + vlc_fourcc_t from_fourcc = VLC_FOURCC(f[0], f[1], f[2], f[3]); + vlc_fourcc_t to_fourcc = 0; + if (f[4] == '-' && strlen(f) >= 9) + to_fourcc = VLC_FOURCC(f[5], f[6], f[7], f[8]); + libvlc_instance_t *vlc = libvlc_new(0, NULL); + assert(vlc != NULL); + + size_t count; + struct vlc_chroma_conv_result *results = + vlc_chroma_conv_Probe(from_fourcc, to_fourcc, 0, 0, + max_indirect_steps, flags, &count); + assert(results != NULL); + print_results(results, count); + free(results); + + libvlc_release(vlc); + return 0; + } + + /* Disable all modules except the one from this test */ + const char *libvlc_argv[] = { + "--no-plugins-cache", + "--no-plugins-scan", + }; + int libvlc_argc = ARRAY_SIZE(libvlc_argv); + + libvlc_instance_t *vlc = libvlc_new(libvlc_argc, libvlc_argv); + assert(vlc != NULL); + + size_t scenario_count = ARRAY_SIZE(scenario_array); + for (size_t i = 0; i < scenario_count; i++) + { + const struct scenario *scr = &scenario_array[i]; + + fprintf(stderr, "scenario: %4.4s -> %4.4s flags: 0x%x, " + "max_indirect_steps: %u result_count: %zu\n", + (const char *)&scr->in, (const char *)&scr->out, + scr->flags, + scr->max_indirect_steps, scr->result_count); + + size_t count; + struct vlc_chroma_conv_result *results = + vlc_chroma_conv_Probe(scr->in, scr->out, 0, 0, + scr->max_indirect_steps, scr->flags, &count); + if (results == NULL) + { + assert(scr->result_count == 0); + continue; + } + print_results(results, count); + assert(count == scr->result_count); + check_results(scr, results); + free(results); + } + + libvlc_release(vlc); + + return 0; +}