summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-07-14 17:59:26 +0200
committerwm4 <wm4@nowhere>2013-07-14 17:59:26 +0200
commite18ffd6b998858ca0797cb0ce4aabd4a509655dd (patch)
tree199bddd30923db1175a1331191eb86ba684e9e41 /core
parent3e7d483ac89289f613138002be2043ec5f479bb0 (diff)
parent5ead20bdb3328d199dad693039d18e7a05eb2465 (diff)
downloadmpv-e18ffd6b998858ca0797cb0ce4aabd4a509655dd.tar.bz2
mpv-e18ffd6b998858ca0797cb0ce4aabd4a509655dd.tar.xz
Merge branch 'remove_old_demuxers'
The merged branch doesn't actually just remove old demuxers, but also includes a branch of cleanups and some refactoring. Conflicts: stream/stream.c
Diffstat (limited to 'core')
-rw-r--r--core/asxparser.c4
-rw-r--r--core/command.c10
-rw-r--r--core/encode_lavc.c2
-rw-r--r--core/input/input.c2
-rw-r--r--core/mp_core.h3
-rw-r--r--core/mplayer.c409
-rw-r--r--core/options.c18
-rw-r--r--core/options.h3
-rw-r--r--core/playlist_parser.c5
-rw-r--r--core/timeline/tl_cue.c15
-rw-r--r--core/timeline/tl_edl.c10
-rw-r--r--core/timeline/tl_matroska.c20
12 files changed, 201 insertions, 300 deletions
diff --git a/core/asxparser.c b/core/asxparser.c
index 17ce6b3e8c..ec15313547 100644
--- a/core/asxparser.c
+++ b/core/asxparser.c
@@ -27,7 +27,6 @@
#include "playlist.h"
#include "playlist_parser.h"
#include "stream/stream.h"
-#include "demux/demux.h"
#include "asxparser.h"
#include "core/mp_msg.h"
@@ -451,7 +450,6 @@ asx_parse_ref(ASX_Parser_t* parser, char** attribs) {
static void asx_parse_entryref(ASX_Parser_t* parser,char* buffer,char** _attribs) {
char *href;
stream_t* stream;
- int f=DEMUXER_TYPE_UNKNOWN;
if(parser->deep > 0)
return;
@@ -461,7 +459,7 @@ static void asx_parse_entryref(ASX_Parser_t* parser,char* buffer,char** _attribs
asx_warning_attrib_required(parser,"ENTRYREF" ,"HREF" );
return;
}
- stream=open_stream(href,0,&f);
+ stream=stream_open(href, NULL);
if(!stream) {
mp_msg(MSGT_PLAYTREE,MSGL_WARN,"Can't open playlist %s\n",href);
free(href);
diff --git a/core/command.c b/core/command.c
index 6056596d04..cba9ef5a9a 100644
--- a/core/command.c
+++ b/core/command.c
@@ -566,13 +566,11 @@ static int mp_property_angle(m_option_t *prop, int action, void *arg,
case M_PROPERTY_SET:
angle = demuxer_set_angle(demuxer, *(int *)arg);
if (angle >= 0) {
- struct sh_video *sh_video = demuxer->video->sh;
- if (sh_video)
- resync_video_stream(sh_video);
+ if (mpctx->sh_video)
+ resync_video_stream(mpctx->sh_video);
- struct sh_audio *sh_audio = demuxer->audio->sh;
- if (sh_audio)
- resync_audio_stream(sh_audio);
+ if (mpctx->sh_audio)
+ resync_audio_stream(mpctx->sh_audio);
}
return M_PROPERTY_OK;
case M_PROPERTY_GET_TYPE: {
diff --git a/core/encode_lavc.c b/core/encode_lavc.c
index 9fada7de58..75e57a2443 100644
--- a/core/encode_lavc.c
+++ b/core/encode_lavc.c
@@ -397,7 +397,7 @@ static void encode_2pass_prepare(struct encode_lavc_context *ctx,
buf[sizeof(buf) - 1] = 0;
if (value_has_flag(de ? de->value : "", "pass2")) {
- if (!(*bytebuf = open_stream(buf, NULL, NULL))) {
+ if (!(*bytebuf = stream_open(buf, NULL))) {
mp_msg(MSGT_ENCODE, MSGL_WARN, "%s: could not open '%s', "
"disabling 2-pass encoding at pass 2\n", prefix, buf);
stream->codec->flags &= ~CODEC_FLAG_PASS2;
diff --git a/core/input/input.c b/core/input/input.c
index 47005fdf83..7ae76b9e04 100644
--- a/core/input/input.c
+++ b/core/input/input.c
@@ -1958,7 +1958,7 @@ static int parse_config_file(struct input_ctx *ictx, char *file, bool warn)
"Input config file %s not found.\n", file);
return 0;
}
- stream_t *s = open_stream(file, NULL, NULL);
+ stream_t *s = stream_open(file, NULL);
if (!s) {
mp_msg(MSGT_INPUT, MSGL_ERR, "Can't open input config file %s.\n", file);
return 0;
diff --git a/core/mp_core.h b/core/mp_core.h
index b9c835e497..6bd51cb85c 100644
--- a/core/mp_core.h
+++ b/core/mp_core.h
@@ -172,6 +172,9 @@ typedef struct MPContext {
/* We're starting playback from scratch or after a seek. Show first
* video frame immediately and reinitialize sync. */
bool restart_playback;
+ /* Set if audio should be timed to start with video frame after seeking,
+ * not set when e.g. playing cover art */
+ bool sync_audio_to_video;
/* After playback restart (above) or audio stream change, adjust audio
* stream by cutting samples or adding silence at the beginning to make
* audio playback position match video position. */
diff --git a/core/mplayer.c b/core/mplayer.c
index 1341a51a1a..95a31aa15b 100644
--- a/core/mplayer.c
+++ b/core/mplayer.c
@@ -288,8 +288,6 @@ static void print_stream(struct MPContext *mpctx, struct track *t)
static void print_file_properties(struct MPContext *mpctx, const char *filename)
{
- double start_pts = MP_NOPTS_VALUE;
- double video_start_pts = MP_NOPTS_VALUE;
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_FILENAME=%s\n",
filename);
if (mpctx->sh_video) {
@@ -310,7 +308,6 @@ static void print_file_properties(struct MPContext *mpctx, const char *filename)
"ID_VIDEO_FPS=%5.3f\n", mpctx->sh_video->fps);
mp_msg(MSGT_IDENTIFY, MSGL_INFO,
"ID_VIDEO_ASPECT=%1.4f\n", mpctx->sh_video->aspect);
- video_start_pts = ds_get_next_pts(mpctx->sh_video->ds);
}
if (mpctx->sh_audio) {
/* Assume FOURCC if all bytes >= 0x20 (' ') */
@@ -326,17 +323,7 @@ static void print_file_properties(struct MPContext *mpctx, const char *filename)
"ID_AUDIO_RATE=%d\n", mpctx->sh_audio->samplerate);
mp_msg(MSGT_IDENTIFY, MSGL_INFO,
"ID_AUDIO_NCH=%d\n", mpctx->sh_audio->channels.num);
- start_pts = ds_get_next_pts(mpctx->sh_audio->ds);
}
- if (video_start_pts != MP_NOPTS_VALUE) {
- if (start_pts == MP_NOPTS_VALUE || !mpctx->sh_audio ||
- (mpctx->sh_video && video_start_pts < start_pts))
- start_pts = video_start_pts;
- }
- if (start_pts != MP_NOPTS_VALUE)
- mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_START_TIME=%.2f\n", start_pts);
- else
- mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_START_TIME=unknown\n");
mp_msg(MSGT_IDENTIFY, MSGL_INFO,
"ID_LENGTH=%.2f\n", get_time_length(mpctx));
int chapter_count = get_chapter_count(mpctx);
@@ -373,13 +360,9 @@ static double get_main_demux_pts(struct MPContext *mpctx)
{
double main_new_pos = MP_NOPTS_VALUE;
if (mpctx->demuxer) {
- for (int type = 0; type < STREAM_TYPE_COUNT; type++) {
- struct demux_stream *ds = mpctx->demuxer->ds[type];
- if (ds->sh && main_new_pos == MP_NOPTS_VALUE) {
- demux_fill_buffer(mpctx->demuxer, ds);
- if (ds->first)
- main_new_pos = ds->first->pts;
- }
+ for (int n = 0; n < mpctx->demuxer->num_streams; n++) {
+ if (main_new_pos == MP_NOPTS_VALUE)
+ main_new_pos = demux_get_next_pts(mpctx->demuxer->streams[n]);
}
}
return main_new_pos;
@@ -445,11 +428,11 @@ static void preselect_demux_streams(struct MPContext *mpctx)
static void uninit_subs(struct demuxer *demuxer)
{
- for (int i = 0; i < MAX_S_STREAMS; i++) {
- struct sh_sub *sh = demuxer->s_streams[i];
- if (sh) {
- sub_destroy(sh->dec_sub);
- sh->dec_sub = NULL;
+ for (int i = 0; i < demuxer->num_streams; i++) {
+ struct sh_stream *sh = demuxer->streams[i];
+ if (sh->sub) {
+ sub_destroy(sh->sub->dec_sub);
+ sh->sub->dec_sub = NULL;
}
}
}
@@ -484,6 +467,7 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask)
if (mpctx->sh_video)
uninit_video(mpctx->sh_video);
cleanup_demux_stream(mpctx, STREAM_VIDEO);
+ mpctx->sync_audio_to_video = false;
}
if (mask & INITIALIZED_DEMUXER) {
@@ -930,12 +914,6 @@ static int map_id_from_demuxer(struct demuxer *d, enum stream_type type, int id)
id = id & 0x1F;
return id;
}
-static int map_id_to_demuxer(struct demuxer *d, enum stream_type type, int id)
-{
- if (d->stream->uncached_type == STREAMTYPE_DVD && type == STREAM_SUB)
- id = id | 0x20;
- return id;
-}
static struct track *add_stream_track(struct MPContext *mpctx,
struct sh_stream *stream,
@@ -954,7 +932,9 @@ static struct track *add_stream_track(struct MPContext *mpctx,
track->stream = stream;
track->demuxer_id = stream->demuxer_id;
// Initialize lazily selected track
- if (track == mpctx->current_track[STREAM_SUB])
+ bool selected = track == mpctx->current_track[STREAM_SUB];
+ demuxer_select_track(track->demuxer, stream, selected);
+ if (selected)
reinit_subs(mpctx);
return track;
}
@@ -967,7 +947,7 @@ static struct track *add_stream_track(struct MPContext *mpctx,
.demuxer_id = stream->demuxer_id,
.title = stream->title,
.default_track = stream->default_track,
- .attached_picture = stream->attached_picture,
+ .attached_picture = stream->attached_picture != NULL,
.lang = stream->lang,
.under_timeline = under_timeline,
.demuxer = stream->demuxer,
@@ -990,6 +970,8 @@ static struct track *add_stream_track(struct MPContext *mpctx,
track->lang = talloc_strdup(track, req.name);
}
+ demuxer_select_track(track->demuxer, stream, false);
+
return track;
}
@@ -1021,6 +1003,7 @@ static void add_dvd_tracks(struct MPContext *mpctx)
track->lang = talloc_strdup(track, req.name);
}
}
+ demuxer_enable_autoselect(demuxer);
#endif
}
@@ -1152,7 +1135,7 @@ static void print_status(struct MPContext *mpctx)
saddf(&line, " x%4.2f", opts->playback_speed);
// A-V sync
- if (mpctx->sh_audio && sh_video) {
+ if (mpctx->sh_audio && sh_video && mpctx->sync_audio_to_video) {
if (mpctx->last_av_difference != MP_NOPTS_VALUE)
saddf(&line, " A-V:%7.3f", mpctx->last_av_difference);
else
@@ -1684,41 +1667,25 @@ static double written_audio_pts(struct MPContext *mpctx)
sh_audio_t *sh_audio = mpctx->sh_audio;
if (!sh_audio)
return MP_NOPTS_VALUE;
- demux_stream_t *d_audio = mpctx->sh_audio->ds;
+
+ double bps = sh_audio->channels.num * sh_audio->samplerate *
+ sh_audio->samplesize;
+
// first calculate the end pts of audio that has been output by decoder
double a_pts = sh_audio->pts;
- if (a_pts != MP_NOPTS_VALUE)
- // Good, decoder supports new way of calculating audio pts.
- // sh_audio->pts is the timestamp of the latest input packet with
- // known pts that the decoder has decoded. sh_audio->pts_bytes is
- // the amount of bytes the decoder has written after that timestamp.
- a_pts += sh_audio->pts_bytes / (double) sh_audio->o_bps;
- else {
- // Decoder doesn't support new way of calculating pts (or we're
- // being called before it has decoded anything with known timestamp).
- // Use the old method of audio pts calculation: take the timestamp
- // of last packet with known pts the decoder has read data from,
- // and add amount of bytes read after the beginning of that packet
- // divided by input bps. This will be inaccurate if the input/output
- // ratio is not constant for every audio packet or if it is constant
- // but not accurately known in sh_audio->i_bps.
-
- a_pts = d_audio->pts;
- if (a_pts == MP_NOPTS_VALUE)
- return a_pts;
-
- // ds_tell_pts returns bytes read after last timestamp from
- // demuxing layer, decoder might use sh_audio->a_in_buffer for bytes
- // it has read but not decoded
- if (sh_audio->i_bps)
- a_pts += (ds_tell_pts(d_audio) - sh_audio->a_in_buffer_len) /
- (double)sh_audio->i_bps;
- }
+ if (a_pts == MP_NOPTS_VALUE)
+ return MP_NOPTS_VALUE;
+
+ // sh_audio->pts is the timestamp of the latest input packet with
+ // known pts that the decoder has decoded. sh_audio->pts_bytes is
+ // the amount of bytes the decoder has written after that timestamp.
+ a_pts += sh_audio->pts_bytes / bps;
+
// Now a_pts hopefully holds the pts for end of audio from decoder.
- // Substract data in buffers between decoder and audio out.
+ // Subtract data in buffers between decoder and audio out.
// Decoded but not filtered
- a_pts -= sh_audio->a_buffer_len / (double)sh_audio->o_bps;
+ a_pts -= sh_audio->a_buffer_len / bps;
// Data buffered in audio filters, measured in bytes of "missing" output
double buffered_output = af_calc_delay(sh_audio->afilter);
@@ -1743,21 +1710,21 @@ double playing_audio_pts(struct MPContext *mpctx)
return pts - mpctx->opts.playback_speed *ao_get_delay(mpctx->ao);
}
-// When reading subtitles from a demuxer, and we don't read video or audio
-// from the demuxer, we must explicitly read subtitle packets. (Normally,
-// subs are interleaved with video and audio, so we get them automatically.)
-static bool is_non_interleaved(struct MPContext *mpctx, struct track *track)
+// When reading subtitles from a demuxer, and we read video or audio from the
+// demuxer, we should not explicitly read subtitle packets. (With external
+// subs, we have to.)
+static bool is_interleaved(struct MPContext *mpctx, struct track *track)
{
if (track->is_external || !track->demuxer)
- return true;
+ return false;
struct demuxer *demuxer = track->demuxer;
for (int type = 0; type < STREAM_TYPE_COUNT; type++) {
struct track *other = mpctx->current_track[type];
if (other && other != track && other->demuxer && other->demuxer == demuxer)
- return false;
+ return true;
}
- return true;
+ return false;
}
static void reset_subtitles(struct MPContext *mpctx)
@@ -1785,29 +1752,14 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl)
double curpts_s = refpts_s + opts->sub_delay;
if (!track->preloaded) {
- struct demux_stream *d_sub = sh_sub->ds;
- bool non_interleaved = is_non_interleaved(mpctx, track);
+ bool interleaved = is_interleaved(mpctx, track);
while (1) {
- if (non_interleaved)
- ds_get_next_pts(d_sub);
- if (!d_sub->first)
+ if (interleaved && !demux_has_packet(sh_sub->gsh))
+ break;
+ double subpts_s = demux_get_next_pts(sh_sub->gsh);
+ if (!demux_has_packet(sh_sub->gsh))
break;
- double subpts_s = ds_get_next_pts(d_sub);
- if (subpts_s == MP_NOPTS_VALUE) {
- // Try old method of getting PTS. This is only needed in the
- // DVD playback case with demux_mpg.
- // XXX This is wrong, sh_video->pts can be arbitrarily
- // much behind demuxing position. Unfortunately using
- // d_video->pts which would have been the simplest
- // improvement doesn't work because mpeg specific hacks
- // in video.c set d_video->pts to 0.
- float x = d_sub->pts - refpts_s;
- if (x > -20 && x < 20) // prevent missing subs on pts reset
- subpts_s = d_sub->pts;
- else
- subpts_s = curpts_s;
- }
if (subpts_s > curpts_s) {
mp_dbg(MSGT_CPLAYER, MSGL_DBG2,
"Sub early: c_pts=%5.3f s_pts=%5.3f\n",
@@ -1816,19 +1768,15 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl)
if (!sub_accept_packets_in_advance(dec_sub))
break;
// Try to avoid demuxing whole file at once
- if (non_interleaved && subpts_s > curpts_s + 1)
+ if (subpts_s > curpts_s + 1 && !interleaved)
break;
}
- struct demux_packet pkt;
- struct demux_packet *orig = ds_get_packet_sub(d_sub);
- if (!orig)
- break;
- pkt = *orig;
- pkt.pts = subpts_s;
+ struct demux_packet *pkt = demux_read_packet(sh_sub->gsh);
mp_dbg(MSGT_CPLAYER, MSGL_V, "Sub: c_pts=%5.3f s_pts=%5.3f "
- "duration=%5.3f len=%d\n", curpts_s, pkt.pts, pkt.duration,
- pkt.len);
- sub_decode(dec_sub, &pkt);
+ "duration=%5.3f len=%d\n", curpts_s, pkt->pts, pkt->duration,
+ pkt->len);
+ sub_decode(dec_sub, pkt);
+ talloc_free(pkt);
}
}
@@ -1840,9 +1788,13 @@ static int check_framedrop(struct MPContext *mpctx, double frame_time)
{
struct MPOpts *opts = &mpctx->opts;
// check for frame-drop:
- if (mpctx->sh_audio && !mpctx->ao->untimed && !mpctx->sh_audio->ds->eof) {
+ if (mpctx->sh_audio && !mpctx->ao->untimed &&
+ !demux_stream_eof(mpctx->sh_audio->gsh))
+ {
float delay = opts->playback_speed * ao_get_delay(mpctx->ao);
float d = delay - mpctx->delay;
+ if (frame_time < 0)
+ frame_time = mpctx->sh_video->fps > 0 ? 1.0 / mpctx->sh_video->fps : 0;
// we should avoid dropping too many frames in sequence unless we
// are too late. and we allow 100ms A-V delay here:
if (d < -mpctx->dropped_frames * frame_time - 0.100 && !mpctx->paused
@@ -1933,21 +1885,9 @@ static void reinit_subs(struct MPContext *mpctx)
mpctx->sh_sub->dec_sub = sub_create(opts);
assert(track->demuxer);
- if (!track->stream) {
- // Lazily added DVD track - we must not miss the first subtitle packet,
- // which makes the demuxer create the sh_stream, and contains the first
- // subtitle event.
-
- // demux_mpg - maps IDs directly to the logical stream number
- track->demuxer->sub->id = track->demuxer_id;
-
- // demux_lavf - IDs are essentially random, have to use MPEG IDs
- int id = map_id_to_demuxer(track->demuxer, track->type,
- track->demuxer_id);
- demux_control(track->demuxer, DEMUXER_CTRL_AUTOSELECT_SUBTITLE, &id);
-
+ // Lazily added DVD track - will be created on first sub packet
+ if (!track->stream)
return;
- }
mpctx->initialized_flags |= INITIALIZED_SUB;
@@ -2234,7 +2174,7 @@ static int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
playsize = ao_get_space(ao);
// Coming here with hrseek_active still set means audio-only
- if (!mpctx->sh_video)
+ if (!mpctx->sh_video || !mpctx->sync_audio_to_video)
mpctx->syncing_audio = false;
if (!opts->initial_audio_sync || !modifiable_audio_format) {
mpctx->syncing_audio = false;
@@ -2259,7 +2199,7 @@ static int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
return -1;
} else if (res == ASYNC_PLAY_DONE)
return 0;
- else if (mpctx->sh_audio->ds->eof)
+ else if (demux_stream_eof(mpctx->sh_audio->gsh))
audio_eof = true;
}
@@ -2357,25 +2297,18 @@ int reinit_video_chain(struct MPContext *mpctx)
goto no_video;
}
- if (!video_read_properties(mpctx->sh_video)) {
- mp_tmsg(MSGT_CPLAYER, MSGL_ERR, "Video: Cannot read properties.\n");
- goto err_out;
- } else {
- mp_tmsg(MSGT_CPLAYER, MSGL_V, "[V] filefmt:%d fourcc:0x%X "
- "size:%dx%d fps:%5.3f ftime:=%6.4f\n",
- mpctx->master_demuxer->file_format, mpctx->sh_video->format,
- mpctx->sh_video->disp_w, mpctx->sh_video->disp_h,
- mpctx->sh_video->fps, mpctx->sh_video->frametime);
- if (opts->force_fps) {
- mpctx->sh_video->fps = opts->force_fps;
- mpctx->sh_video->frametime = 1.0f / mpctx->sh_video->fps;
- }
- update_fps(mpctx);
+ mp_tmsg(MSGT_CPLAYER, MSGL_V, "[V] fourcc:0x%X "
+ "size:%dx%d fps:%5.3f\n",
+ mpctx->sh_video->format,
+ mpctx->sh_video->disp_w, mpctx->sh_video->disp_h,
+ mpctx->sh_video->fps);
+ if (opts->force_fps)
+ mpctx->sh_video->fps = opts->force_fps;
+ update_fps(mpctx);
- if (!mpctx->sh_video->fps && !opts->force_fps && !opts->correct_pts) {
- mp_tmsg(MSGT_CPLAYER, MSGL_ERR, "FPS not specified in the "
- "header or invalid, use the -fps option.\n");
- }
+ if (!mpctx->sh_video->fps && !opts->force_fps && !opts->correct_pts) {
+ mp_tmsg(MSGT_CPLAYER, MSGL_ERR, "FPS not specified in the "
+ "header or invalid, use the -fps option.\n");
}
double ar = -1.0;
@@ -2397,7 +2330,7 @@ int reinit_video_chain(struct MPContext *mpctx)
vo_update_window_title(mpctx);
- if (stream_control(mpctx->sh_video->ds->demuxer->stream,
+ if (stream_control(mpctx->sh_video->gsh->demuxer->stream,
STREAM_CTRL_GET_ASPECT_RATIO, &ar) != STREAM_UNSUPPORTED)
mpctx->sh_video->stream_aspect = ar;
@@ -2421,6 +2354,7 @@ int reinit_video_chain(struct MPContext *mpctx)
sh_video->num_buffered_pts = 0;
sh_video->next_frame_time = 0;
mpctx->restart_playback = true;
+ mpctx->sync_audio_to_video = !sh_video->gsh->attached_picture;
mpctx->delay = 0;
mpctx->vo_pts_history_seek_ts++;
@@ -2433,6 +2367,7 @@ err_out:
cleanup_demux_stream(mpctx, STREAM_VIDEO);
no_video:
mpctx->current_track[STREAM_VIDEO] = NULL;
+ mpctx->sync_audio_to_video = false;
mp_tmsg(MSGT_CPLAYER, MSGL_INFO, "Video: no video\n");
return 0;
}
@@ -2484,6 +2419,15 @@ static bool filter_output_queued_frame(struct MPContext *mpctx)
return !!img;
}
+static bool load_next_vo_frame(struct MPContext *mpctx, bool eof)
+{
+ if (vo_get_buffered_frame(mpctx->video_out, eof) >= 0)
+ return true;
+ if (filter_output_queued_frame(mpctx))
+ return true;
+ return false;
+}
+
static void filter_video(struct MPContext *mpctx, struct mp_image *frame)
{
struct sh_video *sh_video = mpctx->sh_video;
@@ -2493,26 +2437,57 @@ static void filter_video(struct MPContext *mpctx, struct mp_image *frame)
filter_output_queued_frame(mpctx);
}
+
+static struct demux_packet *video_read_frame(struct MPContext *mpctx)
+{
+ sh_video_t *sh_video = mpctx->sh_video;
+ demuxer_t *demuxer = sh_video->gsh->demuxer;
+ float pts1 = sh_video->last_pts;
+
+ struct demux_packet *pkt = demux_read_packet(sh_video->gsh);
+ if (!pkt)
+ return NULL; // EOF
+
+ if (pkt->pts != MP_NOPTS_VALUE)
+ sh_video->last_pts = pkt->pts;
+
+ float frame_time = sh_video->fps > 0 ? 1.0f / sh_video->fps : 0;
+
+ // override frame_time for variable/unknown FPS formats:
+ if (!mpctx->opts.force_fps) {
+ double next_pts = demux_get_next_pts(sh_video->gsh);
+ double d = next_pts == MP_NOPTS_VALUE ? sh_video->last_pts - pts1
+ : next_pts - sh_video->last_pts;
+ if (d >= 0) {
+ if (demuxer->type == DEMUXER_TYPE_TV) {
+ if (d > 0)
+ sh_video->fps = 1.0f / d;
+ frame_time = d;
+ } else {
+ if ((int)sh_video->fps <= 1)
+ frame_time = d;
+ }
+ }
+ }
+
+ sh_video->pts = sh_video->last_pts;
+ sh_video->next_frame_time = frame_time;
+ return pkt;
+}
+
static double update_video_nocorrect_pts(struct MPContext *mpctx)
{
struct sh_video *sh_video = mpctx->sh_video;
double frame_time = 0;
- struct vo *video_out = mpctx->video_out;
while (1) {
// In nocorrect-pts mode there is no way to properly time these frames
- if (vo_get_buffered_frame(video_out, 0) >= 0)
- break;
- if (filter_output_queued_frame(mpctx))
+ if (load_next_vo_frame(mpctx, false))
break;
- unsigned char *packet = NULL;
frame_time = sh_video->next_frame_time;
if (mpctx->restart_playback)
frame_time = 0;
- int in_size = 0;
- while (!in_size)
- in_size = video_read_frame(sh_video, &sh_video->next_frame_time,
- &packet, mpctx->opts.force_fps);
- if (in_size < 0)
+ struct demux_packet *pkt = video_read_frame(mpctx);
+ if (!pkt)
return -1;
if (mpctx->sh_audio)
mpctx->delay -= frame_time;
@@ -2520,13 +2495,9 @@ static double update_video_nocorrect_pts(struct MPContext *mpctx)
update_fps(mpctx);
int framedrop_type = check_framedrop(mpctx, frame_time);
- struct demux_packet pkt = {0};
- if (sh_video->ds->current)
- pkt = *sh_video->ds->current;
- pkt.buffer = packet;
- pkt.len = in_size;
- void *decoded_frame = decode_video(sh_video, &pkt, framedrop_type,
+ void *decoded_frame = decode_video(sh_video, pkt, framedrop_type,
sh_video->pts);
+ talloc_free(pkt);
if (decoded_frame) {
filter_video(mpctx, decoded_frame);
}
@@ -2535,6 +2506,23 @@ static double update_video_nocorrect_pts(struct MPContext *mpctx)
return frame_time;
}
+static double update_video_attached_pic(struct MPContext *mpctx)
+{
+ struct sh_video *sh_video = mpctx->sh_video;
+
+ // Try to decode the picture multiple times, until it is displayed.
+ if (mpctx->video_out->hasframe)
+ return -1;
+
+ struct mp_image *decoded_frame =
+ decode_video(sh_video, sh_video->gsh->attached_picture, 0, 0);
+ if (decoded_frame)
+ filter_video(mpctx, decoded_frame);
+ load_next_vo_frame(mpctx, true);
+ mpctx->sh_video->pts = MP_NOPTS_VALUE;
+ return 0;
+}
+
static void determine_frame_pts(struct MPContext *mpctx)
{
struct sh_video *sh_video = mpctx->sh_video;
@@ -2543,7 +2531,7 @@ static void determine_frame_pts(struct MPContext *mpctx)
if (opts->user_pts_assoc_mode)
sh_video->pts_assoc_mode = opts->user_pts_assoc_mode;
else if (sh_video->pts_assoc_mode == 0) {
- if (mpctx->sh_video->ds->demuxer->timestamp_type == TIMESTAMP_TYPE_PTS
+ if (mpctx->sh_video->gsh->demuxer->timestamp_type == TIMESTAMP_TYPE_PTS
&& sh_video->codec_reordered_pts != MP_NOPTS_VALUE)
sh_video->pts_assoc_mode = 1;
else
@@ -2575,22 +2563,24 @@ static double update_video(struct MPContext *mpctx, double endpts)
if (!mpctx->opts.correct_pts)
return update_video_nocorrect_pts(mpctx);
+ if (sh_video->gsh->attached_picture)
+ return update_video_attached_pic(mpctx);
+
double pts;
while (1) {
- if (vo_get_buffered_frame(video_out, false) >= 0)
- break;
- if (filter_output_queued_frame(mpctx))
+ if (load_next_vo_frame(mpctx, false))
break;
pts = MP_NOPTS_VALUE;
- struct demux_packet *pkt;
+ struct demux_packet *pkt = NULL;
while (1) {
- pkt = ds_get_packet2(mpctx->sh_video->ds, false);
+ pkt = demux_read_packet(mpctx->sh_video->gsh);
if (!pkt || pkt->len)
break;
/* Packets with size 0 are assumed to not correspond to frames,
* but to indicate the absence of a frame in formats like AVI
* that must have packets at fixed timecode intervals. */
+ talloc_free(pkt);
}
if (pkt)
pts = pkt->pts;
@@ -2599,14 +2589,15 @@ static double update_video(struct MPContext *mpctx, double endpts)
if (pts >= mpctx->hrseek_pts - .005)
mpctx->hrseek_framedrop = false;
int framedrop_type = mpctx->hrseek_active && mpctx->hrseek_framedrop ?
- 1 : check_framedrop(mpctx, sh_video->frametime);
+ 1 : check_framedrop(mpctx, -1);
struct mp_image *decoded_frame =
decode_video(sh_video, pkt, framedrop_type, pts);
+ talloc_free(pkt);
if (decoded_frame) {
determine_frame_pts(mpctx);
filter_video(mpctx, decoded_frame);
} else if (!pkt) {
- if (vo_get_buffered_frame(video_out, true) < 0)
+ if (!load_next_vo_frame(mpctx, true))
return -1;
}
break;
@@ -2616,6 +2607,8 @@ static double update_video(struct MPContext *mpctx, double endpts)
return 0;
pts = video_out->next_pts;
+ if (sh_video->gsh->attached_picture)
+ pts = mpctx->last_seek_pts;
if (pts == MP_NOPTS_VALUE) {
mp_msg(MSGT_CPLAYER, MSGL_ERR, "Video pts after filters MISSING\n");
// Try to use decoder pts from before filters
@@ -2754,13 +2747,10 @@ static void seek_reset(struct MPContext *mpctx, bool reset_ao, bool reset_ac)
vf_chain_seek_reset(mpctx->sh_video->vfilter);
mpctx->sh_video->num_buffered_pts = 0;
mpctx->sh_video->last_pts = MP_NOPTS_VALUE;
+ mpctx->sh_video->pts = MP_NOPTS_VALUE;
+ mpctx->video_pts = MP_NOPTS_VALUE;
mpctx->delay = 0;
mpctx->time_frame = 0;
- // Not all demuxers set d_video->pts during seek, so this value
- // (which was used by at least vobsub code below) may be completely
- // wrong (probably 0).
- mpctx->sh_video->pts = mpctx->sh_video->ds->pts + mpctx->video_offset;
- mpctx->video_pts = mpctx->sh_video->pts;
}
if (mpctx->sh_audio && reset_ac) {
@@ -3039,17 +3029,7 @@ double get_time_length(struct MPContext *mpctx)
if (len >= 0)
return len;
- struct sh_video *sh_video = mpctx->sh_video;
- struct sh_audio *sh_audio = mpctx->sh_audio;
- if (sh_video && sh_video->i_bps && sh_audio && sh_audio->i_bps)
- return (double) (demuxer->movi_end - demuxer->movi_start) /
- (sh_video->i_bps + sh_audio->i_bps);
- if (sh_video && sh_video->i_bps)
- return (double) (demuxer->movi_end - demuxer->movi_start) /
- sh_video->i_bps;
- if (sh_audio && sh_audio->i_bps)
- return (double) (demuxer->movi_end - demuxer->movi_start) /
- sh_audio->i_bps;
+ // Unknown
return 0;
}
@@ -3497,10 +3477,12 @@ static void run_playloop(struct MPContext *mpctx)
mpctx->time_frame -= get_relative_time(mpctx);
}
if (mpctx->restart_playback) {
- mpctx->syncing_audio = true;
- if (mpctx->sh_audio)
- fill_audio_out_buffers(mpctx, endpts);
- mpctx->restart_playback = false;
+ if (mpctx->sync_audio_to_video) {
+ mpctx->syncing_audio = true;
+ if (mpctx->sh_audio)
+ fill_audio_out_buffers(mpctx, endpts);
+ mpctx->restart_playback = false;
+ }
mpctx->time_frame = 0;
get_relative_time(mpctx);
}
@@ -3512,6 +3494,8 @@ static void run_playloop(struct MPContext *mpctx)
break;
} // video
+ video_left &= mpctx->sync_audio_to_video; // force no-video semantics
+
if (mpctx->sh_audio && (mpctx->restart_playback ? !video_left :
mpctx->ao->untimed && (mpctx->delay <= 0 ||
!video_left))) {
@@ -3888,31 +3872,21 @@ static struct track *open_external_file(struct MPContext *mpctx, char *filename,
struct MPOpts *opts = &mpctx->opts;
if (!filename)
return NULL;
- int format = 0;
char *disp_filename = filename;
if (strncmp(disp_filename, "memory://", 9) == 0)
disp_filename = "memory://"; // avoid noise
- struct stream *stream = open_stream(filename, &mpctx->opts, &format);
+ struct stream *stream = stream_open(filename, &mpctx->opts);
if (!stream)
goto err_out;
stream_enable_cache_percent(&stream, stream_cache,
opts->stream_cache_def_size,
opts->stream_cache_min_percent,
opts->stream_cache_seek_min_percent);
- // deal with broken demuxers: preselect streams
- int vs = -2, as = -2, ss = -2;
- switch (filter) {
- case STREAM_VIDEO: vs = -1; break;
- case STREAM_AUDIO: as = -1; break;
- case STREAM_SUB: ss = -1; break;
- }
- vs = -1; // avi can't go without video
struct demuxer_params params = {
.ass_library = mpctx->ass_library, // demux_libass requires it
};
struct demuxer *demuxer =
- demux_open_withparams(&mpctx->opts, stream, format, demuxer_name,
- as, vs, ss, filename, &params);
+ demux_open(stream, demuxer_name, &params, &mpctx->opts);
if (!demuxer) {
free_stream(stream);
goto err_out;
@@ -3930,6 +3904,7 @@ static struct track *open_external_file(struct MPContext *mpctx, char *filename,
}
if (!first) {
free_demuxer(demuxer);
+ free_stream(stream);
mp_msg(MSGT_CPLAYER, MSGL_WARN, "No streams added from file %s.\n",
disp_filename);
goto err_out;
@@ -4171,36 +4146,13 @@ static void play_current_file(struct MPContext *mpctx)
}
stream_filename = mpctx->resolve_result->url;