From 5106cc0bee61724b573ccbe37c629d0450963027 Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Wed, 13 Nov 2024 08:48:07 +0100 Subject: [PATCH 1/2] [Utils] Add HvccToAnnexb method --- src/utils/Utils.cpp | 58 ++++++++++++++++++++++++++++++++++++++++++++- src/utils/Utils.h | 1 + 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/utils/Utils.cpp b/src/utils/Utils.cpp index 6c97a7c46..65034d93e 100644 --- a/src/utils/Utils.cpp +++ b/src/utils/Utils.cpp @@ -11,7 +11,6 @@ #include "Base64Utils.h" #include "StringUtils.h" #include "log.h" -#include "kodi/tools/StringUtils.h" #include // any_of #include @@ -21,6 +20,63 @@ using namespace UTILS; using namespace kodi::tools; +std::vector UTILS::HvccToAnnexb(const std::vector& hvcc) +{ + if (hvcc.size() < 23) + { + LOG::LogF(LOGERROR, "Cannot convert HVCC data, wrong data size"); + return {}; + } + + std::vector result; + const uint8_t* data = hvcc.data() + 22; // Start after length field + const uint8_t* end = hvcc.data() + hvcc.size(); + uint8_t numSequences = *data++; + + for (uint8_t i = 0; i < numSequences; ++i) + { + if (data + 2 > end) + { + LOG::LogF(LOGERROR, "Cannot convert HVCC data, wrong data size"); + return {}; + } + + uint8_t nalType = (*data++ << 1); + uint16_t numNals = (data[0] << 8) | data[1]; + data += 2; + + for (uint16_t j = 0; j < numNals; ++j) + { + if (data + 2 > end) + { + LOG::LogF(LOGERROR, "Cannot convert HVCC data, wrong data size"); + return {}; + } + + uint16_t nalSize = (data[0] << 8) | data[1]; + data += 2; + + if (data + nalSize > end) + { + LOG::LogF(LOGERROR, "Cannot convert HVCC data, wrong data size"); + return {}; + } + + // Add Annex B start code + result.emplace_back(0x00); + result.emplace_back(0x00); + result.emplace_back(0x00); + result.emplace_back(0x01); + + // Copy NAL data + result.insert(result.end(), data, data + nalSize); + data += nalSize; + } + } + + return result; +} + std::vector UTILS::AnnexbToHvcc(const std::vector& annexb) { std::vector result; diff --git a/src/utils/Utils.h b/src/utils/Utils.h index 0cb995c72..af35ff75a 100644 --- a/src/utils/Utils.h +++ b/src/utils/Utils.h @@ -22,6 +22,7 @@ constexpr uint8_t DEFAULT_KEYID[16]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Placeholder for unknown AP4_Track id constexpr uint32_t AP4_TRACK_ID_UNKNOWN = -1; +std::vector HvccToAnnexb(const std::vector& hvcc); std::vector AnnexbToHvcc(const std::vector& annexb); std::vector AnnexbToAvc(const std::vector& annexb); bool IsAnnexB(const std::vector& data); From 8d253017200bd6aa7c3a3b5d33d8db4c8119c48f Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Tue, 12 Nov 2024 18:30:42 +0100 Subject: [PATCH 2/2] [codechandler] Removed ExtraDataToAnnexB and cleanups --- src/codechandler/AVCCodecHandler.cpp | 58 +----------------- src/codechandler/AVCCodecHandler.h | 3 +- src/codechandler/CodecHandler.h | 2 +- src/codechandler/HEVCCodecHandler.cpp | 65 ++------------------- src/codechandler/HEVCCodecHandler.h | 3 +- src/samplereader/FragmentedSampleReader.cpp | 27 ++++++--- 6 files changed, 30 insertions(+), 128 deletions(-) diff --git a/src/codechandler/AVCCodecHandler.cpp b/src/codechandler/AVCCodecHandler.cpp index a40f4a990..bdef5e73d 100644 --- a/src/codechandler/AVCCodecHandler.cpp +++ b/src/codechandler/AVCCodecHandler.cpp @@ -12,7 +12,7 @@ using namespace UTILS; -AVCCodecHandler::AVCCodecHandler(AP4_SampleDescription* sd, bool isRequiredAnnexB) +AVCCodecHandler::AVCCodecHandler(AP4_SampleDescription* sd) : CodecHandler{sd}, m_countPictureSetIds{0}, m_needSliceInfo{false}, @@ -29,16 +29,8 @@ AVCCodecHandler::AVCCodecHandler(AP4_SampleDescription* sd, bool isRequiredAnnex if (AP4_AvcSampleDescription* avcSampleDescription = AP4_DYNAMIC_CAST(AP4_AvcSampleDescription, m_sampleDescription)) { - if (isRequiredAnnexB) - { - ExtraDataToAnnexB(); - } - else - { - m_extraData.SetData(avcSampleDescription->GetRawBytes().GetData(), - avcSampleDescription->GetRawBytes().GetDataSize()); - } - + m_extraData.SetData(avcSampleDescription->GetRawBytes().GetData(), + avcSampleDescription->GetRawBytes().GetDataSize()); m_countPictureSetIds = avcSampleDescription->GetPictureParameters().ItemCount(); m_naluLengthSize = avcSampleDescription->GetNaluLengthSize(); m_needSliceInfo = (m_countPictureSetIds > 1 || width == 0 || height == 0); @@ -89,50 +81,6 @@ bool AVCCodecHandler::CheckExtraData(std::vector& extraData, bool isReq return false; } -bool AVCCodecHandler::ExtraDataToAnnexB() -{ - if (AP4_AvcSampleDescription* avcSampleDescription = - AP4_DYNAMIC_CAST(AP4_AvcSampleDescription, m_sampleDescription)) - { - //calculate the size for annexb - AP4_Size sz(0); - AP4_Array& pps(avcSampleDescription->GetPictureParameters()); - for (unsigned int i{0}; i < pps.ItemCount(); ++i) - sz += 4 + pps[i].GetDataSize(); - AP4_Array& sps(avcSampleDescription->GetSequenceParameters()); - for (unsigned int i{0}; i < sps.ItemCount(); ++i) - sz += 4 + sps[i].GetDataSize(); - - if (sz > 0) - { - m_extraData.SetDataSize(sz); - AP4_Byte* cursor(m_extraData.UseData()); - - for (unsigned int i{0}; i < sps.ItemCount(); ++i) - { - cursor[0] = 0; - cursor[1] = 0; - cursor[2] = 0; - cursor[3] = 1; - memcpy(cursor + 4, sps[i].GetData(), sps[i].GetDataSize()); - cursor += sps[i].GetDataSize() + 4; - } - for (unsigned int i{0}; i < pps.ItemCount(); ++i) - { - cursor[0] = 0; - cursor[1] = 0; - cursor[2] = 0; - cursor[3] = 1; - memcpy(cursor + 4, pps[i].GetData(), pps[i].GetDataSize()); - cursor += pps[i].GetDataSize() + 4; - } - return true; - } - } - - return false; -} - void AVCCodecHandler::UpdatePPSId(const AP4_DataBuffer& buffer) { if (!m_needSliceInfo) diff --git a/src/codechandler/AVCCodecHandler.h b/src/codechandler/AVCCodecHandler.h index 337cebd9f..6b350b359 100644 --- a/src/codechandler/AVCCodecHandler.h +++ b/src/codechandler/AVCCodecHandler.h @@ -13,10 +13,9 @@ class ATTR_DLL_LOCAL AVCCodecHandler : public CodecHandler { public: - AVCCodecHandler(AP4_SampleDescription* sd, bool isRequiredAnnexB); + AVCCodecHandler(AP4_SampleDescription* sd); bool CheckExtraData(std::vector& extraData, bool isRequiredAnnexB) override; - bool ExtraDataToAnnexB() override; void UpdatePPSId(const AP4_DataBuffer& buffer) override; bool GetInformation(kodi::addon::InputstreamInfo& info) override; STREAMCODEC_PROFILE GetProfile() override { return m_codecProfile; }; diff --git a/src/codechandler/CodecHandler.h b/src/codechandler/CodecHandler.h index 6ba39c5b7..30f00631b 100644 --- a/src/codechandler/CodecHandler.h +++ b/src/codechandler/CodecHandler.h @@ -33,7 +33,7 @@ class ATTR_DLL_LOCAL CodecHandler * \return True if some info is changed, otherwise false */ virtual bool GetInformation(kodi::addon::InputstreamInfo& info); - virtual bool ExtraDataToAnnexB() { return false; }; + /*! * \brief Check for extradata data format, if needed it will be converted * \param extraData The data diff --git a/src/codechandler/HEVCCodecHandler.cpp b/src/codechandler/HEVCCodecHandler.cpp index aff633791..ca1942d7d 100644 --- a/src/codechandler/HEVCCodecHandler.cpp +++ b/src/codechandler/HEVCCodecHandler.cpp @@ -13,21 +13,13 @@ using namespace UTILS; -HEVCCodecHandler::HEVCCodecHandler(AP4_SampleDescription* sd, bool isRequiredAnnexB) - : CodecHandler(sd) +HEVCCodecHandler::HEVCCodecHandler(AP4_SampleDescription* sd) : CodecHandler(sd) { if (AP4_HevcSampleDescription* hevcSampleDescription = AP4_DYNAMIC_CAST(AP4_HevcSampleDescription, m_sampleDescription)) { - if (isRequiredAnnexB) - { - ExtraDataToAnnexB(); - } - else - { - m_extraData.SetData(hevcSampleDescription->GetRawBytes().GetData(), - hevcSampleDescription->GetRawBytes().GetDataSize()); - } + m_extraData.SetData(hevcSampleDescription->GetRawBytes().GetData(), + hevcSampleDescription->GetRawBytes().GetDataSize()); m_naluLengthSize = hevcSampleDescription->GetNaluLengthSize(); } } @@ -40,9 +32,8 @@ bool HEVCCodecHandler::CheckExtraData(std::vector& extraData, bool isRe // Make sure that extradata is in the required format if (isRequiredAnnexB && !UTILS::IsAnnexB(extraData)) { - //! @todo: this was never implemented on the older ISA versions - LOG::LogF(LOGDEBUG, "Required extradata annex b format, data conversion not implemented"); - return false; + extraData = UTILS::HvccToAnnexb(extraData); + return true; } if (!isRequiredAnnexB && UTILS::IsAnnexB(extraData)) { @@ -53,52 +44,6 @@ bool HEVCCodecHandler::CheckExtraData(std::vector& extraData, bool isRe return false; } -bool HEVCCodecHandler::ExtraDataToAnnexB() -{ - if (AP4_HevcSampleDescription* hevcSampleDescription = - AP4_DYNAMIC_CAST(AP4_HevcSampleDescription, m_sampleDescription)) - { - const AP4_Array& sequences = hevcSampleDescription->GetSequences(); - - if (sequences.ItemCount() == 0) - { - LOG::LogF(LOGWARNING, "No available sequences for HEVC codec extra data"); - return false; - } - - //calculate the size for annexb - AP4_Size size{0}; - for (unsigned int i{0}; i < sequences.ItemCount(); ++i) - { - for (unsigned int j{0}; j < sequences[i].m_Nalus.ItemCount(); ++j) - { - size += sequences[i].m_Nalus[j].GetDataSize() + 4; - } - } - - m_extraData.SetDataSize(size); - uint8_t* cursor(m_extraData.UseData()); - - for (unsigned int i{0}; i < sequences.ItemCount(); ++i) - { - for (unsigned int j{0}; j < sequences[i].m_Nalus.ItemCount(); ++j) - { - cursor[0] = 0; - cursor[1] = 0; - cursor[2] = 0; - cursor[3] = 1; - memcpy(cursor + 4, sequences[i].m_Nalus[j].GetData(), - sequences[i].m_Nalus[j].GetDataSize()); - cursor += sequences[i].m_Nalus[j].GetDataSize() + 4; - } - } - LOG::LogF(LOGDEBUG, "Converted %lu bytes HEVC codec extradata", m_extraData.GetDataSize()); - return true; - } - LOG::LogF(LOGWARNING, "No HevcSampleDescription - annexb extradata not available"); - return false; -} - bool HEVCCodecHandler::GetInformation(kodi::addon::InputstreamInfo& info) { bool isChanged = UpdateInfoCodecName(info, CODEC::FOURCC_HEVC); diff --git a/src/codechandler/HEVCCodecHandler.h b/src/codechandler/HEVCCodecHandler.h index e4186afac..73cd002c7 100644 --- a/src/codechandler/HEVCCodecHandler.h +++ b/src/codechandler/HEVCCodecHandler.h @@ -13,9 +13,8 @@ class ATTR_DLL_LOCAL HEVCCodecHandler : public CodecHandler { public: - HEVCCodecHandler(AP4_SampleDescription* sd, bool isRequiredAnnexB); + HEVCCodecHandler(AP4_SampleDescription* sd); bool CheckExtraData(std::vector& extraData, bool isRequiredAnnexB) override; - bool ExtraDataToAnnexB() override; bool GetInformation(kodi::addon::InputstreamInfo& info) override; }; diff --git a/src/samplereader/FragmentedSampleReader.cpp b/src/samplereader/FragmentedSampleReader.cpp index 60d432910..a8fafcb97 100644 --- a/src/samplereader/FragmentedSampleReader.cpp +++ b/src/samplereader/FragmentedSampleReader.cpp @@ -94,6 +94,9 @@ bool CFragmentedSampleReader::Initialize(SESSION::CStream* stream) break; } + // Create codec handler and get extradata + UpdateSampleDescription(); + return true; } @@ -107,9 +110,6 @@ void CFragmentedSampleReader::SetDecrypter(std::shared_ptrm_extraData.GetDataSize() && !info.CompareExtraData(m_codecHandler->m_extraData.GetData(), @@ -361,6 +363,18 @@ AP4_Result CFragmentedSampleReader::ProcessMoof(AP4_ContainerAtom* moof, { m_sampleDescIndex = tfhd->GetSampleDescriptionIndex(); UpdateSampleDescription(); + + //! @todo: mix of types AP4_DataBuffer vs std::vector + //! bento4 AP4_DataBuffer is not really needed, to change it required also decrypters cleanups + AP4_DataBuffer& chExtradata = m_codecHandler->m_extraData; + std::vector extradata(chExtradata.GetData(), + chExtradata.GetData() + chExtradata.GetDataSize()); + if (m_codecHandler->CheckExtraData( + extradata, + (m_decrypterCaps.flags & DRM::DecrypterCapabilites::SSD_ANNEXB_REQUIRED) != 0)) + { + m_codecHandler->m_extraData.SetData(extradata.data(), extradata.size()); + } } //Correct PTS @@ -496,22 +510,19 @@ void CFragmentedSampleReader::UpdateSampleDescription() } else { - const bool isRequiredAnnexB = - (m_decrypterCaps.flags & DRM::DecrypterCapabilites::SSD_ANNEXB_REQUIRED) != 0; - switch (desc->GetFormat()) { case AP4_SAMPLE_FORMAT_AVC1: case AP4_SAMPLE_FORMAT_AVC2: case AP4_SAMPLE_FORMAT_AVC3: case AP4_SAMPLE_FORMAT_AVC4: - m_codecHandler = new AVCCodecHandler(desc, isRequiredAnnexB); + m_codecHandler = new AVCCodecHandler(desc); break; case AP4_SAMPLE_FORMAT_HEV1: case AP4_SAMPLE_FORMAT_HVC1: case AP4_SAMPLE_FORMAT_DVHE: case AP4_SAMPLE_FORMAT_DVH1: - m_codecHandler = new HEVCCodecHandler(desc, isRequiredAnnexB); + m_codecHandler = new HEVCCodecHandler(desc); break; case AP4_SAMPLE_FORMAT_STPP: m_codecHandler = new TTMLCodecHandler(desc, false);