From 2e2935081944bd5894f283df5616679552bc7ad7 Mon Sep 17 00:00:00 2001 From: Gilles Boccon-Gibod Date: Sun, 28 Mar 2021 20:17:45 -0700 Subject: [PATCH] sample description cleanups --- .../Bento4/Bento4.vcxproj | 8 + .../Bento4/Bento4.vcxproj.filters | 24 + Source/C++/Apps/Mp4Info/Mp4Info.cpp | 665 +++++++----------- Source/C++/Apps/Mp4Mux/Mp4Mux.cpp | 4 +- Source/C++/Codecs/Ap4AvcParser.cpp | 10 +- Source/C++/Codecs/Ap4AvcParser.h | 8 - Source/C++/Codecs/Ap4HevcParser.cpp | 16 +- Source/C++/Codecs/Ap4HevcParser.h | 10 - Source/C++/Core/Ap4AtomFactory.cpp | 11 +- Source/C++/Core/Ap4Dac4Atom.cpp | 40 +- Source/C++/Core/Ap4Dac4Atom.h | 9 +- Source/C++/Core/Ap4DvccAtom.cpp | 60 ++ Source/C++/Core/Ap4DvccAtom.h | 8 + Source/C++/Core/Ap4File.h | 7 +- Source/C++/Core/Ap4SampleDescription.cpp | 317 +++++---- Source/C++/Core/Ap4SampleDescription.h | 20 +- Source/C++/Core/Ap4SampleEntry.cpp | 43 +- Source/C++/Core/Ap4SampleEntry.h | 40 +- Source/C++/Core/Ap4VpccAtom.cpp | 4 +- Source/C++/Core/Ap4VpccAtom.h | 2 +- Source/Python/utils/mp4-dash.py | 311 +++++--- Source/Python/utils/mp4-hls.py | 32 +- Source/Python/utils/mp4utils.py | 241 ++++++- 23 files changed, 1148 insertions(+), 742 deletions(-) diff --git a/Build/Targets/x86_64-microsoft-win32-vs2019/Bento4/Bento4.vcxproj b/Build/Targets/x86_64-microsoft-win32-vs2019/Bento4/Bento4.vcxproj index c5c1a973c..767c63f60 100644 --- a/Build/Targets/x86_64-microsoft-win32-vs2019/Bento4/Bento4.vcxproj +++ b/Build/Targets/x86_64-microsoft-win32-vs2019/Bento4/Bento4.vcxproj @@ -152,11 +152,15 @@ + + + + @@ -282,12 +286,16 @@ + + + + diff --git a/Build/Targets/x86_64-microsoft-win32-vs2019/Bento4/Bento4.vcxproj.filters b/Build/Targets/x86_64-microsoft-win32-vs2019/Bento4/Bento4.vcxproj.filters index 5e02c260f..e99223913 100644 --- a/Build/Targets/x86_64-microsoft-win32-vs2019/Bento4/Bento4.vcxproj.filters +++ b/Build/Targets/x86_64-microsoft-win32-vs2019/Bento4/Bento4.vcxproj.filters @@ -399,6 +399,18 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + @@ -809,5 +821,17 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + \ No newline at end of file diff --git a/Source/C++/Apps/Mp4Info/Mp4Info.cpp b/Source/C++/Apps/Mp4Info/Mp4Info.cpp index 86ae8af98..19b9b904a 100644 --- a/Source/C++/Apps/Mp4Info/Mp4Info.cpp +++ b/Source/C++/Apps/Mp4Info/Mp4Info.cpp @@ -299,17 +299,13 @@ ShowMpegAudioSampleDescription(AP4_MpegAudioSampleDescription& mpeg_audio_desc) AP4_MpegAudioSampleDescription::Mpeg4AudioObjectType object_type = mpeg_audio_desc.GetMpeg4AudioObjectType(); const char* object_type_string = AP4_MpegAudioSampleDescription::GetMpeg4AudioObjectTypeString(object_type); - AP4_String codec_string; - mpeg_audio_desc.GetCodecString(codec_string); switch (Options.format) { case TEXT_FORMAT: - printf(" Codecs String: %s\n", codec_string.GetChars()); printf(" MPEG-4 Audio Object Type: %d (%s)\n", object_type, object_type_string); break; case JSON_FORMAT: - printf("\"codecs_string\": \"%s\",\n", codec_string.GetChars()); printf("\"mpeg_4_audio_object_type\":%d,\n", object_type); printf("\"mpeg_4_audio_object_type_name\":\"%s\"", object_type_string); break; @@ -388,14 +384,19 @@ ShowSampleDescription_Text(AP4_SampleDescription& description, bool verbose) char coding[5]; AP4_FormatFourChars(coding, desc->GetFormat()); - printf( " Coding: %s", coding); + printf( " Coding: %s", coding); const char* format_name = AP4_GetFormatName(desc->GetFormat()); if (format_name) { printf(" (%s)\n", format_name); } else { printf("\n"); } - if (desc->GetType() == AP4_SampleDescription::TYPE_MPEG) { + AP4_String codec; + desc->GetCodecString(codec); + printf( " Codec String: %s\n", codec.GetChars()); + + switch (desc->GetType()) { + case AP4_SampleDescription::TYPE_MPEG: { // MPEG sample description AP4_MpegSampleDescription* mpeg_desc = AP4_DYNAMIC_CAST(AP4_MpegSampleDescription, desc); @@ -411,7 +412,114 @@ ShowSampleDescription_Text(AP4_SampleDescription& description, bool verbose) AP4_MpegAudioSampleDescription* mpeg_audio_desc = AP4_DYNAMIC_CAST(AP4_MpegAudioSampleDescription, mpeg_desc); if (mpeg_audio_desc) ShowMpegAudioSampleDescription(*mpeg_audio_desc); } + break; + } + + case AP4_SampleDescription::TYPE_AVC: { + // AVC specifics + AP4_AvcSampleDescription* avc_desc = AP4_DYNAMIC_CAST(AP4_AvcSampleDescription, desc); + const char* profile_name = AP4_AvccAtom::GetProfileName(avc_desc->GetProfile()); + printf(" AVC Profile: %d", avc_desc->GetProfile()); + if (profile_name) { + printf(" (%s)\n", profile_name); + } else { + printf("\n"); + } + printf(" AVC Profile Compat: %x\n", avc_desc->GetProfileCompatibility()); + printf(" AVC Level: %d\n", avc_desc->GetLevel()); + printf(" AVC NALU Length Size: %d\n", avc_desc->GetNaluLengthSize()); + printf(" AVC SPS: ["); + const char* sep = ""; + for (unsigned int i=0; iGetSequenceParameters().ItemCount(); i++) { + printf("%s", sep); + ShowData(avc_desc->GetSequenceParameters()[i]); + sep = ", "; + } + printf("]\n"); + printf(" AVC PPS: ["); + sep = ""; + for (unsigned int i=0; iGetPictureParameters().ItemCount(); i++) { + printf("%s", sep); + ShowData(avc_desc->GetPictureParameters()[i]); + sep = ", "; + } + printf("]\n"); + break; + } + + case AP4_SampleDescription::TYPE_HEVC: { + // HEVC specifics + AP4_HevcSampleDescription* hevc_desc = AP4_DYNAMIC_CAST(AP4_HevcSampleDescription, desc); + const char* profile_name = AP4_HvccAtom::GetProfileName(hevc_desc->GetGeneralProfileSpace(), hevc_desc->GetGeneralProfile()); + printf(" HEVC Profile Space: %d\n", hevc_desc->GetGeneralProfileSpace()); + printf(" HEVC Profile: %d", hevc_desc->GetGeneralProfile()); + if (profile_name) printf(" (%s)", profile_name); + printf("\n"); + printf(" HEVC Profile Compat: %x\n", hevc_desc->GetGeneralProfileCompatibilityFlags()); + printf(" HEVC Level: %d.%d\n", hevc_desc->GetGeneralLevel()/30, (hevc_desc->GetGeneralLevel()%30)/3); + printf(" HEVC Tier: %d\n", hevc_desc->GetGeneralTierFlag()); + printf(" HEVC Chroma Format: %d", hevc_desc->GetChromaFormat()); + const char* chroma_format_name = AP4_HvccAtom::GetChromaFormatName(hevc_desc->GetChromaFormat()); + if (chroma_format_name) printf(" (%s)", chroma_format_name); + printf("\n"); + printf(" HEVC Chroma Bit Depth: %d\n", hevc_desc->GetChromaBitDepth()); + printf(" HEVC Luma Bit Depth: %d\n", hevc_desc->GetLumaBitDepth()); + printf(" HEVC Average Frame Rate: %d\n", hevc_desc->GetAverageFrameRate()); + printf(" HEVC Constant Frame Rate: %d\n", hevc_desc->GetConstantFrameRate()); + printf(" HEVC NALU Length Size: %d\n", hevc_desc->GetNaluLengthSize()); + printf(" HEVC Sequences:\n"); + for (unsigned int i=0; iGetSequences().ItemCount(); i++) { + const AP4_HvccAtom::Sequence& seq = hevc_desc->GetSequences()[i]; + printf(" {\n"); + printf(" Array Completeness=%d\n", seq.m_ArrayCompleteness); + printf(" Type=%d", seq.m_NaluType); + const char* nalu_type_name = AP4_HevcNalParser::NaluTypeName(seq.m_NaluType); + if (nalu_type_name) { + printf(" (%s)", nalu_type_name); + } + printf("\n"); + const char* sep = ""; + for (unsigned int j=0; jGetSeqProfile()); + printf(" AV1 Profile: %d", av1_desc->GetSeqProfile()); + if (profile_name) { + printf(" (%s)\n", profile_name); + } else { + printf("\n"); + } + printf(" AV1 Level: %d.%d\n", + 2 + (av1_desc->GetSeqLevelIdx0() / 4), + av1_desc->GetSeqLevelIdx0() % 4); + printf(" AV1 Tier: %d\n", av1_desc->GetSeqTier0()); + break; + } + + case AP4_SampleDescription::TYPE_SUBTITLES: { + // Subtitles + AP4_SubtitleSampleDescription* subt_desc = AP4_DYNAMIC_CAST(AP4_SubtitleSampleDescription, desc); + printf(" Subtitles:\n"); + printf(" Namespace: %s\n", subt_desc->GetNamespace().GetChars()); + printf(" Schema Location: %s\n", subt_desc->GetSchemaLocation().GetChars()); + printf(" Image Mime Type: %s\n", subt_desc->GetImageMimeType().GetChars()); + break; + } + + default: + break; } + AP4_AudioSampleDescription* audio_desc = AP4_DYNAMIC_CAST(AP4_AudioSampleDescription, desc); if (audio_desc) { @@ -474,18 +582,12 @@ ShowSampleDescription_Text(AP4_SampleDescription& description, bool verbose) printf("]\n"); } break; - } + } case AP4_SAMPLE_FORMAT_AC_4: { // Dolby AC-4 specifics AP4_Dac4Atom* dac4 = AP4_DYNAMIC_CAST(AP4_Dac4Atom, desc->GetDetails().GetChild(AP4_ATOM_TYPE_DAC4)); if (dac4) { - printf(" Codecs String: "); - AP4_String codec; - dac4->GetCodecString(codec); - printf("%s", codec.GetChars()); - printf("\n"); - const AP4_Dac4Atom::Ac4Dsi& dsi = dac4->GetDsi(); unsigned short self_contained = 0; if (dsi.ac4_dsi_version == 1) { @@ -542,159 +644,29 @@ ShowSampleDescription_Text(AP4_SampleDescription& description, bool verbose) } break; } - } - - switch (desc->GetType()) { - case AP4_SampleDescription::TYPE_AVC: { - // AVC specifics - AP4_AvcSampleDescription* avc_desc = AP4_DYNAMIC_CAST(AP4_AvcSampleDescription, desc); - const char* profile_name = AP4_AvccAtom::GetProfileName(avc_desc->GetProfile()); - printf(" AVC Profile: %d", avc_desc->GetProfile()); - if (profile_name) { - printf(" (%s)\n", profile_name); - } else { - printf("\n"); - } - printf(" AVC Profile Compat: %x\n", avc_desc->GetProfileCompatibility()); - printf(" AVC Level: %d\n", avc_desc->GetLevel()); - printf(" AVC NALU Length Size: %d\n", avc_desc->GetNaluLengthSize()); - printf(" AVC SPS: ["); - const char* sep = ""; - for (unsigned int i=0; iGetSequenceParameters().ItemCount(); i++) { - printf("%s", sep); - ShowData(avc_desc->GetSequenceParameters()[i]); - sep = ", "; - } - printf("]\n"); - printf(" AVC PPS: ["); - sep = ""; - for (unsigned int i=0; iGetPictureParameters().ItemCount(); i++) { - printf("%s", sep); - ShowData(avc_desc->GetPictureParameters()[i]); - sep = ", "; - } - printf("]\n"); - avc_desc->GetCodecString(codec); - printf("%s", codec.GetChars()); - printf("\n"); - break; - } - - case AP4_SampleDescription::TYPE_HEVC: { - // HEVC specifics - AP4_HevcSampleDescription* hevc_desc = AP4_DYNAMIC_CAST(AP4_HevcSampleDescription, desc); - const char* profile_name = AP4_HvccAtom::GetProfileName(hevc_desc->GetGeneralProfileSpace(), hevc_desc->GetGeneralProfile()); - printf(" HEVC Profile Space: %d\n", hevc_desc->GetGeneralProfileSpace()); - printf(" HEVC Profile: %d", hevc_desc->GetGeneralProfile()); - if (profile_name) printf(" (%s)", profile_name); - printf("\n"); - printf(" HEVC Profile Compat: %x\n", hevc_desc->GetGeneralProfileCompatibilityFlags()); - printf(" HEVC Level: %d.%d\n", hevc_desc->GetGeneralLevel()/30, (hevc_desc->GetGeneralLevel()%30)/3); - printf(" HEVC Tier: %d\n", hevc_desc->GetGeneralTierFlag()); - printf(" HEVC Chroma Format: %d", hevc_desc->GetChromaFormat()); - const char* chroma_format_name = AP4_HvccAtom::GetChromaFormatName(hevc_desc->GetChromaFormat()); - if (chroma_format_name) printf(" (%s)", chroma_format_name); - printf("\n"); - printf(" HEVC Chroma Bit Depth: %d\n", hevc_desc->GetChromaBitDepth()); - printf(" HEVC Luma Bit Depth: %d\n", hevc_desc->GetLumaBitDepth()); - printf(" HEVC Average Frame Rate: %d\n", hevc_desc->GetAverageFrameRate()); - printf(" HEVC Constant Frame Rate: %d\n", hevc_desc->GetConstantFrameRate()); - printf(" HEVC NALU Length Size: %d\n", hevc_desc->GetNaluLengthSize()); - printf(" HEVC Sequences:\n"); - for (unsigned int i=0; iGetSequences().ItemCount(); i++) { - const AP4_HvccAtom::Sequence& seq = hevc_desc->GetSequences()[i]; - printf(" {\n"); - printf(" Array Completeness=%d\n", seq.m_ArrayCompleteness); - printf(" Type=%d", seq.m_NaluType); - const char* nalu_type_name = AP4_HevcNalParser::NaluTypeName(seq.m_NaluType); - if (nalu_type_name) { - printf(" (%s)", nalu_type_name); - } - printf("\n"); - const char* sep = ""; - for (unsigned int j=0; jGetCodecString(codec); - printf("%s", codec.GetChars()); - printf("\n"); - break; - } - - case AP4_SampleDescription::TYPE_AV1: { - // AV1 specifics - AP4_Av1SampleDescription* av1_desc = AP4_DYNAMIC_CAST(AP4_Av1SampleDescription, desc); - const char* profile_name = AP4_Av1cAtom::GetProfileName(av1_desc->GetSeqProfile()); - printf(" AV1 Profile: %d", av1_desc->GetSeqProfile()); - if (profile_name) { - printf(" (%s)\n", profile_name); - } else { - printf("\n"); + + // VPx Specifics + case AP4_SAMPLE_FORMAT_VP8: + case AP4_SAMPLE_FORMAT_VP9: + case AP4_SAMPLE_FORMAT_VP10: { + AP4_VpccAtom* vpcc = AP4_DYNAMIC_CAST(AP4_VpccAtom, desc->GetDetails().GetChild(AP4_ATOM_TYPE_VPCC)); + if (vpcc) { + printf(" Profile: %d\n", vpcc->GetProfile()); + printf(" Level: %d\n", vpcc->GetLevel()); + printf(" Bit Depth: %d\n", vpcc->GetBitDepth()); + printf(" Chroma Subsampling: %d\n", vpcc->GetChromaSubsampling()); + printf(" Colour Primaries: %d\n", vpcc->GetColourPrimaries()); + printf(" Transfer Characteristics: %d\n", vpcc->GetTransferCharacteristics()); + printf(" Matrix Coefficients: %d\n", vpcc->GetMatrixCoefficients()); + printf(" Video Full Range Flag: %s\n", vpcc->GetVideoFullRangeFlag() ? "true" : "false"); } - printf(" AV1 Level: %d.%d\n", - 2 + (av1_desc->GetSeqLevelIdx0() / 4), - av1_desc->GetSeqLevelIdx0() % 4); - printf(" AV1 Tier: %d\n", av1_desc->GetSeqTier0()); - printf(" Codecs String: "); - AP4_String codec; - av1_desc->GetCodecString(codec); - printf("%s", codec.GetChars()); - printf("\n"); break; } - - default: - break; } // Dolby Vision specifics AP4_DvccAtom* dvcc = AP4_DYNAMIC_CAST(AP4_DvccAtom, desc->GetDetails().GetChild(AP4_ATOM_TYPE_DVCC)); - if(!dvcc) { - dvcc = AP4_DYNAMIC_CAST(AP4_DvccAtom, desc->GetDetails().GetChild(AP4_ATOM_TYPE_DVVC)); - } if (dvcc) { - /* Codec String */ - char workspace[64]; - char coding[5]; - strncpy(coding, codec.GetChars(), 4); - coding[4] = '\0'; - - /* Non backward-compatible */ - if (strcmp(coding, "dvav") == 0 || strcmp(coding, "dva1") == 0 || - strcmp(coding, "dvhe") == 0 || strcmp(coding, "dvh1") == 0){ - AP4_FormatString(workspace, - sizeof(workspace), - "%s.%02d.%02d", - coding, - dvcc->GetDvProfile(), - dvcc->GetDvLevel()); - codec = workspace; - } else { - if (strcmp(coding, "avc1") == 0){ - strcpy(coding, "dva1"); - }else if (strcmp(coding, "avc3") == 0){ - strcpy(coding, "dvav"); - }else if (strcmp(coding, "hev1") == 0){ - strcpy(coding, "dvhe"); - }else if (strcmp(coding, "hvc1") == 0){ - strcpy(coding, "dvh1"); - } - AP4_FormatString(workspace, - sizeof(workspace), - "%s,%s.%02d.%02d", - codec.GetChars(), - coding, - dvcc->GetDvProfile(), - dvcc->GetDvLevel()); - codec = workspace; - } - printf(" Codecs String: "); - printf("%s", codec.GetChars()); - printf("\n"); /* Dolby Vision */ printf(" Dolby Vision:\n"); printf(" Version: %d.%d\n", dvcc->GetDvVersionMajor(), dvcc->GetDvVersionMinor()); @@ -709,40 +681,6 @@ ShowSampleDescription_Text(AP4_SampleDescription& description, bool verbose) printf(" EL Present: %s\n", dvcc->GetElPresentFlag()?"true":"false"); printf(" BL Present: %s\n", dvcc->GetBlPresentFlag()?"true":"false"); printf(" BL Signal Compatibility ID: %d\n", dvcc->GetDvBlSignalCompatibilityID()); - } else if (desc->GetType() == AP4_SampleDescription::TYPE_AVC || desc->GetType() == AP4_SampleDescription::TYPE_HEVC){ - printf(" Codecs String: "); - printf("%s", codec.GetChars()); - printf("\n"); - } - - // VPx Specifics - if (desc->GetFormat() == AP4_SAMPLE_FORMAT_VP8 || - desc->GetFormat() == AP4_SAMPLE_FORMAT_VP9 || - desc->GetFormat() == AP4_SAMPLE_FORMAT_VP10) { - AP4_VpccAtom* vpcc = AP4_DYNAMIC_CAST(AP4_VpccAtom, desc->GetDetails().GetChild(AP4_ATOM_TYPE_VPCC)); - if (vpcc) { - printf(" Profile: %d\n", vpcc->GetProfile()); - printf(" Level: %d\n", vpcc->GetLevel()); - printf(" Bit Depth: %d\n", vpcc->GetBitDepth()); - printf(" Chroma Subsampling: %d\n", vpcc->GetChromaSubsampling()); - printf(" Colour Primaries: %d\n", vpcc->GetColourPrimaries()); - printf(" Transfer Characteristics: %d\n", vpcc->GetTransferCharacteristics()); - printf(" Matrix Coefficients: %d\n", vpcc->GetMatrixCoefficients()); - printf(" Video Full Range Flag: %s\n", vpcc->GetVideoFullRangeFlag() ? "true" : "false"); - AP4_String codec; - vpcc->GetCodecString(desc->GetFormat(), codec); - printf(" Codecs String: %s", codec.GetChars()); - printf("\n"); - } - } - - // Subtitles - if (desc->GetType() == AP4_SampleDescription::TYPE_SUBTITLES) { - AP4_SubtitleSampleDescription* subt_desc = AP4_DYNAMIC_CAST(AP4_SubtitleSampleDescription, desc); - printf(" Subtitles:\n"); - printf(" Namespace: %s\n", subt_desc->GetNamespace().GetChars()); - printf(" Schema Location: %s\n", subt_desc->GetSchemaLocation().GetChars()); - printf(" Image Mime Type: %s\n", subt_desc->GetImageMimeType().GetChars()); } } @@ -766,14 +704,13 @@ ShowSampleDescription_Json(AP4_SampleDescription& description, bool verbose) AP4_FormatFourChars(coding, desc->GetFormat()); const char* format_name = AP4_GetFormatName(desc->GetFormat()); printf("\"coding\":\"%s\",\n", coding); - printf("\"coding_name\":"); - if (format_name) { - printf("\"%s\"", format_name); - } else { - printf("\"\""); - } + printf("\"coding_name\":\"%s\",\n", format_name ? format_name : ""); + AP4_String codec; + desc->GetCodecString(codec); + printf("\"codecs_string\":\"%s\"", codec.GetChars()); - if (desc->GetType() == AP4_SampleDescription::TYPE_MPEG) { + switch (desc->GetType()) { + case AP4_SampleDescription::TYPE_MPEG: { // MPEG sample description AP4_MpegSampleDescription* mpeg_desc = AP4_DYNAMIC_CAST(AP4_MpegSampleDescription, desc); @@ -784,7 +721,7 @@ ShowSampleDescription_Json(AP4_SampleDescription& description, bool verbose) printf("\"object_type_name\":\"%s\",\n", mpeg_desc->GetObjectTypeString(mpeg_desc->GetObjectTypeId())); printf("\"max_bitrate\":%d,\n", mpeg_desc->GetMaxBitrate()); printf("\"average_bitrate\":%d,\n", mpeg_desc->GetAvgBitrate()); - printf("\"buffer_size\":%d,\n", mpeg_desc->GetBufferSize()); + printf("\"buffer_size\":%d,\n", mpeg_desc->GetBufferSize()); printf("\"decoder_info\": \""); ShowData(mpeg_desc->GetDecoderInfo()); printf("\""); @@ -797,6 +734,116 @@ ShowSampleDescription_Json(AP4_SampleDescription& description, bool verbose) ShowMpegAudioSampleDescription(*mpeg_audio_desc); } } + break; + } + + case AP4_SampleDescription::TYPE_AVC: { + // AVC specifics + AP4_AvcSampleDescription* avc_desc = AP4_DYNAMIC_CAST(AP4_AvcSampleDescription, desc); + printf(",\n"); + printf("\"avc_profile\":%d,\n", avc_desc->GetProfile()); + const char* profile_name = AP4_AvccAtom::GetProfileName(avc_desc->GetProfile()); + if (profile_name) printf("\"avc_profile_name\":\"%s\",\n", profile_name); + printf("\"avc_profile_compat\":%d,\n", avc_desc->GetProfileCompatibility()); + printf("\"avc_level\":%d,\n", avc_desc->GetLevel()); + printf("\"avc_nalu_length_size\":%d,\n", avc_desc->GetNaluLengthSize()); + printf("\"avc_sps\": ["); + const char* sep = ""; + for (unsigned int i=0; iGetSequenceParameters().ItemCount(); i++) { + printf("%s", sep); + printf("\""); + ShowData(avc_desc->GetSequenceParameters()[i]); + printf("\""); + sep = ", "; + } + printf("],\n"); + printf("\"avc_pps\": ["); + sep = ""; + for (unsigned int i=0; iGetPictureParameters().ItemCount(); i++) { + printf("%s", sep); + printf("\""); + ShowData(avc_desc->GetPictureParameters()[i]); + printf("\""); + sep = ", "; + } + printf("]"); + break; + } + + case AP4_SampleDescription::TYPE_HEVC: { + // HEVC Specifics + AP4_HevcSampleDescription* hevc_desc = AP4_DYNAMIC_CAST(AP4_HevcSampleDescription, desc); + printf(",\n"); + printf("\"hevc_profile_space\":%d,\n", hevc_desc->GetGeneralProfileSpace()); + printf("\"hevc_profile\":%d,\n", hevc_desc->GetGeneralProfile()); + const char* profile_name = AP4_HvccAtom::GetProfileName(hevc_desc->GetGeneralProfileSpace(), hevc_desc->GetGeneralProfile()); + if (profile_name) printf("\"hevc_profile_name\":\"%s\",\n", profile_name); + printf("\"hevc_profile_compat\":%d,\n", hevc_desc->GetGeneralProfileCompatibilityFlags()); + printf("\"hevc_constraints\":%llu,\n", hevc_desc->GetGeneralConstraintIndicatorFlags()); + printf("\"hevc_level\":%d,\n", hevc_desc->GetGeneralLevel()); + printf("\"hevc_level_name\":\"%d.%d\",\n", hevc_desc->GetGeneralLevel()/30, (hevc_desc->GetGeneralLevel()%30)/3); + printf("\"hevc_tier\":%d,\n", hevc_desc->GetGeneralTierFlag()); + printf("\"hevc_chroma_format\":%d,\n", hevc_desc->GetChromaFormat()); + const char* chroma_format_name = AP4_HvccAtom::GetChromaFormatName(hevc_desc->GetChromaFormat()); + if (chroma_format_name) printf("\"hevc_chroma_format_name\":\"%s\",\n", chroma_format_name); + printf("\"hevc_chroma_bit_depth\":%d,\n", hevc_desc->GetChromaBitDepth()); + printf("\"hevc_lunma_bit_depth\":%d,\n", hevc_desc->GetLumaBitDepth()); + printf("\"hevc_average_frame_rate\":%d,\n", hevc_desc->GetAverageFrameRate()); + printf("\"hevc_constant_frame_rate\":%d,\n", hevc_desc->GetConstantFrameRate()); + printf("\"hevc_nalu_length_size\":%d,\n", hevc_desc->GetNaluLengthSize()); + printf("\"hevc_sequences\": [\n"); + const char* seq_sep = ""; + for (unsigned int i=0; iGetSequences().ItemCount(); i++) { + const AP4_HvccAtom::Sequence& seq = hevc_desc->GetSequences()[i]; + printf("%s {\n", seq_sep); + printf(" \"array_completeness\":%d,\n", seq.m_ArrayCompleteness); + printf(" \"type\":%d,\n", seq.m_NaluType); + const char* nalu_type_name = AP4_HevcNalParser::NaluTypeName(seq.m_NaluType); + if (nalu_type_name) { + printf(" \"type_name\":\"%s\",\n", nalu_type_name); + } + printf(" \"data\":["); + const char* sep = ""; + for (unsigned int j=0; jGetSeqProfile()); + const char* profile_name = AP4_Av1cAtom::GetProfileName(av1_desc->GetSeqProfile()); + if (profile_name) printf("\"av1_seq_profile_name\":\"%s\",\n", profile_name); + printf("\"av1_seq_level_idx_0\":%d,\n", av1_desc->GetSeqLevelIdx0()); + printf("\"av1_seq_tier_0\":%d", av1_desc->GetSeqTier0()); + break; + } + + case AP4_SampleDescription::TYPE_SUBTITLES: { + // Subtitles + printf(",\n"); + printf("\"subtitles\": {\n"); + AP4_SubtitleSampleDescription* subt_desc = AP4_DYNAMIC_CAST(AP4_SubtitleSampleDescription, desc); + printf(" \"namespace\": \"%s\",\n", subt_desc->GetNamespace().GetChars()); + printf(" \"schema_location\": \"%s\",\n", subt_desc->GetSchemaLocation().GetChars()); + printf(" \"image_mime_type\": \"%s\"\n", subt_desc->GetImageMimeType().GetChars()); + printf("}"); + break; + } + + default: + break; } AP4_AudioSampleDescription* audio_desc = AP4_DYNAMIC_CAST(AP4_AudioSampleDescription, desc); @@ -925,7 +972,6 @@ ShowSampleDescription_Json(AP4_SampleDescription& description, bool verbose) printf("\"Stream Type\": \"%s\", ", presentation_type); } printf("\"presentation_id\": %d, ", presentation.d.v1.b_presentation_id? presentation.d.v1.presentation_id : -1); - printf("\"Codec String\": \"%s\", ", presentation_codec); printf("\"presentation_channel_mask_v1\": %u, ",presentation.d.v1.presentation_channel_mask_v1); printf("\"Dolby Atmos source\": \"%s\", ", presentation.d.v1.dolby_atmos_indicator? "Yes": "No"); printf("\"Language\": \"%s\", ", presentation_lang); @@ -939,171 +985,36 @@ ShowSampleDescription_Json(AP4_SampleDescription& description, bool verbose) printf(" \"Self Contained\": \"%s\",\n", (self_contained == dsi.d.v1.n_presentations) ? "Yes": ((self_contained == 0)? "No": "Part")); printf(" \"dac4_payload\": \""); ShowData(dac4->GetRawBytes()); - printf("\"\n},\n"); - - printf("\"codecs_string\":\""); - AP4_String codec; - dac4->GetCodecString(codec); - printf("%s", codec.GetChars()); - printf("\""); + printf("\"\n}"); } break; } - } - - switch (desc->GetType()) { - case AP4_SampleDescription::TYPE_AVC: { - // AVC specifics - AP4_AvcSampleDescription* avc_desc = AP4_DYNAMIC_CAST(AP4_AvcSampleDescription, desc); - printf(",\n"); - printf("\"avc_profile\":%d,\n", avc_desc->GetProfile()); - const char* profile_name = AP4_AvccAtom::GetProfileName(avc_desc->GetProfile()); - if (profile_name) printf("\"avc_profile_name\":\"%s\",\n", profile_name); - printf("\"avc_profile_compat\":%d,\n", avc_desc->GetProfileCompatibility()); - printf("\"avc_level\":%d,\n", avc_desc->GetLevel()); - printf("\"avc_nalu_length_size\":%d,\n", avc_desc->GetNaluLengthSize()); - printf("\"avc_sps\": ["); - const char* sep = ""; - for (unsigned int i=0; iGetSequenceParameters().ItemCount(); i++) { - printf("%s", sep); - printf("\""); - ShowData(avc_desc->GetSequenceParameters()[i]); - printf("\""); - sep = ", "; - } - printf("],\n"); - printf("\"avc_pps\": ["); - sep = ""; - for (unsigned int i=0; iGetPictureParameters().ItemCount(); i++) { - printf("%s", sep); - printf("\""); - ShowData(avc_desc->GetPictureParameters()[i]); - printf("\""); - sep = ", "; - } - printf("],\n"); - avc_desc->GetCodecString(codec); - printf("%s", codec.GetChars()); - printf("\""); - break; - } - - case AP4_SampleDescription::TYPE_HEVC: { - // HEVC Specifics - AP4_HevcSampleDescription* hevc_desc = AP4_DYNAMIC_CAST(AP4_HevcSampleDescription, desc); - printf(",\n"); - printf("\"hevc_profile_space\":%d,\n", hevc_desc->GetGeneralProfileSpace()); - printf("\"hevc_profile\":%d,\n", hevc_desc->GetGeneralProfile()); - const char* profile_name = AP4_HvccAtom::GetProfileName(hevc_desc->GetGeneralProfileSpace(), hevc_desc->GetGeneralProfile()); - if (profile_name) printf("\"hevc_profile_name\":\"%s\",\n", profile_name); - printf("\"hevc_profile_compat\":%d,\n", hevc_desc->GetGeneralProfileCompatibilityFlags()); - printf("\"hevc_constraints\":%llu,\n", hevc_desc->GetGeneralConstraintIndicatorFlags()); - printf("\"hevc_level\":%d,\n", hevc_desc->GetGeneralLevel()); - printf("\"hevc_level_name\":\"%d.%d\",\n", hevc_desc->GetGeneralLevel()/30, (hevc_desc->GetGeneralLevel()%30)/3); - printf("\"hevc_tier\":%d,\n", hevc_desc->GetGeneralTierFlag()); - printf("\"hevc_chroma_format\":%d,\n", hevc_desc->GetChromaFormat()); - const char* chroma_format_name = AP4_HvccAtom::GetChromaFormatName(hevc_desc->GetChromaFormat()); - if (chroma_format_name) printf("\"hevc_chroma_format_name\":\"%s\",\n", chroma_format_name); - printf("\"hevc_chroma_bit_depth\":%d,\n", hevc_desc->GetChromaBitDepth()); - printf("\"hevc_lunma_bit_depth\":%d,\n", hevc_desc->GetLumaBitDepth()); - printf("\"hevc_average_frame_rate\":%d,\n", hevc_desc->GetAverageFrameRate()); - printf("\"hevc_constant_frame_rate\":%d,\n", hevc_desc->GetConstantFrameRate()); - printf("\"hevc_nalu_length_size\":%d,\n", hevc_desc->GetNaluLengthSize()); - printf("\"hevc_sequences\": [\n"); - const char* seq_sep = ""; - for (unsigned int i=0; iGetSequences().ItemCount(); i++) { - const AP4_HvccAtom::Sequence& seq = hevc_desc->GetSequences()[i]; - printf("%s {\n", seq_sep); - printf(" \"array_completeness\":%d,\n", seq.m_ArrayCompleteness); - printf(" \"type\":%d,\n", seq.m_NaluType); - const char* nalu_type_name = AP4_HevcNalParser::NaluTypeName(seq.m_NaluType); - if (nalu_type_name) { - printf(" \"type_name\":\"%s\",\n", nalu_type_name); - } - printf(" \"data\":["); - const char* sep = ""; - for (unsigned int j=0; jGetDetails().GetChild(AP4_ATOM_TYPE_VPCC)); + if (vpcc) { + printf(",\n"); + printf("\"vpx_info\": {\n"); + printf(" \"profile\":%d,\n", vpcc->GetProfile()); + printf(" \"level\":%d,\n", vpcc->GetLevel()); + printf(" \"bit_depth\":%d,\n", vpcc->GetBitDepth()); + printf(" \"chroma_subsampling\":%d,\n", vpcc->GetChromaSubsampling()); + printf(" \"colour_primaries\":%d,\n", vpcc->GetColourPrimaries()); + printf(" \"transfer_characteristics\":%d,\n", vpcc->GetTransferCharacteristics()); + printf(" \"matrix_coefficients\":%d,\n", vpcc->GetMatrixCoefficients()); + printf(" \"video_full_range_flag\":%s\n", vpcc->GetVideoFullRangeFlag() ? "true" : "false"); + printf("}"); } - printf("\n],\n"); - hevc_desc->GetCodecString(codec); - printf("%s", codec.GetChars()); - printf("\""); break; } - - case AP4_SampleDescription::TYPE_AV1: { - // AV1 specifics - AP4_Av1SampleDescription* av1_desc = AP4_DYNAMIC_CAST(AP4_Av1SampleDescription, desc); - printf(",\n"); - printf("\"av1_seq_profile\":%d,\n", av1_desc->GetSeqProfile()); - const char* profile_name = AP4_Av1cAtom::GetProfileName(av1_desc->GetSeqProfile()); - if (profile_name) printf("\"av1_seq_profile_name\":\"%s\",\n", profile_name); - printf("\"av1_seq_level_idx_0\":%d,\n", av1_desc->GetSeqLevelIdx0()); - printf("\"av1_seq_tier_0\":%d,\n", av1_desc->GetSeqTier0()); - printf("\"codecs_string\":\""); - AP4_String codec; - av1_desc->GetCodecString(codec); - printf("%s", codec.GetChars()); - printf("\""); - break; - } - - default: - break; } - + // Dolby Vision specifics AP4_DvccAtom* dvcc = AP4_DYNAMIC_CAST(AP4_DvccAtom, desc->GetDetails().GetChild(AP4_ATOM_TYPE_DVCC)); - if(!dvcc) { - dvcc = AP4_DYNAMIC_CAST(AP4_DvccAtom, desc->GetDetails().GetChild(AP4_ATOM_TYPE_DVVC)); - } if (dvcc) { - /* Codec String */ - char workspace[64]; - char coding[5]; - strncpy(coding, codec.GetChars(), 4); - coding[4] = '\0'; - - /* Non backward-compatible */ - if (strcmp(coding, "dvav") == 0 || strcmp(coding, "dva1") == 0 || - strcmp(coding, "dvhe") == 0 || strcmp(coding, "dvh1") == 0){ - AP4_FormatString(workspace, - sizeof(workspace), - "%s.%02d.%02d", - coding, - dvcc->GetDvProfile(), - dvcc->GetDvLevel()); - codec = workspace; - } else { - if (strcmp(coding, "avc1") == 0){ - strcpy(coding, "dva1"); - }else if (strcmp(coding, "avc3") == 0){ - strcpy(coding, "dvav"); - }else if (strcmp(coding, "hev1") == 0){ - strcpy(coding, "dvhe"); - }else if (strcmp(coding, "hvc1") == 0){ - strcpy(coding, "dvh1"); - } - AP4_FormatString(workspace, - sizeof(workspace), - "%s,%s.%02d.%02d", - codec.GetChars(), - coding, - dvcc->GetDvProfile(), - dvcc->GetDvLevel()); - codec = workspace; - } - printf("\"codecs_string\":\""); - printf("%s", codec.GetChars()); - printf("\""); /* Dolby Vision */ printf(",\n"); printf("\"dolby_vision\": {\n"); @@ -1118,48 +1029,8 @@ ShowSampleDescription_Json(AP4_SampleDescription& description, bool verbose) printf(" \"bl_present\": %s,\n", dvcc->GetBlPresentFlag()?"true":"false"); printf(" \"dv_bl_signal_compatibility_id\": %d\n", dvcc->GetDvBlSignalCompatibilityID()); printf("}"); - } else if (desc->GetType() == AP4_SampleDescription::TYPE_AVC || desc->GetType() == AP4_SampleDescription::TYPE_HEVC){ - printf("\"codecs_string\":\""); - printf("%s", codec.GetChars()); - printf("\""); } - // VPx Specifics - if (desc->GetFormat() == AP4_SAMPLE_FORMAT_VP8 || - desc->GetFormat() == AP4_SAMPLE_FORMAT_VP9 || - desc->GetFormat() == AP4_SAMPLE_FORMAT_VP10) { - AP4_VpccAtom* vpcc = AP4_DYNAMIC_CAST(AP4_VpccAtom, desc->GetDetails().GetChild(AP4_ATOM_TYPE_VPCC)); - if (vpcc) { - printf(",\n"); - printf("\"vpx_info\": {\n"); - printf(" \"profile\":%d,\n", vpcc->GetProfile()); - printf(" \"level\":%d,\n", vpcc->GetLevel()); - printf(" \"bit_depth\":%d,\n", vpcc->GetBitDepth()); - printf(" \"chroma_subsampling\":%d,\n", vpcc->GetChromaSubsampling()); - printf(" \"colour_primaries\":%d,\n", vpcc->GetColourPrimaries()); - printf(" \"transfer_characteristics\":%d,\n", vpcc->GetTransferCharacteristics()); - printf(" \"matrix_coefficients\":%d,\n", vpcc->GetMatrixCoefficients()); - printf(" \"video_full_range_flag\":%s\n", vpcc->GetVideoFullRangeFlag() ? "true" : "false"); - printf("},\n"); - printf("\"codecs_string\":\""); - AP4_String codec; - vpcc->GetCodecString(desc->GetFormat(), codec); - printf("%s", codec.GetChars()); - printf("\""); - } - } - - // Subtitles - if (desc->GetType() == AP4_SampleDescription::TYPE_SUBTITLES) { - printf(",\n"); - printf("\"subtitles\": {\n"); - AP4_SubtitleSampleDescription* subt_desc = AP4_DYNAMIC_CAST(AP4_SubtitleSampleDescription, desc); - printf(" \"namespace\": \"%s\",\n", subt_desc->GetNamespace().GetChars()); - printf(" \"schema_location\": \"%s\",\n", subt_desc->GetSchemaLocation().GetChars()); - printf(" \"image_mime_type\": \"%s\"\n", subt_desc->GetImageMimeType().GetChars()); - printf("}"); - } - printf("\n}"); } @@ -2013,6 +1884,8 @@ main(int argc, char** argv) } else { if (Options.format == TEXT_FORMAT) { printf("No movie found in the file\n"); + } else { + printf("\"movie\":{}\n"); } } } diff --git a/Source/C++/Apps/Mp4Mux/Mp4Mux.cpp b/Source/C++/Apps/Mp4Mux/Mp4Mux.cpp index 7651530ca..bc74ff696 100644 --- a/Source/C++/Apps/Mp4Mux/Mp4Mux.cpp +++ b/Source/C++/Apps/Mp4Mux/Mp4Mux.cpp @@ -2300,7 +2300,7 @@ main(int argc, char** argv) hasDovi = true; } } else { - AddH264Track(*movie, input_name, parameters, brands, *sample_storage); + AddH264Track(*movie, input_name, parameters, brands, *sample_storage); } } else if (!strcmp(input_type, "h265")) { if (isDovi) { @@ -2313,7 +2313,7 @@ main(int argc, char** argv) hasDovi = true; } } else { - AddH265Track(*movie, input_name, parameters, brands, *sample_storage); + AddH265Track(*movie, input_name, parameters, brands, *sample_storage); } } else if (!strcmp(input_type, "aac")) { AddAacTrack(*movie, input_name, parameters, *sample_storage); diff --git a/Source/C++/Codecs/Ap4AvcParser.cpp b/Source/C++/Codecs/Ap4AvcParser.cpp index 3fd362ad7..b95398b30 100644 --- a/Source/C++/Codecs/Ap4AvcParser.cpp +++ b/Source/C++/Codecs/Ap4AvcParser.cpp @@ -77,10 +77,8 @@ AP4_AvcNalParser::NaluTypeName(unsigned int nalu_type) case 15: return "Subset sequence parameter set"; case 19: return "Coded slice of an auxiliary coded picture without partitioning"; case 20: return "Coded slice in scalable extension"; -#if defined(AP4_HEVC_DOVI_EXTENSION) case 28: return "Dolby Vision RPU NAL units"; case 30: return "Dolby Vision EL NAL units"; -#endif default: return NULL; } } @@ -1117,9 +1115,7 @@ AP4_AvcFrameParser::Feed(const AP4_UI08* nal_unit, } else if (nal_unit_type >= 14 && nal_unit_type <= 18) { CheckIfAccessUnitIsCompleted(access_unit_info); DBG_PRINTF_0("\n"); - } -#if defined(AP4_HEVC_DOVI_EXTENSION) - else if (nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_UNSPECIFIED28) { + } else if (nal_unit_type == AP4_AVC_NAL_UNIT_TYPE_UNSPECIFIED28) { AppendNalUnitData(nal_unit, nal_unit_size); CheckIfAccessUnitIsCompleted(access_unit_info); DBG_PRINTF_0("\n"); @@ -1127,9 +1123,7 @@ AP4_AvcFrameParser::Feed(const AP4_UI08* nal_unit, AppendNalUnitData(nal_unit, nal_unit_size); CheckIfAccessUnitIsCompleted(access_unit_info); DBG_PRINTF_0("\n"); - } -#endif - else { + } else { DBG_PRINTF_0("\n"); } m_TotalNalUnitCount++; diff --git a/Source/C++/Codecs/Ap4AvcParser.h b/Source/C++/Codecs/Ap4AvcParser.h index 1cb36caeb..8f9cd6c31 100644 --- a/Source/C++/Codecs/Ap4AvcParser.h +++ b/Source/C++/Codecs/Ap4AvcParser.h @@ -38,11 +38,6 @@ #include "Ap4NalParser.h" #include "Ap4Array.h" -/*---------------------------------------------------------------------- -| Dolby Vision extension -+---------------------------------------------------------------------*/ -#define AP4_HEVC_DOVI_EXTENSION 1 - /*---------------------------------------------------------------------- | constants +---------------------------------------------------------------------*/ @@ -64,11 +59,8 @@ const unsigned int AP4_AVC_NAL_UNIT_TYPE_PREFIX = 14; const unsigned int AP4_AVC_NAL_UNIT_TYPE_SUBSET_SPS = 15; const unsigned int AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_OF_AUXILIARY_PICTURE = 19; const unsigned int AP4_AVC_NAL_UNIT_TYPE_CODED_SLICE_IN_SCALABLE_EXTENSION = 20; - -#if defined(AP4_HEVC_DOVI_EXTENSION) const unsigned int AP4_AVC_NAL_UNIT_TYPE_UNSPECIFIED28 = 28; const unsigned int AP4_AVC_NAL_UNIT_TYPE_UNSPECIFIED30 = 30; -#endif const unsigned int AP4_AVC_SLICE_TYPE_P = 0; const unsigned int AP4_AVC_SLICE_TYPE_B = 1; diff --git a/Source/C++/Codecs/Ap4HevcParser.cpp b/Source/C++/Codecs/Ap4HevcParser.cpp index bd2f73c47..306a7c1ab 100644 --- a/Source/C++/Codecs/Ap4HevcParser.cpp +++ b/Source/C++/Codecs/Ap4HevcParser.cpp @@ -105,10 +105,8 @@ AP4_HevcNalParser::NaluTypeName(unsigned int nalu_type) case 38: return "FD_NUT - Filler data"; case 39: return "PREFIX_SEI_NUT - Supplemental enhancement information"; case 40: return "SUFFIX_SEI_NUT - Supplemental enhancement information"; -#if defined(AP4_HEVC_DOVI_EXTENSION) case 62: return "Dolby Vision RPU NAL units"; case 63: return "Dolby Vision EL NAL units"; -#endif default: return NULL; } } @@ -976,17 +974,15 @@ AP4_HevcVideoParameterSet::AP4_HevcVideoParameterSet() : } } -#if defined(AP4_HEVC_DOVI_EXTENSION) /*---------------------------------------------------------------------- | AP4_HevcVideoParameterSet::GetInfo +---------------------------------------------------------------------*/ void AP4_HevcVideoParameterSet::GetInfo(unsigned int& time_scale, unsigned int& num_units) { - time_scale = vps_time_scale; - num_units = vps_num_units_in_tick; + time_scale = vps_time_scale; + num_units = vps_num_units_in_tick; } -#endif /*---------------------------------------------------------------------- | AP4_HevcVideoParameterSet::Parse @@ -1341,15 +1337,11 @@ AP4_HevcFrameParser::Feed(const AP4_UI08* nal_unit, AppendNalUnitData(nal_unit, nal_unit_size); } else if (nal_unit_type == AP4_HEVC_NALU_TYPE_SUFFIX_SEI_NUT){ AppendNalUnitData(nal_unit, nal_unit_size); - } -#if defined(AP4_HEVC_DOVI_EXTENSION) - else if (nal_unit_type == AP4_HEVC_NALU_TYPE_UNSPEC62) { + } else if (nal_unit_type == AP4_HEVC_NALU_TYPE_UNSPEC62) { AppendNalUnitData(nal_unit, nal_unit_size); - } - else if (nal_unit_type == AP4_HEVC_NALU_TYPE_UNSPEC63) { + } else if (nal_unit_type == AP4_HEVC_NALU_TYPE_UNSPEC63) { AppendNalUnitData(nal_unit, nal_unit_size); } -#endif DBG_PRINTF_0("\n"); m_TotalNalUnitCount++; } diff --git a/Source/C++/Codecs/Ap4HevcParser.h b/Source/C++/Codecs/Ap4HevcParser.h index 964d55410..5e30662e1 100644 --- a/Source/C++/Codecs/Ap4HevcParser.h +++ b/Source/C++/Codecs/Ap4HevcParser.h @@ -39,11 +39,6 @@ #include "Ap4Array.h" #include "Ap4Utils.h" -/*---------------------------------------------------------------------- -| Dolby Vision extension -+---------------------------------------------------------------------*/ -#define AP4_HEVC_DOVI_EXTENSION 1 - /*---------------------------------------------------------------------- | constants +---------------------------------------------------------------------*/ @@ -95,11 +90,8 @@ const unsigned int AP4_HEVC_NALU_TYPE_RSV_NVCL44 = 44; const unsigned int AP4_HEVC_NALU_TYPE_RSV_NVCL45 = 45; const unsigned int AP4_HEVC_NALU_TYPE_RSV_NVCL46 = 46; const unsigned int AP4_HEVC_NALU_TYPE_RSV_NVCL47 = 47; - -#if defined(AP4_HEVC_DOVI_EXTENSION) const unsigned int AP4_HEVC_NALU_TYPE_UNSPEC62 = 62; const unsigned int AP4_HEVC_NALU_TYPE_UNSPEC63 = 63; -#endif const unsigned int AP4_HEVC_PPS_MAX_ID = 63; const unsigned int AP4_HEVC_SPS_MAX_ID = 15; @@ -288,9 +280,7 @@ struct AP4_HevcVideoParameterSet { // methods AP4_Result Parse(const unsigned char* data, unsigned int data_size); -#if defined(AP4_HEVC_DOVI_EXTENSION) void GetInfo(unsigned int& time_scale, unsigned int& num_units); -#endif AP4_DataBuffer raw_bytes; unsigned int vps_video_parameter_set_id; diff --git a/Source/C++/Core/Ap4AtomFactory.cpp b/Source/C++/Core/Ap4AtomFactory.cpp index 932e0b1b2..d689a78bb 100644 --- a/Source/C++/Core/Ap4AtomFactory.cpp +++ b/Source/C++/Core/Ap4AtomFactory.cpp @@ -330,10 +330,19 @@ AP4_AtomFactory::CreateAtomFromStream(AP4_ByteStream& stream, atom = new AP4_Av1SampleEntry(type, size_32, stream, *this); break; - case AP4_ATOM_TYPE_ALAC: case AP4_ATOM_TYPE_AC_3: + atom = new AP4_Ac3SampleEntry(type, size_32, stream, *this); + break; + case AP4_ATOM_TYPE_EC_3: + atom = new AP4_Eac3SampleEntry(type, size_32, stream, *this); + break; + case AP4_ATOM_TYPE_AC_4: + atom = new AP4_Ac4SampleEntry(type, size_32, stream, *this); + break; + + case AP4_ATOM_TYPE_ALAC: case AP4_ATOM_TYPE_DTSC: case AP4_ATOM_TYPE_DTSH: case AP4_ATOM_TYPE_DTSL: diff --git a/Source/C++/Core/Ap4Dac4Atom.cpp b/Source/C++/Core/Ap4Dac4Atom.cpp index 63944c29b..12b55d4ef 100644 --- a/Source/C++/Core/Ap4Dac4Atom.cpp +++ b/Source/C++/Core/Ap4Dac4Atom.cpp @@ -57,14 +57,6 @@ AP4_Dac4Atom::Create(AP4_Size size, AP4_ByteStream& stream) const AP4_UI08* payload = payload_data.GetData(); return new AP4_Dac4Atom(size, payload); } -/*---------------------------------------------------------------------- -| AP4_Dac4Atom::AP4_Dac4Atom -+---------------------------------------------------------------------*/ -AP4_Dac4Atom::AP4_Dac4Atom(const AP4_Dac4Atom& other): - AP4_Atom(AP4_ATOM_TYPE_DAC4, other.m_Size32), - m_RawBytes(other.m_RawBytes), - m_Dsi(other.m_Dsi){ -} /*---------------------------------------------------------------------- | AP4_Dac4Atom::AP4_Dac4Atom @@ -423,10 +415,10 @@ AP4_Dac4Atom::~AP4_Dac4Atom() } else if (m_Dsi.ac4_dsi_version == 1) { for (int i = 0; i < m_Dsi.d.v1.n_presentations; i++) { for (int j = 0; j < m_Dsi.d.v1.presentations[i].d.v1.n_substream_groups; j++) { - delete[] m_Dsi.d.v1.presentations[i].d.v1.substream_groups[j].d.v1.substreams; - } - delete[] m_Dsi.d.v1.presentations[i].d.v1.substream_groups; + delete[] m_Dsi.d.v1.presentations[i].d.v1.substream_groups[j].d.v1.substreams; } + delete[] m_Dsi.d.v1.presentations[i].d.v1.substream_groups; + } delete[] m_Dsi.d.v1.presentations; } } @@ -460,7 +452,9 @@ AP4_Dac4Atom::GetCodecString(AP4_String& codec) } else if (presentation_version == 1 || presentation_version == 2) { mdcompat = m_Dsi.d.v1.presentations[0].d.v1.mdcompat; for (int idx = 0; idx < m_Dsi.d.v1.n_presentations; idx ++){ - if (mdcompat > m_Dsi.d.v1.presentations[idx].d.v1.mdcompat) { mdcompat = m_Dsi.d.v1.presentations[idx].d.v1.mdcompat;} + if (mdcompat > m_Dsi.d.v1.presentations[idx].d.v1.mdcompat) { + mdcompat = m_Dsi.d.v1.presentations[idx].d.v1.mdcompat; + } } } } @@ -1134,21 +1128,21 @@ AP4_Dac4Atom::Ac4Dsi::SubStream::GetChModeCore(unsigned char b_channel_coded) | AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1::ParseSubstreamGroupInfo +---------------------------------------------------------------------*/ AP4_Result -AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1::ParseSubstreamGroupInfo(AP4_BitReader &bits, - unsigned int bitstream_version, - unsigned int presentation_version, - unsigned char defalut_presentation_flag, - unsigned int frame_rate_factor, - unsigned int fs_idx, - unsigned int &channel_count, - unsigned int &speaker_index_mask, - unsigned int &b_obj_or_Ajoc) +AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1::ParseSubstreamGroupInfo(AP4_BitReader& bits, + unsigned int bitstream_version, + unsigned int presentation_version, + unsigned char defalut_presentation_flag, + unsigned int frame_rate_factor, + unsigned int fs_idx, + unsigned int& channel_count, + unsigned int& speaker_index_mask, + unsigned int& b_obj_or_Ajoc) { d.v1.b_substreams_present = bits.ReadBit(); d.v1.b_hsf_ext = bits.ReadBit(); if (bits.ReadBit()) { d.v1.n_substreams = 1; - }else{ + } else{ d.v1.n_substreams = bits.ReadBits(2) + 2; if (d.v1.n_substreams == 5) { d.v1.n_substreams += AP4_Ac4VariableBits(bits, 2); @@ -1179,7 +1173,7 @@ AP4_Dac4Atom::Ac4Dsi::SubStreamGroupV1::ParseSubstreamGroupInfo(AP4_BitReader &b ParseHsfExtSubstreamInfo(bits); } } - }else { // b_channel_coded == 0 + } else { // b_channel_coded == 0 b_obj_or_Ajoc = 1; if (bits.ReadBit()) { // b_oamd_substream //oamd_substream_info() diff --git a/Source/C++/Core/Ap4Dac4Atom.h b/Source/C++/Core/Ap4Dac4Atom.h index 60b3ae909..227c50a88 100644 --- a/Source/C++/Core/Ap4Dac4Atom.h +++ b/Source/C++/Core/Ap4Dac4Atom.h @@ -277,16 +277,16 @@ class AP4_Dac4Atom : public AP4_Atom static AP4_Dac4Atom* Create(AP4_Size size, AP4_ByteStream& stream); // constructors - AP4_Dac4Atom(const AP4_Dac4Atom& other); AP4_Dac4Atom(AP4_UI32 size, const Ac4Dsi* ac4Dsi); // DSI vaiable initialize m_RawBytes (m_Dsi -> m_RawBytes) // destructor ~AP4_Dac4Atom(); // methods - virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); - virtual AP4_Result WriteFields(AP4_ByteStream& stream); - virtual AP4_Atom* Clone() { return new AP4_Dac4Atom(m_Size32, m_RawBytes.GetData()); } + virtual AP4_Result InspectFields(AP4_AtomInspector& inspector); + virtual AP4_Result WriteFields(AP4_ByteStream& stream); + virtual AP4_Atom* Clone() { return new AP4_Dac4Atom(m_Size32, m_RawBytes.GetData()); } + virtual AP4_Dac4Atom* CloneConst() const { return new AP4_Dac4Atom(m_Size32, m_RawBytes.GetData()); } // accessors const AP4_DataBuffer& GetRawBytes() const { return m_RawBytes; } @@ -297,6 +297,7 @@ class AP4_Dac4Atom : public AP4_Atom private: // methods + AP4_Dac4Atom(const AP4_Dac4Atom& other); AP4_Dac4Atom(AP4_UI32 size, const AP4_UI08* payload); // box data initialize m_Dsi (m_RawBytes -> m_Dsi) // members diff --git a/Source/C++/Core/Ap4DvccAtom.cpp b/Source/C++/Core/Ap4DvccAtom.cpp index 817220dc1..494036ffa 100644 --- a/Source/C++/Core/Ap4DvccAtom.cpp +++ b/Source/C++/Core/Ap4DvccAtom.cpp @@ -33,6 +33,7 @@ #include "Ap4AtomFactory.h" #include "Ap4Utils.h" #include "Ap4Types.h" +#include "Ap4SampleDescription.h" /*---------------------------------------------------------------------- | dynamic cast support @@ -122,6 +123,65 @@ AP4_DvccAtom::AP4_DvccAtom(AP4_UI08 dv_version_major, { } +/*---------------------------------------------------------------------- +| AP4_DvccAtom::GetCodecString ++---------------------------------------------------------------------*/ +AP4_Result +AP4_DvccAtom::GetCodecString(AP4_SampleDescription* parent, AP4_String& codec) +{ + char workspace[64]; + + AP4_UI32 format = parent->GetFormat(); + if (format == AP4_ATOM_TYPE_DVAV || + format == AP4_ATOM_TYPE_DVA1 || + format == AP4_ATOM_TYPE_DVHE || + format == AP4_ATOM_TYPE_DVH1) { + /* Non backward-compatible */ + char coding[5]; + AP4_FormatFourChars(coding, format); + AP4_FormatString(workspace, + sizeof(workspace), + "%s.%02d.%02d", + coding, + GetDvProfile(), + GetDvLevel()); + codec = workspace; + } else { + /* Backward-compatible */ + switch (format) { + case AP4_ATOM_TYPE_AVC1: + format = AP4_ATOM_TYPE_DVA1; + break; + + case AP4_ATOM_TYPE_AVC3: + format = AP4_ATOM_TYPE_DVAV; + break; + + case AP4_ATOM_TYPE_HEV1: + format = AP4_ATOM_TYPE_DVHE; + break; + + case AP4_ATOM_TYPE_HVC1: + format = AP4_ATOM_TYPE_DVH1; + break; + } + char coding[5]; + AP4_FormatFourChars(coding, format); + AP4_String parent_codec; + parent->GetCodecString(parent_codec); + AP4_FormatString(workspace, + sizeof(workspace), + "%s,%s.%02d.%02d", + parent_codec.GetChars(), + coding, + GetDvProfile(), + GetDvLevel()); + codec = workspace; + } + + return AP4_SUCCESS; +} + /*---------------------------------------------------------------------- | AP4_DvccAtom::WriteFields +---------------------------------------------------------------------*/ diff --git a/Source/C++/Core/Ap4DvccAtom.h b/Source/C++/Core/Ap4DvccAtom.h index a5b46d5ea..3329cac88 100644 --- a/Source/C++/Core/Ap4DvccAtom.h +++ b/Source/C++/Core/Ap4DvccAtom.h @@ -35,6 +35,11 @@ #include "Ap4Atom.h" #include "Ap4Array.h" +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class AP4_SampleDescription; + /*---------------------------------------------------------------------- | constants +---------------------------------------------------------------------*/ @@ -86,6 +91,9 @@ class AP4_DvccAtom : public AP4_Atom bool GetBlPresentFlag() { return m_BlPresentFlag != 0; } AP4_UI08 GetDvBlSignalCompatibilityID() { return m_DvBlSignalCompatibilityID; } + // helpers + AP4_Result GetCodecString(AP4_SampleDescription* parent, AP4_String& codec); + private: // members AP4_UI08 m_DvVersionMajor; diff --git a/Source/C++/Core/Ap4File.h b/Source/C++/Core/Ap4File.h index 0e7784a95..9375258d2 100644 --- a/Source/C++/Core/Ap4File.h +++ b/Source/C++/Core/Ap4File.h @@ -37,10 +37,6 @@ #include "Ap4Atom.h" #include "Ap4AtomFactory.h" -/*---------------------------------------------------------------------- -| Dolby Vision extension -+---------------------------------------------------------------------*/ -#define AP4_HEVC_DOVI_EXTENSION 1 /*---------------------------------------------------------------------- | class references +---------------------------------------------------------------------*/ @@ -76,9 +72,8 @@ const AP4_UI32 AP4_FILE_BRAND_ODCF = AP4_ATOM_TYPE('o','d','c','f'); const AP4_UI32 AP4_FILE_BRAND_OPF2 = AP4_ATOM_TYPE('o','p','f','2'); const AP4_UI32 AP4_FILE_BRAND_AVC1 = AP4_ATOM_TYPE('a','v','c','1'); const AP4_UI32 AP4_FILE_BRAND_HVC1 = AP4_ATOM_TYPE('h','v','c','1'); -#if defined(AP4_HEVC_DOVI_EXTENSION) const AP4_UI32 AP4_FILE_BRAND_DBY1 = AP4_ATOM_TYPE('d','b','y','1'); -#endif + /*---------------------------------------------------------------------- | AP4_File +---------------------------------------------------------------------*/ diff --git a/Source/C++/Core/Ap4SampleDescription.cpp b/Source/C++/Core/Ap4SampleDescription.cpp index 5d5e7dcf8..829942244 100644 --- a/Source/C++/Core/Ap4SampleDescription.cpp +++ b/Source/C++/Core/Ap4SampleDescription.cpp @@ -279,6 +279,21 @@ AP4_GenericAudioSampleDescription::ToAtom() const return sample_entry; } +/*---------------------------------------------------------------------- +| AP4_GenericVideoSampleDescription::GetCodecString ++---------------------------------------------------------------------*/ +AP4_Result +AP4_GenericVideoSampleDescription::GetCodecString(AP4_String& codec) +{ + // VPx override + AP4_VpccAtom* vpcc = AP4_DYNAMIC_CAST(AP4_VpccAtom, m_Details.GetChild(AP4_ATOM_TYPE_VPCC)); + if (vpcc) { + return vpcc->GetCodecString(GetFormat(), codec); + } + + return AP4_SampleDescription::GetCodecString(codec); +} + /*---------------------------------------------------------------------- | AP4_GenericVideoSampleDescription +---------------------------------------------------------------------*/ @@ -381,6 +396,12 @@ AP4_AvcSampleDescription::AP4_AvcSampleDescription(AP4_UI32 format, +---------------------------------------------------------------------*/ AP4_Result AP4_AvcSampleDescription::GetCodecString(AP4_String& codec) { + // Dolby Vision override + AP4_DvccAtom* dvcc = AP4_DYNAMIC_CAST(AP4_DvccAtom, m_Details.GetChild(AP4_ATOM_TYPE_DVCC)); + if (dvcc) { + return dvcc->GetCodecString(this, codec); + } + char coding[5]; AP4_FormatFourChars(coding, GetFormat()); char workspace[64]; @@ -410,51 +431,6 @@ AP4_AvcSampleDescription::ToAtom() const &m_Details); } -/*---------------------------------------------------------------------- -| AP4_HevcSampleDescription::AP4_HevcSampleDescription -+---------------------------------------------------------------------*/ -AP4_HevcSampleDescription::AP4_HevcSampleDescription(AP4_UI32 format, - AP4_UI16 width, - AP4_UI16 height, - AP4_UI16 depth, - const char* compressor_name, - const AP4_HvccAtom* hvcc) : - AP4_SampleDescription(TYPE_HEVC, format, NULL), - AP4_VideoSampleDescription(width, height, depth, compressor_name) -{ - if (hvcc) { - m_HvccAtom = new AP4_HvccAtom(*hvcc); - } else { - // should never happen - m_HvccAtom = new AP4_HvccAtom(); - } - m_Details.AddChild(m_HvccAtom); -} - -/*---------------------------------------------------------------------- -| AP4_HevcSampleDescription::AP4_HevcSampleDescription -+---------------------------------------------------------------------*/ -AP4_HevcSampleDescription::AP4_HevcSampleDescription(AP4_UI32 format, - AP4_UI16 width, - AP4_UI16 height, - AP4_UI16 depth, - const char* compressor_name, - AP4_AtomParent* details) : - AP4_SampleDescription(TYPE_HEVC, format, details), - AP4_VideoSampleDescription(width, height, depth, compressor_name), - m_HvccAtom(NULL) -{ - AP4_HvccAtom* hvcc = AP4_DYNAMIC_CAST(AP4_HvccAtom, m_Details.GetChild(AP4_ATOM_TYPE_HVCC)); - if (hvcc) { - m_HvccAtom = hvcc; - } else { - // shoud never happen - m_HvccAtom = new AP4_HvccAtom(); - m_Details.AddChild(m_HvccAtom); - } -} - -#if defined(AP4_HEVC_DOVI_EXTENSION) /*---------------------------------------------------------------------- | AP4_AvcDoviSampleDescription::AP4_AvcDoviSampleDescription +---------------------------------------------------------------------*/ @@ -479,7 +455,7 @@ AP4_AvcDoviSampleDescription::AP4_AvcDoviSampleDescription(AP4_UI32 bool rpu_present_flag, bool el_present_flag, bool bl_present_flag, - AP4_UI08 dv_bl_signal_compatibility_id) : + AP4_UI08 dv_bl_signal_compatibility_id) : AP4_AvcSampleDescription(format, width, height, @@ -505,7 +481,50 @@ AP4_AvcDoviSampleDescription::AP4_AvcDoviSampleDescription(AP4_UI32 dv_bl_signal_compatibility_id); m_Details.AddChild(m_DvccAtom); } -#endif + +/*---------------------------------------------------------------------- +| AP4_HevcSampleDescription::AP4_HevcSampleDescription ++---------------------------------------------------------------------*/ +AP4_HevcSampleDescription::AP4_HevcSampleDescription(AP4_UI32 format, + AP4_UI16 width, + AP4_UI16 height, + AP4_UI16 depth, + const char* compressor_name, + const AP4_HvccAtom* hvcc) : + AP4_SampleDescription(TYPE_HEVC, format, NULL), + AP4_VideoSampleDescription(width, height, depth, compressor_name) +{ + if (hvcc) { + m_HvccAtom = new AP4_HvccAtom(*hvcc); + } else { + // should never happen + m_HvccAtom = new AP4_HvccAtom(); + } + m_Details.AddChild(m_HvccAtom); +} + +/*---------------------------------------------------------------------- +| AP4_HevcSampleDescription::AP4_HevcSampleDescription ++---------------------------------------------------------------------*/ +AP4_HevcSampleDescription::AP4_HevcSampleDescription(AP4_UI32 format, + AP4_UI16 width, + AP4_UI16 height, + AP4_UI16 depth, + const char* compressor_name, + AP4_AtomParent* details) : + AP4_SampleDescription(TYPE_HEVC, format, details), + AP4_VideoSampleDescription(width, height, depth, compressor_name), + m_HvccAtom(NULL) +{ + AP4_HvccAtom* hvcc = AP4_DYNAMIC_CAST(AP4_HvccAtom, m_Details.GetChild(AP4_ATOM_TYPE_HVCC)); + if (hvcc) { + m_HvccAtom = hvcc; + } else { + // shoud never happen + m_HvccAtom = new AP4_HvccAtom(); + m_Details.AddChild(m_HvccAtom); + } +} /*---------------------------------------------------------------------- | AP4_HevcSampleDescription::AP4_HevcSampleDescription @@ -565,7 +584,74 @@ AP4_HevcSampleDescription::AP4_HevcSampleDescription(AP4_UI32 m_Details.AddChild(m_HvccAtom); } -#if defined(AP4_HEVC_DOVI_EXTENSION) +/*---------------------------------------------------------------------- +| ReverseBits ++---------------------------------------------------------------------*/ +static AP4_UI32 +ReverseBits(AP4_UI32 bits) +{ + unsigned int count = sizeof(bits) * 8; + AP4_UI32 reverse_bits = 0; + + while (bits) { + reverse_bits = (reverse_bits << 1) | (bits & 1); + bits >>= 1; + count--; + } + return (count < 32) ? (reverse_bits << count) : 0; +} + +/*---------------------------------------------------------------------- +| AP4_HevcSampleDescription:GetCodecString ++---------------------------------------------------------------------*/ +AP4_Result +AP4_HevcSampleDescription::GetCodecString(AP4_String& codec) { + // Dolby Vision override + AP4_DvccAtom* dvcc = AP4_DYNAMIC_CAST(AP4_DvccAtom, m_Details.GetChild(AP4_ATOM_TYPE_DVCC)); + if (dvcc) { + return dvcc->GetCodecString(this, codec); + } + + char coding[5]; + AP4_FormatFourChars(coding, GetFormat()); + char profile_space[2] = {0,0}; + if (GetGeneralProfileSpace() > 0 && GetGeneralProfileSpace() <= 3) { + profile_space[0] = 'A'+GetGeneralProfileSpace()-1; + } + AP4_UI64 constraints = GetGeneralConstraintIndicatorFlags(); + while (constraints && ((constraints & 0xFF) == 0)) { + constraints >>= 8; + } + char workspace[64]; + AP4_FormatString(workspace, + sizeof(workspace), + "%s.%s%d.%X.%c%d.%llx", + coding, + profile_space, + GetGeneralProfile(), + ReverseBits(GetGeneralProfileCompatibilityFlags()), + GetGeneralTierFlag()?'H':'L', + GetGeneralLevel(), + constraints); + codec = workspace; + + return AP4_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AP4_HevcSampleDescription::ToAtom ++---------------------------------------------------------------------*/ +AP4_Atom* +AP4_HevcSampleDescription::ToAtom() const +{ + return new AP4_HevcSampleEntry(m_Format, + m_Width, + m_Height, + m_Depth, + m_CompressorName.GetChars(), + &m_Details); +} + /*---------------------------------------------------------------------- | AP4_HevcDoviSampleDescription::AP4_HevcDoviSampleDescription +---------------------------------------------------------------------*/ @@ -596,14 +682,14 @@ AP4_HevcDoviSampleDescription::AP4_HevcDoviSampleDescription(AP4_UI32 AP4_UI08 sequence_parameters_completeness, const AP4_Array& picture_parameters, AP4_UI08 picture_parameters_completeness, - AP4_UI08 dv_version_major, - AP4_UI08 dv_version_minor, - AP4_UI08 dv_profile, - AP4_UI08 dv_level, - bool rpu_present_flag, - bool el_present_flag, - bool bl_present_flag, - AP4_UI08 dv_bl_signal_compatibility_id) : + AP4_UI08 dv_version_major, + AP4_UI08 dv_version_minor, + AP4_UI08 dv_profile, + AP4_UI08 dv_level, + bool rpu_present_flag, + bool el_present_flag, + bool bl_present_flag, + AP4_UI08 dv_bl_signal_compatibility_id) : AP4_HevcSampleDescription(format, width, height, @@ -642,69 +728,6 @@ AP4_HevcDoviSampleDescription::AP4_HevcDoviSampleDescription(AP4_UI32 dv_bl_signal_compatibility_id); m_Details.AddChild(m_DvccAtom); } -#endif - -/*---------------------------------------------------------------------- -| ReverseBits -+---------------------------------------------------------------------*/ -static AP4_UI32 -ReverseBits(AP4_UI32 bits) -{ - unsigned int count = sizeof(bits) * 8; - AP4_UI32 reverse_bits = 0; - - while (bits) { - reverse_bits = (reverse_bits << 1) | (bits & 1); - bits >>= 1; - count--; - } - return (count < 32) ? (reverse_bits << count) : 0; -} - -/*---------------------------------------------------------------------- -| AP4_HevcSampleDescription:GetCodecString -+---------------------------------------------------------------------*/ -AP4_Result -AP4_HevcSampleDescription::GetCodecString(AP4_String& codec) { - char coding[5]; - AP4_FormatFourChars(coding, GetFormat()); - char profile_space[2] = {0,0}; - if (GetGeneralProfileSpace() > 0 && GetGeneralProfileSpace() <= 3) { - profile_space[0] = 'A'+GetGeneralProfileSpace()-1; - } - AP4_UI64 constraints = GetGeneralConstraintIndicatorFlags(); - while (constraints && ((constraints & 0xFF) == 0)) { - constraints >>= 8; - } - char workspace[64]; - AP4_FormatString(workspace, - sizeof(workspace), - "%s.%s%d.%X.%c%d.%llx", - coding, - profile_space, - GetGeneralProfile(), - ReverseBits(GetGeneralProfileCompatibilityFlags()), - GetGeneralTierFlag()?'H':'L', - GetGeneralLevel(), - constraints); - codec = workspace; - - return AP4_SUCCESS; -} - -/*---------------------------------------------------------------------- -| AP4_HevcSampleDescription::ToAtom -+---------------------------------------------------------------------*/ -AP4_Atom* -AP4_HevcSampleDescription::ToAtom() const -{ - return new AP4_HevcSampleEntry(m_Format, - m_Width, - m_Height, - m_Depth, - m_CompressorName.GetChars(), - &m_Details); -} /*---------------------------------------------------------------------- | AP4_Av1SampleDescription::AP4_Av1SampleDescription @@ -807,7 +830,7 @@ AP4_Av1SampleDescription::GetCodecString(AP4_String& codec) { char workspace[64]; AP4_FormatString(workspace, sizeof(workspace), - "%s.%d.%d%d.%c.%d.%d%d%d.%02d.%02d.%02d.%d", + "%s.%d.%02d%c.%02d.%d.%d%d%d.%02d.%02d.%02d.%d", coding, this->GetSeqProfile(), this->GetSeqLevelIdx0() >> 4, @@ -1071,17 +1094,17 @@ AP4_MpegAudioSampleDescription::GetMpeg4AudioObjectType() const /*---------------------------------------------------------------------- | AP4_Ac3SampleDescription::AP4_Ac3SampleDescription +---------------------------------------------------------------------*/ -AP4_Ac3SampleDescription::AP4_Ac3SampleDescription(AP4_UI32 sample_rate, - AP4_UI16 sample_size, - AP4_UI16 channel_count, - const AP4_Dac3Atom* dac3Atom): +AP4_Ac3SampleDescription::AP4_Ac3SampleDescription(AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count, + const AP4_Dac3Atom* dac3): AP4_SampleDescription(TYPE_AC3, AP4_SAMPLE_FORMAT_AC_3, NULL), AP4_AudioSampleDescription(sample_rate, sample_size, channel_count) { - if (dac3Atom) { - m_Dac3Atom = new AP4_Dac3Atom(*dac3Atom); + if (dac3) { + m_Dac3Atom = new AP4_Dac3Atom(*dac3); } else { - // TODO: add default construtor, m_Dac3Atom = new AP4_Dac3Atom(). It shall never happen. + // TODO: add default construtor, m_Dac3Atom = new AP4_Dac3Atom() / should never happen m_Dac3Atom = NULL; } m_Details.AddChild(m_Dac3Atom); @@ -1102,7 +1125,7 @@ m_Dac3Atom(NULL) if (ac3) { m_Dac3Atom = ac3; } else { - // TODO: add default construtor, m_Dac3Atom = new AP4_Dac3Atom(). It shall never happen. + // TODO: add default construtor, m_Dac3Atom = new AP4_Dac3Atom() / should never happen m_Dac3Atom = NULL; m_Details.AddChild(m_Dac3Atom); } @@ -1112,15 +1135,15 @@ m_Dac3Atom(NULL) | AP4_Ac3SampleDescription::AP4_Ac3SampleDescription +---------------------------------------------------------------------*/ -AP4_Ac3SampleDescription::AP4_Ac3SampleDescription(AP4_UI32 sample_rate, - AP4_UI16 sample_size, - AP4_UI16 channel_count, - AP4_UI32 size, - const AP4_Dac3Atom::StreamInfo* m_Ac3StreamInfo): +AP4_Ac3SampleDescription::AP4_Ac3SampleDescription(AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count, + AP4_UI32 size, + const AP4_Dac3Atom::StreamInfo* ac3_stream_info): AP4_SampleDescription(TYPE_AC3, AP4_SAMPLE_FORMAT_AC_3, NULL), AP4_AudioSampleDescription(sample_rate, sample_size, channel_count) { - m_Dac3Atom = new AP4_Dac3Atom(m_Ac3StreamInfo); + m_Dac3Atom = new AP4_Dac3Atom(ac3_stream_info); m_Details.AddChild(m_Dac3Atom); } @@ -1154,12 +1177,12 @@ AP4_Eac3SampleDescription::AP4_Eac3SampleDescription(): AP4_Eac3SampleDescription::AP4_Eac3SampleDescription(AP4_UI32 sample_rate, AP4_UI16 sample_size, AP4_UI16 channel_count, - const AP4_Dec3Atom* dec3Atom): + const AP4_Dec3Atom* dec3): AP4_SampleDescription(TYPE_EAC3, AP4_SAMPLE_FORMAT_EC_3, NULL), AP4_AudioSampleDescription(sample_rate, sample_size, channel_count) { - if (dec3Atom) { - m_Dec3Atom = new AP4_Dec3Atom(*dec3Atom); + if (dec3) { + m_Dec3Atom = new AP4_Dec3Atom(*dec3); } else { // shoud never happen m_Dec3Atom = new AP4_Dec3Atom(); @@ -1225,14 +1248,15 @@ AP4_Eac3SampleDescription::ToAtom() const AP4_Ac4SampleDescription::AP4_Ac4SampleDescription(AP4_UI32 sample_rate, AP4_UI16 sample_size, AP4_UI16 channel_count, - const AP4_Dac4Atom* dac4Atom): + const AP4_Dac4Atom* dac4): AP4_SampleDescription(TYPE_AC4, AP4_SAMPLE_FORMAT_AC_4, NULL), AP4_AudioSampleDescription(sample_rate, sample_size, channel_count) { - if (dac4Atom) { - m_Dac4Atom = new AP4_Dac4Atom(*dac4Atom); + if (dac4) { + m_Dac4Atom = dac4->CloneConst(); +; } else { - // TODO: add default construtor, m_Dac4Atom = new AP4_Dac4Atom(). It shall never happen. + // TODO: add default construtor, m_Dac4Atom = new AP4_Dac4Atom() / should never happen m_Dac4Atom = NULL; } m_Details.AddChild(m_Dac4Atom); @@ -1253,7 +1277,7 @@ AP4_Ac4SampleDescription::AP4_Ac4SampleDescription(AP4_UI32 sample_rate, if (ac4) { m_Dac4Atom = ac4; } else { - // TODO: add default construtor, m_Dac4Atom = new AP4_Dac4Atom(). It shall never happen. + // TODO: add default construtor, m_Dac4Atom = new AP4_Dac4Atom() / should never happen m_Dac4Atom = NULL; m_Details.AddChild(m_Dac4Atom); } @@ -1262,11 +1286,10 @@ AP4_Ac4SampleDescription::AP4_Ac4SampleDescription(AP4_UI32 sample_rate, /*---------------------------------------------------------------------- | AP4_Ac4SampleDescription::AP4_Ac4SampleDescription +---------------------------------------------------------------------*/ - -AP4_Ac4SampleDescription::AP4_Ac4SampleDescription(AP4_UI32 sample_rate, - AP4_UI16 sample_size, - AP4_UI16 channel_count, - AP4_UI32 size, +AP4_Ac4SampleDescription::AP4_Ac4SampleDescription(AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count, + AP4_UI32 size, const AP4_Dac4Atom::Ac4Dsi* ac4Dsi): AP4_SampleDescription(TYPE_AC4, AP4_SAMPLE_FORMAT_AC_4, NULL), AP4_AudioSampleDescription(sample_rate, sample_size, channel_count) diff --git a/Source/C++/Core/Ap4SampleDescription.h b/Source/C++/Core/Ap4SampleDescription.h index 92080947c..27f3136c8 100644 --- a/Source/C++/Core/Ap4SampleDescription.h +++ b/Source/C++/Core/Ap4SampleDescription.h @@ -46,11 +46,6 @@ #include "Ap4Dac3Atom.h" #include "Ap4DvccAtom.h" -/*---------------------------------------------------------------------- -| Dolby Vision extension -+---------------------------------------------------------------------*/ -#define AP4_HEVC_DOVI_EXTENSION 1 - /*---------------------------------------------------------------------- | class references +---------------------------------------------------------------------*/ @@ -287,7 +282,8 @@ class AP4_GenericVideoSampleDescription : public AP4_SampleDescription, AP4_VideoSampleDescription(width, height, depth, compressor_name) {} // inherited from AP4_SampleDescription - virtual AP4_Atom* ToAtom() const; + virtual AP4_Atom* ToAtom() const; + virtual AP4_Result GetCodecString(AP4_String& codec); }; /*---------------------------------------------------------------------- @@ -355,7 +351,6 @@ class AP4_AvcSampleDescription : public AP4_SampleDescription, AP4_AvccAtom* m_AvccAtom; }; -#if defined(AP4_HEVC_DOVI_EXTENSION) /*---------------------------------------------------------------------- | AP4_AvcDoviSampleDescription +---------------------------------------------------------------------*/ @@ -387,7 +382,6 @@ class AP4_AvcDoviSampleDescription : public AP4_AvcSampleDescription private: AP4_DvccAtom* m_DvccAtom; }; -#endif /*---------------------------------------------------------------------- | AP4_HevcSampleDescription @@ -475,7 +469,6 @@ class AP4_HevcSampleDescription : public AP4_SampleDescription, AP4_HvccAtom* m_HvccAtom; }; -#if defined(AP4_HEVC_DOVI_EXTENSION) /*---------------------------------------------------------------------- | AP4_HevcDoviSampleDescription +---------------------------------------------------------------------*/ @@ -520,7 +513,6 @@ class AP4_HevcDoviSampleDescription : public AP4_HevcSampleDescription private: AP4_DvccAtom* m_DvccAtom; }; -#endif /*---------------------------------------------------------------------- | AP4_Av1SampleDescription @@ -796,10 +788,10 @@ class AP4_Ac4SampleDescription : public AP4_SampleDescription, AP4_UI16 channel_count, AP4_AtomParent* details); - AP4_Ac4SampleDescription(AP4_UI32 sample_rate, - AP4_UI16 sample_size, - AP4_UI16 channel_count, - AP4_UI32 size, // DSI size + AP4_Ac4SampleDescription(AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count, + AP4_UI32 size, // DSI size const AP4_Dac4Atom::Ac4Dsi* ac4Dsi); // inherited from AP4_SampleDescription diff --git a/Source/C++/Core/Ap4SampleEntry.cpp b/Source/C++/Core/Ap4SampleEntry.cpp index 8355e2bf1..1c175a380 100644 --- a/Source/C++/Core/Ap4SampleEntry.cpp +++ b/Source/C++/Core/Ap4SampleEntry.cpp @@ -697,6 +697,17 @@ AP4_Ac3SampleEntry::AP4_Ac3SampleEntry(AP4_UI32 format, } } +/*---------------------------------------------------------------------- +| AP4_Ac3SampleEntry::AP4_Ac3SampleEntry ++---------------------------------------------------------------------*/ +AP4_Ac3SampleEntry::AP4_Ac3SampleEntry(AP4_UI32 type, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_AudioSampleEntry(type, size, stream, atom_factory) +{ +} + /*---------------------------------------------------------------------- | AP4_Ac3SampleEntry::ToSampleDescription +---------------------------------------------------------------------*/ @@ -731,6 +742,17 @@ AP4_Eac3SampleEntry::AP4_Eac3SampleEntry(AP4_UI32 format, } } +/*---------------------------------------------------------------------- +| AP4_Eac3SampleEntry::AP4_Eac3SampleEntry ++---------------------------------------------------------------------*/ +AP4_Eac3SampleEntry::AP4_Eac3SampleEntry(AP4_UI32 type, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_AudioSampleEntry(type, size, stream, atom_factory) +{ +} + /*---------------------------------------------------------------------- | AP4_Eac3SampleEntry::ToSampleDescription +---------------------------------------------------------------------*/ @@ -753,10 +775,10 @@ AP4_Eac3SampleEntry::ToSampleDescription() /*---------------------------------------------------------------------- | AP4_Ac4SampleEntry::AP4_Ac4SampleEntry +---------------------------------------------------------------------*/ -AP4_Ac4SampleEntry::AP4_Ac4SampleEntry(AP4_UI32 format, - AP4_UI32 sample_rate, - AP4_UI16 sample_size, - AP4_UI16 channel_count, +AP4_Ac4SampleEntry::AP4_Ac4SampleEntry(AP4_UI32 format, + AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count, const AP4_AtomParent* details): AP4_AudioSampleEntry(format, sample_rate, sample_size, channel_count) { @@ -769,6 +791,17 @@ AP4_Ac4SampleEntry::AP4_Ac4SampleEntry(AP4_UI32 format, } } +/*---------------------------------------------------------------------- +| AP4_Ac4SampleEntry::AP4_Ac4SampleEntry ++---------------------------------------------------------------------*/ +AP4_Ac4SampleEntry::AP4_Ac4SampleEntry(AP4_UI32 type, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory) : + AP4_AudioSampleEntry(type, size, stream, atom_factory) +{ +} + /*---------------------------------------------------------------------- | AP4_Ac4SampleEntry::ToSampleDescription +---------------------------------------------------------------------*/ @@ -779,7 +812,7 @@ AP4_Ac4SampleEntry::ToSampleDescription() AP4_Dac4Atom* dac4 = AP4_DYNAMIC_CAST(AP4_Dac4Atom, GetChild(AP4_ATOM_TYPE_DAC4)); if (dac4 == NULL) { return NULL; - }else{ + } else{ return new AP4_Ac4SampleDescription(GetSampleRate(), GetSampleSize(), GetChannelCount(), diff --git a/Source/C++/Core/Ap4SampleEntry.h b/Source/C++/Core/Ap4SampleEntry.h index c98ae3131..1f54ad7ca 100644 --- a/Source/C++/Core/Ap4SampleEntry.h +++ b/Source/C++/Core/Ap4SampleEntry.h @@ -271,11 +271,15 @@ class AP4_MpegAudioSampleEntry : public AP4_AudioSampleEntry class AP4_Ac3SampleEntry : public AP4_AudioSampleEntry { public: - AP4_Ac3SampleEntry(AP4_UI32 format, - AP4_UI32 sample_rate, - AP4_UI16 sample_size, - AP4_UI16 channel_count, - const AP4_AtomParent *details); + AP4_Ac3SampleEntry(AP4_UI32 format, + AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count, + const AP4_AtomParent* details); + AP4_Ac3SampleEntry(AP4_UI32 type, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); // inherited from AP4_SampleEntry virtual AP4_SampleDescription* ToSampleDescription(); @@ -287,11 +291,15 @@ class AP4_Ac3SampleEntry : public AP4_AudioSampleEntry class AP4_Eac3SampleEntry : public AP4_AudioSampleEntry { public: - AP4_Eac3SampleEntry(AP4_UI32 format, - AP4_UI32 sample_rate, - AP4_UI16 sample_size, - AP4_UI16 channel_count, - const AP4_AtomParent *details); + AP4_Eac3SampleEntry(AP4_UI32 format, + AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count, + const AP4_AtomParent* details); + AP4_Eac3SampleEntry(AP4_UI32 type, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); // inherited from AP4_SampleEntry virtual AP4_SampleDescription* ToSampleDescription(); @@ -304,11 +312,15 @@ class AP4_Eac3SampleEntry : public AP4_AudioSampleEntry class AP4_Ac4SampleEntry : public AP4_AudioSampleEntry { public: - AP4_Ac4SampleEntry(AP4_UI32 format, - AP4_UI32 sample_rate, - AP4_UI16 sample_size, - AP4_UI16 channel_count, + AP4_Ac4SampleEntry(AP4_UI32 format, + AP4_UI32 sample_rate, + AP4_UI16 sample_size, + AP4_UI16 channel_count, const AP4_AtomParent* details); + AP4_Ac4SampleEntry(AP4_UI32 type, + AP4_Size size, + AP4_ByteStream& stream, + AP4_AtomFactory& atom_factory); // inherited from AP4_SampleEntry virtual AP4_SampleDescription* ToSampleDescription(); diff --git a/Source/C++/Core/Ap4VpccAtom.cpp b/Source/C++/Core/Ap4VpccAtom.cpp index 47084ad1a..8c16876cb 100644 --- a/Source/C++/Core/Ap4VpccAtom.cpp +++ b/Source/C++/Core/Ap4VpccAtom.cpp @@ -125,7 +125,7 @@ AP4_VpccAtom::AP4_VpccAtom(AP4_UI08 profile, /*---------------------------------------------------------------------- | AP4_VpccAtom::GetCodecString +---------------------------------------------------------------------*/ -void +AP4_Result AP4_VpccAtom::GetCodecString(AP4_UI32 container_type, AP4_String& codec) { char type_name[5]; @@ -144,6 +144,8 @@ AP4_VpccAtom::GetCodecString(AP4_UI32 container_type, AP4_String& codec) m_MatrixCoefficients, m_VideoFullRangeFlag ? 1 : 0); codec = string; + + return AP4_SUCCESS; } /*---------------------------------------------------------------------- diff --git a/Source/C++/Core/Ap4VpccAtom.h b/Source/C++/Core/Ap4VpccAtom.h index 0c993917c..9fb60bc37 100644 --- a/Source/C++/Core/Ap4VpccAtom.h +++ b/Source/C++/Core/Ap4VpccAtom.h @@ -81,7 +81,7 @@ class AP4_VpccAtom : public AP4_Atom const AP4_DataBuffer& GetCodecInitializationData() { return m_CodecIntializationData; } // helpers - void GetCodecString(AP4_UI32 container_type, AP4_String& codec); + AP4_Result GetCodecString(AP4_UI32 container_type, AP4_String& codec); private: // methods diff --git a/Source/Python/utils/mp4-dash.py b/Source/Python/utils/mp4-dash.py index a9234b1e1..1137845cb 100755 --- a/Source/Python/utils/mp4-dash.py +++ b/Source/Python/utils/mp4-dash.py @@ -54,8 +54,22 @@ LanguageCodeMap,\ XmlDuration,\ PrintErrorAndExit,\ - MakeNewDir - + MakeNewDir,\ + GetDolbyDigitalPlusChannels,\ + DolbyVisionProfile8DualEntry,\ + ReGroupVideoSetsDASH,\ + ReOrderMediaTrack,\ + ReGroupAC4Sets,\ + ReOrderAudioSetsInternally,\ + DolbyDigitalWithMPEGDASHScheme,\ + DolbyAc4WithMPEGDASHScheme,\ + ReGroupAudioSets,\ + PrintBlankLine,\ + GenVideoSets,\ + ReGroupVideoSetsHLS,\ + FindAudioGroups,\ + GetVideoRangeValue + # setup main options VERSION = "2.0.0" SDK_REVISION = '637' @@ -129,6 +143,7 @@ HIPPO_MEDIA_SEGMENT_GROUPS_SMOOTH = '["time"]' MPEG_DASH_AUDIO_CHANNEL_CONFIGURATION_SCHEME_ID_URI = 'urn:mpeg:dash:23003:3:audio_channel_configuration:2011' +MPEG_DASH_NEW_AUDIO_CHANNEL_CONFIGURATION_SCHEME_ID_URI = 'urn:mpeg:mpegB:cicp:ChannelConfiguration' DOLBY_DIGITAL_AUDIO_CHANNEL_CONFIGURATION_SCHEME_ID_URI = 'tag:dolby.com,2014:dash:audio_channel_configuration:2011' DOLBY_AC4_AUDIO_CHANNEL_CONFIGURATION_SCHEME_ID_URI = 'tag:dolby.com,2015:dash:audio_channel_configuration:2015' @@ -372,6 +387,8 @@ def AddDescriptor(adaptation_set, set_attributes, set_name, category_name): if not attributes: return + descriptor_list = [] + descriptor_names = ['Accessibility', 'Role', 'Rating', 'Viewpoint'] for descriptor_name in attributes: descriptor_values = attributes[descriptor_name] for descriptor_value in descriptor_values.split(','): @@ -391,16 +408,24 @@ def AddDescriptor(adaptation_set, set_attributes, set_name, category_name): if descriptor_name == 'rating': descriptor_name = 'Rating' if descriptor_name == 'viewpoint': descriptor_name = 'Viewpoint' - if descriptor_name not in ['Accessibility', 'Role', 'Rating', 'Viewpoint']: + if descriptor_name not in descriptor_names: continue if descriptor_namespace: - xml.SubElement(adaptation_set, - descriptor_name, - schemeIdUri=descriptor_namespace, - value=descriptor_value) + descriptor_list.append({'order':descriptor_names.index(descriptor_name), + 'name':descriptor_name, + 'schemeIdUri':descriptor_namespace, + 'value':descriptor_value}) else: sys.stderr.write('WARNING: ignoring ' + descriptor_name + ' descriptor for set "' + set_name + '", the schemeIdUri must be specified\n') + if descriptor_list: + descriptor_list.sort(key=lambda x: x['order']) + for item in descriptor_list: + xml.SubElement(adaptation_set, + item['name'], + schemeIdUri=item['schemeIdUri'], + value=item['value']) + ############################################# def OutputDash(options, set_attributes, audio_sets, video_sets, subtitles_sets, subtitles_files): all_audio_tracks = sum(list(audio_sets.values()), []) @@ -435,7 +460,12 @@ def OutputDash(options, set_attributes, audio_sets, video_sets, subtitles_sets, if video_sets: period.append(xml.Comment(' Video ')) - for video_tracks in list(video_sets.values()): + # Re-group video sets to handle the duplicated video track for Dolby Vision profile 8. + regroup_video_sets = ReGroupVideoSetsDASH(video_sets.values()) + + # Re-order video tracks according to input order via command line. + ordered_video_track = ReOrderMediaTrack(regroup_video_sets) + for video_tracks in ordered_video_track: # compute the max values maxWidth = 0 maxHeight = 0 @@ -496,7 +526,13 @@ def OutputDash(options, set_attributes, audio_sets, video_sets, subtitles_sets, # process the audio tracks if audio_sets: period.append(xml.Comment(' Audio ')) - for _, audio_tracks in list(audio_sets.items()): + # Re-group audio sets for AC-4 stream. (add channel attributes, and whether it's self contained (Multi-PID)). + audio_sets = ReGroupAC4Sets(audio_sets) + # Re-order audio tracks internally according to input order. + audio_sets = ReOrderAudioSetsInternally(audio_sets) + # Re-order audio tracks according to input order via command line. + ordered_audio_track = ReOrderMediaTrack(audio_sets.values()) + for audio_tracks in ordered_audio_track: args = [period, 'AdaptationSet'] kwargs = {'mimeType': AUDIO_MIMETYPE, 'startWithSAP': '1', 'segmentAlignment': 'true'} language = audio_tracks[0].language @@ -535,12 +571,20 @@ def OutputDash(options, set_attributes, audio_sets, video_sets, subtitles_sets, codecs=audio_track.codec, bandwidth=str(audio_track.bandwidth), audioSamplingRate=str(audio_track.sample_rate)) - if audio_track.codec == 'ec-3': + if audio_track.codec == 'ec-3' or audio_track.codec == 'ac-3': audio_channel_config_value = ComputeDolbyDigitalPlusAudioChannelConfig(audio_track) - scheme_id_uri = DOLBY_DIGITAL_AUDIO_CHANNEL_CONFIGURATION_SCHEME_ID_URI + (mpeg_scheme, audio_channel_config_value) = DolbyDigitalWithMPEGDASHScheme(audio_channel_config_value) + if (mpeg_scheme): + scheme_id_uri = MPEG_DASH_NEW_AUDIO_CHANNEL_CONFIGURATION_SCHEME_ID_URI + else: + scheme_id_uri = DOLBY_DIGITAL_AUDIO_CHANNEL_CONFIGURATION_SCHEME_ID_URI elif audio_track.codec.startswith('ac-4'): audio_channel_config_value = ComputeDolbyAc4AudioChannelConfig(audio_track) - scheme_id_uri = DOLBY_AC4_AUDIO_CHANNEL_CONFIGURATION_SCHEME_ID_URI + (mpeg_scheme, audio_channel_config_value) = DolbyAc4WithMPEGDASHScheme(audio_channel_config_value) + if (mpeg_scheme): + scheme_id_uri = MPEG_DASH_NEW_AUDIO_CHANNEL_CONFIGURATION_SCHEME_ID_URI + else: + scheme_id_uri = DOLBY_AC4_AUDIO_CHANNEL_CONFIGURATION_SCHEME_ID_URI else: # detect the actual number of channels sample_description = audio_track.info['sample_descriptions'][0] @@ -553,6 +597,22 @@ def OutputDash(options, set_attributes, audio_sets, video_sets, subtitles_sets, 'AudioChannelConfiguration', schemeIdUri=scheme_id_uri, value=audio_channel_config_value) + # DD+ Atmos SupplementalProperty + if audio_track.codec_family == 'ec-3' and audio_track.dolby_ddp_atmos == 'Yes': + xml.SubElement(representation, + 'SupplementalProperty', + schemeIdUri='tag:dolby.com,2018:dash:EC3_ExtensionType:2018', + value='JOC') + xml.SubElement(representation, + 'SupplementalProperty', + schemeIdUri='tag:dolby.com,2018:dash:EC3_ExtensionComplexityIndex:2018', + value=str(audio_track.complexity_index)) + # AC-4 IMS SupplementalProperty + if audio_track.codec_family == 'ac-4' and audio_track.dolby_ac4_ims == 'Yes': + xml.SubElement(representation, + 'SupplementalProperty', + schemeIdUri='tag:dolby.com,2016:dash:virtualized_content:2016', + value='1') if options.on_demand: base_url = xml.SubElement(representation, 'BaseURL') @@ -830,7 +890,7 @@ def OutputHls(options, set_attributes, audio_sets, video_sets, subtitles_sets, s all_video_tracks = sum(list(video_sets.values()), []) all_subtitles_tracks = sum(list(subtitles_sets.values()), []) - master_playlist_file = open(path.join(options.output_dir, options.hls_master_playlist_name), 'w', newline='\r\n') + master_playlist_file = open(path.join(options.output_dir, options.hls_master_playlist_name), 'w', encoding= 'utf-8', newline='\r\n') master_playlist_file.write('#EXTM3U\n') master_playlist_file.write('# Created with Bento4 mp4-dash.py, VERSION=' + VERSION + '-' + SDK_REVISION+'\n') master_playlist_file.write('#\n') @@ -840,20 +900,33 @@ def OutputHls(options, set_attributes, audio_sets, video_sets, subtitles_sets, s master_playlist_file.write('\n') master_playlist_file.write('# Audio\n') - audio_groups = {} - for adaptation_set_name, audio_tracks in list(audio_sets.items()): - language = audio_tracks[0].language - language_name = audio_tracks[0].language_name - audio_group_name = adaptation_set_name[0]+'/'+adaptation_set_name[2] + # Start to process audio tracks. + audio_groups = {} + # Re-group the audio tracks. (codec + channels, including DD+ Atmos and AC-4 IMS). + audio_sets = ReGroupAudioSets(audio_sets) + # Re-order audio tracks internally according to input order. + audio_sets = ReOrderAudioSetsInternally(audio_sets) + # Re-order the audio tracks according to input order via command line. + ordered_audio_track = ReOrderMediaTrack(audio_sets.values()) + + for audio_tracks in ordered_audio_track: + audio_channel_name = str(audio_tracks[0].channels) + if audio_channel_name.find('/JOC') != -1 or audio_channel_name.find('/IMS') != -1: + audio_channel_name = audio_channel_name.replace('/', '-') + else: + audio_channel_name += 'ch' + audio_group_name = 'audio' + '/'+ audio_tracks[0].codec_family + '/' + audio_channel_name audio_groups[audio_group_name] = { 'codec': '', + 'channels': '', 'average_segment_bitrate': 0, - 'max_segment_bitrate': 0 + 'max_segment_bitrate': 0, + 'group_order': ordered_audio_track.index(audio_tracks) + 1 } select_as_default = True for audio_track in audio_tracks: - # update the avergage and max bitrates + # update the average and max bitrates if audio_track.average_segment_bitrate > audio_groups[audio_group_name]['average_segment_bitrate']: audio_groups[audio_group_name]['average_segment_bitrate'] = audio_track.average_segment_bitrate if audio_track.max_segment_bitrate > audio_groups[audio_group_name]['max_segment_bitrate']: @@ -866,6 +939,13 @@ def OutputHls(options, set_attributes, audio_sets, video_sets, subtitles_sets, s if audio_groups[audio_group_name]['codec'] != audio_track.codec: print('WARNING: audio codecs not all the same:', audio_groups[audio_group_name]['codec'], audio_track.codec) + # update/check the channels + if audio_groups[audio_group_name]['channels'] == '': + audio_groups[audio_group_name]['channels'] = audio_track.channels + else: + if audio_groups[audio_group_name]['channels'] != audio_track.channels: + print ('WARNING: audio channels not all the same:', audio_groups[audio_group_name]['channels'], audio_track.channels) + if options.on_demand or not options.split: media_subdir = '' media_file_name = audio_track.parent.media_name @@ -877,85 +957,123 @@ def OutputHls(options, set_attributes, audio_sets, video_sets, subtitles_sets, s media_playlist_name = options.hls_media_playlist_name media_playlist_path = media_subdir+'/'+media_playlist_name + # different languages can be belonged to same group, so put here. + language = audio_track.language + language_name = audio_track.language_name group_name = audio_track.label if audio_track.label != '' else language_name - master_playlist_file.write('#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="{}",LANGUAGE="{}",NAME="{}",AUTOSELECT=YES,DEFAULT={},URI="{}"\n'.format( + master_playlist_file.write('#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="{}",LANGUAGE="{}",NAME="{}",AUTOSELECT=YES,DEFAULT={},CHANNELS="{}",URI="{}"\n'.format( audio_group_name, language, group_name, 'YES' if select_as_default else 'NO', + audio_track.channels, media_playlist_path)) select_as_default = False OutputHlsTrack(options, audio_track, all_audio_tracks + all_video_tracks, media_subdir, media_playlist_name, media_file_name) # Add an audio stream entry for audio-only presentations if not all_video_tracks: - master_playlist_file.write('#EXT-X-STREAM-INF:AUDIO="{}",AVERAGE-BANDWIDTH={:.0f},BANDWIDTH={:.0f},CODECS="{}"\n'.format( + master_playlist_file.write('#EXT-X-STREAM-INF:AUDIO="{}",AVERAGE-BANDWIDTH={:.0f},BANDWIDTH={:.0f},CHANNELS="{}",CODECS="{}"\n'.format( audio_group_name, audio_track.average_segment_bitrate, audio_track.max_segment_bitrate, + audio_track.channels, audio_track.codec)) master_playlist_file.write(media_playlist_path+'\n') + if PrintBlankLine(ordered_audio_track): + master_playlist_file.write('\n') + master_playlist_file.write('\n') - master_playlist_file.write('# Video\n') - iframe_playlist_lines = [] - subtitles_group = 'SUBTITLES="subtitles",' if subtitles_files else '' - for video_track in all_video_tracks: - if options.on_demand or not options.split: - media_subdir = '' - media_file_name = video_track.parent.media_name - media_playlist_name = video_track.representation_id+".m3u8" - media_playlist_path = media_playlist_name - iframes_playlist_name = video_track.representation_id+"_iframes.m3u8" - iframes_playlist_path = iframes_playlist_name - else: - media_subdir = video_track.representation_id - media_file_name = '' - media_playlist_name = options.hls_media_playlist_name - media_playlist_path = media_subdir+'/'+media_playlist_name - iframes_playlist_name = options.hls_iframes_playlist_name - iframes_playlist_path = media_subdir+'/'+iframes_playlist_name - - if audio_groups: - # one entry per audio group - for audio_group_name in audio_groups: - audio_codec = audio_groups[audio_group_name]['codec'] - master_playlist_file.write('#EXT-X-STREAM-INF:{}AUDIO="{}",AVERAGE-BANDWIDTH={:.0f},BANDWIDTH={:.0f},CODECS="{}",RESOLUTION={:.0f}x{:.0f},FRAME-RATE={:.3f}\n'.format( + + # Start to process video tracks + audio_group_name_list = [] + for audio_group_name in audio_groups: + audio_group_name_list.append(audio_group_name) + # Create the default audio groups + if len(audio_groups) == 0: + audio_groups['no_audio_group'] = { + 'codec': '', + 'channels': '', + 'average_segment_bitrate': 0, + 'max_segment_bitrate': 0, + 'group_order': -1 + } + # Group video sets according to the codec. + video_sets = GenVideoSets(all_video_tracks) + # It's not mandatory for ReGroupVideoSetsHLS function to handle avc1, avc2, avc3 and avc4. Put here just in case extending ReGroupVideoSetsHLS functionality. + regroup_video_sets = ReGroupVideoSetsHLS(video_sets.values()) + # Re-order video tracks according to input order via command line. + ordered_video_track = ReOrderMediaTrack(regroup_video_sets) + for video_group in ordered_video_track: + master_playlist_file.write('# Video {}\n'.format(video_group[0].codec_family.upper())) + iframe_playlist_lines = [] + subtitles_group = 'SUBTITLES="subtitles",' if subtitles_files else '' + # Flag used to avoid duplicated work when generating video tracks + processing_video_tracks = True + for idx in range(len(audio_groups)): + audio_group_name = FindAudioGroups(idx + 1, audio_groups) + for video_track in video_group: + if options.on_demand or not options.split: + media_subdir = '' + media_file_name = video_track.parent.media_name + media_playlist_name = video_track.representation_id+".m3u8" + media_playlist_path = media_playlist_name + iframes_playlist_name = video_track.representation_id+"_iframes.m3u8" + iframes_playlist_path = iframes_playlist_name + else: + media_subdir = video_track.representation_id + media_file_name = '' + media_playlist_name = options.hls_media_playlist_name + media_playlist_path = media_subdir+'/'+media_playlist_name + iframes_playlist_name = options.hls_iframes_playlist_name + iframes_playlist_path = media_subdir+'/'+iframes_playlist_name + + if audio_group_name != 'no_audio_group': + # one entry per audio group + audio_codec = audio_groups[audio_group_name]['codec'] + master_playlist_file.write('#EXT-X-STREAM-INF:{}AUDIO="{}",AVERAGE-BANDWIDTH={:.0f},BANDWIDTH={:.0f},VIDEO-RANGE={},CODECS="{}",RESOLUTION={:.0f}x{:.0f},FRAME-RATE={:.3f}\n'.format( + subtitles_group, + audio_group_name, + video_track.average_segment_bitrate + audio_groups[audio_group_name]['average_segment_bitrate'], + video_track.max_segment_bitrate + audio_groups[audio_group_name]['max_segment_bitrate'], + GetVideoRangeValue(video_track), + video_track.codec+','+audio_codec, + video_track.width, + video_track.height, + video_track.frame_rate)) + else: + # no audio + master_playlist_file.write('#EXT-X-STREAM-INF:{}AVERAGE-BANDWIDTH={:.0f},BANDWIDTH={:.0f},VIDEO-RANGE={},CODECS="{}",RESOLUTION={:.0f}x{:.0f},FRAME-RATE={:.3f}\n'.format( subtitles_group, - audio_group_name, - video_track.average_segment_bitrate + audio_groups[audio_group_name]['average_segment_bitrate'], - video_track.max_segment_bitrate + audio_groups[audio_group_name]['max_segment_bitrate'], - video_track.codec+','+audio_codec, + video_track.average_segment_bitrate, + video_track.max_segment_bitrate, + GetVideoRangeValue(video_track), + video_track.codec, video_track.width, video_track.height, video_track.frame_rate)) - master_playlist_file.write(media_playlist_path+'\n') - else: - # no audio - master_playlist_file.write('#EXT-X-STREAM-INF:{}AVERAGE-BANDWIDTH={:.0f},BANDWIDTH={:.0f},CODECS="{}",RESOLUTION={:.0f}x{:.0f},FRAME-RATE={:.3f}\n'.format( - subtitles_group, - video_track.average_segment_bitrate, - video_track.max_segment_bitrate, - video_track.codec, - video_track.width, - video_track.height, - video_track.frame_rate)) - master_playlist_file.write(media_playlist_path+'\n') - - OutputHlsTrack(options, video_track, all_audio_tracks + all_video_tracks, media_subdir, media_playlist_name, media_file_name) - iframe_average_segment_bitrate,iframe_max_bitrate = OutputHlsIframeIndex(options, video_track, all_audio_tracks + all_video_tracks, media_subdir, iframes_playlist_name, media_file_name) - - # this will be written later - iframe_playlist_lines.append('#EXT-X-I-FRAME-STREAM-INF:AVERAGE-BANDWIDTH={:.0f},BANDWIDTH={:.0f},CODECS="{}",RESOLUTION={:.0f}x{:.0f},URI="{}"\n'.format( - iframe_average_segment_bitrate, - iframe_max_bitrate, - video_track.codec, - video_track.width, - video_track.height, - iframes_playlist_path)) - - master_playlist_file.write('\n# I-Frame Playlists\n') - master_playlist_file.write(''.join(iframe_playlist_lines)) + master_playlist_file.write(media_playlist_path + '\n') + + if processing_video_tracks: + OutputHlsTrack(options, video_track, all_audio_tracks + all_video_tracks, media_subdir, media_playlist_name, media_file_name) + iframe_average_segment_bitrate,iframe_max_bitrate = OutputHlsIframeIndex(options, video_track, all_audio_tracks + all_video_tracks, media_subdir, iframes_playlist_name, media_file_name) + + # this will be written later + iframe_playlist_lines.append('#EXT-X-I-FRAME-STREAM-INF:AVERAGE-BANDWIDTH={:.0f},BANDWIDTH={:.0f},VIDEO-RANGE={},CODECS="{}",RESOLUTION={:.0f}x{:.0f},URI="{}"\n'.format( + iframe_average_segment_bitrate, + iframe_max_bitrate, + GetVideoRangeValue(video_track), + video_track.codec, + video_track.width, + video_track.height, + iframes_playlist_path)) + if len(video_group) > 1: + master_playlist_file.write('\n') + processing_video_tracks = False + master_playlist_file.write('# I-Frame Playlists {}\n'.format(video_group[0].codec_family.upper())) + master_playlist_file.write(''.join(iframe_playlist_lines)) + master_playlist_file.write('\n') # IMSC1 subtitles if all_subtitles_tracks: @@ -1044,7 +1162,11 @@ def OutputSmooth(options, audio_tracks, video_tracks): audio_tag = '65534' fourcc = 'EC-3' channels = str(channels) - data_rate = int(audio_track.info['sample_descriptions'][0]['dolby_digital_info']['data_rate']) + if audio_track.info['sample_descriptions'][0].has_key('dolby_digital_info'): + data_rate = int(audio_track.info['sample_descriptions'][0]['dolby_digital_info']['data_rate']) + else: + # set the default data rate value + data_rate = 256 packet_size = str(4*data_rate) else: # assume AAC @@ -1263,6 +1385,8 @@ def SelectTracks(options, media_sources): video_adaptation_sets = {} subtitles_adaptation_sets = {} label_indexes = {} + audio_source_idx = 0 + video_source_idx = 0 for media_source in media_sources: track_id = media_source.spec['track'] track_type = media_source.spec['type'] @@ -1322,6 +1446,10 @@ def SelectTracks(options, media_sources): # label track.label = media_source.spec.get('+label', '') + # Set'ac-3' and 'ec-3' channels correctly. + if track.codec_family == 'ac-3' or track.codec_family == 'ec-3': + (track.channels, _channels) = GetDolbyDigitalPlusChannels(track) + # update label indexes (so that we can use numbers instead of strings for labels) for track in tracks: if track.label not in label_indexes: @@ -1338,22 +1466,34 @@ def SelectTracks(options, media_sources): adaptation_set = audio_adaptation_sets.get(adaptation_set_name, []) # only keep this track if there isn't already a track with the same - # codec at the same bitrate (within 10%) - with_same_bandwidth = [t for t in adaptation_set if abs(float(t.bandwidth-track.bandwidth)/float(t.bandwidth)) < 0.1] + # codec at the same bitrate (within 10%), and have same channel numbers. + with_same_bandwidth = [t for t in adaptation_set if abs(float(t.bandwidth-track.bandwidth)/float(t.bandwidth)) < 0.1 and t.channels == track.channels] if with_same_bandwidth: continue audio_adaptation_sets[adaptation_set_name] = adaptation_set + + audio_source_idx += 1 adaptation_set.append(track) track.order_index = len(adaptation_set) + if hasattr(media_source, 'input_order'): + track.input_order = media_source.input_order + else: + track.input_order = audio_source_idx # process video tracks for track in [t for t in tracks if t.type == 'video']: adaptation_set_name = ('video', track.codec_family) adaptation_set = video_adaptation_sets.get(adaptation_set_name, []) video_adaptation_sets[adaptation_set_name] = adaptation_set + + video_source_idx += 1 adaptation_set.append(track) track.order_index = len(adaptation_set) + if hasattr(media_source, 'input_order'): + track.input_order = media_source.input_order + else: + track.input_order = video_source_idx # process subtitle tracks if options.subtitles: @@ -1909,7 +2049,10 @@ def main(): if options.on_demand: (audio_sets, video_sets, subtitles_sets, mp4_files) = SelectTracks(options, media_sources) media_sources = [x for x in media_sources if x.format == "webvtt"] # Keep subtitles - for track in sum(list(audio_sets.values()) + list(video_sets.values()), []): + # Just for display order (log information) is correct, it's not mandatory. + ordered_audio_track = ReOrderMediaTrack(audio_sets.values()) + ordered_video_track = ReOrderMediaTrack(video_sets.values()) + for track in sum(ordered_audio_track + ordered_video_track, []): print('Extracting track', track.id, 'from', GetMappedFileName(track.parent.media_source.filename)) track_file = tempfile.NamedTemporaryFile(dir=options.output_dir, delete=False) TempFiles.append(track_file.name) @@ -1926,6 +2069,8 @@ def main(): media_source = MediaSource(options, track_file.name) media_source.spec = track.parent.media_source.spec + if hasattr(track, 'input_order'): + media_source.input_order = track.input_order media_sources.append(media_source) # compute the KID(s) and encryption key(s) @@ -2122,6 +2267,10 @@ def main(): media_filename = path.join(out_dir, subtitles_file.media_name) shutil.copyfile(subtitles_file.media_source.filename, media_filename) + # Dual entry for Dolby Vision profile 8 + DolbyVisionProfile8DualEntry(video_sets, 'hvc1', 'dvh1') + DolbyVisionProfile8DualEntry(video_sets, 'hev1', 'dvhe') + # output the DASH MPD OutputDash(options, set_attributes, audio_sets, video_sets, subtitles_sets, subtitles_files) diff --git a/Source/Python/utils/mp4-hls.py b/Source/Python/utils/mp4-hls.py index af2aafeb4..c07490e7c 100644 --- a/Source/Python/utils/mp4-hls.py +++ b/Source/Python/utils/mp4-hls.py @@ -27,7 +27,11 @@ LanguageNames,\ LanguageCodeMap,\ PrintErrorAndExit,\ - MakeNewDir + MakeNewDir,\ + ContainDolbyVision,\ + ContainAtmosAndAC4,\ + PrintBlankLine,\ + GetDolbyDigitalPlusChannels # setup main options VERSION = "1.2.0" @@ -57,6 +61,8 @@ def ComputeCodecName(codec_family): name = 'ac3' elif codec_family == 'ec-3': name = 'ec3' + elif codec_family == 'ac-4': + name = 'ac4' return name ############################################# @@ -152,6 +158,9 @@ def AnalyzeSources(options, media_sources): media_source.has_video = True if track.type == 'audio': media_source.has_audio = True + # 'ac-3' and 'ec-3' channels + if track.codec_family == 'ac-3' or track.codec_family == 'ec-3': + (track.channels, _channels) = GetDolbyDigitalPlusChannels(track) media_source.tracks = tracks @@ -175,7 +184,15 @@ def SelectAudioTracks(options, media_sources): # process audio tracks for track in [t for t in media_source.tracks if t.type == 'audio']: - group_id = track.group_id + if track.codec_family == 'ec-3' and track.dolby_ddp_atmos == 'Yes': + complexity_idx = str(track.info['sample_descriptions'][0]['dolby_digital_info']['Dolby Atmos Complexity Index']) + group_id = track.group_id + '_' + complexity_idx + '_JOC' + track.channels = complexity_idx + '/JOC' + elif track.codec_family == 'ac-4' and (track.dolby_ac4_ims == 'Yes' or track.dolby_ac4_cbi == 'Yes'): + group_id = track.group_id + '_' + str(track.channels) + '_IMS' + track.channels = str(track.channels) + '/IMS' + else: + group_id = track.group_id + '_' + str(track.channels) + 'ch' group = audio_tracks.get(group_id, []) audio_tracks[group_id] = group if len([x for x in group if x.language == track.language]): @@ -345,6 +362,8 @@ def OutputHls(options, media_sources): } if options.audio_format == 'packed': audio_track.media_info['file_extension'] = ComputeCodecName(audio_track.codec_family) + elif ContainAtmosAndAC4(audio_tracks.values()): + PrintErrorAndExit('ERROR: For DD+/Atmos and AC-4, the format of segment audio must be packed audio, please add "--audio-format packed"') # process the source out_dir = path.join(options.output_dir, 'audio', group_id, audio_track.language) @@ -355,7 +374,8 @@ def OutputHls(options, media_sources): master_playlist = open(path.join(options.output_dir, options.master_playlist_name), 'w', newline='\r\n') master_playlist.write('#EXTM3U\n') master_playlist.write('# Created with Bento4 mp4-hls.py version '+VERSION+'r'+SDK_REVISION+'\n') - + if ContainDolbyVision(main_media): + PrintErrorAndExit('ERROR: For Dolby Vision, the format of segment video must be fragemnted MP4, please use mp4-dash.py') if options.hls_version >= 4: master_playlist.write('\n') master_playlist.write('#EXT-X-VERSION:'+str(options.hls_version)+'\n') @@ -409,10 +429,11 @@ def OutputHls(options, media_sources): if default: extra_info += 'DEFAULT=YES,' default = False - master_playlist.write(('#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="%s",NAME="%s",LANGUAGE="%s",%sURI="%s"\n' % ( + master_playlist.write(('#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="%s",NAME="%s",LANGUAGE="%s",CHANNELS="%s",%sURI="%s"\n' % ( group_name, audio_track.media_info['language_name'], audio_track.media_info['language'], + str(audio_track.channels), extra_info, options.base_url+audio_track.media_info['dir']+'/'+options.media_playlist_name))) audio_groups.append({ @@ -421,6 +442,8 @@ def OutputHls(options, media_sources): 'avg_segment_bitrate': group_avg_segment_bitrate, 'max_segment_bitrate': group_max_segment_bitrate }) + if PrintBlankLine(audio_tracks.values()): + master_playlist.write('\n') if options.debug: print('Audio Groups:') @@ -470,6 +493,7 @@ def OutputHls(options, media_sources): master_playlist.write(ext_x_stream_inf+'\n') master_playlist.write(options.base_url+media['dir']+'/'+options.media_playlist_name+'\n') + master_playlist.write('\n') # write the I-FRAME playlist info if not audio_only and options.hls_version >= 4: diff --git a/Source/Python/utils/mp4utils.py b/Source/Python/utils/mp4utils.py index c53e9a4a0..1e6a0a32c 100644 --- a/Source/Python/utils/mp4utils.py +++ b/Source/Python/utils/mp4utils.py @@ -6,6 +6,7 @@ import sys import os +import copy import os.path as path from subprocess import check_output, CalledProcessError import json @@ -429,6 +430,22 @@ def __init__(self, parent, info): if self.type == 'audio': self.sample_rate = sample_desc['sample_rate'] self.channels = sample_desc['channels'] + # Set the default values for Dolby audio codec flags + self.dolby_ddp_atmos = 'No' + self.dolby_ac4_ims = 'No' + self.dolby_ac4_cbi = 'No' + self.self_contained = 'Yes' + if self.codec_family == 'ec-3' and 'dolby_digital_info' in sample_desc: + self.dolby_ddp_atmos = sample_desc['dolby_digital_info']['Dolby Digital Plus with Dolby Atmos'] + if (self.dolby_ddp_atmos == 'Yes'): + self.complexity_index = sample_desc['dolby_digital_info']['Dolby Atmos Complexity Index'] + elif self.codec_family == 'ac-4' and 'dolby_ac4_info' in sample_desc: + stream_type = sample_desc['dolby_ac4_info']['presentations'][0]['Stream Type'] + if stream_type == 'Immersive stereo': + self.dolby_ac4_ims = 'Yes' + elif stream_type == 'Channel based immsersive': + self.dolby_ac4_cbi = 'Yes' + self.self_contained = sample_desc['dolby_ac4_info']['Self Contained'] self.language = info['language'] self.language_name = LanguageNames.get(LanguageCodeMap.get(self.language, 'und'), '') @@ -859,11 +876,14 @@ def GetDolbyDigitalPlusChannels(track): sample_desc = track.info['sample_descriptions'][0] if 'dolby_digital_info' not in sample_desc: return (track.channels, []) - dd_info = sample_desc['dolby_digital_info']['substreams'][0] + if 'substreams' in sample_desc['dolby_digital_info']: + dd_info = sample_desc['dolby_digital_info']['substreams'][0] + else: + dd_info = sample_desc['dolby_digital_info']['stream_info'] channels = DolbyDigital_acmod[dd_info['acmod']][:] if dd_info['lfeon'] == 1: channels.append('LFE') - if dd_info['num_dep_sub'] and 'chan_loc' in dd_info: + if 'num_dep_sub' in dd_info and dd_info['num_dep_sub'] and 'chan_loc' in dd_info: chan_loc_value = dd_info['chan_loc'] for i in range(9): if chan_loc_value & (1< 1: + return True + return False + +def FindAudioGroups(expected_order_idx, audio_groups): + for name, value in audio_groups.items(): + if value['group_order'] == expected_order_idx: + return name + return 'no_audio_group' + +def ContainDolbyVision(video_tracks): + for track in video_tracks: + codecs = track['info']['video']['codec'].split(',') + for codec in codecs: + if codec.split('.')[0] in ['dvh1', 'dvhe']: + return True + return False + +def ContainAtmosAndAC4(audio_sets): + for audio_tracks in audio_sets: + if audio_tracks[0].codec_family in ['ac-4']: + return True + if audio_tracks[0].codec_family in ['ec-3'] and audio_tracks[0].dolby_ddp_atmos == 'Yes': + return True + return False + def ComputeDolbyDigitalPlusAudioChannelMask(track): masks = { 'L': 0x1, # SPEAKER_FRONT_LEFT 'R': 0x2, # SPEAKER_FRONT_RIGHT - 'C': 0x4, # SPEAKER_FRONT_CENTER + 'C': 0x4, # SPEAKER_FRONT_CENTER 'LFE': 0x8, # SPEAKER_LOW_FREQUENCY 'Ls': 0x10, # SPEAKER_BACK_LEFT 'Rs': 0x20, # SPEAKER_BACK_RIGHT @@ -953,7 +1183,8 @@ def ComputeDolbyDigitalPlusSmoothStreamingInfo(track): mask_hex_be = "{0:0{1}x}".format(channel_mask, 4) info += mask_hex_be[2:4]+mask_hex_be[0:2]+'0000' info += "af87fba7022dfb42a4d405cd93843bdd" - info += track.info['sample_descriptions'][0]['dolby_digital_info']['dec3_payload'] + if 'dolby_digital_info' in track.info['sample_descriptions'][0]: + info += track.info['sample_descriptions'][0]['dolby_digital_info']['dec3_payload'] return (channel_count, info.lower()) def ComputeMarlinPssh(options):