mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Allow forcing duration in FrameworkMuxer.
PiperOrigin-RevId: 501865706
This commit is contained in:
parent
492dfeb0c7
commit
a82fcdefcb
@ -39,16 +39,27 @@ public final class DefaultMuxer implements Muxer {
|
|||||||
* set to {@link #DEFAULT_MAX_DELAY_BETWEEN_SAMPLES_MS}.
|
* set to {@link #DEFAULT_MAX_DELAY_BETWEEN_SAMPLES_MS}.
|
||||||
*/
|
*/
|
||||||
public Factory() {
|
public Factory() {
|
||||||
this.muxerFactory = new FrameworkMuxer.Factory(DEFAULT_MAX_DELAY_BETWEEN_SAMPLES_MS);
|
this(/* maxDelayBetweenSamplesMs= */ DEFAULT_MAX_DELAY_BETWEEN_SAMPLES_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an instance.
|
* Creates an instance.
|
||||||
*
|
*
|
||||||
* @param maxDelayBetweenSamplesMs See {@link Muxer#getMaxDelayBetweenSamplesMs()}.
|
* @param maxDelayBetweenSamplesMs See {@link Muxer#getMaxDelayBetweenSamplesMs()}.
|
||||||
*/
|
*/
|
||||||
public Factory(long maxDelayBetweenSamplesMs) {
|
public Factory(long maxDelayBetweenSamplesMs) {
|
||||||
this.muxerFactory = new FrameworkMuxer.Factory(maxDelayBetweenSamplesMs);
|
this(maxDelayBetweenSamplesMs, /* videoDurationMs= */ C.TIME_UNSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance.
|
||||||
|
*
|
||||||
|
* @param maxDelayBetweenSamplesMs See {@link Muxer#getMaxDelayBetweenSamplesMs()}.
|
||||||
|
* @param videoDurationMs The duration of the video track (in milliseconds) to enforce in the
|
||||||
|
* output, or {@link C#TIME_UNSET} to not enforce. Only applicable when a video track is
|
||||||
|
* {@linkplain #addTrack(Format) added}.
|
||||||
|
*/
|
||||||
|
public Factory(long maxDelayBetweenSamplesMs, long videoDurationMs) {
|
||||||
|
this.muxerFactory = new FrameworkMuxer.Factory(maxDelayBetweenSamplesMs, videoDurationMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -57,9 +57,11 @@ import java.nio.ByteBuffer;
|
|||||||
public static final class Factory implements Muxer.Factory {
|
public static final class Factory implements Muxer.Factory {
|
||||||
|
|
||||||
private final long maxDelayBetweenSamplesMs;
|
private final long maxDelayBetweenSamplesMs;
|
||||||
|
private final long videoDurationMs;
|
||||||
|
|
||||||
public Factory(long maxDelayBetweenSamplesMs) {
|
public Factory(long maxDelayBetweenSamplesMs, long videoDurationMs) {
|
||||||
this.maxDelayBetweenSamplesMs = maxDelayBetweenSamplesMs;
|
this.maxDelayBetweenSamplesMs = maxDelayBetweenSamplesMs;
|
||||||
|
this.videoDurationMs = videoDurationMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -70,7 +72,7 @@ import java.nio.ByteBuffer;
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new MuxerException("Error creating muxer", e);
|
throw new MuxerException("Error creating muxer", e);
|
||||||
}
|
}
|
||||||
return new FrameworkMuxer(mediaMuxer, maxDelayBetweenSamplesMs);
|
return new FrameworkMuxer(mediaMuxer, maxDelayBetweenSamplesMs, videoDurationMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(26)
|
@RequiresApi(26)
|
||||||
@ -85,7 +87,7 @@ import java.nio.ByteBuffer;
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new MuxerException("Error creating muxer", e);
|
throw new MuxerException("Error creating muxer", e);
|
||||||
}
|
}
|
||||||
return new FrameworkMuxer(mediaMuxer, maxDelayBetweenSamplesMs);
|
return new FrameworkMuxer(mediaMuxer, maxDelayBetweenSamplesMs, videoDurationMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -101,29 +103,31 @@ import java.nio.ByteBuffer;
|
|||||||
|
|
||||||
private final MediaMuxer mediaMuxer;
|
private final MediaMuxer mediaMuxer;
|
||||||
private final long maxDelayBetweenSamplesMs;
|
private final long maxDelayBetweenSamplesMs;
|
||||||
|
private final long videoDurationUs;
|
||||||
private final MediaCodec.BufferInfo bufferInfo;
|
private final MediaCodec.BufferInfo bufferInfo;
|
||||||
private final SparseLongArray trackIndexToLastPresentationTimeUs;
|
private final SparseLongArray trackIndexToLastPresentationTimeUs;
|
||||||
|
|
||||||
|
private int videoTrackIndex;
|
||||||
|
|
||||||
private boolean isStarted;
|
private boolean isStarted;
|
||||||
|
|
||||||
private FrameworkMuxer(MediaMuxer mediaMuxer, long maxDelayBetweenSamplesMs) {
|
private FrameworkMuxer(
|
||||||
|
MediaMuxer mediaMuxer, long maxDelayBetweenSamplesMs, long videoDurationMs) {
|
||||||
this.mediaMuxer = mediaMuxer;
|
this.mediaMuxer = mediaMuxer;
|
||||||
this.maxDelayBetweenSamplesMs = maxDelayBetweenSamplesMs;
|
this.maxDelayBetweenSamplesMs = maxDelayBetweenSamplesMs;
|
||||||
|
this.videoDurationUs = Util.msToUs(videoDurationMs);
|
||||||
bufferInfo = new MediaCodec.BufferInfo();
|
bufferInfo = new MediaCodec.BufferInfo();
|
||||||
trackIndexToLastPresentationTimeUs = new SparseLongArray();
|
trackIndexToLastPresentationTimeUs = new SparseLongArray();
|
||||||
|
videoTrackIndex = C.INDEX_UNSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int addTrack(Format format) throws MuxerException {
|
public int addTrack(Format format) throws MuxerException {
|
||||||
String sampleMimeType = checkNotNull(format.sampleMimeType);
|
String sampleMimeType = checkNotNull(format.sampleMimeType);
|
||||||
MediaFormat mediaFormat;
|
MediaFormat mediaFormat;
|
||||||
if (MimeTypes.isAudio(sampleMimeType)) {
|
boolean isVideo = MimeTypes.isVideo(sampleMimeType);
|
||||||
mediaFormat =
|
if (isVideo) {
|
||||||
MediaFormat.createAudioFormat(
|
mediaFormat = MediaFormat.createVideoFormat(sampleMimeType, format.width, format.height);
|
||||||
castNonNull(sampleMimeType), format.sampleRate, format.channelCount);
|
|
||||||
} else {
|
|
||||||
mediaFormat =
|
|
||||||
MediaFormat.createVideoFormat(castNonNull(sampleMimeType), format.width, format.height);
|
|
||||||
MediaFormatUtil.maybeSetColorInfo(mediaFormat, format.colorInfo);
|
MediaFormatUtil.maybeSetColorInfo(mediaFormat, format.colorInfo);
|
||||||
try {
|
try {
|
||||||
mediaMuxer.setOrientationHint(format.rotationDegrees);
|
mediaMuxer.setOrientationHint(format.rotationDegrees);
|
||||||
@ -131,6 +135,9 @@ import java.nio.ByteBuffer;
|
|||||||
throw new MuxerException(
|
throw new MuxerException(
|
||||||
"Failed to set orientation hint with rotationDegrees=" + format.rotationDegrees, e);
|
"Failed to set orientation hint with rotationDegrees=" + format.rotationDegrees, e);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
mediaFormat =
|
||||||
|
MediaFormat.createAudioFormat(sampleMimeType, format.sampleRate, format.channelCount);
|
||||||
}
|
}
|
||||||
MediaFormatUtil.setCsdBuffers(mediaFormat, format.initializationData);
|
MediaFormatUtil.setCsdBuffers(mediaFormat, format.initializationData);
|
||||||
int trackIndex;
|
int trackIndex;
|
||||||
@ -139,6 +146,11 @@ import java.nio.ByteBuffer;
|
|||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
throw new MuxerException("Failed to add track with format=" + format, e);
|
throw new MuxerException("Failed to add track with format=" + format, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isVideo) {
|
||||||
|
videoTrackIndex = trackIndex;
|
||||||
|
}
|
||||||
|
|
||||||
return trackIndex;
|
return trackIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,6 +158,13 @@ import java.nio.ByteBuffer;
|
|||||||
public void writeSampleData(
|
public void writeSampleData(
|
||||||
int trackIndex, ByteBuffer data, long presentationTimeUs, @C.BufferFlags int flags)
|
int trackIndex, ByteBuffer data, long presentationTimeUs, @C.BufferFlags int flags)
|
||||||
throws MuxerException {
|
throws MuxerException {
|
||||||
|
|
||||||
|
if (videoDurationUs != C.TIME_UNSET
|
||||||
|
&& trackIndex == videoTrackIndex
|
||||||
|
&& presentationTimeUs > videoDurationUs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isStarted) {
|
if (!isStarted) {
|
||||||
isStarted = true;
|
isStarted = true;
|
||||||
try {
|
try {
|
||||||
@ -154,20 +173,22 @@ import java.nio.ByteBuffer;
|
|||||||
throw new MuxerException("Failed to start the muxer", e);
|
throw new MuxerException("Failed to start the muxer", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int offset = data.position();
|
int offset = data.position();
|
||||||
int size = data.limit() - offset;
|
int size = data.limit() - offset;
|
||||||
bufferInfo.set(offset, size, presentationTimeUs, flags);
|
|
||||||
|
bufferInfo.set(offset, size, presentationTimeUs, getMediaMuxerFlags(flags));
|
||||||
long lastSamplePresentationTimeUs = trackIndexToLastPresentationTimeUs.get(trackIndex);
|
long lastSamplePresentationTimeUs = trackIndexToLastPresentationTimeUs.get(trackIndex);
|
||||||
|
// writeSampleData blocks on old API versions, so check here to avoid calling the method.
|
||||||
|
checkState(
|
||||||
|
Util.SDK_INT > 24 || presentationTimeUs >= lastSamplePresentationTimeUs,
|
||||||
|
"Samples not in presentation order ("
|
||||||
|
+ presentationTimeUs
|
||||||
|
+ " < "
|
||||||
|
+ lastSamplePresentationTimeUs
|
||||||
|
+ ") unsupported on this API version");
|
||||||
|
trackIndexToLastPresentationTimeUs.put(trackIndex, presentationTimeUs);
|
||||||
try {
|
try {
|
||||||
// writeSampleData blocks on old API versions, so check here to avoid calling the method.
|
|
||||||
checkState(
|
|
||||||
Util.SDK_INT > 24 || presentationTimeUs >= lastSamplePresentationTimeUs,
|
|
||||||
"Samples not in presentation order ("
|
|
||||||
+ presentationTimeUs
|
|
||||||
+ " < "
|
|
||||||
+ lastSamplePresentationTimeUs
|
|
||||||
+ ") unsupported on this API version");
|
|
||||||
trackIndexToLastPresentationTimeUs.put(trackIndex, presentationTimeUs);
|
|
||||||
mediaMuxer.writeSampleData(trackIndex, data, bufferInfo);
|
mediaMuxer.writeSampleData(trackIndex, data, bufferInfo);
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
throw new MuxerException(
|
throw new MuxerException(
|
||||||
@ -188,6 +209,14 @@ import java.nio.ByteBuffer;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (videoDurationUs != C.TIME_UNSET && videoTrackIndex != C.INDEX_UNSET) {
|
||||||
|
writeSampleData(
|
||||||
|
videoTrackIndex,
|
||||||
|
ByteBuffer.allocateDirect(0),
|
||||||
|
videoDurationUs,
|
||||||
|
C.BUFFER_FLAG_END_OF_STREAM);
|
||||||
|
}
|
||||||
|
|
||||||
isStarted = false;
|
isStarted = false;
|
||||||
try {
|
try {
|
||||||
stopMuxer(mediaMuxer);
|
stopMuxer(mediaMuxer);
|
||||||
@ -206,6 +235,17 @@ import java.nio.ByteBuffer;
|
|||||||
return maxDelayBetweenSamplesMs;
|
return maxDelayBetweenSamplesMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int getMediaMuxerFlags(@C.BufferFlags int flags) {
|
||||||
|
int mediaMuxerFlags = 0;
|
||||||
|
if ((flags & C.BUFFER_FLAG_KEY_FRAME) == C.BUFFER_FLAG_KEY_FRAME) {
|
||||||
|
mediaMuxerFlags |= MediaCodec.BUFFER_FLAG_KEY_FRAME;
|
||||||
|
}
|
||||||
|
if ((flags & C.BUFFER_FLAG_END_OF_STREAM) == C.BUFFER_FLAG_END_OF_STREAM) {
|
||||||
|
mediaMuxerFlags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
|
||||||
|
}
|
||||||
|
return mediaMuxerFlags;
|
||||||
|
}
|
||||||
|
|
||||||
// Accesses MediaMuxer state via reflection to ensure that muxer resources can be released even
|
// Accesses MediaMuxer state via reflection to ensure that muxer resources can be released even
|
||||||
// if stopping fails.
|
// if stopping fails.
|
||||||
@SuppressLint("PrivateApi")
|
@SuppressLint("PrivateApi")
|
||||||
|
@ -94,7 +94,7 @@ public interface Muxer {
|
|||||||
* @param data A buffer containing the sample data to write to the container.
|
* @param data A buffer containing the sample data to write to the container.
|
||||||
* @param presentationTimeUs The presentation time of the sample in microseconds.
|
* @param presentationTimeUs The presentation time of the sample in microseconds.
|
||||||
* @param flags The {@link C.BufferFlags} associated with the data. Only {@link
|
* @param flags The {@link C.BufferFlags} associated with the data. Only {@link
|
||||||
* C#BUFFER_FLAG_KEY_FRAME} is supported.
|
* C#BUFFER_FLAG_KEY_FRAME} and {@link C#BUFFER_FLAG_END_OF_STREAM} are supported.
|
||||||
* @throws MuxerException If the muxer fails to write the sample.
|
* @throws MuxerException If the muxer fails to write the sample.
|
||||||
*/
|
*/
|
||||||
void writeSampleData(
|
void writeSampleData(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user