Merge BaseSamplePipeline and SamplePipeline

PiperOrigin-RevId: 499469006
This commit is contained in:
kimvde 2023-01-04 14:26:45 +00:00 committed by Marc Baechinger
parent 9d431a52ef
commit e6527ec1dd
5 changed files with 108 additions and 140 deletions

View File

@ -36,7 +36,7 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.Pure;
/** Pipeline to process, re-encode and mux raw audio samples. */ /** Pipeline to process, re-encode and mux raw audio samples. */
/* package */ final class AudioTranscodingSamplePipeline extends BaseSamplePipeline { /* package */ final class AudioTranscodingSamplePipeline extends SamplePipeline {
private static final int DEFAULT_ENCODER_BITRATE = 128 * 1024; private static final int DEFAULT_ENCODER_BITRATE = 128 * 1024;

View File

@ -1,123 +0,0 @@
/*
* 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.android.exoplayer2.util.Assertions.checkStateNotNull;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.util.MimeTypes;
/* package */ abstract class BaseSamplePipeline implements SamplePipeline {
private final long streamStartPositionUs;
private final MuxerWrapper muxerWrapper;
private final @C.TrackType int trackType;
private boolean muxerWrapperTrackAdded;
public BaseSamplePipeline(
Format inputFormat, long streamStartPositionUs, MuxerWrapper muxerWrapper) {
this.streamStartPositionUs = streamStartPositionUs;
this.muxerWrapper = muxerWrapper;
trackType = MimeTypes.getTrackType(inputFormat.sampleMimeType);
}
protected static TransformationException createNoSupportedMimeTypeException(
Format requestedEncoderFormat) {
return TransformationException.createForCodec(
new IllegalArgumentException("No MIME type is supported by both encoder and muxer."),
MimeTypes.isVideo(requestedEncoderFormat.sampleMimeType),
/* isDecoder= */ false,
requestedEncoderFormat,
/* mediaCodecName= */ null,
TransformationException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED);
}
@Override
public boolean expectsDecodedData() {
return true;
}
@Override
public boolean processData() throws TransformationException {
return feedMuxer() || processDataUpToMuxer();
}
protected abstract boolean processDataUpToMuxer() throws TransformationException;
@Nullable
protected abstract Format getMuxerInputFormat() throws TransformationException;
@Nullable
protected abstract DecoderInputBuffer getMuxerInputBuffer() throws TransformationException;
protected abstract void releaseMuxerInputBuffer() throws TransformationException;
protected abstract boolean isMuxerInputEnded();
/**
* Attempts to pass encoded data to the muxer, and returns whether it may be possible to pass more
* data immediately by calling this method again.
*/
private boolean feedMuxer() throws TransformationException {
if (!muxerWrapperTrackAdded) {
@Nullable Format inputFormat = getMuxerInputFormat();
if (inputFormat == null) {
return false;
}
try {
muxerWrapper.addTrackFormat(inputFormat);
} catch (Muxer.MuxerException e) {
throw TransformationException.createForMuxer(
e, TransformationException.ERROR_CODE_MUXING_FAILED);
}
muxerWrapperTrackAdded = true;
}
if (isMuxerInputEnded()) {
muxerWrapper.endTrack(trackType);
return false;
}
@Nullable DecoderInputBuffer muxerInputBuffer = getMuxerInputBuffer();
if (muxerInputBuffer == null) {
return false;
}
long samplePresentationTimeUs = muxerInputBuffer.timeUs - streamStartPositionUs;
// TODO(b/204892224): Consider subtracting the first sample timestamp from the sample pipeline
// buffer from all samples so that they are guaranteed to start from zero in the output file.
try {
if (!muxerWrapper.writeSample(
trackType,
checkStateNotNull(muxerInputBuffer.data),
muxerInputBuffer.isKeyFrame(),
samplePresentationTimeUs)) {
return false;
}
} catch (Muxer.MuxerException e) {
throw TransformationException.createForMuxer(
e, TransformationException.ERROR_CODE_MUXING_FAILED);
}
releaseMuxerInputBuffer();
return true;
}
}

View File

@ -21,7 +21,7 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
/** Pipeline that muxes encoded samples without any transcoding or transformation. */ /** Pipeline that muxes encoded samples without any transcoding or transformation. */
/* package */ final class PassthroughSamplePipeline extends BaseSamplePipeline { /* package */ final class PassthroughSamplePipeline extends SamplePipeline {
private final DecoderInputBuffer buffer; private final DecoderInputBuffer buffer;
private final Format format; private final Format format;
@ -61,11 +61,6 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
@Override @Override
public void release() {} public void release() {}
@Override
protected boolean processDataUpToMuxer() {
return false;
}
@Override @Override
protected Format getMuxerInputFormat() { protected Format getMuxerInputFormat() {
return format; return format;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021 The Android Open Source Project * Copyright 2022 The Android Open Source Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,19 +16,120 @@
package com.google.android.exoplayer2.transformer; package com.google.android.exoplayer2.transformer;
import static com.google.android.exoplayer2.util.Assertions.checkStateNotNull;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.util.MimeTypes;
/** /**
* Pipeline for processing media data. * Pipeline for processing media data.
* *
* <p>This pipeline can be used to implement transformations of audio or video samples. * <p>This pipeline can be used to implement transformations of audio or video samples.
*/ */
/* package */ interface SamplePipeline extends SampleConsumer { /* package */ abstract class SamplePipeline implements SampleConsumer {
private final long streamStartPositionUs;
private final MuxerWrapper muxerWrapper;
private final @C.TrackType int trackType;
private boolean muxerWrapperTrackAdded;
public SamplePipeline(Format inputFormat, long streamStartPositionUs, MuxerWrapper muxerWrapper) {
this.streamStartPositionUs = streamStartPositionUs;
this.muxerWrapper = muxerWrapper;
trackType = MimeTypes.getTrackType(inputFormat.sampleMimeType);
}
protected static TransformationException createNoSupportedMimeTypeException(
Format requestedEncoderFormat) {
return TransformationException.createForCodec(
new IllegalArgumentException("No MIME type is supported by both encoder and muxer."),
MimeTypes.isVideo(requestedEncoderFormat.sampleMimeType),
/* isDecoder= */ false,
requestedEncoderFormat,
/* mediaCodecName= */ null,
TransformationException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED);
}
@Override
public boolean expectsDecodedData() {
return true;
}
/** /**
* Processes the input data and returns whether it may be possible to process more data by calling * Processes the input data and returns whether it may be possible to process more data by calling
* this method again. * this method again.
*/ */
boolean processData() throws TransformationException; public final boolean processData() throws TransformationException {
return feedMuxer() || processDataUpToMuxer();
}
/** Releases all resources held by the pipeline. */ /** Releases all resources held by the pipeline. */
void release(); public abstract void release();
protected boolean processDataUpToMuxer() throws TransformationException {
return false;
}
@Nullable
protected abstract Format getMuxerInputFormat() throws TransformationException;
@Nullable
protected abstract DecoderInputBuffer getMuxerInputBuffer() throws TransformationException;
protected abstract void releaseMuxerInputBuffer() throws TransformationException;
protected abstract boolean isMuxerInputEnded();
/**
* Attempts to pass encoded data to the muxer, and returns whether it may be possible to pass more
* data immediately by calling this method again.
*/
private boolean feedMuxer() throws TransformationException {
if (!muxerWrapperTrackAdded) {
@Nullable Format inputFormat = getMuxerInputFormat();
if (inputFormat == null) {
return false;
}
try {
muxerWrapper.addTrackFormat(inputFormat);
} catch (Muxer.MuxerException e) {
throw TransformationException.createForMuxer(
e, TransformationException.ERROR_CODE_MUXING_FAILED);
}
muxerWrapperTrackAdded = true;
}
if (isMuxerInputEnded()) {
muxerWrapper.endTrack(trackType);
return false;
}
@Nullable DecoderInputBuffer muxerInputBuffer = getMuxerInputBuffer();
if (muxerInputBuffer == null) {
return false;
}
long samplePresentationTimeUs = muxerInputBuffer.timeUs - streamStartPositionUs;
// TODO(b/204892224): Consider subtracting the first sample timestamp from the sample pipeline
// buffer from all samples so that they are guaranteed to start from zero in the output file.
try {
if (!muxerWrapper.writeSample(
trackType,
checkStateNotNull(muxerInputBuffer.data),
muxerInputBuffer.isKeyFrame(),
samplePresentationTimeUs)) {
return false;
}
} catch (Muxer.MuxerException e) {
throw TransformationException.createForMuxer(
e, TransformationException.ERROR_CODE_MUXING_FAILED);
}
releaseMuxerInputBuffer();
return true;
}
} }

View File

@ -54,7 +54,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.Pure;
/** Pipeline to process, re-encode and mux raw video frames. */ /** Pipeline to process, re-encode and mux raw video frames. */
/* package */ final class VideoTranscodingSamplePipeline extends BaseSamplePipeline { /* package */ final class VideoTranscodingSamplePipeline extends SamplePipeline {
private final FrameProcessor frameProcessor; private final FrameProcessor frameProcessor;
private final ColorInfo frameProcessorInputColor; private final ColorInfo frameProcessorInputColor;
@ -257,11 +257,6 @@ import org.checkerframework.dataflow.qual.Pure;
encoderWrapper.release(); encoderWrapper.release();
} }
@Override
protected boolean processDataUpToMuxer() {
return false;
}
@Override @Override
@Nullable @Nullable
protected Format getMuxerInputFormat() throws TransformationException { protected Format getMuxerInputFormat() throws TransformationException {