Files
Bento4/Source/C++/Core/Ap4HvccAtom.cpp
Gilles Boccon-Gibod 2fe0cb251d making some progress...
2017-09-24 19:06:52 -07:00

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;
}