Andreas, On Mon, 22. Jul 12:22, Andreas Håkon wrote: > Hi, > > Based on the discussion of my previous patch > https://patchwork.ffmpeg.org/patch/13487/ > Here I publish a first part of the patch that only addresses the PCR problem.
Thanks for splitting the patch set. > > This supersedes too: https://patchwork.ffmpeg.org/patch/13745/ > > Regards. > A.H. > > --- > From a9d51e71c546986c8ea3bd111d16fc81354ffa3d Mon Sep 17 00:00:00 2001 > From: Andreas Hakon <andreas.ha...@protonmail.com> > Date: Mon, 22 Jul 2019 13:10:20 +0100 > Subject: [PATCH] libavformat/mpegtsenc: fix incorrect PCR with multiple > programs > > The MPEG-TS muxer has a serious bug related to the PCR pid selection. > This bug appears when more than one program is used. The root cause is because > the current code targets only one program when selecting the stream for the > PCR. The PCR pid selection is probably fine. The issue is that pcr_packet_period is zero for N-1 out of N programs. That's why in your tests you see the insertion of the pcr adaptation field in each frame for 1/2 programs. > > This patch solves this problem. And you can check it with these commands: > > - First, make sure you have "ffmpeg-old" (a binary without the patch), > "ffmpeg-new" (a binary with the patch), and the test file "Day_Flight.mpg" > from > https://samples.ffmpeg.org/MPEG2/mpegts-klv/Day%20Flight.mpg > > - Execute these commands: > > $ ffmpeg-old -loglevel verbose -y -f mpegts -i Day_Flight.mpg \ > -map i:0x1e1 -c:v:0 copy -map i:0x1e1 -c:v:1 copy \ > -program st=0 -program st=1 -f mpegts out-error.ts > > $ ffmpeg-new -loglevel verbose -y -f mpegts -i Day_Flight.mpg \ > -map i:0x1e1 -c:v:0 copy -map i:0x1e1 -c:v:1 copy \ > -program st=0 -program st=1 -f mpegts out-ok.ts > > - As a result, you have two files "out-error.ts" and "out-ok.ts". Both files > with the same content (but not identical): two services, and each one with one > video stream. However, the first file has errors in the PCR timestamps. > > - If you analyze the files, you can see that the file "out-error.ts" has PCR > marks in every packet of the pid 256 (a total of 561862 packets with PCR > marks). > However, the pid 257 has 783 packets only with PCR marks. On the other hand, > the file "out-ok.ts" has correct PCR marks, and both pids (256 & 257) only > have > 783 packets with PCR timestamps. > > - You can do additional checks with the tool "tsreport" from the tstools > package. > Try this to see the difference: > > $ tsreport -b -v out-ok.ts | more > $ tsreport -b -v out-error.ts | more > > > Signed-off-by: Andreas Hakon <andreas.ha...@protonmail.com> > --- > libavformat/mpegtsenc.c | 82 > +++++++++++++++++++++++++---------------------- > 1 file changed, 44 insertions(+), 38 deletions(-) > > diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c > index fc0ea22..4a978ed 100644 > --- a/libavformat/mpegtsenc.c > +++ b/libavformat/mpegtsenc.c > @@ -953,46 +953,54 @@ static int mpegts_init(AVFormatContext *s) > > av_freep(&pids); > > - /* if no video stream, use the first stream as PCR */ > - if (service->pcr_pid == 0x1fff && s->nb_streams > 0) { > - pcr_st = s->streams[0]; > - ts_st = pcr_st->priv_data; > - service->pcr_pid = ts_st->pid; > - } else > - ts_st = pcr_st->priv_data; > - > - if (ts->mux_rate > 1) { > - service->pcr_packet_period = (int64_t)ts->mux_rate * ts->pcr_period / > - (TS_PACKET_SIZE * 8 * 1000); > - ts->sdt_packet_period = (int64_t)ts->mux_rate * > SDT_RETRANS_TIME / > - (TS_PACKET_SIZE * 8 * 1000); > - ts->pat_packet_period = (int64_t)ts->mux_rate * > PAT_RETRANS_TIME / > - (TS_PACKET_SIZE * 8 * 1000); > - > - if (ts->copyts < 1) > - ts->first_pcr = av_rescale(s->max_delay, PCR_TIME_BASE, > AV_TIME_BASE); > - } else { > - /* Arbitrary values, PAT/PMT will also be written on video key > frames */ > - ts->sdt_packet_period = 200; > - ts->pat_packet_period = 40; > - if (pcr_st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { > - int frame_size = av_get_audio_frame_duration2(pcr_st->codecpar, > 0); > - if (!frame_size) { > - av_log(s, AV_LOG_WARNING, "frame size not set\n"); > - service->pcr_packet_period = > - pcr_st->codecpar->sample_rate / (10 * 512); > + for (i = 0; i < ts->nb_services; i++) { > + service = ts->services[i]; > + > + /* if no video stream, use the first stream as PCR */ > + if (service->pcr_pid == 0x1fff && s->nb_streams > 0) { > + pcr_st = s->streams[0]; How do you know that s->streams[0] belongs to this particular program? > + ts_st = pcr_st->priv_data; > + service->pcr_pid = ts_st->pid; > + } else > + ts_st = pcr_st->priv_data; pcr_st stream is set outside the for loop. No reason that it's part of this program. > + > + if (ts->mux_rate > 1) { > + service->pcr_packet_period = (int64_t)ts->mux_rate * > ts->pcr_period / > + (TS_PACKET_SIZE * 8 * 1000); > + ts->sdt_packet_period = (int64_t)ts->mux_rate * > SDT_RETRANS_TIME / > + (TS_PACKET_SIZE * 8 * 1000); > + ts->pat_packet_period = (int64_t)ts->mux_rate * > PAT_RETRANS_TIME / > + (TS_PACKET_SIZE * 8 * 1000); > + if (ts->copyts < 1) > + ts->first_pcr = av_rescale(s->max_delay, PCR_TIME_BASE, > AV_TIME_BASE); > + } else { > + /* Arbitrary values, PAT/PMT will also be written on video key > frames */ > + ts->sdt_packet_period = 200; > + ts->pat_packet_period = 40; These assignments do not change for each service/program. They should probably be outside of the for loop. > + if (pcr_st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { > + int frame_size = > av_get_audio_frame_duration2(pcr_st->codecpar, 0); > + if (!frame_size) { > + av_log(s, AV_LOG_WARNING, "frame size not set\n"); > + service->pcr_packet_period = > + pcr_st->codecpar->sample_rate / (10 * 512); > + } else { > + service->pcr_packet_period = > + pcr_st->codecpar->sample_rate / (10 * frame_size); > + } > } else { > + // max delta PCR 0.1s > + // TODO: should be avg_frame_rate > service->pcr_packet_period = > - pcr_st->codecpar->sample_rate / (10 * frame_size); > + ts_st->user_tb.den / (10 * ts_st->user_tb.num); pcr_packet_period may be incorrect here because ts_st may be coming from a stream that's not part of this program. > } > - } else { > - // max delta PCR 0.1s > - // TODO: should be avg_frame_rate > - service->pcr_packet_period = > - ts_st->user_tb.den / (10 * ts_st->user_tb.num); > + if (!service->pcr_packet_period) > + service->pcr_packet_period = 1; > } > - if (!service->pcr_packet_period) > - service->pcr_packet_period = 1; > + > + // output a PCR as soon as possible > + service->pcr_packet_count = service->pcr_packet_period; > + > + av_log(s, AV_LOG_VERBOSE, "service %i using PCR in pid=%i\n", > service->sid, service->pcr_pid); > } > > ts->last_pat_ts = AV_NOPTS_VALUE; > @@ -1005,8 +1013,6 @@ static int mpegts_init(AVFormatContext *s) > ts->sdt_packet_period = INT_MAX; > } > > - // output a PCR as soon as possible > - service->pcr_packet_count = service->pcr_packet_period; > ts->pat_packet_count = ts->pat_packet_period - 1; > ts->sdt_packet_count = ts->sdt_packet_period - 1; > Andriy _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".