Merge pull request #451 from jcdr428/VVC

Add VVC Codec
This commit is contained in:
jcdr428 2021-09-05 01:04:39 +01:00 committed by GitHub
commit 3d6e3eec87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 1782 additions and 4 deletions

View File

@ -52,6 +52,8 @@ add_executable (tsmuxer
vc1Parser.cpp
vc1StreamReader.cpp
vod_common.cpp
vvc.cpp
vvcStreamReader.cpp
wave.cpp
)

View File

@ -23,6 +23,7 @@ const static int CODEC_S_PGS = 12;
const static int CODEC_S_SRT = 13;
const static int CODEC_V_MPEG4_H264_DEP = 14;
const static int CODEC_V_MPEG4_H265 = 15;
const static int CODEC_V_MPEG4_H266 = 16;
struct CodecInfo
{
@ -52,6 +53,7 @@ struct CheckStreamRez
bool unused;
};
const static CodecInfo vvcCodecInfo(CODEC_V_MPEG4_H266, "VVC", "V_MPEGI/ISO/VVC");
const static CodecInfo hevcCodecInfo(CODEC_V_MPEG4_H265, "HEVC", "V_MPEGH/ISO/HEVC");
const static CodecInfo h264CodecInfo(CODEC_V_MPEG4_H264, "H.264", "V_MPEG4/ISO/AVC");
const static CodecInfo h264DepCodecInfo(CODEC_V_MPEG4_H264_DEP, "MVC",

View File

@ -4,7 +4,7 @@
#include <array>
#include "hevc.h"
//#include "hevc.h"
#include "iso_writer.h"
#include "muxerManager.h"
#include "psgStreamReader.h"

View File

@ -378,6 +378,7 @@ Supported input containers:
- MPLS (Blu-ray media play list file)
Names of codecs in the meta file:
- V_MPEGI/ISO/VVC H.266/VVC
- V_MPEGH/ISO/HEVC H.265/HEVC
- V_MPEG4/ISO/AVC H.264/AVC
- V_MPEG4/ISO/MVC H.264/MVC

View File

@ -31,6 +31,7 @@
#include "vc1StreamReader.h"
#include "vodCoreException.h"
#include "vod_common.h"
#include "vvcStreamReader.h"
using namespace std;
@ -771,6 +772,11 @@ CheckStreamRez METADemuxer::detectTrackReader(uint8_t* tmpBuffer, int len,
if (rez.codecInfo.codecID)
return rez;
VVCStreamReader vvcCodec;
rez = vvcCodec.checkStream(tmpBuffer, len);
if (rez.codecInfo.codecID)
return rez;
MPEG2StreamReader mpeg2ccodec;
rez = mpeg2ccodec.checkStream(tmpBuffer, len);
if (rez.codecInfo.codecID)
@ -904,6 +910,17 @@ AbstractStreamReader* METADemuxer::createCodec(const string& codecName, const ma
((HEVCStreamReader*)rez)->setFPS(fps);
}
}
else if (codecName == "V_MPEGI/ISO/VVC")
{
rez = new VVCStreamReader();
map<string, string>::const_iterator itr = addParams.find("fps");
if (itr != addParams.end())
{
double fps = strToDouble(itr->second.c_str());
fps = correctFps(fps);
((VVCStreamReader*)rez)->setFPS(fps);
}
}
else if (codecName == "V_MS/VFW/WVC1")
{
rez = new VC1StreamReader();

View File

@ -106,6 +106,10 @@ void SingleFileMuxer::intAddStream(const std::string& streamName, const std::str
{
fileExt = ".hevc";
}
else if (codecName == "V_MPEGI/ISO/VVC")
{
fileExt = ".vvc";
}
else
{
fileExt = ".mpv";

View File

@ -310,6 +310,12 @@ void TSMuxer::intAddStream(const std::string& streamName, const std::string& cod
tsStreamIndex,
PMTStreamInfo(stream_type, tsStreamIndex, descrBuffer, descriptorLen, codecReader, lang, isSecondary)));
}
else if (codecName == "V_MPEGI/ISO/VVC")
{
m_pmt.pidList.insert(
std::make_pair(tsStreamIndex, PMTStreamInfo(STREAM_TYPE_VIDEO_H266, tsStreamIndex, descrBuffer,
descriptorLen, codecReader, lang, isSecondary)));
}
else if (codecName == "V_MS/VFW/WVC1")
m_pmt.pidList.insert(
std::make_pair(tsStreamIndex, PMTStreamInfo(STREAM_TYPE_VIDEO_VC1, tsStreamIndex, descrBuffer,

View File

@ -11,12 +11,13 @@
#include "bitStream.h"
#include "crc32.h"
#include "h264StreamReader.h"
#include "hevc.h"
//#include "hevc.h"
#include "math.h"
#include "mpegStreamReader.h"
#include "simplePacketizerReader.h"
#include "tsMuxer.h"
#include "vodCoreException.h"
//#include "vvc.h"
using namespace std;
@ -29,7 +30,7 @@ bool isVideoStreamType(int stream_coding_type)
{
return stream_coding_type == STREAM_TYPE_VIDEO_MPEG2 || stream_coding_type == STREAM_TYPE_VIDEO_H264 ||
stream_coding_type == STREAM_TYPE_VIDEO_VC1 || stream_coding_type == STREAM_TYPE_VIDEO_MVC ||
stream_coding_type == STREAM_TYPE_VIDEO_H265;
stream_coding_type == STREAM_TYPE_VIDEO_H265 || STREAM_TYPE_VIDEO_H266;
}
bool isAudioStreamType(int stream_coding_type)
@ -2374,7 +2375,8 @@ void MPLSParser::composeSTN_table(BitStreamWriter& writer, int PlayItem_id, bool
}
else
{
LTRACE(LT_ERROR, 2, "Unsupported media type " << stream_coding_type << " for AVCHD/Blu-ray muxing. Aborting...");
LTRACE(LT_ERROR, 2,
"Unsupported media type " << stream_coding_type << " for AVCHD/Blu-ray muxing. Aborting...");
THROW(ERR_COMMON, "");
}
}

View File

@ -42,6 +42,7 @@ static const uint8_t STREAM_TYPE_VIDEO_MPEG4 = 0x10;
static const uint8_t STREAM_TYPE_VIDEO_H264 = 0x1b;
static const uint8_t STREAM_TYPE_VIDEO_MVC = 0x20;
static const uint8_t STREAM_TYPE_VIDEO_H265 = 0x24;
static const uint8_t STREAM_TYPE_VIDEO_H266 = 0x25;
static const uint8_t STREAM_TYPE_VIDEO_VC1 = 0xea;
static const uint8_t STREAM_TYPE_AUDIO_MPEG1 = 0x03;

1040
tsMuxer/vvc.cpp Normal file

File diff suppressed because it is too large Load Diff

178
tsMuxer/vvc.h Normal file
View File

@ -0,0 +1,178 @@
#ifndef __VVC_H_
#define __VVC_H_
#include "nalUnits.h"
enum VvcSliceTypes
{
VVC_BFRAME_SLICE = 0,
VVC_PFRAME_SLICE = 1,
VVC_IFRAME_SLICE = 2
};
enum VVCUnitType
{
V_TRAIL = 0, // first slice
V_STSA = 1,
V_RADL = 2,
V_RASL = 3,
V_IDR_W_RADL = 7,
V_IDR_N_LP = 8,
V_CRA = 9,
V_GDR = 10,
V_RSV_IRAP_11 = 11,
V_OPI = 12,
V_DCI = 13,
V_VPS = 14,
V_SPS = 15,
V_PPS = 16,
V_PREFIX_APS = 17,
V_SUFFIX_APS = 18,
V_PH = 19,
V_AUD = 20,
V_EOS = 21,
V_EOB = 22,
V_PREFIX_SEI = 23,
V_SUFFIX_SEI = 24,
V_FD = 25
};
struct VvcUnit
{
VvcUnit() : nal_unit_type(0), nuh_layer_id(0), nuh_temporal_id_plus1(0), m_nalBuffer(0), m_nalBufferLen(0) {}
void decodeBuffer(const uint8_t* buffer, const uint8_t* end);
virtual int deserialize();
int serializeBuffer(uint8_t* dstBuffer, uint8_t* dstEnd) const;
int nalBufferLen() const { return m_nalBufferLen; }
public:
int nal_unit_type;
int nuh_layer_id;
int nuh_temporal_id_plus1;
protected:
unsigned extractUEGolombCode();
int extractSEGolombCode();
void updateBits(int bitOffset, int bitLen, int value);
bool dpb_parameters(int MaxSubLayersMinus1, bool subLayerInfoFlag);
protected:
uint8_t* m_nalBuffer;
int m_nalBufferLen;
BitStreamReader m_reader;
};
struct VvcUnitWithProfile : public VvcUnit
{
VvcUnitWithProfile();
std::string getProfileString() const;
public:
int profile_idc;
int level_idc;
protected:
void profile_tier_level(bool profileTierPresentFlag, int MaxNumSubLayersMinus1);
};
struct VvcHrdUnit : public VvcUnit
{
VvcHrdUnit();
public:
unsigned num_units_in_tick;
unsigned time_scale;
bool general_nal_hrd_params_present_flag;
bool general_vcl_hrd_params_present_flag;
bool general_du_hrd_params_present_flag;
int hrd_cpb_cnt_minus1;
bool general_timing_hrd_parameters();
bool ols_timing_hrd_parameters(int firstSubLayer, int MaxSubLayersVal);
bool sublayer_hrd_parameters(int subLayerId);
};
struct VvcVpsUnit : public VvcUnitWithProfile
{
VvcVpsUnit();
int deserialize() override;
double getFPS() const;
void setFPS(double value);
std::string getDescription() const;
public:
int vps_id;
int vps_max_layers;
int vps_max_sublayers;
int num_units_in_tick;
int time_scale;
int num_units_in_tick_bit_pos;
VvcHrdUnit m_vps_hrd;
};
struct VvcSpsUnit : public VvcUnitWithProfile
{
VvcSpsUnit();
int deserialize() override;
double getFPS() const;
std::string getDescription() const;
public:
int sps_id;
int vps_id;
int max_sublayers_minus1;
int chroma_format_idc;
unsigned pic_width_max_in_luma_samples;
unsigned pic_height_max_in_luma_samples;
unsigned bitdepth_minus8;
unsigned log2_max_pic_order_cnt_lsb;
VvcHrdUnit m_sps_hrd;
std::vector<unsigned> cpb_cnt_minus1;
int colour_primaries;
int transfer_characteristics;
int matrix_coeffs;
bool full_range_flag;
unsigned chroma_sample_loc_type_frame;
unsigned chroma_sample_loc_type_top_field;
unsigned chroma_sample_loc_type_bottom_field;
unsigned num_units_in_tick;
unsigned time_scale;
private:
int ref_pic_list_struct(int listIdx, int rplsIdx);
unsigned sps_num_ref_pic_lists;
bool weighted_pred_flag;
bool weighted_bipred_flag;
bool long_term_ref_pics_flag;
bool inter_layer_prediction_enabled_flag;
int vui_parameters();
};
struct VvcPpsUnit : public VvcUnit
{
VvcPpsUnit();
int deserialize() override;
public:
int pps_id;
int sps_id;
};
struct VvcSliceHeader : public VvcUnit
{
VvcSliceHeader();
int deserialize(const VvcSpsUnit* sps, const VvcPpsUnit* pps);
bool isIDR() const;
public:
unsigned ph_pps_id;
int pic_order_cnt_lsb;
};
std::vector<std::vector<uint8_t>> vvc_extract_priv_data(const uint8_t* buff, int size, int* nal_size);
#endif // __VVC_H_

456
tsMuxer/vvcStreamReader.cpp Normal file
View File

@ -0,0 +1,456 @@
#include "vvcStreamReader.h"
#include <fs/systemlog.h>
#include "nalUnits.h"
#include "tsMuxer.h"
#include "tsPacket.h"
#include "vodCoreException.h"
#include "vvc.h"
using namespace std;
static const int MAX_SLICE_HEADER = 64;
static const int VVC_DESCRIPTOR_TAG = 0x38;
VVCStreamReader::VVCStreamReader()
: MPEGStreamReader(),
m_vps(0),
m_sps(0),
m_pps(0),
m_firstFrame(true),
m_frameNum(0),
m_fullPicOrder(0),
m_frameDepth(1),
m_picOrderMsb(0),
m_prevPicOrder(0),
m_picOrderBase(0),
m_lastIFrame(false),
m_firstFileFrame(false),
m_vpsCounter(0),
m_vpsSizeDiff(0)
{
}
VVCStreamReader::~VVCStreamReader()
{
delete m_vps;
delete m_sps;
delete m_pps;
}
CheckStreamRez VVCStreamReader::checkStream(uint8_t* buffer, int len)
{
CheckStreamRez rez;
VvcSliceHeader slice;
uint8_t* end = buffer + len;
for (uint8_t* nal = NALUnit::findNextNAL(buffer, end); nal < end - 4; nal = NALUnit::findNextNAL(nal, end))
{
if (*nal & 0x80)
return rez; // invalid nal
int nalType = (nal[1] >> 3);
uint8_t* nextNal = NALUnit::findNALWithStartCode(nal, end, true);
switch (nalType)
{
case V_VPS:
if (!m_vps)
m_vps = new VvcVpsUnit();
m_vps->decodeBuffer(nal, nextNal);
if (m_vps->deserialize())
return rez;
m_spsPpsFound = true;
if (m_vps->num_units_in_tick)
updateFPS(m_vps, nal, nextNal, 0);
break;
case V_SPS:
if (!m_sps)
m_sps = new VvcSpsUnit();
m_sps->decodeBuffer(nal, nextNal);
if (m_sps->deserialize() != 0)
return rez;
m_spsPpsFound = true;
updateFPS(m_sps, nal, nextNal, 0);
break;
case V_PPS:
if (!m_pps)
m_pps = new VvcPpsUnit();
m_pps->decodeBuffer(nal, nextNal);
if (m_pps->deserialize() != 0)
return rez;
}
// check Frame Depth on first slices
if (isSlice(nalType) && (nal[2] & 0x80))
{
slice.decodeBuffer(nal, FFMIN(nal + MAX_SLICE_HEADER, nextNal));
if (slice.deserialize(m_sps, m_pps))
return rez; // not enough buffer or error
m_fullPicOrder = toFullPicOrder(&slice, m_sps->log2_max_pic_order_cnt_lsb);
incTimings();
}
}
m_totalFrameNum = m_frameNum = m_fullPicOrder = 0;
m_curDts = m_curPts = 0;
if (m_sps && m_pps && m_pps->sps_id == m_sps->sps_id)
{
rez.codecInfo = vvcCodecInfo;
rez.streamDescr = m_sps->getDescription();
size_t frSpsPos = rez.streamDescr.find("Frame rate: not found");
if (frSpsPos != string::npos)
rez.streamDescr = rez.streamDescr.substr(0, frSpsPos);
if (m_vps)
rez.streamDescr += string(" ") + m_vps->getDescription();
}
return rez;
}
int VVCStreamReader::getTSDescriptor(uint8_t* dstBuff, bool blurayMode, bool hdmvDescriptors)
{
if (m_firstFrame)
CheckStreamRez rez = checkStream(m_buffer, m_bufEnd - m_buffer);
if (hdmvDescriptors)
{
// 'HDMV' registration descriptor
*dstBuff++ = 0x05;
*dstBuff++ = 8;
memcpy(dstBuff, "HDMV\xff\x24", 6);
dstBuff += 6;
int video_format, frame_rate_index, aspect_ratio_index;
M2TSStreamInfo::blurayStreamParams(getFPS(), getInterlaced(), getStreamWidth(), getStreamHeight(),
getStreamAR(), &video_format, &frame_rate_index, &aspect_ratio_index);
*dstBuff++ = (video_format << 4) + frame_rate_index;
*dstBuff++ = (aspect_ratio_index << 4) + 0xf;
}
else
{
uint8_t tmpBuffer[512];
for (uint8_t* nal = NALUnit::findNextNAL(m_buffer, m_bufEnd); nal < m_bufEnd - 4;
nal = NALUnit::findNextNAL(nal, m_bufEnd))
{
uint8_t nalType = (*nal >> 1) & 0x3f;
uint8_t* nextNal = NALUnit::findNALWithStartCode(nal, m_bufEnd, true);
if (nalType == V_SPS)
{
int toDecode = FFMIN(sizeof(tmpBuffer) - 8, nextNal - nal);
int decodedLen = NALUnit::decodeNAL(nal, nal + toDecode, tmpBuffer, sizeof(tmpBuffer));
break;
}
}
*dstBuff++ = VVC_DESCRIPTOR_TAG;
*dstBuff++ = 13; // descriptor length
memcpy(dstBuff, tmpBuffer + 3, 12);
dstBuff += 12;
// flags temporal_layer_subset, VVC_still_present,
// VVC_24hr_picture_present, HDR_WCG unspecified
*dstBuff = 0x0f;
dstBuff++;
/* VVC_timing_and_HRD_descriptor
// mandatory for interlaced video only
memcpy(dstBuff, "\x3f\x0f\x03\x7f\x7f", 5);
dstBuff += 5;
uint32_t N = 1001 * getFPS();
uint32_t K = 27000000;
uint32_t num_units_in_tick = 1001;
if (N % 1000)
{
N = 1000 * getFPS();
num_units_in_tick = 1000;
}
N = my_htonl(N);
K = my_htonl(K);
num_units_in_tick = my_htonl(num_units_in_tick);
memcpy(dstBuff, &N, 4);
dstBuff += 4;
memcpy(dstBuff, &K, 4);
dstBuff += 4;
memcpy(dstBuff, &num_units_in_tick, 4);
dstBuff += 4;
*/
}
return (hdmvDescriptors ? 10 : 15);
}
void VVCStreamReader::updateStreamFps(void* nalUnit, uint8_t* buff, uint8_t* nextNal, int)
{
int oldNalSize = nextNal - buff;
m_vpsSizeDiff = 0;
VvcVpsUnit* vps = (VvcVpsUnit*)nalUnit;
vps->setFPS(m_fps);
uint8_t* tmpBuffer = new uint8_t[vps->nalBufferLen() + 16];
long newSpsLen = vps->serializeBuffer(tmpBuffer, tmpBuffer + vps->nalBufferLen() + 16);
if (newSpsLen == -1)
THROW(ERR_COMMON, "Not enough buffer");
if (m_bufEnd && newSpsLen != oldNalSize)
{
m_vpsSizeDiff = newSpsLen - oldNalSize;
if (m_bufEnd + m_vpsSizeDiff > m_tmpBuffer + TMP_BUFFER_SIZE)
THROW(ERR_COMMON, "Not enough buffer");
memmove(nextNal + m_vpsSizeDiff, nextNal, m_bufEnd - nextNal);
m_bufEnd += m_vpsSizeDiff;
}
memcpy(buff, tmpBuffer, newSpsLen);
delete[] tmpBuffer;
}
int VVCStreamReader::getStreamWidth() const { return m_sps ? m_sps->pic_width_max_in_luma_samples : 0; }
int VVCStreamReader::getStreamHeight() const { return m_sps ? m_sps->pic_height_max_in_luma_samples : 0; }
double VVCStreamReader::getStreamFPS(void* curNalUnit)
{
double fps = 0;
if (m_vps)
fps = m_vps->getFPS();
if (fps == 0 && m_sps)
fps = m_sps->getFPS();
return fps;
}
bool VVCStreamReader::isSlice(int nalType) const
{
if (!m_sps || !m_pps)
return false;
return (nalType >= V_TRAIL && nalType <= V_RASL) || (nalType >= V_IDR_W_RADL && nalType <= V_GDR);
}
bool VVCStreamReader::isSuffix(int nalType) const
{
if (!m_sps || !m_vps || !m_pps)
return false;
return (nalType == V_FD || nalType == V_SUFFIX_APS);
}
void VVCStreamReader::incTimings()
{
if (m_totalFrameNum++ > 0)
m_curDts += m_pcrIncPerFrame;
int delta = m_frameNum - m_fullPicOrder;
m_curPts = m_curDts - delta * m_pcrIncPerFrame;
m_frameNum++;
m_firstFrame = false;
if (delta > m_frameDepth)
{
m_frameDepth = delta;
LTRACE(LT_INFO, 2,
"B-pyramid level " << m_frameDepth - 1 << " detected. Shift DTS to " << m_frameDepth << " frames");
}
}
int VVCStreamReader::toFullPicOrder(VvcSliceHeader* slice, int pic_bits)
{
if (slice->isIDR())
{
m_picOrderBase = m_frameNum;
m_picOrderMsb = 0;
m_prevPicOrder = 0;
}
else
{
int range = 1 << pic_bits;
if (slice->pic_order_cnt_lsb < m_prevPicOrder && m_prevPicOrder - slice->pic_order_cnt_lsb >= range / 2)
m_picOrderMsb += range;
else if (slice->pic_order_cnt_lsb > m_prevPicOrder && slice->pic_order_cnt_lsb - m_prevPicOrder >= range / 2)
m_picOrderMsb -= range;
m_prevPicOrder = slice->pic_order_cnt_lsb;
}
return slice->pic_order_cnt_lsb + m_picOrderMsb + m_picOrderBase;
}
void VVCStreamReader::storeBuffer(MemoryBlock& dst, const uint8_t* data, const uint8_t* dataEnd)
{
dataEnd--;
while (dataEnd > data && dataEnd[-1] == 0) dataEnd--;
if (dataEnd > data)
{
dst.resize(dataEnd - data);
memcpy(dst.data(), data, dataEnd - data);
}
}
int VVCStreamReader::intDecodeNAL(uint8_t* buff)
{
int rez = 0;
bool sliceFound = false;
m_spsPpsFound = false;
m_lastIFrame = false;
uint8_t* prevPos = 0;
uint8_t* curPos = buff;
uint8_t* nextNal = NALUnit::findNextNAL(curPos, m_bufEnd);
uint8_t* nextNalWithStartCode;
long oldSpsLen = 0;
if (!m_eof && nextNal == m_bufEnd)
return NOT_ENOUGH_BUFFER;
while (curPos < m_bufEnd)
{
int nalType = (*curPos >> 1) & 0x3f;
if (isSlice(nalType))
{
if (curPos[2] & 0x80) // slice.first_slice
{
if (sliceFound)
{ // first slice of next frame: case where there is no non-VCL NAL between the two frames
m_lastDecodedPos = prevPos; // next frame started
incTimings();
return 0;
}
else
{ // first slice of current frame
VvcSliceHeader slice;
slice.decodeBuffer(curPos, FFMIN(curPos + MAX_SLICE_HEADER, nextNal));
rez = slice.deserialize(m_sps, m_pps);
if (rez)
return rez; // not enough buffer or error
// if (slice.slice_type == VVC_IFRAME_SLICE)
if (nalType >= NAL_BLA_W_LP)
m_lastIFrame = true;
m_fullPicOrder = toFullPicOrder(&slice, m_sps->log2_max_pic_order_cnt_lsb);
}
}
sliceFound = true;
}
else if (!isSuffix(nalType))
{ // first non-VCL prefix NAL (AUD, SEI...) following current frame
if (sliceFound)
{
incTimings();
m_lastDecodedPos = prevPos; // next frame started
return 0;
}
nextNalWithStartCode = nextNal[-4] == 0 ? nextNal - 4 : nextNal - 3;
switch (nalType)
{
case NAL_VPS:
if (!m_vps)
m_vps = new VvcVpsUnit();
m_vps->decodeBuffer(curPos, nextNalWithStartCode);
rez = m_vps->deserialize();
if (rez)
return rez;
m_spsPpsFound = true;
m_vpsCounter++;
m_vpsSizeDiff = 0;
if (m_vps->num_units_in_tick)
updateFPS(m_vps, curPos, nextNalWithStartCode, 0);
nextNal += m_vpsSizeDiff;
storeBuffer(m_vpsBuffer, curPos, nextNalWithStartCode);
break;
case NAL_SPS:
if (!m_sps)
m_sps = new VvcSpsUnit();
m_sps->decodeBuffer(curPos, nextNalWithStartCode);
rez = m_sps->deserialize();
if (rez)
return rez;
m_spsPpsFound = true;
updateFPS(m_sps, curPos, nextNalWithStartCode, 0);
storeBuffer(m_spsBuffer, curPos, nextNalWithStartCode);
break;
case NAL_PPS:
if (!m_pps)
m_pps = new VvcPpsUnit();
m_pps->decodeBuffer(curPos, nextNalWithStartCode);
rez = m_pps->deserialize();
if (rez)
return rez;
m_spsPpsFound = true;
storeBuffer(m_ppsBuffer, curPos, nextNalWithStartCode);
}
}
prevPos = curPos;
curPos = nextNal;
nextNal = NALUnit::findNextNAL(curPos, m_bufEnd);
if (!m_eof && nextNal == m_bufEnd)
return NOT_ENOUGH_BUFFER;
}
if (m_eof)
{
m_lastDecodedPos = m_bufEnd;
return 0;
}
else
return NEED_MORE_DATA;
}
uint8_t* VVCStreamReader::writeNalPrefix(uint8_t* curPos)
{
if (!m_shortStartCodes)
*curPos++ = 0;
*curPos++ = 0;
*curPos++ = 0;
*curPos++ = 1;
return curPos;
}
uint8_t* VVCStreamReader::writeBuffer(MemoryBlock& srcData, uint8_t* dstBuffer, uint8_t* dstEnd)
{
if (srcData.isEmpty())
return dstBuffer;
int bytesLeft = dstEnd - dstBuffer;
int requiredBytes = srcData.size() + 3 + (m_shortStartCodes ? 0 : 1);
if (bytesLeft < requiredBytes)
return dstBuffer;
dstBuffer = writeNalPrefix(dstBuffer);
memcpy(dstBuffer, srcData.data(), srcData.size());
dstBuffer += srcData.size();
return dstBuffer;
}
int VVCStreamReader::writeAdditionData(uint8_t* dstBuffer, uint8_t* dstEnd, AVPacket& avPacket,
PriorityDataInfo* priorityData)
{
uint8_t* curPos = dstBuffer;
if (avPacket.size > 4 && avPacket.size < dstEnd - dstBuffer)
{
int offset = avPacket.data[2] == 1 ? 3 : 4;
uint8_t nalType = (avPacket.data[offset] >> 1) & 0x3f;
if (nalType == NAL_AUD)
{
// place delimiter at first place
memcpy(curPos, avPacket.data, avPacket.size);
curPos += avPacket.size;
avPacket.size = 0;
avPacket.data = 0;
}
}
bool needInsSpsPps = m_firstFileFrame && !(avPacket.flags & AVPacket::IS_SPS_PPS_IN_GOP);
if (needInsSpsPps)
{
avPacket.flags |= AVPacket::IS_SPS_PPS_IN_GOP;
curPos = writeBuffer(m_vpsBuffer, curPos, dstEnd);
curPos = writeBuffer(m_spsBuffer, curPos, dstEnd);
curPos = writeBuffer(m_ppsBuffer, curPos, dstEnd);
}
m_firstFileFrame = false;
return curPos - dstBuffer;
}

69
tsMuxer/vvcStreamReader.h Normal file
View File

@ -0,0 +1,69 @@
#ifndef __VVC_STREAM_READER_H__
#define __VVC_STREAM_READER_H__
#include <map>
#include "abstractDemuxer.h"
#include "mpegStreamReader.h"
#include "vvc.h"
class VVCStreamReader : public MPEGStreamReader
{
public:
VVCStreamReader();
~VVCStreamReader() override;
int getTSDescriptor(uint8_t* dstBuff, bool blurayMode, bool hdmvDescriptors) override;
virtual CheckStreamRez checkStream(uint8_t* buffer, int len);
bool needSPSForSplit() const override { return false; }
protected:
const CodecInfo& getCodecInfo() override { return vvcCodecInfo; }
virtual int intDecodeNAL(uint8_t* buff) override;
double getStreamFPS(void* curNalUnit) override;
int getStreamWidth() const override;
int getStreamHeight() const override;
bool getInterlaced() override { return false; }
bool isIFrame() override { return m_lastIFrame; }
void updateStreamFps(void* nalUnit, uint8_t* buff, uint8_t* nextNal, int oldSpsLen) override;
int getFrameDepth() override { return m_frameDepth; }
virtual int writeAdditionData(uint8_t* dstBuffer, uint8_t* dstEnd, AVPacket& avPacket,
PriorityDataInfo* priorityData) override;
void onSplitEvent() override { m_firstFileFrame = true; }
private:
bool isSlice(int nalType) const;
bool isSuffix(int nalType) const;
void incTimings();
int toFullPicOrder(VvcSliceHeader* slice, int pic_bits);
void storeBuffer(MemoryBlock& dst, const uint8_t* data, const uint8_t* dataEnd);
uint8_t* writeBuffer(MemoryBlock& srcData, uint8_t* dstBuffer, uint8_t* dstEnd);
uint8_t* writeNalPrefix(uint8_t* curPos);
private:
typedef std::map<int, VvcVpsUnit*> VPSMap;
VvcVpsUnit* m_vps;
VvcSpsUnit* m_sps;
VvcPpsUnit* m_pps;
bool m_firstFrame;
int m_frameNum;
int m_fullPicOrder;
int m_picOrderBase;
int m_frameDepth;
int m_picOrderMsb;
int m_prevPicOrder;
bool m_lastIFrame;
MemoryBlock m_vpsBuffer;
MemoryBlock m_spsBuffer;
MemoryBlock m_ppsBuffer;
bool m_firstFileFrame;
int m_vpsCounter;
int m_vpsSizeDiff;
};
#endif // __VVC_STREAM_READER_H__