Skip to content

Commit

Permalink
Merge pull request #1728 from CastagnaIT/mp4_extradata
Browse files Browse the repository at this point in the history
[codechandler] Removed ExtraDataToAnnexB and cleanups
  • Loading branch information
CastagnaIT authored Nov 15, 2024
2 parents a1a28e0 + 8d25301 commit ea8d8b8
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 129 deletions.
58 changes: 3 additions & 55 deletions src/codechandler/AVCCodecHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand All @@ -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);
Expand Down Expand Up @@ -89,50 +81,6 @@ bool AVCCodecHandler::CheckExtraData(std::vector<uint8_t>& 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<AP4_DataBuffer>& pps(avcSampleDescription->GetPictureParameters());
for (unsigned int i{0}; i < pps.ItemCount(); ++i)
sz += 4 + pps[i].GetDataSize();
AP4_Array<AP4_DataBuffer>& 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)
Expand Down
3 changes: 1 addition & 2 deletions src/codechandler/AVCCodecHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint8_t>& 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; };
Expand Down
2 changes: 1 addition & 1 deletion src/codechandler/CodecHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
65 changes: 5 additions & 60 deletions src/codechandler/HEVCCodecHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
Expand All @@ -40,9 +32,8 @@ bool HEVCCodecHandler::CheckExtraData(std::vector<uint8_t>& 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))
{
Expand All @@ -53,52 +44,6 @@ bool HEVCCodecHandler::CheckExtraData(std::vector<uint8_t>& extraData, bool isRe
return false;
}

bool HEVCCodecHandler::ExtraDataToAnnexB()
{
if (AP4_HevcSampleDescription* hevcSampleDescription =
AP4_DYNAMIC_CAST(AP4_HevcSampleDescription, m_sampleDescription))
{
const AP4_Array<AP4_HvccAtom::Sequence>& 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);
Expand Down
3 changes: 1 addition & 2 deletions src/codechandler/HEVCCodecHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint8_t>& extraData, bool isRequiredAnnexB) override;
bool ExtraDataToAnnexB() override;
bool GetInformation(kodi::addon::InputstreamInfo& info) override;
};
27 changes: 19 additions & 8 deletions src/samplereader/FragmentedSampleReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ bool CFragmentedSampleReader::Initialize(SESSION::CStream* stream)
break;
}

// Create codec handler and get extradata
UpdateSampleDescription();

return true;
}

Expand All @@ -107,9 +110,6 @@ void CFragmentedSampleReader::SetDecrypter(std::shared_ptr<Adaptive_CencSingleSa
}

m_decrypterCaps = dcaps;

// We need this to fill extradata
UpdateSampleDescription();
}

AP4_Result CFragmentedSampleReader::Start(bool& bStarted)
Expand Down Expand Up @@ -239,6 +239,8 @@ bool CFragmentedSampleReader::GetInformation(kodi::addon::InputstreamInfo& info)
if (!m_codecHandler)
return false;

// Note: when a manifest provides extradata, it will already be set to InputstreamInfo

bool isChanged{false};
if (m_bSampleDescChanged && m_codecHandler->m_extraData.GetDataSize() &&
!info.CompareExtraData(m_codecHandler->m_extraData.GetData(),
Expand Down Expand Up @@ -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<uint8_t>
//! bento4 AP4_DataBuffer is not really needed, to change it required also decrypters cleanups
AP4_DataBuffer& chExtradata = m_codecHandler->m_extraData;
std::vector<uint8_t> 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
Expand Down Expand Up @@ -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);
Expand Down
58 changes: 57 additions & 1 deletion src/utils/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
#include "Base64Utils.h"
#include "StringUtils.h"
#include "log.h"
#include "kodi/tools/StringUtils.h"

#include <algorithm> // any_of
#include <chrono>
Expand All @@ -21,6 +20,63 @@
using namespace UTILS;
using namespace kodi::tools;

std::vector<uint8_t> UTILS::HvccToAnnexb(const std::vector<uint8_t>& hvcc)
{
if (hvcc.size() < 23)
{
LOG::LogF(LOGERROR, "Cannot convert HVCC data, wrong data size");
return {};
}

std::vector<uint8_t> 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<uint8_t> UTILS::AnnexbToHvcc(const std::vector<uint8_t>& annexb)
{
std::vector<uint8_t> result;
Expand Down
1 change: 1 addition & 0 deletions src/utils/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint8_t> HvccToAnnexb(const std::vector<uint8_t>& hvcc);
std::vector<uint8_t> AnnexbToHvcc(const std::vector<uint8_t>& annexb);
std::vector<uint8_t> AnnexbToAvc(const std::vector<uint8_t>& annexb);
bool IsAnnexB(const std::vector<uint8_t>& data);
Expand Down

0 comments on commit ea8d8b8

Please sign in to comment.