Skip to content

Commit

Permalink
[media] Implement IAMF audio parsing (youtube#2279)
Browse files Browse the repository at this point in the history
Cherry-picks
https://chromium-review.googlesource.com/c/chromium/src/+/5128755 and
adds minor changes to allow it to build.
Original CL description follows.

Adds an IAMF codec definition and implements IAMF MP4 parsing for
v1.0.0. The implementation is disabled by default.

Immersive Audio Model and Formats v1.0.0
https://aomediacodec.github.io/iamf/v1.0.0.html

b/271301103
  • Loading branch information
osagie98 committed Jan 25, 2024
1 parent 79920bc commit 5868085
Show file tree
Hide file tree
Showing 20 changed files with 438 additions and 18 deletions.
1 change: 1 addition & 0 deletions third_party/chromium/media/BUILD.gn.chromium
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ buildflag_header("media_buildflags") {
"ENABLE_MEDIA_REMOTING=$enable_media_remoting",
"ENABLE_MEDIA_REMOTING_RPC=$enable_media_remoting_rpc",
"ENABLE_OPENH264=$media_use_openh264",
"ENABLE_PLATFORM_IAMF_AUDIO=$enable_platform_iamf_audio",
"ENABLE_PLATFORM_MPEG_H_AUDIO=$enable_platform_mpeg_h_audio",
"ENABLE_MSE_MPEG2TS_STREAM_PARSER=$enable_mse_mpeg2ts_stream_parser",
"ENABLE_CAST_STREAMING_RENDERER=$enable_cast_streaming_renderer",
Expand Down
122 changes: 122 additions & 0 deletions third_party/chromium/media/base/audio_codecs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#include <ostream>

#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"

namespace media {
Expand Down Expand Up @@ -37,6 +39,8 @@ std::string GetCodecName(AudioCodec codec) {
return "gsm_ms";
case AudioCodec::kOpus:
return "opus";
case AudioCodec::kIAMF:
return "iamf";
case AudioCodec::kPCM_ALAW:
return "pcm_alaw";
case AudioCodec::kEAC3:
Expand All @@ -56,6 +60,10 @@ std::string GetProfileName(AudioCodecProfile profile) {
return "unknown";
case AudioCodecProfile::kXHE_AAC:
return "xhe-aac";
case AudioCodecProfile::kIAMF_SIMPLE:
return "iamf-simple";
case AudioCodecProfile::kIAMF_BASE:
return "iamf-base";
}
}

Expand All @@ -82,11 +90,125 @@ AudioCodec StringToAudioCodec(const std::string& codec_id) {
return AudioCodec::kVorbis;
if (base::StartsWith(codec_id, "mp4a.40.", base::CompareCase::SENSITIVE))
return AudioCodec::kAAC;
if (codec_id == "iamf" ||
base::StartsWith(codec_id, "iamf.", base::CompareCase::SENSITIVE)) {
return AudioCodec::kIAMF;
}
return AudioCodec::kUnknown;
}

std::ostream& operator<<(std::ostream& os, const AudioCodec& codec) {
return os << GetCodecName(codec);
}

#if BUILDFLAG(ENABLE_PLATFORM_IAMF_AUDIO)
bool ParseIamfCodecId(std::string_view codec_id,
uint8_t* primary_profilec,
uint8_t* additional_profilec) {
// Reference: Immersive Audio Model and Formats;
// v1.0.0
// 6.3. Codecs Parameter String
// (https://aomediacodec.github.io/iamf/v1.0.0.html#codecsparameter)
if (!(std::string(codec_id).find("iamf") == 0)) {
return false;
}

// For test purposes only, just "iamf" is acceptable.
if (codec_id == "iamf") {
return true;
}

constexpr int kMaxIamfCodecIdLength =
4 // FOURCC string "iamf".
+ 1 // delimiting period.
+ 3 // primary_profile as 3 digit string.
+ 1 // delimiting period.
+ 3 // additional_profile as 3 digit string.
+ 1 // delimiting period.
+ 9; // The remaining string is one of
// "opus", "mp4a.40.2", "flac", "ipcm".

if (codec_id.size() > kMaxIamfCodecIdLength) {
DVLOG(4) << __func__ << ": Codec id is too long (" << codec_id << ")";
return false;
}

std::vector<std::string> elem = base::SplitString(
std::string(codec_id), ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
if (elem.size() < 4) {
DVLOG(4) << __func__ << ": invalid IAMF codec id:" << codec_id;
return false;
}

DCHECK_EQ(elem[0], "iamf");

if (StringToAudioCodec(elem[0]) != AudioCodec::kIAMF) {
DVLOG(4) << __func__ << ": invalid IAMF codec id:" << codec_id;
return false;
}

// The primary profile string should be three digits, and should be between 0
// and 255 inclusive.
uint32_t primary_profile = 0;
if (elem[1].size() != 3 || !base::StringToUint(elem[1], &primary_profile) ||
primary_profile > 0xFF) {
DVLOG(4) << __func__ << ": invalid IAMF primary profile: " << elem[1];
return false;
}

// The additional profile string should be three digits, and should be between
// 0 and 255 inclusive.
uint32_t additional_profile = 0;
if (elem[2].size() != 3 ||
!base::StringToUint(elem[2], &additional_profile) ||
additional_profile > 0xFF) {
DVLOG(4) << __func__ << ": invalid IAMF additional profile: " << elem[2];
return false;
}

// The codec string should be one of "opus", "mp4a", "flac", or "ipcm".
std::string codec = base::ToLowerASCII(elem[3]);
if (codec.size() != 4 || ((codec != "opus") && (codec != "mp4a") &&
(codec != "flac") && (codec != "ipcm"))) {
DVLOG(4) << __func__ << ": invalid IAMF stream codec: " << elem[3];
return false;
}

if (codec == "mp4a") {
if (elem.size() != 6) {
DVLOG(4) << __func__
<< ": incorrect mp4a codec string syntax:" << codec_id;
return false;
}

// The fields following "mp4a" should be "40" and "2" to signal AAC-LC.
uint32_t object_type_indication = 0;
if (elem[4].size() != 2 ||
!base::HexStringToUInt(elem[4], &object_type_indication) ||
object_type_indication != 0x40) {
DVLOG(4) << __func__
<< ": invalid mp4a Object Type Indication:" << codec_id;
return false;
}

uint32_t audio_object_type = 0;
if (elem[5].size() != 1 ||
!base::HexStringToUInt(elem[5], &audio_object_type) ||
audio_object_type != 0x02) {
DVLOG(4) << __func__ << ": invalid mp4a Audio Object Type:" << codec_id;
return false;
}
}

if (primary_profilec) {
*primary_profilec = primary_profile;
}

if (additional_profilec) {
*additional_profilec = additional_profile;
}

return true;
}
#endif // BUILDFLAG(ENABLE_PLATFORM_IAMF_AUDIO)
} // namespace media
17 changes: 15 additions & 2 deletions third_party/chromium/media/base/audio_codecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@
#ifndef MEDIA_BASE_AUDIO_CODECS_H_
#define MEDIA_BASE_AUDIO_CODECS_H_

#include <stdint.h>

#include <string>
#include <string_view>

#include "media/base/media_export.h"
#include "media/media_buildflags.h"

namespace media {

Expand All @@ -33,13 +38,14 @@ enum class AudioCodec {
kALAC = 15,
kAC3 = 16,
kMpegHAudio = 17,
kIAMF = 22,
// DO NOT ADD RANDOM AUDIO CODECS!
//
// The only acceptable time to add a new codec is if there is production code
// that uses said codec in the same CL.

// Must always be equal to the largest entry ever logged.
kMaxValue = kMpegHAudio,
kMaxValue = kIAMF,
};

enum class AudioCodecProfile {
Expand All @@ -49,7 +55,9 @@ enum class AudioCodecProfile {
// kMaxValue to equal the new codec.
kUnknown = 0,
kXHE_AAC = 1,
kMaxValue = kXHE_AAC,
kIAMF_SIMPLE = 2,
kIAMF_BASE = 3,
kMaxValue = kIAMF_BASE,
};

std::string MEDIA_EXPORT GetCodecName(AudioCodec codec);
Expand All @@ -58,6 +66,11 @@ std::string MEDIA_EXPORT GetProfileName(AudioCodecProfile profile);
MEDIA_EXPORT std::ostream& operator<<(std::ostream& os,
const AudioCodec& codec);
MEDIA_EXPORT AudioCodec StringToAudioCodec(const std::string& codec_id);
#if BUILDFLAG(ENABLE_PLATFORM_IAMF_AUDIO)
MEDIA_EXPORT bool ParseIamfCodecId(std::string_view codec_id,
uint8_t* primary_profilec,
uint8_t* additional_profilec);
#endif // BUILDFLAG(ENABLE_PLATFORM_IAMF_AUDIO)

} // namespace media

Expand Down
4 changes: 4 additions & 0 deletions third_party/chromium/media/base/eme_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ enum EmeCodec : uint32_t {
EME_CODEC_FLAC = 1 << 13,
EME_CODEC_AV1 = 1 << 14,
EME_CODEC_HEVC_PROFILE_MAIN10 = 1 << 15,
EME_CODEC_IAMF = 1 << 23,
};

// *_ALL values should only be used for masking, do not use them to specify
Expand All @@ -60,6 +61,9 @@ constexpr SupportedCodecs GetMp4AudioCodecs() {
codecs |= EME_CODEC_MPEG_H_AUDIO;
#endif // BUILDFLAG(ENABLE_PLATFORM_MPEG_H_AUDIO)
#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
#if BUILDFLAG(ENABLE_PLATFORM_IAMF_AUDIO)
codecs |= EME_CODEC_IAMF;
#endif // BUILDFLAG(ENABLE_PLATFORM_IAMF_AUDIO)
return codecs;
}

Expand Down
2 changes: 2 additions & 0 deletions third_party/chromium/media/base/key_systems.cc
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ EmeCodec ToAudioEmeCodec(AudioCodec codec) {
return EME_CODEC_EAC3;
case AudioCodec::kAC3:
return EME_CODEC_AC3;
case AudioCodec::kIAMF:
return EME_CODEC_IAMF;
case AudioCodec::kMpegHAudio:
return EME_CODEC_MPEG_H_AUDIO;
default:
Expand Down
15 changes: 15 additions & 0 deletions third_party/chromium/media/base/mime_util_internal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ AudioCodec MimeUtilToAudioCodec(MimeUtil::Codec codec) {
return AudioCodec::kOpus;
case MimeUtil::FLAC:
return AudioCodec::kFLAC;
case MimeUtil::IAMF:
return AudioCodec::kIAMF;
default:
break;
}
Expand Down Expand Up @@ -345,6 +347,10 @@ void MimeUtil::AddSupportedMediaFormats() {
mp4_video_codecs.emplace(AV1);
#endif

#if BUILDFLAG(ENABLE_PLATFORM_IAMF_AUDIO)
mp4_audio_codecs.emplace(IAMF);
#endif // BUILDFLAG(ENABLE_PLATFORM_IAMF_AUDIO)

CodecSet mp4_codecs(mp4_audio_codecs);
mp4_codecs.insert(mp4_video_codecs.begin(), mp4_video_codecs.end());

Expand Down Expand Up @@ -670,6 +676,8 @@ bool MimeUtil::IsCodecSupportedOnAndroid(
#else
return false;
#endif
case IAMF:
return false;
}

return false;
Expand Down Expand Up @@ -863,6 +871,13 @@ bool MimeUtil::ParseCodecHelper(const std::string& mime_type_lower_case,
}
#endif

#if BUILDFLAG(ENABLE_PLATFORM_IAMF_AUDIO)
if (ParseIamfCodecId(codec_id.data(), nullptr, nullptr)) {
out_result->codec = MimeUtil::IAMF;
return true;
}
#endif

DVLOG(2) << __func__ << ": Unrecognized codec id \"" << codec_id << "\"";
return false;
}
Expand Down
3 changes: 2 additions & 1 deletion third_party/chromium/media/base/mime_util_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ class MEDIA_EXPORT MimeUtil {
DOLBY_VISION,
AV1,
MPEG_H_AUDIO,
LAST_CODEC = MPEG_H_AUDIO
IAMF,
LAST_CODEC = IAMF
};

// Platform configuration structure. Controls which codecs are supported at
Expand Down
8 changes: 8 additions & 0 deletions third_party/chromium/media/base/mime_util_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,10 @@ TEST(IsCodecSupportedOnAndroidTest, EncryptedCodecBehavior) {
case MimeUtil::AV1:
EXPECT_EQ(BUILDFLAG(ENABLE_AV1_DECODER), result);
break;

case MimeUtil::IAMF:
EXPECT_EQ(HasIamfSupport(), result);
break;
}
});
}
Expand Down Expand Up @@ -677,6 +681,10 @@ TEST(IsCodecSupportedOnAndroidTest, ClearCodecBehavior) {
case MimeUtil::AV1:
EXPECT_EQ(BUILDFLAG(ENABLE_AV1_DECODER), result);
break;

case MimeUtil::IAMF:
EXPECT_EQ(HasIamfSupport(), result);
break;
}
});
}
Expand Down
2 changes: 2 additions & 0 deletions third_party/chromium/media/base/supported_types.cc
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ bool IsAudioCodecProprietary(AudioCodec codec) {
return true;

case AudioCodec::kFLAC:
case AudioCodec::kIAMF:
case AudioCodec::kMP3:
case AudioCodec::kOpus:
case AudioCodec::kVorbis:
Expand Down Expand Up @@ -291,6 +292,7 @@ bool IsDefaultSupportedAudioType(const AudioType& type) {
case AudioCodec::kALAC:
case AudioCodec::kAC3:
case AudioCodec::kMpegHAudio:
case AudioCodec::kIAMF:
case AudioCodec::kUnknown:
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ void MediaCodecAudioDecoder::Initialize(const AudioDecoderConfig& config,
config.codec() == AudioCodec::kFLAC ||
config.codec() == AudioCodec::kAAC ||
config.codec() == AudioCodec::kOpus ||
config.codec() == AudioCodec::kIAMF ||
is_passthrough_;
if (!is_codec_supported) {
DVLOG(1) << "Unsuported codec " << GetCodecName(config.codec());
Expand Down
Loading

0 comments on commit 5868085

Please sign in to comment.