demux_mkv: skip files faster in ordered chapter file search

Ordered chapter code tries opening files to find those matching the
SegmentUID values specified in the timeline. Previously this scan did
a full initialization of the Matroska demuxer for each file, then
checked whether the UID value in the demuxer was a match. Make the
scan code instead provide a list of searched-for UIDs to the demuxer
open code, and make that do a comparison against the list as soon as
it sees the UID in the file, aborting if there is no match.

Also fix units used in "Merging timeline part" verbose message.
This commit is contained in:
Uoti Urpala 2011-08-04 08:38:39 +03:00
parent 1f3ad32960
commit 0ece360eea
4 changed files with 95 additions and 51 deletions

View File

@ -374,6 +374,7 @@ static int demux_mkv_read_info(demuxer_t *demuxer)
{ {
mkv_demuxer_t *mkv_d = demuxer->priv; mkv_demuxer_t *mkv_d = demuxer->priv;
stream_t *s = demuxer->stream; stream_t *s = demuxer->stream;
int res = 0;
mkv_d->tc_scale = 1000000; mkv_d->tc_scale = 1000000;
mkv_d->duration = 0; mkv_d->duration = 0;
@ -381,7 +382,7 @@ static int demux_mkv_read_info(demuxer_t *demuxer)
struct ebml_info info = {}; struct ebml_info info = {};
struct ebml_parse_ctx parse_ctx = {}; struct ebml_parse_ctx parse_ctx = {};
if (ebml_read_element(s, &parse_ctx, &info, &ebml_info_desc) < 0) if (ebml_read_element(s, &parse_ctx, &info, &ebml_info_desc) < 0)
return 1; return -1;
if (info.n_timecode_scale) { if (info.n_timecode_scale) {
mkv_d->tc_scale = info.timecode_scale; mkv_d->tc_scale = info.timecode_scale;
mp_msg(MSGT_DEMUX, MSGL_V, mp_msg(MSGT_DEMUX, MSGL_V,
@ -407,8 +408,22 @@ static int demux_mkv_read_info(demuxer_t *demuxer)
mp_msg(MSGT_DEMUX, MSGL_V, "\n"); mp_msg(MSGT_DEMUX, MSGL_V, "\n");
} }
} }
if (demuxer->params && demuxer->params->matroska_wanted_uids) {
unsigned char (*uids)[16] = demuxer->params->matroska_wanted_uids;
if (!info.n_segment_uid)
uids = NULL;
for (int i = 0; i < MP_TALLOC_ELEMS(uids); i++) {
if (!memcmp(info.segment_uid.start, uids[i], 16))
goto out;
}
mp_tmsg(MSGT_DEMUX, MSGL_INFO,
"[mkv] This is not one of the wanted files. "
"Stopping attempt to open.\n");
res = -2;
}
out:
talloc_free(parse_ctx.talloc_ctx); talloc_free(parse_ctx.talloc_ctx);
return 0; return res;
} }
static void parse_trackencodings(struct demuxer *demuxer, static void parse_trackencodings(struct demuxer *demuxer,
@ -923,7 +938,7 @@ static int demux_mkv_read_seekhead(demuxer_t *demuxer)
mp_msg(MSGT_DEMUX, MSGL_V, mp_msg(MSGT_DEMUX, MSGL_V,
"[mkv] /---- [ parsing seek head ] ---------\n"); "[mkv] /---- [ parsing seek head ] ---------\n");
if (ebml_read_element(s, &parse_ctx, &seekhead, &ebml_seek_head_desc) < 0) { if (ebml_read_element(s, &parse_ctx, &seekhead, &ebml_seek_head_desc) < 0) {
res = 1; res = -1;
goto out; goto out;
} }
/* off now holds the position of the next element after the seek head. */ /* off now holds the position of the next element after the seek head. */
@ -940,12 +955,16 @@ static int demux_mkv_read_seekhead(demuxer_t *demuxer)
"end of file - incomplete file?\n"); "end of file - incomplete file?\n");
continue; continue;
} }
read_header_element(demuxer, seek->seek_id, pos); int r = read_header_element(demuxer, seek->seek_id, pos);
if (r <= -2) {
res = r;
goto out;
}
} }
if (!stream_seek(s, off)) { if (!stream_seek(s, off)) {
mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] Couldn't seek back after " mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] Couldn't seek back after "
"SeekHead??\n"); "SeekHead??\n");
res = 1; res = -1;
} }
out: out:
mp_msg(MSGT_DEMUX, MSGL_V, mp_msg(MSGT_DEMUX, MSGL_V,
@ -982,7 +1001,7 @@ static int read_header_element(struct demuxer *demuxer, uint32_t id,
return -1; return -1;
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ segment information...\n"); mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ segment information...\n");
mkv_d->parsed_info = true; mkv_d->parsed_info = true;
return demux_mkv_read_info(demuxer) ? -1 : 1; return demux_mkv_read_info(demuxer);
case MATROSKA_ID_TRACKS: case MATROSKA_ID_TRACKS:
if (mkv_d->parsed_tracks) if (mkv_d->parsed_tracks)
@ -1013,7 +1032,7 @@ static int read_header_element(struct demuxer *demuxer, uint32_t id,
break; break;
if (at_filepos && !seek_pos_id(s, at_filepos, id)) if (at_filepos && !seek_pos_id(s, at_filepos, id))
return -1; return -1;
return demux_mkv_read_seekhead(demuxer) ? -1 : 1; return demux_mkv_read_seekhead(demuxer);
case MATROSKA_ID_CHAPTERS: case MATROSKA_ID_CHAPTERS:
if (mkv_d->parsed_chapters) if (mkv_d->parsed_chapters)
@ -1602,12 +1621,22 @@ static int demux_mkv_open_sub(demuxer_t *demuxer, mkv_track_t *track,
return 0; return 0;
} }
static void mkv_free(struct demuxer *demuxer)
{
struct mkv_demuxer *mkv_d = demuxer->priv;
if (!mkv_d)
return;
for (int i = 0; i < mkv_d->num_tracks; i++)
demux_mkv_free_trackentry(mkv_d->tracks[i]);
free(mkv_d->indexes);
free(mkv_d->cluster_positions);
}
static int demux_mkv_open(demuxer_t *demuxer) static int demux_mkv_open(demuxer_t *demuxer)
{ {
stream_t *s = demuxer->stream; stream_t *s = demuxer->stream;
mkv_demuxer_t *mkv_d; mkv_demuxer_t *mkv_d;
mkv_track_t *track; mkv_track_t *track;
int i, cont = 0;
stream_seek(s, s->start_pos); stream_seek(s, s->start_pos);
if (ebml_read_id(s, NULL) != EBML_ID_EBML) if (ebml_read_id(s, NULL) != EBML_ID_EBML)
@ -1660,7 +1689,7 @@ static int demux_mkv_open(demuxer_t *demuxer)
mkv_d->tc_scale = 1000000; mkv_d->tc_scale = 1000000;
mkv_d->segment_start = stream_tell(s); mkv_d->segment_start = stream_tell(s);
while (!cont) { while (1) {
uint32_t id = ebml_read_id(s, NULL); uint32_t id = ebml_read_id(s, NULL);
switch (id) { switch (id) {
case MATROSKA_ID_CLUSTER: case MATROSKA_ID_CLUSTER:
@ -1668,17 +1697,21 @@ static int demux_mkv_open(demuxer_t *demuxer)
"[mkv] |+ found cluster, headers are " "[mkv] |+ found cluster, headers are "
"parsed completely :)\n"); "parsed completely :)\n");
stream_seek(s, stream_tell(s) - 4); stream_seek(s, stream_tell(s) - 4);
cont = 1; goto headersdone;
break; default:;
int res = read_header_element(demuxer, id, 0);
default: if (res == -2) {
cont = read_header_element(demuxer, id, 0) < 1; mkv_free(demuxer);
return 0;
} else if (res < 1)
goto headersdone;
break; break;
case EBML_ID_VOID: case EBML_ID_VOID:
ebml_read_skip(s, NULL); ebml_read_skip(s, NULL);
break; break;
} }
} }
headersdone:
display_create_tracks(demuxer); display_create_tracks(demuxer);
@ -1686,7 +1719,7 @@ static int demux_mkv_open(demuxer_t *demuxer)
track = NULL; track = NULL;
if (demuxer->video->id == -1) { /* automatically select a video track */ if (demuxer->video->id == -1) { /* automatically select a video track */
/* search for a video track that has the 'default' flag set */ /* search for a video track that has the 'default' flag set */
for (i = 0; i < mkv_d->num_tracks; i++) for (int i = 0; i < mkv_d->num_tracks; i++)
if (mkv_d->tracks[i]->type == MATROSKA_TRACK_VIDEO if (mkv_d->tracks[i]->type == MATROSKA_TRACK_VIDEO
&& mkv_d->tracks[i]->default_track) { && mkv_d->tracks[i]->default_track) {
track = mkv_d->tracks[i]; track = mkv_d->tracks[i];
@ -1696,7 +1729,7 @@ static int demux_mkv_open(demuxer_t *demuxer)
if (track == NULL) if (track == NULL)
/* no track has the 'default' flag set */ /* no track has the 'default' flag set */
/* let's take the first video track */ /* let's take the first video track */
for (i = 0; i < mkv_d->num_tracks; i++) for (int i = 0; i < mkv_d->num_tracks; i++)
if (mkv_d->tracks[i]->type == MATROSKA_TRACK_VIDEO if (mkv_d->tracks[i]->type == MATROSKA_TRACK_VIDEO
&& mkv_d->tracks[i]->id >= 0) { && mkv_d->tracks[i]->id >= 0) {
track = mkv_d->tracks[i]; track = mkv_d->tracks[i];
@ -1731,21 +1764,6 @@ static int demux_mkv_open(demuxer_t *demuxer)
return DEMUXER_TYPE_MATROSKA; return DEMUXER_TYPE_MATROSKA;
} }
static void demux_close_mkv(demuxer_t *demuxer)
{
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
if (mkv_d) {
int i;
if (mkv_d->tracks) {
for (i = 0; i < mkv_d->num_tracks; i++)
demux_mkv_free_trackentry(mkv_d->tracks[i]);
}
free(mkv_d->indexes);
free(mkv_d->cluster_positions);
}
}
static int demux_mkv_read_block_lacing(uint8_t *buffer, uint64_t *size, static int demux_mkv_read_block_lacing(uint8_t *buffer, uint64_t *size,
uint8_t *laces, uint8_t *laces,
uint32_t **all_lace_sizes) uint32_t **all_lace_sizes)
@ -2518,7 +2536,7 @@ const demuxer_desc_t demuxer_desc_matroska = {
demux_mkv_open, demux_mkv_open,
demux_mkv_fill_buffer, demux_mkv_fill_buffer,
NULL, NULL,
demux_close_mkv, mkv_free,
demux_mkv_seek, demux_mkv_seek,
demux_mkv_control demux_mkv_control
}; };

View File

@ -911,12 +911,14 @@ static struct demuxer *open_given_type(struct MPOpts *opts,
const struct demuxer_desc *desc, const struct demuxer_desc *desc,
struct stream *stream, bool force, struct stream *stream, bool force,
int audio_id, int video_id, int sub_id, int audio_id, int video_id, int sub_id,
char *filename) char *filename,
struct demuxer_params *params)
{ {
struct demuxer *demuxer; struct demuxer *demuxer;
int fformat; int fformat;
demuxer = new_demuxer(opts, stream, desc->type, audio_id, demuxer = new_demuxer(opts, stream, desc->type, audio_id,
video_id, sub_id, filename); video_id, sub_id, filename);
demuxer->params = params;
if (desc->check_file) if (desc->check_file)
fformat = desc->check_file(demuxer); fformat = desc->check_file(demuxer);
else else
@ -960,7 +962,7 @@ static struct demuxer *open_given_type(struct MPOpts *opts,
return NULL; return NULL;
} }
return open_given_type(opts, desc, stream, false, audio_id, return open_given_type(opts, desc, stream, false, audio_id,
video_id, sub_id, filename); video_id, sub_id, filename, params);
} }
fail: fail:
free_demuxer(demuxer); free_demuxer(demuxer);
@ -971,7 +973,8 @@ static struct demuxer *demux_open_stream(struct MPOpts *opts,
struct stream *stream, struct stream *stream,
int file_format, bool force, int file_format, bool force,
int audio_id, int video_id, int sub_id, int audio_id, int video_id, int sub_id,
char *filename) char *filename,
struct demuxer_params *params)
{ {
struct demuxer *demuxer = NULL; struct demuxer *demuxer = NULL;
const struct demuxer_desc *desc; const struct demuxer_desc *desc;
@ -983,7 +986,7 @@ static struct demuxer *demux_open_stream(struct MPOpts *opts,
// should only happen with obsolete -demuxer 99 numeric format // should only happen with obsolete -demuxer 99 numeric format
return NULL; return NULL;
demuxer = open_given_type(opts, desc, stream, force, audio_id, demuxer = open_given_type(opts, desc, stream, force, audio_id,
video_id, sub_id, filename); video_id, sub_id, filename, params);
if (demuxer) if (demuxer)
goto dmx_open; goto dmx_open;
return NULL; return NULL;
@ -993,7 +996,7 @@ static struct demuxer *demux_open_stream(struct MPOpts *opts,
for (int i = 0; (desc = demuxer_list[i]); i++) { for (int i = 0; (desc = demuxer_list[i]); i++) {
if (desc->safe_check) { if (desc->safe_check) {
demuxer = open_given_type(opts, desc, stream, false, audio_id, demuxer = open_given_type(opts, desc, stream, false, audio_id,
video_id, sub_id, filename); video_id, sub_id, filename, params);
if (demuxer) if (demuxer)
goto dmx_open; goto dmx_open;
} }
@ -1006,7 +1009,7 @@ static struct demuxer *demux_open_stream(struct MPOpts *opts,
desc = get_demuxer_desc_from_type(demuxer_type_by_filename(filename)); desc = get_demuxer_desc_from_type(demuxer_type_by_filename(filename));
if (desc) if (desc)
demuxer = open_given_type(opts, desc, stream, false, audio_id, demuxer = open_given_type(opts, desc, stream, false, audio_id,
video_id, sub_id, filename); video_id, sub_id, filename, params);
if (demuxer) if (demuxer)
goto dmx_open; goto dmx_open;
} }
@ -1015,7 +1018,7 @@ static struct demuxer *demux_open_stream(struct MPOpts *opts,
for (int i = 0; (desc = demuxer_list[i]); i++) { for (int i = 0; (desc = demuxer_list[i]); i++) {
if (!desc->safe_check && desc->check_file) { if (!desc->safe_check && desc->check_file) {
demuxer = open_given_type(opts, desc, stream, false, audio_id, demuxer = open_given_type(opts, desc, stream, false, audio_id,
video_id, sub_id, filename); video_id, sub_id, filename, params);
if (demuxer) if (demuxer)
goto dmx_open; goto dmx_open;
} }
@ -1041,9 +1044,17 @@ static struct demuxer *demux_open_stream(struct MPOpts *opts,
return demuxer; return demuxer;
} }
demuxer_t *demux_open(struct MPOpts *opts, stream_t *vs, int file_format, struct demuxer *demux_open(struct MPOpts *opts, stream_t *vs, int file_format,
int audio_id, int video_id, int dvdsub_id, int audio_id, int video_id, int sub_id,
char *filename) char *filename)
{
return demux_open_withparams(opts, vs, file_format, audio_id, video_id,
sub_id, filename, NULL);
}
struct demuxer *demux_open_withparams(struct MPOpts *opts, stream_t *vs,
int file_format, int audio_id, int video_id, int dvdsub_id,
char *filename, struct demuxer_params *params)
{ {
stream_t *as = NULL, *ss = NULL; stream_t *as = NULL, *ss = NULL;
demuxer_t *vd, *ad = NULL, *sd = NULL; demuxer_t *vd, *ad = NULL, *sd = NULL;
@ -1108,7 +1119,8 @@ demuxer_t *demux_open(struct MPOpts *opts, stream_t *vs, int file_format,
vd = demux_open_stream(opts, vs, demuxer_type ? demuxer_type : file_format, vd = demux_open_stream(opts, vs, demuxer_type ? demuxer_type : file_format,
demuxer_force, opts->audio_stream ? -2 : audio_id, demuxer_force, opts->audio_stream ? -2 : audio_id,
video_id, opts->sub_stream ? -2 : dvdsub_id, filename); video_id, opts->sub_stream ? -2 : dvdsub_id,
filename, params);
if (!vd) { if (!vd) {
if (as) if (as)
free_stream(as); free_stream(as);
@ -1120,7 +1132,7 @@ demuxer_t *demux_open(struct MPOpts *opts, stream_t *vs, int file_format,
ad = demux_open_stream(opts, as, ad = demux_open_stream(opts, as,
audio_demuxer_type ? audio_demuxer_type : afmt, audio_demuxer_type ? audio_demuxer_type : afmt,
audio_demuxer_force, audio_id, -2, -2, audio_demuxer_force, audio_id, -2, -2,
opts->audio_stream); opts->audio_stream, params);
if (!ad) { if (!ad) {
mp_tmsg(MSGT_DEMUXER, MSGL_WARN, "Failed to open audio demuxer: %s\n", mp_tmsg(MSGT_DEMUXER, MSGL_WARN, "Failed to open audio demuxer: %s\n",
opts->audio_stream); opts->audio_stream);
@ -1133,7 +1145,7 @@ demuxer_t *demux_open(struct MPOpts *opts, stream_t *vs, int file_format,
sd = demux_open_stream(opts, ss, sd = demux_open_stream(opts, ss,
sub_demuxer_type ? sub_demuxer_type : sfmt, sub_demuxer_type ? sub_demuxer_type : sfmt,
sub_demuxer_force, -2, -2, dvdsub_id, sub_demuxer_force, -2, -2, dvdsub_id,
opts->sub_stream); opts->sub_stream, params);
if (!sd) { if (!sd) {
mp_tmsg(MSGT_DEMUXER, MSGL_WARN, mp_tmsg(MSGT_DEMUXER, MSGL_WARN,
"Failed to open subtitle demuxer: %s\n", opts->sub_stream); "Failed to open subtitle demuxer: %s\n", opts->sub_stream);

View File

@ -239,6 +239,10 @@ typedef struct demux_attachment
unsigned int data_size; unsigned int data_size;
} demux_attachment_t; } demux_attachment_t;
struct demuxer_params {
unsigned char (*matroska_wanted_uids)[16];
};
typedef struct demuxer { typedef struct demuxer {
const demuxer_desc_t *desc; ///< Demuxer description structure const demuxer_desc_t *desc; ///< Demuxer description structure
const char *filetype; // format name when not identified by demuxer (libavformat) const char *filetype; // format name when not identified by demuxer (libavformat)
@ -289,6 +293,7 @@ typedef struct demuxer {
void *priv; // demuxer-specific internal data void *priv; // demuxer-specific internal data
char **info; // metadata char **info; // metadata
struct MPOpts *opts; struct MPOpts *opts;
struct demuxer_params *params;
} demuxer_t; } demuxer_t;
typedef struct { typedef struct {
@ -370,6 +375,11 @@ static inline int avi_stream_id(unsigned int id)
struct demuxer *demux_open(struct MPOpts *opts, struct stream *stream, struct demuxer *demux_open(struct MPOpts *opts, struct stream *stream,
int file_format, int aid, int vid, int sid, int file_format, int aid, int vid, int sid,
char *filename); char *filename);
struct demuxer *demux_open_withparams(struct MPOpts *opts,
struct stream *stream, int file_format, int aid, int vid, int sid,
char *filename, struct demuxer_params *params);
void demux_flush(struct demuxer *demuxer); void demux_flush(struct demuxer *demuxer);
int demux_seek(struct demuxer *demuxer, float rel_seek_secs, float audio_delay, int demux_seek(struct demuxer *demuxer, float rel_seek_secs, float audio_delay,
int flags); int flags);

View File

@ -112,10 +112,12 @@ static int find_ordered_chapter_sources(struct MPContext *mpctx,
struct stream *s = open_stream(filenames[i], &mpctx->opts, &format); struct stream *s = open_stream(filenames[i], &mpctx->opts, &format);
if (!s) if (!s)
continue; continue;
struct demuxer *d = demux_open(&mpctx->opts, s, DEMUXER_TYPE_MATROSKA, struct demuxer *d = demux_open_withparams(&mpctx->opts, s,
mpctx->opts.audio_id, DEMUXER_TYPE_MATROSKA, mpctx->opts.audio_id,
mpctx->opts.video_id, mpctx->opts.video_id, mpctx->opts.sub_id, filenames[i],
mpctx->opts.sub_id, filenames[i]); &(struct demuxer_params){.matroska_wanted_uids = uid_map});
if (!d) { if (!d) {
free_stream(s); free_stream(s);
continue; continue;
@ -176,7 +178,8 @@ void build_ordered_chapter_timeline(struct MPContext *mpctx)
m->num_ordered_chapters+1); m->num_ordered_chapters+1);
sources[0].stream = mpctx->stream; sources[0].stream = mpctx->stream;
sources[0].demuxer = mpctx->demuxer; sources[0].demuxer = mpctx->demuxer;
unsigned char uid_map[m->num_ordered_chapters+1][16]; unsigned char (*uid_map)[16] = talloc_array_ptrtype(NULL, uid_map,
m->num_ordered_chapters + 1);
int num_sources = 1; int num_sources = 1;
memcpy(uid_map[0], m->segment_uid, 16); memcpy(uid_map[0], m->segment_uid, 16);
@ -241,7 +244,7 @@ void build_ordered_chapter_timeline(struct MPContext *mpctx)
/* Chapter was merged at an inexact boundary; /* Chapter was merged at an inexact boundary;
* adjust timestamps to match. */ * adjust timestamps to match. */
mp_msg(MSGT_CPLAYER, MSGL_V, "Merging timeline part %d with " mp_msg(MSGT_CPLAYER, MSGL_V, "Merging timeline part %d with "
"offset %d ms.\n", i, (int) join_diff); "offset %g ms.\n", i, join_diff / 1e6);
starttime += join_diff; starttime += join_diff;
} }
chapters[num_chapters].start = starttime / 1e9; chapters[num_chapters].start = starttime / 1e9;
@ -250,6 +253,7 @@ void build_ordered_chapter_timeline(struct MPContext *mpctx)
num_chapters++; num_chapters++;
} }
timeline[part_count].start = starttime / 1e9; timeline[part_count].start = starttime / 1e9;
talloc_free(uid_map);
if (!part_count) { if (!part_count) {
// None of the parts come from the file itself??? // None of the parts come from the file itself???