1
0
mirror of https://github.com/mpv-player/mpv synced 2025-04-07 10:02:50 +00:00

demux_lavf: reorganize hacks

An attempt to make format-specifics more declarative. (In my opinion,
all of this should be either provided by libavformat, or should not be
needed.)

I'm still leaving many checks with matches_avinputformat_name(), because
they're so specific.

Also useful for the following commit.
This commit is contained in:
wm4 2015-02-18 21:10:15 +01:00
parent c7f450723f
commit 37a0c9140a

View File

@ -94,9 +94,49 @@ const struct m_sub_options demux_lavf_conf = {
}, },
}; };
struct format_hack {
const char *ff_name;
const char *mime_type;
int probescore;
float analyzeduration;
bool max_probe : 1; // use probescore only if max. probe size reached
bool ignore : 1; // blacklisted
bool no_stream : 1; // do not wrap struct stream as AVIOContext
bool use_stream_ids : 1; // export the native stream IDs
// Do not confuse player's position estimation (position is into external
// segment, with e.g. HLS, player knows about the playlist main file only).
bool clear_filepos : 1;
};
#define BLACKLIST(fmt) {fmt, .ignore = true}
static const struct format_hack format_hacks[] = {
// for webradios
{"aac", "audio/aacp", 25, 0.5},
{"aac", "audio/aac", 25, 0.5},
// some mp3 files don't detect correctly (usually id3v2 too large)
{"mp3", "audio/mpeg", 24, 0.5},
{"mp3", NULL, 24, .max_probe = true},
{"hls", .no_stream = true, .clear_filepos = true},
{"mpeg", .use_stream_ids = true},
{"mpegts", .use_stream_ids = true},
// Useless non-sense, sometimes breaks MLP2 subreader.c fallback
BLACKLIST("tty"),
// Image demuxers, disabled in favor of demux_mf (for now):
BLACKLIST("image"),
BLACKLIST("image2pipe"),
BLACKLIST("bmp_pipe"), BLACKLIST("dpx_pipe"), BLACKLIST("exr_pipe"),
BLACKLIST("j2k_pipe"), BLACKLIST("png_pipe"), BLACKLIST("tiff_pipe"),
BLACKLIST("jpeg_pipe"),
{0}
};
typedef struct lavf_priv { typedef struct lavf_priv {
char *filename; char *filename;
const struct format_hack *format_hack; struct format_hack format_hack;
AVInputFormat *avif; AVInputFormat *avif;
AVFormatContext *avfc; AVFormatContext *avfc;
AVIOContext *pb; AVIOContext *pb;
@ -109,32 +149,22 @@ typedef struct lavf_priv {
bool merge_track_metadata; bool merge_track_metadata;
} lavf_priv_t; } lavf_priv_t;
struct format_hack { // At least mp4 has name="mov,mp4,m4a,3gp,3g2,mj2", so we split the name
const char *ff_name; // on "," in general.
const char *mime_type; static bool matches_avinputformat_name(struct lavf_priv *priv,
int probescore; const char *name)
float analyzeduration; {
bool max_probe; // use probescore only if max. probe size reached const char *avifname = priv->avif->name;
}; while (1) {
const char *next = strchr(avifname, ',');
static const struct format_hack format_hacks[] = { if (!next)
// for webradios return !strcmp(avifname, name);
{"aac", "audio/aacp", 25, 0.5}, int len = next - avifname;
{"aac", "audio/aac", 25, 0.5}, if (len == strlen(name) && !memcmp(avifname, name, len))
// some mp3 files don't detect correctly return true;
{"mp3", "audio/mpeg", 24, 0.5}, avifname = next + 1;
{"mp3", NULL, 24, .max_probe = true}, }
{0} }
};
static const char *const format_blacklist[] = {
"tty", // Useless non-sense, sometimes breaks MLP2 subreader.c fallback
// Image demuxers, disabled in favor of demux_mf:
"image2", "image2pipe",
"bmp_pipe", "dpx_pipe", "exr_pipe", "j2k_pipe", "png_pipe", "tiff_pipe",
"jpeg_pipe",
0
};
static int mp_read(void *opaque, uint8_t *buf, int size) static int mp_read(void *opaque, uint8_t *buf, int size)
{ {
@ -306,41 +336,34 @@ static int lavf_check_file(demuxer_t *demuxer, enum demux_check check)
MP_VERBOSE(demuxer, "Found '%s' at score=%d size=%d.\n", MP_VERBOSE(demuxer, "Found '%s' at score=%d size=%d.\n",
priv->avif->name, score, avpd.buf_size); priv->avif->name, score, avpd.buf_size);
priv->format_hack = NULL;
for (int n = 0; format_hacks[n].ff_name; n++) { for (int n = 0; format_hacks[n].ff_name; n++) {
const struct format_hack *entry = &format_hacks[n]; const struct format_hack *entry = &format_hacks[n];
if (strcmp(entry->ff_name, priv->avif->name) != 0) if (!matches_avinputformat_name(priv, entry->ff_name))
continue; continue;
if (entry->mime_type && strcasecmp(entry->mime_type, mime_type) != 0) if (entry->mime_type && strcasecmp(entry->mime_type, mime_type) != 0)
continue; continue;
priv->format_hack = entry; priv->format_hack = *entry;
break; break;
} }
if (score >= min_probe) if (score >= min_probe)
break; break;
if (priv->format_hack) { if (priv->format_hack.probescore &&
if (score >= priv->format_hack->probescore && score >= priv->format_hack.probescore &&
(!priv->format_hack->max_probe || final_probe)) (!priv->format_hack.max_probe || final_probe))
break; break;
}
} }
priv->avif = NULL; priv->avif = NULL;
priv->format_hack = NULL; priv->format_hack = (struct format_hack){0};
} while (!final_probe); } while (!final_probe);
av_free(avpd.buf); av_free(avpd.buf);
if (priv->avif && !format) { if (priv->avif && !format && priv->format_hack.ignore) {
for (int n = 0; format_blacklist[n]; n++) { MP_VERBOSE(demuxer, "Format blacklisted.\n");
if (strcmp(format_blacklist[n], priv->avif->name) == 0) { priv->avif = NULL;
MP_VERBOSE(demuxer, "Format blacklisted.\n");
priv->avif = NULL;
break;
}
}
} }
if (!priv->avif) { if (!priv->avif) {
@ -355,23 +378,6 @@ success:
return 0; return 0;
} }
static bool matches_avinputformat_name(struct lavf_priv *priv,
const char *name)
{
// At least mp4 has name="mov,mp4,m4a,3gp,3g2,mj2", so we split the name
// on "," in general.
const char *avifname = priv->avif->name;
while (1) {
const char *next = strchr(avifname, ',');
if (!next)
return !strcmp(avifname, name);
int len = next - avifname;
if (len == strlen(name) && !memcmp(avifname, name, len))
return true;
avifname = next + 1;
}
}
static uint8_t char2int(char c) static uint8_t char2int(char c)
{ {
if (c >= '0' && c <= '9') return c - '0'; if (c >= '0' && c <= '9') return c - '0';
@ -597,8 +603,7 @@ static void handle_stream(demuxer_t *demuxer, int i)
if (st->disposition & AV_DISPOSITION_DEFAULT) if (st->disposition & AV_DISPOSITION_DEFAULT)
sh->default_track = 1; sh->default_track = 1;
if (matches_avinputformat_name(priv, "mpeg") || if (priv->format_hack.use_stream_ids)
matches_avinputformat_name(priv, "mpegts"))
sh->demuxer_id = st->id; sh->demuxer_id = st->id;
AVDictionaryEntry *title = av_dict_get(st->metadata, "title", NULL, 0); AVDictionaryEntry *title = av_dict_get(st->metadata, "title", NULL, 0);
if (title && title->value) if (title && title->value)
@ -708,8 +713,8 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
lavfdopts->probesize); lavfdopts->probesize);
} }
if (priv->format_hack && priv->format_hack->analyzeduration) if (priv->format_hack.analyzeduration)
analyze_duration = priv->format_hack->analyzeduration; analyze_duration = priv->format_hack.analyzeduration;
if (lavfdopts->analyzeduration) if (lavfdopts->analyzeduration)
analyze_duration = lavfdopts->analyzeduration; analyze_duration = lavfdopts->analyzeduration;
if (analyze_duration > 0) { if (analyze_duration > 0) {
@ -723,7 +728,7 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
if ((priv->avif->flags & AVFMT_NOFILE) || if ((priv->avif->flags & AVFMT_NOFILE) ||
demuxer->stream->type == STREAMTYPE_AVDEVICE || demuxer->stream->type == STREAMTYPE_AVDEVICE ||
matches_avinputformat_name(priv, "hls")) priv->format_hack.no_stream)
{ {
mp_setup_av_network_options(&dopts, demuxer->global, demuxer->log, opts); mp_setup_av_network_options(&dopts, demuxer->global, demuxer->log, opts);
// This might be incorrect. // This might be incorrect.
@ -870,9 +875,7 @@ static int demux_lavf_fill_buffer(demuxer_t *demux)
} }
av_free_packet(pkt); av_free_packet(pkt);
// Do not confuse player's position estimation (position is into segment, if (priv->format_hack.clear_filepos)
// player knows about the playlist main file only).
if (matches_avinputformat_name(priv, "hls"))
dp->pos = -1; dp->pos = -1;
demux_add_packet(stream, dp); demux_add_packet(stream, dp);