commit
3d6e3eec87
@ -52,6 +52,8 @@ add_executable (tsmuxer
|
||||
vc1Parser.cpp
|
||||
vc1StreamReader.cpp
|
||||
vod_common.cpp
|
||||
vvc.cpp
|
||||
vvcStreamReader.cpp
|
||||
wave.cpp
|
||||
)
|
||||
|
||||
|
@ -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",
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "hevc.h"
|
||||
//#include "hevc.h"
|
||||
#include "iso_writer.h"
|
||||
#include "muxerManager.h"
|
||||
#include "psgStreamReader.h"
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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";
|
||||
|
@ -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,
|
||||
|
@ -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, "");
|
||||
}
|
||||
}
|
||||
|
@ -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
1040
tsMuxer/vvc.cpp
Normal file
File diff suppressed because it is too large
Load Diff
178
tsMuxer/vvc.h
Normal file
178
tsMuxer/vvc.h
Normal 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
456
tsMuxer/vvcStreamReader.cpp
Normal 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
69
tsMuxer/vvcStreamReader.h
Normal 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__
|
Loading…
x
Reference in New Issue
Block a user