Last active
April 6, 2017 10:56
-
-
Save tmm1/c15634952122d60a7adb6865b59afd48 to your computer and use it in GitHub Desktop.
[wip] mpv patch to enable playback of mpegts with mid-stream pid changes, like https://s3.amazonaws.com/tmm1/pmt-version-change.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/demux/demux.c b/demux/demux.c | |
index 0c45083e2d..61e45be90b 100644 | |
--- a/demux/demux.c | |
+++ b/demux/demux.c | |
@@ -268,6 +268,7 @@ struct sh_stream *demux_alloc_sh_stream(enum stream_type type) | |
.index = -1, | |
.ff_index = -1, // may be overwritten by demuxer | |
.demuxer_id = -1, // ... same | |
+ .program_num = -1, // ... | |
.codec = talloc_zero(sh, struct mp_codec_params), | |
.tags = talloc_zero(sh, struct mp_tags), | |
}; | |
@@ -1505,6 +1506,25 @@ void demuxer_select_track(struct demuxer *demuxer, struct sh_stream *stream, | |
pthread_mutex_unlock(&in->lock); | |
} | |
+void demuxer_select_track2(struct demuxer *demuxer, struct sh_stream *stream, | |
+ double ref_pts, bool selected) | |
+{ | |
+ struct demux_internal *in = demuxer->in; | |
+ pthread_mutex_lock(&in->lock); | |
+ // don't flush buffers if stream is already selected / unselected | |
+ if (stream->ds->selected != selected) { | |
+ stream->ds->selected = selected; | |
+ ds_flush(stream->ds); | |
+ in->tracks_switched = true; | |
+ if (in->threading) { | |
+ pthread_cond_signal(&in->wakeup); | |
+ } else { | |
+ execute_trackswitch(in); | |
+ } | |
+ } | |
+ pthread_mutex_unlock(&in->lock); | |
+} | |
+ | |
void demux_set_stream_autoselect(struct demuxer *demuxer, bool autoselect) | |
{ | |
assert(!demuxer->in->threading); // laziness | |
diff --git a/demux/demux.h b/demux/demux.h | |
index 8a1da4e400..650eaaf7b1 100644 | |
--- a/demux/demux.h | |
+++ b/demux/demux.h | |
@@ -272,6 +272,8 @@ void demux_set_ts_offset(struct demuxer *demuxer, double offset); | |
int demux_control(struct demuxer *demuxer, int cmd, void *arg); | |
+void demuxer_select_track2(struct demuxer *demuxer, struct sh_stream *stream, | |
+ double ref_pts, bool selected); | |
void demuxer_select_track(struct demuxer *demuxer, struct sh_stream *stream, | |
double ref_pts, bool selected); | |
void demux_set_stream_autoselect(struct demuxer *demuxer, bool autoselect); | |
diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c | |
index 8371985419..cf4e30381d 100644 | |
--- a/demux/demux_lavf.c | |
+++ b/demux/demux_lavf.c | |
@@ -183,6 +183,12 @@ static const struct format_hack format_hacks[] = { | |
{0} | |
}; | |
+typedef struct { | |
+ int num; | |
+ int pcr_pid; | |
+ unsigned int nb_stream_indexes; | |
+} lavf_program_t; | |
+ | |
typedef struct lavf_priv { | |
struct stream *stream; | |
bool own_stream; | |
@@ -200,6 +206,9 @@ typedef struct lavf_priv { | |
char *mime_type; | |
double seek_delay; | |
+ lavf_program_t program; | |
+ struct sh_stream *video_stream; | |
+ | |
struct demux_lavf_opts *opts; | |
double mf_fps; | |
} lavf_priv_t; | |
@@ -551,6 +560,15 @@ static void select_tracks(struct demuxer *demuxer, int start) | |
bool selected = stream && demux_stream_is_selected(stream) && | |
!stream->attached_picture; | |
st->discard = selected ? AVDISCARD_DEFAULT : AVDISCARD_ALL; | |
+ | |
+ if (stream && stream->type == STREAM_VIDEO) { | |
+ if (selected) { | |
+ priv->program.num = stream->program_num; | |
+ priv->video_stream = stream; | |
+ } | |
+ if (!selected && stream->program_num == priv->program.num) | |
+ st->discard = AVDISCARD_DEFAULT; | |
+ } | |
} | |
} | |
@@ -700,6 +718,9 @@ static void handle_new_stream(demuxer_t *demuxer, int i) | |
MP_TARRAY_APPEND(priv, priv->streams, priv->num_streams, sh); | |
if (sh) { | |
+ AVProgram *program = av_find_program_from_stream(priv->avfc, NULL, st->index); | |
+ if (program) | |
+ sh->program_num = program->program_num; | |
sh->ff_index = st->index; | |
sh->codec->codec = mp_codec_from_av_codec_id(codec->codec_id); | |
sh->codec->codec_tag = codec->codec_tag; | |
@@ -736,6 +757,70 @@ static void handle_new_stream(demuxer_t *demuxer, int i) | |
select_tracks(demuxer, i); | |
} | |
+static void detect_program_changes(demuxer_t *demuxer) | |
+{ | |
+ lavf_priv_t *priv = demuxer->priv; | |
+ struct sh_stream *old_stream = NULL, *new_stream = NULL; | |
+ AVProgram *program; | |
+ int i, j; | |
+ | |
+ if (priv->avfc->nb_programs < 1) | |
+ return; | |
+ if (priv->program.num == 0) | |
+ return; | |
+ | |
+ for (i = 0; i < priv->avfc->nb_programs; i++) | |
+ if (priv->avfc->programs[i]->id == priv->program.num) | |
+ break; | |
+ if (i == priv->avfc->nb_programs) | |
+ return; | |
+ program = priv->avfc->programs[i]; | |
+ | |
+ // skip unless program changed | |
+ if (program->pcr_pid == priv->program.pcr_pid && | |
+ program->nb_stream_indexes == priv->program.nb_stream_indexes) { | |
+ return; | |
+ } | |
+ | |
+ MP_VERBOSE(demuxer, "Detected program change for %d: " | |
+ "(pcr=%d,nb=%d) -> (pcr=%d,nb=%d) \n", | |
+ program->program_num, | |
+ priv->program.pcr_pid, priv->program.nb_stream_indexes, | |
+ program->pcr_pid, program->nb_stream_indexes); | |
+ | |
+ priv->program = (lavf_program_t){ | |
+ .num = program->program_num, | |
+ .pcr_pid = program->pcr_pid, | |
+ .nb_stream_indexes = program->nb_stream_indexes, | |
+ }; | |
+ | |
+ for (i = 0; i < priv->num_streams; i++) { | |
+ struct sh_stream *stream = priv->streams[i]; | |
+ if (!stream || stream->type != STREAM_AUDIO) | |
+ continue; | |
+ | |
+ int found = 0; | |
+ for (j = 0; j < program->nb_stream_indexes; j++) { | |
+ if (program->stream_index[j] == stream->ff_index) { | |
+ found = 1; | |
+ break; | |
+ } | |
+ } | |
+ | |
+ if (found) { | |
+ if (!new_stream) new_stream = stream; | |
+ } else if (demux_stream_is_selected(stream)) { | |
+ old_stream = stream; | |
+ } | |
+ } | |
+ | |
+ if (old_stream && new_stream) { | |
+ MP_VERBOSE(demuxer, "Switching audio from %d to %d\n", old_stream->index, new_stream->index); | |
+ demuxer_select_track(demuxer, old_stream, MP_NOPTS_VALUE, false); | |
+ demuxer_select_track2(demuxer, new_stream, MP_NOPTS_VALUE, true); | |
+ } | |
+} | |
+ | |
// Add any new streams that might have been added | |
static void add_new_streams(demuxer_t *demuxer) | |
{ | |
@@ -952,12 +1037,19 @@ static int demux_lavf_fill_buffer(demuxer_t *demux) | |
} | |
add_new_streams(demux); | |
+ detect_program_changes(demux); | |
update_metadata(demux, pkt); | |
assert(pkt->stream_index >= 0 && pkt->stream_index < priv->num_streams); | |
struct sh_stream *stream = priv->streams[pkt->stream_index]; | |
AVStream *st = priv->avfc->streams[pkt->stream_index]; | |
+ if (stream->type == STREAM_VIDEO && | |
+ stream != priv->video_stream && | |
+ priv->video_stream && | |
+ priv->program.num == stream->program_num) | |
+ stream = priv->video_stream; | |
+ | |
if (!demux_stream_is_selected(stream)) { | |
av_packet_unref(pkt); | |
return 1; // don't signal EOF if skipping a packet | |
diff --git a/demux/stheader.h b/demux/stheader.h | |
index 26c1246d66..7280074605 100644 | |
--- a/demux/stheader.h | |
+++ b/demux/stheader.h | |
@@ -41,6 +41,7 @@ struct sh_stream { | |
struct mp_codec_params *codec; | |
+ int program_num; | |
char *title; | |
char *lang; // language code | |
bool default_track; // container default track flag |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment