From 4d016a92c876e98797c362d05468bf27d5a85414 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 9 Feb 2013 15:15:19 +0100 Subject: core: redo how codecs are mapped, remove codecs.conf Use codec names instead of FourCCs to identify codecs. Rewrite how codecs are selected and initialized. Now each decoder exports a list of decoders (and the codec it supports) via add_decoders(). The order matters, and the first decoder for a given decoder is preferred over the other decoders. E.g. all ad_mpg123 decoders are preferred over ad_lavc, because it comes first in the mpcodecs_ad_drivers array. Likewise, decoders within ad_lavc that are enumerated first by libavcodec (using av_codec_next()) are preferred. (This is actually critical to select h264 software decoding by default instead of vdpau. libavcodec and ffmpeg/avconv use the same method to select decoders by default, so we hope this is sane.) The codec names follow libavcodec's codec names as defined by AVCodecDescriptor.name (see libavcodec/codec_desc.c). Some decoders have names different from the canonical codec name. The AVCodecDescriptor API is relatively new, so we need a compatibility layer for older libavcodec versions for codec names that are referenced internally, and which are different from the decoder name. (Add a configure check for that, because checking versions is getting way too messy.) demux/codec_tags.c is generated from the former codecs.conf (minus "special" decoders like vdpau, and excluding the mappings that are the same as the mappings libavformat's exported RIFF tables). It contains all the mappings from FourCCs to codec name. This is needed for demux_mkv, demux_mpg, demux_avi and demux_asf. demux_lavf will set the codec as determined by libavformat, while the other demuxers have to do this on their own, using the mp_set_audio/video_codec_from_tag() functions. Note that the sh_audio/video->format members don't uniquely identify the codec anymore, and sh->codec takes over this role. Replace the --ac/--vc/--afm/--vfm with new --vd/--ad options, which provide cover the functionality of the removed switched. Note: there's no CODECS_FLAG_FLIP flag anymore. This means some obscure container/video combinations (e.g. the sample Film_200_zygo_pro.mov) are played flipped. ffplay/avplay doesn't handle this properly either, so we don't care and blame ffmeg/libav instead. --- .gitignore | 1 - DOCS/OUTDATED-tech/codecs.conf.txt | 214 ---- DOCS/man/en/changes.rst | 1 + DOCS/man/en/input.rst | 4 +- DOCS/man/en/options.rst | 67 +- DOCS/tech-overview.txt | 6 +- Makefile | 9 +- audio/decode/ad.c | 4 +- audio/decode/ad.h | 9 +- audio/decode/ad_internal.h | 8 +- audio/decode/ad_lavc.c | 64 +- audio/decode/ad_mpg123.c | 16 +- audio/decode/ad_spdif.c | 54 +- audio/decode/dec_audio.c | 228 ++-- audio/decode/dec_audio.h | 7 +- audio/out/ao.h | 8 +- configure | 24 + core/av_common.c | 130 +++ core/av_common.h | 30 + core/cfg-mplayer.h | 9 +- core/codec-cfg.c | 607 ---------- core/codec-cfg.h | 79 -- core/codecs.c | 147 +++ core/codecs.h | 43 + core/command.c | 62 +- core/defaultopts.c | 2 + core/m_property.c | 2 + core/mp_common.h | 7 + core/mpc_info.h | 44 - core/mplayer.c | 95 +- core/options.h | 4 +- demux/asfheader.c | 4 + demux/aviheader.c | 3 + demux/codec_tags.c | 379 +++++++ demux/codec_tags.h | 31 + demux/demux.c | 66 +- demux/demux_lavf.c | 19 +- demux/demux_mkv.c | 11 +- demux/demux_mng.c | 4 +- demux/demux_mpg.c | 5 + demux/demux_rawaudio.c | 15 +- demux/demux_rawvideo.c | 14 +- demux/demux_ts.c | 4 + demux/stheader.h | 14 +- etc/codecs.conf | 2210 ------------------------------------ stream/tv.c | 10 +- video/decode/dec_video.c | 224 ++-- video/decode/dec_video.h | 6 +- video/decode/lavc.h | 2 +- video/decode/vd.c | 4 +- video/decode/vd.h | 9 +- video/decode/vd_lavc.c | 116 +- video/filter/vf.h | 1 - video/img_fourcc.h | 10 - 54 files changed, 1220 insertions(+), 3926 deletions(-) delete mode 100644 DOCS/OUTDATED-tech/codecs.conf.txt create mode 100644 core/av_common.c create mode 100644 core/av_common.h delete mode 100644 core/codec-cfg.c delete mode 100644 core/codec-cfg.h create mode 100644 core/codecs.c create mode 100644 core/codecs.h delete mode 100644 core/mpc_info.h create mode 100644 demux/codec_tags.c create mode 100644 demux/codec_tags.h delete mode 100644 etc/codecs.conf diff --git a/.gitignore b/.gitignore index 7ceff799c5..6915d4ff65 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,6 @@ /mpv /mpv.app /version.h -/core/codecs.conf.h /core/input/input_conf.h /tags /TAGS diff --git a/DOCS/OUTDATED-tech/codecs.conf.txt b/DOCS/OUTDATED-tech/codecs.conf.txt deleted file mode 100644 index 75f480933f..0000000000 --- a/DOCS/OUTDATED-tech/codecs.conf.txt +++ /dev/null @@ -1,214 +0,0 @@ -Understanding MPlayer's etc/codecs.conf File - -Introduction ------------- -MPlayer features a very flexible codec architecture which allows it to -use its own open source codecs, as well as open source libraries, Win32 -codec DLLs and other binary codec modules. To the MPlayer user, the -most visible piece of this architecture is the etc/codecs.conf file. This -is a text-based configuration file that controls which MPlayer components -are in charge of handling particular compressed data formats. - -The codecs.conf file is stored either in a shared directory for all system -users to access, or in the .mplayer directory in a user's home -directory. When MPlayer starts, it first looks for a codecs.conf file in a -user's home directory. Failing that, it searches for the shared file. If -no codecs.conf file is found MPlayer falls back on its internal hardcoded -configuration. If the file is present but has syntax errors, MPlayer will -report the error. - -The codecs.conf file is really quite simple. It is simply a collection of -codec definition blocks that define how different media types should be -handled. There are a number of keywords that can occur in a block. Not all -of them are required and no particular order is enforced. - -Editing codecs.conf -------------------- -You can edit codecs.conf using your favorite text editor. Anything that -comes after a semicolon (;) on a line is regarded as a comment. For -example: -; this is a comment - format 0x34616d69 ; "ima4" (MOV files) - -The codec blocks can be in any order; the file parser doesn't -care. However, they are organized in a particular order for the benefit of -human readers. For example, all of the open source decoders that MPlayer -implements natively are grouped in one section. - -Release Number --------------- -Your codecs.conf now requires a release number to avoid codec release -incompatibilities. The format is simple: (YYYYMMDD) - -release 20020520 - -Whenever changes are made to the codecs that *require* an updated -codecs.conf, then MPlayer will no longer accept outdated versions. -It is not recommended to change this line unless you know exactly -what you are doing. - -Video Codecs ------------- -Let's jump right in with an example. Here is an example video codec block: - -videocodec indeo5ds - info "Intel Indeo 5" - status working - fourcc IV50,iv50 - driver dshow - dll "ir50_32.dll" - guid 0x30355649, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 - out YV12 - out YUY2 - out BGR32,BGR24,BGR16,BGR15 - -This is a particularly full-featured video codec. The "videocodec" keyword -identifies the fact that this is the start of a new video -codec. "indeo5ds" is MPlayer's unique name for the codec. You have to use -this name with the -vc/-ac option. - -The next line has the keyword "info" which specifies a human-readable -comment accompanying this codec. This is printed by -vc help / -ac help. - -The "status" keyword carries information about the codec's functional -status. MPlayer currently recognizes 4 status levels: working, buggy, -crashing, and untested. When it gets to codec auto-selection, it tries -untested first (to force users to test it for us and report results :)), -then working and finally buggy ones. Codecs marked crashing won't be tried, -unless explicitly (-vc/-ac) selected. - -The next line lists 4-character codes (FOURCCs) that are associated with -this codec. There can be more than one FOURCC specified on a fourcc line -as long as they are separated with a comma. There can also be multiple -fourcc lines in the codec. A second fourcc can also be given, separated -with a space. MPlayer will replace the original fourcc in the headers with -this one before opening the codec. It's useful for win32 codecs checking for -the fourccs. - -The "driver" keyword associates this codec with an internal MPlayer -decoder module. MPlayer has a module named "dshow" that handles data -encoded by the codec. See -vfm help / -afm help for the available module list. - -The "dll" keyword specifies which Win32/XAnim/Real/Quicktime binary -module needs to be loaded. It's also used to specify which FFmpeg codec -to load. The list of FFmpeg codecs can be found in libavcodec/allcodecs.c. - -The "guid" keyword identifies a 16-byte Microsoft GUID that some media -files use to identify codecs. Used only for win32 dshow and DMO codecs. - -The "out" keyword identifies which output format the decoder is known -to provide. Just like the fourcc line, there can be multiple out lines or -multiple comma-separated output formats on the same line. The output -formats should be listed in order of preference. - -The outfmt values can be followed by one or more flags, like flip, noflip, -static, query. The flags are defined as follows: - -"flip": - If this flag is set for a given format, then o_bih->biHeight will NOT be - set to -bih->biHeight, i.e. the image will be decoded upside-down. - Used only by vfw and vfwex codecs. - -"noflip": - This flag is ignored (no effect) without "flip" being set! - If this flag is set, it means the codec doesn't decode upside-down, - although it's told to do so. - -"yuvhack": - This flag is required for the old win32 ms-mpeg4 vfw codecs, including - MP42 and DIV3 (DivX 3.11). These DLLs actually support YUV formats, - but the query/begin functions are buggy and don't accept YUV fourccs - (the decode function accepts it and works well!) - If this flag is set, then o_bih->biCompression will be set to 0 for - the initialization for the YUV modes. Used only by vfw/vfwex codecs. - -"query": - This flag is used to control VDCTRL_QUERY_FORMAT for vfw/vfewx codecs. - If this flag is set, the control() will query the codec for the csp - support, otherwise it will assume a constant csp table. Required for - some DLLs (like huffyuv, CRAM). - -"static", - This flag forces STATIC (instead of TEMP) buffer allocation for the codec. - Used for some very old DLLs like Indeo 3 and for some XAnim codecs like - cinepak. See dr-methods.txt for details on buffer types. - -The "in" keyword -- UNDOCUMENTED - -Audio Codecs ------------- -Here is an example of a rather full-featured audio codec block: - -audiocodec mp3 - info "MPEG layer-2, layer-3" - status working - comment "Optimized to MMX/SSE/3Dnow!" - format 0x50 - format 0x55 - format 0x33706d2e ; ".mp3" CBR/VBR MP3 (MOV files) - format 0x5500736d ; "ms\0\x55" older mp3 fcc (MOV files) - driver mp3lib - dll "mp3lib (mpglib)" - flags seekable - -Many of the keywords are the same as a video codec block. However, we see -a few that we haven't seen before. The "comment" keyword identifies -another human-readable note for this codec. - -The "format" keyword performs a similar job as the fourcc line. However, -since certain media file formats (notably AVI) identify audio formats with -16-bit numbers rather than 32-bit FOURCCs, it's necessary to use this -convention to accommodate them. However, as shown in this example, FOURCCs -can also be specified with the format keyword as long as they're converted -to their hex representation. It's important to note that this can be -useful for video codecs as well if a FOURCC contains a space (such as -Apple's "rle " codec). - -The "flags" keywords identifies any additional abilities of this -codec. Currently, seekable is the only supported flag. - - -Adding FFmpeg Codecs -------------------- -example codec: - -videocodec ffmdec - info "FFmpeg Sony PlayStation MDEC (Motion DECoder)" - status working - fourcc MDEC ; internal MPlayer FourCC - driver ffmpeg - dll mdec - out YV12 - -The "videocodec" name should start with ff to differentiate it from other -libraries or binary codecs. - -The "dll" name comes from the codec source file or the libavcodec/allcodecs.c -file. - -The "out" colorspace can be found in the codec source file in the PIX_FMT -struct. Note that some codecs may have several pix_fmt structs. -The pix_fmt can be converted to the codecs.conf "out" format by reading -the fmt-conversion.c file. - -If there are BE and LE versions of a pix_fmt, ignore them and use the short -native format instead. e.g. 422P16_LE becomes out 422P16. also to note that -underscores cause parse errors, so 422P16_LE becomes out 422P16LE. - -libmpdemux/mp_taglists.c --------------- -Sometimes the lavf demuxer will not pass on a fourcc (mostly video game -formats or other containers that do not support isom/riff tags). You will have -to make one based on the codec_id listed in the codec source file. - -Note that it is a good idea to mark any fourcc you create as -' ; internal MPlayer FourCC'. In case another codec uses that fourcc, -you can easily change the internal one. Also this will stop other projects -from thinking of the internal tag as a real fourcc found in the wild. - -libmpdemux/demuxer.c --------------- -Some audio codecs require a parser, you can see which ones do -by reading the parsers section in libavcodec/allcodecs.c. - -EOF diff --git a/DOCS/man/en/changes.rst b/DOCS/man/en/changes.rst index 892b3f0af9..adaf1aa0d2 100644 --- a/DOCS/man/en/changes.rst +++ b/DOCS/man/en/changes.rst @@ -120,6 +120,7 @@ Command line switches -vobsub --sub (pass the .idx file) -ass-bottom-margin --vf=sub=bottom:top -vc ffh264vdpau (etc.) --hwdec=vdpau + -ac spdifac3 --ad=spdif:ac3 (see --ad=help) -x W, -y H --geometry=WxH + --no-keepaspect -xy W --autofit=W =================================== =================================== diff --git a/DOCS/man/en/input.rst b/DOCS/man/en/input.rst index f146208fd3..6b61578a1a 100644 --- a/DOCS/man/en/input.rst +++ b/DOCS/man/en/input.rst @@ -283,7 +283,7 @@ hr-seek x see ``--hr-seek`` volume x current volume (0-100) mute x current mute status (bool) audio-delay x see ``--audio-delay`` -audio-format audio format (codec tag) +audio-format audio format (string) audio-codec audio codec selected for decoding audio-bitrate audio bitrate samplerate audio samplerate @@ -306,7 +306,7 @@ saturation x see ``--saturation`` hue x see ``--hue`` panscan x see ``--panscan`` vsync x see ``--vsync`` -video-format video format (integer FourCC) +video-format video format (string) video-codec video codec selected for decoding video-bitrate video bitrate width video width diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst index ea43b9c49f..12dccdc8c4 100644 --- a/DOCS/man/en/options.rst +++ b/DOCS/man/en/options.rst @@ -10,14 +10,32 @@ (``--ao=oss`` only) (OBSOLETE) Override audio driver/card buffer size detection. ---ac=<[-\|+]codec1,[-\|+]codec2,...[,]> - Specify a priority list of audio codecs to be used, according to their - codec name in codecs.conf. Use a '-' before the codec name to omit it. - Use a '+' before the codec name to force it, this will likely crash! If - the list has a trailing ',' mpv will fall back on codecs not contained - in the list. +--ad=<[+|-]family1:(*|decoder1),[+|-]family2:(*|decoder2),...[-]> + Specify a priority list of audio decoders to be used, according to their + family and decoder name. Entries like ``family:*`` prioritize all decoders + of the given family. When determining which decoder to use, the first + decoder that matches the audio format is selected. If that is unavailable, + the next decoder is used. Finally, it tries all other decoders that are not + explicitly selected or rejected by the option. - *NOTE*: See ``--ac=help`` for a full list of available codecs. + ``-`` at the end of the list suppresses fallback to other available + decoders not on the ``--ad`` list. ``+`` in front of an entry forces the + decoder. Both of these shouldn't normally be used, because they break + normal decoder auto-selection! + + ``-`` in front of an entry disables selection of the decoder. + + *EXAMPLE*: + + ``--ad=lavc:mp3float`` + Prefer the FFmpeg/Libav ``mp3float`` decoder over all other mp3 + decoders. + + ``--ad=spdif:ac3,lavc:*`` + Always prefer spdif AC3 over FFmpeg/Libav over anything else. + + ``--ad=help`` + List all available decoders. --af= Specify a list of audio filters to apply to the audio stream. See @@ -60,17 +78,6 @@ list= Same as ``--af``. ---afm= - Specify a priority list of audio codec families to be used, according to - their codec name in codecs.conf. Falls back on the default codecs if none - of the given codec families work. - - *NOTE*: See ``--afm=help`` for a full list of available codec families. - - *EXAMPLE*: - - :``--afm=ffmpeg``: Try FFmpeg's libavcodec codecs first. - --aid= Select audio channel. ``auto`` selects the default, ``no`` disables audio. See also ``--alang``. @@ -409,10 +416,6 @@ the start of the next one then keep playing video normally over the chapter change instead of doing a seek. ---codecs-file= - Override the standard search path and use the specified file instead of - the builtin codecs.conf. - --colormatrix= Controls the YUV to RGB color space conversion when playing video. There are various standards. Normally, BT.601 should be used for SD video, and @@ -2257,14 +2260,13 @@ Increment verbosity level, one level for each ``-v`` found on the command line. ---vc=<[-\|+]codec1,[-\|+]codec2,...[,]> - Specify a priority list of video codecs to be used, according to their - codec name in ``codecs.conf``. Use a '-' before the codec name to omit it. - Use a '+' before the codec name to force it, this will likely crash! If - the list has a trailing ',' mpv will fall back on codecs not contained - in the list. +--vd=<[+|-]family1:(*|decoder1),[+|-]family2:(*|decoder2),...[-]> + Specify a priority list of video decoders to be used, according to their + family and name. See ``--ad`` for further details. Both of these options + use the same syntax and semantics, the only difference is that they + operate on different codec lists. - *NOTE*: See ``--vc=help`` for a full list of available codecs. + *NOTE*: See ``--vd=help`` for a full list of available decoders. --vf= Specify a list of video filters to apply to the video stream. See @@ -2273,13 +2275,6 @@ ``--vf-clr`` exist to modify a previously specified list, but you shouldn't need these for typical use. ---vfm= - Specify a priority list of video codec families to be used, according to - their names in codecs.conf. Falls back on the default codecs if none of - the given codec families work. - - *NOTE*: See ``--vfm=help`` for a full list of available codec families. - --vid= Select video channel. ``auto`` selects the default, ``no`` disables video. diff --git a/DOCS/tech-overview.txt b/DOCS/tech-overview.txt index 0fb20e7e81..9582caaea4 100644 --- a/DOCS/tech-overview.txt +++ b/DOCS/tech-overview.txt @@ -203,7 +203,5 @@ core/timeline/: segments for playing an ordered chapters file is in tl_matroska.c. etc/: - The files codecs.conf and input.conf are actually integrated into the - mplayer binary by the build system. These files define the default settings. - codecs.conf maps video/audio formats to decoders. input.conf contains - the default keybindings. + The file input.conf is actually integrated into the mpv binary by the + build system. It contains the default keybindings. diff --git a/Makefile b/Makefile index 3aa27d12e2..26165505b9 100644 --- a/Makefile +++ b/Makefile @@ -151,10 +151,11 @@ SOURCES = talloc.c \ audio/out/ao_null.c \ audio/out/ao_pcm.c \ core/asxparser.c \ + core/av_common.c \ core/av_log.c \ core/av_opts.c \ core/bstr.c \ - core/codec-cfg.c \ + core/codecs.c \ core/command.c \ core/cpudetect.c \ core/defaultopts.c \ @@ -181,6 +182,7 @@ SOURCES = talloc.c \ demux/asfheader.c \ demux/aviheader.c \ demux/aviprint.c \ + demux/codec_tags.c \ demux/demux.c \ demux/demux_asf.c \ demux/demux_avi.c \ @@ -343,10 +345,6 @@ mpv$(EXESUF): $(OBJECTS) mpv$(EXESUF): $(CC) -o $@ $^ $(EXTRALIBS) -core/codec-cfg.c: core/codecs.conf.h -core/codecs.conf.h: TOOLS/file2string.pl etc/codecs.conf - ./$^ >$@ - core/input/input.c: core/input/input_conf.h core/input/input_conf.h: TOOLS/file2string.pl etc/input.conf ./$^ >$@ @@ -442,7 +440,6 @@ clean: -$(RM) $(call ADD_ALL_EXESUFS,mpv) -$(RM) DOCS/man/en/mpv.1 -$(RM) version.h - -$(RM) core/codecs.conf.h -$(RM) core/input/input_conf.h -$(RM) video/out/vdpau_template.c -$(RM) demux/ebml_types.h demux/ebml_defs.c diff --git a/audio/decode/ad.c b/audio/decode/ad.c index 9af7112bf0..846cd146d1 100644 --- a/audio/decode/ad.c +++ b/audio/decode/ad.c @@ -32,7 +32,7 @@ /* Missed vorbis, mad, dshow */ extern const ad_functions_t mpcodecs_ad_mpg123; -extern const ad_functions_t mpcodecs_ad_ffmpeg; +extern const ad_functions_t mpcodecs_ad_lavc; extern const ad_functions_t mpcodecs_ad_spdif; const ad_functions_t * const mpcodecs_ad_drivers[] = @@ -40,7 +40,7 @@ const ad_functions_t * const mpcodecs_ad_drivers[] = #ifdef CONFIG_MPG123 &mpcodecs_ad_mpg123, #endif - &mpcodecs_ad_ffmpeg, + &mpcodecs_ad_lavc, &mpcodecs_ad_spdif, NULL }; diff --git a/audio/decode/ad.h b/audio/decode/ad.h index 2de0e0641a..3bc3e39267 100644 --- a/audio/decode/ad.h +++ b/audio/decode/ad.h @@ -19,17 +19,20 @@ #ifndef MPLAYER_AD_H #define MPLAYER_AD_H -#include "core/mpc_info.h" +#include "core/codecs.h" #include "demux/stheader.h" typedef struct mp_codec_info ad_info_t; +struct mp_decoder_list; + /* interface of video decoder drivers */ typedef struct ad_functions { - const ad_info_t *info; + const char *name; + void (*add_decoders)(struct mp_decoder_list *list); int (*preinit)(sh_audio_t *sh); - int (*init)(sh_audio_t *sh); + int (*init)(sh_audio_t *sh, const char *decoder); void (*uninit)(sh_audio_t *sh); int (*control)(sh_audio_t *sh,int cmd,void* arg, ...); int (*decode_audio)(sh_audio_t *sh, unsigned char *buffer, int minlen, diff --git a/audio/decode/ad_internal.h b/audio/decode/ad_internal.h index 1fed350b98..7eca629fca 100644 --- a/audio/decode/ad_internal.h +++ b/audio/decode/ad_internal.h @@ -19,7 +19,7 @@ #ifndef MPLAYER_AD_INTERNAL_H #define MPLAYER_AD_INTERNAL_H -#include "core/codec-cfg.h" +#include "core/codecs.h" #include "audio/format.h" #include "stream/stream.h" @@ -28,14 +28,16 @@ #include "ad.h" -static int init(sh_audio_t *sh); +static void add_decoders(struct mp_decoder_list *list); +static int init(sh_audio_t *sh, const char *decoder); static int preinit(sh_audio_t *sh); static void uninit(sh_audio_t *sh); static int control(sh_audio_t *sh,int cmd,void* arg, ...); static int decode_audio(sh_audio_t *sh,unsigned char *buffer,int minlen,int maxlen); #define LIBAD_EXTERN(x) const ad_functions_t mpcodecs_ad_##x = {\ - &info,\ + #x, \ + add_decoders, \ preinit,\ init,\ uninit,\ diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c index 9bcbde33cf..26c02b3240 100644 --- a/audio/decode/ad_lavc.c +++ b/audio/decode/ad_lavc.c @@ -28,6 +28,8 @@ #include "talloc.h" #include "config.h" +#include "core/av_common.h" +#include "core/codecs.h" #include "core/mp_msg.h" #include "core/options.h" @@ -37,17 +39,7 @@ #include "compat/mpbswap.h" #include "compat/libav.h" -static const ad_info_t info = -{ - "libavcodec audio decoders", - "ffmpeg", - "", - "", - "", - .print_name = "libavcodec", -}; - -LIBAD_EXTERN(ffmpeg) +LIBAD_EXTERN(lavc) struct priv { AVCodecContext *avctx; @@ -189,48 +181,26 @@ static int setup_format(sh_audio_t *sh_audio, return 0; } -static int init(sh_audio_t *sh_audio) +static int init(sh_audio_t *sh_audio, const char *decoder) { struct MPOpts *opts = sh_audio->opts; AVCodecContext *lavc_context; AVCodec *lavc_codec; - const char *dll = sh_audio->codec->dll; - - if (sh_audio->wf && dll && strcmp(dll, "pcm") == 0) { - if (sh_audio->format == MKTAG('M', 'P', 'a', 'f')) { - // demuxer_rawaudio convenience (abuses wFormatTag) - dll = find_pcm_decoder(af_map, sh_audio->wf->wFormatTag, 0); - } else { - dll = find_pcm_decoder(tag_map, sh_audio->format, + if (sh_audio->wf && strcmp(decoder, "pcm") == 0) { + decoder = find_pcm_decoder(tag_map, sh_audio->format, sh_audio->wf->wBitsPerSample); - } + } else if (sh_audio->wf && strcmp(decoder, "mp-pcm") == 0) { + decoder = find_pcm_decoder(af_map, sh_audio->format, 0); } - if (dll) { - lavc_codec = avcodec_find_decoder_by_name(dll); - if (!lavc_codec) { - mp_tmsg(MSGT_DECAUDIO, MSGL_ERR, - "Cannot find codec '%s' in libavcodec...\n", dll); - return 0; - } - } else if (!sh_audio->libav_codec_id) { - mp_tmsg(MSGT_DECAUDIO, MSGL_INFO, "No Libav codec ID known. " - "Generic lavc decoder is not applicable.\n"); + lavc_codec = avcodec_find_decoder_by_name(decoder); + if (!lavc_codec) { + mp_tmsg(MSGT_DECAUDIO, MSGL_ERR, + "Cannot find codec '%s' in libavcodec...\n", decoder); return 0; - } else { - lavc_codec = avcodec_find_decoder(sh_audio->libav_codec_id); - if (!lavc_codec) { - mp_tmsg(MSGT_DECAUDIO, MSGL_INFO, "Libavcodec has no decoder " - "for this codec\n"); - return 0; - } } - sh_audio->codecname = lavc_codec->long_name; - if (!sh_audio->codecname) - sh_audio->codecname = lavc_codec->name; - struct priv *ctx = talloc_zero(NULL, struct priv); sh_audio->context = ctx; lavc_context = avcodec_alloc_context3(lavc_codec); @@ -303,7 +273,7 @@ static int init(sh_audio_t *sh_audio) } if (++tries >= 5) { mp_msg(MSGT_DECAUDIO, MSGL_ERR, - "ad_ffmpeg: initial decode failed\n"); + "ad_lavc: initial decode failed\n"); uninit(sh_audio); return 0; } @@ -328,7 +298,6 @@ static int init(sh_audio_t *sh_audio) static void uninit(sh_audio_t *sh) { - sh->codecname = NULL; struct priv *ctx = sh->context; if (!ctx) return; @@ -494,3 +463,10 @@ static int decode_audio(sh_audio_t *sh_audio, unsigned char *buf, int minlen, } return len; } + +static void add_decoders(struct mp_decoder_list *list) +{ + mp_add_lavc_decoders(list, AVMEDIA_TYPE_AUDIO); + mp_add_decoder(list, "lavc", "pcm", "pcm", "Raw PCM"); + mp_add_decoder(list, "lavc", "mp-pcm", "mp-pcm", "Raw PCM"); +} diff --git a/audio/decode/ad_mpg123.c b/audio/decode/ad_mpg123.c index a3ce2cdcf6..999dc2fbba 100644 --- a/audio/decode/ad_mpg123.c +++ b/audio/decode/ad_mpg123.c @@ -26,14 +26,6 @@ #include "ad_internal.h" -static const ad_info_t info = { - "MPEG 1.0/2.0/2.5 layers I, II, III", - "mpg123", - "Thomas Orgis", - "mpg123.org", - "High-performance decoder using libmpg123." -}; - LIBAD_EXTERN(mpg123) /* Reducing the ifdeffery to two main variants: @@ -327,7 +319,7 @@ static int reopen_stream(sh_audio_t *sh) * Paranoia note: The mpg123_close() on errors is not really necessary, * But it ensures that we don't accidentally continue decoding with a * bad state (possibly interpreting the format badly or whatnot). */ -static int init(sh_audio_t *sh) +static int init(sh_audio_t *sh, const char *decoder) { long rate = 0; int channels = 0; @@ -487,3 +479,9 @@ static int control(sh_audio_t *sh, int cmd, void *arg, ...) } return CONTROL_UNKNOWN; } + +static void add_decoders(struct mp_decoder_list *list) +{ + mp_add_decoder(list, "mpg123", "mp3", "mp3", + "High-performance decoder using libmpg123"); +} diff --git a/audio/decode/ad_spdif.c b/audio/decode/ad_spdif.c index d8cf731d38..e20566a265 100644 --- a/audio/decode/ad_spdif.c +++ b/audio/decode/ad_spdif.c @@ -1,6 +1,8 @@ /* * This file is part of MPlayer. * + * Copyright (C) 2012 Naoya OYAMA + * * MPlayer 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 @@ -24,16 +26,9 @@ #include "config.h" #include "core/mp_msg.h" +#include "core/av_common.h" #include "ad_internal.h" -static const ad_info_t info = { - "libavformat/spdifenc audio pass-through decoder.", - "spdif", - "Naoya OYAMA", - "Naoya OYAMA", - "For ALL hardware decoders" -}; - LIBAD_EXTERN(spdif) #define FILENAME_SPDIFENC "spdif" @@ -76,22 +71,21 @@ static int preinit(sh_audio_t *sh) return 1; } -static int init(sh_audio_t *sh) +static int codecs[] = { + CODEC_ID_AAC, + CODEC_ID_AC3, + CODEC_ID_DTS, + CODEC_ID_EAC3, + CODEC_ID_MP3, + CODEC_ID_TRUEHD, + CODEC_ID_NONE +}; + +static int init(sh_audio_t *sh, const char *decoder) { - int i, x, in_size, srate, bps, *dtshd_rate; + int x, in_size, srate, bps, *dtshd_rate; unsigned char *start; double pts; - static const struct { - const char *name; enum CodecID id; - } fmt_id_type[] = { - { "aac" , CODEC_ID_AAC }, - { "ac3" , CODEC_ID_AC3 }, - { "dca" , CODEC_ID_DTS }, - { "eac3", CODEC_ID_EAC3 }, - { "mpa" , CODEC_ID_MP3 }, - { "thd" , CODEC_ID_TRUEHD }, - { NULL , 0 } - }; AVFormatContext *lavf_ctx = NULL; AVStream *stream = NULL; const AVOption *opt = NULL; @@ -122,12 +116,7 @@ static int init(sh_audio_t *sh) goto fail; lavf_ctx->duration = AV_NOPTS_VALUE; lavf_ctx->start_time = AV_NOPTS_VALUE; - for (i = 0; fmt_id_type[i].name; i++) { - if (!strcmp(sh->codec->dll, fmt_id_type[i].name)) { - lavf_ctx->streams[0]->codec->codec_id = fmt_id_type[i].id; - break; - } - } + lavf_ctx->streams[0]->codec->codec_id = mp_codec_to_av_codec_id(decoder); lavf_ctx->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE; if (AVERROR_PATCHWELCOME == lavf_ctx->oformat->write_header(lavf_ctx)) { mp_msg(MSGT_DECAUDIO,MSGL_INFO, @@ -306,3 +295,14 @@ static void uninit(sh_audio_t *sh) av_freep(&lavf_ctx); av_freep(&spdif_ctx); } + +static void add_decoders(struct mp_decoder_list *list) +{ + for (int n = 0; codecs[n] != CODEC_ID_NONE; n++) { + const char *format = mp_codec_from_av_codec_id(codecs[n]); + if (format) { + mp_add_decoder(list, "spdif", format, format, + "libavformat/spdifenc audio pass-through decoder"); + } + } +} diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c index 0d58bf6012..cac33a9a31 100644 --- a/audio/decode/dec_audio.c +++ b/audio/decode/dec_audio.c @@ -21,14 +21,16 @@ #include #include +#include "demux/codec_tags.h" + #include "config.h" +#include "core/codecs.h" #include "core/mp_msg.h" #include "core/bstr.h" #include "stream/stream.h" #include "demux/demux.h" -#include "core/codec-cfg.h" #include "demux/stheader.h" #include "dec_audio.h" @@ -41,27 +43,7 @@ int fakemono = 0; struct af_cfg af_cfg = {1, NULL}; // Configuration for audio filters -void afm_help(void) -{ - int i; - mp_tmsg(MSGT_DECAUDIO, MSGL_INFO, - "Available (compiled-in) audio codec families/drivers:\n"); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AUDIO_DRIVERS\n"); - mp_msg(MSGT_DECAUDIO, MSGL_INFO, " afm: info: (comment)\n"); - for (i = 0; mpcodecs_ad_drivers[i] != NULL; i++) - if (mpcodecs_ad_drivers[i]->info->comment - && mpcodecs_ad_drivers[i]->info->comment[0]) - mp_msg(MSGT_DECAUDIO, MSGL_INFO, "%9s %s (%s)\n", - mpcodecs_ad_drivers[i]->info->short_name, - mpcodecs_ad_drivers[i]->info->name, - mpcodecs_ad_drivers[i]->info->comment); - else - mp_msg(MSGT_DECAUDIO, MSGL_INFO, "%9s %s\n", - mpcodecs_ad_drivers[i]->info->short_name, - mpcodecs_ad_drivers[i]->info->name); -} - -static int init_audio_codec(sh_audio_t *sh_audio) +static int init_audio_codec(sh_audio_t *sh_audio, const char *decoder) { assert(!sh_audio->initialized); resync_audio_stream(sh_audio); @@ -77,7 +59,7 @@ static int init_audio_codec(sh_audio_t *sh_audio) } sh_audio->audio_out_minsize = 8192; // default, preinit() may change it if (!sh_audio->ad_driver->preinit(sh_audio)) { - mp_tmsg(MSGT_DECAUDIO, MSGL_ERR, "ADecoder preinit failed :(\n"); + mp_tmsg(MSGT_DECAUDIO, MSGL_ERR, "Audio decoder preinit failed.\n"); return 0; } @@ -104,8 +86,8 @@ static int init_audio_codec(sh_audio_t *sh_audio) abort(); sh_audio->a_buffer_len = 0; - if (!sh_audio->ad_driver->init(sh_audio)) { - mp_tmsg(MSGT_DECAUDIO, MSGL_V, "ADecoder init failed :(\n"); + if (!sh_audio->ad_driver->init(sh_audio, decoder)) { + mp_tmsg(MSGT_DECAUDIO, MSGL_V, "Audio decoder init failed.\n"); uninit_audio(sh_audio); // free buffers return 0; } @@ -125,140 +107,83 @@ static int init_audio_codec(sh_audio_t *sh_audio) return 1; } -static int init_audio(sh_audio_t *sh_audio, char *codecname, char *afm, - int status, stringset_t *selected) +struct mp_decoder_list *mp_audio_decoder_list(void) { - int force = 0; - if (codecname && codecname[0] == '+') { - codecname = &codecname[1]; - force = 1; - } - sh_audio->codec = NULL; - while (1) { - const ad_functions_t *mpadec; - sh_audio->ad_driver = 0; - if (!(sh_audio->codec = find_audio_codec(sh_audio->format, NULL, - sh_audio->codec, force))) - break; - // ok we found one codec - if (stringset_test(selected, sh_audio->codec->name)) - continue; // already tried & failed - if (codecname && strcmp(sh_audio->codec->name, codecname)) - continue; // -ac - if (afm && strcmp(sh_audio->codec->drv, afm)) - continue; // afm doesn't match - if (!force && sh_audio->codec->status < status) - continue; // too unstable - stringset_add(selected, sh_audio->codec->name); // tagging it - // ok, it matches all rules, let's find the driver! - int i; - for (i = 0; mpcodecs_ad_drivers[i] != NULL; i++) - if (!strcmp(mpcodecs_ad_drivers[i]->info->short_name, - sh_audio->codec->drv)) - break; - mpadec = mpcodecs_ad_drivers[i]; - if (!mpadec) { // driver not available (==compiled in) - mp_tmsg(MSGT_DECAUDIO, MSGL_ERR, "Requested audio codec family " - "[%s] (afm=%s) not available.\nEnable it at compilation.\n", - sh_audio->codec->name, sh_audio->codec->drv); - continue; - } - // it's available, let's try to init! - // init() - mp_tmsg(MSGT_DECAUDIO, MSGL_V, "Opening audio decoder: [%s] %s\n", - mpadec->info->short_name, mpadec->info->name); - sh_audio->ad_driver = mpadec; - if (!init_audio_codec(sh_audio)) { - mp_tmsg(MSGT_DECAUDIO, MSGL_WARN, "Audio decoder init failed for " - "codecs.conf entry \"%s\".\n", sh_audio->codec->name); - continue; // try next... - } - // Yeah! We got it! - return 1; + struct mp_decoder_list *list = talloc_zero(NULL, struct mp_decoder_list); + for (int i = 0; mpcodecs_ad_drivers[i] != NULL; i++) + mpcodecs_ad_drivers[i]->add_decoders(list); + return list; +} + +static struct mp_decoder_list *mp_select_audio_decoders(const char *codec, + char *selection) +{ + struct mp_decoder_list *list = mp_audio_decoder_list(); + struct mp_decoder_list *new = mp_select_decoders(list, codec, selection); + talloc_free(list); + return new; +} + +static const struct ad_functions *find_driver(const char *name) +{ + for (int i = 0; mpcodecs_ad_drivers[i] != NULL; i++) { + if (strcmp(mpcodecs_ad_drivers[i]->name, name) == 0) + return mpcodecs_ad_drivers[i]; } - return 0; + return NULL; } -int init_best_audio_codec(sh_audio_t *sh_audio, char **audio_codec_list, - char **audio_fm_list) +int init_best_audio_codec(sh_audio_t *sh_audio, char *audio_decoders) { - stringset_t selected; - char *ac_l_default[2] = { - "", (char *) NULL - }; - // hack: - if (!audio_codec_list) - audio_codec_list = ac_l_default; - // Go through the codec.conf and find the best codec... - sh_audio->initialized = 0; - stringset_init(&selected); - while (!sh_audio->initialized && *audio_codec_list) { - char *audio_codec = *(audio_codec_list++); - if (audio_codec[0]) { - if (audio_codec[0] == '-') { - // disable this codec: - stringset_add(&selected, audio_codec + 1); - } else { - // forced codec by name: - mp_tmsg(MSGT_DECAUDIO, MSGL_INFO, "Forced audio codec: %s\n", - audio_codec); - init_audio(sh_audio, audio_codec, NULL, -1, &selected); - } - } else { - int status; - // try in stability order: UNTESTED, WORKING, BUGGY. - // never try CRASHING. - if (audio_fm_list) { - char **fmlist = audio_fm_list; - // try first the preferred codec families: - while (!sh_audio->initialized && *fmlist) { - char *audio_fm = *(fmlist++); - mp_tmsg(MSGT_DECAUDIO, MSGL_INFO, - "Trying to force audio codec driver family %s...\n", - audio_fm); - for (status = CODECS_STATUS__MAX; - status >= CODECS_STATUS__MIN; --status) - if (init_audio(sh_audio, NULL, audio_fm, status, - &selected)) - break; - } - } - if (!sh_audio->initialized) - for (status = CODECS_STATUS__MAX; status >= CODECS_STATUS__MIN; - --status) - if (init_audio(sh_audio, NULL, NULL, status, &selected)) - break; + assert(!sh_audio->initialized); + + struct mp_decoder_entry *decoder = NULL; + struct mp_decoder_list *list = + mp_select_audio_decoders(sh_audio->gsh->codec, audio_decoders); + + mp_print_decoders(MSGT_DECAUDIO, MSGL_V, "Codec list:", list); + + for (int n = 0; n < list->num_entries; n++) { + struct mp_decoder_entry *sel = &list->entries[n]; + const struct ad_functions *driver = find_driver(sel->family); + if (!driver) + continue; + mp_tmsg(MSGT_DECAUDIO, MSGL_V, "Opening audio decoder %s:%s\n", + sel->family, sel->decoder); + sh_audio->ad_driver = driver; + if (init_audio_codec(sh_audio, sel->decoder)) { + decoder = sel; + break; } + sh_audio->ad_driver = NULL; + mp_tmsg(MSGT_DECAUDIO, MSGL_WARN, "Audio decoder init failed for " + "%s:%s\n", sel->family, sel->decoder); } - stringset_free(&selected); - if (!sh_audio->initialized) { - mp_tmsg(MSGT_DECAUDIO, MSGL_ERR, - "Cannot find codec for audio format 0x%X.\n", - sh_audio->format); - return 0; // failed + if (sh_audio->initialized) { + sh_audio->gsh->decoder_desc = + talloc_asprintf(NULL, "%s [%s:%s]", decoder->desc, decoder->family, + decoder->decoder); + mp_msg(MSGT_DECAUDIO, MSGL_INFO, "Selected audio codec: %s\n", + sh_audio->gsh->decoder_desc); + mp_msg(MSGT_DECAUDIO, MSGL_V, + "AUDIO: %d Hz, %d ch, %s, %3.1f kbit/%3.2f%% (ratio: %d->%d)\n", + sh_audio->samplerate, sh_audio->channels, + af_fmt2str_short(sh_audio->sample_format), + sh_audio->i_bps * 8 * 0.001, + ((float) sh_audio->i_bps / sh_audio->o_bps) * 100.0, + sh_audio->i_bps, sh_audio->o_bps); + mp_msg(MSGT_IDENTIFY, MSGL_INFO, + "ID_AUDIO_BITRATE=%d\nID_AUDIO_RATE=%d\n" "ID_AUDIO_NCH=%d\n", + sh_audio->i_bps * 8, sh_audio->samplerate, sh_audio->channels); + } else { + mp_msg(MSGT_DECAUDIO, MSGL_ERR, + "Failed to initialize an audio decoder for codec '%s'.\n", + sh_audio->gsh->codec ? sh_audio->gsh->codec : ""); } - mp_tmsg(MSGT_DECAUDIO, MSGL_INFO, "Selected audio codec: %s [%s]\n", - sh_audio->codecname ? sh_audio->codecname : sh_audio->codec->info, - sh_audio->ad_driver->info->print_name ? - sh_audio->ad_driver->info->print_name : - sh_audio->ad_driver->info->short_name); - mp_tmsg(MSGT_DECAUDIO, MSGL_V, - "Audio codecs.conf entry: %s (%s) afm: %s\n", - sh_audio->codec->name, sh_audio->codec->info, sh_audio->codec->drv); - mp_msg(MSGT_DECAUDIO, MSGL_V, - "AUDIO: %d Hz, %d ch, %s, %3.1f kbit/%3.2f%% (ratio: %d->%d)\n", - sh_audio->samplerate, sh_audio->channels, - af_fmt2str_short(sh_audio->sample_format), - sh_audio->i_bps * 8 * 0.001, - ((float) sh_audio->i_bps / sh_audio->o_bps) * 100.0, - sh_audio->i_bps, sh_audio->o_bps); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, - "ID_AUDIO_BITRATE=%d\nID_AUDIO_RATE=%d\n" "ID_AUDIO_NCH=%d\n", - sh_audio->i_bps * 8, sh_audio->samplerate, sh_audio->channels); - - return 1; // success + talloc_free(list); + return sh_audio->initialized; } void uninit_audio(sh_audio_t *sh_audio) @@ -270,11 +195,12 @@ void uninit_audio(sh_audio_t *sh_audio) sh_audio->afilter = NULL; } if (sh_audio->initialized) { - mp_tmsg(MSGT_DECAUDIO, MSGL_V, "Uninit audio: %s\n", - sh_audio->codec->drv); + mp_tmsg(MSGT_DECAUDIO, MSGL_V, "Uninit audio.\n"); sh_audio->ad_driver->uninit(sh_audio); sh_audio->initialized = 0; } + talloc_free(sh_audio->gsh->decoder_desc); + sh_audio->gsh->decoder_desc = NULL; av_freep(&sh_audio->a_buffer); av_freep(&sh_audio->a_in_buffer); } diff --git a/audio/decode/dec_audio.h b/audio/decode/dec_audio.h index 6481717091..9fa6aad8dd 100644 --- a/audio/decode/dec_audio.h +++ b/audio/decode/dec_audio.h @@ -22,11 +22,10 @@ #include "demux/stheader.h" struct bstr; +struct mp_decoder_list; -// dec_audio.c: -void afm_help(void); -int init_best_audio_codec(sh_audio_t *sh_audio, char **audio_codec_list, - char **audio_fm_list); +struct mp_decoder_list *mp_audio_decoder_list(void); +int init_best_audio_codec(sh_audio_t *sh_audio, char *audio_decoders); int decode_audio(sh_audio_t *sh_audio, struct bstr *outbuf, int minlen); void decode_audio_prepend_bytes(struct bstr *outbuf, int count, int byte); void resync_audio_stream(sh_audio_t *sh_audio); diff --git a/audio/out/ao.h b/audio/out/ao.h index 6b79508943..4a7c928824 100644 --- a/audio/out/ao.h +++ b/audio/out/ao.h @@ -22,13 +22,7 @@ #include #include "core/bstr.h" - -#define CONTROL_OK 1 -#define CONTROL_TRUE 1 -#define CONTROL_FALSE 0 -#define CONTROL_UNKNOWN -1 -#define CONTROL_ERROR -2 -#define CONTROL_NA -3 +#include "core/mp_common.h" enum aocontrol { // _VOLUME commands take struct ao_control_vol pointer for input/output. diff --git a/configure b/configure index 7e0cb2b227..4301f0d103 100755 --- a/configure +++ b/configure @@ -2663,6 +2663,28 @@ else fi +echocheck "libavcodec AVCodecDescriptor API" +_avcodec_codec_desc_api=no +statement_check libavcodec/avcodec.h 'const AVCodecDescriptor *desc = avcodec_descriptor_get_by_name("c")' $_ld_tmp && _avcodec_codec_desc_api=yes +if test "$_avcodec_codec_desc_api" = yes ; then + def_avcodec_codec_desc_api='#define HAVE_AVCODEC_CODEC_DESC_API 1' +else + def_avcodec_codec_desc_api='#define HAVE_AVCODEC_CODEC_DESC_API 0' +fi +echores "$_avcodec_codec_desc_api" + + +echocheck "libavcodec av_codec_is_decoder API" +_avcodec_is_decoder_api=no +statement_check libavcodec/avcodec.h 'av_codec_is_decoder(NULL)' $_ld_tmp && _avcodec_is_decoder_api=yes +if test "$_avcodec_is_decoder_api" = yes ; then + def_avcodec_is_decoder_api='#define HAVE_AVCODEC_IS_DECODER_API 1' +else + def_avcodec_is_decoder_api='#define HAVE_AVCODEC_IS_DECODER_API 0' +fi +echores "$_avcodec_is_decoder_api" + + echocheck "libavfilter >= 3.17.0" if test "$libavfilter" = auto ; then libavfilter=no @@ -3158,6 +3180,8 @@ $def_vcd $def_mpg123 $def_zlib +$def_avcodec_codec_desc_api +$def_avcodec_is_decoder_api $def_libpostproc $def_libavdevice $def_libavfilter diff --git a/core/av_common.c b/core/av_common.c new file mode 100644 index 0000000000..55fa5e086b --- /dev/null +++ b/core/av_common.c @@ -0,0 +1,130 @@ +/* + * This file is part of mpv. + * + * mpv 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. + * + * mpv 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 mpv. If not, see . + */ + +#include + +#include "config.h" +#include "core/mp_talloc.h" +#include "av_common.h" +#include "codecs.h" + + +#if !HAVE_AVCODEC_IS_DECODER_API +static int av_codec_is_decoder(AVCodec *codec) +{ + return !!codec->decode; +} +#endif + +void mp_add_lavc_decoders(struct mp_decoder_list *list, enum AVMediaType type) +{ + AVCodec *cur = NULL; + for (;;) { + cur = av_codec_next(cur); + if (!cur) + break; + if (av_codec_is_decoder(cur) && cur->type == type) { + struct mp_decoder_entry entry = { + .family = "lavc", + .codec = mp_codec_from_av_codec_id(cur->id), + .decoder = cur->name, + .desc = cur->long_name, + }; + assert(entry.family); + MP_TARRAY_APPEND(list, list->entries, list->num_entries, entry); + } + } +} + +#if HAVE_AVCODEC_CODEC_DESC_API + +int mp_codec_to_av_codec_id(const char *codec) +{ + + const AVCodecDescriptor *desc = avcodec_descriptor_get_by_name(codec); + return desc ? desc->id : CODEC_ID_NONE; +} + +const char *mp_codec_from_av_codec_id(int codec_id) +{ + const AVCodecDescriptor *desc = avcodec_descriptor_get(codec_id); + return desc ? desc->name : NULL; +} + +#else + +struct mp_av_codec { + const char *name; + int codec_id; +}; + +// Some decoders have a different name from the canonical codec name, for +// example the codec "dts" CODEC_ID_DTS has the decoder named "dca", and +// avcodec_find_decoder_by_name("dts") would return 0. We always want the +// canonical name. +// On newer lavc versions, avcodec_descriptor_get_by_name("dts") will return +// CODEC_ID_DTS, which is what we want, but for older versions we need this +// lookup table. +struct mp_av_codec mp_av_codec_id_list[] = { + {"ra_144", CODEC_ID_RA_144}, + {"ra_288", CODEC_ID_RA_288}, + {"smackaudio", CODEC_ID_SMACKAUDIO}, + {"dts", CODEC_ID_DTS}, + {"musepack7", CODEC_ID_MUSEPACK7}, + {"musepack8", CODEC_ID_MUSEPACK8}, + {"amr_nb", CODEC_ID_AMR_NB}, + {"amr_wb", CODEC_ID_AMR_WB}, + {"adpcm_g722", CODEC_ID_ADPCM_G722}, + {"adpcm_g726", CODEC_ID_ADPCM_G726}, + {"westwood_snd1", CODEC_ID_WESTWOOD_SND1}, + {"mp4als", CODEC_ID_MP4ALS}, + {"vixl", CODEC_ID_VIXL}, + {"flv1", CODEC_ID_FLV1}, + {"msmpeg4v3", CODEC_ID_MSMPEG4V3}, + {"jpeg2000", CODEC_ID_JPEG2000}, + {"ulti", CODEC_ID_ULTI}, + {"smackvideo", CODEC_ID_SMACKVIDEO}, + {"tscc", CODEC_ID_TSCC}, + {"cscd", CODEC_ID_CSCD}, + {"tgv", CODEC_ID_TGV}, + {"roq", CODEC_ID_ROQ}, + {"idcin", CODEC_ID_IDCIN}, + {"ws_vqa", CODEC_ID_WS_VQA}, + {0}, +}; + +int mp_codec_to_av_codec_id(const char *codec) +{ + for (int n = 0; mp_av_codec_id_list[n].name; n++) { + if (strcmp(mp_av_codec_id_list[n].name, codec) == 0) + return mp_av_codec_id_list[n].codec_id; + } + AVCodec *avcodec = avcodec_find_decoder_by_name(codec); + return avcodec ? avcodec->id : CODEC_ID_NONE; +} + +const char *mp_codec_from_av_codec_id(int codec_id) +{ + for (int n = 0; mp_av_codec_id_list[n].name; n++) { + if (mp_av_codec_id_list[n].codec_id == codec_id) + return mp_av_codec_id_list[n].name; + } + AVCodec *avcodec = avcodec_find_decoder(codec_id); + return avcodec ? avcodec->name : NULL; +} + +#endif diff --git a/core/av_common.h b/core/av_common.h new file mode 100644 index 0000000000..4fbe592f11 --- /dev/null +++ b/core/av_common.h @@ -0,0 +1,30 @@ +/* + * This file is part of mpv. + * + * mpv 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. + * + * mpv 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 mpv. If not, see . + */ + +#ifndef MP_AVCOMMON_H +#define MP_AVCOMMON_H + +#include +#include + +struct mp_decoder_list; + +void mp_add_lavc_decoders(struct mp_decoder_list *list, enum AVMediaType type); +int mp_codec_to_av_codec_id(const char *codec); +const char *mp_codec_from_av_codec_id(int codec_id); + +#endif diff --git a/core/cfg-mplayer.h b/core/cfg-mplayer.h index 78d85aa9ed..1c0f269e90 100644 --- a/core/cfg-mplayer.h +++ b/core/cfg-mplayer.h @@ -439,11 +439,9 @@ const m_option_t common_opts[] = { {"af-adv", (void *) audio_filter_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL}, OPT_SETTINGSLIST("vf*", vf_settings, 0, &vf_obj_list), - // select audio/video codec (by name) or codec family (by number): - {"afm", &audio_fm_list, CONF_TYPE_STRING_LIST, 0, 0, 0, NULL}, - {"vfm", &video_fm_list, CONF_TYPE_STRING_LIST, 0, 0, 0, NULL}, - {"ac", &audio_codec_list, CONF_TYPE_STRING_LIST, 0, 0, 0, NULL}, - {"vc", &video_codec_list, CONF_TYPE_STRING_LIST, 0, 0, 0, NULL}, + + OPT_STRING("ad", audio_decoders, 0), + OPT_STRING("vd", video_decoders, 0), OPT_CHOICE("hwdec", hwdec_api, 0, ({"no", 0}, @@ -473,7 +471,6 @@ const m_option_t common_opts[] = { {"lavdopts", (void *) lavc_decode_opts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL}, {"lavfdopts", (void *) lavfdopts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL}, - OPT_STRING("codecs-file", codecs_file, 0), // ------------------------- subtitles options -------------------- OPT_STRINGLIST("sub", sub_name, 0), diff --git a/core/codec-cfg.c b/core/codec-cfg.c deleted file mode 100644 index ac875a8a82..0000000000 --- a/core/codec-cfg.c +++ /dev/null @@ -1,607 +0,0 @@ -/* - * codecs.conf parser - * - * Copyright (C) 2001 Szabolcs Berecz - * - * This file is part of MPlayer. - * - * MPlayer 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. - * - * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "core/mp_msg.h" -#include "video/img_format.h" -#include "codec-cfg.h" -#include "core/bstr.h" -#include "stream/stream.h" -#include "core/path.h" - -static const char embedded_file[] = -#include "codecs.conf.h" - ; -static const struct bstr builtin_codecs_conf = { - .start = (char *)embedded_file, .len = sizeof(embedded_file) - 1 -}; - -#define mmioFOURCC( ch0, ch1, ch2, ch3 ) \ - ( (uint32_t)(uint8_t)(ch0) | ( (uint32_t)(uint8_t)(ch1) << 8 ) | \ - ( (uint32_t)(uint8_t)(ch2) << 16 ) | ( (uint32_t)(uint8_t)(ch3) << 24 ) ) - -#define PRINT_LINENUM mp_msg(MSGT_CODECCFG,MSGL_ERR," at line %d\n", line_num) - -#define MAX_NR_TOKEN 16 - -#define RET_EOF -1 -#define RET_EOL -2 - -#define TYPE_VIDEO 0 -#define TYPE_AUDIO 1 - -static int add_to_fourcc(char *s, char *alias, unsigned int *fourcc, - unsigned int *map) -{ - int i, j, freeslots; - unsigned int tmp; - - /* find first unused slot */ - for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++) - /* NOTHING */; - freeslots = CODECS_MAX_FOURCC - i; - if (!freeslots) - goto err_out_too_many; - - do { - if (strlen(s) < 4) - goto err_out_parse_error; - tmp = mmioFOURCC(s[0], s[1], s[2], s[3]); - for (j = 0; j < i; j++) - if (tmp == fourcc[j]) - goto err_out_duplicated; - fourcc[i] = tmp; - map[i] = alias ? mmioFOURCC(alias[0], alias[1], alias[2], alias[3]) : tmp; - s += 4; - i++; - } while ((*(s++) == ',') && --freeslots); - - if (!freeslots) - goto err_out_too_many; - if (*(--s) != '\0') - goto err_out_parse_error; - return 1; -err_out_duplicated: - mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"duplicated FourCC"); - return 0; -err_out_too_many: - mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"too many FourCCs/formats..."); - return 0; -err_out_parse_error: - mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error"); - return 0; -} - -static int add_to_format(char *s, char *alias,unsigned int *fourcc, unsigned int *fourccmap) -{ - int i, j; - char *endptr; - - /* find first unused slot */ - for (i = 0; i < CODECS_MAX_FOURCC && fourcc[i] != 0xffffffff; i++) - /* NOTHING */; - if (i == CODECS_MAX_FOURCC) { - mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"too many FourCCs/formats..."); - return 0; - } - - fourcc[i]=strtoul(s,&endptr,0); - if (*endptr != '\0') { - mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error (format ID not a number?)"); - return 0; - } - - if(alias){ - fourccmap[i]=strtoul(alias,&endptr,0); - if (*endptr != '\0') { - mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"parse error (format ID alias not a number?)"); - return 0; - } - } else - fourccmap[i]=fourcc[i]; - - for (j = 0; j < i; j++) - if (fourcc[j] == fourcc[i]) { - mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"duplicated format ID"); - return 0; - } - - return 1; -} - -static int validate_codec(codecs_t *c, int type) -{ - unsigned int i; - char *tmp_name = c->name; - - for (i = 0; i < strlen(tmp_name) && isalnum(tmp_name[i]); i++) - /* NOTHING */; - - if (i < strlen(tmp_name)) { - mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) name is not valid!\n", c->name); - return 0; - } - - if (!c->info) - c->info = strdup(c->name); - - if (!c->drv) { - mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"\ncodec(%s) does not have a driver!\n", c->name); - return 0; - } - - return 1; -} - -static int add_comment(char *s, char **d) -{ - int pos; - - if (!*d) - pos = 0; - else { - pos = strlen(*d); - (*d)[pos++] = '\n'; - } - if (!(*d = realloc(*d, pos + strlen(s) + 1))) { - mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't allocate memory for comment. "); - return 0; - } - strcpy(*d + pos, s); - return 1; -} - -static struct bstr filetext; -static int line_num = 0; -static char *line; -static char *token[MAX_NR_TOKEN]; -static int read_nextline = 1; - -static int get_token(int min, int max) -{ - static int line_pos; - int i; - char c; - - if (max >= MAX_NR_TOKEN) { - mp_tmsg(MSGT_CODECCFG,MSGL_ERR,"get_token(): max >= MAX_MR_TOKEN!"); - goto out_eof; - } - - memset(token, 0x00, sizeof(*token) * max); - - if (read_nextline) { - if (!filetext.len) - goto out_eof; - struct bstr nextline = bstr_getline(filetext, &filetext); - line = nextline.start; - line[nextline.len - 1] = 0; - line_pos = 0; - ++line_num; - read_nextline = 0; - } - for (i = 0; i < max; i++) { - while (isspace(line[line_pos])) - ++line_pos; - if (line[line_pos] == '\0' || line[line_pos] == '#' || - line[line_pos] == ';') { - read_nextline = 1; - if (i >= min) - goto out_ok; - goto out_eol; - } - token[i] = line + line_pos; - c = line[line_pos]; - if (c == '"' || c == '\'') { - token[i]++; - while (line[++line_pos] != c && line[line_pos]) - /* NOTHING */; - } else { - for (/* NOTHING */; !isspace(line[line_pos]) && - line[line_pos]; line_pos++) - /* NOTHING */; - } - if (!line[line_pos]) { - read_nextline = 1; - if (i >= min - 1) - goto out_ok; - goto out_eol; - } - line[line_pos] = '\0'; - line_pos++; - } -out_ok: - return i; -out_eof: - read_nextline = 1; - return RET_EOF; -out_eol: - return RET_EOL; -} - -static codecs_t *video_codecs=NULL; -static codecs_t *audio_codecs=NULL; -static int nr_vcodecs = 0; -static int nr_acodecs = 0; - -int parse_codec_cfg(const char *cfgfile) -{ - codecs_t *codec = NULL; // current codec - codecs_t **codecsp = NULL;// points to audio_codecs or to video_codecs - char *endptr; // strtoul()... - int *nr_codecsp; - int codec_type; /* TYPE_VIDEO/TYPE_AUDIO */ - int tmp, i; - int codec_cfg_min; - - for (struct bstr s = builtin_codecs_conf; ; bstr_getline(s, &s)) { - if (!s.len) - abort(); - if (bstr_eatstart0(&s, "release ")) { - codec_cfg_min = atoi(s.start); - break; - } - } - - // in case we call it a second time - codecs_uninit_free(); - - nr_vcodecs = 0; - nr_acodecs = 0; - - if (cfgfile) { - // Avoid printing errors from open_stream when trying optional files - if (!mp_path_exists(cfgfile)) { - mp_tmsg(MSGT_CODECCFG, MSGL_V, - "No optional codecs config file: %s\n", cfgfile); - return 0; - } - mp_msg(MSGT_CODECCFG, MSGL_V, "Reading codec config file: %s\n", - cfgfile); - struct stream *s = open_stream(cfgfile, NULL, NULL); - if (!s) - return 0; - filetext = stream_read_complete(s, NULL, 10000000, 1); - free_stream(s); - if (!filetext.start) - return 0; - } else - // Parsing modifies the data - filetext = bstrdup(NULL, builtin_codecs_conf); - void *tmpmem = filetext.start; - - read_nextline = 1; - - /* - * this only catches release lines at the start of - * codecs.conf, before audiocodecs and videocodecs. - */ - while ((tmp = get_token(1, 1)) == RET_EOL) - /* NOTHING */; - if (tmp == RET_EOF) - goto out; - if (!strcmp(token[0], "release")) { - if (get_token(1, 2) < 0) - goto err_out_parse_error; - tmp = atoi(token[0]); - if (tmp < codec_cfg_min) - goto err_out_release_num; - while ((tmp = get_token(1, 1)) == RET_EOL) - /* NOTHING */; - if (tmp == RET_EOF) - goto out; - } else - goto err_out_release_num; - - /* - * check if the next block starts with 'audiocodec' or - * with 'videocodec' - */ - if (!strcmp(token[0], "audiocodec") || !strcmp(token[0], "videocodec")) - goto loop_enter; - goto err_out_parse_error; - - while ((tmp = get_token(1, 1)) != RET_EOF) { - if (tmp == RET_EOL) - continue; - if (!strcmp(token[0], "audiocodec") || - !strcmp(token[0], "videocodec")) { - if (!validate_codec(codec, codec_type)) - goto err_out_not_valid; - loop_enter: - if (*token[0] == 'v') { - codec_type = TYPE_VIDEO; - nr_codecsp = &nr_vcodecs; - codecsp = &video_codecs; - } else { - assert(*token[0] == 'a'); - codec_type = TYPE_AUDIO; - nr_codecsp = &nr_acodecs; - codecsp = &audio_codecs; - } - if (!(*codecsp = realloc(*codecsp, - sizeof(codecs_t) * (*nr_codecsp + 2)))) { - mp_tmsg(MSGT_CODECCFG,MSGL_FATAL,"Can't real