Skip to content

Commit

Permalink
Add release reason argument in the MuxerWrapper.release() method
Browse files Browse the repository at this point in the history
Also called `muxer.release()` in other tests where it is
appropriate.

PiperOrigin-RevId: 609736956
  • Loading branch information
SheenaChhabra authored and Copybara-Service committed Feb 23, 2024
1 parent 1ca8b76 commit 68d0fe5
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,26 @@
/** Used for appending the remaining samples with the previously muxed partial file. */
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 MUXER_TIMEOUT_ERROR_FORMAT_STRING =
"Abort: no output sample written in the last %d milliseconds. DebugTrace: %s";
Expand Down Expand Up @@ -521,19 +541,21 @@ public boolean isEnded() {
* mode} to {@link #MUXER_MODE_APPEND}. In all other modes the {@link MuxerWrapper} cannot be used
* anymore once this method has been called.
*
* @param forCancellation Whether the reason for releasing the resources is the transformation
* cancellation.
* <p>The resources are always released when the {@code releaseReason} is {@link
* #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
* and {@code forCancellation} is false.
* and the {@code releaseReason} is not {@link #MUXER_RELEASE_REASON_CANCELLED}.
*/
public void release(boolean forCancellation) throws Muxer.MuxerException {
if (muxerMode == MUXER_MODE_MUX_PARTIAL && !forCancellation) {
public void release(@MuxerReleaseReason int releaseReason) throws Muxer.MuxerException {
if (releaseReason == MUXER_RELEASE_REASON_COMPLETED && muxerMode == MUXER_MODE_MUX_PARTIAL) {
return;
}
isReady = false;
abortScheduledExecutorService.shutdownNow();
if (muxer != null) {
muxer.release(forCancellation);
muxer.release(releaseReason == MUXER_RELEASE_REASON_CANCELLED);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
import static com.google.android.exoplayer2.transformer.ExoAssetLoaderVideoRenderer.getDecoderOutputColor;
import static com.google.android.exoplayer2.transformer.ExportException.ERROR_CODE_FAILED_RUNTIME_CHECK;
import static com.google.android.exoplayer2.transformer.ExportException.ERROR_CODE_MUXING_FAILED;
import static com.google.android.exoplayer2.transformer.MuxerWrapper.MUXER_RELEASE_REASON_CANCELLED;
import static com.google.android.exoplayer2.transformer.MuxerWrapper.MUXER_RELEASE_REASON_COMPLETED;
import static com.google.android.exoplayer2.transformer.MuxerWrapper.MUXER_RELEASE_REASON_ERROR;
import static com.google.android.exoplayer2.transformer.Transformer.PROGRESS_STATE_AVAILABLE;
import static com.google.android.exoplayer2.transformer.Transformer.PROGRESS_STATE_NOT_STARTED;
import static com.google.android.exoplayer2.transformer.TransformerUtil.getProcessedTrackType;
Expand Down Expand Up @@ -404,7 +407,7 @@ private void endInternal(@EndReason int endReason, @Nullable ExportException exp
}
}
try {
muxerWrapper.release(forCancellation);
muxerWrapper.release(getMuxerReleaseReason(endReason));
} catch (Muxer.MuxerException e) {
if (releaseExportException == null) {
releaseExportException = ExportException.createForMuxer(e, ERROR_CODE_MUXING_FAILED);
Expand Down Expand Up @@ -462,6 +465,18 @@ private void endInternal(@EndReason int endReason, @Nullable ExportException exp
}
}

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() {
if (released) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ public class MuxerWrapperTest {
@After
public void tearDown() throws Muxer.MuxerException {
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);
}
}

Expand Down Expand Up @@ -136,6 +137,7 @@ public void addTrackFormat_withSameVideoFormatInAppendMode_doesNotThrow() throws
muxerWrapper.writeSample(
C.TRACK_TYPE_VIDEO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
muxerWrapper.endTrack(C.TRACK_TYPE_VIDEO);
muxerWrapper.release(MuxerWrapper.MUXER_RELEASE_REASON_COMPLETED);
muxerWrapper.changeToAppendMode();
muxerWrapper.setTrackCount(1);

Expand All @@ -156,6 +158,7 @@ public void addTrackFormat_withSameAudioFormatInAppendMode_doesNotThrow() throws
muxerWrapper.writeSample(
C.TRACK_TYPE_AUDIO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
muxerWrapper.endTrack(C.TRACK_TYPE_AUDIO);
muxerWrapper.release(MuxerWrapper.MUXER_RELEASE_REASON_COMPLETED);
muxerWrapper.changeToAppendMode();
muxerWrapper.setTrackCount(1);

Expand All @@ -176,6 +179,7 @@ public void addTrackFormat_withDifferentVideoFormatInAppendMode_throws() throws
muxerWrapper.writeSample(
C.TRACK_TYPE_VIDEO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
muxerWrapper.endTrack(C.TRACK_TYPE_VIDEO);
muxerWrapper.release(MuxerWrapper.MUXER_RELEASE_REASON_COMPLETED);
muxerWrapper.changeToAppendMode();
muxerWrapper.setTrackCount(1);
Format differentVideoFormat = FAKE_VIDEO_TRACK_FORMAT.buildUpon().setHeight(5000).build();
Expand All @@ -198,6 +202,7 @@ public void addTrackFormat_withDifferentAudioFormatInAppendMode_throws() throws
muxerWrapper.writeSample(
C.TRACK_TYPE_AUDIO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
muxerWrapper.endTrack(C.TRACK_TYPE_AUDIO);
muxerWrapper.release(MuxerWrapper.MUXER_RELEASE_REASON_COMPLETED);
muxerWrapper.changeToAppendMode();
muxerWrapper.setTrackCount(1);
Format differentAudioFormat = FAKE_AUDIO_TRACK_FORMAT.buildUpon().setSampleRate(48000).build();
Expand Down Expand Up @@ -264,6 +269,8 @@ public void addTrackFormat_withDifferentAudioFormatInAppendMode_throws() throws
C.TRACK_TYPE_AUDIO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 17);
muxerWrapper.endTrack(C.TRACK_TYPE_AUDIO);
muxerWrapper.endTrack(C.TRACK_TYPE_VIDEO);
muxerWrapper.release(MuxerWrapper.MUXER_RELEASE_REASON_COMPLETED);
muxerWrapper = null;

DumpFileAsserts.assertOutput(
context,
Expand All @@ -285,8 +292,10 @@ public void isEnded_afterPartialVideoMuxed_returnsTrue() throws Exception {
muxerWrapper.writeSample(
C.TRACK_TYPE_VIDEO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
muxerWrapper.endTrack(C.TRACK_TYPE_VIDEO);
muxerWrapper.release(MuxerWrapper.MUXER_RELEASE_REASON_COMPLETED);

assertThat(muxerWrapper.isEnded()).isTrue();
muxerWrapper = null;
}

@Test
Expand All @@ -311,8 +320,10 @@ public void isEnded_afterPartialAudioAndVideoMuxed_returnsTrue() throws Exceptio
muxerWrapper.writeSample(
C.TRACK_TYPE_AUDIO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
muxerWrapper.endTrack(C.TRACK_TYPE_AUDIO);
muxerWrapper.release(MuxerWrapper.MUXER_RELEASE_REASON_COMPLETED);

assertThat(muxerWrapper.isEnded()).isTrue();
muxerWrapper = null;
}

@Test
Expand All @@ -329,6 +340,7 @@ public void isEnded_afterEnteringAppendMode_returnsFalse() throws Exception {
muxerWrapper.writeSample(
C.TRACK_TYPE_VIDEO, FAKE_SAMPLE, /* isKeyFrame= */ true, /* presentationTimeUs= */ 0);
muxerWrapper.endTrack(C.TRACK_TYPE_VIDEO);
muxerWrapper.release(MuxerWrapper.MUXER_RELEASE_REASON_COMPLETED);
muxerWrapper.changeToAppendMode();
muxerWrapper.setTrackCount(1);
muxerWrapper.addTrackFormat(FAKE_VIDEO_TRACK_FORMAT);
Expand Down Expand Up @@ -437,6 +449,80 @@ public void isInitializationDataCompatible_h264_missingMimeType_returnsFalse() {
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 {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@ sample:
size = 4
isKeyFrame = true
presentationTimeUs = 15
released = false
released = true

0 comments on commit 68d0fe5

Please sign in to comment.