#include "media/base/audio_codecs.h"
#include <ostream>
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
namespace media {
std::string GetCodecName(AudioCodec codec) { … }
std::string GetProfileName(AudioCodecProfile profile) { … }
AudioCodec StringToAudioCodec(const std::string& codec_id) { … }
std::ostream& operator<<(std::ostream& os, const AudioCodec& codec) { … }
#if BUILDFLAG(ENABLE_PLATFORM_AC4_AUDIO)
bool ParseDolbyAc4CodecId(const std::string& codec_id,
uint8_t* bitstream_versionc,
uint8_t* presentation_versionc,
uint8_t* presentation_levelc) {
if (!base::StartsWith(codec_id, "ac-4")) {
return false;
}
const int kMaxAc4CodecIdLength =
4
+ 1
+ 2
+ 1
+ 2
+ 1
+ 2;
if (codec_id.size() > kMaxAc4CodecIdLength) {
DVLOG(4) << __func__ << ": Codec id is too long (" << codec_id << ")";
return false;
}
std::vector<std::string> elem = base::SplitString(
codec_id, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
DCHECK(elem[0] == "ac-4");
if (elem.size() != 4) {
DVLOG(4) << __func__ << ": invalid Dolby AC-4 codec id:" << codec_id;
return false;
}
if (StringToAudioCodec(elem[0]) != AudioCodec::kAC4) {
DVLOG(4) << __func__ << ": invalid Dolby AC-4 codec id:" << codec_id;
return false;
}
unsigned bitstream_version = 0;
if (elem[1].size() != 2 ||
!base::HexStringToUInt(elem[1], &bitstream_version) ||
bitstream_version != 0x02) {
DVLOG(4) << __func__
<< ": invalid Dolby AC-4 bitstream version: " << elem[1];
return false;
}
unsigned presentation_version = 0;
if (elem[2].size() != 2 ||
!base::HexStringToUInt(elem[2], &presentation_version) ||
!(presentation_version == 0x01 || presentation_version == 0x02)) {
DVLOG(4) << __func__
<< ": invalid Dolby AC-4 presentation_version: " << elem[1];
return false;
}
unsigned presentation_level = 0;
if (elem[3].size() != 2 ||
!base::HexStringToUInt(elem[3], &presentation_level) ||
presentation_level > 0x07) {
DVLOG(4) << __func__
<< ": invalid Dolby AC-4 presentation_level: " << elem[1];
return false;
}
if (bitstream_versionc) {
*bitstream_versionc = bitstream_version;
}
if (presentation_versionc) {
*presentation_versionc = presentation_version;
}
if (presentation_levelc) {
*presentation_levelc = presentation_level;
}
return true;
}
#endif
#if BUILDFLAG(ENABLE_PLATFORM_IAMF_AUDIO)
bool ParseIamfCodecId(std::string_view codec_id,
uint8_t* primary_profilec,
uint8_t* additional_profilec) {
if (!codec_id.starts_with("iamf")) {
return false;
}
if (codec_id == "iamf") {
return true;
}
constexpr int kMaxIamfCodecIdLength =
4
+ 1
+ 3
+ 1
+ 3
+ 1
+ 9;
if (codec_id.size() > kMaxIamfCodecIdLength) {
DVLOG(4) << __func__ << ": Codec id is too long (" << codec_id << ")";
return false;
}
std::vector<std::string> elem = base::SplitString(
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;
}
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;
}
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;
}
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;
}
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
}