Skip to content

Commit

Permalink
Generate silent audio if no audio track is available.
Browse files Browse the repository at this point in the history
To always generate silent audio, `removeAudio(true)` can be used in conjunction.

PiperOrigin-RevId: 502814315
  • Loading branch information
Samrobbo authored and christosts committed Jan 18, 2023
1 parent 6b6e499 commit 76af427
Show file tree
Hide file tree
Showing 9 changed files with 575 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
public static final String SHOULD_REMOVE_AUDIO = "should_remove_audio";
public static final String SHOULD_REMOVE_VIDEO = "should_remove_video";
public static final String SHOULD_FLATTEN_FOR_SLOW_MOTION = "should_flatten_for_slow_motion";
public static final String FORCE_SILENT_AUDIO = "force_silent_audio";
public static final String GENERATE_SILENT_AUDIO = "generate_silent_audio";
public static final String AUDIO_MIME_TYPE = "audio_mime_type";
public static final String VIDEO_MIME_TYPE = "video_mime_type";
public static final String RESOLUTION_HEIGHT = "resolution_height";
Expand Down Expand Up @@ -210,7 +210,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
private @MonotonicNonNull CheckBox removeAudioCheckbox;
private @MonotonicNonNull CheckBox removeVideoCheckbox;
private @MonotonicNonNull CheckBox flattenForSlowMotionCheckbox;
private @MonotonicNonNull CheckBox forceSilentAudioCheckbox;
private @MonotonicNonNull CheckBox generateSilentAudioCheckbox;
private @MonotonicNonNull Spinner audioMimeSpinner;
private @MonotonicNonNull Spinner videoMimeSpinner;
private @MonotonicNonNull Spinner resolutionHeightSpinner;
Expand Down Expand Up @@ -271,7 +271,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {

flattenForSlowMotionCheckbox = findViewById(R.id.flatten_for_slow_motion_checkbox);

forceSilentAudioCheckbox = findViewById(R.id.force_silent_audio_checkbox);
generateSilentAudioCheckbox = findViewById(R.id.generate_silent_audio_checkbox);

ArrayAdapter<String> audioMimeAdapter =
new ArrayAdapter<>(/* context= */ this, R.layout.spinner_item);
Expand Down Expand Up @@ -382,7 +382,7 @@ protected void onNewIntent(Intent intent) {
"removeAudioCheckbox",
"removeVideoCheckbox",
"flattenForSlowMotionCheckbox",
"forceSilentAudioCheckbox",
"generateSilentAudioCheckbox",
"audioMimeSpinner",
"videoMimeSpinner",
"resolutionHeightSpinner",
Expand All @@ -402,7 +402,7 @@ private void startTransformation(View view) {
bundle.putBoolean(SHOULD_REMOVE_AUDIO, removeAudioCheckbox.isChecked());
bundle.putBoolean(SHOULD_REMOVE_VIDEO, removeVideoCheckbox.isChecked());
bundle.putBoolean(SHOULD_FLATTEN_FOR_SLOW_MOTION, flattenForSlowMotionCheckbox.isChecked());
bundle.putBoolean(FORCE_SILENT_AUDIO, forceSilentAudioCheckbox.isChecked());
bundle.putBoolean(GENERATE_SILENT_AUDIO, generateSilentAudioCheckbox.isChecked());
String selectedAudioMimeType = String.valueOf(audioMimeSpinner.getSelectedItem());
if (!SAME_AS_INPUT_OPTION.equals(selectedAudioMimeType)) {
bundle.putString(AUDIO_MIME_TYPE, selectedAudioMimeType);
Expand Down Expand Up @@ -738,7 +738,7 @@ private void controlTextOverlaySettings() {

@RequiresNonNull({
"removeVideoCheckbox",
"forceSilentAudioCheckbox",
"generateSilentAudioCheckbox",
"audioMimeSpinner",
"videoMimeSpinner",
"resolutionHeightSpinner",
Expand All @@ -760,7 +760,7 @@ private void onRemoveAudio(View view) {

@RequiresNonNull({
"removeAudioCheckbox",
"forceSilentAudioCheckbox",
"generateSilentAudioCheckbox",
"audioMimeSpinner",
"videoMimeSpinner",
"resolutionHeightSpinner",
Expand All @@ -781,7 +781,7 @@ private void onRemoveVideo(View view) {
}

@RequiresNonNull({
"forceSilentAudioCheckbox",
"generateSilentAudioCheckbox",
"audioMimeSpinner",
"videoMimeSpinner",
"resolutionHeightSpinner",
Expand All @@ -793,7 +793,7 @@ private void onRemoveVideo(View view) {
"selectVideoEffectsButton"
})
private void enableTrackSpecificOptions(boolean isAudioEnabled, boolean isVideoEnabled) {
forceSilentAudioCheckbox.setEnabled(isVideoEnabled);
generateSilentAudioCheckbox.setEnabled(isVideoEnabled);
audioMimeSpinner.setEnabled(isAudioEnabled);
videoMimeSpinner.setEnabled(isVideoEnabled);
resolutionHeightSpinner.setEnabled(isVideoEnabled);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,8 @@ private Transformer createTransformer(@Nullable Bundle bundle, String filePath)
transformerBuilder
.setRemoveAudio(bundle.getBoolean(ConfigurationActivity.SHOULD_REMOVE_AUDIO))
.setRemoveVideo(bundle.getBoolean(ConfigurationActivity.SHOULD_REMOVE_VIDEO))
.experimentalSetGenerateSilentAudio(
bundle.getBoolean(ConfigurationActivity.GENERATE_SILENT_AUDIO))
.setEncoderFactory(
new DefaultEncoderFactory.Builder(this.getApplicationContext())
.setEnableFallback(bundle.getBoolean(ConfigurationActivity.ENABLE_FALLBACK))
Expand All @@ -322,9 +324,6 @@ private Transformer createTransformer(@Nullable Bundle bundle, String filePath)
if (bundle.getBoolean(ConfigurationActivity.ENABLE_DEBUG_PREVIEW)) {
transformerBuilder.setDebugViewProvider(new DemoDebugViewProvider());
}

transformerBuilder.experimentalSetForceSilentAudio(
bundle.getBoolean(ConfigurationActivity.FORCE_SILENT_AUDIO));
}

return transformerBuilder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,9 @@
android:layout_weight="1">
<TextView
android:layout_gravity="center_vertical"
android:text="@string/force_silent_audio" />
android:text="@string/generate_silent_audio" />
<CheckBox
android:id="@+id/force_silent_audio_checkbox"
android:id="@+id/generate_silent_audio_checkbox"
android:layout_gravity="end" />
</TableRow>
<TableRow
Expand Down
2 changes: 1 addition & 1 deletion demos/transformer/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
<string name="permission_denied">Permission Denied</string>
<string name="hide_input_video">Hide input video</string>
<string name="show_input_video">Show input video</string>
<string name="force_silent_audio">Force silent audio</string>
<string name="generate_silent_audio">Generate silent audio</string>
<string name="overlay_alpha">Alpha</string>
<string name="overlay_uri">Uri</string>
<string name="bitmap_overlay_settings">Specify bitmap overlay settings</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,15 @@ public AudioSamplePipeline(
long streamOffsetUs,
TransformationRequest transformationRequest,
ImmutableList<AudioProcessor> audioProcessors,
long forceSilentAudioDurationUs,
long generateSilentAudioDurationUs,
Codec.EncoderFactory encoderFactory,
MuxerWrapper muxerWrapper,
FallbackListener fallbackListener)
throws TransformationException {
super(inputFormat, streamStartPositionUs, muxerWrapper);

if (forceSilentAudioDurationUs != C.TIME_UNSET) {
silentAudioGenerator = new SilentAudioGenerator(inputFormat, forceSilentAudioDurationUs);
if (generateSilentAudioDurationUs != C.TIME_UNSET) {
silentAudioGenerator = new SilentAudioGenerator(inputFormat, generateSilentAudioDurationUs);
} else {
silentAudioGenerator = null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public static final class Builder {
private ImmutableList<Effect> videoEffects;
private boolean removeAudio;
private boolean removeVideo;
private boolean forceSilentAudio;
private boolean generateSilentAudio;
private ListenerSet<Transformer.Listener> listeners;
@Nullable private AssetLoader.Factory assetLoaderFactory;
private FrameProcessor.Factory frameProcessorFactory;
Expand Down Expand Up @@ -123,7 +123,7 @@ private Builder(Transformer transformer) {
this.videoEffects = transformer.videoEffects;
this.removeAudio = transformer.removeAudio;
this.removeVideo = transformer.removeVideo;
this.forceSilentAudio = transformer.forceSilentAudio;
this.generateSilentAudio = transformer.generateSilentAudio;
this.listeners = transformer.listeners;
this.assetLoaderFactory = transformer.assetLoaderFactory;
this.frameProcessorFactory = transformer.frameProcessorFactory;
Expand Down Expand Up @@ -398,29 +398,32 @@ public Builder setDebugViewProvider(DebugViewProvider debugViewProvider) {
}

/**
* Sets whether to force silent audio for the output file, ignoring any existing audio.
* Sets whether to generate silent audio for the output file, if there is no audio available.
*
* <p>This method is experimental and may be removed or changed without warning.
*
* <p>To replace existing audio with silence, call {@link #setRemoveAudio(boolean)} as well.
*
* <p>Audio properties/format:
*
* <ul>
* <li>Duration will match duration of the input media.
* <li>Sample mime type will match {@link TransformationRequest#audioMimeType}, or {@link
* MimeTypes#AUDIO_AAC} if {@code null}.
* <li>Sample rate will be 44100hz. This can be modified by passing a {@link
* <li>Sample rate will be {@code 44100} hz. This can be modified by passing a {@link
* SonicAudioProcessor} to {@link #setAudioProcessors(List)}, using {@link
* SonicAudioProcessor#setOutputSampleRateHz(int)}.
* <li>Channel count will be 2. This can be modified by implementing a custom {@link
* <li>Channel count will be {@code 2}. This can be modified by implementing a custom {@link
* AudioProcessor} and passing it to {@link #setAudioProcessors(List)}.
* </ul>
*
* @param forceSilentAudio Whether to output silent audio for the output file.
* @param generateSilentAudio Whether to generate silent audio for the output file if there is
* no audio track.
* @return This builder.
*/
@CanIgnoreReturnValue
public Builder experimentalSetForceSilentAudio(boolean forceSilentAudio) {
this.forceSilentAudio = forceSilentAudio;
public Builder experimentalSetGenerateSilentAudio(boolean generateSilentAudio) {
this.generateSilentAudio = generateSilentAudio;
return this;
}

Expand Down Expand Up @@ -457,7 +460,7 @@ public Transformer build() {
videoEffects,
removeAudio,
removeVideo,
forceSilentAudio,
generateSilentAudio,
listeners,
assetLoaderFactory,
frameProcessorFactory,
Expand Down Expand Up @@ -577,7 +580,7 @@ default void onFallbackApplied(
private final ImmutableList<Effect> videoEffects;
private final boolean removeAudio;
private final boolean removeVideo;
private final boolean forceSilentAudio;
private final boolean generateSilentAudio;
private final ListenerSet<Transformer.Listener> listeners;
private final AssetLoader.Factory assetLoaderFactory;
private final FrameProcessor.Factory frameProcessorFactory;
Expand All @@ -596,7 +599,7 @@ private Transformer(
ImmutableList<Effect> videoEffects,
boolean removeAudio,
boolean removeVideo,
boolean forceSilentAudio,
boolean generateSilentAudio,
ListenerSet<Listener> listeners,
AssetLoader.Factory assetLoaderFactory,
FrameProcessor.Factory frameProcessorFactory,
Expand All @@ -605,18 +608,14 @@ private Transformer(
Looper looper,
DebugViewProvider debugViewProvider,
Clock clock) {
if (forceSilentAudio) {
removeAudio = true;
}
checkState(!removeVideo || !forceSilentAudio, "Silent only audio track needs a video track.");
checkState(!removeAudio || !removeVideo, "Audio and video cannot both be removed.");
this.context = context;
this.transformationRequest = transformationRequest;
this.audioProcessors = audioProcessors;
this.videoEffects = videoEffects;
this.removeAudio = removeAudio;
this.removeVideo = removeVideo;
this.forceSilentAudio = forceSilentAudio;
this.generateSilentAudio = generateSilentAudio;
this.listeners = listeners;
this.assetLoaderFactory = assetLoaderFactory;
this.frameProcessorFactory = frameProcessorFactory;
Expand Down Expand Up @@ -759,7 +758,7 @@ private void startTransformationInternal(
videoEffects,
removeAudio,
removeVideo,
forceSilentAudio,
generateSilentAudio,
assetLoaderFactory,
frameProcessorFactory,
encoderFactory,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ public interface Listener {
private final TransformationRequest transformationRequest;
private final ImmutableList<AudioProcessor> audioProcessors;
private final ImmutableList<Effect> videoEffects;
private final boolean forceSilentAudio;
private final FrameProcessor.Factory frameProcessorFactory;
private final CapturingEncoderFactory encoderFactory;
private final Listener listener;
Expand All @@ -108,6 +107,7 @@ public interface Listener {
private final ConditionVariable transformerConditionVariable;
private final TransformationResult.Builder transformationResultBuilder;

private boolean generateSilentAudio;
private boolean isDrainingPipelines;
private @Transformer.ProgressState int progressState;
private @MonotonicNonNull RuntimeException cancelException;
Expand All @@ -124,7 +124,7 @@ public TransformerInternal(
ImmutableList<Effect> videoEffects,
boolean removeAudio,
boolean removeVideo,
boolean forceSilentAudio,
boolean generateSilentAudio,
AssetLoader.Factory assetLoaderFactory,
FrameProcessor.Factory frameProcessorFactory,
Codec.EncoderFactory encoderFactory,
Expand All @@ -138,7 +138,7 @@ public TransformerInternal(
this.transformationRequest = transformationRequest;
this.audioProcessors = audioProcessors;
this.videoEffects = videoEffects;
this.forceSilentAudio = forceSilentAudio;
this.generateSilentAudio = generateSilentAudio;
this.frameProcessorFactory = frameProcessorFactory;
this.encoderFactory = new CapturingEncoderFactory(encoderFactory);
this.listener = listener;
Expand Down Expand Up @@ -373,9 +373,6 @@ public void onTrackCount(int trackCount) {
return;
}
this.trackCount.set(trackCount);
if (forceSilentAudio) {
this.trackCount.incrementAndGet();
}
}

@Override
Expand All @@ -386,6 +383,14 @@ public SampleConsumer onTrackAdded(
long streamOffsetUs)
throws TransformationException {
if (!trackAdded) {
if (generateSilentAudio) {
if (this.trackCount.get() == 1 && MimeTypes.isVideo(format.sampleMimeType)) {
this.trackCount.incrementAndGet();
} else {
generateSilentAudio = false;
}
}

// Call setTrackCount() methods here so that they are called from the same thread as the
// MuxerWrapper and FallbackListener methods called when building the sample pipelines.
muxerWrapper.setTrackCount(trackCount.get());
Expand All @@ -397,7 +402,7 @@ public SampleConsumer onTrackAdded(
getSamplePipeline(format, supportedOutputTypes, streamStartPositionUs, streamOffsetUs);
internalHandler.obtainMessage(MSG_REGISTER_SAMPLE_PIPELINE, samplePipeline).sendToTarget();

if (forceSilentAudio) {
if (generateSilentAudio) {
Format silentAudioFormat =
new Format.Builder()
.setSampleMimeType(MimeTypes.AUDIO_AAC)
Expand Down Expand Up @@ -482,7 +487,7 @@ private SamplePipeline getSamplePipeline(
streamOffsetUs,
transformationRequest,
audioProcessors,
forceSilentAudio ? durationUs : C.TIME_UNSET,
generateSilentAudio ? durationUs : C.TIME_UNSET,
encoderFactory,
muxerWrapper,
fallbackListener);
Expand Down Expand Up @@ -528,7 +533,7 @@ private boolean shouldTranscodeAudio(Format inputFormat) {
if (!audioProcessors.isEmpty()) {
return true;
}
if (forceSilentAudio) {
if (generateSilentAudio) {
return true;
}

Expand Down
Loading

0 comments on commit 76af427

Please sign in to comment.