Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MPEG-H support #952

Merged
merged 10 commits into from
Jun 30, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

3Q GmbH <*@3qsdn.com>
Alen Vrecko <[email protected]>
Amazon Music <*@amazon.com>
Anders Hasselqvist <[email protected]>
Audible <*@audible.com>
Chun-da Chen <[email protected]>
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,5 @@ Sanil Raut <[email protected]>
Sergio Ammirata <[email protected]>
Thomas Inskip <[email protected]>
Tim Lansen <[email protected]>
Vincent Nguyen <[email protected]>
Weiguo Shao <[email protected]>
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Shaka Packager supports:
| MP3 | O | - | I / O | - | O |
| Dolby AC3 | I / O | - | I / O | - | O |
| Dolby EAC3 | I / O | - | O | - | O |
| MPEG-H Audio | I / O | - | - | - | - |
| Dolby AC4 | I / O | - | - | - | - |
| DTS | I / O | - | - | - | - |
| FLAC | I / O | - | - | - | - |
Expand Down
20 changes: 20 additions & 0 deletions packager/media/base/audio_stream_info.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,17 @@ std::string AudioCodecToString(Codec codec) {
return "UnknownCodec";
}
}

FourCC CodecToFourCC(Codec codec) {
switch (codec) {
case kCodecMha1:
return FOURCC_mha1;
case kCodecMhm1:
return FOURCC_mhm1;
default:
return FOURCC_NULL;
}
}
} // namespace

AudioStreamInfo::AudioStreamInfo(
Expand Down Expand Up @@ -139,6 +150,15 @@ std::string AudioStreamInfo::GetCodecString(Codec codec,
return "mp3";
case kCodecVorbis:
return "vorbis";
case kCodecMha1:
case kCodecMhm1:
// The signalling of the codecs parameters is according to RFC6381 [11]
// and ISO/IEC 23008-3 clause 21 [7].
// The value consists of the following two parts separated by a dot:
// - the sample entry 4CC code ('mha1', 'mha2', 'mhm1', 'mhm2')
// - ‘0x’ followed by the hex value of the profile-levelid, as defined
// in in ISO/IEC 23008-3 [7]
return base::StringPrintf("%s.0x%02x", FourCCToString(CodecToFourCC(codec)).c_str(), audio_object_type);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

80 characters line limit.

Can you break it into three lines, e.g.

      return base::StringPrintf("%s.0x%02x",
                                FourCCToString(CodecToFourCC(codec)).c_str(),
                                audio_object_type);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies, I missed that one. Fixed.

default:
NOTIMPLEMENTED() << "Codec: " << codec;
return "unknown";
Expand Down
3 changes: 3 additions & 0 deletions packager/media/base/fourccs.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ enum FourCC : uint32_t {
FOURCC_meco = 0x6d65636f,
FOURCC_mehd = 0x6d656864,
FOURCC_meta = 0x6d657461,
FOURCC_mha1 = 0x6d686131,
FOURCC_mhaC = 0x6d686143,
FOURCC_mhm1 = 0x6d686d31,
Comment on lines +92 to +94
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for not noticing it earlier. I think it has to be moved after line 94 to follow alphabetical order.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arranged to alphabetical order.

FOURCC_mfhd = 0x6d666864,
FOURCC_mfra = 0x6d667261,
FOURCC_minf = 0x6d696e66,
Expand Down
2 changes: 2 additions & 0 deletions packager/media/base/stream_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ enum Codec {
kCodecOpus,
kCodecVorbis,
kCodecMP3,
kCodecMha1,
kCodecMhm1,
Comment on lines +57 to +58
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you move them before kCodecAudioMaxPlusOne, i.e. before line 57?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

kCodecAudioMaxPlusOne,

kCodecText = 300,
Expand Down
26 changes: 25 additions & 1 deletion packager/media/formats/mp4/box_definitions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1709,6 +1709,29 @@ size_t ElementaryStreamDescriptor::ComputeSizeInternal() {
return HeaderSize() + es_descriptor.ComputeSize();
}

MHAConfiguration::MHAConfiguration() = default;
MHAConfiguration::~MHAConfiguration() = default;

FourCC MHAConfiguration::BoxType() const {
return FOURCC_mhaC;
}

bool MHAConfiguration::ReadWriteInternal(BoxBuffer* buffer) {
RCHECK(ReadWriteHeaderInternal(buffer) &&
buffer->ReadWriteVector(
&data, buffer->Reading() ? buffer->BytesLeft() : data.size()));
RCHECK(data.size() > 1);
mpeg_h_3da_profile_level_indication = data[1];
Comment on lines +1723 to +1724
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be inside an if (buffer->Reading()) condition? i.e.

  if (buffer->Reading()) {
    RCHECK(data.size() > 1);
    mpeg_h_3da_profile_level_indication = data[1];
  }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is better I think, though it does not really matter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I just left it alone.

return true;
}

size_t MHAConfiguration::ComputeSizeInternal() {
// This box is optional. Skip it if not initialized.
if (data.empty())
return 0;
return HeaderSize() + data.size();
}

DTSSpecific::DTSSpecific() = default;
DTSSpecific::~DTSSpecific() = default;
;
Expand Down Expand Up @@ -1922,6 +1945,7 @@ bool AudioSampleEntry::ReadWriteInternal(BoxBuffer* buffer) {
RCHECK(buffer->TryReadWriteChild(&dac4));
RCHECK(buffer->TryReadWriteChild(&dops));
RCHECK(buffer->TryReadWriteChild(&dfla));
RCHECK(buffer->TryReadWriteChild(&mhac));

// Somehow Edge does not support having sinf box before codec_configuration,
// box, so just do it in the end of AudioSampleEntry. See
Expand All @@ -1947,7 +1971,7 @@ size_t AudioSampleEntry::ComputeSizeInternal() {
sizeof(samplesize) + sizeof(samplerate) + sinf.ComputeSize() +
esds.ComputeSize() + ddts.ComputeSize() + dac3.ComputeSize() +
dec3.ComputeSize() + dops.ComputeSize() + dfla.ComputeSize() +
dac4.ComputeSize() +
dac4.ComputeSize() + mhac.ComputeSize() +
// Reserved and predefined bytes.
6 + 8 + // 6 + 8 bytes reserved.
4; // 4 bytes predefined.
Expand Down
8 changes: 8 additions & 0 deletions packager/media/formats/mp4/box_definitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,13 @@ struct AC3Specific : Box {
std::vector<uint8_t> data;
};

struct MHAConfiguration : Box {
DECLARE_BOX_METHODS(MHAConfiguration);

std::vector<uint8_t> data;
uint8_t mpeg_h_3da_profile_level_indication;
};

struct EC3Specific : Box {
DECLARE_BOX_METHODS(EC3Specific);

Expand Down Expand Up @@ -382,6 +389,7 @@ struct AudioSampleEntry : Box {
AC4Specific dac4;
OpusSpecific dops;
FlacSpecific dfla;
MHAConfiguration mhac;
};

struct WebVTTConfigurationBox : Box {
Expand Down
30 changes: 30 additions & 0 deletions packager/media/formats/mp4/box_definitions_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1222,6 +1222,36 @@ TEST_F(BoxDefinitionsTest, AC3SampleEntry) {
ASSERT_EQ(entry, entry_readback);
}

TEST_F(BoxDefinitionsTest, MHA1SampleEntry) {
AudioSampleEntry entry;
entry.format = FOURCC_mha1;
entry.data_reference_index = 2;
entry.channelcount = 5;
entry.samplesize = 16;
entry.samplerate = 44100;
Fill(&entry.mhac);
entry.Write(this->buffer_.get());

AudioSampleEntry entry_readback;
ASSERT_TRUE(ReadBack(&entry_readback));
ASSERT_EQ(entry, entry_readback);
}

TEST_F(BoxDefinitionsTest, MHACSampleEntry) {
AudioSampleEntry entry;
entry.format = FOURCC_mhaC;
entry.data_reference_index = 2;
entry.channelcount = 5;
entry.samplesize = 16;
entry.samplerate = 44100;
Fill(&entry.mhac);
entry.Write(this->buffer_.get());

AudioSampleEntry entry_readback;
ASSERT_TRUE(ReadBack(&entry_readback));
ASSERT_EQ(entry, entry_readback);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test can be removed as it tests the same thing as the test above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

TEST_F(BoxDefinitionsTest, EC3SampleEntry) {
AudioSampleEntry entry;
entry.format = FOURCC_ec_3;
Expand Down
9 changes: 9 additions & 0 deletions packager/media/formats/mp4/mp4_media_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ Codec FourCCToCodec(FourCC fourcc) {
return kCodecAC4;
case FOURCC_fLaC:
return kCodecFlac;
case FOURCC_mha1:
return kCodecMha1;
case FOURCC_mhm1:
return kCodecMhm1;
default:
return kUnknownCodec;
}
Expand Down Expand Up @@ -510,6 +514,11 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
codec_delay_ns =
entry.dops.preskip * kNanosecondsPerSecond / sampling_frequency;
break;
case FOURCC_mha1:
case FOURCC_mhm1:
codec_config = entry.mhac.data;
audio_object_type = entry.mhac.mpeg_h_3da_profile_level_indication;
break;
default:
// Intentionally not to fail in the parser as there may be multiple
// streams in the source content, which allows the supported stream to
Expand Down
8 changes: 8 additions & 0 deletions packager/media/formats/mp4/mp4_muxer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ FourCC CodecToFourCC(Codec codec, H26xStreamFormat h26x_stream_format) {
return FOURCC_fLaC;
case kCodecOpus:
return FOURCC_Opus;
case kCodecMha1:
return FOURCC_mha1;
case kCodecMhm1:
return FOURCC_mhm1;
default:
return FOURCC_NULL;
}
Expand Down Expand Up @@ -513,6 +517,10 @@ bool MP4Muxer::GenerateAudioTrak(const AudioStreamInfo* audio_info,
case kCodecOpus:
audio.dops.opus_identification_header = audio_info->codec_config();
break;
case kCodecMha1:
case kCodecMhm1:
audio.mhac.data = audio_info->codec_config();
break;
default:
NOTIMPLEMENTED() << " Unsupported audio codec " << audio_info->codec();
return false;
Expand Down