From caa47e374d4b04262196ec27c338098982211068 Mon Sep 17 00:00:00 2001 From: koln67 <67125539+koln67@users.noreply.github.com> Date: Thu, 6 Aug 2020 00:08:53 +0000 Subject: [PATCH] Properly handle AVC profiles with SPS extension Part of #755 to improve DASH spec compliance. --- .../output.mpd | 14 ++-- .../bear-640x360-ac3-video-iframe.m3u8 | 8 +-- .../bear-640x360-ac3-video.m3u8 | 4 +- .../bear-640x360-ac3-video.mp4 | Bin 301709 -> 301713 bytes .../hls-only-dash-only-captions/output.mpd | 24 +++---- .../output.mpd | 20 +++--- .../avc_decoder_configuration_record.cc | 24 +++++++ .../codecs/avc_decoder_configuration_record.h | 9 +++ ...c_decoder_configuration_record_unittest.cc | 48 +++++++++++++ .../h264_byte_to_unit_stream_converter.cc | 56 +++++++++++++-- .../h264_byte_to_unit_stream_converter.h | 1 + ..._byte_to_unit_stream_converter_unittest.cc | 59 +++++++++++++++ .../nal_unit_to_byte_stream_converter.cc | 5 ++ ..._unit_to_byte_stream_converter_unittest.cc | 68 ++++++++++++++++++ .../media/codecs/video_slice_header_parser.cc | 3 +- 15 files changed, 301 insertions(+), 42 deletions(-) diff --git a/packager/app/test/testdata/audio-video-with-codec-switching/output.mpd b/packager/app/test/testdata/audio-video-with-codec-switching/output.mpd index 2aadb124ea..5a7630776d 100644 --- a/packager/app/test/testdata/audio-video-with-codec-switching/output.mpd +++ b/packager/app/test/testdata/audio-video-with-codec-switching/output.mpd @@ -15,18 +15,18 @@ - - bear-640x360-video.mp4 - - - - - + bear-1280x720-video.mp4 + + bear-640x360-video.mp4 + + + + diff --git a/packager/app/test/testdata/avc-ac3-ts-to-mp4/bear-640x360-ac3-video-iframe.m3u8 b/packager/app/test/testdata/avc-ac3-ts-to-mp4/bear-640x360-ac3-video-iframe.m3u8 index 751f42ff59..7a72360de2 100644 --- a/packager/app/test/testdata/avc-ac3-ts-to-mp4/bear-640x360-ac3-video-iframe.m3u8 +++ b/packager/app/test/testdata/avc-ac3-ts-to-mp4/bear-640x360-ac3-video-iframe.m3u8 @@ -4,14 +4,14 @@ #EXT-X-TARGETDURATION:2 #EXT-X-PLAYLIST-TYPE:VOD #EXT-X-I-FRAMES-ONLY -#EXT-X-MAP:URI="bear-640x360-ac3-video.mp4",BYTERANGE="859@0" +#EXT-X-MAP:URI="bear-640x360-ac3-video.mp4",BYTERANGE="863@0" #EXTINF:1.001, -#EXT-X-BYTERANGE:15581@927 +#EXT-X-BYTERANGE:15581@931 bear-640x360-ac3-video.mp4 #EXTINF:1.001, -#EXT-X-BYTERANGE:18221@100240 +#EXT-X-BYTERANGE:18221@100244 bear-640x360-ac3-video.mp4 #EXTINF:0.734, -#EXT-X-BYTERANGE:19663@222047 +#EXT-X-BYTERANGE:19663@222051 bear-640x360-ac3-video.mp4 #EXT-X-ENDLIST diff --git a/packager/app/test/testdata/avc-ac3-ts-to-mp4/bear-640x360-ac3-video.m3u8 b/packager/app/test/testdata/avc-ac3-ts-to-mp4/bear-640x360-ac3-video.m3u8 index 0ba1c17eaf..0faccfd182 100644 --- a/packager/app/test/testdata/avc-ac3-ts-to-mp4/bear-640x360-ac3-video.m3u8 +++ b/packager/app/test/testdata/avc-ac3-ts-to-mp4/bear-640x360-ac3-video.m3u8 @@ -3,9 +3,9 @@ ## Generated with https://github.com/google/shaka-packager version -- #EXT-X-TARGETDURATION:2 #EXT-X-PLAYLIST-TYPE:VOD -#EXT-X-MAP:URI="bear-640x360-ac3-video.mp4",BYTERANGE="859@0" +#EXT-X-MAP:URI="bear-640x360-ac3-video.mp4",BYTERANGE="863@0" #EXTINF:1.001, -#EXT-X-BYTERANGE:99313@927 +#EXT-X-BYTERANGE:99313@931 bear-640x360-ac3-video.mp4 #EXTINF:1.001, #EXT-X-BYTERANGE:121807 diff --git a/packager/app/test/testdata/avc-ac3-ts-to-mp4/bear-640x360-ac3-video.mp4 b/packager/app/test/testdata/avc-ac3-ts-to-mp4/bear-640x360-ac3-video.mp4 index f3c1337bde8b25c87df929a7e80dda9c00c82b88..97ad3c1e4327289ae279140d82000e1eb5c3f755 100644 GIT binary patch delta 93 zcmeC(Dl~Dc&;)fx>xmkF8CfT*F(xzCPVQn1Vbqv>pHW-#MR7?|4g&+joZ^z=6d(-( pj6mEoS(z!6(QI-hlOD_8A3qqHmov35XJQ0m5Y4=OITOpX=>R$(----> - - - - - - - - - - - - + + @@ -22,6 +12,16 @@ + + + + + + + + + + diff --git a/packager/app/test/testdata/live-profile-and-encryption-and-mult-files/output.mpd b/packager/app/test/testdata/live-profile-and-encryption-and-mult-files/output.mpd index 565aaabd30..a233a9be50 100644 --- a/packager/app/test/testdata/live-profile-and-encryption-and-mult-files/output.mpd +++ b/packager/app/test/testdata/live-profile-and-encryption-and-mult-files/output.mpd @@ -7,8 +7,8 @@ AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA== - - + + @@ -23,8 +23,8 @@ - - + + @@ -37,13 +37,13 @@ AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA== - + - + - + @@ -57,13 +57,13 @@ - + - + - + diff --git a/packager/media/codecs/avc_decoder_configuration_record.cc b/packager/media/codecs/avc_decoder_configuration_record.cc index d7463629a9..d6022c2a3f 100644 --- a/packager/media/codecs/avc_decoder_configuration_record.cc +++ b/packager/media/codecs/avc_decoder_configuration_record.cc @@ -82,6 +82,30 @@ bool AVCDecoderConfigurationRecord::ParseInternal() { AddNalu(nalu); } + if (profile_indication_ == 100 || profile_indication_ == 110 || + profile_indication_ == 122 || profile_indication_ == 144) { + + uint8_t sps_ext_count; + if (!reader.Read1(&chroma_format_) || !reader.Read1(&bit_depth_luma_minus8_) || + !reader.Read1(&bit_depth_chroma_minus8_) || !reader.Read1(&sps_ext_count)) { + LOG(WARNING) << "Insufficient bits in bitstream for given AVC profile"; + return true; + } + chroma_format_ &= 0x3; + bit_depth_luma_minus8_ &= 0x7; + bit_depth_chroma_minus8_ &= 0x7; + for (uint8_t i = 0; i < sps_ext_count; i++) { + uint16_t size = 0; + RCHECK(reader.Read2(&size)); + const uint8_t* nalu_data = reader.data() + reader.pos(); + RCHECK(reader.SkipBytes(size)); + + Nalu nalu; + RCHECK(nalu.Initialize(Nalu::kH264, nalu_data, size)); + RCHECK(nalu.type() == Nalu::H264_SPSExtension); + AddNalu(nalu); + } + } return true; } diff --git a/packager/media/codecs/avc_decoder_configuration_record.h b/packager/media/codecs/avc_decoder_configuration_record.h index 2924cbedde..2959d4664c 100644 --- a/packager/media/codecs/avc_decoder_configuration_record.h +++ b/packager/media/codecs/avc_decoder_configuration_record.h @@ -35,6 +35,9 @@ class AVCDecoderConfigurationRecord : public DecoderConfigurationRecord { uint32_t coded_height() const { return coded_height_; } uint32_t pixel_width() const { return pixel_width_; } uint32_t pixel_height() const { return pixel_height_; } + uint8_t chroma_format() const { return chroma_format_; } + uint8_t bit_depth_luma_minus8() const { return bit_depth_luma_minus8_; } + uint8_t bit_depth_chroma_minus8() const { return bit_depth_chroma_minus8_; } /// Static version of GetCodecString. /// @return The codec string. @@ -56,6 +59,12 @@ class AVCDecoderConfigurationRecord : public DecoderConfigurationRecord { uint32_t coded_height_ = 0; uint32_t pixel_width_ = 0; uint32_t pixel_height_ = 0; + + // Only should be present for special case profile values. + // Refer to ISO/IEC 14496-15 Section 5.3.3.1.1. + uint8_t chroma_format_ = 0; + uint8_t bit_depth_luma_minus8_ = 0; + uint8_t bit_depth_chroma_minus8_ = 0; DISALLOW_COPY_AND_ASSIGN(AVCDecoderConfigurationRecord); }; diff --git a/packager/media/codecs/avc_decoder_configuration_record_unittest.cc b/packager/media/codecs/avc_decoder_configuration_record_unittest.cc index b3027d1eb7..0e74fea301 100644 --- a/packager/media/codecs/avc_decoder_configuration_record_unittest.cc +++ b/packager/media/codecs/avc_decoder_configuration_record_unittest.cc @@ -45,11 +45,59 @@ TEST(AVCDecoderConfigurationRecordTest, Success) { EXPECT_EQ(8u, avc_config.pixel_width()); EXPECT_EQ(9u, avc_config.pixel_height()); EXPECT_EQ(0u, avc_config.transfer_characteristics()); + EXPECT_EQ(0u, avc_config.chroma_format()); + EXPECT_EQ(0u, avc_config.bit_depth_luma_minus8()); + EXPECT_EQ(0u, avc_config.bit_depth_chroma_minus8()); EXPECT_EQ("avc1.64001e", avc_config.GetCodecString(FOURCC_avc1)); EXPECT_EQ("avc3.64001e", avc_config.GetCodecString(FOURCC_avc3)); } +TEST(AVCDecoderConfigurationRecordTest, SuccessWithSPSExtension) { + // clang-format off + const uint8_t kAvcDecoderConfigurationData[] = { + 0x01, // version + 0x64, // profile_indication + 0x00, // profile_compatibility + 0x1E, // avc_level + 0xFF, // Least significant 3 bits is length_size_minus_one + 0xE1, // Least significant 5 bits is num_sps + // sps 1 + 0x00, 0x1D, // size + 0x67, 0x64, 0x00, 0x1E, 0xAC, 0xD9, 0x40, 0xB4, 0x2F, 0xF9, 0x7F, 0xF0, + 0x00, 0x80, 0x00, 0x91, 0x00, 0x00, 0x03, 0x03, 0xE9, 0x00, 0x00, 0xEA, + 0x60, 0x0F, 0x16, 0x2D, 0x96, + 0x01, // num_pps + 0x00, 0x06, // size + 0x68, 0xEB, 0xE3, 0xCB, 0x22, 0xC0, + 0xFC, // Least significant 2 bits is chroma_format + 0xF9, // Least significant 3 bits is bit_depth_luma_minus8 + 0xFF, // Least significant 3 bits is bit_depth_chroma_minus8 + 0x01, // num_sps_ext + 0x00, 0x05, // size + 0x6D, 0x33, 0x01, 0x57, 0x78 + }; + // clang-format on + + AVCDecoderConfigurationRecord avc_config; + ASSERT_TRUE(avc_config.Parse(kAvcDecoderConfigurationData, + arraysize(kAvcDecoderConfigurationData))); + + EXPECT_EQ(1u, avc_config.version()); + EXPECT_EQ(0x64, avc_config.profile_indication()); + EXPECT_EQ(0u, avc_config.profile_compatibility()); + EXPECT_EQ(0x1E, avc_config.avc_level()); + EXPECT_EQ(4u, avc_config.nalu_length_size()); + EXPECT_EQ(720u, avc_config.coded_width()); + EXPECT_EQ(360u, avc_config.coded_height()); + EXPECT_EQ(8u, avc_config.pixel_width()); + EXPECT_EQ(9u, avc_config.pixel_height()); + EXPECT_EQ(0u, avc_config.transfer_characteristics()); + EXPECT_EQ(0u, avc_config.chroma_format()); + EXPECT_EQ(1u, avc_config.bit_depth_luma_minus8()); + EXPECT_EQ(7u, avc_config.bit_depth_chroma_minus8()); +} + TEST(AVCDecoderConfigurationRecordTest, SuccessWithTransferCharacteristics) { // clang-format off const uint8_t kAvcDecoderConfigurationData[] = { diff --git a/packager/media/codecs/h264_byte_to_unit_stream_converter.cc b/packager/media/codecs/h264_byte_to_unit_stream_converter.cc index cdf54928b1..b1e41cdf85 100644 --- a/packager/media/codecs/h264_byte_to_unit_stream_converter.cc +++ b/packager/media/codecs/h264_byte_to_unit_stream_converter.cc @@ -15,6 +15,21 @@ namespace shaka { namespace media { +namespace { +// utility helper function to get an sps +const H264Sps* ParseSpsFromBytes(const std::vector sps, + H264Parser* parser) { + Nalu nalu; + if (!nalu.Initialize(Nalu::kH264, sps.data(), sps.size())) + return nullptr; + + int sps_id = 0; + if (parser->ParseSps(nalu, &sps_id) != H264Parser::kOk) + return nullptr; + return parser->GetSps(sps_id); +} +} // namespace + H264ByteToUnitStreamConverter::H264ByteToUnitStreamConverter() : H26xByteToUnitStreamConverter(Nalu::kH264) {} @@ -27,15 +42,14 @@ H264ByteToUnitStreamConverter::~H264ByteToUnitStreamConverter() {} bool H264ByteToUnitStreamConverter::GetDecoderConfigurationRecord( std::vector* decoder_config) const { DCHECK(decoder_config); - if ((last_sps_.size() < 4) || last_pps_.empty()) { // No data available to construct AVCDecoderConfigurationRecord. return false; } - - // Construct an AVCDecoderConfigurationRecord containing a single SPS and a - // single PPS NALU. Please refer to ISO/IEC 14496-15 for format specifics. - BufferWriter buffer(last_sps_.size() + last_pps_.size() + 11); + // Construct an AVCDecoderConfigurationRecord containing a single SPS, a + // single PPS, and if available, a single SPS Extension NALU. + // Please refer to ISO/IEC 14496-15 for format specifics. + BufferWriter buffer; uint8_t version(1); buffer.AppendInt(version); buffer.AppendInt(last_sps_[1]); @@ -51,6 +65,32 @@ bool H264ByteToUnitStreamConverter::GetDecoderConfigurationRecord( buffer.AppendInt(num_pps); buffer.AppendInt(static_cast(last_pps_.size())); buffer.AppendVector(last_pps_); + // handle profile special cases, refer to ISO/IEC 14496-15 Section 5.3.3.1.2 + uint8_t profile_indication = last_sps_[1]; + if (profile_indication == 100 || profile_indication == 110 || + profile_indication == 122 || profile_indication == 144) { + + H264Parser parser; + const H264Sps* sps = ParseSpsFromBytes(last_sps_, &parser); + if (sps == nullptr) + return false; + + uint8_t reserved_chroma_format = 0xfc | (sps->chroma_format_idc); + buffer.AppendInt(reserved_chroma_format); + uint8_t reserved_bit_depth_luma_minus8 = 0xf8 | sps->bit_depth_luma_minus8; + buffer.AppendInt(reserved_bit_depth_luma_minus8); + uint8_t reserved_bit_depth_chroma_minus8 = 0xf8 | sps->bit_depth_chroma_minus8; + buffer.AppendInt(reserved_bit_depth_chroma_minus8); + + if (last_sps_ext_.empty()) { + uint8_t num_sps_ext(0); + buffer.AppendInt(num_sps_ext); + } else { + uint8_t num_sps_ext(1); + buffer.AppendInt(num_sps_ext); + buffer.AppendVector(last_sps_ext_); + } + } buffer.SwapBuffer(decoder_config); return true; @@ -70,6 +110,12 @@ bool H264ByteToUnitStreamConverter::ProcessNalu(const Nalu& nalu) { // Grab SPS NALU. last_sps_.assign(nalu_ptr, nalu_ptr + nalu_size); return strip_parameter_set_nalus(); + case Nalu::H264_SPSExtension: + if (strip_parameter_set_nalus()) + WarnIfNotMatch(nalu.type(), nalu_ptr, nalu_size, last_sps_ext_); + // Grab SPSExtension NALU. + last_sps_ext_.assign(nalu_ptr, nalu_ptr + nalu_size); + return strip_parameter_set_nalus(); case Nalu::H264_PPS: if (strip_parameter_set_nalus()) WarnIfNotMatch(nalu.type(), nalu_ptr, nalu_size, last_pps_); diff --git a/packager/media/codecs/h264_byte_to_unit_stream_converter.h b/packager/media/codecs/h264_byte_to_unit_stream_converter.h index ad3523434a..cab8a1b2d7 100644 --- a/packager/media/codecs/h264_byte_to_unit_stream_converter.h +++ b/packager/media/codecs/h264_byte_to_unit_stream_converter.h @@ -42,6 +42,7 @@ class H264ByteToUnitStreamConverter : public H26xByteToUnitStreamConverter { std::vector last_sps_; std::vector last_pps_; + std::vector last_sps_ext_; DISALLOW_COPY_AND_ASSIGN(H264ByteToUnitStreamConverter); }; diff --git a/packager/media/codecs/h264_byte_to_unit_stream_converter_unittest.cc b/packager/media/codecs/h264_byte_to_unit_stream_converter_unittest.cc index 5fcfeb324d..f1e61bf407 100644 --- a/packager/media/codecs/h264_byte_to_unit_stream_converter_unittest.cc +++ b/packager/media/codecs/h264_byte_to_unit_stream_converter_unittest.cc @@ -79,5 +79,64 @@ TEST(H264ByteToUnitStreamConverter, ConversionFailure) { EXPECT_FALSE(converter.GetDecoderConfigurationRecord(&decoder_config)); } +TEST(H264ByteToUnitStreamConverter, NaluConversionWithSpsExtension) { + const uint8_t kByteStreamWithSpsExtension[] = { + 0x00, 0x00, 0x00, 0x01, // Start code + 0x09, // AUD Type + 0xF0, // Primary pic type + 0x00, 0x00, 0x00, 0x01, // Start code + // Some SPS Data + 0x67, 0x64, 0x00, 0x1E, 0xAC, 0xD9, 0x40, 0xB4, 0x2F, + 0xF9, 0x7F, 0xF0, 0x00, 0x80, 0x00, 0x91, 0x00, 0x00, + 0x03, 0x03, 0xE9, 0x00, 0x00, 0xEA, 0x60, 0x0F, 0x16, + 0x2D, 0x96, + 0x00, 0x00, 0x00, 0x01, // Start code + // Some PPS Data + 0x68, 0xFE, 0xFD, 0xFC, 0xFB, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x00, 0x00, 0x00, 0x01, // Start code + // Some SPS Extension data + 0x6D, 0x33, 0x01, 0x57, 0x78, + 0x00, 0x00, 0x00, 0x01, // Start code + // The input NALU + 0x06, // NALU type + 0xFD, 0x78, 0xA4, 0xC3, 0x82, 0x62, 0x11, 0x29, 0x77, + }; + std::vector byte_stream_with_sps_extension( + std::begin(kByteStreamWithSpsExtension), + std::end(kByteStreamWithSpsExtension)); + + H264ByteToUnitStreamConverter converter( + H26xStreamFormat::kNalUnitStreamWithoutParameterSetNalus); + + std::vector unit_stream; + ASSERT_TRUE(converter.ConvertByteStreamToNalUnitStream( + byte_stream_with_sps_extension.data(), + byte_stream_with_sps_extension.size(), &unit_stream)); + + const uint8_t kExpectedUnitStream[] = { + 0x00, 0x00, 0x00, 0x0A, 0x06, 0xFD, 0x78, + 0xA4, 0xC3, 0x82, 0x62, 0x11, 0x29, 0x77 + }; + EXPECT_EQ(std::vector(std::begin(kExpectedUnitStream), + std::end(kExpectedUnitStream)), unit_stream); + + std::cout << std::endl << std::endl; + std::vector decoder_config; + EXPECT_TRUE(converter.GetDecoderConfigurationRecord(&decoder_config)); + + const uint8_t kExpectedDecoderConfig[] = { + 0x01, 0x64, 0x00, 0x1E, 0xFF, 0xE1, 0x00, 0x1D, + 0x67, 0x64, 0x00, 0x1E, 0xAC, 0xD9, 0x40, 0xB4, + 0x2F, 0xF9, 0x7F, 0xF0, 0x00, 0x80, 0x00, 0x91, + 0x00, 0x00, 0x03, 0x03, 0xE9, 0x00, 0x00, 0xEA, + 0x60, 0x0F, 0x16, 0x2D, 0x96, 0x01, 0x00, 0x0A, + 0x68, 0xFE, 0xFD, 0xFC, 0xFB, 0x11, 0x12, 0x13, + 0x14, 0x15, 0xFD, 0xF8, 0xF8, 0x01, 0x6D, 0x33, + 0x01, 0x57, 0x78 + }; + EXPECT_EQ(std::vector(std::begin(kExpectedDecoderConfig), + std::end(kExpectedDecoderConfig)), decoder_config); +} + } // namespace media } // namespace shaka diff --git a/packager/media/codecs/nal_unit_to_byte_stream_converter.cc b/packager/media/codecs/nal_unit_to_byte_stream_converter.cc index fb2936dce2..bf707658c0 100644 --- a/packager/media/codecs/nal_unit_to_byte_stream_converter.cc +++ b/packager/media/codecs/nal_unit_to_byte_stream_converter.cc @@ -242,6 +242,9 @@ bool NalUnitToByteStreamConverter::Initialize( buffer_writer.AppendArray(kNaluStartCode, arraysize(kNaluStartCode)); AppendNalu(nalu, nalu_length_size_, !kEscapeData, &buffer_writer); found_pps = true; + } else if (nalu.type() == Nalu::H264NaluType::H264_SPSExtension) { + buffer_writer.AppendArray(kNaluStartCode, arraysize(kNaluStartCode)); + AppendNalu(nalu, nalu_length_size_, !kEscapeData, &buffer_writer); } } if (!found_sps || !found_pps) { @@ -313,6 +316,8 @@ bool NalUnitToByteStreamConverter::ConvertUnitToByteStreamWithSubsamples( break; case Nalu::H264_SPS: FALLTHROUGH_INTENDED; + case Nalu::H264_SPSExtension: + FALLTHROUGH_INTENDED; case Nalu::H264_PPS: { // Also write this SPS/PPS if it is not the same as SPS/PPS in decoder // configuration, which is already written. diff --git a/packager/media/codecs/nal_unit_to_byte_stream_converter_unittest.cc b/packager/media/codecs/nal_unit_to_byte_stream_converter_unittest.cc index abed910f5c..4f482d4179 100644 --- a/packager/media/codecs/nal_unit_to_byte_stream_converter_unittest.cc +++ b/packager/media/codecs/nal_unit_to_byte_stream_converter_unittest.cc @@ -201,6 +201,74 @@ TEST(NalUnitToByteStreamConverterTest, ConvertUnitToByteStream) { output); } +// Expect a valid AVCDecoderConfigurationRecord with SPSExtension to pass. +TEST(NalUnitToByteStreamConverterTest, ConvertUnitToByteStreamWithSPSExtension) { + NalUnitToByteStreamConverter converter; + const uint8_t kDecoderConfigWithSpsExt[] = { + 0x01, // configuration version (must be 1) + 0x64, // AVCProfileIndication (100: sps special case) + 0x00, // profile_compatibility (bogus) + 0x00, // AVCLevelIndication (bogus) + 0xFF, // Length size minus 1 == 3 + 0xE1, // 1 sps. + 0x00, 0x1D, // SPS length == 29 + // Some valid SPS data. + 0x67, 0x64, 0x00, 0x1E, 0xAC, 0xD9, 0x40, 0xB4, + 0x2F, 0xF9, 0x7F, 0xF0, 0x00, 0x80, 0x00, 0x91, + 0x00, 0x00, 0x03, 0x03, 0xE9, 0x00, 0x00, 0xEA, + 0x60, 0x0F, 0x16, 0x2D, 0x96, + 0x01, // 1 pps. + 0x00, 0x0A, // PPS length == 10 + 0x68, 0xFE, 0xFD, 0xFC, 0xFB, 0x11, 0x12, 0x13, 0x14, 0x15, + 0xFC, // chroma_format == 0 + 0xF9, // bit_depth_luma_minus8 == 1 + 0xFF, // bit_depth_chroma_minus8 == 7 + 0x01, // 1 SPS Extension + 0x00, 0x05, // SPSExtension length = 5 + 0x6D, 0x33, 0x01, 0x57, 0x78 + }; + + // Only the type of the NAL units are checked. + // This does not contain AUD, SPS, nor PPS. + const uint8_t kUnitStreamLikeMediaSample[] = { + 0x00, 0x00, 0x00, 0x0A, // Size 10 NALU. + 0x06, // NAL unit type. + 0xFD, 0x78, 0xA4, 0xC3, 0x82, 0x62, 0x11, 0x29, 0x77 + }; + + const uint8_t kByteStreamWithSpsExtension[] = { + 0x00, 0x00, 0x00, 0x01, // Start code + 0x09, // AUD Type + 0xF0, // Primary pic type + 0x00, 0x00, 0x00, 0x01, // Start code + // Some SPS Data + 0x67, 0x64, 0x00, 0x1E, 0xAC, 0xD9, 0x40, 0xB4, 0x2F, + 0xF9, 0x7F, 0xF0, 0x00, 0x80, 0x00, 0x91, 0x00, 0x00, + 0x03, 0x03, 0xE9, 0x00, 0x00, 0xEA, 0x60, 0x0F, 0x16, + 0x2D, 0x96, + 0x00, 0x00, 0x00, 0x01, // Start code + // Some PPS Data + 0x68, 0xFE, 0xFD, 0xFC, 0xFB, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x00, 0x00, 0x00, 0x01, // Start code + // Some SPS Extension data + 0x6D, 0x33, 0x01, 0x57, 0x78, + 0x00, 0x00, 0x00, 0x01, // Start code + // The input NALU + 0x06, // NALU type + 0xFD, 0x78, 0xA4, 0xC3, 0x82, 0x62, 0x11, 0x29, 0x77, + }; + EXPECT_TRUE(converter.Initialize(kDecoderConfigWithSpsExt, + arraysize(kDecoderConfigWithSpsExt))); + + std::vector output; + EXPECT_TRUE(converter.ConvertUnitToByteStream( + kUnitStreamLikeMediaSample, + arraysize(kUnitStreamLikeMediaSample), kIsKeyFrame, &output)); + EXPECT_EQ(std::vector(std::begin(kByteStreamWithSpsExtension), + std::end(kByteStreamWithSpsExtension)), + output); +} + // Verify that if it is not a key frame then SPS and PPS from decoder // configuration is not used. TEST(NalUnitToByteStreamConverterTest, NonKeyFrameSample) { diff --git a/packager/media/codecs/video_slice_header_parser.cc b/packager/media/codecs/video_slice_header_parser.cc index 141d6189e1..a829766879 100644 --- a/packager/media/codecs/video_slice_header_parser.cc +++ b/packager/media/codecs/video_slice_header_parser.cc @@ -35,8 +35,7 @@ bool H264VideoSliceHeaderParser::Initialize( const Nalu& nalu = config.nalu(i); if (nalu.type() == Nalu::H264_SPS) { RCHECK(parser_.ParseSps(nalu, &id) == H264Parser::kOk); - } else { - DCHECK_EQ(Nalu::H264_PPS, nalu.type()); + } else if (nalu.type() == Nalu::H264_PPS) { RCHECK(parser_.ParsePps(nalu, &id) == H264Parser::kOk); } }