2014-07-14 23:49:02 +00:00
|
|
|
/*
|
|
|
|
* This file is part of mpv.
|
|
|
|
*
|
Relicense some non-MPlayer source files to LGPL 2.1 or later
This covers source files which were added in mplayer2 and mpv times
only, and where all code is covered by LGPL relicensing agreements.
There are probably more files to which this applies, but I'm being
conservative here.
A file named ao_sdl.c exists in MPlayer too, but the mpv one is a
complete rewrite, and was added some time after the original ao_sdl.c
was removed. The same applies to vo_sdl.c, for which the SDL2 API is
radically different in addition (MPlayer supports SDL 1.2 only).
common.c contains only code written by me. But common.h is a strange
case: although it originally was named mp_common.h and exists in MPlayer
too, by now it contains only definitions written by uau and me. The
exceptions are the CONTROL_ defines - thus not changing the license of
common.h yet.
codec_tags.c contained once large tables generated from MPlayer's
codecs.conf, but all of these tables were removed.
From demux_playlist.c I'm removing a code fragment from someone who was
not asked; this probably could be done later (see commit 15dccc37).
misc.c is a bit complicated to reason about (it was split off mplayer.c
and thus contains random functions out of this file), but actually all
functions have been added post-MPlayer. Except get_relative_time(),
which was written by uau, but looks similar to 3 different versions of
something similar in each of the Unix/win32/OSX timer source files. I'm
not sure what that means in regards to copyright, so I've just moved it
into another still-GPL source file for now.
screenshot.c once had some minor parts of MPlayer's vf_screenshot.c, but
they're all gone.
2016-01-19 17:36:06 +00:00
|
|
|
* mpv is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
2014-07-14 23:49:02 +00:00
|
|
|
*
|
|
|
|
* mpv is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
Relicense some non-MPlayer source files to LGPL 2.1 or later
This covers source files which were added in mplayer2 and mpv times
only, and where all code is covered by LGPL relicensing agreements.
There are probably more files to which this applies, but I'm being
conservative here.
A file named ao_sdl.c exists in MPlayer too, but the mpv one is a
complete rewrite, and was added some time after the original ao_sdl.c
was removed. The same applies to vo_sdl.c, for which the SDL2 API is
radically different in addition (MPlayer supports SDL 1.2 only).
common.c contains only code written by me. But common.h is a strange
case: although it originally was named mp_common.h and exists in MPlayer
too, by now it contains only definitions written by uau and me. The
exceptions are the CONTROL_ defines - thus not changing the license of
common.h yet.
codec_tags.c contained once large tables generated from MPlayer's
codecs.conf, but all of these tables were removed.
From demux_playlist.c I'm removing a code fragment from someone who was
not asked; this probably could be done later (see commit 15dccc37).
misc.c is a bit complicated to reason about (it was split off mplayer.c
and thus contains random functions out of this file), but actually all
functions have been added post-MPlayer. Except get_relative_time(),
which was written by uau, but looks similar to 3 different versions of
something similar in each of the Unix/win32/OSX timer source files. I'm
not sure what that means in regards to copyright, so I've just moved it
into another still-GPL source file for now.
screenshot.c once had some minor parts of MPlayer's vf_screenshot.c, but
they're all gone.
2016-01-19 17:36:06 +00:00
|
|
|
* GNU Lesser General Public License for more details.
|
2014-07-14 23:49:02 +00:00
|
|
|
*
|
Relicense some non-MPlayer source files to LGPL 2.1 or later
This covers source files which were added in mplayer2 and mpv times
only, and where all code is covered by LGPL relicensing agreements.
There are probably more files to which this applies, but I'm being
conservative here.
A file named ao_sdl.c exists in MPlayer too, but the mpv one is a
complete rewrite, and was added some time after the original ao_sdl.c
was removed. The same applies to vo_sdl.c, for which the SDL2 API is
radically different in addition (MPlayer supports SDL 1.2 only).
common.c contains only code written by me. But common.h is a strange
case: although it originally was named mp_common.h and exists in MPlayer
too, by now it contains only definitions written by uau and me. The
exceptions are the CONTROL_ defines - thus not changing the license of
common.h yet.
codec_tags.c contained once large tables generated from MPlayer's
codecs.conf, but all of these tables were removed.
From demux_playlist.c I'm removing a code fragment from someone who was
not asked; this probably could be done later (see commit 15dccc37).
misc.c is a bit complicated to reason about (it was split off mplayer.c
and thus contains random functions out of this file), but actually all
functions have been added post-MPlayer. Except get_relative_time(),
which was written by uau, but looks similar to 3 different versions of
something similar in each of the Unix/win32/OSX timer source files. I'm
not sure what that means in regards to copyright, so I've just moved it
into another still-GPL source file for now.
screenshot.c once had some minor parts of MPlayer's vf_screenshot.c, but
they're all gone.
2016-01-19 17:36:06 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
2014-07-14 23:49:02 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string.h>
|
2014-07-17 23:08:43 +00:00
|
|
|
#include <math.h>
|
2014-07-14 23:49:02 +00:00
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include "common/common.h"
|
|
|
|
#include "common/msg.h"
|
|
|
|
|
|
|
|
#include "stream/stream.h"
|
2015-12-20 08:36:56 +00:00
|
|
|
#include "video/mp_image.h"
|
2014-07-14 23:49:02 +00:00
|
|
|
#include "demux.h"
|
|
|
|
#include "stheader.h"
|
|
|
|
|
|
|
|
#include "video/csputils.h"
|
|
|
|
|
|
|
|
struct priv {
|
|
|
|
struct demuxer *slave;
|
|
|
|
// streams[slave_stream_index] == our_stream
|
|
|
|
struct sh_stream **streams;
|
|
|
|
int num_streams;
|
|
|
|
// This contains each DVD sub stream, or NULL. Needed because DVD packets
|
|
|
|
// can come arbitrarily late in the MPEG stream, so the slave demuxer
|
|
|
|
// might add the streams only later.
|
|
|
|
struct sh_stream *dvd_subs[32];
|
|
|
|
// Used to rewrite the raw MPEG timestamps to playback time.
|
2014-07-17 23:08:43 +00:00
|
|
|
double base_time; // playback display start time of current segment
|
|
|
|
double base_dts; // packet DTS that maps to base_time
|
|
|
|
double last_dts; // DTS of previously demuxed packet
|
2014-07-14 23:49:02 +00:00
|
|
|
bool seek_reinit; // needs reinit after seek
|
|
|
|
};
|
|
|
|
|
2014-07-17 23:08:43 +00:00
|
|
|
// If the timestamp difference between subsequent packets is this big, assume
|
|
|
|
// a reset. It should be big enough to account for 1. low video framerates and
|
|
|
|
// large audio frames, and 2. bad interleaving.
|
|
|
|
#define DTS_RESET_THRESHOLD 5.0
|
|
|
|
|
2014-07-14 23:49:02 +00:00
|
|
|
static void reselect_streams(demuxer_t *demuxer)
|
|
|
|
{
|
|
|
|
struct priv *p = demuxer->priv;
|
demux: remove weird tripple-buffering for the sh_stream list
The demuxer infrastructure was originally single-threaded. To make it
suitable for multithreading (specifically, demuxing and decoding on
separate threads), some sort of tripple-buffering was introduced. There
are separate "struct demuxer" allocations. The demuxer thread sets the
state on d_thread. If anything changes, the state is copied to d_buffer
(the copy is protected by a lock), and the decoder thread is notified.
Then the decoder thread copies the state from d_buffer to d_user (again
while holding a lock). This avoids the need for locking in the
demuxer/decoder code itself (only demux.c needs an internal, "invisible"
lock.)
Remove the streams/num_streams fields from this tripple-buffering
schema. Move them to the internal struct, and protect them with the
internal lock. Use accessors for read access outside of demux.c.
Other than replacing all field accesses with accessors, this separates
allocating and adding sh_streams. This is needed to avoid race
conditions. Before this change, this was awkwardly handled by first
initializing the sh_stream, and then sending a stream change event. Now
the stream is allocated, then initialized, and then declared as
immutable and added (at which point it becomes visible to the decoder
thread immediately).
This change is useful for PR #2626. And eventually, we should probably
get entirely of the tripple buffering, and this makes a nice first step.
2015-12-23 20:44:53 +00:00
|
|
|
int num_slave = demux_get_num_stream(p->slave);
|
|
|
|
for (int n = 0; n < MPMIN(num_slave, p->num_streams); n++) {
|
2014-07-14 23:49:02 +00:00
|
|
|
if (p->streams[n]) {
|
demux: remove weird tripple-buffering for the sh_stream list
The demuxer infrastructure was originally single-threaded. To make it
suitable for multithreading (specifically, demuxing and decoding on
separate threads), some sort of tripple-buffering was introduced. There
are separate "struct demuxer" allocations. The demuxer thread sets the
state on d_thread. If anything changes, the state is copied to d_buffer
(the copy is protected by a lock), and the decoder thread is notified.
Then the decoder thread copies the state from d_buffer to d_user (again
while holding a lock). This avoids the need for locking in the
demuxer/decoder code itself (only demux.c needs an internal, "invisible"
lock.)
Remove the streams/num_streams fields from this tripple-buffering
schema. Move them to the internal struct, and protect them with the
internal lock. Use accessors for read access outside of demux.c.
Other than replacing all field accesses with accessors, this separates
allocating and adding sh_streams. This is needed to avoid race
conditions. Before this change, this was awkwardly handled by first
initializing the sh_stream, and then sending a stream change event. Now
the stream is allocated, then initialized, and then declared as
immutable and added (at which point it becomes visible to the decoder
thread immediately).
This change is useful for PR #2626. And eventually, we should probably
get entirely of the tripple buffering, and this makes a nice first step.
2015-12-23 20:44:53 +00:00
|
|
|
demuxer_select_track(p->slave, demux_get_stream(p->slave, n),
|
player: improve instant track switching
When switching tracks, we normally have the problem that data gets lost
due to readahead buffering. (Which in turn is because we're stubborn and
instruct the demuxers to discard data on unselected streams.) The
demuxer layer has a hack that re-reads discarded buffered data if a
stream is enabled mid-stream, so track switching will seem instant.
A somewhat similar problem is when all tracks of an external files were
disabled - when enabling the first track, we have to seek to the target
position.
Handle these with the same mechanism. Pass the "current time" to the
demuxer's stream switch function, and let the demuxer figure out what to
do. The demuxer will issue a refresh seek (if possible) to update the
new stream, or will issue a "normal" seek if there was no active stream
yet.
One case that changes is when a video/audio stream is enabled on an
external file with only a subtitle stream active, and the demuxer does
not support rrefresh seeks. This is a fuzzy case, because subtitles are
sparse, and the demuxer might have skipped large amounts of data. We
used to seek (and send the subtitle decoder some subtitle packets
twice). This case is sort of obscure and insane, and the fix would be
questionable, so we simply don't care.
Should mostly fix #3392.
2016-08-06 13:47:04 +00:00
|
|
|
MP_NOPTS_VALUE, demux_stream_is_selected(p->streams[n]));
|
2014-07-14 23:49:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void get_disc_lang(struct stream *stream, struct sh_stream *sh)
|
|
|
|
{
|
|
|
|
struct stream_lang_req req = {.type = sh->type, .id = sh->demuxer_id};
|
|
|
|
if (stream->uncached_type == STREAMTYPE_DVD && sh->type == STREAM_SUB)
|
|
|
|
req.id = req.id & 0x1F; // mpeg ID to index
|
|
|
|
stream_control(stream, STREAM_CTRL_GET_LANG, &req);
|
|
|
|
if (req.name[0])
|
|
|
|
sh->lang = talloc_strdup(sh, req.name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void add_dvd_streams(demuxer_t *demuxer)
|
|
|
|
{
|
|
|
|
struct priv *p = demuxer->priv;
|
|
|
|
struct stream *stream = demuxer->stream;
|
|
|
|
if (stream->uncached_type != STREAMTYPE_DVD)
|
|
|
|
return;
|
|
|
|
struct stream_dvd_info_req info;
|
|
|
|
if (stream_control(stream, STREAM_CTRL_GET_DVD_INFO, &info) > 0) {
|
|
|
|
for (int n = 0; n < MPMIN(32, info.num_subs); n++) {
|
demux: remove weird tripple-buffering for the sh_stream list
The demuxer infrastructure was originally single-threaded. To make it
suitable for multithreading (specifically, demuxing and decoding on
separate threads), some sort of tripple-buffering was introduced. There
are separate "struct demuxer" allocations. The demuxer thread sets the
state on d_thread. If anything changes, the state is copied to d_buffer
(the copy is protected by a lock), and the decoder thread is notified.
Then the decoder thread copies the state from d_buffer to d_user (again
while holding a lock). This avoids the need for locking in the
demuxer/decoder code itself (only demux.c needs an internal, "invisible"
lock.)
Remove the streams/num_streams fields from this tripple-buffering
schema. Move them to the internal struct, and protect them with the
internal lock. Use accessors for read access outside of demux.c.
Other than replacing all field accesses with accessors, this separates
allocating and adding sh_streams. This is needed to avoid race
conditions. Before this change, this was awkwardly handled by first
initializing the sh_stream, and then sending a stream change event. Now
the stream is allocated, then initialized, and then declared as
immutable and added (at which point it becomes visible to the decoder
thread immediately).
This change is useful for PR #2626. And eventually, we should probably
get entirely of the tripple buffering, and this makes a nice first step.
2015-12-23 20:44:53 +00:00
|
|
|
struct sh_stream *sh = demux_alloc_sh_stream(STREAM_SUB);
|
2014-07-14 23:49:02 +00:00
|
|
|
sh->demuxer_id = n + 0x20;
|
2016-01-12 22:48:19 +00:00
|
|
|
sh->codec->codec = "dvd_subtitle";
|
2014-07-14 23:49:02 +00:00
|
|
|
get_disc_lang(stream, sh);
|
|
|
|
// p->streams _must_ match with p->slave->streams, so we can't add
|
|
|
|
// it yet - it has to be done when the real stream appears, which
|
|
|
|
// could be right on start, or any time later.
|
|
|
|
p->dvd_subs[n] = sh;
|
|
|
|
|
|
|
|
// emulate the extradata
|
|
|
|
struct mp_csp_params csp = MP_CSP_PARAMS_DEFAULTS;
|
2015-01-06 15:49:53 +00:00
|
|
|
struct mp_cmat cmatrix;
|
2015-12-08 23:22:12 +00:00
|
|
|
mp_get_csp_matrix(&csp, &cmatrix);
|
2014-07-14 23:49:02 +00:00
|
|
|
|
|
|
|
char *s = talloc_strdup(sh, "");
|
|
|
|
s = talloc_asprintf_append(s, "palette: ");
|
|
|
|
for (int i = 0; i < 16; i++) {
|
|
|
|
int color = info.palette[i];
|
2015-12-08 23:08:00 +00:00
|
|
|
int y[3] = {(color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff};
|
|
|
|
int c[3];
|
|
|
|
mp_map_fixp_color(&cmatrix, 8, y, 8, c);
|
2014-07-14 23:49:02 +00:00
|
|
|
color = (c[2] << 16) | (c[1] << 8) | c[0];
|
|
|
|
|
|
|
|
if (i != 0)
|
|
|
|
s = talloc_asprintf_append(s, ", ");
|
|
|
|
s = talloc_asprintf_append(s, "%06x", color);
|
|
|
|
}
|
|
|
|
s = talloc_asprintf_append(s, "\n");
|
|
|
|
|
2016-01-12 22:48:19 +00:00
|
|
|
sh->codec->extradata = s;
|
|
|
|
sh->codec->extradata_size = strlen(s);
|
demux: remove weird tripple-buffering for the sh_stream list
The demuxer infrastructure was originally single-threaded. To make it
suitable for multithreading (specifically, demuxing and decoding on
separate threads), some sort of tripple-buffering was introduced. There
are separate "struct demuxer" allocations. The demuxer thread sets the
state on d_thread. If anything changes, the state is copied to d_buffer
(the copy is protected by a lock), and the decoder thread is notified.
Then the decoder thread copies the state from d_buffer to d_user (again
while holding a lock). This avoids the need for locking in the
demuxer/decoder code itself (only demux.c needs an internal, "invisible"
lock.)
Remove the streams/num_streams fields from this tripple-buffering
schema. Move them to the internal struct, and protect them with the
internal lock. Use accessors for read access outside of demux.c.
Other than replacing all field accesses with accessors, this separates
allocating and adding sh_streams. This is needed to avoid race
conditions. Before this change, this was awkwardly handled by first
initializing the sh_stream, and then sending a stream change event. Now
the stream is allocated, then initialized, and then declared as
immutable and added (at which point it becomes visible to the decoder
thread immediately).
This change is useful for PR #2626. And eventually, we should probably
get entirely of the tripple buffering, and this makes a nice first step.
2015-12-23 20:44:53 +00:00
|
|
|
|
|
|
|
demux_add_sh_stream(demuxer, sh);
|
2014-07-14 23:49:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void add_streams(demuxer_t *demuxer)
|
|
|
|
{
|
|
|
|
struct priv *p = demuxer->priv;
|
|
|
|
|
demux: remove weird tripple-buffering for the sh_stream list
The demuxer infrastructure was originally single-threaded. To make it
suitable for multithreading (specifically, demuxing and decoding on
separate threads), some sort of tripple-buffering was introduced. There
are separate "struct demuxer" allocations. The demuxer thread sets the
state on d_thread. If anything changes, the state is copied to d_buffer
(the copy is protected by a lock), and the decoder thread is notified.
Then the decoder thread copies the state from d_buffer to d_user (again
while holding a lock). This avoids the need for locking in the
demuxer/decoder code itself (only demux.c needs an internal, "invisible"
lock.)
Remove the streams/num_streams fields from this tripple-buffering
schema. Move them to the internal struct, and protect them with the
internal lock. Use accessors for read access outside of demux.c.
Other than replacing all field accesses with accessors, this separates
allocating and adding sh_streams. This is needed to avoid race
conditions. Before this change, this was awkwardly handled by first
initializing the sh_stream, and then sending a stream change event. Now
the stream is allocated, then initialized, and then declared as
immutable and added (at which point it becomes visible to the decoder
thread immediately).
This change is useful for PR #2626. And eventually, we should probably
get entirely of the tripple buffering, and this makes a nice first step.
2015-12-23 20:44:53 +00:00
|
|
|
for (int n = p->num_streams; n < demux_get_num_stream(p->slave); n++) {
|
|
|
|
struct sh_stream *src = demux_get_stream(p->slave, n);
|
2016-01-12 22:48:19 +00:00
|
|
|
if (src->type == STREAM_SUB) {
|
2014-07-14 23:49:02 +00:00
|
|
|
struct sh_stream *sub = NULL;
|
|
|
|
if (src->demuxer_id >= 0x20 && src->demuxer_id <= 0x3F)
|
|
|
|
sub = p->dvd_subs[src->demuxer_id - 0x20];
|
|
|
|
if (sub) {
|
|
|
|
assert(p->num_streams == n); // directly mapped
|
|
|
|
MP_TARRAY_APPEND(p, p->streams, p->num_streams, sub);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
demux: remove weird tripple-buffering for the sh_stream list
The demuxer infrastructure was originally single-threaded. To make it
suitable for multithreading (specifically, demuxing and decoding on
separate threads), some sort of tripple-buffering was introduced. There
are separate "struct demuxer" allocations. The demuxer thread sets the
state on d_thread. If anything changes, the state is copied to d_buffer
(the copy is protected by a lock), and the decoder thread is notified.
Then the decoder thread copies the state from d_buffer to d_user (again
while holding a lock). This avoids the need for locking in the
demuxer/decoder code itself (only demux.c needs an internal, "invisible"
lock.)
Remove the streams/num_streams fields from this tripple-buffering
schema. Move them to the internal struct, and protect them with the
internal lock. Use accessors for read access outside of demux.c.
Other than replacing all field accesses with accessors, this separates
allocating and adding sh_streams. This is needed to avoid race
conditions. Before this change, this was awkwardly handled by first
initializing the sh_stream, and then sending a stream change event. Now
the stream is allocated, then initialized, and then declared as
immutable and added (at which point it becomes visible to the decoder
thread immediately).
This change is useful for PR #2626. And eventually, we should probably
get entirely of the tripple buffering, and this makes a nice first step.
2015-12-23 20:44:53 +00:00
|
|
|
struct sh_stream *sh = demux_alloc_sh_stream(src->type);
|
2014-07-14 23:49:02 +00:00
|
|
|
assert(p->num_streams == n); // directly mapped
|
|
|
|
MP_TARRAY_APPEND(p, p->streams, p->num_streams, sh);
|
|
|
|
// Copy all stream fields that might be relevant
|
2016-01-12 22:48:19 +00:00
|
|
|
*sh->codec = *src->codec;
|
2014-09-30 21:38:01 +00:00
|
|
|
sh->demuxer_id = src->demuxer_id;
|
2016-01-12 22:48:19 +00:00
|
|
|
if (src->type == STREAM_VIDEO) {
|
2014-07-14 23:49:02 +00:00
|
|
|
double ar;
|
|
|
|
if (stream_control(demuxer->stream, STREAM_CTRL_GET_ASPECT_RATIO, &ar)
|
|
|
|
== STREAM_OK)
|
2015-12-19 19:04:31 +00:00
|
|
|
{
|
2016-01-12 22:48:19 +00:00
|
|
|
struct mp_image_params f = {.w = src->codec->disp_w,
|
|
|
|
.h = src->codec->disp_h};
|
2015-12-20 19:50:54 +00:00
|
|
|
mp_image_params_set_dsize(&f, 1728 * ar, 1728);
|
2016-01-12 22:48:19 +00:00
|
|
|
sh->codec->par_w = f.p_w;
|
|
|
|
sh->codec->par_h = f.p_h;
|
2015-12-19 19:04:31 +00:00
|
|
|
}
|
2014-07-14 23:49:02 +00:00
|
|
|
}
|
2014-09-29 16:01:46 +00:00
|
|
|
get_disc_lang(demuxer->stream, sh);
|
demux: remove weird tripple-buffering for the sh_stream list
The demuxer infrastructure was originally single-threaded. To make it
suitable for multithreading (specifically, demuxing and decoding on
separate threads), some sort of tripple-buffering was introduced. There
are separate "struct demuxer" allocations. The demuxer thread sets the
state on d_thread. If anything changes, the state is copied to d_buffer
(the copy is protected by a lock), and the decoder thread is notified.
Then the decoder thread copies the state from d_buffer to d_user (again
while holding a lock). This avoids the need for locking in the
demuxer/decoder code itself (only demux.c needs an internal, "invisible"
lock.)
Remove the streams/num_streams fields from this tripple-buffering
schema. Move them to the internal struct, and protect them with the
internal lock. Use accessors for read access outside of demux.c.
Other than replacing all field accesses with accessors, this separates
allocating and adding sh_streams. This is needed to avoid race
conditions. Before this change, this was awkwardly handled by first
initializing the sh_stream, and then sending a stream change event. Now
the stream is allocated, then initialized, and then declared as
immutable and added (at which point it becomes visible to the decoder
thread immediately).
This change is useful for PR #2626. And eventually, we should probably
get entirely of the tripple buffering, and this makes a nice first step.
2015-12-23 20:44:53 +00:00
|
|
|
demux_add_sh_stream(demuxer, sh);
|
2014-07-14 23:49:02 +00:00
|
|
|
}
|
|
|
|
reselect_streams(demuxer);
|
|
|
|
}
|
|
|
|
|
2016-02-28 18:14:23 +00:00
|
|
|
static void d_seek(demuxer_t *demuxer, double seek_pts, int flags)
|
2014-07-14 23:49:02 +00:00
|
|
|
{
|
|
|
|
struct priv *p = demuxer->priv;
|
|
|
|
|
|
|
|
if (demuxer->stream->uncached_type == STREAMTYPE_CDDA) {
|
2016-02-28 18:14:23 +00:00
|
|
|
demux_seek(p->slave, seek_pts, flags);
|
2014-07-14 23:49:02 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & SEEK_FACTOR) {
|
|
|
|
double tmp = 0;
|
|
|
|
stream_control(demuxer->stream, STREAM_CTRL_GET_TIME_LENGTH, &tmp);
|
2016-02-28 18:14:23 +00:00
|
|
|
seek_pts *= tmp;
|
2014-07-14 23:49:02 +00:00
|
|
|
}
|
|
|
|
|
2016-02-28 18:14:23 +00:00
|
|
|
MP_VERBOSE(demuxer, "seek to: %f\n", seek_pts);
|
2014-07-14 23:49:02 +00:00
|
|
|
|
2016-02-28 18:14:23 +00:00
|
|
|
double seek_arg[] = {seek_pts, flags};
|
2015-01-19 19:45:31 +00:00
|
|
|
stream_control(demuxer->stream, STREAM_CTRL_SEEK_TO_TIME, seek_arg);
|
2014-07-14 23:49:02 +00:00
|
|
|
demux_control(p->slave, DEMUXER_CTRL_RESYNC, NULL);
|
|
|
|
|
|
|
|
p->seek_reinit = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void reset_pts(demuxer_t *demuxer)
|
|
|
|
{
|
|
|
|
struct priv *p = demuxer->priv;
|
|
|
|
|
|
|
|
double base;
|
|
|
|
if (stream_control(demuxer->stream, STREAM_CTRL_GET_CURRENT_TIME, &base) < 1)
|
|
|
|
base = 0;
|
|
|
|
|
|
|
|
MP_VERBOSE(demuxer, "reset to time: %f\n", base);
|
|
|
|
|
2014-07-17 23:08:43 +00:00
|
|
|
p->base_dts = p->last_dts = MP_NOPTS_VALUE;
|
|
|
|
p->base_time = base;
|
2014-07-14 23:49:02 +00:00
|
|
|
p->seek_reinit = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int d_fill_buffer(demuxer_t *demuxer)
|
|
|
|
{
|
|
|
|
struct priv *p = demuxer->priv;
|
|
|
|
|
|
|
|
struct demux_packet *pkt = demux_read_any_packet(p->slave);
|
|
|
|
if (!pkt)
|
|
|
|
return 0;
|
|
|
|
|
2014-07-16 20:40:21 +00:00
|
|
|
demux_update(p->slave);
|
|
|
|
|
2014-07-14 23:49:02 +00:00
|
|
|
if (p->seek_reinit)
|
|
|
|
reset_pts(demuxer);
|
|
|
|
|
|
|
|
add_streams(demuxer);
|
|
|
|
if (pkt->stream >= p->num_streams) { // out of memory?
|
|
|
|
talloc_free(pkt);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct sh_stream *sh = p->streams[pkt->stream];
|
|
|
|
if (!demux_stream_is_selected(sh)) {
|
|
|
|
talloc_free(pkt);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-02-03 18:32:30 +00:00
|
|
|
if (demuxer->stream->uncached_type == STREAMTYPE_CDDA) {
|
|
|
|
demux_add_packet(sh, pkt);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-07-14 23:49:02 +00:00
|
|
|
MP_TRACE(demuxer, "ipts: %d %f %f\n", sh->type, pkt->pts, pkt->dts);
|
|
|
|
|
|
|
|
if (sh->type == STREAM_SUB) {
|
2014-07-17 23:08:43 +00:00
|
|
|
if (p->base_dts == MP_NOPTS_VALUE)
|
|
|
|
MP_WARN(demuxer, "subtitle packet along PTS reset\n");
|
2014-07-14 23:49:02 +00:00
|
|
|
} else if (pkt->dts != MP_NOPTS_VALUE) {
|
2014-07-17 23:08:43 +00:00
|
|
|
// Use the very first DTS to rebase the start time of the MPEG stream
|
|
|
|
// to the playback time.
|
|
|
|
if (p->base_dts == MP_NOPTS_VALUE)
|
|
|
|
p->base_dts = pkt->dts;
|
|
|
|
|
|
|
|
if (p->last_dts == MP_NOPTS_VALUE)
|
|
|
|
p->last_dts = pkt->dts;
|
|
|
|
|
|
|
|
if (fabs(p->last_dts - pkt->dts) >= DTS_RESET_THRESHOLD) {
|
|
|
|
MP_WARN(demuxer, "PTS discontinuity: %f->%f\n", p->last_dts, pkt->dts);
|
|
|
|
p->base_time += p->last_dts - p->base_dts;
|
|
|
|
p->base_dts = pkt->dts - pkt->duration;
|
2014-07-14 23:49:02 +00:00
|
|
|
}
|
2014-07-17 23:08:43 +00:00
|
|
|
p->last_dts = pkt->dts;
|
2014-07-14 23:49:02 +00:00
|
|
|
}
|
2014-07-17 23:08:43 +00:00
|
|
|
|
|
|
|
if (p->base_dts != MP_NOPTS_VALUE) {
|
|
|
|
double delta = -p->base_dts + p->base_time;
|
2014-07-14 23:49:02 +00:00
|
|
|
if (pkt->pts != MP_NOPTS_VALUE)
|
|
|
|
pkt->pts += delta;
|
|
|
|
if (pkt->dts != MP_NOPTS_VALUE)
|
|
|
|
pkt->dts += delta;
|
|
|
|
}
|
|
|
|
|
|
|
|
MP_TRACE(demuxer, "opts: %d %f %f\n", sh->type, pkt->pts, pkt->dts);
|
|
|
|
|
|
|
|
demux_add_packet(sh, pkt);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void add_stream_chapters(struct demuxer *demuxer)
|
|
|
|
{
|
|
|
|
int num = 0;
|
|
|
|
if (stream_control(demuxer->stream, STREAM_CTRL_GET_NUM_CHAPTERS, &num) < 1)
|
|
|
|
return;
|
|
|
|
for (int n = 0; n < num; n++) {
|
|
|
|
double p = n;
|
|
|
|
if (stream_control(demuxer->stream, STREAM_CTRL_GET_CHAPTER_TIME, &p) < 1)
|
|
|
|
continue;
|
2015-06-24 12:18:51 +00:00
|
|
|
demuxer_add_chapter(demuxer, "", p, 0);
|
2014-07-14 23:49:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2015-02-20 20:21:14 +00:00
|
|
|
struct demuxer_params params = {.force_format = "+lavf"};
|
|
|
|
|
2014-07-14 23:49:02 +00:00
|
|
|
if (demuxer->stream->uncached_type == STREAMTYPE_CDDA)
|
2015-02-20 20:21:14 +00:00
|
|
|
params.force_format = "+rawaudio";
|
2014-07-14 23:49:02 +00:00
|
|
|
|
2014-07-16 20:40:21 +00:00
|
|
|
char *t = NULL;
|
|
|
|
stream_control(demuxer->stream, STREAM_CTRL_GET_DISC_NAME, &t);
|
|
|
|
if (t) {
|
2015-06-24 12:18:51 +00:00
|
|
|
mp_tags_set_str(demuxer->metadata, "TITLE", t);
|
2014-07-16 20:40:21 +00:00
|
|
|
talloc_free(t);
|
|
|
|
}
|
|
|
|
|
2014-07-14 23:49:02 +00:00
|
|
|
// 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);
|
|
|
|
|
2015-02-20 20:21:14 +00:00
|
|
|
p->slave = demux_open(demuxer->stream, ¶ms, demuxer->global);
|
2014-07-14 23:49:02 +00:00
|
|
|
if (!p->slave)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
// So that we don't miss initial packets of delayed subtitle streams.
|
2014-07-16 20:40:21 +00:00
|
|
|
demux_set_stream_autoselect(p->slave, true);
|
2014-07-14 23:49:02 +00:00
|
|
|
|
2014-09-29 15:49:26 +00:00
|
|
|
// 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.
|
2015-02-03 18:32:30 +00:00
|
|
|
if (demuxer->stream->uncached_type != STREAMTYPE_CDDA) {
|
|
|
|
demuxer->stream->seekable = false;
|
|
|
|
|
|
|
|
// Can be seekable even if the stream isn't.
|
|
|
|
demuxer->seekable = true;
|
|
|
|
}
|
2014-09-29 15:49:26 +00:00
|
|
|
|
2014-07-14 23:49:02 +00:00
|
|
|
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,
|
|
|
|
};
|