static int enable_cache(struct MPContext *mpctx, struct stream **stream, struct demuxer **demuxer, struct demuxer_params *params) { struct MPOpts *opts = mpctx->opts; if (opts->stream_cache_size <= 0) return 0; char *filename = talloc_strdup(NULL, (*demuxer)->filename); free_demuxer(*demuxer); free_stream(*stream); *stream = stream_open(filename, opts); if (!*stream) { talloc_free(filename); return -1; } stream_enable_cache_percent(stream, opts->stream_cache_size, opts->stream_cache_def_size, opts->stream_cache_min_percent, opts->stream_cache_seek_min_percent); *demuxer = demux_open(*stream, "mkv", params, opts); if (!*demuxer) { talloc_free(filename); free_stream(*stream); return -1; } talloc_free(filename); return 1; }
static void demux_close_demuxers(demuxer_t* demuxer) { dd_priv_t* priv = demuxer->priv; stream_t *s; if(priv->vd) free_demuxer(priv->vd); if(priv->ad && priv->ad != priv->vd) { // That's a hack to free the audio file stream // It's ok atm but we shouldn't free that here s = priv->ad->stream; free_demuxer(priv->ad); free_stream(s); } if(priv->sd && priv->sd != priv->vd && priv->sd != priv->ad) { s = priv->sd->stream; free_demuxer(priv->sd); free_stream(s); } free(priv); }
// segment = get Nth segment of a multi-segment file static bool check_file_seg(struct MPContext *mpctx, struct demuxer **sources, int num_sources, unsigned char uid_map[][16], char *filename, int segment) { bool was_valid = false; struct demuxer_params params = { .matroska_wanted_uids = uid_map, .matroska_wanted_segment = segment, .matroska_was_valid = &was_valid, }; struct stream *s = stream_open(filename, mpctx->opts); if (!s) return false; struct demuxer *d = demux_open(s, "mkv", ¶ms, mpctx->opts); if (!d) { free_stream(s); return was_valid; } if (d->type == DEMUXER_TYPE_MATROSKA) { for (int i = 1; i < num_sources; i++) { if (sources[i]) continue; if (!memcmp(uid_map[i], d->matroska_data.segment_uid, 16)) { mp_msg(MSGT_CPLAYER, MSGL_INFO, "Match for source %d: %s\n", i, d->filename); if (enable_cache(mpctx, &s, &d, ¶ms) < 0) continue; sources[i] = d; return true; } } } free_demuxer(d); free_stream(s); return was_valid; }
static struct demuxer *open_given_type(struct MPOpts *opts, const struct demuxer_desc *desc, struct stream *stream, bool force, int audio_id, int video_id, int sub_id, char *filename, struct demuxer_params *params) { struct demuxer *demuxer; int fformat; demuxer = new_demuxer(opts, stream, desc->type, audio_id, video_id, sub_id, filename); demuxer->params = params; if (desc->check_file) fformat = desc->check_file(demuxer); else fformat = desc->type; if (force) fformat = desc->type; if (fformat == 0) goto fail; if (fformat == desc->type) { if (demuxer->filetype) mp_tmsg(MSGT_DEMUXER, MSGL_INFO, "Detected file format: %s (%s)\n", demuxer->filetype, desc->shortdesc); else mp_tmsg(MSGT_DEMUXER, MSGL_INFO, "Detected file format: %s\n", desc->shortdesc); if (demuxer->desc->open) { struct demuxer *demux2 = demuxer->desc->open(demuxer); if (!demux2) { mp_tmsg(MSGT_DEMUXER, MSGL_ERR, "Opening as detected format " "\"%s\" failed.\n", desc->shortdesc); goto fail; } /* At least demux_mov can return a demux_demuxers instance * from open() instead of the original fed in. */ demuxer = demux2; } demuxer->file_format = fformat; return demuxer; } else { // demux_mov can return playlist instead of mov if (fformat == DEMUXER_TYPE_PLAYLIST) return demuxer; // handled in mplayer.c /* Internal MPEG PS demuxer check can return other MPEG subtypes * which don't have their own checks; recurse to try opening as * the returned type instead. */ free_demuxer(demuxer); desc = get_demuxer_desc_from_type(fformat); if (!desc) { mp_msg(MSGT_DEMUXER, MSGL_ERR, "BUG: recursion to nonexistent file format\n"); return NULL; } return open_given_type(opts, desc, stream, false, audio_id, video_id, sub_id, filename, params); } fail: free_demuxer(demuxer); return NULL; }
static int d_open(demuxer_t *demuxer, enum demux_check check) { struct priv *p = demuxer->priv = talloc_zero(demuxer, struct priv); if (check != DEMUX_CHECK_FORCE) return -1; struct demuxer_params params = {.force_format = "+lavf"}; if (demuxer->stream->uncached_type == STREAMTYPE_CDDA) params.force_format = "+rawaudio"; char *t = NULL; stream_control(demuxer->stream, STREAM_CTRL_GET_DISC_NAME, &t); if (t) { mp_tags_set_str(demuxer->metadata, "TITLE", t); talloc_free(t); } // Initialize the playback time. We need to read _some_ data to get the // correct stream-layer time (at least with libdvdnav). stream_peek(demuxer->stream, 1); reset_pts(demuxer); p->slave = demux_open(demuxer->stream, ¶ms, demuxer->global); if (!p->slave) return -1; // So that we don't miss initial packets of delayed subtitle streams. demux_set_stream_autoselect(p->slave, true); // With cache enabled, the stream can be seekable. This causes demux_lavf.c // (actually libavformat/mpegts.c) to seek sometimes when reading a packet. // It does this to seek back a bit in case the current file position points // into the middle of a packet. if (demuxer->stream->uncached_type != STREAMTYPE_CDDA) { demuxer->stream->seekable = false; // Can be seekable even if the stream isn't. demuxer->seekable = true; demuxer->rel_seeks = true; } add_dvd_streams(demuxer); add_streams(demuxer); add_stream_chapters(demuxer); return 0; } static void d_close(demuxer_t *demuxer) { struct priv *p = demuxer->priv; free_demuxer(p->slave); } static int d_control(demuxer_t *demuxer, int cmd, void *arg) { struct priv *p = demuxer->priv; switch (cmd) { case DEMUXER_CTRL_GET_TIME_LENGTH: { double len; if (stream_control(demuxer->stream, STREAM_CTRL_GET_TIME_LENGTH, &len) < 1) break; *(double *)arg = len; return DEMUXER_CTRL_OK; } case DEMUXER_CTRL_RESYNC: demux_flush(p->slave); break; // relay to slave demuxer case DEMUXER_CTRL_SWITCHED_TRACKS: reselect_streams(demuxer); return DEMUXER_CTRL_OK; } return demux_control(p->slave, cmd, arg); } const demuxer_desc_t demuxer_desc_disc = { .name = "disc", .desc = "CD/DVD/BD wrapper", .fill_buffer = d_fill_buffer, .open = d_open, .close = d_close, .seek = d_seek, .control = d_control, };
static void d_close(demuxer_t *demuxer) { struct priv *p = demuxer->priv; free_demuxer(p->slave); }