mirror of
https://github.com/axiomatic-systems/Bento4.git
synced 2026-01-19 00:05:12 +08:00
398 lines
17 KiB
C++
398 lines
17 KiB
C++
/*****************************************************************
|
|
|
|
|
| AP4 - hvcC Atoms
|
|
|
|
|
| Copyright 2002-2016 Axiomatic Systems, LLC
|
|
|
|
|
|
|
|
| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
|
|
|
|
|
| Unless you have obtained Bento4 under a difference license,
|
|
| this version of Bento4 is Bento4|GPL.
|
|
| Bento4|GPL is free software; you can redistribute it and/or modify
|
|
| it under the terms of the GNU General Public License as published by
|
|
| the Free Software Foundation; either version 2, or (at your option)
|
|
| any later version.
|
|
|
|
|
| Bento4|GPL is distributed in the hope that it will be useful,
|
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
| GNU General Public License for more details.
|
|
|
|
|
| You should have received a copy of the GNU General Public License
|
|
| along with Bento4|GPL; see the file COPYING. If not, write to the
|
|
| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
|
| 02111-1307, USA.
|
|
|
|
|
****************************************************************/
|
|
|
|
/*----------------------------------------------------------------------
|
|
| includes
|
|
+---------------------------------------------------------------------*/
|
|
#include "Ap4HvccAtom.h"
|
|
#include "Ap4AtomFactory.h"
|
|
#include "Ap4Utils.h"
|
|
#include "Ap4Types.h"
|
|
#include "Ap4HevcParser.h"
|
|
|
|
/*----------------------------------------------------------------------
|
|
| dynamic cast support
|
|
+---------------------------------------------------------------------*/
|
|
AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_HvccAtom)
|
|
|
|
/*----------------------------------------------------------------------
|
|
| AP4_HvccAtom::GetProfileName
|
|
+---------------------------------------------------------------------*/
|
|
const char*
|
|
AP4_HvccAtom::GetProfileName(AP4_UI08 profile_space, AP4_UI08 profile)
|
|
{
|
|
if (profile_space != 0) {
|
|
return NULL;
|
|
}
|
|
switch (profile) {
|
|
case AP4_HEVC_PROFILE_MAIN: return "Main";
|
|
case AP4_HEVC_PROFILE_MAIN_10: return "Main 10";
|
|
case AP4_HEVC_PROFILE_MAIN_STILL_PICTURE: return "Main Still Picture";
|
|
case AP4_HEVC_PROFILE_REXT: return "Rext";
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
| AP4_HvccAtom::GetChromaFormatName
|
|
+---------------------------------------------------------------------*/
|
|
const char*
|
|
AP4_HvccAtom::GetChromaFormatName(AP4_UI08 chroma_format)
|
|
{
|
|
switch (chroma_format) {
|
|
case AP4_HEVC_CHROMA_FORMAT_MONOCHROME: return "Monochrome";
|
|
case AP4_HEVC_CHROMA_FORMAT_420: return "4:2:0";
|
|
case AP4_HEVC_CHROMA_FORMAT_422: return "4:2:2";
|
|
case AP4_HEVC_CHROMA_FORMAT_444: return "4:4:4";
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
| AP4_AvccAtom::Create
|
|
+---------------------------------------------------------------------*/
|
|
AP4_HvccAtom*
|
|
AP4_HvccAtom::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;
|
|
|
|
return new AP4_HvccAtom(size, payload_data.GetData());
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
| AP4_HvccAtom::AP4_HvccAtom
|
|
+---------------------------------------------------------------------*/
|
|
AP4_HvccAtom::AP4_HvccAtom() :
|
|
AP4_Atom(AP4_ATOM_TYPE_HVCC, AP4_ATOM_HEADER_SIZE),
|
|
m_ConfigurationVersion(1),
|
|
m_GeneralProfileSpace(0),
|
|
m_GeneralTierFlag(0),
|
|
m_GeneralProfile(0),
|
|
m_GeneralProfileCompatibilityFlags(0),
|
|
m_GeneralConstraintIndicatorFlags(0),
|
|
m_GeneralLevel(0),
|
|
m_Reserved1(0),
|
|
m_MinSpatialSegmentation(0),
|
|
m_Reserved2(0),
|
|
m_ParallelismType(0),
|
|
m_Reserved3(0),
|
|
m_ChromaFormat(0),
|
|
m_Reserved4(0),
|
|
m_LumaBitDepth(8),
|
|
m_Reserved5(0),
|
|
m_ChromaBitDepth(8),
|
|
m_AverageFrameRate(0),
|
|
m_ConstantFrameRate(0),
|
|
m_NumTemporalLayers(0),
|
|
m_TemporalIdNested(0),
|
|
m_NaluLengthSize(4)
|
|
{
|
|
UpdateRawBytes();
|
|
m_Size32 += m_RawBytes.GetDataSize();
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
| AP4_HvccAtom::AP4_HvccAtom
|
|
+---------------------------------------------------------------------*/
|
|
AP4_HvccAtom::AP4_HvccAtom(const AP4_HvccAtom& other) :
|
|
AP4_Atom(AP4_ATOM_TYPE_HVCC, other.m_Size32),
|
|
m_ConfigurationVersion(other.m_ConfigurationVersion),
|
|
m_GeneralProfileSpace(other.m_GeneralProfileSpace),
|
|
m_GeneralTierFlag(other.m_GeneralTierFlag),
|
|
m_GeneralProfile(other.m_GeneralProfile),
|
|
m_GeneralProfileCompatibilityFlags(other.m_GeneralProfileCompatibilityFlags),
|
|
m_GeneralConstraintIndicatorFlags(other.m_GeneralConstraintIndicatorFlags),
|
|
m_GeneralLevel(other.m_GeneralLevel),
|
|
m_Reserved1(other.m_Reserved1),
|
|
m_MinSpatialSegmentation(other.m_MinSpatialSegmentation),
|
|
m_Reserved2(other.m_Reserved2),
|
|
m_ParallelismType(other.m_ParallelismType),
|
|
m_Reserved3(other.m_Reserved3),
|
|
m_ChromaFormat(other.m_ChromaFormat),
|
|
m_Reserved4(other.m_Reserved4),
|
|
m_LumaBitDepth(other.m_LumaBitDepth),
|
|
m_Reserved5(other.m_Reserved5),
|
|
m_ChromaBitDepth(other.m_ChromaBitDepth),
|
|
m_AverageFrameRate(other.m_AverageFrameRate),
|
|
m_ConstantFrameRate(other.m_ConstantFrameRate),
|
|
m_NumTemporalLayers(other.m_NumTemporalLayers),
|
|
m_TemporalIdNested(other.m_TemporalIdNested),
|
|
m_NaluLengthSize(other.m_NaluLengthSize),
|
|
m_RawBytes(other.m_RawBytes)
|
|
{
|
|
// deep copy of the parameters
|
|
unsigned int i = 0;
|
|
for (i=0; i<other.m_Sequences.ItemCount(); i++) {
|
|
m_Sequences.Append(other.m_Sequences[i]);
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
| AP4_HvccAtom::AP4_HvccAtom
|
|
+---------------------------------------------------------------------*/
|
|
AP4_HvccAtom::AP4_HvccAtom(AP4_UI08 general_profile_space,
|
|
AP4_UI08 general_tier_flag,
|
|
AP4_UI08 general_profile,
|
|
AP4_UI32 general_profile_compatibility_flags,
|
|
AP4_UI64 general_constraint_indicator_flags,
|
|
AP4_UI08 general_level,
|
|
AP4_UI32 min_spatial_segmentation,
|
|
AP4_UI08 parallelism_type,
|
|
AP4_UI08 chroma_format,
|
|
AP4_UI08 luma_bit_depth,
|
|
AP4_UI08 chroma_bit_depth,
|
|
AP4_UI16 average_frame_rate,
|
|
AP4_UI08 constant_frame_rate,
|
|
AP4_UI08 num_temporal_layers,
|
|
AP4_UI08 temporal_id_nested,
|
|
AP4_UI08 nalu_length_size,
|
|
const AP4_Array<AP4_DataBuffer>& video_parameters,
|
|
AP4_UI08 video_parameters_completeness,
|
|
const AP4_Array<AP4_DataBuffer>& sequence_parameters,
|
|
AP4_UI08 sequence_parameters_completeness,
|
|
const AP4_Array<AP4_DataBuffer>& picture_parameters,
|
|
AP4_UI08 picture_parameters_completeness) :
|
|
AP4_Atom(AP4_ATOM_TYPE_HVCC, AP4_ATOM_HEADER_SIZE),
|
|
m_ConfigurationVersion(1),
|
|
m_GeneralProfileSpace(general_profile_space),
|
|
m_GeneralTierFlag(general_tier_flag),
|
|
m_GeneralProfile(general_profile),
|
|
m_GeneralProfileCompatibilityFlags(general_profile_compatibility_flags),
|
|
m_GeneralConstraintIndicatorFlags(general_constraint_indicator_flags),
|
|
m_GeneralLevel(general_level),
|
|
m_Reserved1(0),
|
|
m_MinSpatialSegmentation(min_spatial_segmentation),
|
|
m_Reserved2(0),
|
|
m_ParallelismType(parallelism_type),
|
|
m_Reserved3(0),
|
|
m_ChromaFormat(chroma_format),
|
|
m_Reserved4(0),
|
|
m_LumaBitDepth(luma_bit_depth),
|
|
m_Reserved5(0),
|
|
m_ChromaBitDepth(chroma_bit_depth),
|
|
m_AverageFrameRate(average_frame_rate),
|
|
m_ConstantFrameRate(constant_frame_rate),
|
|
m_NumTemporalLayers(num_temporal_layers),
|
|
m_TemporalIdNested(temporal_id_nested),
|
|
m_NaluLengthSize(nalu_length_size)
|
|
{
|
|
// deep copy of the parameters
|
|
AP4_HvccAtom::Sequence vps_sequence;
|
|
vps_sequence.m_NaluType = AP4_HEVC_NALU_TYPE_VPS_NUT;
|
|
vps_sequence.m_ArrayCompleteness = video_parameters_completeness;
|
|
for (unsigned int i=0; i<video_parameters.ItemCount(); i++) {
|
|
vps_sequence.m_Nalus.Append(video_parameters[i]);
|
|
}
|
|
if (vps_sequence.m_Nalus.ItemCount()) {
|
|
m_Sequences.Append(vps_sequence);
|
|
}
|
|
|
|
AP4_HvccAtom::Sequence sps_sequence;
|
|
sps_sequence.m_NaluType = AP4_HEVC_NALU_TYPE_SPS_NUT;
|
|
sps_sequence.m_ArrayCompleteness = sequence_parameters_completeness;
|
|
for (unsigned int i=0; i<sequence_parameters.ItemCount(); i++) {
|
|
sps_sequence.m_Nalus.Append(sequence_parameters[i]);
|
|
}
|
|
if (sps_sequence.m_Nalus.ItemCount()) {
|
|
m_Sequences.Append(sps_sequence);
|
|
}
|
|
|
|
AP4_HvccAtom::Sequence pps_sequence;
|
|
pps_sequence.m_NaluType = AP4_HEVC_NALU_TYPE_PPS_NUT;
|
|
pps_sequence.m_ArrayCompleteness = picture_parameters_completeness;
|
|
for (unsigned int i=0; i<picture_parameters.ItemCount(); i++) {
|
|
pps_sequence.m_Nalus.Append(picture_parameters[i]);
|
|
}
|
|
if (pps_sequence.m_Nalus.ItemCount()) {
|
|
m_Sequences.Append(pps_sequence);
|
|
}
|
|
|
|
UpdateRawBytes();
|
|
m_Size32 += m_RawBytes.GetDataSize();
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
| AP4_HvccAtom::AP4_HvccAtom
|
|
+---------------------------------------------------------------------*/
|
|
AP4_HvccAtom::AP4_HvccAtom(AP4_UI32 size, const AP4_UI08* payload) :
|
|
AP4_Atom(AP4_ATOM_TYPE_HVCC, size)
|
|
{
|
|
// make a copy of our configuration bytes
|
|
unsigned int payload_size = size-AP4_ATOM_HEADER_SIZE;
|
|
|
|
// keep a raw copy
|
|
if (payload_size < 22) return;
|
|
m_RawBytes.SetData(payload, payload_size);
|
|
|
|
// parse the payload
|
|
m_ConfigurationVersion = payload[0];
|
|
m_GeneralProfileSpace = (payload[1]>>6) & 0x03;
|
|
m_GeneralTierFlag = (payload[1]>>5) & 0x01;
|
|
m_GeneralProfile = (payload[1] ) & 0x1F;
|
|
m_GeneralProfileCompatibilityFlags = AP4_BytesToUInt32BE(&payload[2]);
|
|
m_GeneralConstraintIndicatorFlags = (((AP4_UI64)AP4_BytesToUInt32BE(&payload[6]))<<16) | AP4_BytesToUInt16BE(&payload[10]);
|
|
m_GeneralLevel = payload[12];
|
|
m_Reserved1 = (payload[13]>>4) & 0x0F;
|
|
m_MinSpatialSegmentation = AP4_BytesToUInt16BE(&payload[13]) & 0x0FFF;
|
|
m_Reserved2 = (payload[15]>>2) & 0x3F;
|
|
m_ParallelismType = payload[15] & 0x03;
|
|
m_Reserved3 = (payload[16]>>2) & 0x3F;
|
|
m_ChromaFormat = payload[16] & 0x03;
|
|
m_Reserved4 = (payload[17]>>3) & 0x1F;
|
|
m_LumaBitDepth = 8+(payload[17] & 0x07);
|
|
m_Reserved5 = (payload[18]>>3) & 0x1F;
|
|
m_ChromaBitDepth = 8+(payload[18] & 0x07);
|
|
m_AverageFrameRate = AP4_BytesToUInt16BE(&payload[19]);
|
|
m_ConstantFrameRate = (payload[21]>>6) & 0x03;
|
|
m_NumTemporalLayers = (payload[21]>>3) & 0x07;
|
|
m_TemporalIdNested = (payload[21]>>2) & 0x01;
|
|
m_NaluLengthSize = 1+(payload[21] & 0x03);
|
|
|
|
AP4_UI08 num_seq = payload[22];
|
|
m_Sequences.SetItemCount(num_seq);
|
|
unsigned int cursor = 23;
|
|
for (unsigned int i=0; i<num_seq; i++) {
|
|
|
|
Sequence& seq = m_Sequences[i];
|
|
if (cursor+1 > payload_size) break;
|
|
seq.m_ArrayCompleteness = (payload[cursor] >> 7) & 0x01;
|
|
seq.m_Reserved = (payload[cursor] >> 6) & 0x01;
|
|
seq.m_NaluType = payload[cursor] & 0x3F;
|
|
cursor += 1;
|
|
|
|
if (cursor+2 > payload_size) break;
|
|
AP4_UI16 nalu_count = AP4_BytesToUInt16BE(&payload[cursor]);
|
|
seq.m_Nalus.SetItemCount(nalu_count);
|
|
cursor += 2;
|
|
|
|
for (unsigned int j=0; j<nalu_count; j++) {
|
|
if (cursor+2 > payload_size) break;
|
|
unsigned int nalu_length = AP4_BytesToUInt16BE(&payload[cursor]);
|
|
cursor += 2;
|
|
if (cursor + nalu_length > payload_size) break;
|
|
seq.m_Nalus[j].SetData(&payload[cursor], nalu_length);
|
|
cursor += nalu_length;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
| AP4_HvccAtom::UpdateRawBytes
|
|
+---------------------------------------------------------------------*/
|
|
void
|
|
AP4_HvccAtom::UpdateRawBytes()
|
|
{
|
|
AP4_BitWriter bits(23);
|
|
bits.Write(m_ConfigurationVersion, 8);
|
|
bits.Write(m_GeneralProfileSpace, 2);
|
|
bits.Write(m_GeneralTierFlag, 1);
|
|
bits.Write(m_GeneralProfile, 5);
|
|
bits.Write(m_GeneralProfileCompatibilityFlags, 32);
|
|
bits.Write((AP4_UI32)(m_GeneralConstraintIndicatorFlags>>32), 16);
|
|
bits.Write((AP4_UI32)(m_GeneralConstraintIndicatorFlags), 32);
|
|
bits.Write(m_GeneralLevel, 8);
|
|
bits.Write(0xFF, 4);
|
|
bits.Write(m_MinSpatialSegmentation, 12);
|
|
bits.Write(0xFF, 6);
|
|
bits.Write(m_ParallelismType, 2);
|
|
bits.Write(0xFF, 6);
|
|
bits.Write(m_ChromaFormat, 2);
|
|
bits.Write(0xFF, 5);
|
|
bits.Write(m_LumaBitDepth >= 8 ? m_LumaBitDepth - 8 : 0, 3);
|
|
bits.Write(0xFF, 5);
|
|
bits.Write(m_ChromaBitDepth >= 8 ? m_ChromaBitDepth - 8 : 0, 3);
|
|
bits.Write(m_AverageFrameRate, 16);
|
|
bits.Write(m_ConstantFrameRate, 2);
|
|
bits.Write(m_NumTemporalLayers, 3);
|
|
bits.Write(m_TemporalIdNested, 1);
|
|
bits.Write(m_NaluLengthSize > 0 ? m_NaluLengthSize - 1 : 0, 2);
|
|
bits.Write(m_Sequences.ItemCount(), 8);
|
|
|
|
m_RawBytes.SetData(bits.GetData(), 23);
|
|
|
|
for (unsigned int i=0; i<m_Sequences.ItemCount(); i++) {
|
|
AP4_UI08 bytes[3];
|
|
bytes[0] = (m_Sequences[i].m_ArrayCompleteness ? (1<<7) : 0) | m_Sequences[i].m_NaluType;
|
|
AP4_BytesFromUInt16BE(&bytes[1], m_Sequences[i].m_Nalus.ItemCount());
|
|
m_RawBytes.AppendData(bytes, 3);
|
|
|
|
for (unsigned int j=0; j<m_Sequences[i].m_Nalus.ItemCount(); j++) {
|
|
AP4_UI08 size[2];
|
|
AP4_BytesFromUInt16BE(&size[0], (AP4_UI16)m_Sequences[i].m_Nalus[j].GetDataSize());
|
|
m_RawBytes.AppendData(size, 2);
|
|
m_RawBytes.AppendData(m_Sequences[i].m_Nalus[j].GetData(), m_Sequences[i].m_Nalus[j].GetDataSize());
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
| AP4_HvccAtom::WriteFields
|
|
+---------------------------------------------------------------------*/
|
|
AP4_Result
|
|
AP4_HvccAtom::WriteFields(AP4_ByteStream& stream)
|
|
{
|
|
return stream.Write(m_RawBytes.GetData(), m_RawBytes.GetDataSize());
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
| AP4_HvccAtom::InspectFields
|
|
+---------------------------------------------------------------------*/
|
|
AP4_Result
|
|
AP4_HvccAtom::InspectFields(AP4_AtomInspector& inspector)
|
|
{
|
|
inspector.AddField("Configuration Version", m_ConfigurationVersion);
|
|
inspector.AddField("Profile Space", m_GeneralProfileSpace);
|
|
const char* profile_name = GetProfileName(m_GeneralProfileSpace, m_GeneralProfile);
|
|
if (profile_name) {
|
|
inspector.AddField("Profile", profile_name);
|
|
} else {
|
|
inspector.AddField("Profile", m_GeneralProfile);
|
|
}
|
|
inspector.AddField("Tier", m_GeneralTierFlag);
|
|
inspector.AddField("Profile Compatibility", m_GeneralProfileCompatibilityFlags, AP4_AtomInspector::HINT_HEX);
|
|
inspector.AddField("Constraint", m_GeneralConstraintIndicatorFlags, AP4_AtomInspector::HINT_HEX);
|
|
inspector.AddField("Level", m_GeneralLevel);
|
|
inspector.AddField("Min Spatial Segmentation", m_MinSpatialSegmentation);
|
|
inspector.AddField("Parallelism Type", m_ParallelismType);
|
|
inspector.AddField("Chroma Format", m_ChromaFormat);
|
|
inspector.AddField("Chroma Depth", m_ChromaBitDepth);
|
|
inspector.AddField("Luma Depth", m_LumaBitDepth);
|
|
inspector.AddField("Average Frame Rate", m_AverageFrameRate);
|
|
inspector.AddField("Constant Frame Rate", m_ConstantFrameRate);
|
|
inspector.AddField("Number Of Temporal Layers", m_NumTemporalLayers);
|
|
inspector.AddField("Temporal Id Nested", m_TemporalIdNested);
|
|
inspector.AddField("NALU Length Size", m_NaluLengthSize);
|
|
return AP4_SUCCESS;
|
|
}
|