Commit 32bed828 by samrobinson Committed by Ian Baker

Add an option to force a silent audio track.

PiperOrigin-RevId: 492154544
parent 90d4fdcf
...@@ -41,6 +41,7 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -41,6 +41,7 @@ import org.checkerframework.dataflow.qual.Pure;
private static final int DEFAULT_ENCODER_BITRATE = 128 * 1024; private static final int DEFAULT_ENCODER_BITRATE = 128 * 1024;
@Nullable private final SilentAudioGenerator silentAudioGenerator;
private final DecoderInputBuffer inputBuffer; private final DecoderInputBuffer inputBuffer;
private final AudioProcessingPipeline audioProcessingPipeline; private final AudioProcessingPipeline audioProcessingPipeline;
private final Codec encoder; private final Codec encoder;
...@@ -52,12 +53,14 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -52,12 +53,14 @@ import org.checkerframework.dataflow.qual.Pure;
private long nextEncoderInputBufferTimeUs; private long nextEncoderInputBufferTimeUs;
private long encoderBufferDurationRemainder; private long encoderBufferDurationRemainder;
// TODO(b/260618558): Move silent audio generation upstream of this component.
public AudioTranscodingSamplePipeline( public AudioTranscodingSamplePipeline(
Format inputFormat, Format inputFormat,
long streamStartPositionUs, long streamStartPositionUs,
long streamOffsetUs, long streamOffsetUs,
TransformationRequest transformationRequest, TransformationRequest transformationRequest,
ImmutableList<AudioProcessor> audioProcessors, ImmutableList<AudioProcessor> audioProcessors,
long forceSilentAudioDurationUs,
Codec.EncoderFactory encoderFactory, Codec.EncoderFactory encoderFactory,
MuxerWrapper muxerWrapper, MuxerWrapper muxerWrapper,
Listener listener, Listener listener,
...@@ -71,6 +74,16 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -71,6 +74,16 @@ import org.checkerframework.dataflow.qual.Pure;
muxerWrapper, muxerWrapper,
listener); listener);
if (forceSilentAudioDurationUs != C.TIME_UNSET) {
silentAudioGenerator =
new SilentAudioGenerator(
forceSilentAudioDurationUs,
inputFormat.sampleRate,
Util.getPcmFrameSize(C.ENCODING_PCM_16BIT, inputFormat.channelCount));
} else {
silentAudioGenerator = null;
}
inputBuffer = new DecoderInputBuffer(BUFFER_REPLACEMENT_MODE_DISABLED); inputBuffer = new DecoderInputBuffer(BUFFER_REPLACEMENT_MODE_DISABLED);
encoderInputBuffer = new DecoderInputBuffer(BUFFER_REPLACEMENT_MODE_DISABLED); encoderInputBuffer = new DecoderInputBuffer(BUFFER_REPLACEMENT_MODE_DISABLED);
encoderOutputBuffer = new DecoderInputBuffer(BUFFER_REPLACEMENT_MODE_DISABLED); encoderOutputBuffer = new DecoderInputBuffer(BUFFER_REPLACEMENT_MODE_DISABLED);
...@@ -160,11 +173,17 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -160,11 +173,17 @@ import org.checkerframework.dataflow.qual.Pure;
@Override @Override
protected boolean processDataUpToMuxer() throws TransformationException { protected boolean processDataUpToMuxer() throws TransformationException {
if (audioProcessingPipeline.isOperational()) { if (!audioProcessingPipeline.isOperational()) {
return feedEncoderFromProcessingPipeline() || feedProcessingPipelineFromInput(); return silentAudioGenerator == null ? feedEncoderFromInput() : feedEncoderFromSilence();
} else {
return feedEncoderFromInput();
} }
if (feedEncoderFromProcessingPipeline()) {
return true;
}
return silentAudioGenerator == null
? feedProcessingPipelineFromInput()
: feedProcessingPipelineFromSilence();
} }
@Override @Override
...@@ -269,6 +288,45 @@ import org.checkerframework.dataflow.qual.Pure; ...@@ -269,6 +288,45 @@ import org.checkerframework.dataflow.qual.Pure;
} }
/** /**
* Attempts to pass silent audio to the encoder.
*
* @return Whether it may be possible to feed more data immediately by calling this method again.
*/
private boolean feedEncoderFromSilence() throws TransformationException {
checkNotNull(silentAudioGenerator);
if (!encoder.maybeDequeueInputBuffer(encoderInputBuffer)) {
return false;
}
if (silentAudioGenerator.isEnded()) {
queueEndOfStreamToEncoder();
return false;
}
ByteBuffer silence = silentAudioGenerator.getBuffer();
feedEncoder(silence);
return true;
}
/**
* Attempts to feed silent audio to the {@link AudioProcessingPipeline}.
*
* @return Whether it may be possible to feed more data immediately by calling this method again.
*/
private boolean feedProcessingPipelineFromSilence() {
checkNotNull(silentAudioGenerator);
if (silentAudioGenerator.isEnded()) {
audioProcessingPipeline.queueEndOfStream();
return false;
}
checkState(!audioProcessingPipeline.isEnded());
ByteBuffer silence = silentAudioGenerator.getBuffer();
audioProcessingPipeline.queueInput(silence);
return !silence.hasRemaining();
}
/**
* Feeds as much data as possible between the current position and limit of the specified {@link * Feeds as much data as possible between the current position and limit of the specified {@link
* ByteBuffer} to the encoder, and advances its position by the number of bytes fed. * ByteBuffer} to the encoder, and advances its position by the number of bytes fed.
*/ */
......
/*
* Copyright 2022 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 java.nio.ByteBuffer;
import java.nio.ByteOrder;
/* package */ final class SilentAudioGenerator {
private static final int DEFAULT_BUFFER_SIZE = 4096;
private final ByteBuffer internalBuffer;
private long remainingBytesToOutput;
public SilentAudioGenerator(long totalDurationUs, long sampleRate, int frameSize) {
remainingBytesToOutput = (sampleRate * frameSize * totalDurationUs) / 1_000_000L;
internalBuffer = ByteBuffer.allocate(DEFAULT_BUFFER_SIZE).order(ByteOrder.nativeOrder());
internalBuffer.flip();
}
public ByteBuffer getBuffer() {
if (!internalBuffer.hasRemaining()) {
// "next" buffer.
internalBuffer.clear();
if (remainingBytesToOutput < internalBuffer.capacity()) {
internalBuffer.limit((int) remainingBytesToOutput);
}
// Only reduce remaining bytes when we "generate" a new one.
remainingBytesToOutput -= internalBuffer.remaining();
}
return internalBuffer;
}
public boolean isEnded() {
return !internalBuffer.hasRemaining() && remainingBytesToOutput == 0;
}
}
...@@ -30,6 +30,7 @@ import com.google.android.exoplayer2.C; ...@@ -30,6 +30,7 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.audio.AudioProcessor; import com.google.android.exoplayer2.audio.AudioProcessor;
import com.google.android.exoplayer2.audio.SonicAudioProcessor;
import com.google.android.exoplayer2.effect.GlEffect; import com.google.android.exoplayer2.effect.GlEffect;
import com.google.android.exoplayer2.effect.GlEffectsFrameProcessor; import com.google.android.exoplayer2.effect.GlEffectsFrameProcessor;
import com.google.android.exoplayer2.effect.GlMatrixTransformation; import com.google.android.exoplayer2.effect.GlMatrixTransformation;
...@@ -86,6 +87,7 @@ public final class Transformer { ...@@ -86,6 +87,7 @@ public final class Transformer {
private ImmutableList<Effect> videoEffects; private ImmutableList<Effect> videoEffects;
private boolean removeAudio; private boolean removeAudio;
private boolean removeVideo; private boolean removeVideo;
private boolean forceSilentAudio;
private ListenerSet<Transformer.Listener> listeners; private ListenerSet<Transformer.Listener> listeners;
private MediaSource.@MonotonicNonNull Factory mediaSourceFactory; private MediaSource.@MonotonicNonNull Factory mediaSourceFactory;
private Codec.DecoderFactory decoderFactory; private Codec.DecoderFactory decoderFactory;
...@@ -124,6 +126,7 @@ public final class Transformer { ...@@ -124,6 +126,7 @@ public final class Transformer {
this.videoEffects = transformer.videoEffects; this.videoEffects = transformer.videoEffects;
this.removeAudio = transformer.removeAudio; this.removeAudio = transformer.removeAudio;
this.removeVideo = transformer.removeVideo; this.removeVideo = transformer.removeVideo;
this.forceSilentAudio = transformer.forceSilentAudio;
this.listeners = transformer.listeners; this.listeners = transformer.listeners;
this.mediaSourceFactory = transformer.mediaSourceFactory; this.mediaSourceFactory = transformer.mediaSourceFactory;
this.decoderFactory = transformer.decoderFactory; this.decoderFactory = transformer.decoderFactory;
...@@ -415,6 +418,33 @@ public final class Transformer { ...@@ -415,6 +418,33 @@ public final class Transformer {
} }
/** /**
* Sets whether to force silent audio for the output file, ignoring any existing audio.
*
* <p>This method is experimental and may be removed or changed without warning.
*
* <p>Audio properties/format:
*
* <ul>
* <li>Duration will match duration of the input media.
* <li>Sample mime type will match {@link TransformationRequest#audioMimeType}, or {@link
* MimeTypes#AUDIO_AAC} if {@code null}.
* <li>Sample rate will be 44100hz. This can be modified by passing a {@link
* SonicAudioProcessor} to {@link #setAudioProcessors(List)}, using {@link
* SonicAudioProcessor#setOutputSampleRateHz(int)}.
* <li>Channel count will be 2. This can be modified by implementing a custom {@link
* AudioProcessor} and passing it to {@link #setAudioProcessors(List)}.
* </ul>
*
* @param forceSilentAudio Whether to output silent audio for the output file.
* @return This builder.
*/
@CanIgnoreReturnValue
public Builder experimentalSetForceSilentAudio(boolean forceSilentAudio) {
this.forceSilentAudio = forceSilentAudio;
return this;
}
/**
* Builds a {@link Transformer} instance. * Builds a {@link Transformer} instance.
* *
* @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
...@@ -443,6 +473,7 @@ public final class Transformer { ...@@ -443,6 +473,7 @@ public final class Transformer {
videoEffects, videoEffects,
removeAudio, removeAudio,
removeVideo, removeVideo,
forceSilentAudio,
listeners, listeners,
mediaSourceFactory, mediaSourceFactory,
decoderFactory, decoderFactory,
...@@ -555,6 +586,7 @@ public final class Transformer { ...@@ -555,6 +586,7 @@ public final class Transformer {
private final ImmutableList<Effect> videoEffects; private final ImmutableList<Effect> videoEffects;
private final boolean removeAudio; private final boolean removeAudio;
private final boolean removeVideo; private final boolean removeVideo;
private final boolean forceSilentAudio;
private final ListenerSet<Transformer.Listener> listeners; private final ListenerSet<Transformer.Listener> listeners;
private final MediaSource.Factory mediaSourceFactory; private final MediaSource.Factory mediaSourceFactory;
private final FrameProcessor.Factory frameProcessorFactory; private final FrameProcessor.Factory frameProcessorFactory;
...@@ -572,7 +604,8 @@ public final class Transformer { ...@@ -572,7 +604,8 @@ public final class Transformer {
ImmutableList<Effect> videoEffects, ImmutableList<Effect> videoEffects,
boolean removeAudio, boolean removeAudio,
boolean removeVideo, boolean removeVideo,
ListenerSet<Transformer.Listener> listeners, boolean forceSilentAudio,
ListenerSet<Listener> listeners,
MediaSource.Factory mediaSourceFactory, MediaSource.Factory mediaSourceFactory,
Codec.DecoderFactory decoderFactory, Codec.DecoderFactory decoderFactory,
Codec.EncoderFactory encoderFactory, Codec.EncoderFactory encoderFactory,
...@@ -581,6 +614,10 @@ public final class Transformer { ...@@ -581,6 +614,10 @@ public final class Transformer {
Looper looper, Looper looper,
DebugViewProvider debugViewProvider, DebugViewProvider debugViewProvider,
Clock clock) { Clock clock) {
if (forceSilentAudio) {
removeAudio = true;
}
checkState(!removeVideo || !forceSilentAudio, "Silent only audio track needs a video track.");
checkState(!removeAudio || !removeVideo, "Audio and video cannot both be removed."); checkState(!removeAudio || !removeVideo, "Audio and video cannot both be removed.");
this.context = context; this.context = context;
this.transformationRequest = transformationRequest; this.transformationRequest = transformationRequest;
...@@ -588,6 +625,7 @@ public final class Transformer { ...@@ -588,6 +625,7 @@ public final class Transformer {
this.videoEffects = videoEffects; this.videoEffects = videoEffects;
this.removeAudio = removeAudio; this.removeAudio = removeAudio;
this.removeVideo = removeVideo; this.removeVideo = removeVideo;
this.forceSilentAudio = forceSilentAudio;
this.listeners = listeners; this.listeners = listeners;
this.mediaSourceFactory = mediaSourceFactory; this.mediaSourceFactory = mediaSourceFactory;
this.decoderFactory = decoderFactory; this.decoderFactory = decoderFactory;
...@@ -726,6 +764,7 @@ public final class Transformer { ...@@ -726,6 +764,7 @@ public final class Transformer {
videoEffects, videoEffects,
removeAudio, removeAudio,
removeVideo, removeVideo,
forceSilentAudio,
mediaSourceFactory, mediaSourceFactory,
decoderFactory, decoderFactory,
encoderFactory, encoderFactory,
......
...@@ -97,6 +97,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -97,6 +97,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final TransformationRequest transformationRequest; private final TransformationRequest transformationRequest;
private final ImmutableList<AudioProcessor> audioProcessors; private final ImmutableList<AudioProcessor> audioProcessors;
private final ImmutableList<Effect> videoEffects; private final ImmutableList<Effect> videoEffects;
private final boolean forceSilentAudio;
private final Codec.DecoderFactory decoderFactory; private final Codec.DecoderFactory decoderFactory;
private final Codec.EncoderFactory encoderFactory; private final Codec.EncoderFactory encoderFactory;
private final FrameProcessor.Factory frameProcessorFactory; private final FrameProcessor.Factory frameProcessorFactory;
...@@ -114,6 +115,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -114,6 +115,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Nullable private DecoderInputBuffer pendingInputBuffer; @Nullable private DecoderInputBuffer pendingInputBuffer;
private boolean isDrainingPipelines; private boolean isDrainingPipelines;
private int silentSamplePipelineIndex;
private @Transformer.ProgressState int progressState; private @Transformer.ProgressState int progressState;
private long progressPositionMs; private long progressPositionMs;
private long durationUs; private long durationUs;
...@@ -131,6 +133,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -131,6 +133,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
ImmutableList<Effect> videoEffects, ImmutableList<Effect> videoEffects,
boolean removeAudio, boolean removeAudio,
boolean removeVideo, boolean removeVideo,
boolean forceSilentAudio,
MediaSource.Factory mediaSourceFactory, MediaSource.Factory mediaSourceFactory,
Codec.DecoderFactory decoderFactory, Codec.DecoderFactory decoderFactory,
Codec.EncoderFactory encoderFactory, Codec.EncoderFactory encoderFactory,
...@@ -145,6 +148,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -145,6 +148,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
this.transformationRequest = transformationRequest; this.transformationRequest = transformationRequest;
this.audioProcessors = audioProcessors; this.audioProcessors = audioProcessors;
this.videoEffects = videoEffects; this.videoEffects = videoEffects;
this.forceSilentAudio = forceSilentAudio;
this.decoderFactory = decoderFactory; this.decoderFactory = decoderFactory;
this.encoderFactory = encoderFactory; this.encoderFactory = encoderFactory;
this.frameProcessorFactory = frameProcessorFactory; this.frameProcessorFactory = frameProcessorFactory;
...@@ -168,6 +172,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -168,6 +172,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
componentListener, componentListener,
clock); clock);
samplePipelines = new ArrayList<>(); samplePipelines = new ArrayList<>();
silentSamplePipelineIndex = C.INDEX_UNSET;
dequeueBufferConditionVariable = new ConditionVariable(); dequeueBufferConditionVariable = new ConditionVariable();
muxerWrapper = muxerWrapper =
new MuxerWrapper( new MuxerWrapper(
...@@ -258,6 +263,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -258,6 +263,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
while (samplePipeline.processData()) {} while (samplePipeline.processData()) {}
pendingInputBuffer = samplePipeline.dequeueInputBuffer(); pendingInputBuffer = samplePipeline.dequeueInputBuffer();
dequeueBufferConditionVariable.open(); dequeueBufferConditionVariable.open();
if (forceSilentAudio) {
while (samplePipelines.get(silentSamplePipelineIndex).processData()) {}
}
} }
private void queueInputInternal(int samplePipelineIndex) throws TransformationException { private void queueInputInternal(int samplePipelineIndex) throws TransformationException {
...@@ -391,6 +400,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -391,6 +400,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
trackRegistered = true; trackRegistered = true;
muxerWrapper.registerTrack(); muxerWrapper.registerTrack();
fallbackListener.registerTrack(); fallbackListener.registerTrack();
if (forceSilentAudio) {
muxerWrapper.registerTrack();
fallbackListener.registerTrack();
}
} }
@Override @Override
...@@ -410,6 +424,23 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -410,6 +424,23 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
int samplePipelineIndex = tracksAddedCount; int samplePipelineIndex = tracksAddedCount;
tracksAddedCount++; tracksAddedCount++;
if (forceSilentAudio) {
Format silentAudioFormat =
new Format.Builder()
.setSampleMimeType(MimeTypes.AUDIO_AAC)
.setSampleRate(44100)
.setChannelCount(2)
.build();
SamplePipeline audioSamplePipeline =
getSamplePipeline(silentAudioFormat, streamStartPositionUs, streamOffsetUs);
internalHandler
.obtainMessage(MSG_REGISTER_SAMPLE_PIPELINE, audioSamplePipeline)
.sendToTarget();
silentSamplePipelineIndex = tracksAddedCount;
tracksAddedCount++;
}
return new SamplePipelineInput(samplePipelineIndex, samplePipeline.expectsDecodedData()); return new SamplePipelineInput(samplePipelineIndex, samplePipeline.expectsDecodedData());
} }
...@@ -459,6 +490,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -459,6 +490,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
streamOffsetUs, streamOffsetUs,
transformationRequest, transformationRequest,
audioProcessors, audioProcessors,
forceSilentAudio ? durationUs : C.TIME_UNSET,
encoderFactory, encoderFactory,
muxerWrapper, muxerWrapper,
/* listener= */ this, /* listener= */ this,
...@@ -509,6 +541,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -509,6 +541,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
if (!audioProcessors.isEmpty()) { if (!audioProcessors.isEmpty()) {
return true; return true;
} }
if (forceSilentAudio) {
return true;
}
return false; return false;
} }
......
/*
* Copyright 2022 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.common.truth.Truth.assertThat;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.nio.ByteBuffer;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Unit tests for {@link SilentAudioGenerator}. */
@RunWith(AndroidJUnit4.class)
public class SilentAudioGeneratorTest {
@Test
public void numberOfBytesProduced_isCorrect() {
SilentAudioGenerator generator =
new SilentAudioGenerator(
/* totalDurationUs= */ 3_000_000, /* sampleRate= */ 88_200, /* frameSize= */ 12);
int bytesOutput = 0;
while (!generator.isEnded()) {
ByteBuffer output = generator.getBuffer();
bytesOutput += output.remaining();
// "Consume" buffer.
output.position(output.limit());
}
// 88_200 * 12 * 3s = 3175200
assertThat(bytesOutput).isEqualTo(3_175_200);
}
@Test
public void lastBufferProduced_isCorrectSize() {
SilentAudioGenerator generator =
new SilentAudioGenerator(
/* totalDurationUs= */ 1_000_000, /* sampleRate= */ 44_100, /* frameSize= */ 4);
int currentBufferSize = 0;
while (!generator.isEnded()) {
ByteBuffer output = generator.getBuffer();
currentBufferSize = output.remaining();
// "Consume" buffer.
output.position(output.limit());
}
// Last buffer is smaller and only outputs the 'leftover' bytes.
// (44_100 * 4) % 4096 = 272
assertThat(currentBufferSize).isEqualTo(272);
}
@Test
public void totalBytesLowerThanDefaultBufferSize_smallBufferProduced() {
SilentAudioGenerator generator =
new SilentAudioGenerator(
/* totalDurationUs= */ 5_000, /* sampleRate= */ 48_000, /* frameSize= */ 4);
// 5_000 * 48_000 * 4 / 1_000_000 = 960
assertThat(generator.getBuffer().remaining()).isEqualTo(960);
}
}
...@@ -266,6 +266,21 @@ public final class TransformerEndToEndTest { ...@@ -266,6 +266,21 @@ public final class TransformerEndToEndTest {
} }
@Test @Test
public void startTransformation_silentAudio_completesSuccessfully() throws Exception {
Transformer transformer =
createTransformerBuilder(/* enableFallback= */ false)
.experimentalSetForceSilentAudio(true)
.build();
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
transformer.startTransformation(mediaItem, outputPath);
TransformerTestRunner.runUntilCompleted(transformer);
DumpFileAsserts.assertOutput(
context, testMuxer, getDumpFileName(FILE_AUDIO_VIDEO + ".silentaudio"));
}
@Test
public void startTransformation_withMultipleListeners_callsEachOnCompletion() throws Exception { public void startTransformation_withMultipleListeners_callsEachOnCompletion() throws Exception {
Transformer.Listener mockListener1 = mock(Transformer.Listener.class); Transformer.Listener mockListener1 = mock(Transformer.Listener.class);
Transformer.Listener mockListener2 = mock(Transformer.Listener.class); Transformer.Listener mockListener2 = mock(Transformer.Listener.class);
......
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
format 1:
sampleMimeType = audio/mp4a-latm
channelCount = 2
sampleRate = 44100
pcmEncoding = 2
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 0
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 23220
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 46440
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 69660
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 92880
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 116100
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 139320
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 162540
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 185760
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 208980
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 232200
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 255420
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 278640
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 301860
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 325080
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 348300
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 371520
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 394740
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 417960
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 441180
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 464400
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 487620
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 510840
sample:
trackIndex = 0
dataHashCode = -770308242
size = 36692
isKeyFrame = true
presentationTimeUs = 0
sample:
trackIndex = 0
dataHashCode = -732087136
size = 5312
isKeyFrame = false
presentationTimeUs = 66733
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 534059
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 557279
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 580499
sample:
trackIndex = 0
dataHashCode = 468156717
size = 599
isKeyFrame = false
presentationTimeUs = 33366
sample:
trackIndex = 0
dataHashCode = 1150349584
size = 7735
isKeyFrame = false
presentationTimeUs = 200200
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 603719
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 626939
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 650159
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 673379
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 696599
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 719819
sample:
trackIndex = 0
dataHashCode = 1443582006
size = 987
isKeyFrame = false
presentationTimeUs = 133466
sample:
trackIndex = 0
dataHashCode = -310585145
size = 673
isKeyFrame = false
presentationTimeUs = 100100
sample:
trackIndex = 0
dataHashCode = 807460688
size = 523
isKeyFrame = false
presentationTimeUs = 166833
sample:
trackIndex = 0
dataHashCode = 1936487090
size = 6061
isKeyFrame = false
presentationTimeUs = 333666
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 743039
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 766259
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 789479
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 812699
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 835919
sample:
trackIndex = 0
dataHashCode = -32297181
size = 992
isKeyFrame = false
presentationTimeUs = 266933
sample:
trackIndex = 0
dataHashCode = 1529616406
size = 623
isKeyFrame = false
presentationTimeUs = 233566
sample:
trackIndex = 0
dataHashCode = 1949198785
size = 421
isKeyFrame = false
presentationTimeUs = 300300
sample:
trackIndex = 0
dataHashCode = -147880287
size = 4899
isKeyFrame = false
presentationTimeUs = 433766
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 859139
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 882359
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 905579
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 928799
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 952019
sample:
trackIndex = 0
dataHashCode = 1369083472
size = 568
isKeyFrame = false
presentationTimeUs = 400400
sample:
trackIndex = 0
dataHashCode = 965782073
size = 620
isKeyFrame = false
presentationTimeUs = 367033
sample:
trackIndex = 0
dataHashCode = -261176150
size = 5450
isKeyFrame = false
presentationTimeUs = 567233
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 975239
sample:
trackIndex = 1
dataHashCode = 1742602241
size = 4096
isKeyFrame = true
presentationTimeUs = 998459
sample:
trackIndex = 1
dataHashCode = -1029274849
size = 409
isKeyFrame = true
presentationTimeUs = 1021679
sample:
trackIndex = 0
dataHashCode = -1830836678
size = 1051
isKeyFrame = false
presentationTimeUs = 500500
sample:
trackIndex = 0
dataHashCode = 1767407540
size = 874
isKeyFrame = false
presentationTimeUs = 467133
sample:
trackIndex = 0
dataHashCode = 918440283
size = 781
isKeyFrame = false
presentationTimeUs = 533866
sample:
trackIndex = 0
dataHashCode = -1408463661
size = 4725
isKeyFrame = false
presentationTimeUs = 700700
sample:
trackIndex = 0
dataHashCode = 1569455924
size = 1022
isKeyFrame = false
presentationTimeUs = 633966
sample:
trackIndex = 0
dataHashCode = -1723778407
size = 790
isKeyFrame = false
presentationTimeUs = 600600
sample:
trackIndex = 0
dataHashCode = 1578275472
size = 610
isKeyFrame = false
presentationTimeUs = 667333
sample:
trackIndex = 0
dataHashCode = 1989768395
size = 2751
isKeyFrame = false
presentationTimeUs = 834166
sample:
trackIndex = 0
dataHashCode = -1215674502
size = 745
isKeyFrame = false
presentationTimeUs = 767433
sample:
trackIndex = 0
dataHashCode = -814473606
size = 621
isKeyFrame = false
presentationTimeUs = 734066
sample:
trackIndex = 0
dataHashCode = 498370894
size = 505
isKeyFrame = false
presentationTimeUs = 800800
sample:
trackIndex = 0
dataHashCode = -1051506468
size = 1268
isKeyFrame = false
presentationTimeUs = 967633
sample:
trackIndex = 0
dataHashCode = -1025604144
size = 880
isKeyFrame = false
presentationTimeUs = 900900
sample:
trackIndex = 0
dataHashCode = -913586520
size = 530
isKeyFrame = false
presentationTimeUs = 867533
sample:
trackIndex = 0
dataHashCode = 1340459242
size = 568
isKeyFrame = false
presentationTimeUs = 934266
released = true
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment