Mp4Extractor: add smta metadata to audio track

This is needed for slomo audio flattening.

PiperOrigin-RevId: 346965990
This commit is contained in:
kimvde 2020-12-11 11:14:11 +00:00 committed by Ian Baker
parent 73b9cee83a
commit 4ee02a27de
3 changed files with 24 additions and 12 deletions

View File

@ -17,6 +17,7 @@
package com.google.android.exoplayer2; package com.google.android.exoplayer2;
import static com.google.android.exoplayer2.MetadataRetriever.retrieveMetadata; import static com.google.android.exoplayer2.MetadataRetriever.retrieveMetadata;
import static com.google.android.exoplayer2.metadata.mp4.MdtaMetadataEntry.KEY_ANDROID_CAPTURE_FPS;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertThrows;
@ -24,8 +25,10 @@ import android.content.Context;
import android.net.Uri; import android.net.Uri;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.metadata.mp4.MdtaMetadataEntry;
import com.google.android.exoplayer2.metadata.mp4.MotionPhotoMetadata; import com.google.android.exoplayer2.metadata.mp4.MotionPhotoMetadata;
import com.google.android.exoplayer2.metadata.mp4.SlowMotionData; import com.google.android.exoplayer2.metadata.mp4.SlowMotionData;
import com.google.android.exoplayer2.metadata.mp4.SmtaMetadataEntry;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.testutil.AutoAdvancingFakeClock; import com.google.android.exoplayer2.testutil.AutoAdvancingFakeClock;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
@ -141,6 +144,8 @@ public class MetadataRetrieverTest {
public void retrieveMetadata_sefSlowMotion_outputsExpectedMetadata() throws Exception { public void retrieveMetadata_sefSlowMotion_outputsExpectedMetadata() throws Exception {
MediaItem mediaItem = MediaItem mediaItem =
MediaItem.fromUri(Uri.parse("asset://android_asset/media/mp4/sample_sef_slow_motion.mp4")); MediaItem.fromUri(Uri.parse("asset://android_asset/media/mp4/sample_sef_slow_motion.mp4"));
SmtaMetadataEntry expectedSmtaEntry =
new SmtaMetadataEntry(/* captureFrameRate= */ 240, /* svcTemporalLayerCount= */ 4);
List<SlowMotionData.Segment> segments = new ArrayList<>(); List<SlowMotionData.Segment> segments = new ArrayList<>();
segments.add( segments.add(
new SlowMotionData.Segment( new SlowMotionData.Segment(
@ -149,6 +154,12 @@ public class MetadataRetrieverTest {
new SlowMotionData.Segment( new SlowMotionData.Segment(
/* startTimeMs= */ 1255, /* endTimeMs= */ 1970, /* speedDivisor= */ 8)); /* startTimeMs= */ 1255, /* endTimeMs= */ 1970, /* speedDivisor= */ 8));
SlowMotionData expectedSlowMotionData = new SlowMotionData(segments); SlowMotionData expectedSlowMotionData = new SlowMotionData(segments);
MdtaMetadataEntry expectedMdtaEntry =
new MdtaMetadataEntry(
KEY_ANDROID_CAPTURE_FPS,
/* value= */ new byte[] {67, 112, 0, 0},
/* localeIndicator= */ 0,
/* typeIndicator= */ 23);
ListenableFuture<TrackGroupArray> trackGroupsFuture = ListenableFuture<TrackGroupArray> trackGroupsFuture =
retrieveMetadata(context, mediaItem, clock); retrieveMetadata(context, mediaItem, clock);
@ -156,11 +167,13 @@ public class MetadataRetrieverTest {
assertThat(trackGroups.length).isEqualTo(2); // Video and audio assertThat(trackGroups.length).isEqualTo(2); // Video and audio
// Audio // Audio
assertThat(trackGroups.get(0).getFormat(0).metadata.length()).isEqualTo(1); assertThat(trackGroups.get(0).getFormat(0).metadata.length()).isEqualTo(2);
assertThat(trackGroups.get(0).getFormat(0).metadata.get(0)).isEqualTo(expectedSlowMotionData); assertThat(trackGroups.get(0).getFormat(0).metadata.get(0)).isEqualTo(expectedSmtaEntry);
assertThat(trackGroups.get(0).getFormat(0).metadata.get(1)).isEqualTo(expectedSlowMotionData);
// Video // Video
assertThat(trackGroups.get(1).getFormat(0).metadata.length()) assertThat(trackGroups.get(1).getFormat(0).metadata.length()).isEqualTo(3);
.isEqualTo(3); // 2 Mdta entries and 1 slow motion entry. assertThat(trackGroups.get(1).getFormat(0).metadata.get(0)).isEqualTo(expectedMdtaEntry);
assertThat(trackGroups.get(1).getFormat(0).metadata.get(1)).isEqualTo(expectedSmtaEntry);
assertThat(trackGroups.get(1).getFormat(0).metadata.get(2)).isEqualTo(expectedSlowMotionData); assertThat(trackGroups.get(1).getFormat(0).metadata.get(2)).isEqualTo(expectedSlowMotionData);
} }

View File

@ -31,6 +31,7 @@ import com.google.android.exoplayer2.metadata.id3.TextInformationFrame;
import com.google.android.exoplayer2.metadata.mp4.MdtaMetadataEntry; import com.google.android.exoplayer2.metadata.mp4.MdtaMetadataEntry;
import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.ParsableByteArray;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/** Utilities for handling metadata in MP4. */ /** Utilities for handling metadata in MP4. */
/* package */ final class MetadataUtil { /* package */ final class MetadataUtil {
@ -290,9 +291,8 @@ import com.google.android.exoplayer2.util.ParsableByteArray;
int trackType, int trackType,
@Nullable Metadata udtaMetaMetadata, @Nullable Metadata udtaMetaMetadata,
@Nullable Metadata mdtaMetadata, @Nullable Metadata mdtaMetadata,
@Nullable Metadata smtaMetadata,
Format.Builder formatBuilder, Format.Builder formatBuilder,
Metadata.Entry... additionalEntries) { @NullableType Metadata... additionalMetadata) {
Metadata formatMetadata = new Metadata(); Metadata formatMetadata = new Metadata();
if (trackType == C.TRACK_TYPE_AUDIO) { if (trackType == C.TRACK_TYPE_AUDIO) {
@ -314,12 +314,11 @@ import com.google.android.exoplayer2.util.ParsableByteArray;
} }
} }
} }
if (smtaMetadata != null) {
formatMetadata = formatMetadata.copyWithAppendedEntriesFrom(smtaMetadata);
}
} }
formatMetadata = formatMetadata.copyWithAppendedEntries(additionalEntries); for (Metadata metadata : additionalMetadata) {
formatMetadata = formatMetadata.copyWithAppendedEntriesFrom(metadata);
}
if (formatMetadata.length() > 0) { if (formatMetadata.length() > 0) {
formatBuilder.setMetadata(formatMetadata); formatBuilder.setMetadata(formatMetadata);

View File

@ -525,9 +525,9 @@ public final class Mp4Extractor implements Extractor, SeekMap {
track.type, track.type,
udtaMetaMetadata, udtaMetaMetadata,
mdtaMetadata, mdtaMetadata,
smtaMetadata,
formatBuilder, formatBuilder,
/* additionalEntries...= */ slowMotionMetadataEntries.toArray(new Metadata.Entry[0])); smtaMetadata,
slowMotionMetadataEntries.isEmpty() ? null : new Metadata(slowMotionMetadataEntries));
mp4Track.trackOutput.format(formatBuilder.build()); mp4Track.trackOutput.format(formatBuilder.build());
if (track.type == C.TRACK_TYPE_VIDEO && firstVideoTrackIndex == C.INDEX_UNSET) { if (track.type == C.TRACK_TYPE_VIDEO && firstVideoTrackIndex == C.INDEX_UNSET) {