summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/mp_core.h3
-rw-r--r--core/mplayer.c65
-rw-r--r--demux/demux.c28
-rw-r--r--demux/demux_lavf.c13
-rw-r--r--demux/stheader.h4
5 files changed, 63 insertions, 50 deletions
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 2cc4659eef..026af6a989 100644
--- a/core/mplayer.c
+++ b/core/mplayer.c
@@ -467,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) {
@@ -946,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,
@@ -1134,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
@@ -2173,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;
@@ -2353,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++;
@@ -2365,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;
}
@@ -2416,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;
@@ -2467,12 +2479,9 @@ 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;
frame_time = sh_video->next_frame_time;
if (mpctx->restart_playback)
@@ -2497,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;
@@ -2537,15 +2563,16 @@ 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 = demux_read_packet(mpctx->sh_video->gsh);
if (!pkt || pkt->len)
@@ -2570,7 +2597,7 @@ static double update_video(struct MPContext *mpctx, double endpts)
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;
@@ -2580,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
@@ -3458,10 +3487,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);
}
@@ -3473,6 +3504,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))) {
diff --git a/demux/demux.c b/demux/demux.c
index f0652fba4d..1ae4137e62 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -92,7 +92,6 @@ const demuxer_desc_t *const demuxer_list[] = {
struct demux_stream {
int selected; // user wants packets from this stream
int eof; // end of demuxed stream? (true if all buffer empty)
- int fill_count; // number of unsuccessful tries to get a packet
int packs; // number of packets in buffer
int bytes; // total bytes of packets in buffer
struct demux_packet *head;
@@ -441,16 +440,6 @@ overflow:
return true;
}
-static bool need_coverart_hack(struct demuxer *demux)
-{
- for (int n = 0; n < demux->num_streams; n++) {
- struct sh_stream *sh = demux->streams[n];
- if (sh->attached_picture && sh->ds->selected)
- return true;
- }
- return false;
-}
-
// return value:
// 0 = EOF or no stream found or invalid type
// 1 = successfully read a packet
@@ -476,31 +465,14 @@ static void ds_get_packets(struct sh_stream *sh)
* despite the eof flag then it's better to clear it to avoid
* weird behavior. */
ds->eof = 0;
- ds->fill_count = 0;
return;
}
- // avoid buffering too far ahead in e.g. badly interleaved files
- // or when one stream is shorter, without breaking large audio
- // delay with well interleaved files.
- // This needs to be enough for at least 1 second of packets
- // since libavformat mov demuxer does not try to interleave
- // with more than 1s precision.
- if (ds->fill_count > 80)
- break;
if (demux_check_queue_full(demux))
break;
- int apacks = count_packs(demux, STREAM_AUDIO);
- int vpacks = count_packs(demux, STREAM_VIDEO);
-
if (!demux_fill_buffer(demux))
break; // EOF
-
- if (need_coverart_hack(demux)) {
- ds->fill_count += count_packs(demux, STREAM_AUDIO) - apacks;
- ds->fill_count += count_packs(demux, STREAM_VIDEO) - vpacks;
- }
}
mp_msg(MSGT_DEMUXER, MSGL_V, "ds_get_packets: EOF reached (stream: %s)\n",
stream_type_name(sh->type));
diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c
index 385cd23006..3f330332e3 100644
--- a/demux/demux_lavf.c
+++ b/demux/demux_lavf.c
@@ -351,7 +351,8 @@ static void select_tracks(struct demuxer *demuxer, int start)
for (int n = start; n < priv->num_streams; n++) {
struct sh_stream *stream = priv->streams[n];
AVStream *st = priv->avfc->streams[n];
- bool selected = stream && demuxer_stream_is_selected(demuxer, stream);
+ bool selected = stream && demuxer_stream_is_selected(demuxer, stream) &&
+ !stream->attached_picture;
st->discard = selected ? AVDISCARD_DEFAULT : AVDISCARD_ALL;
}
}
@@ -388,8 +389,12 @@ static void handle_stream(demuxer_t *demuxer, int i)
break;
sh_video_t *sh_video = sh->video;
- if (st->disposition & AV_DISPOSITION_ATTACHED_PIC)
- sh_video->gsh->attached_picture = true;
+ if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) {
+ sh->attached_picture = new_demux_packet_from(st->attached_pic.data,
+ st->attached_pic.size);
+ sh->attached_picture->pts = 0;
+ talloc_steal(sh, sh->attached_picture);
+ }
sh_video->format = codec->codec_tag;
sh_video->disp_w = codec->width;
@@ -679,8 +684,6 @@ static int demux_lavf_fill_buffer(demuxer_t *demux)
dp->avpacket = pkt;
int64_t ts = priv->use_dts ? pkt->dts : pkt->pts;
- if (ts == AV_NOPTS_VALUE && (st->disposition & AV_DISPOSITION_ATTACHED_PIC))
- ts = 0;
if (ts != AV_NOPTS_VALUE) {
dp->pts = ts * av_q2d(st->time_base);
priv->last_pts = dp->pts * AV_TIME_BASE;
diff --git a/demux/stheader.h b/demux/stheader.h
index 0d94607fa2..2ca4bd0bae 100644
--- a/demux/stheader.h
+++ b/demux/stheader.h
@@ -61,7 +61,9 @@ struct sh_stream {
char *title;
char *lang; // language code
bool default_track; // container default track flag
- bool attached_picture; // stream is a picture (such as album art)
+
+ // stream is a picture (such as album art)
+ struct demux_packet *attached_picture;
// Human readable description of the running decoder, or NULL
char *decoder_desc;