diff --git a/RELEASENOTES.md b/RELEASENOTES.md index c22e1e648d..e99fd84e74 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -50,6 +50,14 @@ passthrough capability from API 29 onwards, instead of using the HDMI audio plug intent ([#6500](https://github.com/google/ExoPlayer/pull/6500)). +* Extractors: + * Fix issue where a `trun` atom could be associated with the wrong track + in an FMP4 stream + ([#9056](https://github.com/google/ExoPlayer/pull/9056)). The fix + removes a previous workaround to handle content in which the `track_ID` + is set incorrectly + ([#4083](https://github.com/google/ExoPlayer/issues/4083)). Such content + is malformed and should be re-encoded. * Ad playback: * Support changing ad break positions in the player logic ([#5067](https://github.com/google/ExoPlayer/issues/5067). diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java index e3e5f27090..0ec5bd48ed 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java @@ -556,7 +556,7 @@ public class FragmentedMp4Extractor implements Extractor { } private void onMoofContainerAtomRead(ContainerAtom moof) throws ParserException { - parseMoof(moof, trackBundles, flags, scratchBytes); + parseMoof(moof, trackBundles, sideloadedTrack != null, flags, scratchBytes); @Nullable DrmInitData drmInitData = getDrmInitDataFromAtoms(moof.leafChildren); if (drmInitData != null) { @@ -703,7 +703,8 @@ public class FragmentedMp4Extractor implements Extractor { private static void parseMoof( ContainerAtom moof, - SparseArray trackBundleArray, + SparseArray trackBundles, + boolean haveSideloadedTrack, @Flags int flags, byte[] extendedTypeScratch) throws ParserException { @@ -712,7 +713,7 @@ public class FragmentedMp4Extractor implements Extractor { Atom.ContainerAtom child = moof.containerChildren.get(i); // TODO: Support multiple traf boxes per track in a single moof. if (child.type == Atom.TYPE_traf) { - parseTraf(child, trackBundleArray, flags, extendedTypeScratch); + parseTraf(child, trackBundles, haveSideloadedTrack, flags, extendedTypeScratch); } } } @@ -720,12 +721,13 @@ public class FragmentedMp4Extractor implements Extractor { /** Parses a traf atom (defined in 14496-12). */ private static void parseTraf( ContainerAtom traf, - SparseArray trackBundleArray, + SparseArray trackBundles, + boolean haveSideloadedTrack, @Flags int flags, byte[] extendedTypeScratch) throws ParserException { LeafAtom tfhd = checkNotNull(traf.getLeafAtomOfType(Atom.TYPE_tfhd)); - @Nullable TrackBundle trackBundle = parseTfhd(tfhd.data, trackBundleArray); + @Nullable TrackBundle trackBundle = parseTfhd(tfhd.data, trackBundles, haveSideloadedTrack); if (trackBundle == null) { return; } @@ -883,17 +885,21 @@ public class FragmentedMp4Extractor implements Extractor { * * @param tfhd The tfhd atom to decode. * @param trackBundles The track bundles, one of which corresponds to the tfhd atom being parsed. + * @param haveSideloadedTrack Whether {@code trackBundles} contains a single bundle corresponding + * to a side-loaded track. * @return The {@link TrackBundle} to which the {@link TrackFragment} belongs, or null if the tfhd * does not refer to any {@link TrackBundle}. */ @Nullable private static TrackBundle parseTfhd( - ParsableByteArray tfhd, SparseArray trackBundles) { + ParsableByteArray tfhd, SparseArray trackBundles, boolean haveSideloadedTrack) { tfhd.setPosition(Atom.HEADER_SIZE); int fullAtom = tfhd.readInt(); int atomFlags = Atom.parseFullAtomFlags(fullAtom); int trackId = tfhd.readInt(); - @Nullable TrackBundle trackBundle = getTrackBundle(trackBundles, trackId); + @Nullable + TrackBundle trackBundle = + haveSideloadedTrack ? trackBundles.valueAt(0) : trackBundles.get(trackId); if (trackBundle == null) { return null; } @@ -929,17 +935,6 @@ public class FragmentedMp4Extractor implements Extractor { return trackBundle; } - private static @Nullable TrackBundle getTrackBundle( - SparseArray trackBundles, int trackId) { - if (trackBundles.size() == 1) { - // Ignore track id if there is only one track. This is either because we have a side-loaded - // track or to cope with non-matching track indices (see - // https://github.com/google/ExoPlayer/issues/4083). - return trackBundles.valueAt(/* index= */ 0); - } - return trackBundles.get(trackId); - } - /** * Parses a tfdt atom (defined in 14496-12). *