diff options
Diffstat (limited to 'demux')
-rw-r--r-- | demux/demux.c | 11 | ||||
-rw-r--r-- | demux/demux.h | 1 | ||||
-rw-r--r-- | demux/demux_lavf.c | 9 | ||||
-rw-r--r-- | demux/demux_mkv.c | 87 | ||||
-rw-r--r-- | demux/demux_playlist.c | 54 | ||||
-rw-r--r-- | demux/demux_raw.c | 1 | ||||
-rw-r--r-- | demux/stheader.h | 1 |
7 files changed, 126 insertions, 38 deletions
diff --git a/demux/demux.c b/demux/demux.c index c5fb6dc517..bb367055cb 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -144,6 +144,8 @@ struct demux_stream { // all fields are protected by in->lock bool selected; // user wants packets from this stream bool active; // try to keep at least 1 packet queued + // if false, this stream is disabled, or passively + // read (like subtitles) bool eof; // end of demuxed stream? (true if all buffer empty) bool refreshing; size_t packs; // number of packets in buffer @@ -431,7 +433,6 @@ static bool read_packet(struct demux_internal *in) for (int n = 0; n < in->d_buffer->num_streams; n++) { struct demux_stream *ds = in->d_buffer->streams[n]->ds; ds->eof = true; - ds->active = false; } // If we had EOF previously, then don't wakeup (avoids wakeup loop) if (!in->last_eof) { @@ -498,7 +499,7 @@ static void start_refreshing(struct demux_internal *in) // Seek back to player's current position, with a small offset added. in->d_thread->desc->seek(in->d_thread, start_ts - 1.0, - SEEK_ABSOLUTE | SEEK_BACKWARD | SEEK_SUBPREROLL); + SEEK_ABSOLUTE | SEEK_BACKWARD | SEEK_HR); pthread_mutex_lock(&in->lock); } @@ -1382,10 +1383,8 @@ static int cached_demux_control(struct demux_internal *in, int cmd, void *arg) struct demux_stream *ds = in->d_user->streams[n]->ds; if (ds->active) { r->underrun |= !ds->head && !ds->eof; - if (!ds->eof) { - r->ts_range[0] = MP_PTS_MAX(r->ts_range[0], ds->base_ts); - r->ts_range[1] = MP_PTS_MIN(r->ts_range[1], ds->last_ts); - } + r->ts_range[0] = MP_PTS_MAX(r->ts_range[0], ds->base_ts); + r->ts_range[1] = MP_PTS_MIN(r->ts_range[1], ds->last_ts); num_packets += ds->packs; } } diff --git a/demux/demux.h b/demux/demux.h index b730724ed3..f3ed97c386 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -67,7 +67,6 @@ struct demux_ctrl_stream_ctrl { #define SEEK_FACTOR (1 << 1) // argument is in range [0,1] #define SEEK_FORWARD (1 << 2) // prefer later time if not exact #define SEEK_BACKWARD (1 << 3) // prefer earlier time if not exact -#define SEEK_SUBPREROLL (1 << 4) // try to get more subtitle packets #define SEEK_HR (1 << 5) // hr-seek (this is a weak hint only) // Strictness of the demuxer open format check. diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index dd122f7325..c14869555c 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -65,6 +65,7 @@ struct demux_lavf_opts { char *format; char *cryptokey; char **avopts; + int hacks; int genptsmode; }; @@ -78,6 +79,7 @@ const struct m_sub_options demux_lavf_conf = { OPT_FLAG("allow-mimetype", allow_mimetype, 0), OPT_INTRANGE("probescore", probescore, 0, 1, AVPROBE_SCORE_MAX), OPT_STRING("cryptokey", cryptokey, 0), + OPT_FLAG("hacks", hacks, 0), OPT_CHOICE("genpts-mode", genptsmode, 0, ({"lavf", 1}, {"no", 0})), OPT_KEYVALUELIST("o", avopts, 0), @@ -86,6 +88,7 @@ const struct m_sub_options demux_lavf_conf = { .size = sizeof(struct demux_lavf_opts), .defaults = &(const struct demux_lavf_opts){ .allow_mimetype = 1, + .hacks = 1, // AVPROBE_SCORE_MAX/4 + 1 is the "recommended" limit. Below that, the // user is supposed to retry with larger probe sizes until a higher // value is reached. @@ -351,6 +354,8 @@ static int lavf_check_file(demuxer_t *demuxer, enum demux_check check) for (int n = 0; format_hacks[n].ff_name; n++) { const struct format_hack *entry = &format_hacks[n]; + if (!lavfdopts->hacks) + continue; if (!matches_avinputformat_name(priv, entry->ff_name)) continue; if (entry->mime_type && strcasecmp(entry->mime_type, mime_type) != 0) @@ -540,10 +545,6 @@ static void handle_stream(demuxer_t *demuxer, int i) sh_video->aspect = codec->width * codec->sample_aspect_ratio.num / (float)(codec->height * codec->sample_aspect_ratio.den); - sh_video->bitrate = codec->bit_rate; - if (sh_video->bitrate == 0) - sh_video->bitrate = avfc->bit_rate; - uint8_t *sd = av_stream_get_side_data(st, AV_PKT_DATA_DISPLAYMATRIX, NULL); if (sd) sh_video->rotate = -av_display_rotation_get((uint32_t *)sd); diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index 4216a6ad71..b4ae042feb 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -24,6 +24,7 @@ #include <stdio.h> #include <inttypes.h> #include <stdbool.h> +#include <math.h> #include <assert.h> #include <libavutil/common.h> @@ -43,6 +44,7 @@ #include "talloc.h" #include "common/av_common.h" #include "options/options.h" +#include "options/m_option.h" #include "misc/bstr.h" #include "stream/stream.h" #include "video/csputils.h" @@ -184,6 +186,30 @@ typedef struct mkv_demuxer { bool eof_warning; } mkv_demuxer_t; +#define OPT_BASE_STRUCT struct demux_mkv_opts +struct demux_mkv_opts { + int subtitle_preroll; + double subtitle_preroll_secs; + int probe_duration; + int fix_timestamps; +}; + +const struct m_sub_options demux_mkv_conf = { + .opts = (const m_option_t[]) { + OPT_FLAG("subtitle-preroll", subtitle_preroll, 0), + OPT_DOUBLE("subtitle-preroll-secs", subtitle_preroll_secs, + M_OPT_MIN, .min = 0), + OPT_FLAG("probe-video-duration", probe_duration, 0), + OPT_FLAG("fix-timestamps", fix_timestamps, 0), + {0} + }, + .size = sizeof(struct demux_mkv_opts), + .defaults = &(const struct demux_mkv_opts){ + .subtitle_preroll_secs = 1.0, + .fix_timestamps = 1, + }, +}; + #define REALHEADER_SIZE 16 #define RVPROPERTIES_SIZE 34 #define RAPROPERTIES4_SIZE 56 @@ -1751,6 +1777,7 @@ static int read_mkv_segment_header(demuxer_t *demuxer, int64_t *segment_end) static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check) { stream_t *s = demuxer->stream; + struct MPOpts *opts = demuxer->opts; mkv_demuxer_t *mkv_d; int64_t start_pos; int64_t end_pos; @@ -1836,7 +1863,7 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check) add_coverart(demuxer); demuxer->allow_refresh_seeks = true; - if (demuxer->opts->mkv_probe_duration) + if (opts->demux_mkv->probe_duration) probe_last_timestamp(demuxer); return 0; @@ -2304,6 +2331,19 @@ exit: return res; } +static double fix_timestamp(demuxer_t *demuxer, mkv_track_t *track, double ts) +{ + mkv_demuxer_t *mkv_d = demuxer->priv; + if (demuxer->opts->demux_mkv->fix_timestamps && track->default_duration > 0) { + // Assume that timestamps have been rounded to the timecode scale. + double quant = MPMIN(mkv_d->tc_scale / 1e9, 0.001); + double rts = rint(ts / track->default_duration) * track->default_duration; + if (fabs(rts - ts) < quant) + ts = rts; + } + return ts; +} + static int handle_block(demuxer_t *demuxer, struct block_info *block_info) { mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv; @@ -2326,7 +2366,7 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info) return 0; } - current_pts = tc / 1e9 - track->codec_delay; + current_pts = fix_timestamp(demuxer, track, tc / 1e9) - track->codec_delay; if (track->type == MATROSKA_TRACK_AUDIO) { if (mkv_d->a_skip_to_keyframe) @@ -2619,35 +2659,30 @@ static int create_index_until(struct demuxer *demuxer, uint64_t timecode) return 0; } +#define FLAG_BACKWARD 1 +#define FLAG_SUBPREROLL 2 static struct mkv_index *seek_with_cues(struct demuxer *demuxer, int seek_id, int64_t target_timecode, int flags) { + struct MPOpts *opts = demuxer->opts; struct mkv_demuxer *mkv_d = demuxer->priv; struct mkv_index *index = NULL; - /* Find the entry in the index closest to the target timecode in the - * give direction. If there are no such entries - we're trying to seek - * backward from a target time before the first entry or forward from a - * target time after the last entry - then still seek to the first/last - * entry if that's further in the direction wanted than mkv_d->last_pts. - */ - int64_t min_diff = target_timecode - (int64_t)(mkv_d->last_pts * 1e9 + 0.5); - if (flags & SEEK_BACKWARD) - min_diff = -min_diff; - min_diff = FFMAX(min_diff, 1); - + int64_t min_diff = INT64_MIN; for (size_t i = 0; i < mkv_d->num_indexes; i++) { if (seek_id < 0 || mkv_d->indexes[i].tnum == seek_id) { int64_t diff = target_timecode - (int64_t) (mkv_d->indexes[i].timecode * mkv_d->tc_scale); - if (flags & SEEK_BACKWARD) + if (flags & FLAG_BACKWARD) diff = -diff; - if (diff <= 0) { - if (min_diff <= 0 && diff <= min_diff) + if (min_diff != INT64_MIN) { + if (diff <= 0) { + if (min_diff <= 0 && diff <= min_diff) + continue; + } else if (diff >= min_diff) continue; - } else if (diff >= min_diff) - continue; + } min_diff = diff; index = mkv_d->indexes + i; } @@ -2655,10 +2690,10 @@ static struct mkv_index *seek_with_cues(struct demuxer *demuxer, int seek_id, if (index) { /* We've found an entry. */ uint64_t seek_pos = index->filepos; - if (flags & SEEK_SUBPREROLL) { + if (flags & FLAG_SUBPREROLL) { // Find the cluster with the highest filepos, that has a timestamp // still lower than min_tc. - double secs = demuxer->opts->mkv_subtitle_preroll_secs; + double secs = opts->demux_mkv->subtitle_preroll_secs; uint64_t pre = MPMIN(INT64_MAX, secs * 1e9 / mkv_d->tc_scale); uint64_t min_tc = pre < index->timecode ? index->timecode - pre : 0; uint64_t prev_target = 0; @@ -2717,9 +2752,13 @@ static void demux_mkv_seek(demuxer_t *demuxer, double rel_seek_secs, int flags) a_tnum = track->tnum; } } + + int cueflags = (flags & SEEK_BACKWARD) ? FLAG_BACKWARD : 0; + mkv_d->subtitle_preroll = NUM_SUB_PREROLL_PACKETS; - if (!st_active[STREAM_SUB] || !st_active[STREAM_VIDEO]) - flags &= ~SEEK_SUBPREROLL; + if (((flags & SEEK_HR) || demuxer->opts->demux_mkv->subtitle_preroll) && + st_active[STREAM_SUB] && st_active[STREAM_VIDEO]) + cueflags |= FLAG_SUBPREROLL; // Adjust the target a little bit to catch cases where the target position // specifies a keyframe with high, but not perfect, precision. @@ -2735,9 +2774,9 @@ static void demux_mkv_seek(demuxer_t *demuxer, double rel_seek_secs, int flags) if (create_index_until(demuxer, target_timecode) >= 0) { int seek_id = st_active[STREAM_VIDEO] ? v_tnum : a_tnum; - index = seek_with_cues(demuxer, seek_id, target_timecode, flags); + index = seek_with_cues(demuxer, seek_id, target_timecode, cueflags); if (!index) - index = seek_with_cues(demuxer, -1, target_timecode, flags); + index = seek_with_cues(demuxer, -1, target_timecode, cueflags); } if (!index) diff --git a/demux/demux_playlist.c b/demux/demux_playlist.c index 381b50f269..6f73bea5ba 100644 --- a/demux/demux_playlist.c +++ b/demux/demux_playlist.c @@ -15,7 +15,10 @@ * with mpv. If not, see <http://www.gnu.org/licenses/>. */ +#include <stdlib.h> +#include <string.h> #include <strings.h> +#include <dirent.h> #include "common/common.h" #include "options/options.h" @@ -23,6 +26,7 @@ #include "common/playlist.h" #include "options/path.h" #include "stream/stream.h" +#include "osdep/io.h" #include "demux.h" #define PROBE_SIZE (8 * 1024) @@ -47,6 +51,7 @@ struct pl_parser { bool error; bool probing; bool force; + bool add_base; enum demux_check check_level; struct stream *real_stream; }; @@ -204,6 +209,51 @@ static int parse_txt(struct pl_parser *p) return 0; } +static int cmp_filename(const void *a, const void *b) +{ + return strcmp(*(char **)a, *(char **)b); +} + +static int parse_dir(struct pl_parser *p) +{ + if (p->real_stream->type != STREAMTYPE_DIR) + return -1; + if (p->probing) + return 0; + + char *path = mp_file_get_path(p, bstr0(p->real_stream->url)); + if (strlen(path) >= 8192) + return -1; // things like mount bind loops + + DIR *dp = opendir(path); + if (!dp) { + MP_ERR(p, "Could not read directory.\n"); + return -1; + } + + char **files = NULL; + int num_files = 0; + + struct dirent *ep; + while ((ep = readdir(dp))) { + if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0) + continue; + MP_TARRAY_APPEND(p, files, num_files, talloc_strdup(p, ep->d_name)); + } + + if (files) + qsort(files, num_files, sizeof(files[0]), cmp_filename); + + for (int n = 0; n < num_files; n++) + playlist_add_file(p->pl, mp_path_join(p, bstr0(path), bstr0(files[n]))); + + closedir(dp); + + p->add_base = false; + + return num_files > 0 ? 0 : -1; +} + #define MIME_TYPES(...) \ .mime_types = (const char*const[]){__VA_ARGS__, NULL} @@ -214,6 +264,7 @@ struct pl_format { }; static const struct pl_format formats[] = { + {"directory", parse_dir}, {"m3u", parse_m3u, MIME_TYPES("audio/mpegurl", "audio/x-mpegurl", "application/x-mpegurl")}, {"ini", parse_ref_init}, @@ -248,6 +299,7 @@ static int open_file(struct demuxer *demuxer, enum demux_check check) p->log = demuxer->log; p->pl = talloc_zero(p, struct playlist); p->real_stream = demuxer->stream; + p->add_base = true; bstr probe_buf = stream_peek(demuxer->stream, PROBE_SIZE); p->s = open_memory_stream(probe_buf.start, probe_buf.len); @@ -269,7 +321,7 @@ static int open_file(struct demuxer *demuxer, enum demux_check check) p->s = demuxer->stream; p->utf16 = stream_skip_bom(p->s); bool ok = fmt->parse(p) >= 0 && !p->error; - if (ok) + if (p->add_base) playlist_add_base_path(p->pl, mp_dirname(demuxer->filename)); demuxer->playlist = talloc_steal(demuxer, p->pl); demuxer->filetype = fmt->name; diff --git a/demux/demux_raw.c b/demux/demux_raw.c index f12b774984..65d6b754be 100644 --- a/demux/demux_raw.c +++ b/demux/demux_raw.c @@ -226,7 +226,6 @@ static int demux_rawvideo_open(demuxer_t *demuxer, enum demux_check check) sh_video->fps = opts->fps; sh_video->disp_w = width; sh_video->disp_h = height; - sh_video->bitrate = sh_video->fps * imgsize * 8; struct priv *p = talloc_ptrtype(demuxer, p); demuxer->priv = p; diff --git a/demux/stheader.h b/demux/stheader.h index 3f44a5c57c..444f2f3e34 100644 --- a/demux/stheader.h +++ b/demux/stheader.h @@ -82,7 +82,6 @@ typedef struct sh_video { bool avi_dts; // use DTS timing; first frame and DTS is 0 float fps; // frames per second (set only if constant fps) float aspect; // aspect ratio stored in the file (for prescaling) - int bitrate; // compressed bits/sec int bits_per_coded_sample; unsigned char *extradata; int extradata_len; |