Added SPS/PPS validation functions, RTP lib now only updates SPS/PPS when valid
This commit is contained in:
		
							parent
							
								
									b1740e9bd3
								
							
						
					
					
						commit
						53698eaa49
					
				
					 3 changed files with 137 additions and 3 deletions
				
			
		
							
								
								
									
										124
									
								
								lib/h264.cpp
									
										
									
									
									
								
							
							
						
						
									
										124
									
								
								lib/h264.cpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -75,6 +75,91 @@ namespace h264{
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool sequenceParameterSet::validate() const{
 | 
			
		||||
    Utils::bitstream bs;
 | 
			
		||||
    for (size_t i = 1; i < dataLen; i++){
 | 
			
		||||
      if (i + 2 < dataLen && (memcmp(data + i, "\000\000\003", 3) == 0)){// Emulation prevention bytes
 | 
			
		||||
        // Yes, we increase i here
 | 
			
		||||
        bs.append(data + i, 2);
 | 
			
		||||
        i += 2;
 | 
			
		||||
      }else{
 | 
			
		||||
        // No we don't increase i here
 | 
			
		||||
        bs.append(data + i, 1);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if (bs.size() < 24){return false;}//static size data
 | 
			
		||||
    char profileIdc = bs.get(8);
 | 
			
		||||
    bs.skip(16);
 | 
			
		||||
    bs.getUExpGolomb();//ID
 | 
			
		||||
    if (profileIdc == 100 || profileIdc == 110 || profileIdc == 122 || profileIdc == 244 ||
 | 
			
		||||
        profileIdc == 44 || profileIdc == 83 || profileIdc == 86 || profileIdc == 118 || profileIdc == 128){
 | 
			
		||||
      // chroma format idc
 | 
			
		||||
      char chromaFormatIdc = bs.getUExpGolomb();
 | 
			
		||||
      if (chromaFormatIdc == 3){bs.get(1);}
 | 
			
		||||
      bs.getUExpGolomb(); // luma
 | 
			
		||||
      bs.getUExpGolomb(); // chroma
 | 
			
		||||
      bs.skip(1);         // transform bypass
 | 
			
		||||
      if (bs.get(1)){// Scaling matrix is present
 | 
			
		||||
        char listSize = (chromaFormatIdc == 3 ? 12 : 8);
 | 
			
		||||
        for (size_t i = 0; i < listSize; i++){
 | 
			
		||||
          bool thisListPresent = bs.get(1);
 | 
			
		||||
          if (thisListPresent){
 | 
			
		||||
            if (i < 6){
 | 
			
		||||
              skipScalingList(bs, 16);
 | 
			
		||||
            }else{
 | 
			
		||||
              skipScalingList(bs, 64);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    bs.getUExpGolomb();
 | 
			
		||||
    size_t cnt_type = bs.getUExpGolomb();
 | 
			
		||||
    if (!cnt_type){
 | 
			
		||||
      bs.getUExpGolomb();
 | 
			
		||||
    }else if (cnt_type == 1){
 | 
			
		||||
      ERROR_MSG("This part of the implementation is incomplete(2), to be continued. If this "
 | 
			
		||||
                "message is shown, contact developers immediately.");
 | 
			
		||||
    }
 | 
			
		||||
    if (!bs.size()){return false;}
 | 
			
		||||
    bs.getUExpGolomb(); // max_num_ref_frames
 | 
			
		||||
    bs.get(1);
 | 
			
		||||
    bs.getUExpGolomb();
 | 
			
		||||
    bs.getUExpGolomb();
 | 
			
		||||
    if (!bs.size()){return false;}
 | 
			
		||||
    bool mbs_only = (bs.get(1) == 1); // Gets used in height calculation
 | 
			
		||||
    if (!mbs_only){bs.skip(1);}
 | 
			
		||||
    bs.skip(1);
 | 
			
		||||
    // cropping flag
 | 
			
		||||
    if (bs.get(1)){
 | 
			
		||||
      bs.getUExpGolomb();  // leftOffset
 | 
			
		||||
      bs.getUExpGolomb(); // rightOffset
 | 
			
		||||
      bs.getUExpGolomb();    // topOffset
 | 
			
		||||
      bs.getUExpGolomb();   // bottomOffset
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!bs.size()){return false;}
 | 
			
		||||
    if (bs.get(1)){
 | 
			
		||||
      if (bs.get(1)){bs.skip(8);}
 | 
			
		||||
      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();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Decode timing info
 | 
			
		||||
      if (!bs.size()){return false;}
 | 
			
		||||
      if (bs.get(1)){
 | 
			
		||||
        return (bs.size() >= 65);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  SPSMeta sequenceParameterSet::getCharacteristics() const{
 | 
			
		||||
    SPSMeta result;
 | 
			
		||||
    result.sep_col_plane = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -662,6 +747,45 @@ namespace h264{
 | 
			
		|||
      lastScale = scalingList[i];
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool ppsValidate(const char *data, size_t len){
 | 
			
		||||
    Utils::bitstream bs;
 | 
			
		||||
    for (size_t i = 1; i < len; i++){
 | 
			
		||||
      if (i + 2 < len && (memcmp(data + i, "\000\000\003", 3) == 0)){// Emulation prevention bytes
 | 
			
		||||
        // Yes, we increase i here
 | 
			
		||||
        bs.append(data + i, 2);
 | 
			
		||||
        i += 2;
 | 
			
		||||
      }else{
 | 
			
		||||
        // No we don't increase i here
 | 
			
		||||
        bs.append(data + i, 1);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    bs.getUExpGolomb();
 | 
			
		||||
    bs.getUExpGolomb();
 | 
			
		||||
    bs.get(2);
 | 
			
		||||
    if (bs.getUExpGolomb() > 0){
 | 
			
		||||
      WARN_MSG("num_slice_groups_minus1 > 0, unimplemented structure");
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    bs.getUExpGolomb();
 | 
			
		||||
    bs.getUExpGolomb();
 | 
			
		||||
    bs.get(3);
 | 
			
		||||
    bs.getExpGolomb();
 | 
			
		||||
    bs.getExpGolomb();
 | 
			
		||||
    bs.getExpGolomb();
 | 
			
		||||
    bs.get(2);
 | 
			
		||||
    if (!bs.size()){return false;}
 | 
			
		||||
    bs.get(1);
 | 
			
		||||
    if (!more_rbsp_data(bs)){return true;}
 | 
			
		||||
    bs.get(1);
 | 
			
		||||
    if (bs.get(1)){
 | 
			
		||||
      //tricky scaling stuff, assume we're good.
 | 
			
		||||
      /// \TODO Maybe implement someday? Do we care? Doubt.
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    return bs.size();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ppsUnit::ppsUnit(const char *data, size_t len, uint8_t chromaFormatIdc) : nalUnit(data, len){
 | 
			
		||||
    picScalingMatrixPresentFlags = NULL;
 | 
			
		||||
    Utils::bitstream bs;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -67,6 +67,7 @@ namespace h264{
 | 
			
		|||
    sequenceParameterSet(const char *_data = NULL, size_t _dataLen = 0);
 | 
			
		||||
    void fromDTSCInit(const std::string &dtscInit);
 | 
			
		||||
    SPSMeta getCharacteristics() const;
 | 
			
		||||
    bool validate() const;
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    const char *data;
 | 
			
		||||
| 
						 | 
				
			
			@ -234,6 +235,7 @@ namespace h264{
 | 
			
		|||
    size_t derived_scalingList4x4Amount;
 | 
			
		||||
    size_t derived_scalingList8x8Amount;
 | 
			
		||||
  };
 | 
			
		||||
  bool ppsValidate(const char *data, size_t len);
 | 
			
		||||
  class ppsUnit : public nalUnit{
 | 
			
		||||
  public:
 | 
			
		||||
    ppsUnit(const char *data, size_t len, uint8_t chromaFormatIdc = 0);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										14
									
								
								lib/rtp.cpp
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								lib/rtp.cpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1017,9 +1017,13 @@ namespace RTP{
 | 
			
		|||
      return;
 | 
			
		||||
    case 7: // SPS
 | 
			
		||||
      if (spsData.size() != len - 4 || memcmp(buffer + 4, spsData.data(), len - 4) != 0){
 | 
			
		||||
        HIGH_MSG("Updated SPS from RTP data");
 | 
			
		||||
        h264::sequenceParameterSet sps(buffer + 4, len - 4);
 | 
			
		||||
        if (!sps.validate()){
 | 
			
		||||
          WARN_MSG("Ignoring invalid SPS packet! (%" PRIu32 "b)", len-4);
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        HIGH_MSG("Updated SPS from RTP data: %" PRIu32 "b", len-4);
 | 
			
		||||
        spsData.assign(buffer + 4, len - 4);
 | 
			
		||||
        h264::sequenceParameterSet sps(spsData.data(), spsData.size());
 | 
			
		||||
        h264::SPSMeta hMeta = sps.getCharacteristics();
 | 
			
		||||
        fps = hMeta.fps;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1041,7 +1045,11 @@ namespace RTP{
 | 
			
		|||
      return;
 | 
			
		||||
    case 8: // PPS
 | 
			
		||||
      if (ppsData.size() != len - 4 || memcmp(buffer + 4, ppsData.data(), len - 4) != 0){
 | 
			
		||||
        HIGH_MSG("Updated PPS from RTP data");
 | 
			
		||||
        if (!h264::ppsValidate(buffer+4, len-4)){
 | 
			
		||||
          WARN_MSG("Ignoring invalid PPS packet! (%" PRIu32 "b)", len-4);
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        HIGH_MSG("Updated PPS from RTP data: %" PRIu32 "b", len-4);
 | 
			
		||||
        ppsData.assign(buffer + 4, len - 4);
 | 
			
		||||
        MP4::AVCC avccBox;
 | 
			
		||||
        avccBox.setVersion(1);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue