Skip to content

Instantly share code, notes, and snippets.

@tmm1
Last active April 6, 2017 10:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tmm1/c15634952122d60a7adb6865b59afd48 to your computer and use it in GitHub Desktop.
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
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