/*---------------------------------------------------------------------- | AP4_AvccAtom::Create +---------------------------------------------------------------------*/ AP4_AvccAtom* AP4_AvccAtom::Create(AP4_Size size, AP4_ByteStream& stream) { // read the raw bytes in a buffer unsigned int payload_size = size-AP4_ATOM_HEADER_SIZE; AP4_DataBuffer payload_data(payload_size); AP4_Result result = stream.Read(payload_data.UseData(), payload_size); if (AP4_FAILED(result)) return NULL; // check the version const AP4_UI08* payload = payload_data.GetData(); if (payload[0] != 1) { return NULL; } // check the size if (payload_size < 6) return NULL; unsigned int num_seq_params = payload[5]&31; unsigned int cursor = 6; for (unsigned int i=0; i<num_seq_params; i++) { if (cursor+2 > payload_size) return NULL; cursor += 2+AP4_BytesToInt16BE(&payload[cursor]); if (cursor > payload_size) return NULL; } unsigned int num_pic_params = payload[cursor++]; if (cursor > payload_size) return NULL; for (unsigned int i=0; i<num_pic_params; i++) { if (cursor+2 > payload_size) return NULL; cursor += 2+AP4_BytesToInt16BE(&payload[cursor]); if (cursor > payload_size) return NULL; } return new AP4_AvccAtom(size, payload); }
/*---------------------------------------------------------------------- | AP4_AvccAtom::AP4_AvccAtom +---------------------------------------------------------------------*/ AP4_AvccAtom::AP4_AvccAtom(AP4_UI32 size, const AP4_UI08* payload) : AP4_Atom(AP4_ATOM_TYPE_AVCC, size) { // make a copy of our configuration bytes unsigned int payload_size = size-AP4_ATOM_HEADER_SIZE; m_RawBytes.SetData(payload, payload_size); // parse the payload m_ConfigurationVersion = payload[0]; m_Profile = payload[1]; m_ProfileCompatibility = payload[2]; m_Level = payload[3]; m_NaluLengthSize = 1+(payload[4]&3); AP4_UI08 num_seq_params = payload[5]&31; m_SequenceParameters.EnsureCapacity(num_seq_params); unsigned int cursor = 6; for (unsigned int i=0; i<num_seq_params; i++) { m_SequenceParameters.Append(AP4_DataBuffer()); AP4_UI16 param_length = AP4_BytesToInt16BE(&payload[cursor]); m_SequenceParameters[i].SetData(&payload[cursor]+2, param_length); cursor += 2+param_length; } AP4_UI08 num_pic_params = payload[cursor++]; m_PictureParameters.EnsureCapacity(num_pic_params); for (unsigned int i=0; i<num_pic_params; i++) { m_PictureParameters.Append(AP4_DataBuffer()); AP4_UI16 param_length = AP4_BytesToInt16BE(&payload[cursor]); m_PictureParameters[i].SetData(&payload[cursor]+2, param_length); cursor += 2+param_length; } }
virtual void UpdatePPSId(AP4_DataBuffer const &buffer) override { //Search the Slice header NALU const AP4_UI08 *data(buffer.GetData()); unsigned int data_size(buffer.GetDataSize()); for (; data_size;) { // sanity check if (data_size < naluLengthSize) break; // get the next NAL unit AP4_UI32 nalu_size; switch (naluLengthSize) { case 1:nalu_size = *data++; data_size--; break; case 2:nalu_size = AP4_BytesToInt16BE(data); data += 2; data_size -= 2; break; case 4:nalu_size = AP4_BytesToInt32BE(data); data += 4; data_size -= 4; break; default: data_size = 0; nalu_size = 1; break; } if (nalu_size > data_size) break; // Stop further NALU processing if (countPictureSetIds < 2) naluLengthSize = 0; unsigned int nal_unit_type = *data & 0x1F; if ( //nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_NON_IDR_PICTURE || nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_IDR_PICTURE //|| //nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_A || //nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_B || //nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_C ) { AP4_DataBuffer unescaped(data, data_size); AP4_NalParser::Unescape(unescaped); AP4_BitReader bits(unescaped.GetData(), unescaped.GetDataSize()); bits.SkipBits(8); // NAL Unit Type AP4_AvcFrameParser::ReadGolomb(bits); // first_mb_in_slice AP4_AvcFrameParser::ReadGolomb(bits); // slice_type pictureId = AP4_AvcFrameParser::ReadGolomb(bits); //picture_set_id } // move to the next NAL unit data += nalu_size; data_size -= nalu_size; } }
/*---------------------------------------------------------------------- | WriteSample +---------------------------------------------------------------------*/ static void WriteSample(const AP4_DataBuffer& sample_data, AP4_DataBuffer& prefix, unsigned int nalu_length_size, AP4_ByteStream* output) { const unsigned char* data = sample_data.GetData(); unsigned int data_size = sample_data.GetDataSize(); // detect if we have VPS/SPS/PPS and/or AUD NAL units already bool have_param_sets = false; bool have_access_unit_delimiter = false; while (data_size) { // sanity check if (data_size < nalu_length_size) break; // get the next NAL unit AP4_UI32 nalu_size; if (nalu_length_size == 1) { nalu_size = *data++; data_size--; } else if (nalu_length_size == 2) { nalu_size = AP4_BytesToInt16BE(data); data += 2; data_size -= 2; } else if (nalu_length_size == 4) { nalu_size = AP4_BytesToInt32BE(data); data += 4; data_size -= 4; } else { break; } if (nalu_size > data_size) break; unsigned int nal_unit_type = (data[0]>>1)&0x3F; if (nal_unit_type == AP4_HEVC_NALU_TYPE_AUD_NUT) { have_access_unit_delimiter = true; } if (nal_unit_type == AP4_HEVC_NALU_TYPE_VPS_NUT || nal_unit_type == AP4_HEVC_NALU_TYPE_SPS_NUT || nal_unit_type == AP4_HEVC_NALU_TYPE_PPS_NUT) { have_param_sets = true; break; } // move to the next NAL unit data += nalu_size; data_size -= nalu_size; } data = sample_data.GetData(); data_size = sample_data.GetDataSize(); // allocate a buffer for the frame data AP4_DataBuffer frame_data; unsigned char* frame_buffer = NULL; // add a delimiter if we don't already have one if (data_size && !have_access_unit_delimiter) { AP4_Size frame_data_size = frame_data.GetDataSize(); frame_data.SetDataSize(frame_data_size+7); frame_buffer = frame_data.UseData()+frame_data_size; // start of access unit frame_buffer[0] = 0; frame_buffer[1] = 0; frame_buffer[2] = 0; frame_buffer[3] = 1; frame_buffer[4] = AP4_HEVC_NALU_TYPE_AUD_NUT<<1; frame_buffer[5] = 1; frame_buffer[6] = 0x40; // pic_type = 2 (B,P,I) } // write the NAL units bool prefix_added = false; while (data_size) { // sanity check if (data_size < nalu_length_size) break; // get the next NAL unit AP4_UI32 nalu_size; if (nalu_length_size == 1) { nalu_size = *data++; data_size--; } else if (nalu_length_size == 2) { nalu_size = AP4_BytesToInt16BE(data); data += 2; data_size -= 2; } else if (nalu_length_size == 4) { nalu_size = AP4_BytesToInt32BE(data); data += 4; data_size -= 4; } else { break; } if (nalu_size > data_size) break; // add the prefix if needed if (!have_param_sets && !prefix_added && !have_access_unit_delimiter) { AP4_Size frame_data_size = frame_data.GetDataSize(); frame_data.SetDataSize(frame_data_size+prefix.GetDataSize()); frame_buffer = frame_data.UseData()+frame_data_size; AP4_CopyMemory(frame_buffer, prefix.GetData(), prefix.GetDataSize()); prefix_added = true; } // add a start code before the NAL unit AP4_Size frame_data_size = frame_data.GetDataSize(); frame_data.SetDataSize(frame_data_size+3+nalu_size); frame_buffer = frame_data.UseData()+frame_data_size; frame_buffer[0] = 0; frame_buffer[1] = 0; frame_buffer[2] = 1; AP4_CopyMemory(frame_buffer+3, data, nalu_size); // add the prefix if needed if (!have_param_sets && !prefix_added) { AP4_Size frame_data_size = frame_data.GetDataSize(); frame_data.SetDataSize(frame_data_size+prefix.GetDataSize()); frame_buffer = frame_data.UseData()+frame_data_size; AP4_CopyMemory(frame_buffer, prefix.GetData(), prefix.GetDataSize()); prefix_added = true; } // move to the next NAL unit data += nalu_size; data_size -= nalu_size; } output->Write(frame_data.GetData(), frame_data.GetDataSize()); }
/*---------------------------------------------------------------------- | WriteSample +---------------------------------------------------------------------*/ static void WriteSample(const AP4_DataBuffer& sample_data, AP4_DataBuffer& prefix, unsigned int nalu_length_size, AP4_ByteStream* output) { const unsigned char* data = sample_data.GetData(); unsigned int data_size = sample_data.GetDataSize(); // allocate a buffer for the PES packet AP4_DataBuffer frame_data; unsigned char* frame_buffer = NULL; // add a delimiter if we don't already have one bool have_access_unit_delimiter = (data_size > nalu_length_size) && ((data[nalu_length_size] & 0x1F) == AP4_AVC_NAL_UNIT_TYPE_ACCESS_UNIT_DELIMITER); if (!have_access_unit_delimiter) { AP4_Size frame_data_size = frame_data.GetDataSize(); frame_data.SetDataSize(frame_data_size+6); frame_buffer = frame_data.UseData()+frame_data_size; // start of access unit frame_buffer[0] = 0; frame_buffer[1] = 0; frame_buffer[2] = 0; frame_buffer[3] = 1; frame_buffer[4] = 9; // NAL type = Access Unit Delimiter; frame_buffer[5] = 0xE0; // Slice types = ANY } // write the NAL units bool prefix_added = false; while (data_size) { // sanity check if (data_size < nalu_length_size) break; // get the next NAL unit AP4_UI32 nalu_size; if (nalu_length_size == 1) { nalu_size = *data++; data_size--; } else if (nalu_length_size == 2) { nalu_size = AP4_BytesToInt16BE(data); data += 2; data_size -= 2; } else if (nalu_length_size == 4) { nalu_size = AP4_BytesToInt32BE(data); data += 4; data_size -= 4; } else { break; } if (nalu_size > data_size) break; // add the prefix if needed if (prefix.GetDataSize() && !prefix_added && !have_access_unit_delimiter) { AP4_Size frame_data_size = frame_data.GetDataSize(); frame_data.SetDataSize(frame_data_size+prefix.GetDataSize()); frame_buffer = frame_data.UseData()+frame_data_size; AP4_CopyMemory(frame_buffer, prefix.GetData(), prefix.GetDataSize()); prefix_added = true; } // add a start code before the NAL unit AP4_Size frame_data_size = frame_data.GetDataSize(); frame_data.SetDataSize(frame_data_size+3+nalu_size); frame_buffer = frame_data.UseData()+frame_data_size; frame_buffer[0] = 0; frame_buffer[1] = 0; frame_buffer[2] = 1; AP4_CopyMemory(frame_buffer+3, data, nalu_size); // add the prefix if needed if (prefix.GetDataSize() && !prefix_added) { AP4_Size frame_data_size = frame_data.GetDataSize(); frame_data.SetDataSize(frame_data_size+prefix.GetDataSize()); frame_buffer = frame_data.UseData()+frame_data_size; AP4_CopyMemory(frame_buffer, prefix.GetData(), prefix.GetDataSize()); prefix_added = true; } // move to the next NAL unit data += nalu_size; data_size -= nalu_size; } output->Write(frame_data.GetData(), frame_data.GetDataSize()); }