Add release reason argument in the MuxerWrapper.release() method
Also called `muxer.release()` in other tests where it is appropriate. PiperOrigin-RevId: 609736956
This commit is contained in:
parent
68a78b9218
commit
284d17cb13
@ -42,4 +42,4 @@ sample:
|
|||||||
size = 4
|
size = 4
|
||||||
isKeyFrame = true
|
isKeyFrame = true
|
||||||
presentationTimeUs = 15
|
presentationTimeUs = 15
|
||||||
released = false
|
released = true
|
||||||
|
@ -78,6 +78,26 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
/** Used for appending the remaining samples with the previously muxed partial file. */
|
/** Used for appending the remaining samples with the previously muxed partial file. */
|
||||||
public static final int MUXER_MODE_APPEND = 2;
|
public static final int MUXER_MODE_APPEND = 2;
|
||||||
|
|
||||||
|
/** Represents a reason for which the muxer is released. */
|
||||||
|
@Documented
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
@Target(TYPE_USE)
|
||||||
|
@IntDef({
|
||||||
|
MUXER_RELEASE_REASON_COMPLETED,
|
||||||
|
MUXER_RELEASE_REASON_CANCELLED,
|
||||||
|
MUXER_RELEASE_REASON_ERROR
|
||||||
|
})
|
||||||
|
public @interface MuxerReleaseReason {}
|
||||||
|
|
||||||
|
/** Muxer is released after the export completed successfully. */
|
||||||
|
public static final int MUXER_RELEASE_REASON_COMPLETED = 0;
|
||||||
|
|
||||||
|
/** Muxer is released after the export was cancelled. */
|
||||||
|
public static final int MUXER_RELEASE_REASON_CANCELLED = 1;
|
||||||
|
|
||||||
|
/** Muxer is released after an error occurred during the export. */
|
||||||
|
public static final int MUXER_RELEASE_REASON_ERROR = 2;
|
||||||
|
|
||||||
private static final String TIMER_THREAD_NAME = "Muxer:Timer";
|
private static final String TIMER_THREAD_NAME = "Muxer:Timer";
|
||||||
private static final String MUXER_TIMEOUT_ERROR_FORMAT_STRING =
|
private static final String MUXER_TIMEOUT_ERROR_FORMAT_STRING =
|
||||||
"Abort: no output sample written in the last %d milliseconds. DebugTrace: %s";
|
"Abort: no output sample written in the last %d milliseconds. DebugTrace: %s";
|
||||||
@ -515,19 +535,21 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
* mode} to {@link #MUXER_MODE_APPEND}. In all other modes the {@link MuxerWrapper} cannot be used
|
* mode} to {@link #MUXER_MODE_APPEND}. In all other modes the {@link MuxerWrapper} cannot be used
|
||||||
* anymore once this method has been called.
|
* anymore once this method has been called.
|
||||||
*
|
*
|
||||||
* @param forCancellation Whether the reason for releasing the resources is the transformation
|
* <p>The resources are always released when the {@code releaseReason} is {@link
|
||||||
* cancellation.
|
* #MUXER_RELEASE_REASON_CANCELLED} or {@link #MUXER_RELEASE_REASON_ERROR}.
|
||||||
|
*
|
||||||
|
* @param releaseReason The reason to release the muxer.
|
||||||
* @throws Muxer.MuxerException If the underlying {@link Muxer} fails to finish writing the output
|
* @throws Muxer.MuxerException If the underlying {@link Muxer} fails to finish writing the output
|
||||||
* and {@code forCancellation} is false.
|
* and the {@code releaseReason} is not {@link #MUXER_RELEASE_REASON_CANCELLED}.
|
||||||
*/
|
*/
|
||||||
public void release(boolean forCancellation) throws Muxer.MuxerException {
|
public void release(@MuxerReleaseReason int releaseReason) throws Muxer.MuxerException {
|
||||||
if (muxerMode == MUXER_MODE_MUX_PARTIAL && !forCancellation) {
|
if (releaseReason == MUXER_RELEASE_REASON_COMPLETED && muxerMode == MUXER_MODE_MUX_PARTIAL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
isReady = false;
|
isReady = false;
|
||||||
abortScheduledExecutorService.shutdownNow();
|
abortScheduledExecutorService.shutdownNow();
|
||||||
if (muxer != null) {
|
if (muxer != null) {
|
||||||
muxer.release(forCancellation);
|
muxer.release(releaseReason == MUXER_RELEASE_REASON_CANCELLED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,9 @@ import static androidx.media3.transformer.Composition.HDR_MODE_TONE_MAP_HDR_TO_S
|
|||||||
import static androidx.media3.transformer.ExoAssetLoaderVideoRenderer.getDecoderOutputColor;
|
import static androidx.media3.transformer.ExoAssetLoaderVideoRenderer.getDecoderOutputColor;
|
||||||
import static androidx.media3.transformer.ExportException.ERROR_CODE_FAILED_RUNTIME_CHECK;
|
import static androidx.media3.transformer.ExportException.ERROR_CODE_FAILED_RUNTIME_CHECK;
|
||||||
import static androidx.media3.transformer.ExportException.ERROR_CODE_MUXING_FAILED;
|
import static androidx.media3.transformer.ExportException.ERROR_CODE_MUXING_FAILED;
|
||||||
|
import static androidx.media3.transformer.MuxerWrapper.MUXER_RELEASE_REASON_CANCELLED;
|
||||||
|
import static androidx.media3.transformer.MuxerWrapper.MUXER_RELEASE_REASON_COMPLETED;
|
||||||
|
import static androidx.media3.transformer.MuxerWrapper.MUXER_RELEASE_REASON_ERROR;
|
||||||
import static androidx.media3.transformer.Transformer.PROGRESS_STATE_AVAILABLE;
|
import static androidx.media3.transformer.Transformer.PROGRESS_STATE_AVAILABLE;
|
||||||
import static androidx.media3.transformer.Transformer.PROGRESS_STATE_NOT_STARTED;
|
import static androidx.media3.transformer.Transformer.PROGRESS_STATE_NOT_STARTED;
|
||||||
import static androidx.media3.transformer.TransformerUtil.getProcessedTrackType;
|
import static androidx.media3.transformer.TransformerUtil.getProcessedTrackType;
|
||||||
@ -403,7 +406,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
muxerWrapper.release(forCancellation);
|
muxerWrapper.release(getMuxerReleaseReason(endReason));
|
||||||
} catch (Muxer.MuxerException e) {
|
} catch (Muxer.MuxerException e) {
|
||||||
if (releaseExportException == null) {
|
if (releaseExportException == null) {
|
||||||
releaseExportException = ExportException.createForMuxer(e, ERROR_CODE_MUXING_FAILED);
|
releaseExportException = ExportException.createForMuxer(e, ERROR_CODE_MUXING_FAILED);
|
||||||
@ -461,6 +464,18 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private @MuxerWrapper.MuxerReleaseReason int getMuxerReleaseReason(
|
||||||
|
@EndReason int exportEndReason) {
|
||||||
|
if (exportEndReason == END_REASON_COMPLETED) {
|
||||||
|
return MUXER_RELEASE_REASON_COMPLETED;
|
||||||
|
} else if (exportEndReason == END_REASON_CANCELLED) {
|
||||||
|
return MUXER_RELEASE_REASON_CANCELLED;
|
||||||
|
} else if (exportEndReason == END_REASON_ERROR) {
|
||||||
|
return MUXER_RELEASE_REASON_ERROR;
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Unexpected end reason " + exportEndReason);
|
||||||
|
}
|
||||||
|
|
||||||
private void updateProgressInternal() {
|
private void updateProgressInternal() {
|
||||||
if (released) {
|
if (released) {
|
||||||
return;
|
return;
|
||||||
|
@ -69,7 +69,8 @@ public class MuxerWrapperTest {
|
|||||||
@After
|
@After
|
||||||
public void tearDown() throws Muxer.MuxerException {
|
public void tearDown() throws Muxer.MuxerException {
|
||||||
if (muxerWrapper != null) {
|
if (muxerWrapper != null) {
|
||||||
muxerWrapper.release(/* forCancellation= */ false);
|
// Release with reason cancellation so that underlying resources are always released.
|
||||||
|
muxerWrapper.release(MuxerWrapper.MUXER_RELEASE_REASON_CANCELLED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,6 +137,7 @@ public class MuxerWrapperTest {
|
|||||||
muxerWrapper.writeSample(
|
muxerWrapper.writeSample(
|
||||||
C.TRACK_TYPE_VIDEO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
|
C.TRACK_TYPE_VIDEO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
|
||||||
muxerWrapper.endTrack(C.TRACK_TYPE_VIDEO);
|
muxerWrapper.endTrack(C.TRACK_TYPE_VIDEO);
|
||||||
|
muxerWrapper.release(MuxerWrapper.MUXER_RELEASE_REASON_COMPLETED);
|
||||||
muxerWrapper.changeToAppendMode();
|
muxerWrapper.changeToAppendMode();
|
||||||
muxerWrapper.setTrackCount(1);
|
muxerWrapper.setTrackCount(1);
|
||||||
|
|
||||||
@ -156,6 +158,7 @@ public class MuxerWrapperTest {
|
|||||||
muxerWrapper.writeSample(
|
muxerWrapper.writeSample(
|
||||||
C.TRACK_TYPE_AUDIO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
|
C.TRACK_TYPE_AUDIO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
|
||||||
muxerWrapper.endTrack(C.TRACK_TYPE_AUDIO);
|
muxerWrapper.endTrack(C.TRACK_TYPE_AUDIO);
|
||||||
|
muxerWrapper.release(MuxerWrapper.MUXER_RELEASE_REASON_COMPLETED);
|
||||||
muxerWrapper.changeToAppendMode();
|
muxerWrapper.changeToAppendMode();
|
||||||
muxerWrapper.setTrackCount(1);
|
muxerWrapper.setTrackCount(1);
|
||||||
|
|
||||||
@ -176,6 +179,7 @@ public class MuxerWrapperTest {
|
|||||||
muxerWrapper.writeSample(
|
muxerWrapper.writeSample(
|
||||||
C.TRACK_TYPE_VIDEO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
|
C.TRACK_TYPE_VIDEO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
|
||||||
muxerWrapper.endTrack(C.TRACK_TYPE_VIDEO);
|
muxerWrapper.endTrack(C.TRACK_TYPE_VIDEO);
|
||||||
|
muxerWrapper.release(MuxerWrapper.MUXER_RELEASE_REASON_COMPLETED);
|
||||||
muxerWrapper.changeToAppendMode();
|
muxerWrapper.changeToAppendMode();
|
||||||
muxerWrapper.setTrackCount(1);
|
muxerWrapper.setTrackCount(1);
|
||||||
Format differentVideoFormat = FAKE_VIDEO_TRACK_FORMAT.buildUpon().setHeight(5000).build();
|
Format differentVideoFormat = FAKE_VIDEO_TRACK_FORMAT.buildUpon().setHeight(5000).build();
|
||||||
@ -198,6 +202,7 @@ public class MuxerWrapperTest {
|
|||||||
muxerWrapper.writeSample(
|
muxerWrapper.writeSample(
|
||||||
C.TRACK_TYPE_AUDIO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
|
C.TRACK_TYPE_AUDIO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
|
||||||
muxerWrapper.endTrack(C.TRACK_TYPE_AUDIO);
|
muxerWrapper.endTrack(C.TRACK_TYPE_AUDIO);
|
||||||
|
muxerWrapper.release(MuxerWrapper.MUXER_RELEASE_REASON_COMPLETED);
|
||||||
muxerWrapper.changeToAppendMode();
|
muxerWrapper.changeToAppendMode();
|
||||||
muxerWrapper.setTrackCount(1);
|
muxerWrapper.setTrackCount(1);
|
||||||
Format differentAudioFormat = FAKE_AUDIO_TRACK_FORMAT.buildUpon().setSampleRate(48000).build();
|
Format differentAudioFormat = FAKE_AUDIO_TRACK_FORMAT.buildUpon().setSampleRate(48000).build();
|
||||||
@ -264,6 +269,8 @@ public class MuxerWrapperTest {
|
|||||||
C.TRACK_TYPE_AUDIO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 17);
|
C.TRACK_TYPE_AUDIO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 17);
|
||||||
muxerWrapper.endTrack(C.TRACK_TYPE_AUDIO);
|
muxerWrapper.endTrack(C.TRACK_TYPE_AUDIO);
|
||||||
muxerWrapper.endTrack(C.TRACK_TYPE_VIDEO);
|
muxerWrapper.endTrack(C.TRACK_TYPE_VIDEO);
|
||||||
|
muxerWrapper.release(MuxerWrapper.MUXER_RELEASE_REASON_COMPLETED);
|
||||||
|
muxerWrapper = null;
|
||||||
|
|
||||||
DumpFileAsserts.assertOutput(
|
DumpFileAsserts.assertOutput(
|
||||||
context,
|
context,
|
||||||
@ -285,8 +292,10 @@ public class MuxerWrapperTest {
|
|||||||
muxerWrapper.writeSample(
|
muxerWrapper.writeSample(
|
||||||
C.TRACK_TYPE_VIDEO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
|
C.TRACK_TYPE_VIDEO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
|
||||||
muxerWrapper.endTrack(C.TRACK_TYPE_VIDEO);
|
muxerWrapper.endTrack(C.TRACK_TYPE_VIDEO);
|
||||||
|
muxerWrapper.release(MuxerWrapper.MUXER_RELEASE_REASON_COMPLETED);
|
||||||
|
|
||||||
assertThat(muxerWrapper.isEnded()).isTrue();
|
assertThat(muxerWrapper.isEnded()).isTrue();
|
||||||
|
muxerWrapper = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -311,8 +320,10 @@ public class MuxerWrapperTest {
|
|||||||
muxerWrapper.writeSample(
|
muxerWrapper.writeSample(
|
||||||
C.TRACK_TYPE_AUDIO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
|
C.TRACK_TYPE_AUDIO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
|
||||||
muxerWrapper.endTrack(C.TRACK_TYPE_AUDIO);
|
muxerWrapper.endTrack(C.TRACK_TYPE_AUDIO);
|
||||||
|
muxerWrapper.release(MuxerWrapper.MUXER_RELEASE_REASON_COMPLETED);
|
||||||
|
|
||||||
assertThat(muxerWrapper.isEnded()).isTrue();
|
assertThat(muxerWrapper.isEnded()).isTrue();
|
||||||
|
muxerWrapper = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -329,6 +340,7 @@ public class MuxerWrapperTest {
|
|||||||
muxerWrapper.writeSample(
|
muxerWrapper.writeSample(
|
||||||
C.TRACK_TYPE_VIDEO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
|
C.TRACK_TYPE_VIDEO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
|
||||||
muxerWrapper.endTrack(C.TRACK_TYPE_VIDEO);
|
muxerWrapper.endTrack(C.TRACK_TYPE_VIDEO);
|
||||||
|
muxerWrapper.release(MuxerWrapper.MUXER_RELEASE_REASON_COMPLETED);
|
||||||
muxerWrapper.changeToAppendMode();
|
muxerWrapper.changeToAppendMode();
|
||||||
muxerWrapper.setTrackCount(1);
|
muxerWrapper.setTrackCount(1);
|
||||||
muxerWrapper.addTrackFormat(FAKE_VIDEO_TRACK_FORMAT);
|
muxerWrapper.addTrackFormat(FAKE_VIDEO_TRACK_FORMAT);
|
||||||
@ -437,6 +449,80 @@ public class MuxerWrapperTest {
|
|||||||
assertThat(MuxerWrapper.isInitializationDataCompatible(existingFormat, otherFormat)).isFalse();
|
assertThat(MuxerWrapper.isInitializationDataCompatible(existingFormat, otherFormat)).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void release_withReasonCompletedInMuxPartialMode_doesNotReleaseResources()
|
||||||
|
throws Exception {
|
||||||
|
muxerWrapper =
|
||||||
|
new MuxerWrapper(
|
||||||
|
temporaryFolder.newFile().getPath(),
|
||||||
|
new DefaultMuxer.Factory(),
|
||||||
|
new NoOpMuxerListenerImpl(),
|
||||||
|
MUXER_MODE_MUX_PARTIAL,
|
||||||
|
/* dropSamplesBeforeFirstVideoSample= */ false);
|
||||||
|
muxerWrapper.setTrackCount(1);
|
||||||
|
muxerWrapper.addTrackFormat(FAKE_VIDEO_TRACK_FORMAT);
|
||||||
|
muxerWrapper.writeSample(
|
||||||
|
C.TRACK_TYPE_VIDEO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
|
||||||
|
|
||||||
|
muxerWrapper.release(MuxerWrapper.MUXER_RELEASE_REASON_COMPLETED);
|
||||||
|
|
||||||
|
// Resources are not released and samples can be written in the append mode.
|
||||||
|
muxerWrapper.changeToAppendMode();
|
||||||
|
boolean sampleWritten =
|
||||||
|
muxerWrapper.writeSample(
|
||||||
|
C.TRACK_TYPE_VIDEO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 100);
|
||||||
|
assertThat(sampleWritten).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void release_withReleaseReasonCancelledInMuxPartialMode_releasesResources()
|
||||||
|
throws Exception {
|
||||||
|
muxerWrapper =
|
||||||
|
new MuxerWrapper(
|
||||||
|
temporaryFolder.newFile().getPath(),
|
||||||
|
new DefaultMuxer.Factory(),
|
||||||
|
new NoOpMuxerListenerImpl(),
|
||||||
|
MUXER_MODE_MUX_PARTIAL,
|
||||||
|
/* dropSamplesBeforeFirstVideoSample= */ false);
|
||||||
|
muxerWrapper.setTrackCount(1);
|
||||||
|
muxerWrapper.addTrackFormat(FAKE_VIDEO_TRACK_FORMAT);
|
||||||
|
muxerWrapper.writeSample(
|
||||||
|
C.TRACK_TYPE_VIDEO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
|
||||||
|
|
||||||
|
muxerWrapper.release(MuxerWrapper.MUXER_RELEASE_REASON_CANCELLED);
|
||||||
|
|
||||||
|
// Resources are released and samples can not be written in the append mode.
|
||||||
|
muxerWrapper.changeToAppendMode();
|
||||||
|
boolean sampleWritten =
|
||||||
|
muxerWrapper.writeSample(
|
||||||
|
C.TRACK_TYPE_VIDEO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 100);
|
||||||
|
assertThat(sampleWritten).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void release_withReleaseReasonErrorInMuxPartialMode_releasesResources() throws Exception {
|
||||||
|
muxerWrapper =
|
||||||
|
new MuxerWrapper(
|
||||||
|
temporaryFolder.newFile().getPath(),
|
||||||
|
new DefaultMuxer.Factory(),
|
||||||
|
new NoOpMuxerListenerImpl(),
|
||||||
|
MUXER_MODE_MUX_PARTIAL,
|
||||||
|
/* dropSamplesBeforeFirstVideoSample= */ false);
|
||||||
|
muxerWrapper.setTrackCount(1);
|
||||||
|
muxerWrapper.addTrackFormat(FAKE_VIDEO_TRACK_FORMAT);
|
||||||
|
muxerWrapper.writeSample(
|
||||||
|
C.TRACK_TYPE_VIDEO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
|
||||||
|
|
||||||
|
muxerWrapper.release(MuxerWrapper.MUXER_RELEASE_REASON_ERROR);
|
||||||
|
|
||||||
|
// Resources are released and samples can not be written in the append mode.
|
||||||
|
muxerWrapper.changeToAppendMode();
|
||||||
|
boolean sampleWritten =
|
||||||
|
muxerWrapper.writeSample(
|
||||||
|
C.TRACK_TYPE_VIDEO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 100);
|
||||||
|
assertThat(sampleWritten).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
private static final class NoOpMuxerListenerImpl implements MuxerWrapper.Listener {
|
private static final class NoOpMuxerListenerImpl implements MuxerWrapper.Listener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
x
Reference in New Issue
Block a user