342 lines
		
	
	
	
		
			9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			342 lines
		
	
	
	
		
			9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "h265.h"
 | |
| #include "bitfields.h"
 | |
| #include "defines.h"
 | |
| 
 | |
| namespace h265 {
 | |
|   std::deque<nalu::nalData> analysePackets(const char * data, unsigned long len){
 | |
|     std::deque<nalu::nalData> res;
 | |
| 
 | |
|     int offset = 0;
 | |
|     while (offset < len){
 | |
|       nalu::nalData entry;
 | |
|       entry.nalSize = Bit::btohl(data + offset);
 | |
|       entry.nalType = ((data + offset)[4] & 0x7E) >> 1;
 | |
|       res.push_back(entry);
 | |
|       offset += entry.nalSize + 4;
 | |
|     }
 | |
|     return res;
 | |
|   }
 | |
| 
 | |
|   initData::initData() {}
 | |
| 
 | |
|   void initData::addUnit(char * data) {
 | |
|     unsigned long nalSize = Bit::btohl(data);
 | |
|     unsigned long nalType = (data[4] & 0x7E) >> 1;
 | |
|     switch (nalType) {
 | |
|       case 32: //vps
 | |
|       case 33: //sps
 | |
|       case 34: //pps
 | |
|         nalUnits[nalType].insert(std::string(data + 4, nalSize));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   bool initData::haveRequired() {
 | |
|     return (nalUnits.count(32) && nalUnits.count(33) && nalUnits.count(34));
 | |
|   }
 | |
|   
 | |
|   std::string initData::generateHVCC(){
 | |
|     MP4::HVCC hvccBox;
 | |
|     hvccBox.setConfigurationVersion(1);
 | |
|     hvccBox.setParallelismType(0);
 | |
|     std::set<std::string>::iterator nalIt;
 | |
| 
 | |
|     //We first loop over all VPS Units
 | |
|     for (nalIt = nalUnits[32].begin(); nalIt != nalUnits[32].end(); nalIt++){
 | |
|       vpsUnit vps(*nalIt);
 | |
|       vps.updateHVCC(hvccBox);
 | |
|     }
 | |
|     for (nalIt = nalUnits[33].begin(); nalIt != nalUnits[33].end(); nalIt++){
 | |
|       spsUnit sps(*nalIt);
 | |
|       sps.updateHVCC(hvccBox);
 | |
|     }
 | |
|     //NOTE: We dont parse the ppsUnit, as the only information it contains is parallelism mode, which is set to 0 for 'unknown'
 | |
|     std::deque<MP4::HVCCArrayEntry> hvccArrays;
 | |
|     hvccArrays.resize(3);
 | |
|     hvccArrays[0].arrayCompleteness = 0;
 | |
|     hvccArrays[0].nalUnitType = 32;
 | |
|     for (nalIt = nalUnits[32].begin(); nalIt != nalUnits[32].end(); nalIt++){
 | |
|       hvccArrays[0].nalUnits.push_back(*nalIt);
 | |
|     }
 | |
|     hvccArrays[1].arrayCompleteness = 0;
 | |
|     hvccArrays[1].nalUnitType = 33;
 | |
|     for (nalIt = nalUnits[33].begin(); nalIt != nalUnits[33].end(); nalIt++){
 | |
|       hvccArrays[1].nalUnits.push_back(*nalIt);
 | |
|     }
 | |
|     hvccArrays[2].arrayCompleteness = 0;
 | |
|     hvccArrays[2].nalUnitType = 34;
 | |
|     for (nalIt = nalUnits[34].begin(); nalIt != nalUnits[34].end(); nalIt++){
 | |
|       hvccArrays[2].nalUnits.push_back(*nalIt);
 | |
|     }
 | |
|     hvccBox.setArrays(hvccArrays);
 | |
|     hvccBox.setLengthSizeMinus1(3);
 | |
|     return std::string(hvccBox.payload(), hvccBox.payloadSize());
 | |
|   }
 | |
| 
 | |
|   void updateProfileTierLevel(Utils::bitstream & bs, MP4::HVCC & hvccBox, unsigned int maxSubLayersMinus1){
 | |
|     hvccBox.setGeneralProfileSpace(bs.get(2));
 | |
| 
 | |
|     unsigned int tierFlag = bs.get(1);
 | |
|     hvccBox.setGeneralProfileIdc(std::max((unsigned long long)hvccBox.getGeneralProfileIdc(), bs.get(5)));
 | |
|     hvccBox.setGeneralProfileCompatibilityFlags(hvccBox.getGeneralProfileCompatibilityFlags() & bs.get(32));
 | |
|     hvccBox.setGeneralConstraintIndicatorFlags(hvccBox.getGeneralConstraintIndicatorFlags() & bs.get(48));
 | |
|     unsigned int levelIdc = bs.get(8);
 | |
| 
 | |
|     if (tierFlag && !hvccBox.getGeneralTierFlag()) {
 | |
|       hvccBox.setGeneralLevelIdc(levelIdc);
 | |
|     }else {
 | |
|       hvccBox.setGeneralLevelIdc(std::max((unsigned int)hvccBox.getGeneralLevelIdc(),levelIdc));
 | |
|     }
 | |
|     hvccBox.setGeneralTierFlag(tierFlag || hvccBox.getGeneralTierFlag());
 | |
| 
 | |
| 
 | |
|     //Remainder is for synchronsation of the parser
 | |
|     std::deque<bool> profilePresent;
 | |
|     std::deque<bool> levelPresent;
 | |
| 
 | |
|     for (int 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(32);
 | |
|         bs.skip(32);
 | |
|         bs.skip(24);
 | |
|       }
 | |
|       if (levelPresent[i]){
 | |
|         bs.skip(8);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   vpsUnit::vpsUnit(const std::string & _data){
 | |
|     data = nalu::removeEmulationPrevention(_data);
 | |
|   }
 | |
| 
 | |
|   void vpsUnit::updateHVCC(MP4::HVCC & hvccBox) {
 | |
|     Utils::bitstream bs;
 | |
|     bs.append(data);
 | |
|     bs.skip(16);//Nal Header
 | |
|     bs.skip(12);
 | |
| 
 | |
|     unsigned int maxSubLayers = bs.get(3) + 1;
 | |
| 
 | |
|     hvccBox.setNumberOfTemporalLayers(std::max((unsigned int)hvccBox.getNumberOfTemporalLayers(), maxSubLayers));
 | |
| 
 | |
|     bs.skip(17);
 | |
| 
 | |
|     updateProfileTierLevel(bs, hvccBox, maxSubLayers - 1);
 | |
|   }
 | |
| 
 | |
|   spsUnit::spsUnit(const std::string & _data){
 | |
|     data = nalu::removeEmulationPrevention(_data);
 | |
|   }
 | |
| 
 | |
|   void spsUnit::updateHVCC(MP4::HVCC & hvccBox) {
 | |
|     Utils::bitstream bs;
 | |
|     bs.append(data);
 | |
|     bs.skip(16);//Nal Header
 | |
|     bs.skip(4);
 | |
| 
 | |
|     unsigned int maxSubLayers = bs.get(3) + 1;
 | |
| 
 | |
|     hvccBox.setNumberOfTemporalLayers(std::max((unsigned int)hvccBox.getNumberOfTemporalLayers(), maxSubLayers));
 | |
|     hvccBox.setTemporalIdNested(bs.get(1));
 | |
|     updateProfileTierLevel(bs, hvccBox, maxSubLayers - 1);
 | |
| 
 | |
|     bs.getUExpGolomb();
 | |
| 
 | |
|     hvccBox.setChromaFormat(bs.getUExpGolomb());
 | |
| 
 | |
|     if (hvccBox.getChromaFormat() == 3){
 | |
|       bs.skip(1);
 | |
|     }
 | |
| 
 | |
|     bs.getUExpGolomb();
 | |
|     bs.getUExpGolomb();
 | |
|     
 | |
|     if (bs.get(1)){
 | |
|       bs.getUExpGolomb();
 | |
|       bs.getUExpGolomb();
 | |
|       bs.getUExpGolomb();
 | |
|       bs.getUExpGolomb();
 | |
|     }
 | |
| 
 | |
|     hvccBox.setBitDepthLumaMinus8(bs.getUExpGolomb());
 | |
|     hvccBox.setBitDepthChromaMinus8(bs.getUExpGolomb());
 | |
| 
 | |
|     int log2MaxPicOrderCntLsb = bs.getUExpGolomb() + 4;
 | |
| 
 | |
|     for (int i = bs.get(1) ? 0 : (maxSubLayers - 1); i < maxSubLayers; i++){
 | |
|       bs.getUExpGolomb();
 | |
|       bs.getUExpGolomb();
 | |
|       bs.getUExpGolomb();
 | |
|     }
 | |
| 
 | |
|     bs.getUExpGolomb();
 | |
|     bs.getUExpGolomb();
 | |
|     bs.getUExpGolomb();
 | |
|     bs.getUExpGolomb();
 | |
|     bs.getUExpGolomb();
 | |
|     bs.getUExpGolomb();
 | |
| 
 | |
|     if (bs.get(1) && bs.get(1)){
 | |
|       for (int i = 0; i < 4; i++){
 | |
|         for (int j = 0; j < (i == 3 ? 2 : 6); j++){
 | |
|           if (!bs.get(1)){
 | |
|             bs.getUExpGolomb();
 | |
|           }else{
 | |
|             int numCoeffs = std::min(64, 1 << (4 + (i << 1)));
 | |
|             if (i > 1){
 | |
|               bs.getExpGolomb();
 | |
|             }
 | |
| 
 | |
|             for (int k = 0; k < numCoeffs; k++){
 | |
|               bs.getExpGolomb();
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     bs.skip(2);
 | |
| 
 | |
|     if (bs.get(1)){
 | |
|       bs.skip(8);
 | |
|       bs.getUExpGolomb();
 | |
|       bs.getUExpGolomb();
 | |
|       bs.skip(1);
 | |
|     }
 | |
| 
 | |
|     unsigned long long shortTermRefPicSets = bs.getUExpGolomb();
 | |
|     for (int i = 0; i < shortTermRefPicSets; i++){
 | |
|       //parse rps, return if ret < 0
 | |
|     }
 | |
| 
 | |
|     if (bs.get(1)){
 | |
|       if (log2MaxPicOrderCntLsb > 16){
 | |
|         log2MaxPicOrderCntLsb = 16;
 | |
|       }
 | |
|       int numLongTermRefPicsSps = bs.getUExpGolomb();
 | |
|       for (int i = 0; i < numLongTermRefPicsSps; i++){
 | |
|         bs.skip(log2MaxPicOrderCntLsb + 1);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     bs.skip(2);
 | |
| 
 | |
|     if (bs.get(1)){
 | |
|       //parse vui
 | |
|       if (bs.get(1) && bs.get(8) == 255){ bs.skip(32); }
 | |
| 
 | |
|       if (bs.get(1)){ bs.skip(1); }
 | |
| 
 | |
|       if (bs.get(1)){
 | |
|         bs.skip(4);
 | |
|         if (bs.get(1)){ bs.skip(24); }
 | |
|       }
 | |
| 
 | |
|       if (bs.get(1)){
 | |
|         bs.getUExpGolomb();
 | |
|         bs.getUExpGolomb();
 | |
|       }
 | |
| 
 | |
|       bs.skip(3);
 | |
|       
 | |
|       if (bs.get(1)){
 | |
|         bs.getUExpGolomb();
 | |
|         bs.getUExpGolomb();
 | |
|         bs.getUExpGolomb();
 | |
|         bs.getUExpGolomb();
 | |
|       }
 | |
| 
 | |
|       if (bs.get(1)){
 | |
|         bs.skip(32);
 | |
|         bs.skip(32);
 | |
|         if (bs.get(1)){
 | |
|           bs.getUExpGolomb();
 | |
|         }
 | |
|         if (bs.get(1)){
 | |
|           int nalHrd = bs.get(1);
 | |
|           int vclHrd = bs.get(1);
 | |
|           int subPicPresent = 0;
 | |
|           if (nalHrd || vclHrd){
 | |
|             subPicPresent = bs.get(1);
 | |
|             if (subPicPresent){
 | |
|               bs.skip(19);
 | |
|             }
 | |
|             bs.skip(8);
 | |
|             if (subPicPresent){
 | |
|               bs.skip(4);
 | |
|             }
 | |
|             bs.skip(15);
 | |
|           }
 | |
| 
 | |
|           //
 | |
|           for (int i = 0; i < maxSubLayers; i++){
 | |
|             int cpbCnt = 1;
 | |
|             int lowDelay = 0;
 | |
|             int fixedRateCvs = 0;
 | |
|             int fixedRateGeneral = bs.get(1);
 | |
| 
 | |
|             if (fixedRateGeneral){
 | |
|               fixedRateCvs = bs.get(1);
 | |
|             }
 | |
| 
 | |
|             if (fixedRateCvs){
 | |
|               bs.getUExpGolomb();
 | |
|             }else{
 | |
|               lowDelay = bs.get(1);
 | |
|             }
 | |
| 
 | |
|             if (!lowDelay){
 | |
|               cpbCnt = bs.getUExpGolomb() + 1;
 | |
|             }
 | |
| 
 | |
|             if (nalHrd){
 | |
|               for (int i = 0; i < cpbCnt; i++){
 | |
|                 bs.getUExpGolomb();
 | |
|                 bs.getUExpGolomb();
 | |
|                 if (subPicPresent){
 | |
|                   bs.getUExpGolomb();
 | |
|                   bs.getUExpGolomb();
 | |
|                 }
 | |
|                 bs.skip(1);
 | |
|               }
 | |
|             }
 | |
| 
 | |
|             if (vclHrd){
 | |
|               for (int i = 0; i < cpbCnt; i++){
 | |
|                 bs.getUExpGolomb();
 | |
|                 bs.getUExpGolomb();
 | |
|                 if (subPicPresent){
 | |
|                   bs.getUExpGolomb();
 | |
|                   bs.getUExpGolomb();
 | |
|                 }
 | |
|                 bs.skip(1);
 | |
|               }
 | |
|             }
 | |
| 
 | |
|           }
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (bs.get(1)){
 | |
|         bs.skip(3);
 | |
|         int spatialSegmentIdc = bs.getUExpGolomb();
 | |
|         hvccBox.setMinSpatialSegmentationIdc(std::min((int)hvccBox.getMinSpatialSegmentationIdc(),spatialSegmentIdc));
 | |
|         bs.getUExpGolomb();
 | |
|         bs.getUExpGolomb();
 | |
|         bs.getUExpGolomb();
 | |
|         bs.getUExpGolomb();
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | 
