summaryrefslogtreecommitdiffstats
path: root/demux
diff options
context:
space:
mode:
Diffstat (limited to 'demux')
-rw-r--r--demux/demux.c11
-rw-r--r--demux/demux.h1
-rw-r--r--demux/demux_lavf.c9
-rw-r--r--demux/demux_mkv.c87
-rw-r--r--demux/demux_playlist.c54
-rw-r--r--demux/demux_raw.c1
-rw-r--r--demux/stheader.h1
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;