On 12/18/2018 10:56 AM, Paul B Mahol wrote: > Signed-off-by: Paul B Mahol <one...@gmail.com> > --- > libavformat/nut.h | 3 + > libavformat/nutenc.c | 130 +++++++++++++++++++++++++++++++++++++++++-- > 2 files changed, 129 insertions(+), 4 deletions(-) > > diff --git a/libavformat/nut.h b/libavformat/nut.h > index a4409ee23d..4b15dca1ea 100644 > --- a/libavformat/nut.h > +++ b/libavformat/nut.h > @@ -76,6 +76,9 @@ typedef struct StreamContext { > int last_flags; > int skip_until_key_frame; > int64_t last_pts; > + int64_t eor_pts; > + int64_t eor_dts; > + int eor_flushed; > int time_base_id; > AVRational *time_base; > int msb_pts_shift; > diff --git a/libavformat/nutenc.c b/libavformat/nutenc.c > index e9a3bb49db..9d1c540a9d 100644 > --- a/libavformat/nutenc.c > +++ b/libavformat/nutenc.c > @@ -940,6 +940,80 @@ fail: > return ret; > } > > +static void nut_update_max_pts(AVFormatContext *s, int stream_index, int64_t > pts) > +{ > + NUTContext *nut = s->priv_data; > + StreamContext *nus = &nut->stream[stream_index]; > + > + if (!nut->max_pts_tb || av_compare_ts(nut->max_pts, *nut->max_pts_tb, > pts, *nus->time_base) < 0) { > + nut->max_pts = pts; > + nut->max_pts_tb = nus->time_base; > + } > +} > + > +static int nut_write_eor(AVFormatContext *s, AVPacket *pkt) > +{ > + AVIOContext *bc = s->pb, *dyn_bc; > + NUTContext *nut = s->priv_data; > + StreamContext *nus = &nut->stream[pkt->stream_index]; > + int ret, frame_code, flags, needed_flags; > + int64_t pts = pkt->pts; > + int64_t coded_pts; > + FrameCode *fc; > + > + coded_pts = pts & ((1 << nus->msb_pts_shift) - 1); > + if (ff_lsb2full(nus, coded_pts) != pts) > + coded_pts = pts + (1 << nus->msb_pts_shift); > + > + nut->last_syncpoint_pos = avio_tell(bc); > + ret = avio_open_dyn_buf(&dyn_bc); > + if (ret < 0) > + return ret; > + put_tt(nut, nus->time_base, dyn_bc, pkt->dts); > + ff_put_v(dyn_bc, 0); > + > + if (nut->flags & NUT_BROADCAST) { > + put_tt(nut, nus->time_base, dyn_bc, > + av_rescale_q(av_gettime(), AV_TIME_BASE_Q, *nus->time_base)); > + } > + put_packet(nut, bc, dyn_bc, 1, SYNCPOINT_STARTCODE); > + > + frame_code = -1; > + for (int i = 0; i < 256; i++) { > + FrameCode *fc = &nut->frame_code[i]; > + int flags = fc->flags; > + > + if (flags & FLAG_INVALID) > + continue; > + > + if (!(flags & FLAG_CODED)) { > + continue; > + } > + > + frame_code = i; > + break; > + } > + av_assert0(frame_code != -1); > + > + fc = &nut->frame_code[frame_code]; > + flags = fc->flags; > + needed_flags = FLAG_KEY | FLAG_EOR | FLAG_CODED_PTS | FLAG_STREAM_ID; > + > + ffio_init_checksum(bc, ff_crc04C11DB7_update, 0); > + avio_w8(bc, frame_code); > + if (flags & FLAG_CODED) { > + ff_put_v(bc, (flags ^ needed_flags) & ~(FLAG_CODED)); > + flags = needed_flags; > + } > + if (flags & FLAG_STREAM_ID) ff_put_v(bc, pkt->stream_index); > + if (flags & FLAG_CODED_PTS) ff_put_v(bc, coded_pts); > + ffio_get_checksum(bc); > + > + nut_update_max_pts(s, pkt->stream_index, pkt->pts); > + > + return 0; > +} > + > static int nut_write_packet(AVFormatContext *s, AVPacket *pkt) > { > NUTContext *nut = s->priv_data; > @@ -956,6 +1030,9 @@ static int nut_write_packet(AVFormatContext *s, AVPacket > *pkt) > int data_size = pkt->size; > uint8_t *sm_buf = NULL; > > + if (!data_size) > + return nut_write_eor(s, pkt); > + > if (pkt->pts < 0) { > av_log(s, AV_LOG_ERROR, > "Negative pts not supported stream %d, pts %"PRId64"\n", > @@ -1150,10 +1227,7 @@ static int nut_write_packet(AVFormatContext *s, > AVPacket *pkt) > nus->keyframe_pts[nut->sp_count] = pkt->pts; > } > > - if (!nut->max_pts_tb || av_compare_ts(nut->max_pts, *nut->max_pts_tb, > pkt->pts, *nus->time_base) < 0) { > - nut->max_pts = pkt->pts; > - nut->max_pts_tb = nus->time_base; > - } > + nut_update_max_pts(s, pkt->stream_index, pkt->pts); > > fail: > av_freep(&sm_buf); > @@ -1161,6 +1235,53 @@ fail: > return ret; > } > > +static int nut_interleave_packet(AVFormatContext *s, AVPacket *out, > + AVPacket *pkt, int flush) > +{ > + NUTContext *nut = s->priv_data; > + int ret; > + > + if (pkt) { > + StreamContext *nus = &nut->stream[pkt->stream_index]; > + > + nus->eor_pts = FFMAX(pkt->pts + pkt->duration, nus->eor_pts); > + nus->eor_dts = FFMAX(pkt->dts + pkt->duration, nus->eor_dts); > + } else if (flush) { > + StreamContext *nus; > + int i; > + > + for (i = 0; i < s->nb_streams; i++) { > + nus = &nut->stream[i]; > + > + if (nus->eor_flushed) > + continue; > + > + if (s->streams[i]->last_in_packet_buffer) > + continue; > + > + break; > + } > + > + if (i < s->nb_streams) { > + pkt = av_packet_alloc(); > + if (!pkt) > + return AVERROR(ENOMEM); > + > + ret = av_new_packet(pkt, 0); > + if (ret < 0) > + return ret; > + pkt->stream_index = i; > + pkt->pts = nus->eor_pts; > + pkt->dts = nus->eor_dts; > + pkt->duration = 0; > + nus->eor_flushed = 1; > + ret = ff_interleave_packet_per_dts(s, out, pkt, 0);
This apparently will create a new reference for pkt, but will not unref the existing one or free the packet. The line below should be av_packet_free(&pkt) instead. > + pkt = NULL; > + } > + } > + return ff_interleave_packet_per_dts(s, out, pkt, flush); > +} > + > static int nut_write_trailer(AVFormatContext *s) > { > NUTContext *nut = s->priv_data; > @@ -1225,6 +1346,7 @@ AVOutputFormat ff_nut_muxer = { > .write_header = nut_write_header, > .write_packet = nut_write_packet, > .write_trailer = nut_write_trailer, > + .interleave_packet = nut_interleave_packet, > .deinit = nut_write_deinit, > .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS, > .codec_tag = ff_nut_codec_tags, > _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel