diff mbox series

[FFmpeg-devel,17/17] avformat/avc: Don't discard SPS extensions for some profiles

Message ID 20200709192022.9412-9-andreas.rheinhardt@gmail.com
State New
Headers show
Series [FFmpeg-devel,1/7] avformat/avc: Fix undefined shift and assert when reading exp-golomb num | expand

Checks

Context Check Description
andriy/default pending
andriy/make success Make finished
andriy/make_fate success Make fate finished

Commit Message

Andreas Rheinhardt July 9, 2020, 7:20 p.m. UTC
For some profiles, the AVCDecoderConfigurationRecord contains an array
containing all the SPS Extension NAL units; for the other profiles,
these NAL units should be put into the SPS array. Yet the latter hasn't
been done. This commit implements it.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
---
Honestly, I have no sample containing an SPS extension, so this is
untested.
Btw: The spec is quiet on the order in the SPS array in this case.
Should it be all SPS first, then the extensions or should the it be that
an SPS is immediately followed by its extension (if present) followed by
the next SPS? All it says is that they should be placed in the SPS
array.

 libavformat/avc.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)
diff mbox series

Patch

diff --git a/libavformat/avc.c b/libavformat/avc.c
index 0f43b295a4..84a55fdc98 100644
--- a/libavformat/avc.c
+++ b/libavformat/avc.c
@@ -185,13 +185,13 @@  static void write_array(AVIOContext *pb, const uint8_t *const *ps,
 int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
 {
     const uint8_t *nal, *nal_end, *end;
-    int ret, nb_sps = 0, nb_pps = 0, nb_sps_ext = 0;
-    const uint8_t *sps[H264_MAX_SPS_COUNT];
+    int ret, nb_sps = 0, nb_pps = 0, nb_sps_ext = 0, ext_in_sps_array;
+    const uint8_t *sps[2 * H264_MAX_SPS_COUNT];
     const uint8_t *pps[H264_MAX_PPS_COUNT];
-    const uint8_t *sps_ext[H264_MAX_SPS_COUNT];
-    uint16_t sps_sizes[H264_MAX_SPS_COUNT]     = { 0 };
+    uint16_t sps_sizes[2 * H264_MAX_SPS_COUNT] = { 0 };
     uint16_t pps_sizes[H264_MAX_PPS_COUNT]     = { 0 };
-    uint16_t sps_ext_sizes[H264_MAX_SPS_COUNT] = { 0 };
+    const uint8_t **const sps_ext = &sps[H264_MAX_SPS_COUNT];
+    uint16_t *const sps_ext_sizes = &sps_sizes[H264_MAX_SPS_COUNT];
     H264SPS seq;
 
     if (len <= 6)
@@ -249,8 +249,14 @@  int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
         }
     }
 
-    if (!nb_sps || nb_sps == H264_MAX_SPS_COUNT ||
-        !nb_pps || nb_pps == H264_MAX_PPS_COUNT)
+    if (!nb_sps || !nb_pps)
+        return AVERROR_INVALIDDATA;
+    ext_in_sps_array = seq.profile_idc == 66 ||
+                       seq.profile_idc == 77 ||
+                       seq.profile_idc == 88;
+    if (ext_in_sps_array)
+        nb_sps += nb_sps_ext;
+    if (nb_sps >= H264_MAX_SPS_COUNT || nb_pps >= H264_MAX_PPS_COUNT)
         return AVERROR_INVALIDDATA;
 
     avio_w8(pb, 1); /* version */
@@ -258,10 +264,11 @@  int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
     avio_w8(pb, seq.constraint_set_flags); /* profile compat */
     avio_w8(pb, seq.level_idc);
     avio_w8(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */
-    write_array(pb, sps, sps_sizes, nb_sps, H264_MAX_SPS_COUNT, 0xe0);
+    write_array(pb, sps, sps_sizes, nb_sps,
+                H264_MAX_SPS_COUNT * (1 + ext_in_sps_array), 0xe0);
     write_array(pb, pps, pps_sizes, nb_pps, H264_MAX_PPS_COUNT, 0x00);
 
-    if (seq.profile_idc != 66 && seq.profile_idc != 77 && seq.profile_idc != 88) {
+    if (!ext_in_sps_array) {
         avio_w8(pb, 0xfc |  seq.chroma_format_idc); /* 6 bits reserved (111111) + chroma_format_idc */
         avio_w8(pb, 0xf8 | seq.bit_depth_luma_minus8); /* 5 bits reserved (11111) + bit_depth_luma_minus8 */
         avio_w8(pb, 0xf8 | seq.bit_depth_chroma_minus8); /* 5 bits reserved (11111) + bit_depth_chroma_minus8 */