Merge BaseSamplePipeline and SamplePipeline
PiperOrigin-RevId: 499469006
This commit is contained in:
parent
9d431a52ef
commit
e6527ec1dd
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user