| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 | /******************************************************************************    Copyright (C) 2023 by Dennis Sädtler <[email protected]>    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, see <http://www.gnu.org/licenses/>.******************************************************************************/#include "ffmpeg-utils.hpp"#include <unordered_map>#include <unordered_set>extern "C" {#include <libavformat/avformat.h>}using namespace std;vector<FFmpegCodec> GetFormatCodecs(const FFmpegFormat &format,				    bool ignore_compatibility){	vector<FFmpegCodec> codecs;	const AVCodec *codec;	void *i = 0;	while ((codec = av_codec_iterate(&i)) != nullptr) {		// Not an encoding codec		if (!av_codec_is_encoder(codec))			continue;		// Skip if not supported and compatibility check not disabled		if (!ignore_compatibility &&		    !av_codec_get_tag(format.codec_tags, codec->id)) {			continue;		}		codecs.emplace_back(codec);	}	return codecs;}static bool is_output_device(const AVClass *avclass){	if (!avclass)		return false;	switch (avclass->category) {	case AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT:	case AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT:	case AV_CLASS_CATEGORY_DEVICE_OUTPUT:		return true;	default:		return false;	}}vector<FFmpegFormat> GetSupportedFormats(){	vector<FFmpegFormat> formats;	const AVOutputFormat *output_format;	void *i = 0;	while ((output_format = av_muxer_iterate(&i)) != nullptr) {		if (is_output_device(output_format->priv_class))			continue;		formats.emplace_back(output_format);	}	return formats;}FFmpegCodec FFmpegFormat::GetDefaultEncoder(FFmpegCodecType codec_type) const{	const AVCodecID codec_id = codec_type == VIDEO ? video_codec						       : audio_codec;	if (codec_type == UNKNOWN || codec_id == AV_CODEC_ID_NONE)		return {};	if (auto codec = avcodec_find_encoder(codec_id))		return {codec};	/* Fall back to using the format name as the encoder,	 * this works for some formats such as FLV. */	return FFmpegCodec{name, codec_id, codec_type};}bool FFCodecAndFormatCompatible(const char *codec, const char *format){	if (!codec || !format)		return false;#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(59, 0, 100)	AVOutputFormat *output_format;#else	const AVOutputFormat *output_format;#endif	output_format = av_guess_format(format, nullptr, nullptr);	if (!output_format)		return false;	const AVCodecDescriptor *codec_desc =		avcodec_descriptor_get_by_name(codec);	if (!codec_desc)		return false;#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(60, 0, 100)	return avformat_query_codec(output_format, codec_desc->id,				    FF_COMPLIANCE_EXPERIMENTAL) == 1;#else	return avformat_query_codec(output_format, codec_desc->id,				    FF_COMPLIANCE_NORMAL) == 1;#endif}static const unordered_set<string> builtin_codecs = {	"h264", "hevc", "av1",       "prores",    "aac",       "opus",	"alac", "flac", "pcm_s16le", "pcm_s24le", "pcm_f32le",};bool IsBuiltinCodec(const char *codec){	return builtin_codecs.count(codec) > 0;}static const unordered_map<string, unordered_set<string>> codec_compat = {	// Technically our muxer supports HEVC and AV1 as well, but nothing else does	{"flv",	 {		 "h264",		 "aac",	 }},	{"mpegts",	 {		 "h264",		 "hevc",		 "aac",		 "opus",	 }},	{"hls",	 // Also using MPEG-TS in our case, but no Opus support	 {		 "h264",		 "hevc",		 "aac",	 }},	{"mp4",	 {		 "h264",		 "hevc",		 "av1",		 "aac",		 "opus",		 "alac",		 "flac",#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(60, 5, 100)		 // PCM in MP4 is only supported in FFmpeg > 6.0		 "pcm_s16le",		 "pcm_s24le",		 "pcm_f32le",#endif	 }},	{"fragmented_mp4",	 {		 "h264",		 "hevc",		 "av1",		 "aac",		 "opus",		 "alac",		 "flac",#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(60, 5, 100)		 "pcm_s16le",		 "pcm_s24le",		 "pcm_f32le",#endif	 }},	{"mov",	 {		 "h264",		 "hevc",		 "prores",		 "aac",		 "alac",		 "pcm_s16le",		 "pcm_s24le",		 "pcm_f32le",	 }},	{"fragmented_mov",	 {		 "h264",		 "hevc",		 "prores",		 "aac",		 "alac",		 "pcm_s16le",		 "pcm_s24le",		 "pcm_f32le",	 }},	// MKV supports everything	{"mkv", {}},};bool ContainerSupportsCodec(const string &container, const string &codec){	auto iter = codec_compat.find(container);	if (iter == codec_compat.end())		return false;	auto codecs = iter->second;	// Assume everything is supported	if (codecs.empty())		return true;	return codecs.count(codec) > 0;}
 |