1
0
mirror of https://github.com/mpv-player/mpv synced 2024-12-22 06:42:03 +00:00
mpv/core/av_common.c
wm4 14427ae2ee core: make more robust against missing libavcodec AVCodecDescriptor entries
Missing entries cause avcodec_descriptor_get() to return NULL, and in
turn mp_codec_from_av_codec_id() will return NULL. This shouldn't
happen, and avcodec_descriptor_get() returning NULL for a valid codec is
clearly a bug.

But make it more robust anyway, and use the decoder's name if this
happens, because I doubt maintainance of the AVCodecDescriptor table
in ffmpeg/Libav will always be perfect and reliable.
2013-03-07 23:42:58 +01:00

182 lines
6.0 KiB
C

/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <libavutil/common.h>
#include "config.h"
#include "core/mp_talloc.h"
#include "av_common.h"
#include "codecs.h"
// Copy the codec-related fields from st into avctx. This does not set the
// codec itself, only codec related header data provided by libavformat.
// The goal is to initialize a new decoder with the header data provided by
// libavformat, and unlike avcodec_copy_context(), allow the user to create
// a clean AVCodecContext for a manually selected AVCodec.
// This is strictly for decoding only.
void mp_copy_lav_codec_headers(AVCodecContext *avctx, AVCodecContext *st)
{
if (st->extradata_size) {
av_free(avctx->extradata);
avctx->extradata_size = 0;
avctx->extradata =
av_mallocz(st->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
if (avctx->extradata) {
avctx->extradata_size = st->extradata_size;
memcpy(avctx->extradata, st->extradata, st->extradata_size);
}
}
avctx->codec_tag = st->codec_tag;
avctx->stream_codec_tag = st->stream_codec_tag;
avctx->bit_rate = st->bit_rate;
avctx->width = st->width;
avctx->height = st->height;
avctx->pix_fmt = st->pix_fmt;
avctx->sample_aspect_ratio = st->sample_aspect_ratio;
avctx->chroma_sample_location = st->chroma_sample_location;
avctx->sample_rate = st->sample_rate;
avctx->channels = st->channels;
avctx->block_align = st->block_align;
avctx->channel_layout = st->channel_layout;
avctx->audio_service_type = st->audio_service_type;
avctx->bits_per_coded_sample = st->bits_per_coded_sample;
}
#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)
{
int id = CODEC_ID_NONE;
const AVCodecDescriptor *desc = avcodec_descriptor_get_by_name(codec);
if (desc)
id = desc->id;
if (id == CODEC_ID_NONE) {
AVCodec *avcodec = avcodec_find_decoder_by_name(codec);
if (avcodec)
id = avcodec->id;
}
return id;
}
const char *mp_codec_from_av_codec_id(int codec_id)
{
const char *name = NULL;
const AVCodecDescriptor *desc = avcodec_descriptor_get(codec_id);
if (desc)
name = desc->name;
if (!name) {
AVCodec *avcodec = avcodec_find_decoder(codec_id);
if (avcodec)
name = avcodec->name;
}
return name;
}
#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