mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +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;
|
package com.google.android.exoplayer2.transformer;
|
||||||
|
|
||||||
import static com.google.android.exoplayer2.util.Assertions.checkState;
|
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 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.SparseIntArray;
|
||||||
import android.util.SparseLongArray;
|
import android.util.SparseLongArray;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.Format;
|
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.MimeTypes;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.nio.ByteBuffer;
|
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 static final long MAX_TRACK_WRITE_AHEAD_US = C.msToUs(500);
|
||||||
|
|
||||||
private final MediaMuxer mediaMuxer;
|
private final Muxer muxer;
|
||||||
private final String outputMimeType;
|
|
||||||
private final SparseIntArray trackTypeToIndex;
|
private final SparseIntArray trackTypeToIndex;
|
||||||
private final SparseLongArray trackTypeToTimeUs;
|
private final SparseLongArray trackTypeToTimeUs;
|
||||||
private final MediaCodec.BufferInfo bufferInfo;
|
|
||||||
|
|
||||||
private int trackCount;
|
private int trackCount;
|
||||||
private int trackFormatCount;
|
private int trackFormatCount;
|
||||||
|
|
@ -66,45 +54,10 @@ import java.nio.ByteBuffer;
|
||||||
private int previousTrackType;
|
private int previousTrackType;
|
||||||
private long minTrackTimeUs;
|
private long minTrackTimeUs;
|
||||||
|
|
||||||
/**
|
public MuxerWrapper(Muxer muxer) {
|
||||||
* Constructs an instance.
|
this.muxer = muxer;
|
||||||
*
|
|
||||||
* @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;
|
|
||||||
trackTypeToIndex = new SparseIntArray();
|
trackTypeToIndex = new SparseIntArray();
|
||||||
trackTypeToTimeUs = new SparseLongArray();
|
trackTypeToTimeUs = new SparseLongArray();
|
||||||
bufferInfo = new MediaCodec.BufferInfo();
|
|
||||||
previousTrackType = C.TRACK_TYPE_NONE;
|
previousTrackType = C.TRACK_TYPE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -123,6 +76,11 @@ import java.nio.ByteBuffer;
|
||||||
trackCount++;
|
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.
|
* Adds a track format to the muxer.
|
||||||
*
|
*
|
||||||
|
|
@ -131,9 +89,8 @@ import java.nio.ByteBuffer;
|
||||||
* long) written}.
|
* long) written}.
|
||||||
*
|
*
|
||||||
* @param format The {@link Format} to be added.
|
* @param format The {@link Format} to be added.
|
||||||
* @throws IllegalArgumentException If the format is invalid.
|
* @throws IllegalStateException If the format is unsupported or if there is already a track
|
||||||
* @throws IllegalStateException If the format is unsupported, if there is already a track format
|
* format of the same type (audio or video).
|
||||||
* of the same type (audio or video) or if the muxer is in the wrong state.
|
|
||||||
*/
|
*/
|
||||||
public void addTrackFormat(Format format) {
|
public void addTrackFormat(Format format) {
|
||||||
checkState(trackCount > 0, "All tracks should be registered before the formats are added.");
|
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,
|
trackTypeToIndex.get(trackType, /* valueIfKeyNotFound= */ C.INDEX_UNSET) == C.INDEX_UNSET,
|
||||||
"There is already a track of type " + trackType);
|
"There is already a track of type " + trackType);
|
||||||
|
|
||||||
MediaFormat mediaFormat;
|
int trackIndex = muxer.addTrack(format);
|
||||||
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);
|
|
||||||
trackTypeToIndex.put(trackType, trackIndex);
|
trackTypeToIndex.put(trackType, trackIndex);
|
||||||
trackTypeToTimeUs.put(trackType, 0L);
|
trackTypeToTimeUs.put(trackType, 0L);
|
||||||
trackFormatCount++;
|
trackFormatCount++;
|
||||||
if (trackFormatCount == trackCount) {
|
if (trackFormatCount == trackCount) {
|
||||||
mediaMuxer.start();
|
|
||||||
isReady = true;
|
isReady = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -180,9 +125,8 @@ import java.nio.ByteBuffer;
|
||||||
* {@link #addTrackFormat(Format) received a format} for every {@link #registerTrack()
|
* {@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
|
* registered track}, or if it should write samples of other track types first to ensure a
|
||||||
* good interleaving.
|
* 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}
|
* @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(
|
public boolean writeSample(
|
||||||
int trackType, @Nullable ByteBuffer data, boolean isKeyFrame, long presentationTimeUs) {
|
int trackType, @Nullable ByteBuffer data, boolean isKeyFrame, long presentationTimeUs) {
|
||||||
|
|
@ -197,11 +141,7 @@ import java.nio.ByteBuffer;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int offset = data.position();
|
muxer.writeSampleData(trackIndex, data, isKeyFrame, presentationTimeUs);
|
||||||
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);
|
|
||||||
trackTypeToTimeUs.put(trackType, presentationTimeUs);
|
trackTypeToTimeUs.put(trackType, presentationTimeUs);
|
||||||
previousTrackType = trackType;
|
previousTrackType = trackType;
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -222,35 +162,10 @@ import java.nio.ByteBuffer;
|
||||||
* Stops the muxer.
|
* Stops the muxer.
|
||||||
*
|
*
|
||||||
* <p>The muxer cannot be used anymore once it is stopped.
|
* <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() {
|
public void stop() {
|
||||||
if (!isReady) {
|
if (isReady) {
|
||||||
return;
|
isReady = false;
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -261,7 +176,7 @@ import java.nio.ByteBuffer;
|
||||||
*/
|
*/
|
||||||
public void release() {
|
public void release() {
|
||||||
isReady = false;
|
isReady = false;
|
||||||
mediaMuxer.release();
|
muxer.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the number of {@link #registerTrack() registered} tracks. */
|
/** Returns the number of {@link #registerTrack() registered} tracks. */
|
||||||
|
|
@ -269,48 +184,6 @@ import java.nio.ByteBuffer;
|
||||||
return trackCount;
|
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.
|
* 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;
|
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
|
* 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()}.
|
* transformer must be accessed can be queried using {@link #getApplicationLooper()}.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@RequiresApi(18)
|
@RequiresApi(18)
|
||||||
public final class Transformer {
|
public final class Transformer {
|
||||||
|
|
||||||
|
|
@ -88,6 +87,7 @@ public final class Transformer {
|
||||||
|
|
||||||
private @MonotonicNonNull Context context;
|
private @MonotonicNonNull Context context;
|
||||||
private @MonotonicNonNull MediaSourceFactory mediaSourceFactory;
|
private @MonotonicNonNull MediaSourceFactory mediaSourceFactory;
|
||||||
|
private Muxer.Factory muxerFactory;
|
||||||
private boolean removeAudio;
|
private boolean removeAudio;
|
||||||
private boolean removeVideo;
|
private boolean removeVideo;
|
||||||
private boolean flattenForSlowMotion;
|
private boolean flattenForSlowMotion;
|
||||||
|
|
@ -98,6 +98,7 @@ public final class Transformer {
|
||||||
|
|
||||||
/** Creates a builder with default values. */
|
/** Creates a builder with default values. */
|
||||||
public Builder() {
|
public Builder() {
|
||||||
|
muxerFactory = new FrameworkMuxer.Factory();
|
||||||
outputMimeType = MimeTypes.VIDEO_MP4;
|
outputMimeType = MimeTypes.VIDEO_MP4;
|
||||||
listener = new Listener() {};
|
listener = new Listener() {};
|
||||||
looper = Util.getCurrentOrMainLooper();
|
looper = Util.getCurrentOrMainLooper();
|
||||||
|
|
@ -108,6 +109,7 @@ public final class Transformer {
|
||||||
private Builder(Transformer transformer) {
|
private Builder(Transformer transformer) {
|
||||||
this.context = transformer.context;
|
this.context = transformer.context;
|
||||||
this.mediaSourceFactory = transformer.mediaSourceFactory;
|
this.mediaSourceFactory = transformer.mediaSourceFactory;
|
||||||
|
this.muxerFactory = transformer.muxerFactory;
|
||||||
this.removeAudio = transformer.transformation.removeAudio;
|
this.removeAudio = transformer.transformation.removeAudio;
|
||||||
this.removeVideo = transformer.transformation.removeVideo;
|
this.removeVideo = transformer.transformation.removeVideo;
|
||||||
this.flattenForSlowMotion = transformer.transformation.flattenForSlowMotion;
|
this.flattenForSlowMotion = transformer.transformation.flattenForSlowMotion;
|
||||||
|
|
@ -212,12 +214,8 @@ public final class Transformer {
|
||||||
*
|
*
|
||||||
* @param outputMimeType The MIME type of the output.
|
* @param outputMimeType The MIME type of the output.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
* @throws IllegalArgumentException If the MIME type is not supported.
|
|
||||||
*/
|
*/
|
||||||
public Builder setOutputMimeType(String outputMimeType) {
|
public Builder setOutputMimeType(String outputMimeType) {
|
||||||
if (!MuxerWrapper.supportsOutputMimeType(outputMimeType)) {
|
|
||||||
throw new IllegalArgumentException("Unsupported output MIME type: " + outputMimeType);
|
|
||||||
}
|
|
||||||
this.outputMimeType = outputMimeType;
|
this.outputMimeType = outputMimeType;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
@ -262,12 +260,25 @@ public final class Transformer {
|
||||||
return this;
|
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.
|
* Builds a {@link Transformer} instance.
|
||||||
*
|
*
|
||||||
* @throws IllegalStateException If the {@link Context} has not been provided.
|
* @throws IllegalStateException If the {@link Context} has not been provided.
|
||||||
* @throws IllegalStateException If both audio and video have been removed (otherwise the output
|
* @throws IllegalStateException If both audio and video have been removed (otherwise the output
|
||||||
* would not contain any samples).
|
* would not contain any samples).
|
||||||
|
* @throws IllegalStateException If the muxer doesn't support the requested output MIME type.
|
||||||
*/
|
*/
|
||||||
public Transformer build() {
|
public Transformer build() {
|
||||||
checkStateNotNull(context);
|
checkStateNotNull(context);
|
||||||
|
|
@ -278,9 +289,13 @@ public final class Transformer {
|
||||||
}
|
}
|
||||||
mediaSourceFactory = new DefaultMediaSourceFactory(context, defaultExtractorsFactory);
|
mediaSourceFactory = new DefaultMediaSourceFactory(context, defaultExtractorsFactory);
|
||||||
}
|
}
|
||||||
|
checkState(
|
||||||
|
muxerFactory.supportsOutputMimeType(outputMimeType),
|
||||||
|
"Unsupported output MIME type: " + outputMimeType);
|
||||||
Transformation transformation =
|
Transformation transformation =
|
||||||
new Transformation(removeAudio, removeVideo, flattenForSlowMotion, outputMimeType);
|
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 Context context;
|
||||||
private final MediaSourceFactory mediaSourceFactory;
|
private final MediaSourceFactory mediaSourceFactory;
|
||||||
|
private final Muxer.Factory muxerFactory;
|
||||||
private final Transformation transformation;
|
private final Transformation transformation;
|
||||||
private final Looper looper;
|
private final Looper looper;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
|
|
@ -344,6 +360,7 @@ public final class Transformer {
|
||||||
private Transformer(
|
private Transformer(
|
||||||
Context context,
|
Context context,
|
||||||
MediaSourceFactory mediaSourceFactory,
|
MediaSourceFactory mediaSourceFactory,
|
||||||
|
Muxer.Factory muxerFactory,
|
||||||
Transformation transformation,
|
Transformation transformation,
|
||||||
Transformer.Listener listener,
|
Transformer.Listener listener,
|
||||||
Looper looper,
|
Looper looper,
|
||||||
|
|
@ -353,6 +370,7 @@ public final class Transformer {
|
||||||
"Audio and video cannot both be removed.");
|
"Audio and video cannot both be removed.");
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.mediaSourceFactory = mediaSourceFactory;
|
this.mediaSourceFactory = mediaSourceFactory;
|
||||||
|
this.muxerFactory = muxerFactory;
|
||||||
this.transformation = transformation;
|
this.transformation = transformation;
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
this.looper = looper;
|
this.looper = looper;
|
||||||
|
|
@ -397,7 +415,7 @@ public final class Transformer {
|
||||||
* @throws IOException If an error occurs opening the output file for writing.
|
* @throws IOException If an error occurs opening the output file for writing.
|
||||||
*/
|
*/
|
||||||
public void startTransformation(MediaItem mediaItem, String path) throws IOException {
|
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)
|
public void startTransformation(MediaItem mediaItem, ParcelFileDescriptor parcelFileDescriptor)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
startTransformation(
|
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();
|
verifyApplicationThread();
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
throw new IllegalStateException("There is already a transformation in progress.");
|
throw new IllegalStateException("There is already a transformation in progress.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MuxerWrapper muxerWrapper = new MuxerWrapper(muxer);
|
||||||
this.muxerWrapper = muxerWrapper;
|
this.muxerWrapper = muxerWrapper;
|
||||||
|
|
||||||
DefaultTrackSelector trackSelector = new DefaultTrackSelector(context);
|
DefaultTrackSelector trackSelector = new DefaultTrackSelector(context);
|
||||||
trackSelector.setParameters(
|
trackSelector.setParameters(
|
||||||
new DefaultTrackSelector.ParametersBuilder(context)
|
new DefaultTrackSelector.ParametersBuilder(context)
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
@C.FormatSupport
|
@C.FormatSupport
|
||||||
public final int supportsFormat(Format format) {
|
public final int supportsFormat(Format format) {
|
||||||
@Nullable String sampleMimeType = format.sampleMimeType;
|
@Nullable String sampleMimeType = format.sampleMimeType;
|
||||||
if (MimeTypes.getTrackType(format.sampleMimeType) != getTrackType()) {
|
if (MimeTypes.getTrackType(sampleMimeType) != getTrackType()) {
|
||||||
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_TYPE);
|
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_TYPE);
|
||||||
} else if (muxerWrapper.supportsSampleMimeType(sampleMimeType)) {
|
} else if (muxerWrapper.supportsSampleMimeType(sampleMimeType)) {
|
||||||
return RendererCapabilities.create(C.FORMAT_HANDLED);
|
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
|
@Test
|
||||||
public void setOutputMimeType_unsupportedMimeType_throws() {
|
public void setOutputMimeType_unsupportedMimeType_throws() {
|
||||||
assertThrows(
|
assertThrows(
|
||||||
IllegalArgumentException.class,
|
IllegalStateException.class,
|
||||||
() -> new Transformer.Builder().setOutputMimeType(MimeTypes.VIDEO_FLV));
|
() -> new Transformer.Builder().setOutputMimeType(MimeTypes.VIDEO_FLV).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -28,15 +28,16 @@ import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer2.MediaItem;
|
import com.google.android.exoplayer2.MediaItem;
|
||||||
import com.google.android.exoplayer2.testutil.AutoAdvancingFakeClock;
|
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.MimeTypes;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
|
@ -56,18 +57,20 @@ import org.robolectric.shadows.ShadowMediaCodec;
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public final class TransformerTest {
|
public final class TransformerTest {
|
||||||
|
|
||||||
private static final String FILE_VIDEO_ONLY = "asset:///media/mkv/sample.mkv";
|
private static final String URI_PREFIX = "asset:///media/";
|
||||||
private static final String FILE_AUDIO_ONLY = "asset:///media/amr/sample_nb.amr";
|
private static final String FILE_VIDEO_ONLY = "mkv/sample.mkv";
|
||||||
private static final String FILE_AUDIO_VIDEO = "asset:///media/mp4/sample.mp4";
|
private static final String FILE_AUDIO_ONLY = "amr/sample_nb.amr";
|
||||||
|
private static final String FILE_AUDIO_VIDEO = "mp4/sample.mp4";
|
||||||
// The ShadowMediaMuxer only outputs sample data to the output file.
|
private static final String FILE_WITH_SUBTITLES = "mkv/sample_with_srt.mkv";
|
||||||
private static final int FILE_VIDEO_ONLY_SAMPLE_DATA_LENGTH = 89_502;
|
private static final String FILE_WITH_SEF_SLOW_MOTION = "mp4/sample_sef_slow_motion.mp4";
|
||||||
private static final int FILE_AUDIO_ONLY_SAMPLE_DATA_LENGTH = 2834;
|
private static final String FILE_WITH_ALL_SAMPLE_FORMATS_UNSUPPORTED = "mp4/sample_ac3.mp4";
|
||||||
private static final int FILE_AUDIO_VIDEO_AUDIO_SAMPLE_DATA_LENGTH = 9529;
|
private static final String FILE_UNKNOWN_DURATION = "mp4/sample_fragmented.mp4";
|
||||||
private static final int FILE_AUDIO_VIDEO_VIDEO_SAMPLE_DATA_LENGTH = 89_876;
|
public static final String DUMP_FILE_OUTPUT_DIRECTORY = "transformerdumps";
|
||||||
|
public static final String DUMP_FILE_EXTENSION = "dump";
|
||||||
|
|
||||||
private Context context;
|
private Context context;
|
||||||
private String outputPath;
|
private String outputPath;
|
||||||
|
private TestMuxer testMuxer;
|
||||||
private AutoAdvancingFakeClock clock;
|
private AutoAdvancingFakeClock clock;
|
||||||
private ProgressHolder progressHolder;
|
private ProgressHolder progressHolder;
|
||||||
|
|
||||||
|
|
@ -88,55 +91,78 @@ public final class TransformerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startTransformation_videoOnly_completesSuccessfully() throws Exception {
|
public void startTransformation_videoOnly_completesSuccessfully() throws Exception {
|
||||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
Transformer transformer =
|
||||||
MediaItem mediaItem = MediaItem.fromUri(FILE_VIDEO_ONLY);
|
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.startTransformation(mediaItem, outputPath);
|
||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
assertThat(new File(outputPath).length()).isEqualTo(FILE_VIDEO_ONLY_SAMPLE_DATA_LENGTH);
|
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_VIDEO_ONLY));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startTransformation_audioOnly_completesSuccessfully() throws Exception {
|
public void startTransformation_audioOnly_completesSuccessfully() throws Exception {
|
||||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
Transformer transformer =
|
||||||
MediaItem mediaItem = MediaItem.fromUri(FILE_AUDIO_ONLY);
|
new Transformer.Builder()
|
||||||
|
.setContext(context)
|
||||||
|
.setClock(clock)
|
||||||
|
.setMuxerFactory(new TestMuxerFactory())
|
||||||
|
.build();
|
||||||
|
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_ONLY);
|
||||||
|
|
||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
assertThat(new File(outputPath).length()).isEqualTo(FILE_AUDIO_ONLY_SAMPLE_DATA_LENGTH);
|
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_AUDIO_ONLY));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startTransformation_audioAndVideo_completesSuccessfully() throws Exception {
|
public void startTransformation_audioAndVideo_completesSuccessfully() throws Exception {
|
||||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
Transformer transformer =
|
||||||
MediaItem mediaItem = MediaItem.fromUri(FILE_AUDIO_VIDEO);
|
new Transformer.Builder()
|
||||||
|
.setContext(context)
|
||||||
|
.setClock(clock)
|
||||||
|
.setMuxerFactory(new TestMuxerFactory())
|
||||||
|
.build();
|
||||||
|
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||||
|
|
||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
assertThat(new File(outputPath).length())
|
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_AUDIO_VIDEO));
|
||||||
.isEqualTo(
|
|
||||||
FILE_AUDIO_VIDEO_VIDEO_SAMPLE_DATA_LENGTH + FILE_AUDIO_VIDEO_AUDIO_SAMPLE_DATA_LENGTH);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startTransformation_withSubtitles_completesSuccessfully() throws Exception {
|
public void startTransformation_withSubtitles_completesSuccessfully() throws Exception {
|
||||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
Transformer transformer =
|
||||||
MediaItem mediaItem = MediaItem.fromUri("asset:///media/mkv/sample_with_srt.mkv");
|
new Transformer.Builder()
|
||||||
|
.setContext(context)
|
||||||
|
.setClock(clock)
|
||||||
|
.setMuxerFactory(new TestMuxerFactory())
|
||||||
|
.build();
|
||||||
|
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_WITH_SUBTITLES);
|
||||||
|
|
||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
assertThat(new File(outputPath).length()).isEqualTo(89_502);
|
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_WITH_SUBTITLES));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startTransformation_successiveTransformations_completesSuccessfully()
|
public void startTransformation_successiveTransformations_completesSuccessfully()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
Transformer transformer =
|
||||||
MediaItem mediaItem = MediaItem.fromUri(FILE_VIDEO_ONLY);
|
new Transformer.Builder()
|
||||||
|
.setContext(context)
|
||||||
|
.setClock(clock)
|
||||||
|
.setMuxerFactory(new TestMuxerFactory())
|
||||||
|
.build();
|
||||||
|
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY);
|
||||||
|
|
||||||
// Transform first media item.
|
// Transform first media item.
|
||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
|
|
@ -147,13 +173,13 @@ public final class TransformerTest {
|
||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
assertThat(new File(outputPath).length()).isEqualTo(FILE_VIDEO_ONLY_SAMPLE_DATA_LENGTH);
|
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_VIDEO_ONLY));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startTransformation_concurrentTransformations_throwsError() throws Exception {
|
public void startTransformation_concurrentTransformations_throwsError() throws Exception {
|
||||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
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);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
|
|
||||||
|
|
@ -164,25 +190,37 @@ public final class TransformerTest {
|
||||||
@Test
|
@Test
|
||||||
public void startTransformation_removeAudio_completesSuccessfully() throws Exception {
|
public void startTransformation_removeAudio_completesSuccessfully() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
new Transformer.Builder().setContext(context).setRemoveAudio(true).setClock(clock).build();
|
new Transformer.Builder()
|
||||||
MediaItem mediaItem = MediaItem.fromUri(FILE_AUDIO_VIDEO);
|
.setContext(context)
|
||||||
|
.setRemoveAudio(true)
|
||||||
|
.setClock(clock)
|
||||||
|
.setMuxerFactory(new TestMuxerFactory())
|
||||||
|
.build();
|
||||||
|
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||||
|
|
||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
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
|
@Test
|
||||||
public void startTransformation_removeVideo_completesSuccessfully() throws Exception {
|
public void startTransformation_removeVideo_completesSuccessfully() throws Exception {
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
new Transformer.Builder().setContext(context).setRemoveVideo(true).setClock(clock).build();
|
new Transformer.Builder()
|
||||||
MediaItem mediaItem = MediaItem.fromUri(FILE_AUDIO_VIDEO);
|
.setContext(context)
|
||||||
|
.setRemoveVideo(true)
|
||||||
|
.setClock(clock)
|
||||||
|
.setMuxerFactory(new TestMuxerFactory())
|
||||||
|
.build();
|
||||||
|
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO);
|
||||||
|
|
||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
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
|
@Test
|
||||||
|
|
@ -192,13 +230,14 @@ public final class TransformerTest {
|
||||||
.setContext(context)
|
.setContext(context)
|
||||||
.setFlattenForSlowMotion(true)
|
.setFlattenForSlowMotion(true)
|
||||||
.setClock(clock)
|
.setClock(clock)
|
||||||
|
.setMuxerFactory(new TestMuxerFactory())
|
||||||
.build();
|
.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);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
assertThat(new File(outputPath).length()).isEqualTo(18_172);
|
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_WITH_SEF_SLOW_MOTION));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -217,7 +256,7 @@ public final class TransformerTest {
|
||||||
public void startTransformation_withAllSampleFormatsUnsupported_completesWithError()
|
public void startTransformation_withAllSampleFormatsUnsupported_completesWithError()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
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);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
Exception exception = TransformerTestRunner.runUntilError(transformer);
|
Exception exception = TransformerTestRunner.runUntilError(transformer);
|
||||||
|
|
@ -227,8 +266,13 @@ public final class TransformerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startTransformation_afterCancellation_completesSuccessfully() throws Exception {
|
public void startTransformation_afterCancellation_completesSuccessfully() throws Exception {
|
||||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
Transformer transformer =
|
||||||
MediaItem mediaItem = MediaItem.fromUri(FILE_VIDEO_ONLY);
|
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.startTransformation(mediaItem, outputPath);
|
||||||
transformer.cancel();
|
transformer.cancel();
|
||||||
|
|
@ -238,7 +282,7 @@ public final class TransformerTest {
|
||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
||||||
assertThat(new File(outputPath).length()).isEqualTo(FILE_VIDEO_ONLY_SAMPLE_DATA_LENGTH);
|
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_VIDEO_ONLY));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -247,8 +291,13 @@ public final class TransformerTest {
|
||||||
anotherThread.start();
|
anotherThread.start();
|
||||||
Looper looper = anotherThread.getLooper();
|
Looper looper = anotherThread.getLooper();
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
new Transformer.Builder().setContext(context).setLooper(looper).setClock(clock).build();
|
new Transformer.Builder()
|
||||||
MediaItem mediaItem = MediaItem.fromUri(FILE_AUDIO_ONLY);
|
.setContext(context)
|
||||||
|
.setLooper(looper)
|
||||||
|
.setClock(clock)
|
||||||
|
.setMuxerFactory(new TestMuxerFactory())
|
||||||
|
.build();
|
||||||
|
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_ONLY);
|
||||||
AtomicReference<Exception> exception = new AtomicReference<>();
|
AtomicReference<Exception> exception = new AtomicReference<>();
|
||||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||||
|
|
||||||
|
|
@ -267,13 +316,13 @@ public final class TransformerTest {
|
||||||
countDownLatch.await();
|
countDownLatch.await();
|
||||||
|
|
||||||
assertThat(exception.get()).isNull();
|
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
|
@Test
|
||||||
public void startTransformation_fromWrongThread_throwsError() throws Exception {
|
public void startTransformation_fromWrongThread_throwsError() throws Exception {
|
||||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
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");
|
HandlerThread anotherThread = new HandlerThread("AnotherThread");
|
||||||
AtomicReference<IllegalStateException> illegalStateException = new AtomicReference<>();
|
AtomicReference<IllegalStateException> illegalStateException = new AtomicReference<>();
|
||||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||||
|
|
@ -300,7 +349,7 @@ public final class TransformerTest {
|
||||||
@Test
|
@Test
|
||||||
public void getProgress_knownDuration_returnsConsistentStates() throws Exception {
|
public void getProgress_knownDuration_returnsConsistentStates() throws Exception {
|
||||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
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 =
|
AtomicInteger previousProgressState =
|
||||||
new AtomicInteger(PROGRESS_STATE_WAITING_FOR_AVAILABILITY);
|
new AtomicInteger(PROGRESS_STATE_WAITING_FOR_AVAILABILITY);
|
||||||
AtomicBoolean foundInconsistentState = new AtomicBoolean();
|
AtomicBoolean foundInconsistentState = new AtomicBoolean();
|
||||||
|
|
@ -346,7 +395,7 @@ public final class TransformerTest {
|
||||||
@Test
|
@Test
|
||||||
public void getProgress_knownDuration_givesIncreasingPercentages() throws Exception {
|
public void getProgress_knownDuration_givesIncreasingPercentages() throws Exception {
|
||||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
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<>();
|
List<Integer> progresses = new ArrayList<>();
|
||||||
Handler progressHandler =
|
Handler progressHandler =
|
||||||
new Handler(Looper.myLooper()) {
|
new Handler(Looper.myLooper()) {
|
||||||
|
|
@ -381,7 +430,7 @@ public final class TransformerTest {
|
||||||
@Test
|
@Test
|
||||||
public void getProgress_noCurrentTransformation_returnsNoTransformation() throws Exception {
|
public void getProgress_noCurrentTransformation_returnsNoTransformation() throws Exception {
|
||||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
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.ProgressState int stateBeforeTransform = transformer.getProgress(progressHolder);
|
||||||
transformer.startTransformation(mediaItem, outputPath);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
|
|
@ -395,7 +444,7 @@ public final class TransformerTest {
|
||||||
@Test
|
@Test
|
||||||
public void getProgress_unknownDuration_returnsConsistentStates() throws Exception {
|
public void getProgress_unknownDuration_returnsConsistentStates() throws Exception {
|
||||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
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 =
|
AtomicInteger previousProgressState =
|
||||||
new AtomicInteger(PROGRESS_STATE_WAITING_FOR_AVAILABILITY);
|
new AtomicInteger(PROGRESS_STATE_WAITING_FOR_AVAILABILITY);
|
||||||
AtomicBoolean foundInconsistentState = new AtomicBoolean();
|
AtomicBoolean foundInconsistentState = new AtomicBoolean();
|
||||||
|
|
@ -462,7 +511,7 @@ public final class TransformerTest {
|
||||||
@Test
|
@Test
|
||||||
public void cancel_afterCompletion_doesNotThrow() throws Exception {
|
public void cancel_afterCompletion_doesNotThrow() throws Exception {
|
||||||
Transformer transformer = new Transformer.Builder().setContext(context).setClock(clock).build();
|
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);
|
transformer.startTransformation(mediaItem, outputPath);
|
||||||
TransformerTestRunner.runUntilCompleted(transformer);
|
TransformerTestRunner.runUntilCompleted(transformer);
|
||||||
|
|
@ -507,4 +556,28 @@ public final class TransformerTest {
|
||||||
private static void removeEncodersAndDecoders() {
|
private static void removeEncodersAndDecoders() {
|
||||||
ShadowMediaCodec.clearCodecs();
|
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.Assertions;
|
||||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import com.google.common.base.Function;
|
|
||||||
import com.google.common.primitives.Bytes;
|
import com.google.common.primitives.Bytes;
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
@ -34,7 +33,6 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|
||||||
|
|
||||||
/** A fake {@link TrackOutput}. */
|
/** A fake {@link TrackOutput}. */
|
||||||
public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable {
|
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