diff mbox series

[FFmpeg-devel] avformat/matroskadec: Output palette as stream side data

Message ID AS8P250MB0744AE847962511BE05158218FCAA@AS8P250MB0744.EURP250.PROD.OUTLOOK.COM
State New
Headers show
Series [FFmpeg-devel] avformat/matroskadec: Output palette as stream side data | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished

Commit Message

Andreas Rheinhardt Oct. 5, 2023, 12:36 p.m. UTC
This is simpler implementation-wise (it avoids an almost-always-false
check in read_packet and decreases sizeof(MatroskaTrack) by about 2/3)
and makes the side-data available directly after read_header.

It also fixes the Matroska analog of ticket #10602: If a Matroska track
has a palette, said palette will be attached as side-data to the
first packet of said track and most likely, this is one read during
avformat_find_stream_info(). Yet if this packet is discarded because
of a seek performed immediately after avformat_find_stream_info(),
the information about the global palette will never reach the user.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
Ticket #10602 can unfortunately not be fixed in this way,
because avi allows to update the palette mid-stream,
so that the palette contained in extradata must not be
exported via global side data due to the semantics of the latter.

 libavformat/matroskadec.c | 39 ++++++++++++---------------------------
 1 file changed, 12 insertions(+), 27 deletions(-)

Comments

Michael Niedermayer Oct. 8, 2023, 4:36 p.m. UTC | #1
On Thu, Oct 05, 2023 at 02:36:52PM +0200, Andreas Rheinhardt wrote:
> This is simpler implementation-wise (it avoids an almost-always-false
> check in read_packet and decreases sizeof(MatroskaTrack) by about 2/3)
> and makes the side-data available directly after read_header.
> 
> It also fixes the Matroska analog of ticket #10602: If a Matroska track
> has a palette, said palette will be attached as side-data to the
> first packet of said track and most likely, this is one read during
> avformat_find_stream_info(). Yet if this packet is discarded because
> of a seek performed immediately after avformat_find_stream_info(),
> the information about the global palette will never reach the user.
> 
> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
> ---
> Ticket #10602 can unfortunately not be fixed in this way,
> because avi allows to update the palette mid-stream,
> so that the palette contained in extradata must not be
> exported via global side data due to the semantics of the latter.
> 
>  libavformat/matroskadec.c | 39 ++++++++++++---------------------------
>  1 file changed, 12 insertions(+), 27 deletions(-)

breaks:
aletrek.mkv

probably here:
https://trac.ffmpeg.org/attachment/ticket/5071/aletrek.mkv

thx

[...]
Andreas Rheinhardt Oct. 8, 2023, 7:06 p.m. UTC | #2
Michael Niedermayer:
> On Thu, Oct 05, 2023 at 02:36:52PM +0200, Andreas Rheinhardt wrote:
>> This is simpler implementation-wise (it avoids an almost-always-false
>> check in read_packet and decreases sizeof(MatroskaTrack) by about 2/3)
>> and makes the side-data available directly after read_header.
>>
>> It also fixes the Matroska analog of ticket #10602: If a Matroska track
>> has a palette, said palette will be attached as side-data to the
>> first packet of said track and most likely, this is one read during
>> avformat_find_stream_info(). Yet if this packet is discarded because
>> of a seek performed immediately after avformat_find_stream_info(),
>> the information about the global palette will never reach the user.
>>
>> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
>> ---
>> Ticket #10602 can unfortunately not be fixed in this way,
>> because avi allows to update the palette mid-stream,
>> so that the palette contained in extradata must not be
>> exported via global side data due to the semantics of the latter.
>>
>>  libavformat/matroskadec.c | 39 ++++++++++++---------------------------
>>  1 file changed, 12 insertions(+), 27 deletions(-)
> 
> breaks:
> aletrek.mkv
> 
> probably here:
> https://trac.ffmpeg.org/attachment/ticket/5071/aletrek.mkv
> 

This is actually expected due to the recent changes with respect to side
data: Basically every piece of code currently only looks for palette
side data in packets, not in stream side data and if the latter is not
injected into packets, then it is available, but unused. This is the
reason I opposed deprecating avformat_inject_global_side_data(); see my
reply to James latest iteration of his patchset.

- Andreas
diff mbox series

Patch

diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index 941c0bcdc9..74f3fc7ae7 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -285,9 +285,6 @@  typedef struct MatroskaTrack {
     int needs_decoding;
     uint64_t max_block_additional_id;
     EbmlList block_addition_mappings;
-
-    uint32_t palette[AVPALETTE_COUNT];
-    int has_palette;
 } MatroskaTrack;
 
 typedef struct MatroskaAttachment {
@@ -2852,7 +2849,8 @@  static int mka_parse_audio(MatroskaTrack *track, AVStream *st,
 }
 
 /* Performs the codec-specific part of parsing a video track. */
-static int mkv_parse_video_codec(MatroskaTrack *track, AVCodecParameters *par,
+static int mkv_parse_video_codec(AVStream *st, MatroskaTrack *track,
+                                 AVCodecParameters *par,
                                  const MatroskaDemuxContext *matroska,
                                  int *extradata_offset)
 {
@@ -2886,11 +2884,15 @@  static int mkv_parse_video_codec(MatroskaTrack *track, AVCodecParameters *par,
         if (track->codec_priv.size >= 86) {
             FFIOContext b;
             unsigned bit_depth = AV_RB16(track->codec_priv.data + 82);
+            uint32_t palette[256] = { 0 };
             ffio_init_read_context(&b, track->codec_priv.data,
                                    track->codec_priv.size);
-            if (ff_get_qtpalette(codec_id, &b.pub, track->palette)) {
+            if (ff_get_qtpalette(codec_id, &b.pub, palette)) {
+                void *side_data = av_stream_new_side_data(st, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
+                if (!side_data)
+                    return AVERROR(ENOMEM);
+                memcpy(side_data, palette, AVPALETTE_SIZE);
                 bit_depth         &= 0x1F;
-                track->has_palette = 1;
             }
             par->bits_per_coded_sample = bit_depth;
         }
@@ -2934,7 +2936,7 @@  static int mkv_parse_video(MatroskaTrack *track, AVStream *st,
     if (track->video.color_space.size == 4)
         par->codec_tag = AV_RL32(track->video.color_space.data);
 
-    ret = mkv_parse_video_codec(track, par, matroska,
+    ret = mkv_parse_video_codec(st, track, par, matroska,
                                 extradata_offset);
     if (ret < 0)
         return ret;
@@ -3398,30 +3400,13 @@  static int matroska_read_header(AVFormatContext *s)
 
 /*
  * Put one packet in an application-supplied AVPacket struct.
- * Returns 0 on success or -1 on failure.
+ * Returns 0 on success or < 0 (most likely AVERROR(EAGAIN)
+ * if no packet was available.
  */
 static int matroska_deliver_packet(MatroskaDemuxContext *matroska,
                                    AVPacket *pkt)
 {
-    if (matroska->queue.head) {
-        MatroskaTrack *tracks = matroska->tracks.elem;
-        MatroskaTrack *track;
-
-        avpriv_packet_list_get(&matroska->queue, pkt);
-        track = &tracks[pkt->stream_index];
-        if (track->has_palette) {
-            uint8_t *pal = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
-            if (!pal) {
-                av_log(matroska->ctx, AV_LOG_ERROR, "Cannot append palette to packet\n");
-            } else {
-                memcpy(pal, track->palette, AVPALETTE_SIZE);
-            }
-            track->has_palette = 0;
-        }
-        return 0;
-    }
-
-    return -1;
+    return avpriv_packet_list_get(&matroska->queue, pkt);
 }
 
 /*