[FFmpeg-devel] [PATCH] avformat/nut: fix duration estimation by writting EOR packets

Paul B Mahol onemda at gmail.com
Mon Dec 17 20:32:49 EET 2018


On 12/17/18, Michael Niedermayer <michael at niedermayer.cc> wrote:
> On Mon, Dec 17, 2018 at 06:04:40PM +0100, Paul B Mahol wrote:
>> Hi,
>>
>> patches attached.
>
>>  nut.h    |    2 +
>>  nutdec.c |    3 ++
>>  nutenc.c |   87
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
>>  3 files changed, 88 insertions(+), 4 deletions(-)
>> 870df19d733f29294a2cb2e3ea5ed1a09745f3a4
>> 0001-avformat-nut-fix-duration-estimation-by-writing-EOR-.patch
>> From 80d6805fdf386182341fe72035ab88e06a602752 Mon Sep 17 00:00:00 2001
>> From: Paul B Mahol <onemda at gmail.com>
>> Date: Mon, 17 Dec 2018 16:43:57 +0100
>> Subject: [PATCH 1/2] avformat/nut: fix duration estimation by writing EOR
>>  packets
>>
>> Signed-off-by: Paul B Mahol <onemda at gmail.com>
>> ---
>>  libavformat/nut.h    |  2 +
>>  libavformat/nutdec.c |  3 ++
>>  libavformat/nutenc.c | 87 ++++++++++++++++++++++++++++++++++++++++++--
>>  3 files changed, 88 insertions(+), 4 deletions(-)
>>
>> diff --git a/libavformat/nut.h b/libavformat/nut.h
>> index a4409ee23d..d7ba86b5e5 100644
>> --- a/libavformat/nut.h
>> +++ b/libavformat/nut.h
>> @@ -76,6 +76,8 @@ typedef struct StreamContext {
>>      int last_flags;
>>      int skip_until_key_frame;
>>      int64_t last_pts;
>> +    int64_t last_dts;
>> +    int64_t last_duration;
>>      int time_base_id;
>>      AVRational *time_base;
>>      int msb_pts_shift;
>> diff --git a/libavformat/nutdec.c b/libavformat/nutdec.c
>> index 056ef59d00..f2490f9842 100644
>
>> --- a/libavformat/nutdec.c
>> +++ b/libavformat/nutdec.c
>> @@ -1080,6 +1080,9 @@ static int decode_frame(NUTContext *nut, AVPacket
>> *pkt, int frame_code)
>>
>>      stc = &nut->stream[stream_id];
>>
>> +    if (stc->last_flags & FLAG_EOR)
>> +        return 1;
>
> EOR can occur in the middle of subtitle streams. It would be used to mark
> areas with no vissible subtitles.
> (The point behind this is that it allows seeking to consider a subtitle
> stream
>  if and only if there are actually any displayed subtitles at that time)
>
> this code would break that
>
> also demxuer and muxer changes should be in seperate patches
>
>
>> +
>>      if (stc->last_flags & FLAG_KEY)
>>          stc->skip_until_key_frame = 0;
>>
>> diff --git a/libavformat/nutenc.c b/libavformat/nutenc.c
>> index e9a3bb49db..c12b4cc8cf 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, int stream_index)
>> +{
>> +    AVIOContext *bc = s->pb, *dyn_bc;
>> +    NUTContext *nut = s->priv_data;
>> +    StreamContext *nus = &nut->stream[stream_index];
>> +    int ret, frame_code, flags, needed_flags;
>> +    int64_t pts = nus->last_pts + nus->last_duration;
>> +    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, nus->last_dts +
>> nus->last_duration);
>> +    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, stream_index);
>> +    if (flags & FLAG_CODED_PTS)  ff_put_v(bc, coded_pts);
>> +    ffio_get_checksum(bc);
>> +
>> +    nut_update_max_pts(s, stream_index, nus->last_pts +
>> nus->last_duration);
>> +
>> +    return 0;
>> +}
>> +
>>  static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
>>  {
>>      NUTContext *nut    = s->priv_data;
>> @@ -1136,6 +1210,8 @@ static int nut_write_packet(AVFormatContext *s,
>> AVPacket *pkt)
>>
>>      nus->last_flags = flags;
>>      nus->last_pts   = pkt->pts;
>> +    nus->last_dts   = pkt->dts;
>> +    nus->last_duration = pkt->duration;
>>
>>      //FIXME just store one per syncpoint
>>      if (flags & FLAG_KEY && !(nut->flags & NUT_PIPE)) {
>> @@ -1150,10 +1226,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);
>> @@ -1167,6 +1240,12 @@ static int nut_write_trailer(AVFormatContext *s)
>>      AVIOContext *bc = s->pb, *dyn_bc;
>>      int ret;
>>
>> +    for (int i = 0; i < s->nb_streams; i++) {
>> +        ret = nut_write_eor(s, i);
>> +        if (ret < 0)
>> +            return ret;
>> +    }
>> +
>>      while (nut->header_count < 3)
>>          write_headers(s, bc);
>
> This violates the packet interleaving requirements
> if one stream ends. lets say at time 5sec and one continues with frames at
> 6,7,8 sec then the EOR frame for the stream ending at 5sec has to be
> written
> before the later frames.

How this violates it? It writes it at end. After end there is nothing.

>
> The best way to implement this will likely be with
> oformat->interleave_packet
> because at this level you know when the last packet is reached and you can
> also trivially inject an additional packet. That should then get
> interleaved
> automatically.

That function is no documented at all.

>
> also i suspect that index & syncpoint related code will need changes
> to support EORs


More information about the ffmpeg-devel mailing list