Skip to content

Commit

Permalink
Merge pull request #1720 from CastagnaIT/codec_extradata_move
Browse files Browse the repository at this point in the history
Moved extradata conversions to more appropriate places
  • Loading branch information
CastagnaIT authored Nov 7, 2024
2 parents 9d7d90a + 4fb1388 commit ea39649
Show file tree
Hide file tree
Showing 14 changed files with 237 additions and 143 deletions.
19 changes: 1 addition & 18 deletions src/Session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -701,24 +701,7 @@ void SESSION::CSession::UpdateStream(CStream& stream)
stream.m_info.SetExtraData(nullptr, 0);

if (!rep->GetCodecPrivateData().empty())
{
std::vector<uint8_t> annexb;
const std::vector<uint8_t>* extraData(&annexb);

const DRM::DecrypterCapabilites& caps{GetDecrypterCaps(rep->m_psshSetPos)};

if ((caps.flags & DRM::DecrypterCapabilites::SSD_ANNEXB_REQUIRED) &&
stream.m_info.GetStreamType() == INPUTSTREAM_TYPE_VIDEO)
{
LOG::Log(LOGDEBUG, "UpdateStream: Convert avc -> annexb");
annexb = AvcToAnnexb(rep->GetCodecPrivateData());
}
else
{
extraData = &rep->GetCodecPrivateData();
}
stream.m_info.SetExtraData(extraData->data(), extraData->size());
}
stream.m_info.SetExtraData(rep->GetCodecPrivateData());

stream.m_info.SetCodecFourCC(0);
stream.m_info.SetBitRate(rep->GetBandwidth());
Expand Down
78 changes: 55 additions & 23 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)
AVCCodecHandler::AVCCodecHandler(AP4_SampleDescription* sd, bool isRequiredAnnexB)
: CodecHandler{sd},
m_countPictureSetIds{0},
m_needSliceInfo{false},
Expand All @@ -29,8 +29,16 @@ AVCCodecHandler::AVCCodecHandler(AP4_SampleDescription* sd)
if (AP4_AvcSampleDescription* avcSampleDescription =
AP4_DYNAMIC_CAST(AP4_AvcSampleDescription, m_sampleDescription))
{
m_extraData.SetData(avcSampleDescription->GetRawBytes().GetData(),
avcSampleDescription->GetRawBytes().GetDataSize());
if (isRequiredAnnexB)
{
ExtraDataToAnnexB();
}
else
{
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 @@ -61,6 +69,26 @@ AVCCodecHandler::AVCCodecHandler(AP4_SampleDescription* sd)
}
}

bool AVCCodecHandler::CheckExtraData(std::vector<uint8_t>& extraData, bool isRequiredAnnexB)
{
if (extraData.empty())
return false;

// Make sure that extradata is in the required format
if (isRequiredAnnexB && !UTILS::IsAnnexB(extraData))
{
extraData = UTILS::AvcToAnnexb(extraData);
return true;
}
if (!isRequiredAnnexB && UTILS::IsAnnexB(extraData))
{
extraData = UTILS::AnnexbToAvc(extraData);
return true;
}

return false;
}

bool AVCCodecHandler::ExtraDataToAnnexB()
{
if (AP4_AvcSampleDescription* avcSampleDescription =
Expand All @@ -75,29 +103,33 @@ bool AVCCodecHandler::ExtraDataToAnnexB()
for (unsigned int i{0}; i < sps.ItemCount(); ++i)
sz += 4 + sps[i].GetDataSize();

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)
if (sz > 0)
{
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;
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 true;
}

return false;
}

Expand Down
54 changes: 28 additions & 26 deletions src/codechandler/AVCCodecHandler.h
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
/*
* Copyright (C) 2022 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
* See LICENSES/README.md for more information.
*/

#pragma once

#include "CodecHandler.h"

class ATTR_DLL_LOCAL AVCCodecHandler : public CodecHandler
{
public:
AVCCodecHandler(AP4_SampleDescription* sd);
bool ExtraDataToAnnexB() override;
void UpdatePPSId(const AP4_DataBuffer& buffer) override;
bool GetInformation(kodi::addon::InputstreamInfo& info) override;
STREAMCODEC_PROFILE GetProfile() override { return m_codecProfile; };

private:
unsigned int m_countPictureSetIds;
STREAMCODEC_PROFILE m_codecProfile;
bool m_needSliceInfo;
};
/*
* Copyright (C) 2022 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
* See LICENSES/README.md for more information.
*/

#pragma once

#include "CodecHandler.h"

class ATTR_DLL_LOCAL AVCCodecHandler : public CodecHandler
{
public:
AVCCodecHandler(AP4_SampleDescription* sd, bool isRequiredAnnexB);

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; };

private:
unsigned int m_countPictureSetIds;
STREAMCODEC_PROFILE m_codecProfile;
bool m_needSliceInfo;
};
10 changes: 10 additions & 0 deletions src/codechandler/CodecHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ class ATTR_DLL_LOCAL CodecHandler
*/
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
* \param isRequiredAnnexB If the extradata must be in annex b format
* \return True if data is changed, otherwise false
*/
virtual bool CheckExtraData(std::vector<uint8_t>& extraData, bool isRequiredAnnexB)
{
return false;
}
virtual STREAMCODEC_PROFILE GetProfile() { return STREAMCODEC_PROFILE::CodecProfileNotNeeded; };
virtual bool Transform(AP4_UI64 pts, AP4_UI32 duration, AP4_DataBuffer& buf, AP4_UI64 timescale)
{
Expand Down
35 changes: 32 additions & 3 deletions src/codechandler/HEVCCodecHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,46 @@

using namespace UTILS;

HEVCCodecHandler::HEVCCodecHandler(AP4_SampleDescription* sd) : CodecHandler(sd)
HEVCCodecHandler::HEVCCodecHandler(AP4_SampleDescription* sd, bool isRequiredAnnexB)
: CodecHandler(sd)
{
if (AP4_HevcSampleDescription* hevcSampleDescription =
AP4_DYNAMIC_CAST(AP4_HevcSampleDescription, m_sampleDescription))
{
m_extraData.SetData(hevcSampleDescription->GetRawBytes().GetData(),
hevcSampleDescription->GetRawBytes().GetDataSize());
if (isRequiredAnnexB)
{
ExtraDataToAnnexB();
}
else
{
m_extraData.SetData(hevcSampleDescription->GetRawBytes().GetData(),
hevcSampleDescription->GetRawBytes().GetDataSize());
}
m_naluLengthSize = hevcSampleDescription->GetNaluLengthSize();
}
}

bool HEVCCodecHandler::CheckExtraData(std::vector<uint8_t>& extraData, bool isRequiredAnnexB)
{
if (extraData.empty())
return false;

// 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;
}
if (!isRequiredAnnexB && UTILS::IsAnnexB(extraData))
{
extraData = UTILS::AnnexbToHvcc(extraData);
return true;
}

return false;
}

bool HEVCCodecHandler::ExtraDataToAnnexB()
{
if (AP4_HevcSampleDescription* hevcSampleDescription =
Expand Down
3 changes: 2 additions & 1 deletion src/codechandler/HEVCCodecHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@
class ATTR_DLL_LOCAL HEVCCodecHandler : public CodecHandler
{
public:
HEVCCodecHandler(AP4_SampleDescription* sd);
HEVCCodecHandler(AP4_SampleDescription* sd, bool isRequiredAnnexB);

bool CheckExtraData(std::vector<uint8_t>& extraData, bool isRequiredAnnexB) override;
bool ExtraDataToAnnexB() override;
bool GetInformation(kodi::addon::InputstreamInfo& info) override;
};
17 changes: 16 additions & 1 deletion src/common/AdaptiveUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,23 +77,35 @@ AP4_Movie* PLAYLIST::CreateMovieAtom(adaptive::AdaptiveStream& adStream,
kodi::addon::InputstreamInfo& streamInfo)
{
CRepresentation* repr = adStream.getRepresentation();
const std::vector<uint8_t>& extradata = repr->GetCodecPrivateData();
std::vector<uint8_t> extradata = repr->GetCodecPrivateData();
const std::string codecName = streamInfo.GetCodecName();
AP4_SampleDescription* sampleDesc;

if (codecName == CODEC::NAME_H264)
{
if (UTILS::IsAnnexB(extradata))
extradata = UTILS::AnnexbToAvc(extradata);

AP4_MemoryByteStream ms{extradata.data(), static_cast<const AP4_Size>(extradata.size())};
AP4_AvccAtom* atom =
AP4_AvccAtom::Create(static_cast<AP4_Size>(AP4_ATOM_HEADER_SIZE + extradata.size()), ms);
if (!atom)
LOG::LogF(LOGWARNING, "Unable to create AVCC atom, possible malformed extradata");

sampleDesc = new AP4_AvcSampleDescription(AP4_SAMPLE_FORMAT_AVC1, streamInfo.GetWidth(),
streamInfo.GetHeight(), 0, nullptr, atom);
}
else if (codecName == CODEC::NAME_HEVC)
{
if (UTILS::IsAnnexB(extradata))
extradata = UTILS::AnnexbToHvcc(extradata);

AP4_MemoryByteStream ms{extradata.data(), static_cast<const AP4_Size>(extradata.size())};
AP4_HvccAtom* atom =
AP4_HvccAtom::Create(static_cast<AP4_Size>(AP4_ATOM_HEADER_SIZE + extradata.size()), ms);
if (!atom)
LOG::LogF(LOGWARNING, "Unable to create HVCC atom, possible malformed extradata");

sampleDesc = new AP4_HevcSampleDescription(AP4_SAMPLE_FORMAT_HEV1, streamInfo.GetWidth(),
streamInfo.GetHeight(), 0, nullptr, atom);
}
Expand All @@ -102,6 +114,9 @@ AP4_Movie* PLAYLIST::CreateMovieAtom(adaptive::AdaptiveStream& adStream,
AP4_MemoryByteStream ms{extradata.data(), static_cast<const AP4_Size>(extradata.size())};
AP4_Av1cAtom* atom =
AP4_Av1cAtom::Create(static_cast<AP4_Size>(AP4_ATOM_HEADER_SIZE + extradata.size()), ms);
if (!atom)
LOG::LogF(LOGWARNING, "Unable to create AV1C atom, possible malformed extradata");

sampleDesc = new AP4_Av1SampleDescription(AP4_SAMPLE_FORMAT_AV01, streamInfo.GetWidth(),
streamInfo.GetHeight(), 0, nullptr, atom);
}
Expand Down
7 changes: 5 additions & 2 deletions src/parser/DASHTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -747,8 +747,11 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr,

// ISA custom attribute
// No dash spec, looks like a custom Amazon video service implementation
repr->SetCodecPrivateData(
UTILS::AnnexbToAvc(XML::GetAttrib(nodeRepr, "codecPrivateData").data()));
std::string codecPrivateData;
if (XML::QueryAttrib(nodeRepr, "codecPrivateData", codecPrivateData))
{
repr->SetCodecPrivateData(STRING::HexToBytes(codecPrivateData));
}

// ISA custom attribute
repr->SetSampleRate(XML::GetAttribUint32(nodeRepr, "audioSamplingRate"));
Expand Down
9 changes: 1 addition & 8 deletions src/parser/SmoothTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,14 +323,7 @@ void adaptive::CSmoothTree::ParseTagQualityLevel(pugi::xml_node nodeQI,
std::string codecPrivateData;
if (XML::QueryAttrib(nodeQI, "CodecPrivateData", codecPrivateData))
{
const auto& codecs = repr->GetCodecs();
if (CODEC::Contains(codecs, CODEC::FOURCC_HEVC) ||
CODEC::Contains(codecs, CODEC::FOURCC_HEV1) || CODEC::Contains(codecs, CODEC::FOURCC_HVC1))
{
repr->SetCodecPrivateData(AnnexbToHvcc(codecPrivateData.c_str()));
}
else
repr->SetCodecPrivateData(AnnexbToAvc(codecPrivateData.c_str()));
repr->SetCodecPrivateData(STRING::HexToBytes(codecPrivateData));
}

if (CODEC::Contains(repr->GetCodecs(), CODEC::FOURCC_AACL) && repr->GetCodecPrivateData().empty())
Expand Down
Loading

0 comments on commit ea39649

Please sign in to comment.