Skip to content

Commit

Permalink
Merge pull request #892 from glennguy/codechandler-refactor
Browse files Browse the repository at this point in the history
Codechandler refactor
  • Loading branch information
glennguy authored Feb 6, 2022
2 parents 1cd943c + 994002a commit dc500f5
Show file tree
Hide file tree
Showing 18 changed files with 752 additions and 568 deletions.
18 changes: 16 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,19 @@ find_package(Kodi REQUIRED)

set(ADP_SOURCES
src/main.cpp
src/codechandler/AVCCodecHandler.cpp
src/codechandler/CodecHandler.cpp
src/codechandler/HEVCCodecHandler.cpp
src/codechandler/MPEGCodecHandler.cpp
src/codechandler/TTMLCodecHandler.cpp
src/codechandler/VP9CodecHandler.cpp
src/codechandler/WebVTTCodecHandler.cpp
src/codechandler/ttml/TTML.cpp
src/common/AdaptiveTree.cpp
src/common/RepresentationChooser.cpp
src/parser/DASHTree.cpp
src/parser/HLSTree.cpp
src/parser/SmoothTree.cpp
src/parser/TTML.cpp
src/parser/PRProtectionParser.cpp
src/common/AdaptiveStream.cpp
src/helpers.cpp
Expand All @@ -30,13 +37,20 @@ set(ADP_HEADERS
src/main.h
src/oscompat.h
src/SSD_dll.h
src/codechandler/AVCCodecHandler.h
src/codechandler/CodecHandler.h
src/codechandler/HEVCCodecHandler.h
src/codechandler/MPEGCodecHandler.h
src/codechandler/TTMLCodecHandler.h
src/codechandler/VP9CodecHandler.h
src/codechandler/WebVTTCodecHandler.h
src/codechandler/ttml/TTML.h
src/common/AdaptiveStream.h
src/common/AdaptiveTree.h
src/common/RepresentationChooser.h
src/parser/DASHTree.h
src/parser/HLSTree.h
src/parser/SmoothTree.h
src/parser/TTML.h
src/parser/PRProtectionParser.h
src/TSReader.h
src/log.h
Expand Down
217 changes: 217 additions & 0 deletions src/codechandler/AVCCodecHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
/*
* 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.
*/

#include "AVCCodecHandler.h"

AVCCodecHandler::AVCCodecHandler(AP4_SampleDescription* sd)
: CodecHandler{sd},
m_countPictureSetIds{0},
m_needSliceInfo{false},
m_codecProfile{STREAMCODEC_PROFILE::CodecProfileUnknown}
{
AP4_UI16 height{0};
AP4_UI16 width{0};
if (AP4_VideoSampleDescription* videoSampleDescription =
AP4_DYNAMIC_CAST(AP4_VideoSampleDescription, m_sampleDescription))
{
width = videoSampleDescription->GetWidth();
height = videoSampleDescription->GetHeight();
}
if (AP4_AvcSampleDescription* avcSampleDescription =
AP4_DYNAMIC_CAST(AP4_AvcSampleDescription, m_sampleDescription))
{
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);
switch (avcSampleDescription->GetProfile())
{
case AP4_AVC_PROFILE_BASELINE:
m_codecProfile = STREAMCODEC_PROFILE::H264CodecProfileBaseline;
break;
case AP4_AVC_PROFILE_MAIN:
m_codecProfile = STREAMCODEC_PROFILE::H264CodecProfileMain;
break;
case AP4_AVC_PROFILE_EXTENDED:
m_codecProfile = STREAMCODEC_PROFILE::H264CodecProfileExtended;
break;
case AP4_AVC_PROFILE_HIGH:
m_codecProfile = STREAMCODEC_PROFILE::H264CodecProfileHigh;
break;
case AP4_AVC_PROFILE_HIGH_10:
m_codecProfile = STREAMCODEC_PROFILE::H264CodecProfileHigh10;
break;
case AP4_AVC_PROFILE_HIGH_422:
m_codecProfile = STREAMCODEC_PROFILE::H264CodecProfileHigh422;
break;
case AP4_AVC_PROFILE_HIGH_444:
m_codecProfile = STREAMCODEC_PROFILE::H264CodecProfileHigh444Predictive;
break;
}
}
}

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();

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(AP4_DataBuffer const& buffer)
{
if (!m_needSliceInfo)
return;

//Search the Slice header NALU
const AP4_Byte* data(buffer.GetData());
AP4_Size dataSize(buffer.GetDataSize());
for (; dataSize;)
{
// sanity check
if (dataSize < m_naluLengthSize)
break;

// get the next NAL unit
AP4_UI32 naluSize;
switch (m_naluLengthSize)
{
case 1:
naluSize = *data++;
dataSize--;
break;
case 2:
naluSize = AP4_BytesToUInt16BE(data);
data += 2;
dataSize -= 2;
break;
case 4:
naluSize = AP4_BytesToUInt32BE(data);
data += 4;
dataSize -= 4;
break;
default:
dataSize = 0;
naluSize = 1;
break;
}
if (naluSize > dataSize)
break;

// Stop further NALU processing
if (m_countPictureSetIds < 2)
m_needSliceInfo = false;

unsigned int nal_unit_type = *data & 0x1F;

if (
//nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_NON_IDR_PICTURE ||
nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_IDR_PICTURE //||
//nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_A ||
//nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_B ||
//nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_C
)
{
AP4_DataBuffer unescaped(data, dataSize);
AP4_NalParser::Unescape(unescaped);
AP4_BitReader bits(unescaped.GetData(), unescaped.GetDataSize());

bits.SkipBits(8); // NAL Unit Type

AP4_AvcFrameParser::ReadGolomb(bits); // first_mb_in_slice
AP4_AvcFrameParser::ReadGolomb(bits); // slice_type
m_pictureId = AP4_AvcFrameParser::ReadGolomb(bits); //picture_set_id
}
// move to the next NAL unit
data += naluSize;
dataSize -= naluSize;
}
}

bool AVCCodecHandler::GetInformation(kodi::addon::InputstreamInfo& info)
{
if (m_pictureId == m_pictureIdPrev)
return false;
m_pictureIdPrev = m_pictureId;

if (AP4_AvcSampleDescription* avcSampleDescription =
AP4_DYNAMIC_CAST(AP4_AvcSampleDescription, m_sampleDescription))
{
AP4_Array<AP4_DataBuffer>& ppsList(avcSampleDescription->GetPictureParameters());
AP4_AvcPictureParameterSet pps;
for (unsigned int i(0); i < ppsList.ItemCount(); ++i)
{
AP4_AvcFrameParser fp;
if (AP4_SUCCEEDED(fp.ParsePPS(ppsList[i].GetData(), ppsList[i].GetDataSize(), pps)) &&
pps.pic_parameter_set_id == m_pictureId)
{
AP4_Array<AP4_DataBuffer>& spsList = avcSampleDescription->GetSequenceParameters();
AP4_AvcSequenceParameterSet sps;
for (unsigned int i{0}; i < spsList.ItemCount(); ++i)
{
if (AP4_SUCCEEDED(fp.ParseSPS(spsList[i].GetData(), spsList[i].GetDataSize(), sps)) &&
sps.seq_parameter_set_id == pps.seq_parameter_set_id)
{
unsigned int width = info.GetWidth();
unsigned int height = info.GetHeight();
unsigned int fps_ticks = info.GetFpsRate();
unsigned int fps_scale = info.GetFpsScale();
float aspect = info.GetAspect();
bool ret = sps.GetInfo(width, height);
ret = sps.GetVUIInfo(fps_ticks, fps_scale, aspect) || ret;
if (ret)
{
info.SetWidth(width);
info.SetHeight(height);
info.SetFpsRate(fps_ticks);
info.SetFpsScale(fps_scale);
info.SetAspect(aspect);
}
return ret;
}
}
break;
}
}
}
return false;
};
24 changes: 24 additions & 0 deletions src/codechandler/AVCCodecHandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* 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.
*/

#include "CodecHandler.h"

class ATTR_DLL_LOCAL AVCCodecHandler : public CodecHandler
{
public:
AVCCodecHandler(AP4_SampleDescription* sd);
bool ExtraDataToAnnexB() override;
void UpdatePPSId(AP4_DataBuffer const& 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;
};
63 changes: 63 additions & 0 deletions src/codechandler/CodecHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* 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.
*/

#include "CodecHandler.h"

namespace
{
constexpr const char* NETFLIX_FRAMERATE_UUID = "NetflixFrameRate";
}

bool CodecHandler::GetInformation(kodi::addon::InputstreamInfo& info)
{
AP4_GenericAudioSampleDescription* audioSampleDescription(nullptr);
if (m_sampleDescription)
{
if ((audioSampleDescription =
dynamic_cast<AP4_GenericAudioSampleDescription*>(m_sampleDescription)))
{
if ((info.GetChannels() == 0 &&
audioSampleDescription->GetChannelCount() != info.GetChannels()) ||
(info.GetSampleRate() == 0 &&
audioSampleDescription->GetSampleRate() != info.GetSampleRate()) ||
(info.GetBitsPerSample() == 0 &&
audioSampleDescription->GetSampleSize() != info.GetBitsPerSample()))
{
if (info.GetChannels() == 0)
info.SetChannels(audioSampleDescription->GetChannelCount());
if (info.GetSampleRate() == 0)
info.SetSampleRate(audioSampleDescription->GetSampleRate());
if (info.GetBitsPerSample() == 0)
info.SetBitsPerSample(audioSampleDescription->GetSampleSize());
return true;
}
}
else
{
//Netflix Framerate
AP4_Atom* atom;
AP4_UnknownUuidAtom* nxfr;
atom = m_sampleDescription->GetDetails().GetChild(
reinterpret_cast<const AP4_UI08*>(NETFLIX_FRAMERATE_UUID));
if (atom && (nxfr = dynamic_cast<AP4_UnknownUuidAtom*>(atom)) &&
nxfr->GetData().GetDataSize() == 10)
{
unsigned int fpsRate = nxfr->GetData().GetData()[7] | nxfr->GetData().GetData()[6] << 8;
unsigned int fpsScale = nxfr->GetData().GetData()[9] | nxfr->GetData().GetData()[8] << 8;

if (info.GetFpsScale() != fpsScale || info.GetFpsRate() != fpsRate)
{
info.SetFpsScale(fpsScale);
info.SetFpsRate(fpsRate);
return true;
}
}
}
}
return false;
};
40 changes: 40 additions & 0 deletions src/codechandler/CodecHandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* 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 <bento4/Ap4.h>
#include <kodi/AddonBase.h>
#include <kodi/addon-instance/Inputstream.h>

class ATTR_DLL_LOCAL CodecHandler
{
public:
CodecHandler(AP4_SampleDescription* sd)
: m_sampleDescription(sd), m_naluLengthSize(0), m_pictureId(0), m_pictureIdPrev(0xFF){};
virtual ~CodecHandler(){};

virtual void UpdatePPSId(AP4_DataBuffer const&){};
virtual bool GetInformation(kodi::addon::InputstreamInfo& info);
virtual bool ExtraDataToAnnexB() { 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)
{
return false;
};
virtual bool ReadNextSample(AP4_Sample& sample, AP4_DataBuffer& buf) { return false; };
virtual void SetPTSOffset(AP4_UI64 offset){};
virtual bool TimeSeek(AP4_UI64 seekPos) { return true; };
virtual void Reset(){};

AP4_SampleDescription* m_sampleDescription;
AP4_DataBuffer m_extraData;
AP4_UI08 m_naluLengthSize;
AP4_UI08 m_pictureId;
AP4_UI08 m_pictureIdPrev;
};
Loading

0 comments on commit dc500f5

Please sign in to comment.