diff mbox series

[FFmpeg-devel,5/7] avformat/matroskaenc: write a MaxBlockAdditionID element

Message ID 20230321170637.10907-5-jamrial@gmail.com
State New
Headers show
Series [FFmpeg-devel,1/7] avformat/matroskadec: support parsing more than one BlockMore element | expand

Checks

Context Check Description
andriy/make_x86 success Make finished
andriy/make_fate_x86 fail Make fate failed

Commit Message

James Almer March 21, 2023, 5:06 p.m. UTC
A non zero value is mandatory for Matroska if the track has blocks with BlockAdditions.

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavformat/matroskaenc.c | 36 ++++++++++++++++++++++++++++++++----
 1 file changed, 32 insertions(+), 4 deletions(-)

Comments

Anton Khirnov March 24, 2023, 11:37 a.m. UTC | #1
Quoting James Almer (2023-03-21 18:06:35)
> A non zero value is mandatory for Matroska if the track has blocks with BlockAdditions.
> 
> Signed-off-by: James Almer <jamrial@gmail.com>
> ---
>  libavformat/matroskaenc.c | 36 ++++++++++++++++++++++++++++++++----
>  1 file changed, 32 insertions(+), 4 deletions(-)
> 
> diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
> index 46f4331a18..0687d9c32e 100644
> --- a/libavformat/matroskaenc.c
> +++ b/libavformat/matroskaenc.c
> @@ -188,6 +188,8 @@ typedef struct mkv_track {
>      int64_t         last_timestamp;
>      int64_t         duration;
>      int64_t         duration_offset;
> +    uint64_t        max_blockaddid;
> +    int64_t         blockadditionmapping_offset;
>      int             codecpriv_offset;
>      unsigned        codecpriv_size;     ///< size reserved for CodecPrivate excluding header+length field
>      int64_t         ts_offset;
> @@ -1597,12 +1599,21 @@ static int mkv_write_stereo_mode(AVFormatContext *s, EbmlWriter *writer,
>      return 0;
>  }
>  
> -static void mkv_write_dovi(AVFormatContext *s, AVIOContext *pb, AVStream *st)
> +static void mkv_write_blockadditionmapping(AVFormatContext *s, MatroskaMuxContext *mkv,
> +                                           AVIOContext *pb, mkv_track *track, AVStream *st)
>  {
>  #if CONFIG_MATROSKA_MUXER
>      AVDOVIDecoderConfigurationRecord *dovi = (AVDOVIDecoderConfigurationRecord *)
>                                               av_stream_get_side_data(st, AV_PKT_DATA_DOVI_CONF, NULL);
>  
> +    if (IS_SEEKABLE(s->pb, mkv)) {
> +        track->blockadditionmapping_offset = avio_tell(pb);
> +        // We can't know at this point if there will be a block with BlockAdditions, so
> +        // we either write the default value here, or a void element. Either of them will
> +        // be overwritten when finishing the track.

IIRC matroska uints are variable-size, so the value you write later may
have a longer representation than the dummy placeholder you're writing
here.
Or am I wrong?
James Almer March 24, 2023, 11:41 a.m. UTC | #2
On 3/24/2023 8:37 AM, Anton Khirnov wrote:
> Quoting James Almer (2023-03-21 18:06:35)
>> A non zero value is mandatory for Matroska if the track has blocks with BlockAdditions.
>>
>> Signed-off-by: James Almer <jamrial@gmail.com>
>> ---
>>   libavformat/matroskaenc.c | 36 ++++++++++++++++++++++++++++++++----
>>   1 file changed, 32 insertions(+), 4 deletions(-)
>>
>> diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
>> index 46f4331a18..0687d9c32e 100644
>> --- a/libavformat/matroskaenc.c
>> +++ b/libavformat/matroskaenc.c
>> @@ -188,6 +188,8 @@ typedef struct mkv_track {
>>       int64_t         last_timestamp;
>>       int64_t         duration;
>>       int64_t         duration_offset;
>> +    uint64_t        max_blockaddid;
>> +    int64_t         blockadditionmapping_offset;
>>       int             codecpriv_offset;
>>       unsigned        codecpriv_size;     ///< size reserved for CodecPrivate excluding header+length field
>>       int64_t         ts_offset;
>> @@ -1597,12 +1599,21 @@ static int mkv_write_stereo_mode(AVFormatContext *s, EbmlWriter *writer,
>>       return 0;
>>   }
>>   
>> -static void mkv_write_dovi(AVFormatContext *s, AVIOContext *pb, AVStream *st)
>> +static void mkv_write_blockadditionmapping(AVFormatContext *s, MatroskaMuxContext *mkv,
>> +                                           AVIOContext *pb, mkv_track *track, AVStream *st)
>>   {
>>   #if CONFIG_MATROSKA_MUXER
>>       AVDOVIDecoderConfigurationRecord *dovi = (AVDOVIDecoderConfigurationRecord *)
>>                                                av_stream_get_side_data(st, AV_PKT_DATA_DOVI_CONF, NULL);
>>   
>> +    if (IS_SEEKABLE(s->pb, mkv)) {
>> +        track->blockadditionmapping_offset = avio_tell(pb);
>> +        // We can't know at this point if there will be a block with BlockAdditions, so
>> +        // we either write the default value here, or a void element. Either of them will
>> +        // be overwritten when finishing the track.
> 
> IIRC matroska uints are variable-size, so the value you write later may
> have a longer representation than the dummy placeholder you're writing
> here.
> Or am I wrong?

It might if we were to write any arbitrary value passed to the muxer in 
AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL side data, but we will not. We're 
only going to write 1 (opaque, codec specific, currently used for alpha 
channel) at this point in the patchset, or 4 (itu-t t35) after patch 
6/7, for now.
Anton Khirnov March 24, 2023, 11:43 a.m. UTC | #3
Quoting James Almer (2023-03-24 12:41:27)
> On 3/24/2023 8:37 AM, Anton Khirnov wrote:
> > Quoting James Almer (2023-03-21 18:06:35)
> >> A non zero value is mandatory for Matroska if the track has blocks with BlockAdditions.
> >>
> >> Signed-off-by: James Almer <jamrial@gmail.com>
> >> ---
> >>   libavformat/matroskaenc.c | 36 ++++++++++++++++++++++++++++++++----
> >>   1 file changed, 32 insertions(+), 4 deletions(-)
> >>
> >> diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
> >> index 46f4331a18..0687d9c32e 100644
> >> --- a/libavformat/matroskaenc.c
> >> +++ b/libavformat/matroskaenc.c
> >> @@ -188,6 +188,8 @@ typedef struct mkv_track {
> >>       int64_t         last_timestamp;
> >>       int64_t         duration;
> >>       int64_t         duration_offset;
> >> +    uint64_t        max_blockaddid;
> >> +    int64_t         blockadditionmapping_offset;
> >>       int             codecpriv_offset;
> >>       unsigned        codecpriv_size;     ///< size reserved for CodecPrivate excluding header+length field
> >>       int64_t         ts_offset;
> >> @@ -1597,12 +1599,21 @@ static int mkv_write_stereo_mode(AVFormatContext *s, EbmlWriter *writer,
> >>       return 0;
> >>   }
> >>   
> >> -static void mkv_write_dovi(AVFormatContext *s, AVIOContext *pb, AVStream *st)
> >> +static void mkv_write_blockadditionmapping(AVFormatContext *s, MatroskaMuxContext *mkv,
> >> +                                           AVIOContext *pb, mkv_track *track, AVStream *st)
> >>   {
> >>   #if CONFIG_MATROSKA_MUXER
> >>       AVDOVIDecoderConfigurationRecord *dovi = (AVDOVIDecoderConfigurationRecord *)
> >>                                                av_stream_get_side_data(st, AV_PKT_DATA_DOVI_CONF, NULL);
> >>   
> >> +    if (IS_SEEKABLE(s->pb, mkv)) {
> >> +        track->blockadditionmapping_offset = avio_tell(pb);
> >> +        // We can't know at this point if there will be a block with BlockAdditions, so
> >> +        // we either write the default value here, or a void element. Either of them will
> >> +        // be overwritten when finishing the track.
> > 
> > IIRC matroska uints are variable-size, so the value you write later may
> > have a longer representation than the dummy placeholder you're writing
> > here.
> > Or am I wrong?
> 
> It might if we were to write any arbitrary value passed to the muxer in 
> AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL side data, but we will not. We're 
> only going to write 1 (opaque, codec specific, currently used for alpha 
> channel) at this point in the patchset, or 4 (itu-t t35) after patch 
> 6/7, for now.

Ok, might still be safer against future changes to check that the
updated value is not too large.
diff mbox series

Patch

diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index 46f4331a18..0687d9c32e 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -188,6 +188,8 @@  typedef struct mkv_track {
     int64_t         last_timestamp;
     int64_t         duration;
     int64_t         duration_offset;
+    uint64_t        max_blockaddid;
+    int64_t         blockadditionmapping_offset;
     int             codecpriv_offset;
     unsigned        codecpriv_size;     ///< size reserved for CodecPrivate excluding header+length field
     int64_t         ts_offset;
@@ -1597,12 +1599,21 @@  static int mkv_write_stereo_mode(AVFormatContext *s, EbmlWriter *writer,
     return 0;
 }
 
-static void mkv_write_dovi(AVFormatContext *s, AVIOContext *pb, AVStream *st)
+static void mkv_write_blockadditionmapping(AVFormatContext *s, MatroskaMuxContext *mkv,
+                                           AVIOContext *pb, mkv_track *track, AVStream *st)
 {
 #if CONFIG_MATROSKA_MUXER
     AVDOVIDecoderConfigurationRecord *dovi = (AVDOVIDecoderConfigurationRecord *)
                                              av_stream_get_side_data(st, AV_PKT_DATA_DOVI_CONF, NULL);
 
+    if (IS_SEEKABLE(s->pb, mkv)) {
+        track->blockadditionmapping_offset = avio_tell(pb);
+        // We can't know at this point if there will be a block with BlockAdditions, so
+        // we either write the default value here, or a void element. Either of them will
+        // be overwritten when finishing the track.
+        put_ebml_uint(mkv->track.bc, MATROSKA_ID_TRACKMAXBLKADDID, 0);
+    }
+
     if (dovi && dovi->dv_profile <= 10) {
         ebml_master mapping;
         uint8_t buf[ISOM_DVCC_DVVC_SIZE];
@@ -1846,9 +1857,6 @@  static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv,
         if (ret < 0)
             return ret;
 
-        if (!IS_WEBM(mkv))
-            mkv_write_dovi(s, pb, st);
-
         break;
 
     case AVMEDIA_TYPE_AUDIO:
@@ -1924,6 +1932,9 @@  static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv,
         return AVERROR(EINVAL);
     }
 
+    if (!IS_WEBM(mkv))
+        mkv_write_blockadditionmapping(s, mkv, pb, track, st);
+
     if (!IS_WEBM(mkv) || par->codec_id != AV_CODEC_ID_WEBVTT) {
         uint8_t *codecpriv;
         int codecpriv_size, max_payload_size;
@@ -2667,6 +2678,7 @@  static int mkv_write_block(void *logctx, MatroskaMuxContext *mkv,
                              side_data + 8, side_data_size - 8);
         ebml_writer_close_master(&writer);
         ebml_writer_close_master(&writer);
+        track->max_blockaddid = additional_id;
     }
 
     if (!force_blockgroup && writer.nb_elements == 2) {
@@ -3070,6 +3082,22 @@  after_cues:
 
     if (mkv->track.bc) {
         // write Tracks master
+        int64_t end = avio_tell(mkv->track.bc);
+
+        for (int i = 0; i < s->nb_streams; i++) {
+            const mkv_track *track = &mkv->tracks[i];
+
+            if (IS_WEBM(mkv))
+                break;
+            if (!track->max_blockaddid)
+                continue;
+
+            avio_seek(mkv->track.bc, track->blockadditionmapping_offset, SEEK_SET);
+
+            put_ebml_uint(mkv->track.bc, MATROSKA_ID_TRACKMAXBLKADDID, track->max_blockaddid);
+        }
+
+        avio_seek(mkv->track.bc, end, SEEK_SET);
         avio_seek(pb, mkv->track.pos, SEEK_SET);
         ret = end_ebml_master_crc32(pb, &mkv->track.bc, mkv,
                                     MATROSKA_ID_TRACKS, 0, 0, 0);