diff --git a/RELEASENOTES.md b/RELEASENOTES.md index f54fa79605..03148e314e 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -2,6 +2,8 @@ ### dev-v2 (not yet released) ### +* MP4: Support Opus and FLAC in the MP4 container, and in DASH + ([#4883](https://github.com/google/ExoPlayer/issues/4883)). * DASH: Fix detecting the end of live events ([#4780](https://github.com/google/ExoPlayer/issues/4780)). * Support seeking for a wider range of MPEG-TS streams diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java index a20195139f..440e577c7d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java @@ -145,6 +145,10 @@ import java.util.List; public static final int TYPE_alac = Util.getIntegerCodeForString("alac"); public static final int TYPE_alaw = Util.getIntegerCodeForString("alaw"); public static final int TYPE_ulaw = Util.getIntegerCodeForString("ulaw"); + public static final int TYPE_Opus = Util.getIntegerCodeForString("Opus"); + public static final int TYPE_dOps = Util.getIntegerCodeForString("dOps"); + public static final int TYPE_fLaC = Util.getIntegerCodeForString("fLaC"); + public static final int TYPE_dfLa = Util.getIntegerCodeForString("dfLa"); public final int type; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java index 0cda3fafa8..e3d56489a6 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java @@ -58,6 +58,9 @@ import java.util.List; */ private static final int MAX_GAPLESS_TRIM_SIZE_SAMPLES = 3; + /** The magic signature for an Opus Identification header, as defined in RFC-7845. */ + private static final byte[] opusMagic = Util.getUtf8Bytes("OpusHead"); + /** * Parses a trak atom (defined in 14496-12). * @@ -679,7 +682,9 @@ import java.util.List; || childAtomType == Atom.TYPE__mp3 || childAtomType == Atom.TYPE_alac || childAtomType == Atom.TYPE_alaw - || childAtomType == Atom.TYPE_ulaw) { + || childAtomType == Atom.TYPE_ulaw + || childAtomType == Atom.TYPE_Opus + || childAtomType == Atom.TYPE_fLaC) { parseAudioSampleEntry(stsd, childAtomType, childStartPosition, childAtomSize, trackId, language, isQuickTime, drmInitData, out, i); } else if (childAtomType == Atom.TYPE_TTML || childAtomType == Atom.TYPE_tx3g @@ -976,6 +981,10 @@ import java.util.List; mimeType = MimeTypes.AUDIO_ALAW; } else if (atomType == Atom.TYPE_ulaw) { mimeType = MimeTypes.AUDIO_MLAW; + } else if (atomType == Atom.TYPE_Opus) { + mimeType = MimeTypes.AUDIO_OPUS; + } else if (atomType == Atom.TYPE_fLaC) { + mimeType = MimeTypes.AUDIO_FLAC; } byte[] initializationData = null; @@ -1016,7 +1025,20 @@ import java.util.List; } else if (childAtomType == Atom.TYPE_alac) { initializationData = new byte[childAtomSize]; parent.setPosition(childPosition); - parent.readBytes(initializationData, 0, childAtomSize); + parent.readBytes(initializationData, /* offset= */ 0, childAtomSize); + } else if (childAtomType == Atom.TYPE_dOps) { + // Build an Opus Identification Header (defined in RFC-7845) by concatenating the Opus Magic + // Signature and the body of the dOps atom. + int childAtomBodySize = childAtomSize - Atom.HEADER_SIZE; + initializationData = new byte[opusMagic.length + childAtomBodySize]; + System.arraycopy(opusMagic, 0, initializationData, 0, opusMagic.length); + parent.setPosition(childPosition + Atom.HEADER_SIZE); + parent.readBytes(initializationData, opusMagic.length, childAtomBodySize); + } else if (childAtomSize == Atom.TYPE_dfLa) { + int childAtomBodySize = childAtomSize - Atom.FULL_HEADER_SIZE; + initializationData = new byte[childAtomBodySize]; + parent.setPosition(childPosition + Atom.FULL_HEADER_SIZE); + parent.readBytes(initializationData, /* offset= */ 0, childAtomBodySize); } childPosition += childAtomSize; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java b/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java index f56aac7c70..e506ae1b19 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java @@ -207,7 +207,7 @@ public final class MimeTypes { if (codec == null) { return null; } - codec = codec.trim(); + codec = Util.toLowerInvariant(codec.trim()); if (codec.startsWith("avc1") || codec.startsWith("avc3")) { return MimeTypes.VIDEO_H264; } else if (codec.startsWith("hev1") || codec.startsWith("hvc1")) { @@ -245,6 +245,8 @@ public final class MimeTypes { return MimeTypes.AUDIO_OPUS; } else if (codec.startsWith("vorbis")) { return MimeTypes.AUDIO_VORBIS; + } else if (codec.startsWith("flac")) { + return MimeTypes.AUDIO_FLAC; } else { return getCustomMimeTypeForCodec(codec); }