H265 library improvements

This commit is contained in:
Erik Zandvliet 2017-07-28 11:43:11 +02:00 committed by Thulinma
parent 5126928d0d
commit 5dce70e933
5 changed files with 543 additions and 4 deletions

View file

@ -3,6 +3,46 @@
#include "defines.h" #include "defines.h"
namespace h265 { namespace h265 {
const char * typeToStr(uint8_t type){
switch (type){
case 0:
case 1: return "Trailing slice";
case 2:
case 3: return "TSA slice";
case 4:
case 5: return "STSA slice";
case 6:
case 7: return "Decodable leading slice";
case 8:
case 9: return "Skipped leading slice";
case 16:
case 17:
case 18: return "BLA slice";
case 19:
case 20: return "IDR (keyframe) slice";
case 21: return "CRA slice";
case 32: return "VPS";
case 33: return "SPS";
case 34: return "PPS";
case 35: return "Access unit delimiter";
case 36: return "End of sequence";
case 37: return "End of bitstream";
case 38: return "Filler data";
case 39:
case 40: return "SEI";
case 48: return "RTP Aggregation Packet";
case 49: return "RTP Fragmentation Unit";
case 50: return "RTP PAyload Content Information (PACI)";
default: return "UNKNOWN";
}
}
bool isKeyframe(const char * data, uint32_t len){
if (!len){return false;}
uint8_t nalType = (data[0] & 0x7E) >> 1;
return (nalType >= 16 && nalType <= 21);
}
std::deque<nalu::nalData> analysePackets(const char * data, unsigned long len){ std::deque<nalu::nalData> analysePackets(const char * data, unsigned long len){
std::deque<nalu::nalData> res; std::deque<nalu::nalData> res;
@ -19,6 +59,36 @@ namespace h265 {
initData::initData() {} initData::initData() {}
initData::initData(const std::string& hvccData) {
MP4::HVCC hvccBox;
hvccBox.setPayload(hvccData);
std::deque<MP4::HVCCArrayEntry> arrays = hvccBox.getArrays();
for (std::deque<MP4::HVCCArrayEntry>::iterator it = arrays.begin(); it != arrays.end(); it++){
for (std::deque<std::string>::iterator nalIt = it->nalUnits.begin(); nalIt != it->nalUnits.end(); nalIt++){
nalUnits[it->nalUnitType].insert(*nalIt);
}
}
}
const std::set<std::string> & initData::getVPS() const{
static std::set<std::string> empty;
if (!nalUnits.count(32)){return empty;}
return nalUnits.at(32);
}
const std::set<std::string> & initData::getSPS() const{
static std::set<std::string> empty;
if (!nalUnits.count(33)){return empty;}
return nalUnits.at(33);
}
const std::set<std::string> & initData::getPPS() const{
static std::set<std::string> empty;
if (!nalUnits.count(34)){return empty;}
return nalUnits.at(34);
}
void initData::addUnit(char * data) { void initData::addUnit(char * data) {
unsigned long nalSize = Bit::btohl(data); unsigned long nalSize = Bit::btohl(data);
unsigned long nalType = (data[4] & 0x7E) >> 1; unsigned long nalType = (data[4] & 0x7E) >> 1;
@ -30,6 +100,22 @@ namespace h265 {
} }
} }
void initData::addUnit(const std::string & data) {
if (data.size() <= 1){return;}
unsigned long nalType = (data[0] & 0x7E) >> 1;
switch (nalType) {
case 32: //vps
case 33: //sps
case 34: //pps
nalUnits[nalType].insert(data);
}
INFO_MSG("added nal of type %u" , nalType);
if (nalType == 32){
vpsUnit vps(data);
std::cout << vps.toPrettyString(0);
}
}
bool initData::haveRequired() { bool initData::haveRequired() {
return (nalUnits.count(32) && nalUnits.count(33) && nalUnits.count(34)); return (nalUnits.count(32) && nalUnits.count(33) && nalUnits.count(34));
} }
@ -72,6 +158,94 @@ namespace h265 {
return std::string(hvccBox.payload(), hvccBox.payloadSize()); return std::string(hvccBox.payload(), hvccBox.payloadSize());
} }
metaInfo initData::getMeta() {
metaInfo res;
if (!nalUnits.count(33)){
return res;
}
spsUnit sps(*nalUnits[33].begin());
sps.getMeta(res);
return res;
}
void skipProfileTierLevel(Utils::bitstream & bs, unsigned int maxSubLayersMinus1){
bs.skip(8);
bs.skip(32);//general_profile_flags
bs.skip(4);
bs.skip(44);//reserverd_zero
bs.skip(8);
std::deque<bool> profilePresent;
std::deque<bool> levelPresent;
for (size_t i = 0; i < maxSubLayersMinus1; i++){
profilePresent.push_back(bs.get(1));
levelPresent.push_back(bs.get(1));
}
if (maxSubLayersMinus1){
for (int i = maxSubLayersMinus1; i < 8; i++){
bs.skip(2);
}
}
for (int i = 0; i < maxSubLayersMinus1; i++){
if (profilePresent[i]){
bs.skip(8);
bs.skip(32);//sub_layer_profile_flags
bs.skip(4);
bs.skip(44);//reserved_zero
}
if (levelPresent[i]){
bs.skip(8);
}
}
}
std::string printProfileTierLevel(Utils::bitstream & bs, unsigned int maxSubLayersMinus1, size_t indent){
std::stringstream r;
r << std::string(indent, ' ') << "general_profile_space: " << bs.get(2) << std::endl;
r << std::string(indent, ' ') << "general_tier_flag: " << bs.get(1) << std::endl;
r << std::string(indent, ' ') << "general_profile_idc: " << bs.get(5) << std::endl;
r << std::string(indent, ' ') << "general_profile_compatibility_flags: 0x" << std::hex << bs.get(32) << std::dec << std::endl;
r << std::string(indent, ' ') << "general_progressive_source_flag: " << bs.get(1) << std::endl;
r << std::string(indent, ' ') << "general_interlaced_source_flag: " << bs.get(1) << std::endl;
r << std::string(indent, ' ') << "general_non_packed_constraint_flag: " << bs.get(1) << std::endl;
r << std::string(indent, ' ') << "general_frame_only_constraint_flag: " << bs.get(1) << std::endl;
r << std::string(indent, ' ') << "general_reserved_zero_44bits: " << bs.get(44) << std::endl;
r << std::string(indent, ' ') << "general_level_idc: " << bs.get(8) << std::endl;
std::deque<bool> profilePresent;
std::deque<bool> levelPresent;
for (size_t i = 0; i < maxSubLayersMinus1; i++){
bool profile = bs.get(1);
bool level = bs.get(1);
profilePresent.push_back(profile);
levelPresent.push_back(level);
r << std::string(indent + 1, ' ') << "sub_layer_profile_present_flag[" << i << "]: " << (profile ? 1 : 0) << std::endl;
r << std::string(indent + 1, ' ') << "sub_layer_level_present_flag[" << i << "]: " << (level ? 1 : 0) << std::endl;
}
if (maxSubLayersMinus1){
for (int i = maxSubLayersMinus1; i < 8; i++){
r << std::string(indent + 1, ' ') << "reserver_zero_2_bits[" << i << "]: " << bs.get(2) << std::endl;
}
}
for (int i = 0; i < maxSubLayersMinus1; i++){
r << std::string(indent + 1, ' ') << "sub_layer[" << i << "]:" << std::endl;
if (profilePresent[i]){
r << std::string(indent + 2, ' ') << "sub_layer_profile_space: " << bs.get(2) << std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_tier_flag: " << bs.get(1) << std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_profile_idc: " << bs.get(5) << std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_profile_compatibility_flags: " << std::hex << bs.get(32) << std::dec << std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_progressive_source_flag: " << bs.get(1) << std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_interlaced_source_flag: " << bs.get(1) << std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_non_packed_constraint_flag: " << bs.get(1) << std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_frame_only_constraint_flag: " << bs.get(1) << std::endl;
r << std::string(indent + 2, ' ') << "sub_layer_reserved_zero_44bits: " << bs.get(44) << std::endl;
}
if (levelPresent[i]){
r << std::string(indent + 2, ' ') << "sub_layer_level_idc: " << bs.get(8) << std::endl;
}
}
return r.str();
}
void updateProfileTierLevel(Utils::bitstream & bs, MP4::HVCC & hvccBox, unsigned int maxSubLayersMinus1){ void updateProfileTierLevel(Utils::bitstream & bs, MP4::HVCC & hvccBox, unsigned int maxSubLayersMinus1){
hvccBox.setGeneralProfileSpace(bs.get(2)); hvccBox.setGeneralProfileSpace(bs.get(2));
@ -135,10 +309,339 @@ namespace h265 {
updateProfileTierLevel(bs, hvccBox, maxSubLayers - 1); updateProfileTierLevel(bs, hvccBox, maxSubLayers - 1);
} }
std::string vpsUnit::toPrettyString(size_t indent){
Utils::bitstream bs;
bs.append(data);
bs.skip(16);//Nal Header
std::stringstream r;
r << std::string(indent, ' ') << "vps_video_parameter_set_id: " << bs.get(4) << std::endl;
r << std::string(indent, ' ') << "vps_reserved_three_2bits: " << bs.get(2) << std::endl;
r << std::string(indent, ' ') << "vps_max_layers_minus1: " << bs.get(6) << std::endl;
unsigned int maxSubLayersMinus1 = bs.get(3);
r << std::string(indent, ' ') << "vps_max_sub_layers_minus1: " << maxSubLayersMinus1 << std::endl;
r << std::string(indent, ' ') << "vps_temporal_id_nesting_flag: " << bs.get(1) << std::endl;
r << std::string(indent, ' ') << "vps_reserved_0xffff_16bits: " << std::hex << bs.get(16) << std::dec << std::endl;
r << std::string(indent, ' ') << "profile_tier_level(): " << std::endl << printProfileTierLevel(bs, maxSubLayersMinus1, indent + 1);
bool sub_layer_ordering_info = bs.get(1);
r << std::string(indent, ' ') << "vps_sub_layer_ordering_info_present_flag: " << sub_layer_ordering_info << std::endl;
for (int i = (sub_layer_ordering_info ? 0 : maxSubLayersMinus1); i <= maxSubLayersMinus1; i++){
r << std::string(indent, ' ') << "vps_max_dec_pic_buffering_minus1[" << i << "]: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "vps_max_num_reorder_pics[" << i << "]: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "vps_max_latency_increase_plus1[" << i << "]: " << bs.getUExpGolomb() << std::endl;
}
unsigned int vps_max_layer_id = bs.get(6);
uint64_t vps_num_layer_sets_minus1 = bs.getUExpGolomb();
r << std::string(indent, ' ') << "vps_max_layer_id: " << vps_max_layer_id << std::endl;
r << std::string(indent, ' ') << "vps_num_layer_sets_minus1: " << vps_num_layer_sets_minus1 << std::endl;
for (int i = 1; i <= vps_num_layer_sets_minus1; i++){
for (int j = 0; j < vps_max_layer_id; j++){
r << std::string(indent, ' ') << "layer_id_included_flag[" << i << "][" << j << "]: " << bs.get(1) << std::endl;
}
}
bool vps_timing_info = bs.get(1);
r << std::string(indent, ' ') << "vps_timing_info_present_flag: " << (vps_timing_info ? 1 : 0) << std::endl;
return r.str();
}
spsUnit::spsUnit(const std::string & _data){ spsUnit::spsUnit(const std::string & _data){
data = nalu::removeEmulationPrevention(_data); data = nalu::removeEmulationPrevention(_data);
} }
void skipShortTermRefPicSet(Utils::bitstream & bs, unsigned int idx, size_t count){
static std::map<int,int> negativePics;
static std::map<int,int> positivePics;
if (idx == 0){
negativePics.clear();
positivePics.clear();
}
bool interPrediction = false;
if (idx != 0){
interPrediction = bs.get(1);
}
if (interPrediction){
uint64_t deltaIdxMinus1 = 0;
if (idx == count){
deltaIdxMinus1 = bs.getUExpGolomb();
}
bs.skip(1);
bs.getUExpGolomb();
uint64_t refRpsIdx = idx - deltaIdxMinus1 - 1;
uint64_t deltaPocs = negativePics[refRpsIdx] + positivePics[refRpsIdx];
for (int j = 0; j < deltaPocs; j++){
bool usedByCurrPicFlag = bs.get(1);
if (!usedByCurrPicFlag){
bs.skip(1);
}
}
}else{
negativePics[idx] = bs.getUExpGolomb();
positivePics[idx] = bs.getUExpGolomb();
for (int i = 0; i < negativePics[idx]; i++){
bs.getUExpGolomb();
bs.skip(1);
}
for (int i = 0; i < positivePics[idx]; i++){
bs.getUExpGolomb();
bs.skip(1);
}
}
}
std::string printShortTermRefPicSet(Utils::bitstream & bs, unsigned int idx, size_t indent){
std::stringstream r;
bool interPrediction = false;
if (idx != 0){
interPrediction = bs.get(1);
r << std::string(indent, ' ') << "inter_ref_pic_set_predicition_flag: " << (interPrediction ? 1 : 0) << std::endl;
}
if (interPrediction){
WARN_MSG("interprediciton not yet handled");
}else{
uint64_t negativePics = bs.getUExpGolomb();
uint64_t positivePics = bs.getUExpGolomb();
r << std::string(indent, ' ') << "num_negative_pics: " << negativePics << std::endl;
r << std::string(indent, ' ') << "num_positive_pics: " << positivePics << std::endl;
for (int i = 0; i < negativePics; i++){
r << std::string(indent + 1, ' ') << "delta_poc_s0_minus1[" << i << "]: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent + 1, ' ') << "used_by_curr_pic_s0_flag[" << i << "]: " << bs.get(1) << std::endl;
}
for (int i = 0; i < positivePics; i++){
r << std::string(indent + 1, ' ') << "delta_poc_s1_minus1[" << i << "]: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent + 1, ' ') << "used_by_curr_pic_s1_flag[" << i << "]: " << bs.get(1) << std::endl;
}
}
return r.str();
}
void parseVuiParameters(Utils::bitstream & bs, metaInfo & res){
bool aspectRatio = bs.get(1);
if (aspectRatio){
uint16_t aspectRatioIdc = bs.get(8);
if (aspectRatioIdc == 255){
bs.skip(32);
}
}
bool overscanInfo = bs.get(1);
if (overscanInfo){
bs.skip(1);
}
bool videoSignalTypePresent = bs.get(1);
if (videoSignalTypePresent){
bs.skip(4);
bool colourDescription = bs.get(1);
if (colourDescription){
bs.skip(24);
}
}
bool chromaLocPresent = bs.get(1);
if (chromaLocPresent){
bs.getUExpGolomb();
bs.getUExpGolomb();
}
bs.skip(3);
bool defaultDisplay = bs.get(1);
if (defaultDisplay){
bs.getUExpGolomb();
bs.getUExpGolomb();
bs.getUExpGolomb();
bs.getUExpGolomb();
}
bool timingFlag = bs.get(1);
if (timingFlag){
uint32_t unitsInTick = bs.get(32);
uint32_t timescale = bs.get(32);
res.fps = (double)timescale / unitsInTick;
}
}
std::string printVuiParameters(Utils::bitstream & bs, size_t indent){
std::stringstream r;
bool aspectRatio = bs.get(1);
r << std::string(indent, ' ') << "aspect_ratio_info_present_flag: " << (aspectRatio ? 1 : 0) << std::endl;
if (aspectRatio){
uint16_t aspectRatioIdc = bs.get(8);
r << std::string(indent, ' ') << "aspect_ratio_idc: " << aspectRatioIdc << std::endl;
if (aspectRatioIdc == 255){
r << std::string(indent, ' ') << "sar_width: " << bs.get(16) << std::endl;
r << std::string(indent, ' ') << "sar_height: " << bs.get(16) << std::endl;
}
}
return r.str();
}
void skipScalingList(Utils::bitstream & bs){
for (int sizeId = 0; sizeId < 4; sizeId++){
for (int matrixId = 0; matrixId < (sizeId == 3 ? 2 : 6); matrixId++){
bool modeFlag = bs.get(1);
if (!modeFlag){
bs.getUExpGolomb();
}else{
size_t coefNum = std::min(64, (1 << (4 + (sizeId << 1))));
if (sizeId > 1){
bs.getExpGolomb();
}
for (int i = 0; i < coefNum; i++){
bs.getExpGolomb();
}
}
}
}
}
void spsUnit::getMeta(metaInfo & res) {
Utils::bitstream bs;
bs.append(data);
bs.skip(16);//Nal Header
bs.skip(4);
unsigned int maxSubLayersMinus1 = bs.get(3);
bs.skip(1);
skipProfileTierLevel(bs, maxSubLayersMinus1);
bs.getUExpGolomb();
uint64_t chromaFormatIdc = bs.getUExpGolomb();
bool separateColorPlane = false;
if (chromaFormatIdc == 3){
separateColorPlane = bs.get(1);
}
res.width = bs.getUExpGolomb();
res.height = bs.getUExpGolomb();
bool conformanceWindow = bs.get(1);
if (conformanceWindow){
uint8_t subWidthC = ((chromaFormatIdc == 1 || chromaFormatIdc == 2) ? 2 : 1);
uint8_t subHeightC = (chromaFormatIdc == 1 ? 2 : 1);
uint64_t left = bs.getUExpGolomb();
uint64_t right = bs.getUExpGolomb();
uint64_t top = bs.getUExpGolomb();
uint64_t bottom = bs.getUExpGolomb();
res.width -= (subWidthC * right);
res.height -= (subHeightC * bottom);
}
bs.getUExpGolomb();
bs.getUExpGolomb();
uint64_t log2MaxPicOrderCntLsbMinus4 = bs.getUExpGolomb();
bool subLayerOrdering = bs.get(1);
for (int i= (subLayerOrdering ? 0 : maxSubLayersMinus1); i <= maxSubLayersMinus1; i++){
bs.getUExpGolomb();
bs.getUExpGolomb();
bs.getUExpGolomb();
}
bs.getUExpGolomb();
bs.getUExpGolomb();
bs.getUExpGolomb();
bs.getUExpGolomb();
bs.getUExpGolomb();
bs.getUExpGolomb();
bool scalingListEnabled = bs.get(1);
if (scalingListEnabled){
bool scalingListPresent = bs.get(1);
if (scalingListPresent){
skipScalingList(bs);
}
}
bs.skip(2);
bool pcmEnabled = bs.get(1);
if (pcmEnabled){
bs.skip(8);
bs.getUExpGolomb();
bs.getUExpGolomb();
bs.skip(1);
}
uint64_t shortTermPicSets = bs.getUExpGolomb();
for (int i= 0; i < shortTermPicSets; i++){
skipShortTermRefPicSet(bs, i, shortTermPicSets);
}
bool longTermRefPics = bs.get(1);
if (longTermRefPics){
uint64_t numLongTermPics = bs.getUExpGolomb();
for (int i = 0; i < numLongTermPics; i++){
bs.skip(log2MaxPicOrderCntLsbMinus4 + 4);
bs.skip(1);
}
}
bs.skip(2);
bool vuiParams = bs.get(1);
if (vuiParams){
parseVuiParameters(bs, res);
}
}
std::string spsUnit::toPrettyString(size_t indent){
Utils::bitstream bs;
bs.append(data);
bs.skip(16);//Nal Header
std::stringstream r;
r << std::string(indent, ' ') << "sps_video_parameter_set_id: " << bs.get(4) << std::endl;
unsigned int maxSubLayersMinus1 = bs.get(3);
r << std::string(indent, ' ') << "sps_max_sub_layers_minus1: " << maxSubLayersMinus1 << std::endl;
r << std::string(indent, ' ') << "sps_temporal_id_nesting_flag: " << bs.get(1) << std::endl;
r << std::string(indent, ' ') << "profile_tier_level(): " << std::endl << printProfileTierLevel(bs, maxSubLayersMinus1, indent + 1);
r << std::string(indent, ' ') << "sps_seq_parameter_set_id: " << bs.getUExpGolomb() << std::endl;
uint64_t chromaFormatIdc = bs.getUExpGolomb();
r << std::string(indent, ' ') << "chroma_format_idc: " << chromaFormatIdc << std::endl;
if (chromaFormatIdc == 3){
r << std::string(indent, ' ') << "separate_colour_plane_flag: " << bs.get(1) << std::endl;
}
r << std::string(indent, ' ') << "pic_width_in_luma_samples: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "pic_height_in_luma_samples: " << bs.getUExpGolomb() << std::endl;
bool conformance_window_flag = bs.get(1);
r << std::string(indent, ' ') << "conformance_window_flag: " << conformance_window_flag << std::endl;
if (conformance_window_flag){
r << std::string(indent, ' ') << "conf_window_left_offset: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "conf_window_right_offset: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "conf_window_top_offset: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "conf_window_bottom_offset: " << bs.getUExpGolomb() << std::endl;
}
r << std::string(indent, ' ') << "bit_depth_luma_minus8: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "bit_depth_chroma_minus8: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "log2_max_pic_order_cnt_lsb_minus4: " << bs.getUExpGolomb() << std::endl;
bool subLayerOrdering = bs.get(1);
r << std::string(indent, ' ') << "sps_sub_layer_ordering_info_present_flag: " << subLayerOrdering << std::endl;
for (int i= (subLayerOrdering ? 0 : maxSubLayersMinus1); i <= maxSubLayersMinus1; i++){
r << std::string(indent + 1, ' ') << "sps_max_dec_pic_buffering_minus1[" << i << "]: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent + 1, ' ') << "sps_max_num_reorder_pics[" << i << "]: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent + 1, ' ') << "sps_max_latency_increase_plus1[" << i << "]: " << bs.getUExpGolomb() << std::endl;
}
r << std::string(indent, ' ') << "log2_min_luma_coding_block_size_minus3: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "log2_diff_max_min_luma_coding_block_size: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "log2_min_transform_block_size_minus2: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "log2_diff_max_min_transform_block_size: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "max_transform_hierarchy_depth_inter: " << bs.getUExpGolomb() << std::endl;
r << std::string(indent, ' ') << "max_transform_hierarchy_depth_intra: " << bs.getUExpGolomb() << std::endl;
bool scalingListEnabled = bs.get(1);
r << std::string(indent, ' ') << "scaling_list_enabled_flag: " << scalingListEnabled << std::endl;
if (scalingListEnabled){
WARN_MSG("Not implemented scaling list in HEVC sps");
}
r << std::string(indent, ' ') << "amp_enabled_flag: " << bs.get(1) << std::endl;
r << std::string(indent, ' ') << "sample_adaptive_offset_enabled_flag: " << bs.get(1) << std::endl;
bool pcmEnabled = bs.get(1);
r << std::string(indent, ' ') << "pcm_enabled_flag: " << pcmEnabled << std::endl;
if (pcmEnabled){
WARN_MSG("Not implemented pcm_enabled in HEVC sps");
}
uint64_t shortTermPicSets = bs.getUExpGolomb();
r << std::string(indent, ' ') << "num_short_term_ref_pic_sets: " << shortTermPicSets << std::endl;
for (int i= 0; i < shortTermPicSets; i++){
r << std::string(indent, ' ') << "short_term_ref_pic_set(" << i << "):" << std::endl << printShortTermRefPicSet(bs, i, indent + 1);
}
bool longTermRefPics = bs.get(1);
r << std::string(indent, ' ') << "long_term_ref_pics_present_flag: " << (longTermRefPics ? 1 : 0) << std::endl;
if (longTermRefPics){
WARN_MSG("Implement longTermRefPics");
}
r << std::string(indent, ' ') << "sps_temporal_mvp_enabled_flag: " << bs.get(1) << std::endl;
r << std::string(indent, ' ') << "strong_intra_smoothing_enabled_flag: " << bs.get(1) << std::endl;
bool vuiParams = bs.get(1);
r << std::string(indent, ' ') << "vui_parameters_present_flag: " << (vuiParams ? 1 : 0) << std::endl;
if (vuiParams){
r << std::string(indent, ' ') << "vui_parameters:" << std::endl << printVuiParameters(bs, indent + 1);
}
return r.str();
}
void spsUnit::updateHVCC(MP4::HVCC & hvccBox) { void spsUnit::updateHVCC(MP4::HVCC & hvccBox) {
Utils::bitstream bs; Utils::bitstream bs;
bs.append(data); bs.append(data);

View file

@ -10,14 +10,30 @@
namespace h265 { namespace h265 {
std::deque<nalu::nalData> analysePackets(const char * data, unsigned long len); std::deque<nalu::nalData> analysePackets(const char * data, unsigned long len);
const char * typeToStr(uint8_t type);
bool isKeyframe(const char * data, uint32_t len);
void updateProfileTierLevel(Utils::bitstream & bs, MP4::HVCC & hvccBox, unsigned long maxSubLayersMinus1); void updateProfileTierLevel(Utils::bitstream & bs, MP4::HVCC & hvccBox, unsigned long maxSubLayersMinus1);
std::string printProfileTierLevel(Utils::bitstream & bs, unsigned long maxSubLayersMinus1, size_t indent);
struct metaInfo {
unsigned int width;
unsigned int height;
double fps;
};
class initData { class initData {
public: public:
initData(); initData();
initData(const std::string & hvccData);
void addUnit(char * data); void addUnit(char * data);
void addUnit(const std::string & data);
bool haveRequired(); bool haveRequired();
std::string generateHVCC(); std::string generateHVCC();
metaInfo getMeta();
const std::set<std::string> & getVPS() const;
const std::set<std::string> & getSPS() const;
const std::set<std::string> & getPPS() const;
protected: protected:
std::map<unsigned int, std::set<std::string> > nalUnits; std::map<unsigned int, std::set<std::string> > nalUnits;
}; };
@ -26,6 +42,7 @@ namespace h265 {
public: public:
vpsUnit(const std::string & _data); vpsUnit(const std::string & _data);
void updateHVCC(MP4::HVCC & hvccBox); void updateHVCC(MP4::HVCC & hvccBox);
std::string toPrettyString(size_t indent);
private: private:
std::string data; std::string data;
}; };
@ -34,6 +51,8 @@ namespace h265 {
public: public:
spsUnit(const std::string & _data); spsUnit(const std::string & _data);
void updateHVCC(MP4::HVCC & hvccBox); void updateHVCC(MP4::HVCC & hvccBox);
std::string toPrettyString(size_t indent = 0);
void getMeta(metaInfo & res);
private: private:
std::string data; std::string data;
}; };

View file

@ -1,5 +1,6 @@
#include "mp4_generic.h" #include "mp4_generic.h"
#include "defines.h" #include "defines.h"
#include "h265.h"
namespace MP4 { namespace MP4 {
MFHD::MFHD() { MFHD::MFHD() {
@ -866,7 +867,7 @@ namespace MP4 {
r << std::string(indent + 1, ' ') << "Arrays:" << std::endl; r << std::string(indent + 1, ' ') << "Arrays:" << std::endl;
std::deque<HVCCArrayEntry> arrays = getArrays(); std::deque<HVCCArrayEntry> arrays = getArrays();
for (unsigned int i = 0; i < arrays.size(); i++){ for (unsigned int i = 0; i < arrays.size(); i++){
r << std::string(indent + 2, ' ') << "Array with type " << (int)arrays[i].nalUnitType << std::endl; r << std::string(indent + 2, ' ') << "Array with type " << h265::typeToStr(arrays[i].nalUnitType) << std::endl;
for (unsigned int j = 0; j < arrays[i].nalUnits.size(); j++){ for (unsigned int j = 0; j < arrays[i].nalUnits.size(); j++){
r << std::string(indent + 3, ' ') << "Nal unit of " << arrays[i].nalUnits[j].size() << " bytes" << std::endl; r << std::string(indent + 3, ' ') << "Nal unit of " << arrays[i].nalUnits[j].size() << " bytes" << std::endl;
} }
@ -874,6 +875,11 @@ namespace MP4 {
return r.str(); return r.str();
} }
h265::metaInfo HVCC::getMetaInfo(){
h265::initData init(std::string(payload(), payloadSize()));
return init.getMeta();
}
void HVCC::setPayload(std::string newPayload) { void HVCC::setPayload(std::string newPayload) {
if (!reserve(0, payloadSize(), newPayload.size())) { if (!reserve(0, payloadSize(), newPayload.size())) {
ERROR_MSG("Cannot allocate enough memory for payload"); ERROR_MSG("Cannot allocate enough memory for payload");

View file

@ -1,6 +1,10 @@
#pragma once #pragma once
#include "mp4.h" #include "mp4.h"
namespace h265 {
class metaInfo;
}
namespace MP4 { namespace MP4 {
class MFHD: public Box { class MFHD: public Box {
public: public:
@ -174,6 +178,7 @@ namespace MP4 {
std::string asAnnexB(); std::string asAnnexB();
void setPayload(std::string newPayload); void setPayload(std::string newPayload);
std::string toPrettyString(uint32_t indent = 0); std::string toPrettyString(uint32_t indent = 0);
h265::metaInfo getMetaInfo();
}; };
class Descriptor{ class Descriptor{

View file

@ -192,7 +192,8 @@ namespace TS{
metaInit[pid] = std::string(entry.getESInfo(), entry.getESInfoLength()); metaInit[pid] = std::string(entry.getESInfo(), entry.getESInfoLength());
} }
break; break;
default: break; default:
break;
} }
entry.advance(); entry.advance();
} }
@ -660,9 +661,12 @@ namespace TS{
char typeNal; char typeNal;
isKeyFrame = false; isKeyFrame = false;
typeNal = pesPayload[0] & 0x1F; if (pidToCodec[tid] == MPEG2){
return;
}
if (pidToCodec[tid] == H264){ if (pidToCodec[tid] == H264){
typeNal = pesPayload[0] & 0x1F;
switch (typeNal){ switch (typeNal){
case 0x01:{ case 0x01:{
if (firstSlice){ if (firstSlice){
@ -702,6 +706,7 @@ namespace TS{
default: break; default: break;
} }
}else if (pidToCodec[tid] == H265){ }else if (pidToCodec[tid] == H265){
typeNal = (((pesPayload[0] & 0x7E) >> 1) & 0xFF);
switch (typeNal){ switch (typeNal){
case 2: case 2:
case 3: // TSA Picture case 3: // TSA Picture
@ -723,7 +728,8 @@ namespace TS{
case 32: case 32:
case 33: case 33:
case 34:{ case 34:{
hevcInfo[tid].addUnit((char *)pesPayload); // may i convert to (char *)? tthread::lock_guard<tthread::recursive_mutex> guard(tMutex);
hevcInfo[tid].addUnit(std::string(pesPayload, nextPtr - pesPayload)); // may i convert to (char *)?
break; break;
} }
default: break; default: break;