-
Notifications
You must be signed in to change notification settings - Fork 242
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #892 from glennguy/codechandler-refactor
Codechandler refactor
- Loading branch information
Showing
18 changed files
with
752 additions
and
568 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
}; |
Oops, something went wrong.