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:
parent
c7f450723f
commit
37a0c9140a
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user