mirror of
https://github.com/samsonjs/media.git
synced 2026-04-03 10:55:48 +00:00
Switch transformer tests to use dump files
Add an interface to muxers to allow tests to pass a dumpable muxer. #minor-release PiperOrigin-RevId: 354543388
This commit is contained in:
parent
2b24e88726
commit
afb41123c2
17 changed files with 3052 additions and 302 deletions
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Copyright 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.transformer;
|
||||
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||
import static com.google.android.exoplayer2.util.Util.SDK_INT;
|
||||
import static com.google.android.exoplayer2.util.Util.castNonNull;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaFormat;
|
||||
import android.media.MediaMuxer;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaFormatUtil;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/** Muxer implementation that uses a {@link MediaMuxer}. */
|
||||
@RequiresApi(18)
|
||||
/* package */ final class FrameworkMuxer implements Muxer {
|
||||
|
||||
public static final class Factory implements Muxer.Factory {
|
||||
@Override
|
||||
public FrameworkMuxer create(String path, String outputMimeType) throws IOException {
|
||||
MediaMuxer mediaMuxer = new MediaMuxer(path, mimeTypeToMuxerOutputFormat(outputMimeType));
|
||||
return new FrameworkMuxer(mediaMuxer, outputMimeType);
|
||||
}
|
||||
|
||||
@RequiresApi(26)
|
||||
@Override
|
||||
public FrameworkMuxer create(ParcelFileDescriptor parcelFileDescriptor, String outputMimeType)
|
||||
throws IOException {
|
||||
MediaMuxer mediaMuxer =
|
||||
new MediaMuxer(
|
||||
parcelFileDescriptor.getFileDescriptor(),
|
||||
mimeTypeToMuxerOutputFormat(outputMimeType));
|
||||
return new FrameworkMuxer(mediaMuxer, outputMimeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsOutputMimeType(String mimeType) {
|
||||
try {
|
||||
mimeTypeToMuxerOutputFormat(mimeType);
|
||||
} catch (IllegalStateException e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private final MediaMuxer mediaMuxer;
|
||||
private final String outputMimeType;
|
||||
private final MediaCodec.BufferInfo bufferInfo;
|
||||
|
||||
private boolean isStarted;
|
||||
|
||||
private FrameworkMuxer(MediaMuxer mediaMuxer, String outputMimeType) {
|
||||
this.mediaMuxer = mediaMuxer;
|
||||
this.outputMimeType = outputMimeType;
|
||||
bufferInfo = new MediaCodec.BufferInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsSampleMimeType(@Nullable String mimeType) {
|
||||
// MediaMuxer supported sample formats are documented in MediaMuxer.addTrack(MediaFormat).
|
||||
boolean isAudio = MimeTypes.isAudio(mimeType);
|
||||
boolean isVideo = MimeTypes.isVideo(mimeType);
|
||||
if (outputMimeType.equals(MimeTypes.VIDEO_MP4)) {
|
||||
if (isVideo) {
|
||||
return MimeTypes.VIDEO_H263.equals(mimeType)
|
||||
|| MimeTypes.VIDEO_H264.equals(mimeType)
|
||||
|| MimeTypes.VIDEO_MP4V.equals(mimeType)
|
||||
|| (Util.SDK_INT >= 24 && MimeTypes.VIDEO_H265.equals(mimeType));
|
||||
} else if (isAudio) {
|
||||
return MimeTypes.AUDIO_AAC.equals(mimeType)
|
||||
|| MimeTypes.AUDIO_AMR_NB.equals(mimeType)
|
||||
|| MimeTypes.AUDIO_AMR_WB.equals(mimeType);
|
||||
}
|
||||
} else if (outputMimeType.equals(MimeTypes.VIDEO_WEBM) && SDK_INT >= 21) {
|
||||
if (isVideo) {
|
||||
return MimeTypes.VIDEO_VP8.equals(mimeType)
|
||||
|| (Util.SDK_INT >= 24 && MimeTypes.VIDEO_VP9.equals(mimeType));
|
||||
} else if (isAudio) {
|
||||
return MimeTypes.AUDIO_VORBIS.equals(mimeType);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int addTrack(Format format) {
|
||||
String sampleMimeType = checkNotNull(format.sampleMimeType);
|
||||
MediaFormat mediaFormat;
|
||||
if (MimeTypes.isAudio(sampleMimeType)) {
|
||||
mediaFormat =
|
||||
MediaFormat.createAudioFormat(
|
||||
castNonNull(sampleMimeType), format.sampleRate, format.channelCount);
|
||||
} else {
|
||||
mediaFormat =
|
||||
MediaFormat.createVideoFormat(castNonNull(sampleMimeType), format.width, format.height);
|
||||
mediaMuxer.setOrientationHint(format.rotationDegrees);
|
||||
}
|
||||
MediaFormatUtil.setCsdBuffers(mediaFormat, format.initializationData);
|
||||
return mediaMuxer.addTrack(mediaFormat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSampleData(
|
||||
int trackIndex, ByteBuffer data, boolean isKeyFrame, long presentationTimeUs) {
|
||||
if (!isStarted) {
|
||||
isStarted = true;
|
||||
mediaMuxer.start();
|
||||
}
|
||||
int offset = data.position();
|
||||
int size = data.limit() - offset;
|
||||
int flags = isKeyFrame ? C.BUFFER_FLAG_KEY_FRAME : 0;
|
||||
bufferInfo.set(offset, size, presentationTimeUs, flags);
|
||||
mediaMuxer.writeSampleData(trackIndex, data, bufferInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
if (isStarted) {
|
||||
isStarted = false;
|
||||
try {
|
||||
mediaMuxer.stop();
|
||||
} catch (IllegalStateException e) {
|
||||
if (SDK_INT < 30) {
|
||||
// Set the muxer state to stopped even if mediaMuxer.stop() failed so that
|
||||
// mediaMuxer.release() doesn't attempt to stop the muxer and therefore doesn't throw the
|
||||
// same exception without releasing its resources. This is already implemented in
|
||||
// MediaMuxer
|
||||
// from API level 30.
|
||||
try {
|
||||
Field muxerStoppedStateField = MediaMuxer.class.getDeclaredField("MUXER_STATE_STOPPED");
|
||||
muxerStoppedStateField.setAccessible(true);
|
||||
int muxerStoppedState = castNonNull((Integer) muxerStoppedStateField.get(mediaMuxer));
|
||||
Field muxerStateField = MediaMuxer.class.getDeclaredField("mState");
|
||||
muxerStateField.setAccessible(true);
|
||||
muxerStateField.set(mediaMuxer, muxerStoppedState);
|
||||
} catch (Exception reflectionException) {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
mediaMuxer.release();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@link MimeTypes MIME type} into a {@link MediaMuxer.OutputFormat MediaMuxer output
|
||||
* format}.
|
||||
*
|
||||
* @param mimeType The {@link MimeTypes MIME type} to convert.
|
||||
* @return The corresponding {@link MediaMuxer.OutputFormat MediaMuxer output format}.
|
||||
* @throws IllegalArgumentException If the {@link MimeTypes MIME type} is not supported as output
|
||||
* format.
|
||||
*/
|
||||
private static int mimeTypeToMuxerOutputFormat(String mimeType) {
|
||||
if (mimeType.equals(MimeTypes.VIDEO_MP4)) {
|
||||
return MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4;
|
||||
} else if (SDK_INT >= 21 && mimeType.equals(MimeTypes.VIDEO_WEBM)) {
|
||||
return MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported output MIME type: " + mimeType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.transformer;
|
||||
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Abstracts media muxing operations.
|
||||
*
|
||||
* <p>Query whether {@link #supportsSampleMimeType(String) sample MIME types are supported} and
|
||||
* {@link #addTrack(Format) add all tracks}, then {@link #writeSampleData(int, ByteBuffer, boolean,
|
||||
* long) write sample data} to mux samples. Once any sample data has been written, it is not
|
||||
* possible to add tracks. After writing all sample data, {@link #release() release} the instance to
|
||||
* finish writing to the output and return any resources to the system.
|
||||
*/
|
||||
/* package */ interface Muxer {
|
||||
|
||||
/** Factory for muxers. */
|
||||
interface Factory {
|
||||
/**
|
||||
* Returns a new muxer writing to a file.
|
||||
*
|
||||
* @param path The path to the output file.
|
||||
* @param outputMimeType The container {@link MimeTypes MIME type} of the output file.
|
||||
* @throws IllegalArgumentException If the path is invalid or the MIME type is not supported.
|
||||
* @throws IOException If an error occurs opening the output file for writing.
|
||||
*/
|
||||
Muxer create(String path, String outputMimeType) throws IOException;
|
||||
|
||||
/**
|
||||
* Returns a new muxer writing to a file descriptor.
|
||||
*
|
||||
* @param parcelFileDescriptor A readable and writable {@link ParcelFileDescriptor} of the
|
||||
* output. The file referenced by this ParcelFileDescriptor should not be used before the
|
||||
* muxer is released. It is the responsibility of the caller to close the
|
||||
* ParcelFileDescriptor. This can be done after this method returns.
|
||||
* @param outputMimeType The {@link MimeTypes MIME type} of the output.
|
||||
* @throws IllegalArgumentException If the file descriptor is invalid or the MIME type is not
|
||||
* supported.
|
||||
* @throws IOException If an error occurs opening the output file descriptor for writing.
|
||||
*/
|
||||
Muxer create(ParcelFileDescriptor parcelFileDescriptor, String outputMimeType)
|
||||
throws IOException;
|
||||
|
||||
/** Returns whether the {@link MimeTypes MIME type} provided is a supported output format. */
|
||||
boolean supportsOutputMimeType(String mimeType);
|
||||
}
|
||||
|
||||
/** Returns whether the sample {@link MimeTypes MIME type} is supported. */
|
||||
boolean supportsSampleMimeType(@Nullable String mimeType);
|
||||
|
||||
/**
|
||||
* Adds a track with the specified format, and returns its index (to be passed in subsequent calls
|
||||
* to {@link #writeSampleData(int, ByteBuffer, boolean, long)}).
|
||||
*/
|
||||
int addTrack(Format format);
|
||||
|
||||
/**
|
||||
* Writes the specified sample.
|
||||
*
|
||||
* @param trackIndex The index of the track, previously returned by {@link #addTrack(Format)}.
|
||||
* @param data Buffer containing the sample data to write to the container.
|
||||
* @param isKeyFrame Whether the sample is a key frame.
|
||||
* @param presentationTimeUs The presentation time of the sample in microseconds.
|
||||
*/
|
||||
void writeSampleData(
|
||||
int trackIndex, ByteBuffer data, boolean isKeyFrame, long presentationTimeUs);
|
||||
|
||||
/** Releases any resources associated with muxing. */
|
||||
void release();
|
||||
}
|
||||
|
|
@ -17,25 +17,15 @@
|
|||
package com.google.android.exoplayer2.transformer;
|
||||
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkState;
|
||||
import static com.google.android.exoplayer2.util.Util.SDK_INT;
|
||||
import static com.google.android.exoplayer2.util.Util.castNonNull;
|
||||
import static com.google.android.exoplayer2.util.Util.minValue;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaFormat;
|
||||
import android.media.MediaMuxer;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.SparseIntArray;
|
||||
import android.util.SparseLongArray;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaFormatUtil;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
|
|
@ -54,11 +44,9 @@ import java.nio.ByteBuffer;
|
|||
*/
|
||||
private static final long MAX_TRACK_WRITE_AHEAD_US = C.msToUs(500);
|
||||
|
||||
private final MediaMuxer mediaMuxer;
|
||||
private final String outputMimeType;
|
||||
private final Muxer muxer;
|
||||
private final SparseIntArray trackTypeToIndex;
|
||||
private final SparseLongArray trackTypeToTimeUs;
|
||||
private final MediaCodec.BufferInfo bufferInfo;
|
||||
|
||||
private int trackCount;
|
||||
private int trackFormatCount;
|
||||
|
|
@ -66,45 +54,10 @@ import java.nio.ByteBuffer;
|
|||
private int previousTrackType;
|
||||
private long minTrackTimeUs;
|
||||
|
||||
/**
|
||||
* Constructs an instance.
|
||||
*
|
||||
* @param path The path to the output file.
|
||||
* @param outputMimeType The {@link MimeTypes MIME type} of the output.
|
||||
* @throws IllegalArgumentException If the path is invalid or the MIME type is not supported.
|
||||
* @throws IOException If an error occurs opening the output file for writing.
|
||||
*/
|
||||
public MuxerWrapper(String path, String outputMimeType) throws IOException {
|
||||
this(new MediaMuxer(path, mimeTypeToMuxerOutputFormat(outputMimeType)), outputMimeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance.
|
||||
*
|
||||
* @param parcelFileDescriptor A readable and writable {@link ParcelFileDescriptor} of the output.
|
||||
* The file referenced by this ParcelFileDescriptor should not be used before the muxer is
|
||||
* released. It is the responsibility of the caller to close the ParcelFileDescriptor. This
|
||||
* can be done after this constructor returns.
|
||||
* @param outputMimeType The {@link MimeTypes MIME type} of the output.
|
||||
* @throws IllegalArgumentException If the file descriptor is invalid or the MIME type is not
|
||||
* supported.
|
||||
* @throws IOException If an error occurs opening the output file for writing.
|
||||
*/
|
||||
@RequiresApi(26)
|
||||
public MuxerWrapper(ParcelFileDescriptor parcelFileDescriptor, String outputMimeType)
|
||||
throws IOException {
|
||||
this(
|
||||
new MediaMuxer(
|
||||
parcelFileDescriptor.getFileDescriptor(), mimeTypeToMuxerOutputFormat(outputMimeType)),
|
||||
outputMimeType);
|
||||
}
|
||||
|
||||
private MuxerWrapper(MediaMuxer mediaMuxer, String outputMimeType) {
|
||||
this.mediaMuxer = mediaMuxer;
|
||||
this.outputMimeType = outputMimeType;
|
||||
public MuxerWrapper(Muxer muxer) {
|
||||
this.muxer = muxer;
|
||||
trackTypeToIndex = new SparseIntArray();
|
||||
trackTypeToTimeUs = new SparseLongArray();
|
||||
bufferInfo = new MediaCodec.BufferInfo();
|
||||
previousTrackType = C.TRACK_TYPE_NONE;
|
||||
}
|
||||
|
||||
|
|
@ -123,6 +76,11 @@ import java.nio.ByteBuffer;
|
|||
trackCount++;
|
||||
}
|
||||
|
||||
/** Returns whether the sample {@link MimeTypes MIME type} is supported. */
|
||||
public boolean supportsSampleMimeType(@Nullable String mimeType) {
|
||||
return muxer.supportsSampleMimeType(mimeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a track format to the muxer.
|
||||
*
|
||||
|
|
@ -131,9 +89,8 @@ import java.nio.ByteBuffer;
|
|||
* long) written}.
|
||||
*
|
||||
* @param format The {@link Format} to be added.
|
||||
* @throws IllegalArgumentException If the format is invalid.
|
||||
* @throws IllegalStateException If the format is unsupported, if there is already a track format
|
||||
* of the same type (audio or video) or if the muxer is in the wrong state.
|
||||
* @throws IllegalStateException If the format is unsupported or if there is already a track
|
||||
* format of the same type (audio or video).
|
||||
*/
|
||||
public void addTrackFormat(Format format) {
|
||||
checkState(trackCount > 0, "All tracks should be registered before the formats are added.");
|
||||
|
|
@ -147,23 +104,11 @@ import java.nio.ByteBuffer;
|
|||
trackTypeToIndex.get(trackType, /* valueIfKeyNotFound= */ C.INDEX_UNSET) == C.INDEX_UNSET,
|
||||
"There is already a track of type " + trackType);
|
||||
|
||||
MediaFormat mediaFormat;
|
||||
if (isAudio) {
|
||||
mediaFormat =
|
||||
MediaFormat.createAudioFormat(
|
||||
castNonNull(sampleMimeType), format.sampleRate, format.channelCount);
|
||||
} else {
|
||||
mediaFormat =
|
||||
MediaFormat.createVideoFormat(castNonNull(sampleMimeType), format.width, format.height);
|
||||
mediaMuxer.setOrientationHint(format.rotationDegrees);
|
||||
}
|
||||
MediaFormatUtil.setCsdBuffers(mediaFormat, format.initializationData);
|
||||
int trackIndex = mediaMuxer.addTrack(mediaFormat);
|
||||
int trackIndex = muxer.addTrack(format);
|
||||
trackTypeToIndex.put(trackType, trackIndex);
|
||||
trackTypeToTimeUs.put(trackType, 0L);
|
||||
trackFormatCount++;
|
||||
if (trackFormatCount == trackCount) {
|
||||
mediaMuxer.start();
|
||||
isReady = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -180,9 +125,8 @@ import java.nio.ByteBuffer;
|
|||
* {@link #addTrackFormat(Format) received a format} for every {@link #registerTrack()
|
||||
* registered track}, or if it should write samples of other track types first to ensure a
|
||||
* good interleaving.
|
||||
* @throws IllegalArgumentException If the sample in {@code buffer} is invalid.
|
||||
* @throws IllegalStateException If the muxer doesn't have any {@link #endTrack(int) non-ended}
|
||||
* track of the given track type or if the muxer is in the wrong state.
|
||||
* track of the given track type.
|
||||
*/
|
||||
public boolean writeSample(
|
||||
int trackType, @Nullable ByteBuffer data, boolean isKeyFrame, long presentationTimeUs) {
|
||||
|
|
@ -197,11 +141,7 @@ import java.nio.ByteBuffer;
|
|||
return true;
|
||||
}
|
||||
|
||||
int offset = data.position();
|
||||
int size = data.limit() - offset;
|
||||
int flags = isKeyFrame ? C.BUFFER_FLAG_KEY_FRAME : 0;
|
||||
bufferInfo.set(offset, size, presentationTimeUs, flags);
|
||||
mediaMuxer.writeSampleData(trackIndex, data, bufferInfo);
|
||||
muxer.writeSampleData(trackIndex, data, isKeyFrame, presentationTimeUs);
|
||||
trackTypeToTimeUs.put(trackType, presentationTimeUs);
|
||||
previousTrackType = trackType;
|
||||
return true;
|
||||
|
|
@ -222,35 +162,10 @@ import java.nio.ByteBuffer;
|
|||
* Stops the muxer.
|
||||
*
|
||||
* <p>The muxer cannot be used anymore once it is stopped.
|
||||
*
|
||||
* @throws IllegalStateException If the muxer is in the wrong state (for example if it didn't
|
||||
* receive any samples).
|
||||
*/
|
||||
public void stop() {
|
||||
if (!isReady) {
|
||||
return;
|
||||
}
|
||||
isReady = false;
|
||||
try {
|
||||
mediaMuxer.stop();
|
||||
} catch (IllegalStateException e) {
|
||||
if (SDK_INT < 30) {
|
||||
// Set the muxer state to stopped even if mediaMuxer.stop() failed so that
|
||||
// mediaMuxer.release() doesn't attempt to stop the muxer and therefore doesn't throw the
|
||||
// same exception without releasing its resources. This is already implemented in MediaMuxer
|
||||
// from API level 30.
|
||||
try {
|
||||
Field muxerStoppedStateField = MediaMuxer.class.getDeclaredField("MUXER_STATE_STOPPED");
|
||||
muxerStoppedStateField.setAccessible(true);
|
||||
int muxerStoppedState = castNonNull((Integer) muxerStoppedStateField.get(mediaMuxer));
|
||||
Field muxerStateField = MediaMuxer.class.getDeclaredField("mState");
|
||||
muxerStateField.setAccessible(true);
|
||||
muxerStateField.set(mediaMuxer, muxerStoppedState);
|
||||
} catch (Exception reflectionException) {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
if (isReady) {
|
||||
isReady = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -261,7 +176,7 @@ import java.nio.ByteBuffer;
|
|||
*/
|
||||
public void release() {
|
||||
isReady = false;
|
||||
mediaMuxer.release();
|
||||
muxer.release();
|
||||
}
|
||||
|
||||
/** Returns the number of {@link #registerTrack() registered} tracks. */
|
||||
|
|
@ -269,48 +184,6 @@ import java.nio.ByteBuffer;
|
|||
return trackCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the sample {@link MimeTypes MIME type} is supported.
|
||||
*
|
||||
* <p>Supported sample formats are documented in {@link MediaMuxer#addTrack(MediaFormat)}.
|
||||
*/
|
||||
public boolean supportsSampleMimeType(@Nullable String mimeType) {
|
||||
boolean isAudio = MimeTypes.isAudio(mimeType);
|
||||
boolean isVideo = MimeTypes.isVideo(mimeType);
|
||||
if (outputMimeType.equals(MimeTypes.VIDEO_MP4)) {
|
||||
if (isVideo) {
|
||||
return MimeTypes.VIDEO_H263.equals(mimeType)
|
||||
|| MimeTypes.VIDEO_H264.equals(mimeType)
|
||||
|| MimeTypes.VIDEO_MP4V.equals(mimeType)
|
||||
|| (Util.SDK_INT >= 24 && MimeTypes.VIDEO_H265.equals(mimeType));
|
||||
} else if (isAudio) {
|
||||
return MimeTypes.AUDIO_AAC.equals(mimeType)
|
||||
|| MimeTypes.AUDIO_AMR_NB.equals(mimeType)
|
||||
|| MimeTypes.AUDIO_AMR_WB.equals(mimeType);
|
||||
}
|
||||
} else if (outputMimeType.equals(MimeTypes.VIDEO_WEBM) && SDK_INT >= 21) {
|
||||
if (isVideo) {
|
||||
return MimeTypes.VIDEO_VP8.equals(mimeType)
|
||||
|| (Util.SDK_INT >= 24 && MimeTypes.VIDEO_VP9.equals(mimeType));
|
||||
} else if (isAudio) {
|
||||
return MimeTypes.AUDIO_VORBIS.equals(mimeType);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the {@link MimeTypes MIME type} provided is a supported muxer output format.
|
||||
*/
|
||||
public static boolean supportsOutputMimeType(String mimeType) {
|
||||
try {
|
||||
mimeTypeToMuxerOutputFormat(mimeType);
|
||||
} catch (IllegalStateException e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the muxer can write a sample of the given track type.
|
||||
*
|
||||
|
|
@ -337,22 +210,4 @@ import java.nio.ByteBuffer;
|
|||
return trackTimeUs - minTrackTimeUs <= MAX_TRACK_WRITE_AHEAD_US;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@link MimeTypes MIME type} into a {@link MediaMuxer.OutputFormat MediaMuxer output
|
||||
* format}.
|
||||
*
|
||||
* @param mimeType The {@link MimeTypes MIME type} to convert.
|
||||
* @return The corresponding {@link MediaMuxer.OutputFormat MediaMuxer output format}.
|
||||
* @throws IllegalArgumentException If the {@link MimeTypes MIME type} is not supported as output
|
||||
* format.
|
||||
*/
|
||||
private static int mimeTypeToMuxerOutputFormat(String mimeType) {
|
||||
if (mimeType.equals(MimeTypes.VIDEO_MP4)) {
|
||||
return MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4;
|
||||
} else if (SDK_INT >= 21 && mimeType.equals(MimeTypes.VIDEO_WEBM)) {
|
||||
return MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported output MIME type: " + mimeType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
* of the application's main thread is used. In all cases the Looper of the thread from which the
|
||||
* transformer must be accessed can be queried using {@link #getApplicationLooper()}.
|
||||
*/
|
||||
|
||||
@RequiresApi(18)
|
||||
public final class Transformer {
|
||||
|
||||
|
|
@ -88,6 +87,7 @@ public final class Transformer {
|
|||
|
||||
private @MonotonicNonNull Context context;
|
||||
private @MonotonicNonNull MediaSourceFactory mediaSourceFactory;
|
||||
private Muxer.Factory muxerFactory;
|
||||
private boolean removeAudio;
|
||||
private boolean removeVideo;
|
||||
private boolean flattenForSlowMotion;
|
||||
|
|
@ -98,6 +98,7 @@ public final class Transformer {
|
|||
|
||||
/** Creates a builder with default values. */
|
||||
public Builder() {
|
||||
muxerFactory = new FrameworkMuxer.Factory();
|
||||
outputMimeType = MimeTypes.VIDEO_MP4;
|
||||
listener = new Listener() {};
|
||||
looper = Util.getCurrentOrMainLooper();
|
||||
|
|
@ -108,6 +109,7 @@ public final class Transformer {
|
|||
private Builder(Transformer transformer) {
|
||||
this.context = transformer.context;
|
||||
this.mediaSourceFactory = transformer.mediaSourceFactory;
|
||||
this.muxerFactory = transformer.muxerFactory;
|
||||
this.removeAudio = transformer.transformation.removeAudio;
|
||||
this.removeVideo = transformer.transformation.removeVideo;
|
||||
this.flattenForSlowMotion = transformer.transformation.flattenForSlowMotion;
|
||||
|
|
@ -212,12 +214,8 @@ public final class Transformer {
|
|||
*
|
||||
* @param outputMimeType The MIME type of the output.
|
||||
* @return This builder.
|
||||
* @throws IllegalArgumentException If the MIME type is not supported.
|
||||
*/
|
||||
public Builder setOutputMimeType(String outputMimeType) {
|
||||
if (!MuxerWrapper.supportsOutputMimeType(outputMimeType)) {
|
||||
throw new IllegalArgumentException("Unsupported output MIME type: " + outputMimeType);
|
||||
}
|
||||
this.outputMimeType = outputMimeType;
|
||||
return this;
|
||||
}
|
||||
|
|
@ -262,12 +260,25 @@ public final class Transformer {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the factory for muxers that write the media container.
|
||||
*
|
||||
* @param muxerFactory A {@link Muxer.Factory}.
|
||||
* @return This builder.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
/* package */ Builder setMuxerFactory(Muxer.Factory muxerFactory) {
|
||||
this.muxerFactory = muxerFactory;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a {@link Transformer} instance.
|
||||
*
|
||||
* @throws IllegalStateException If the {@link Context} has not been provided.
|
||||
* @throws IllegalStateException If both audio and video have been removed (otherwise the output
|
||||
* would not contain any samples).
|
||||
* @throws IllegalStateException If the muxer doesn't support the requested output MIME type.
|
||||
*/
|
||||
public Transformer build() {
|
||||
checkStateNotNull(context);
|
||||
|
|
@ -278,9 +289,13 @@ public final class Transformer {
|
|||
}
|
||||
mediaSourceFactory = new DefaultMediaSourceFactory(context, defaultExtractorsFactory);
|
||||
}
|
||||
checkState(
|
||||
muxerFactory.supportsOutputMimeType(outputMimeType),
|
||||
"Unsupported output MIME type: " + outputMimeType);
|
||||
Transformation transformation =
|
||||
new Transformation(removeAudio, removeVideo, flattenForSlowMotion, outputMimeType);
|
||||
return new Transformer(context, mediaSourceFactory, transformation, listener, looper, clock);
|
||||
return new Transformer(
|
||||
context, mediaSourceFactory, muxerFactory, transformation, listener, looper, clock);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -332,6 +347,7 @@ public final class Transformer {
|
|||
|
||||
private final Context context;
|
||||
private final MediaSourceFactory mediaSourceFactory;
|
||||
private final Muxer.Factory muxerFactory;
|
||||
private final Transformation transformation;
|
||||
private final Looper looper;
|
||||
private final Clock clock;
|
||||
|
|
@ -344,6 +360,7 @@ public final class Transformer {
|
|||
private Transformer(
|
||||
Context context,
|
||||
MediaSourceFactory mediaSourceFactory,
|
||||
Muxer.Factory muxerFactory,
|
||||
Transformation transformation,
|
||||
Transformer.Listener listener,
|
||||
Looper looper,
|
||||
|
|
@ -353,6 +370,7 @@ public final class Transformer {
|
|||
"Audio and video cannot both be removed.");
|
||||
this.context = context;
|
||||
this.mediaSourceFactory = mediaSourceFactory;
|
||||
this.muxerFactory = muxerFactory;
|
||||
this.transformation = transformation;
|
||||
this.listener = listener;
|
||||
this.looper = looper;
|
||||
|
|
@ -397,7 +415,7 @@ public final class Transformer {
|
|||
* @throws IOException If an error occurs opening the output file for writing.
|
||||
*/
|
||||
public void startTransformation(MediaItem mediaItem, String path) throws IOException {
|
||||
startTransformation(mediaItem, new MuxerWrapper(path, transformation.outputMimeType));
|
||||
startTransformation(mediaItem, muxerFactory.create(path, transformation.outputMimeType));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -427,17 +445,17 @@ public final class Transformer {
|
|||
public void startTransformation(MediaItem mediaItem, ParcelFileDescriptor parcelFileDescriptor)
|
||||
throws IOException {
|
||||
startTransformation(
|
||||
mediaItem, new MuxerWrapper(parcelFileDescriptor, transformation.outputMimeType));
|
||||
mediaItem, muxerFactory.create(parcelFileDescriptor, transformation.outputMimeType));
|
||||
}
|
||||
|
||||
private void startTransformation(MediaItem mediaItem, MuxerWrapper muxerWrapper) {
|
||||
private void startTransformation(MediaItem mediaItem, Muxer muxer) {
|
||||
verifyApplicationThread();
|
||||
if (player != null) {
|
||||
throw new IllegalStateException("There is already a transformation in progress.");
|
||||
}
|
||||
|
||||
MuxerWrapper muxerWrapper = new MuxerWrapper(muxer);
|
||||
this.muxerWrapper = muxerWrapper;
|
||||
|
||||
DefaultTrackSelector trackSelector = new DefaultTrackSelector(context);
|
||||
trackSelector.setParameters(
|
||||
new DefaultTrackSelector.ParametersBuilder(context)
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ import com.google.android.exoplayer2.util.MimeTypes;
|
|||
@C.FormatSupport
|
||||
public final int supportsFormat(Format format) {
|
||||
@Nullable String sampleMimeType = format.sampleMimeType;
|
||||
if (MimeTypes.getTrackType(format.sampleMimeType) != getTrackType()) {
|
||||
if (MimeTypes.getTrackType(sampleMimeType) != getTrackType()) {
|
||||
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_TYPE);
|
||||
} else if (muxerWrapper.supportsSampleMimeType(sampleMimeType)) {
|
||||
return RendererCapabilities.create(C.FORMAT_HANDLED);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.transformer;
|
||||
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.testutil.DumpableFormat;
|
||||
import com.google.android.exoplayer2.testutil.Dumper;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An implementation of {@link Muxer} that supports dumping information about all interactions (for
|
||||
* testing purposes) and delegates the actual muxing operations to a {@link FrameworkMuxer}.
|
||||
*/
|
||||
public final class TestMuxer implements Muxer, Dumper.Dumpable {
|
||||
|
||||
private final Muxer frameworkMuxer;
|
||||
private final List<Dumper.Dumpable> dumpables;
|
||||
|
||||
/** Creates a new test muxer. */
|
||||
public TestMuxer(String path, String outputMimeType) throws IOException {
|
||||
frameworkMuxer = new FrameworkMuxer.Factory().create(path, outputMimeType);
|
||||
dumpables = new ArrayList<>();
|
||||
dumpables.add(dumper -> dumper.add("containerMimeType", outputMimeType));
|
||||
}
|
||||
|
||||
// Muxer implementation.
|
||||
|
||||
@Override
|
||||
public boolean supportsSampleMimeType(String mimeType) {
|
||||
return frameworkMuxer.supportsSampleMimeType(mimeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int addTrack(Format format) {
|
||||
int trackIndex = frameworkMuxer.addTrack(format);
|
||||
dumpables.add(new DumpableFormat(format, trackIndex));
|
||||
return trackIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSampleData(
|
||||
int trackIndex, ByteBuffer data, boolean isKeyFrame, long presentationTimeUs) {
|
||||
dumpables.add(new DumpableSample(trackIndex, data, isKeyFrame, presentationTimeUs));
|
||||
frameworkMuxer.writeSampleData(trackIndex, data, isKeyFrame, presentationTimeUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
dumpables.add(dumper -> dumper.add("released", true));
|
||||
frameworkMuxer.release();
|
||||
}
|
||||
|
||||
// Dumper.Dumpable implementation.
|
||||
|
||||
@Override
|
||||
public void dump(Dumper dumper) {
|
||||
for (Dumper.Dumpable dumpable : dumpables) {
|
||||
dumpable.dump(dumper);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class DumpableSample implements Dumper.Dumpable {
|
||||
|
||||
private final int trackIndex;
|
||||
private final long presentationTimeUs;
|
||||
private final boolean isKeyFrame;
|
||||
private final int sampleDataHashCode;
|
||||
|
||||
public DumpableSample(
|
||||
int trackIndex, ByteBuffer sample, boolean isKeyFrame, long presentationTimeUs) {
|
||||
this.trackIndex = trackIndex;
|
||||
this.presentationTimeUs = presentationTimeUs;
|
||||
this.isKeyFrame = isKeyFrame;
|
||||
int initialPosition = sample.position();
|
||||
byte[] data = new byte[sample.remaining()];
|
||||
sample.get(data);
|
||||
sample.position(initialPosition);
|
||||
sampleDataHashCode = Arrays.hashCode(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Dumper dumper) {
|
||||
dumper
|
||||
.startBlock("sample")
|
||||
.add("trackIndex", trackIndex)
|
||||
.add("dataHashCode", sampleDataHashCode)
|
||||
.add("isKeyFrame", isKeyFrame)
|
||||
.add("presentationTimeUs", presentationTimeUs)
|
||||
.endBlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -32,8 +32,8 @@ public class TransformerBuilderTest {
|
|||
@Test
|
||||
public void setOutputMimeType_unsupportedMimeType_throws() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> new Transformer.Builder().setOutputMimeType(MimeTypes.VIDEO_FLV));
|
||||
IllegalStateException.class,
|
||||
() -> new Transformer.Builder().setOutputMimeType(MimeTypes.VIDEO_FLV).build());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -28,15 +28,16 @@ import android.os.Handler;
|
|||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.MediaItem;
|
||||
import com.google.android.exoplayer2.testutil.AutoAdvancingFakeClock;
|
||||
import com.google.android.exoplayer2.testutil.DumpFileAsserts;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import com.google.common.collect.Iterables;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
|
@ -56,18 +57,20 @@ import org.robolectric.shadows.ShadowMediaCodec;
|
|||
@RunWith(AndroidJUnit4.class)
|
||||
public final class TransformerTest {
|
||||
|
||||
private static final String FILE_VIDEO_ONLY = "asset:///media/mkv/sample.mkv";
|
||||
private static final String FILE_AUDIO_ONLY = "asset:///media/amr/sample_nb.amr";
|
||||
private static final String FILE_AUDIO_VIDEO = "asset:///media/mp4/sample.mp4";
|
||||
|
||||
// The ShadowMediaMuxer only outputs sample data to the output file.
|
||||
private static final int FILE_VIDEO_ONLY_SAMPLE_DATA_LENGTH = 89_502;
|
||||
private static final int FILE_AUDIO_ONLY_SAMPLE_DATA_LENGTH = 2834;
|
||||
private static final int FILE_AUDIO_VIDEO_AUDIO_SAMPLE_DATA_LENGTH = 9529;
|
||||
private static final int FILE_AUDIO_VIDEO_VIDEO_SAMPLE_DATA_LENGTH = 89_876;
|
||||
private static final String URI_PREFIX = "asset:///media/";
|
||||
private static final String FILE_VIDEO_ONLY = "mkv/sample.mkv";
|
||||
private static final String FILE_AUDIO_ONLY = "amr/sample_nb.amr";
|
||||
private static final String FILE_AUDIO_VIDEO = "mp4/sample.mp4";
|
||||
private static final String FILE_WITH_SUBTITLES = "mkv/sample_with_srt.mkv";
|
||||
private static final String FILE_WITH_SEF_SLOW_MOTION = "mp4/sample_sef_slow_motion.mp4";
|
||||
private static final String FILE_WITH_ALL_SAMPLE_FORMATS_UNSUPPORTED = "mp4/sample_ac3.mp4";
|
||||
private static final String FILE_UNKNOWN_DURATION = "mp4/sample_fragmented.mp4";
|
||||
public static final String DUMP_FILE_OUTPUT_DIRECTORY = "transformerdumps";
|
||||
public static final String DUMP_FILE_EXTENSION = "dump";
|
||||
|
||||
private Context context;
|
||||
private String outputPath;
|
||||
private TestMuxer testMuxer;
|
||||
private AutoAdvancingFakeClock clock;
|
||||
private ProgressHolder progressHolder;
|
||||
|
||||
|
|
@ -88,55 +91,78 @@ public final class TransformerTest {
|
|||
|
||||
@Test
|
||||
public void startTransformation_videoOnly_completesSuccessfully() throws Exception {
|
||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(FILE_VIDEO_ONLY);
|
||||
Transformer transformer =
|
||||
new Transformer.Builder()
|
||||
.setContext(context)
|
||||
.setClock(clock)
|
||||
.setMuxerFactory(new TestMuxerFactory())
|
||||
.build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY);
|
||||
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
TransformerTestRunner.runUntilCompleted(transformer);
|
||||
|
||||
assertThat(new File(outputPath).length()).isEqualTo(FILE_VIDEO_ONLY_SAMPLE_DATA_LENGTH);
|
||||
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_VIDEO_ONLY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startTransformation_audioOnly_completesSuccessfully() throws Exception {
|
||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(FILE_AUDIO_ONLY);
|
||||
Transformer transformer =
|
||||
new Transformer.Builder()
|
||||
.setContext(context)
|
||||
.setClock(clock)
|
||||
.setMuxerFactory(new TestMuxerFactory())
|
||||
.build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_ONLY);
|
||||
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
TransformerTestRunner.runUntilCompleted(transformer);
|
||||
|
||||
assertThat(new File(outputPath).length()).isEqualTo(FILE_AUDIO_ONLY_SAMPLE_DATA_LENGTH);
|
||||
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_AUDIO_ONLY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startTransformation_audioAndVideo_completesSuccessfully() throws Exception {
|
||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(FILE_AUDIO_VIDEO);
|
||||
Transformer transformer =
|
||||
new Transformer.Builder()
|
||||
.setContext(context)
|
||||
.setClock(clock)
|
||||
.setMuxerFactory(new TestMuxerFactory())
|
||||
.build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
TransformerTestRunner.runUntilCompleted(transformer);
|
||||
|
||||
assertThat(new File(outputPath).length())
|
||||
.isEqualTo(
|
||||
FILE_AUDIO_VIDEO_VIDEO_SAMPLE_DATA_LENGTH + FILE_AUDIO_VIDEO_AUDIO_SAMPLE_DATA_LENGTH);
|
||||
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_AUDIO_VIDEO));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startTransformation_withSubtitles_completesSuccessfully() throws Exception {
|
||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri("asset:///media/mkv/sample_with_srt.mkv");
|
||||
Transformer transformer =
|
||||
new Transformer.Builder()
|
||||
.setContext(context)
|
||||
.setClock(clock)
|
||||
.setMuxerFactory(new TestMuxerFactory())
|
||||
.build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_WITH_SUBTITLES);
|
||||
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
TransformerTestRunner.runUntilCompleted(transformer);
|
||||
|
||||
assertThat(new File(outputPath).length()).isEqualTo(89_502);
|
||||
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_WITH_SUBTITLES));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startTransformation_successiveTransformations_completesSuccessfully()
|
||||
throws Exception {
|
||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(FILE_VIDEO_ONLY);
|
||||
Transformer transformer =
|
||||
new Transformer.Builder()
|
||||
.setContext(context)
|
||||
.setClock(clock)
|
||||
.setMuxerFactory(new TestMuxerFactory())
|
||||
.build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY);
|
||||
|
||||
// Transform first media item.
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
|
|
@ -147,13 +173,13 @@ public final class TransformerTest {
|
|||
transformer.startTransformation(mediaItem, outputPath);
|
||||
TransformerTestRunner.runUntilCompleted(transformer);
|
||||
|
||||
assertThat(new File(outputPath).length()).isEqualTo(FILE_VIDEO_ONLY_SAMPLE_DATA_LENGTH);
|
||||
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_VIDEO_ONLY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startTransformation_concurrentTransformations_throwsError() throws Exception {
|
||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(FILE_VIDEO_ONLY);
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY);
|
||||
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
|
||||
|
|
@ -164,25 +190,37 @@ public final class TransformerTest {
|
|||
@Test
|
||||
public void startTransformation_removeAudio_completesSuccessfully() throws Exception {
|
||||
Transformer transformer =
|
||||
new Transformer.Builder().setContext(context).setRemoveAudio(true).setClock(clock).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(FILE_AUDIO_VIDEO);
|
||||
new Transformer.Builder()
|
||||
.setContext(context)
|
||||
.setRemoveAudio(true)
|
||||
.setClock(clock)
|
||||
.setMuxerFactory(new TestMuxerFactory())
|
||||
.build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
TransformerTestRunner.runUntilCompleted(transformer);
|
||||
|
||||
assertThat(new File(outputPath).length()).isEqualTo(FILE_AUDIO_VIDEO_VIDEO_SAMPLE_DATA_LENGTH);
|
||||
DumpFileAsserts.assertOutput(
|
||||
context, testMuxer, getDumpFileName(FILE_AUDIO_VIDEO + ".noaudio"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startTransformation_removeVideo_completesSuccessfully() throws Exception {
|
||||
Transformer transformer =
|
||||
new Transformer.Builder().setContext(context).setRemoveVideo(true).setClock(clock).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(FILE_AUDIO_VIDEO);
|
||||
new Transformer.Builder()
|
||||
.setContext(context)
|
||||
.setRemoveVideo(true)
|
||||
.setClock(clock)
|
||||
.setMuxerFactory(new TestMuxerFactory())
|
||||
.build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
TransformerTestRunner.runUntilCompleted(transformer);
|
||||
|
||||
assertThat(new File(outputPath).length()).isEqualTo(FILE_AUDIO_VIDEO_AUDIO_SAMPLE_DATA_LENGTH);
|
||||
DumpFileAsserts.assertOutput(
|
||||
context, testMuxer, getDumpFileName(FILE_AUDIO_VIDEO + ".novideo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -192,13 +230,14 @@ public final class TransformerTest {
|
|||
.setContext(context)
|
||||
.setFlattenForSlowMotion(true)
|
||||
.setClock(clock)
|
||||
.setMuxerFactory(new TestMuxerFactory())
|
||||
.build();
|
||||
MediaItem mediaItem = MediaItem.fromUri("asset:///media/mp4/sample_sef_slow_motion.mp4");
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_WITH_SEF_SLOW_MOTION);
|
||||
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
TransformerTestRunner.runUntilCompleted(transformer);
|
||||
|
||||
assertThat(new File(outputPath).length()).isEqualTo(18_172);
|
||||
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_WITH_SEF_SLOW_MOTION));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -217,7 +256,7 @@ public final class TransformerTest {
|
|||
public void startTransformation_withAllSampleFormatsUnsupported_completesWithError()
|
||||
throws Exception {
|
||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri("asset:///media/mp4/sample_ac3.mp4");
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_WITH_ALL_SAMPLE_FORMATS_UNSUPPORTED);
|
||||
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
Exception exception = TransformerTestRunner.runUntilError(transformer);
|
||||
|
|
@ -227,8 +266,13 @@ public final class TransformerTest {
|
|||
|
||||
@Test
|
||||
public void startTransformation_afterCancellation_completesSuccessfully() throws Exception {
|
||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(FILE_VIDEO_ONLY);
|
||||
Transformer transformer =
|
||||
new Transformer.Builder()
|
||||
.setContext(context)
|
||||
.setClock(clock)
|
||||
.setMuxerFactory(new TestMuxerFactory())
|
||||
.build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY);
|
||||
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
transformer.cancel();
|
||||
|
|
@ -238,7 +282,7 @@ public final class TransformerTest {
|
|||
transformer.startTransformation(mediaItem, outputPath);
|
||||
TransformerTestRunner.runUntilCompleted(transformer);
|
||||
|
||||
assertThat(new File(outputPath).length()).isEqualTo(FILE_VIDEO_ONLY_SAMPLE_DATA_LENGTH);
|
||||
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_VIDEO_ONLY));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -247,8 +291,13 @@ public final class TransformerTest {
|
|||
anotherThread.start();
|
||||
Looper looper = anotherThread.getLooper();
|
||||
Transformer transformer =
|
||||
new Transformer.Builder().setContext(context).setLooper(looper).setClock(clock).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(FILE_AUDIO_ONLY);
|
||||
new Transformer.Builder()
|
||||
.setContext(context)
|
||||
.setLooper(looper)
|
||||
.setClock(clock)
|
||||
.setMuxerFactory(new TestMuxerFactory())
|
||||
.build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_ONLY);
|
||||
AtomicReference<Exception> exception = new AtomicReference<>();
|
||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
|
||||
|
|
@ -267,13 +316,13 @@ public final class TransformerTest {
|
|||
countDownLatch.await();
|
||||
|
||||
assertThat(exception.get()).isNull();
|
||||
assertThat(new File(outputPath).length()).isEqualTo(FILE_AUDIO_ONLY_SAMPLE_DATA_LENGTH);
|
||||
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_AUDIO_ONLY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startTransformation_fromWrongThread_throwsError() throws Exception {
|
||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(FILE_AUDIO_ONLY);
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_ONLY);
|
||||
HandlerThread anotherThread = new HandlerThread("AnotherThread");
|
||||
AtomicReference<IllegalStateException> illegalStateException = new AtomicReference<>();
|
||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
|
|
@ -300,7 +349,7 @@ public final class TransformerTest {
|
|||
@Test
|
||||
public void getProgress_knownDuration_returnsConsistentStates() throws Exception {
|
||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(FILE_VIDEO_ONLY);
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY);
|
||||
AtomicInteger previousProgressState =
|
||||
new AtomicInteger(PROGRESS_STATE_WAITING_FOR_AVAILABILITY);
|
||||
AtomicBoolean foundInconsistentState = new AtomicBoolean();
|
||||
|
|
@ -346,7 +395,7 @@ public final class TransformerTest {
|
|||
@Test
|
||||
public void getProgress_knownDuration_givesIncreasingPercentages() throws Exception {
|
||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(FILE_VIDEO_ONLY);
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY);
|
||||
List<Integer> progresses = new ArrayList<>();
|
||||
Handler progressHandler =
|
||||
new Handler(Looper.myLooper()) {
|
||||
|
|
@ -381,7 +430,7 @@ public final class TransformerTest {
|
|||
@Test
|
||||
public void getProgress_noCurrentTransformation_returnsNoTransformation() throws Exception {
|
||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(FILE_VIDEO_ONLY);
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY);
|
||||
|
||||
@Transformer.ProgressState int stateBeforeTransform = transformer.getProgress(progressHolder);
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
|
|
@ -395,7 +444,7 @@ public final class TransformerTest {
|
|||
@Test
|
||||
public void getProgress_unknownDuration_returnsConsistentStates() throws Exception {
|
||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri("asset:///media/mp4/sample_fragmented.mp4");
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_UNKNOWN_DURATION);
|
||||
AtomicInteger previousProgressState =
|
||||
new AtomicInteger(PROGRESS_STATE_WAITING_FOR_AVAILABILITY);
|
||||
AtomicBoolean foundInconsistentState = new AtomicBoolean();
|
||||
|
|
@ -462,7 +511,7 @@ public final class TransformerTest {
|
|||
@Test
|
||||
public void cancel_afterCompletion_doesNotThrow() throws Exception {
|
||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(FILE_VIDEO_ONLY);
|
||||
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY);
|
||||
|
||||
transformer.startTransformation(mediaItem, outputPath);
|
||||
TransformerTestRunner.runUntilCompleted(transformer);
|
||||
|
|
@ -507,4 +556,28 @@ public final class TransformerTest {
|
|||
private static void removeEncodersAndDecoders() {
|
||||
ShadowMediaCodec.clearCodecs();
|
||||
}
|
||||
|
||||
private static String getDumpFileName(String originalFileName) {
|
||||
return DUMP_FILE_OUTPUT_DIRECTORY + '/' + originalFileName + '.' + DUMP_FILE_EXTENSION;
|
||||
}
|
||||
|
||||
private final class TestMuxerFactory implements Muxer.Factory {
|
||||
@Override
|
||||
public Muxer create(String path, String outputMimeType) throws IOException {
|
||||
testMuxer = new TestMuxer(path, outputMimeType);
|
||||
return testMuxer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Muxer create(ParcelFileDescriptor parcelFileDescriptor, String outputMimeType)
|
||||
throws IOException {
|
||||
testMuxer = new TestMuxer("FD:" + parcelFileDescriptor.getFd(), outputMimeType);
|
||||
return testMuxer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsOutputMimeType(String mimeType) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1096
testdata/src/test/assets/transformerdumps/amr/sample_nb.amr.dump
vendored
Normal file
1096
testdata/src/test/assets/transformerdumps/amr/sample_nb.amr.dump
vendored
Normal file
File diff suppressed because it is too large
Load diff
163
testdata/src/test/assets/transformerdumps/mkv/sample.mkv.dump
vendored
Normal file
163
testdata/src/test/assets/transformerdumps/mkv/sample.mkv.dump
vendored
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
containerMimeType = video/mp4
|
||||
format 0:
|
||||
id = 1
|
||||
sampleMimeType = video/avc
|
||||
codecs = avc1.640034
|
||||
width = 1080
|
||||
height = 720
|
||||
selectionFlags = 1
|
||||
language = und
|
||||
initializationData:
|
||||
data = length 30, hash F6F3D010
|
||||
data = length 10, hash 7A0D0F2B
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -252482306
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 67000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 67864034
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 134000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 897273234
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 100000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1549870586
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 267000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 672384813
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 200000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -988996493
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 167000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1711151377
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 234000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -506806036
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 400000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1902167649
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 334000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 2054873212
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 300000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1556608231
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 367000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1648978019
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 500000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -484808327
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 467000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -20706048
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 434000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 2085064574
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 634000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -637074022
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 567000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1824027029
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 534000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1701945306
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 600000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -952425536
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 767000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1978031576
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 700000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -2128215508
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 667000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -259850011
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 734000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1920983928
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 900000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1100642337
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 834000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1544917830
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 800000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -116205995
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 867000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 696343585
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 1034000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -644371190
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 967000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1606273467
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 934000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -571265861
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 1000000
|
||||
released = true
|
||||
163
testdata/src/test/assets/transformerdumps/mkv/sample_with_srt.mkv.dump
vendored
Normal file
163
testdata/src/test/assets/transformerdumps/mkv/sample_with_srt.mkv.dump
vendored
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
containerMimeType = video/mp4
|
||||
format 0:
|
||||
id = 1
|
||||
sampleMimeType = video/avc
|
||||
codecs = avc1.640034
|
||||
width = 1080
|
||||
height = 720
|
||||
selectionFlags = 1
|
||||
language = und
|
||||
initializationData:
|
||||
data = length 30, hash F6F3D010
|
||||
data = length 10, hash 7A0D0F2B
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -252482306
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 0
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 67864034
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 67000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 897273234
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 33000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1549870586
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 200000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 672384813
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 133000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -988996493
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 100000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1711151377
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 167000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -506806036
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 333000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1902167649
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 267000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 2054873212
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 233000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1556608231
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 300000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1648978019
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 433000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -484808327
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 400000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -20706048
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 367000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 2085064574
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 567000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -637074022
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 500000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1824027029
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 467000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1701945306
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 533000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -952425536
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 700000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1978031576
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 633000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -2128215508
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 600000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -259850011
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 667000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1920983928
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 833000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1100642337
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 767000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1544917830
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 733000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -116205995
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 800000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 696343585
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 967000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -644371190
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 900000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1606273467
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 867000
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -571265861
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 933000
|
||||
released = true
|
||||
392
testdata/src/test/assets/transformerdumps/mp4/sample.mp4.dump
vendored
Normal file
392
testdata/src/test/assets/transformerdumps/mp4/sample.mp4.dump
vendored
Normal file
|
|
@ -0,0 +1,392 @@
|
|||
containerMimeType = video/mp4
|
||||
format 0:
|
||||
sampleMimeType = audio/mp4a-latm
|
||||
channelCount = 1
|
||||
sampleRate = 44100
|
||||
format 1:
|
||||
id = 1
|
||||
sampleMimeType = video/avc
|
||||
codecs = avc1.64001F
|
||||
maxInputSize = 36722
|
||||
width = 1080
|
||||
height = 720
|
||||
frameRate = 29.970028
|
||||
initializationData:
|
||||
data = length 29, hash 4746B5D9
|
||||
data = length 10, hash 7A0D0F2B
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -770308242
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 0
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -732087136
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 66733
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 468156717
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 33366
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 1150349584
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 200200
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 1443582006
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 133466
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -310585145
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 100100
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 807460688
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 166833
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 1936487090
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 333666
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -32297181
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 266933
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 1529616406
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 233566
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 1949198785
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 300300
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -147880287
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 433766
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 1369083472
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 400400
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 965782073
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 367033
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -261176150
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 567233
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1205768497
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 0
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 837571078
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 249
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1991633045
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 317
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -822987359
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 1995
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1141508176
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 4126
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -226971245
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 6438
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -2099636855
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 8818
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1541550559
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 11198
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 411148001
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 13533
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -897603973
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 16072
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1478106136
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 18498
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1380417145
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 20878
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 780903644
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 23326
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 586204432
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 25911
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -2038771492
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 28541
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -2065161304
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 31194
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 468662933
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 33801
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -358398546
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 36363
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1767325983
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 38811
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1093095458
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 41396
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1687543702
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 43867
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1675188486
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 46588
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 888567545
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 49173
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -439631803
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 51871
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1606694497
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 54524
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1747388653
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 57131
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -734560004
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 59579
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -975079040
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 62277
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1403504710
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 65020
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 379512981
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 67627
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -1830836678
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 500500
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 1767407540
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 467133
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 918440283
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 533866
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -1408463661
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 700700
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -997198863
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 70234
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1394492825
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 72932
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -885232755
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 75471
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 260871367
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 78101
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1505318960
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 80844
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -390625371
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 83474
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1067950751
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 86149
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1179436278
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 88734
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1906607774
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 91387
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -800475828
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 94380
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1718972977
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 97282
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1120448741
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 99844
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1718323210
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 102406
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -422416
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 105059
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 833757830
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 107644
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 1569455924
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 633966
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -1723778407
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 600600
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 1578275472
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 667333
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 1989768395
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 834166
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -1215674502
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 767433
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -814473606
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 734066
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 498370894
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 800800
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -1051506468
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 967633
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -1025604144
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 900900
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -913586520
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 867533
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 1340459242
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 934266
|
||||
released = true
|
||||
163
testdata/src/test/assets/transformerdumps/mp4/sample.mp4.noaudio.dump
vendored
Normal file
163
testdata/src/test/assets/transformerdumps/mp4/sample.mp4.noaudio.dump
vendored
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
containerMimeType = video/mp4
|
||||
format 0:
|
||||
id = 1
|
||||
sampleMimeType = video/avc
|
||||
codecs = avc1.64001F
|
||||
maxInputSize = 36722
|
||||
width = 1080
|
||||
height = 720
|
||||
frameRate = 29.970028
|
||||
initializationData:
|
||||
data = length 29, hash 4746B5D9
|
||||
data = length 10, hash 7A0D0F2B
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -770308242
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 0
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -732087136
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 66733
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 468156717
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 33366
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1150349584
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 200200
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1443582006
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 133466
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -310585145
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 100100
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 807460688
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 166833
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1936487090
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 333666
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -32297181
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 266933
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1529616406
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 233566
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1949198785
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 300300
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -147880287
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 433766
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1369083472
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 400400
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 965782073
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 367033
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -261176150
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 567233
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1830836678
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 500500
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1767407540
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 467133
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 918440283
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 533866
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1408463661
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 700700
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1569455924
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 633966
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1723778407
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 600600
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1578275472
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 667333
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1989768395
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 834166
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1215674502
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 767433
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -814473606
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 734066
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 498370894
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 800800
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1051506468
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 967633
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1025604144
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 900900
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -913586520
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 867533
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1340459242
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 934266
|
||||
released = true
|
||||
231
testdata/src/test/assets/transformerdumps/mp4/sample.mp4.novideo.dump
vendored
Normal file
231
testdata/src/test/assets/transformerdumps/mp4/sample.mp4.novideo.dump
vendored
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
containerMimeType = video/mp4
|
||||
format 0:
|
||||
sampleMimeType = audio/mp4a-latm
|
||||
channelCount = 1
|
||||
sampleRate = 44100
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1205768497
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 0
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 837571078
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 249
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1991633045
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 317
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -822987359
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 1995
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1141508176
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 4126
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -226971245
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 6438
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -2099636855
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 8818
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1541550559
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 11198
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 411148001
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 13533
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -897603973
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 16072
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1478106136
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 18498
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1380417145
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 20878
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 780903644
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 23326
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 586204432
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 25911
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -2038771492
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 28541
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -2065161304
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 31194
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 468662933
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 33801
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -358398546
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 36363
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1767325983
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 38811
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1093095458
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 41396
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1687543702
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 43867
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1675188486
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 46588
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 888567545
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 49173
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -439631803
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 51871
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1606694497
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 54524
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1747388653
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 57131
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -734560004
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 59579
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -975079040
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 62277
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1403504710
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 65020
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 379512981
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 67627
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -997198863
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 70234
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1394492825
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 72932
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -885232755
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 75471
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 260871367
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 78101
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1505318960
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 80844
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -390625371
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 83474
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1067950751
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 86149
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1179436278
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 88734
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1906607774
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 91387
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -800475828
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 94380
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1718972977
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 97282
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1120448741
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 99844
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -1718323210
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 102406
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -422416
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 105059
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 833757830
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 107644
|
||||
released = true
|
||||
188
testdata/src/test/assets/transformerdumps/mp4/sample_sef_slow_motion.mp4.dump
vendored
Normal file
188
testdata/src/test/assets/transformerdumps/mp4/sample_sef_slow_motion.mp4.dump
vendored
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
containerMimeType = video/mp4
|
||||
format 0:
|
||||
sampleMimeType = audio/mp4a-latm
|
||||
channelCount = 2
|
||||
sampleRate = 12000
|
||||
format 1:
|
||||
id = 2
|
||||
sampleMimeType = video/avc
|
||||
codecs = avc1.64000D
|
||||
maxInputSize = 5476
|
||||
width = 320
|
||||
height = 240
|
||||
frameRate = 29.523811
|
||||
metadata = entries=[mdta: key=com.android.capture.fps, smta: captureFrameRate=240.0, svcTemporalLayerCount=4, SlowMotion: segments=[Segment: startTimeMs=88, endTimeMs=879, speedDivisor=2, Segment: startTimeMs=1255, endTimeMs=1970, speedDivisor=8]]
|
||||
initializationData:
|
||||
data = length 33, hash D3FB879D
|
||||
data = length 10, hash 7A0D0F2B
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -549003117
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 0
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 593600631
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 14000
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -961321612
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 47333
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -386347143
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 80667
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -1289764147
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 114000
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 1337088875
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 147333
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -322406979
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 180667
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -1688033783
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 228042
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -700344608
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 244708
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -1441653629
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 334083
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 1201357091
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 267416
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -668484307
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 234083
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 653508165
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 300750
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -816848987
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 467416
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 1842436292
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 400750
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -559603233
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 367416
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -666437886
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 434083
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 182521759
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 600750
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -212376212
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 0
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -833872563
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 416
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -135901925
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 36499
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = -2124187794
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 44415
|
||||
sample:
|
||||
trackIndex = 0
|
||||
dataHashCode = 1016665126
|
||||
isKeyFrame = true
|
||||
presentationTimeUs = 63081
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 2139021989
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 534083
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 2013165108
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 500750
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 405675195
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 567416
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -1893277090
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 734083
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -1554795381
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 667416
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 1197099206
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 634083
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -674808173
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 700750
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -775517313
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 867416
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = -2045106113
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 800750
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 305167697
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 767416
|
||||
sample:
|
||||
trackIndex = 1
|
||||
dataHashCode = 554021920
|
||||
isKeyFrame = false
|
||||
presentationTimeUs = 834083
|
||||
released = true
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.testutil;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import com.google.common.base.Function;
|
||||
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
|
||||
/** Wraps a {@link Format} to allow dumping it. */
|
||||
public final class DumpableFormat implements Dumper.Dumpable {
|
||||
private final Format format;
|
||||
public final int index;
|
||||
|
||||
private static final Format DEFAULT_FORMAT = new Format.Builder().build();
|
||||
|
||||
public DumpableFormat(Format format, int index) {
|
||||
this.format = format;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Dumper dumper) {
|
||||
dumper.startBlock("format " + index);
|
||||
addIfNonDefault(dumper, "averageBitrate", format -> format.averageBitrate);
|
||||
addIfNonDefault(dumper, "peakBitrate", format -> format.peakBitrate);
|
||||
addIfNonDefault(dumper, "id", format -> format.id);
|
||||
addIfNonDefault(dumper, "containerMimeType", format -> format.containerMimeType);
|
||||
addIfNonDefault(dumper, "sampleMimeType", format -> format.sampleMimeType);
|
||||
addIfNonDefault(dumper, "codecs", format -> format.codecs);
|
||||
addIfNonDefault(dumper, "maxInputSize", format -> format.maxInputSize);
|
||||
addIfNonDefault(dumper, "width", format -> format.width);
|
||||
addIfNonDefault(dumper, "height", format -> format.height);
|
||||
addIfNonDefault(dumper, "frameRate", format -> format.frameRate);
|
||||
addIfNonDefault(dumper, "rotationDegrees", format -> format.rotationDegrees);
|
||||
addIfNonDefault(dumper, "pixelWidthHeightRatio", format -> format.pixelWidthHeightRatio);
|
||||
addIfNonDefault(dumper, "channelCount", format -> format.channelCount);
|
||||
addIfNonDefault(dumper, "sampleRate", format -> format.sampleRate);
|
||||
addIfNonDefault(dumper, "pcmEncoding", format -> format.pcmEncoding);
|
||||
addIfNonDefault(dumper, "encoderDelay", format -> format.encoderDelay);
|
||||
addIfNonDefault(dumper, "encoderPadding", format -> format.encoderPadding);
|
||||
addIfNonDefault(dumper, "subsampleOffsetUs", format -> format.subsampleOffsetUs);
|
||||
addIfNonDefault(dumper, "selectionFlags", format -> format.selectionFlags);
|
||||
addIfNonDefault(dumper, "language", format -> format.language);
|
||||
addIfNonDefault(dumper, "label", format -> format.label);
|
||||
if (format.drmInitData != null) {
|
||||
dumper.add("drmInitData", format.drmInitData.hashCode());
|
||||
}
|
||||
addIfNonDefault(dumper, "metadata", format -> format.metadata);
|
||||
if (!format.initializationData.isEmpty()) {
|
||||
dumper.startBlock("initializationData");
|
||||
for (int i = 0; i < format.initializationData.size(); i++) {
|
||||
dumper.add("data", format.initializationData.get(i));
|
||||
}
|
||||
dumper.endBlock();
|
||||
}
|
||||
dumper.endBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
DumpableFormat that = (DumpableFormat) o;
|
||||
return index == that.index && format.equals(that.format);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = format.hashCode();
|
||||
result = 31 * result + index;
|
||||
return result;
|
||||
}
|
||||
|
||||
private void addIfNonDefault(
|
||||
Dumper dumper, String field, Function<Format, @NullableType Object> getFieldFunction) {
|
||||
@Nullable Object thisValue = getFieldFunction.apply(format);
|
||||
@Nullable Object defaultValue = getFieldFunction.apply(DEFAULT_FORMAT);
|
||||
if (!Util.areEqual(thisValue, defaultValue)) {
|
||||
dumper.add(field, thisValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -26,7 +26,6 @@ import com.google.android.exoplayer2.upstream.DataReader;
|
|||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.primitives.Bytes;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
|
|
@ -34,7 +33,6 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
|
||||
/** A fake {@link TrackOutput}. */
|
||||
public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable {
|
||||
|
|
@ -284,81 +282,4 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable {
|
|||
}
|
||||
}
|
||||
|
||||
private static final class DumpableFormat implements Dumper.Dumpable {
|
||||
private final Format format;
|
||||
public final int index;
|
||||
|
||||
private static final Format DEFAULT_FORMAT = new Format.Builder().build();
|
||||
|
||||
public DumpableFormat(Format format, int index) {
|
||||
this.format = format;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Dumper dumper) {
|
||||
dumper.startBlock("format " + index);
|
||||
addIfNonDefault(dumper, "averageBitrate", format -> format.averageBitrate);
|
||||
addIfNonDefault(dumper, "peakBitrate", format -> format.peakBitrate);
|
||||
addIfNonDefault(dumper, "id", format -> format.id);
|
||||
addIfNonDefault(dumper, "containerMimeType", format -> format.containerMimeType);
|
||||
addIfNonDefault(dumper, "sampleMimeType", format -> format.sampleMimeType);
|
||||
addIfNonDefault(dumper, "codecs", format -> format.codecs);
|
||||
addIfNonDefault(dumper, "maxInputSize", format -> format.maxInputSize);
|
||||
addIfNonDefault(dumper, "width", format -> format.width);
|
||||
addIfNonDefault(dumper, "height", format -> format.height);
|
||||
addIfNonDefault(dumper, "frameRate", format -> format.frameRate);
|
||||
addIfNonDefault(dumper, "rotationDegrees", format -> format.rotationDegrees);
|
||||
addIfNonDefault(dumper, "pixelWidthHeightRatio", format -> format.pixelWidthHeightRatio);
|
||||
addIfNonDefault(dumper, "channelCount", format -> format.channelCount);
|
||||
addIfNonDefault(dumper, "sampleRate", format -> format.sampleRate);
|
||||
addIfNonDefault(dumper, "pcmEncoding", format -> format.pcmEncoding);
|
||||
addIfNonDefault(dumper, "encoderDelay", format -> format.encoderDelay);
|
||||
addIfNonDefault(dumper, "encoderPadding", format -> format.encoderPadding);
|
||||
addIfNonDefault(dumper, "subsampleOffsetUs", format -> format.subsampleOffsetUs);
|
||||
addIfNonDefault(dumper, "selectionFlags", format -> format.selectionFlags);
|
||||
addIfNonDefault(dumper, "language", format -> format.language);
|
||||
addIfNonDefault(dumper, "label", format -> format.label);
|
||||
if (format.drmInitData != null) {
|
||||
dumper.add("drmInitData", format.drmInitData.hashCode());
|
||||
}
|
||||
addIfNonDefault(dumper, "metadata", format -> format.metadata);
|
||||
if (!format.initializationData.isEmpty()) {
|
||||
dumper.startBlock("initializationData");
|
||||
for (int i = 0; i < format.initializationData.size(); i++) {
|
||||
dumper.add("data", format.initializationData.get(i));
|
||||
}
|
||||
dumper.endBlock();
|
||||
}
|
||||
dumper.endBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
DumpableFormat that = (DumpableFormat) o;
|
||||
return index == that.index && format.equals(that.format);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = format.hashCode();
|
||||
result = 31 * result + index;
|
||||
return result;
|
||||
}
|
||||
|
||||
private void addIfNonDefault(
|
||||
Dumper dumper, String field, Function<Format, @NullableType Object> getFieldFunction) {
|
||||
@Nullable Object thisValue = getFieldFunction.apply(format);
|
||||
@Nullable Object defaultValue = getFieldFunction.apply(DEFAULT_FORMAT);
|
||||
if (!Util.areEqual(thisValue, defaultValue)) {
|
||||
dumper.add(field, thisValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue