mirror of
https://github.com/androidx/media.git
synced 2025-04-29 22:36:54 +08:00
Split InAppMuxer into InApp Mp4Muxer and FragmentedMp4Muxer
This is pre work required to remove `Muxer.java` interface from the muxer module. `Mp4Muxer` and `FragmentedMp4Muxer` will no longer implement the `Muxer` interface. PiperOrigin-RevId: 716669531
This commit is contained in:
parent
a4d9a3e096
commit
4ac4f7e2e0
@ -29,6 +29,10 @@
|
||||
by the user of the device. Apps can opt-out of contributing to platform
|
||||
diagnostics for Transformer with
|
||||
`Transformer.Builder.setUsePlatformDiagnostics(false)`.
|
||||
* Split `InAppMuxer` into `InAppMp4Muxer` and `InAppFragmentedMp4Muxer`.
|
||||
`InAppMp4Muxer` is to be used for producing a non-fragmented MP4 file,
|
||||
while `InAppFragmentedMp4Muxer` is to be used for producing a fragmented
|
||||
MP4 file.
|
||||
* Track Selection:
|
||||
* Extractors:
|
||||
* Fix handling of NAL units with lengths expressed in 1 or 2 bytes (rather
|
||||
|
@ -57,7 +57,8 @@ import androidx.media3.transformer.EditedMediaItemSequence;
|
||||
import androidx.media3.transformer.Effects;
|
||||
import androidx.media3.transformer.ExportException;
|
||||
import androidx.media3.transformer.ExportResult;
|
||||
import androidx.media3.transformer.InAppMuxer;
|
||||
import androidx.media3.transformer.InAppFragmentedMp4Muxer;
|
||||
import androidx.media3.transformer.InAppMp4Muxer;
|
||||
import androidx.media3.transformer.JsonUtil;
|
||||
import androidx.media3.transformer.Transformer;
|
||||
import androidx.media3.ui.PlayerView;
|
||||
@ -362,21 +363,20 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
|
||||
enableDebugTracingCheckBox.setOnCheckedChangeListener(
|
||||
(buttonView, isChecked) -> DebugTraceUtil.enableTracing = isChecked);
|
||||
|
||||
// Connect producing fragmented MP4 to using Media3 Muxer
|
||||
CheckBox useMedia3MuxerCheckBox =
|
||||
exportSettingsDialogView.findViewById(R.id.use_media3_muxer_checkbox);
|
||||
CheckBox produceFragmentedMp4CheckBox =
|
||||
exportSettingsDialogView.findViewById(R.id.produce_fragmented_mp4_checkbox);
|
||||
useMedia3MuxerCheckBox.setOnCheckedChangeListener(
|
||||
(buttonView, isChecked) -> {
|
||||
if (!isChecked) {
|
||||
produceFragmentedMp4CheckBox.setChecked(false);
|
||||
}
|
||||
});
|
||||
produceFragmentedMp4CheckBox.setOnCheckedChangeListener(
|
||||
CheckBox useMedia3Mp4MuxerCheckBox =
|
||||
exportSettingsDialogView.findViewById(R.id.use_media3_mp4_muxer_checkbox);
|
||||
CheckBox useMedia3FragmentedMp4MuxerCheckBox =
|
||||
exportSettingsDialogView.findViewById(R.id.use_media3_fragmented_mp4_muxer_checkbox);
|
||||
useMedia3Mp4MuxerCheckBox.setOnCheckedChangeListener(
|
||||
(buttonView, isChecked) -> {
|
||||
if (isChecked) {
|
||||
useMedia3MuxerCheckBox.setChecked(true);
|
||||
useMedia3FragmentedMp4MuxerCheckBox.setChecked(false);
|
||||
}
|
||||
});
|
||||
useMedia3FragmentedMp4MuxerCheckBox.setOnCheckedChangeListener(
|
||||
(buttonView, isChecked) -> {
|
||||
if (isChecked) {
|
||||
useMedia3Mp4MuxerCheckBox.setChecked(false);
|
||||
}
|
||||
});
|
||||
|
||||
@ -419,15 +419,15 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
|
||||
transformerBuilder.setVideoMimeType(selectedVideoMimeType);
|
||||
}
|
||||
|
||||
CheckBox useMedia3MuxerCheckBox =
|
||||
exportSettingsDialogView.findViewById(R.id.use_media3_muxer_checkbox);
|
||||
CheckBox produceFragmentedMp4CheckBox =
|
||||
exportSettingsDialogView.findViewById(R.id.produce_fragmented_mp4_checkbox);
|
||||
if (useMedia3MuxerCheckBox.isChecked()) {
|
||||
transformerBuilder.setMuxerFactory(
|
||||
new InAppMuxer.Factory.Builder()
|
||||
.setOutputFragmentedMp4(produceFragmentedMp4CheckBox.isChecked())
|
||||
.build());
|
||||
CheckBox useMedia3Mp4MuxerCheckBox =
|
||||
exportSettingsDialogView.findViewById(R.id.use_media3_mp4_muxer_checkbox);
|
||||
CheckBox useMedia3FragmentedMp4MuxerCheckBox =
|
||||
exportSettingsDialogView.findViewById(R.id.use_media3_fragmented_mp4_muxer_checkbox);
|
||||
if (useMedia3Mp4MuxerCheckBox.isChecked()) {
|
||||
transformerBuilder.setMuxerFactory(new InAppMp4Muxer.Factory());
|
||||
}
|
||||
if (useMedia3FragmentedMp4MuxerCheckBox.isChecked()) {
|
||||
transformerBuilder.setMuxerFactory(new InAppFragmentedMp4Muxer.Factory());
|
||||
}
|
||||
|
||||
transformer =
|
||||
|
@ -79,12 +79,12 @@
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
<TextView
|
||||
android:text="@string/use_media3_muxer"
|
||||
android:text="@string/use_media3_mp4_muxer"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1" />
|
||||
<CheckBox
|
||||
android:id="@+id/use_media3_muxer_checkbox"
|
||||
android:id="@+id/use_media3_mp4_muxer_checkbox"
|
||||
android:layout_gravity="end"
|
||||
android:checked="false"
|
||||
android:layout_height="wrap_content"
|
||||
@ -96,12 +96,12 @@
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
<TextView
|
||||
android:text="@string/produce_fragmented_mp4"
|
||||
android:text="@string/use_media3_fragmented_mp4_muxer"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1" />
|
||||
<CheckBox
|
||||
android:id="@+id/produce_fragmented_mp4_checkbox"
|
||||
android:id="@+id/use_media3_fragmented_mp4_muxer_checkbox"
|
||||
android:layout_gravity="end"
|
||||
android:checked="false"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -34,6 +34,6 @@
|
||||
<string name="output_audio_mime_type" translatable="false">Output audio MIME type</string>
|
||||
<string name="output_video_mime_type" translatable="false">Output video MIME type</string>
|
||||
<string name="enable_debug_tracing" translatable="false">Enable debug tracing</string>
|
||||
<string name="use_media3_muxer" translatable="false">Use Media3 muxer</string>
|
||||
<string name="produce_fragmented_mp4" translatable="false">Produce fragmented MP4</string>
|
||||
<string name="use_media3_mp4_muxer" translatable="false">Use Media3 Mp4Muxer</string>
|
||||
<string name="use_media3_fragmented_mp4_muxer" translatable="false">Use Media3 FragmentedMp4Muxer</string>
|
||||
</resources>
|
||||
|
@ -77,8 +77,8 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
||||
public static final String ENABLE_ANALYZER_MODE = "enable_analyzer_mode";
|
||||
public static final String ENABLE_DEBUG_PREVIEW = "enable_debug_preview";
|
||||
public static final String ABORT_SLOW_EXPORT = "abort_slow_export";
|
||||
public static final String USE_MEDIA3_MUXER = "use_media3_muxer";
|
||||
public static final String PRODUCE_FRAGMENTED_MP4 = "produce_fragmented_mp4";
|
||||
public static final String USE_MEDIA3_MP4_MUXER = "use_media3_mp4_muxer";
|
||||
public static final String USE_MEDIA3_FRAGMENTED_MP4_MUXER = "use_media3_fragmented_mp4_muxer";
|
||||
public static final String HDR_MODE = "hdr_mode";
|
||||
public static final String AUDIO_EFFECTS_SELECTIONS = "audio_effects_selections";
|
||||
public static final String VIDEO_EFFECTS_SELECTIONS = "video_effects_selections";
|
||||
@ -177,8 +177,8 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
||||
private CheckBox enableDebugPreviewCheckBox;
|
||||
private CheckBox enableDebugTracingCheckBox;
|
||||
private CheckBox abortSlowExportCheckBox;
|
||||
private CheckBox useMedia3Muxer;
|
||||
private CheckBox produceFragmentedMp4CheckBox;
|
||||
private CheckBox useMedia3Mp4Muxer;
|
||||
private CheckBox useMedia3FragmentedMp4Muxer;
|
||||
private Spinner hdrModeSpinner;
|
||||
private Button selectAudioEffectsButton;
|
||||
private Button selectVideoEffectsButton;
|
||||
@ -303,18 +303,18 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
||||
(buttonView, isChecked) -> DebugTraceUtil.enableTracing = isChecked);
|
||||
|
||||
abortSlowExportCheckBox = findViewById(R.id.abort_slow_export_checkbox);
|
||||
useMedia3Muxer = findViewById(R.id.use_media3_muxer_checkbox);
|
||||
produceFragmentedMp4CheckBox = findViewById(R.id.produce_fragmented_mp4_checkbox);
|
||||
useMedia3Muxer.setOnCheckedChangeListener(
|
||||
(buttonView, isChecked) -> {
|
||||
if (!isChecked) {
|
||||
produceFragmentedMp4CheckBox.setChecked(false);
|
||||
}
|
||||
});
|
||||
produceFragmentedMp4CheckBox.setOnCheckedChangeListener(
|
||||
useMedia3Mp4Muxer = findViewById(R.id.use_media3_mp4_muxer_checkbox);
|
||||
useMedia3FragmentedMp4Muxer = findViewById(R.id.use_media3_fragmented_mp4_muxer_checkbox);
|
||||
useMedia3Mp4Muxer.setOnCheckedChangeListener(
|
||||
(buttonView, isChecked) -> {
|
||||
if (isChecked) {
|
||||
useMedia3Muxer.setChecked(true);
|
||||
useMedia3FragmentedMp4Muxer.setChecked(false);
|
||||
}
|
||||
});
|
||||
useMedia3FragmentedMp4Muxer.setOnCheckedChangeListener(
|
||||
(buttonView, isChecked) -> {
|
||||
if (isChecked) {
|
||||
useMedia3Mp4Muxer.setChecked(false);
|
||||
}
|
||||
});
|
||||
|
||||
@ -407,8 +407,8 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
||||
bundle.putBoolean(ENABLE_ANALYZER_MODE, enableAnalyzerModeCheckBox.isChecked());
|
||||
bundle.putBoolean(ENABLE_DEBUG_PREVIEW, enableDebugPreviewCheckBox.isChecked());
|
||||
bundle.putBoolean(ABORT_SLOW_EXPORT, abortSlowExportCheckBox.isChecked());
|
||||
bundle.putBoolean(USE_MEDIA3_MUXER, useMedia3Muxer.isChecked());
|
||||
bundle.putBoolean(PRODUCE_FRAGMENTED_MP4, produceFragmentedMp4CheckBox.isChecked());
|
||||
bundle.putBoolean(USE_MEDIA3_MP4_MUXER, useMedia3Mp4Muxer.isChecked());
|
||||
bundle.putBoolean(USE_MEDIA3_FRAGMENTED_MP4_MUXER, useMedia3FragmentedMp4Muxer.isChecked());
|
||||
String selectedHdrMode = String.valueOf(hdrModeSpinner.getSelectedItem());
|
||||
bundle.putInt(HDR_MODE, HDR_MODE_DESCRIPTIONS.get(selectedHdrMode));
|
||||
bundle.putBooleanArray(AUDIO_EFFECTS_SELECTIONS, audioEffectsSelections);
|
||||
|
@ -88,7 +88,8 @@ import androidx.media3.transformer.Effects;
|
||||
import androidx.media3.transformer.ExperimentalAnalyzerModeFactory;
|
||||
import androidx.media3.transformer.ExportException;
|
||||
import androidx.media3.transformer.ExportResult;
|
||||
import androidx.media3.transformer.InAppMuxer;
|
||||
import androidx.media3.transformer.InAppFragmentedMp4Muxer;
|
||||
import androidx.media3.transformer.InAppMp4Muxer;
|
||||
import androidx.media3.transformer.JsonUtil;
|
||||
import androidx.media3.transformer.ProgressHolder;
|
||||
import androidx.media3.transformer.Transformer;
|
||||
@ -302,12 +303,12 @@ public final class TransformerActivity extends AppCompatActivity {
|
||||
transformerBuilder.setMaxDelayBetweenMuxerSamplesMs(C.TIME_UNSET);
|
||||
}
|
||||
|
||||
if (bundle.getBoolean(ConfigurationActivity.USE_MEDIA3_MUXER)) {
|
||||
transformerBuilder.setMuxerFactory(
|
||||
new InAppMuxer.Factory.Builder()
|
||||
.setOutputFragmentedMp4(
|
||||
bundle.getBoolean(ConfigurationActivity.PRODUCE_FRAGMENTED_MP4))
|
||||
.build());
|
||||
if (bundle.getBoolean(ConfigurationActivity.USE_MEDIA3_MP4_MUXER)) {
|
||||
transformerBuilder.setMuxerFactory(new InAppMp4Muxer.Factory());
|
||||
}
|
||||
|
||||
if (bundle.getBoolean(ConfigurationActivity.USE_MEDIA3_FRAGMENTED_MP4_MUXER)) {
|
||||
transformerBuilder.setMuxerFactory(new InAppFragmentedMp4Muxer.Factory());
|
||||
}
|
||||
|
||||
if (bundle.getBoolean(ConfigurationActivity.ENABLE_DEBUG_PREVIEW)) {
|
||||
|
@ -239,18 +239,18 @@
|
||||
android:layout_weight="1">
|
||||
<TextView
|
||||
android:layout_gravity="center_vertical"
|
||||
android:text="@string/use_media3_muxer" />
|
||||
android:text="@string/use_media3_mp4_muxer" />
|
||||
<CheckBox
|
||||
android:id="@+id/use_media3_muxer_checkbox"
|
||||
android:id="@+id/use_media3_mp4_muxer_checkbox"
|
||||
android:layout_gravity="end"/>
|
||||
</TableRow>
|
||||
<TableRow
|
||||
android:layout_weight="1">
|
||||
<TextView
|
||||
android:layout_gravity="center_vertical"
|
||||
android:text="@string/produce_fragmented_mp4" />
|
||||
android:text="@string/use_media3_fragmented_mp4_muxer" />
|
||||
<CheckBox
|
||||
android:id="@+id/produce_fragmented_mp4_checkbox"
|
||||
android:id="@+id/use_media3_fragmented_mp4_muxer_checkbox"
|
||||
android:layout_gravity="end"/>
|
||||
</TableRow>
|
||||
<TableRow
|
||||
|
@ -32,8 +32,8 @@
|
||||
<string name="enable_debug_preview" translatable="false">Enable debug preview</string>
|
||||
<string name="enable_debug_tracing" translatable="false">Enable debug tracing</string>
|
||||
<string name="abort_slow_export" translatable="false">Abort slow export</string>
|
||||
<string name="use_media3_muxer" translatable="false">Use Media3 muxer</string>
|
||||
<string name="produce_fragmented_mp4" translatable="false">Produce fragmented MP4</string>
|
||||
<string name="use_media3_mp4_muxer" translatable="false">Use Media3 Mp4Muxer</string>
|
||||
<string name="use_media3_fragmented_mp4_muxer" translatable="false">Use Media3 FragmentedMp4Muxer</string>
|
||||
<string name="trim" translatable="false">Trim</string>
|
||||
<string name="hdr_mode" translatable="false">HDR mode</string>
|
||||
<string name="select_audio_effects" translatable="false">Add audio effects</string>
|
||||
|
@ -1385,7 +1385,7 @@ public final class AndroidTestUtil {
|
||||
/** Returns a {@link Muxer.Factory} depending upon the API level. */
|
||||
public static Muxer.Factory getMuxerFactoryBasedOnApi() {
|
||||
// MediaMuxer supports B-frame from API > 24.
|
||||
return SDK_INT > 24 ? new DefaultMuxer.Factory() : new InAppMuxer.Factory.Builder().build();
|
||||
return SDK_INT > 24 ? new DefaultMuxer.Factory() : new InAppMp4Muxer.Factory();
|
||||
}
|
||||
|
||||
private static boolean canDecode(Format format) throws MediaCodecUtil.DecoderQueryException {
|
||||
|
@ -1815,7 +1815,7 @@ public class TransformerEndToEndTest {
|
||||
context,
|
||||
new Transformer.Builder(context)
|
||||
.setVideoMimeType(MimeTypes.VIDEO_H265)
|
||||
.setMuxerFactory(new InAppMuxer.Factory.Builder().build())
|
||||
.setMuxerFactory(new InAppMp4Muxer.Factory())
|
||||
.build())
|
||||
.build()
|
||||
.run(testId, editedMediaItem);
|
||||
@ -2112,9 +2112,7 @@ public class TransformerEndToEndTest {
|
||||
public void transmux_audioWithEditListUsingInAppMuxer_preservesDuration() throws Exception {
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
Transformer transformer =
|
||||
new Transformer.Builder(context)
|
||||
.setMuxerFactory(new InAppMuxer.Factory.Builder().build())
|
||||
.build();
|
||||
new Transformer.Builder(context).setMuxerFactory(new InAppMp4Muxer.Factory()).build();
|
||||
MediaItem mediaItem =
|
||||
MediaItem.fromUri(Uri.parse("asset:///media/mp4/long_edit_list_audioonly.mp4"));
|
||||
|
||||
@ -2393,7 +2391,7 @@ public class TransformerEndToEndTest {
|
||||
// The MediaMuxer is not writing the bitrate hence use the InAppMuxer.
|
||||
Transformer transformer =
|
||||
new Transformer.Builder(context)
|
||||
.setMuxerFactory(new InAppMuxer.Factory.Builder().build())
|
||||
.setMuxerFactory(new InAppMp4Muxer.Factory())
|
||||
.setEncoderFactory(
|
||||
new DefaultEncoderFactory.Builder(context)
|
||||
.setRequestedAudioEncoderSettings(
|
||||
|
@ -38,9 +38,9 @@ import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
/** End-to-end instrumentation test for {@link Transformer} with {@link InAppMuxer}. */
|
||||
/** End-to-end instrumentation test for {@link Transformer} with {@link InAppMp4Muxer}. */
|
||||
@RunWith(Parameterized.class)
|
||||
public class TransformerWithInAppMuxerEndToEndAndroidTest {
|
||||
public class TransformerWithInAppMp4MuxerEndToEndAndroidTest {
|
||||
private static final String MP4_FILE_ASSET_DIRECTORY = "asset:///media/mp4/";
|
||||
private static final String H264_MP4 = "sample_no_bframes.mp4";
|
||||
private static final String H265_MP4 = "h265_with_metadata_track.mp4";
|
||||
@ -66,9 +66,7 @@ public class TransformerWithInAppMuxerEndToEndAndroidTest {
|
||||
/* inputFormat= */ MP4_ASSET.videoFormat,
|
||||
/* outputFormat= */ MP4_ASSET.videoFormat);
|
||||
Transformer transformer =
|
||||
new Transformer.Builder(context)
|
||||
.setMuxerFactory(new InAppMuxer.Factory.Builder().build())
|
||||
.build();
|
||||
new Transformer.Builder(context).setMuxerFactory(new InAppMp4Muxer.Factory()).build();
|
||||
ImmutableList<Effect> videoEffects = ImmutableList.of(RgbFilter.createGrayscaleFilter());
|
||||
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(MP4_FILE_ASSET_DIRECTORY + inputFile));
|
||||
EditedMediaItem editedMediaItem =
|
||||
@ -91,9 +89,7 @@ public class TransformerWithInAppMuxerEndToEndAndroidTest {
|
||||
assumeTrue(checkNotNull(inputFile).equals(H264_MP4));
|
||||
String testId = "audioEditing_completesSuccessfully";
|
||||
Transformer transformer =
|
||||
new Transformer.Builder(context)
|
||||
.setMuxerFactory(new InAppMuxer.Factory.Builder().build())
|
||||
.build();
|
||||
new Transformer.Builder(context).setMuxerFactory(new InAppMp4Muxer.Factory()).build();
|
||||
ChannelMixingAudioProcessor channelMixingAudioProcessor = new ChannelMixingAudioProcessor();
|
||||
channelMixingAudioProcessor.putChannelMixingMatrix(
|
||||
ChannelMixingMatrix.create(/* inputChannelCount= */ 1, /* outputChannelCount= */ 2));
|
@ -27,7 +27,7 @@ import androidx.media3.effect.RgbFilter;
|
||||
import androidx.media3.transformer.EditedMediaItem;
|
||||
import androidx.media3.transformer.Effects;
|
||||
import androidx.media3.transformer.ExportTestResult;
|
||||
import androidx.media3.transformer.InAppMuxer;
|
||||
import androidx.media3.transformer.InAppMp4Muxer;
|
||||
import androidx.media3.transformer.Transformer;
|
||||
import androidx.media3.transformer.TransformerAndroidTestRunner;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
@ -40,9 +40,9 @@ import org.junit.Test;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/** End-to-end instrumentation test for {@link Transformer} with {@link InAppMuxer}. */
|
||||
/** End-to-end instrumentation test for {@link Transformer} with {@link InAppMp4Muxer}. */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class TransformerWithInAppMuxerEndToEndMhTest {
|
||||
public class TransformerWithInAppMp4MuxerEndToEndMhTest {
|
||||
@Rule public final TestName testName = new TestName();
|
||||
|
||||
private String testId;
|
||||
@ -61,9 +61,7 @@ public class TransformerWithInAppMuxerEndToEndMhTest {
|
||||
/* inputFormat= */ MP4_ASSET_AV1_VIDEO.videoFormat,
|
||||
/* outputFormat= */ null);
|
||||
Transformer transformer =
|
||||
new Transformer.Builder(context)
|
||||
.setMuxerFactory(new InAppMuxer.Factory.Builder().build())
|
||||
.build();
|
||||
new Transformer.Builder(context).setMuxerFactory(new InAppMp4Muxer.Factory()).build();
|
||||
ImmutableList<Effect> videoEffects = ImmutableList.of(RgbFilter.createGrayscaleFilter());
|
||||
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(MP4_ASSET_AV1_VIDEO.uri));
|
||||
EditedMediaItem editedMediaItem =
|
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright 2023 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 androidx.media3.transformer;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCodec.BufferInfo;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.Format;
|
||||
import androidx.media3.common.Metadata;
|
||||
import androidx.media3.common.MimeTypes;
|
||||
import androidx.media3.common.util.Log;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.container.Mp4OrientationData;
|
||||
import androidx.media3.muxer.FragmentedMp4Muxer;
|
||||
import androidx.media3.muxer.Muxer;
|
||||
import androidx.media3.muxer.MuxerException;
|
||||
import androidx.media3.muxer.MuxerUtil;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Locale;
|
||||
|
||||
/** {@link Muxer} implementation that uses a {@link FragmentedMp4Muxer}. */
|
||||
// TODO: b/372417042 - Add E2E tests for producing fragmented MP4 output.
|
||||
@UnstableApi
|
||||
public final class InAppFragmentedMp4Muxer implements Muxer {
|
||||
/** {@link Muxer.Factory} for {@link InAppFragmentedMp4Muxer}. */
|
||||
public static final class Factory implements Muxer.Factory {
|
||||
// TODO: b/372417042 - Move these lists to FragmentedMp4Muxer.
|
||||
/** A list of supported video sample MIME types. */
|
||||
private static final ImmutableList<String> SUPPORTED_VIDEO_SAMPLE_MIME_TYPES =
|
||||
ImmutableList.of(
|
||||
MimeTypes.VIDEO_AV1,
|
||||
MimeTypes.VIDEO_H263,
|
||||
MimeTypes.VIDEO_H264,
|
||||
MimeTypes.VIDEO_H265,
|
||||
MimeTypes.VIDEO_MP4V);
|
||||
|
||||
/** A list of supported audio sample MIME types. */
|
||||
private static final ImmutableList<String> SUPPORTED_AUDIO_SAMPLE_MIME_TYPES =
|
||||
ImmutableList.of(
|
||||
MimeTypes.AUDIO_AAC,
|
||||
MimeTypes.AUDIO_AMR_NB,
|
||||
MimeTypes.AUDIO_AMR_WB,
|
||||
MimeTypes.AUDIO_OPUS,
|
||||
MimeTypes.AUDIO_VORBIS);
|
||||
|
||||
private final long fragmentDurationMs;
|
||||
|
||||
private long videoDurationUs;
|
||||
|
||||
/** Creates an instance with default values. */
|
||||
public Factory() {
|
||||
this(C.TIME_UNSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
*
|
||||
* @param fragmentDurationMs The fragment duration (in milliseconds).
|
||||
*/
|
||||
public Factory(long fragmentDurationMs) {
|
||||
this.fragmentDurationMs = fragmentDurationMs;
|
||||
videoDurationUs = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the duration of the video track (in microseconds) in the output.
|
||||
*
|
||||
* <p>Only the duration of the last sample is adjusted to achieve the given duration. Duration
|
||||
* of the other samples remains unchanged.
|
||||
*
|
||||
* <p>The default is {@link C#TIME_UNSET} to not set any duration in the output. In this case
|
||||
* the video track duration is determined by the samples written to it and the duration of the
|
||||
* last sample will be same as that of the sample before that.
|
||||
*
|
||||
* @param videoDurationUs The duration of the video track (in microseconds) in the output, or
|
||||
* {@link C#TIME_UNSET} to not set any duration. Only applicable when a video track is
|
||||
* {@linkplain #addTrack(Format) added}.
|
||||
* @return This factory.
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
public Factory setVideoDurationUs(long videoDurationUs) {
|
||||
this.videoDurationUs = videoDurationUs;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InAppFragmentedMp4Muxer create(String path) throws MuxerException {
|
||||
FileOutputStream outputStream;
|
||||
try {
|
||||
outputStream = new FileOutputStream(path);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new MuxerException("Error creating file output stream", e);
|
||||
}
|
||||
|
||||
FragmentedMp4Muxer.Builder builder = new FragmentedMp4Muxer.Builder(outputStream);
|
||||
if (fragmentDurationMs != C.TIME_UNSET) {
|
||||
builder.setFragmentDurationMs(fragmentDurationMs);
|
||||
}
|
||||
FragmentedMp4Muxer muxer = builder.build();
|
||||
|
||||
return new InAppFragmentedMp4Muxer(muxer, videoDurationUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<String> getSupportedSampleMimeTypes(@C.TrackType int trackType) {
|
||||
if (trackType == C.TRACK_TYPE_VIDEO) {
|
||||
return SUPPORTED_VIDEO_SAMPLE_MIME_TYPES;
|
||||
} else if (trackType == C.TRACK_TYPE_AUDIO) {
|
||||
return SUPPORTED_AUDIO_SAMPLE_MIME_TYPES;
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
}
|
||||
|
||||
private static final String TAG = "InAppFragmentedMp4Muxer";
|
||||
private static final int TRACK_ID_UNSET = -1;
|
||||
|
||||
private final FragmentedMp4Muxer muxer;
|
||||
private final long videoDurationUs;
|
||||
|
||||
private int videoTrackId;
|
||||
|
||||
private InAppFragmentedMp4Muxer(FragmentedMp4Muxer muxer, long videoDurationUs) {
|
||||
this.muxer = muxer;
|
||||
this.videoDurationUs = videoDurationUs;
|
||||
videoTrackId = TRACK_ID_UNSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int addTrack(Format format) {
|
||||
int trackId = muxer.addTrack(format);
|
||||
if (MimeTypes.isVideo(format.sampleMimeType)) {
|
||||
muxer.addMetadataEntry(new Mp4OrientationData(format.rotationDegrees));
|
||||
videoTrackId = trackId;
|
||||
}
|
||||
return trackId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSampleData(int trackId, ByteBuffer byteBuffer, BufferInfo bufferInfo)
|
||||
throws MuxerException {
|
||||
if (videoDurationUs != C.TIME_UNSET
|
||||
&& trackId == videoTrackId
|
||||
&& bufferInfo.presentationTimeUs > videoDurationUs) {
|
||||
Log.w(
|
||||
TAG,
|
||||
String.format(
|
||||
Locale.US,
|
||||
"Skipped sample with presentation time (%d) > video duration (%d)",
|
||||
bufferInfo.presentationTimeUs,
|
||||
videoDurationUs));
|
||||
return;
|
||||
}
|
||||
muxer.writeSampleData(trackId, byteBuffer, bufferInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMetadataEntry(Metadata.Entry metadataEntry) {
|
||||
if (MuxerUtil.isMetadataSupported(metadataEntry)) {
|
||||
muxer.addMetadataEntry(metadataEntry);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws MuxerException {
|
||||
if (videoDurationUs != C.TIME_UNSET && videoTrackId != TRACK_ID_UNSET) {
|
||||
BufferInfo bufferInfo = new BufferInfo();
|
||||
bufferInfo.set(
|
||||
/* newOffset= */ 0,
|
||||
/* newSize= */ 0,
|
||||
videoDurationUs,
|
||||
MediaCodec.BUFFER_FLAG_END_OF_STREAM);
|
||||
writeSampleData(videoTrackId, ByteBuffer.allocateDirect(0), bufferInfo);
|
||||
}
|
||||
muxer.close();
|
||||
}
|
||||
}
|
@ -27,7 +27,6 @@ import androidx.media3.common.MimeTypes;
|
||||
import androidx.media3.common.util.Log;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.container.Mp4OrientationData;
|
||||
import androidx.media3.muxer.FragmentedMp4Muxer;
|
||||
import androidx.media3.muxer.Mp4Muxer;
|
||||
import androidx.media3.muxer.Muxer;
|
||||
import androidx.media3.muxer.MuxerException;
|
||||
@ -41,10 +40,9 @@ import java.util.LinkedHashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
/** {@link Muxer} implementation that uses an {@link Mp4Muxer} or {@link FragmentedMp4Muxer}. */
|
||||
/** {@link Muxer} implementation that uses an {@link Mp4Muxer}. */
|
||||
@UnstableApi
|
||||
public final class InAppMuxer implements Muxer {
|
||||
|
||||
public final class InAppMp4Muxer implements Muxer {
|
||||
/** Provides {@linkplain Metadata.Entry metadata} to add in the output MP4 file. */
|
||||
public interface MetadataProvider {
|
||||
|
||||
@ -60,57 +58,9 @@ public final class InAppMuxer implements Muxer {
|
||||
void updateMetadataEntries(Set<Metadata.Entry> metadataEntries);
|
||||
}
|
||||
|
||||
/** {@link Muxer.Factory} for {@link InAppMuxer}. */
|
||||
/** {@link Muxer.Factory} for {@link InAppMp4Muxer}. */
|
||||
public static final class Factory implements Muxer.Factory {
|
||||
|
||||
/** A builder for {@link Factory} instances. */
|
||||
public static final class Builder {
|
||||
@Nullable private MetadataProvider metadataProvider;
|
||||
private boolean outputFragmentedMp4;
|
||||
private long fragmentDurationMs;
|
||||
|
||||
/** Creates a {@link Builder} instance with default values. */
|
||||
public Builder() {
|
||||
fragmentDurationMs = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an implementation of {@link MetadataProvider}.
|
||||
*
|
||||
* <p>The default value is {@code null}.
|
||||
*
|
||||
* <p>If the value is not set then the {@linkplain Metadata.Entry metadata} from the input
|
||||
* file is set as it is in the output file.
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
public Builder setMetadataProvider(MetadataProvider metadataProvider) {
|
||||
this.metadataProvider = metadataProvider;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets whether to output a fragmented MP4. */
|
||||
@CanIgnoreReturnValue
|
||||
public Builder setOutputFragmentedMp4(boolean outputFragmentedMp4) {
|
||||
this.outputFragmentedMp4 = outputFragmentedMp4;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the fragment duration (in milliseconds) if the output file is {@link
|
||||
* #setOutputFragmentedMp4(boolean) fragmented}.
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
public Builder setFragmentDurationMs(long fragmentDurationMs) {
|
||||
this.fragmentDurationMs = fragmentDurationMs;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Builds a {@link Factory} instance. */
|
||||
public Factory build() {
|
||||
return new Factory(metadataProvider, outputFragmentedMp4, fragmentDurationMs);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: b/372417042 - Move these lists to Mp4Muxer.
|
||||
/** A list of supported video sample MIME types. */
|
||||
private static final ImmutableList<String> SUPPORTED_VIDEO_SAMPLE_MIME_TYPES =
|
||||
ImmutableList.of(
|
||||
@ -130,18 +80,21 @@ public final class InAppMuxer implements Muxer {
|
||||
MimeTypes.AUDIO_VORBIS);
|
||||
|
||||
@Nullable private final MetadataProvider metadataProvider;
|
||||
private final boolean outputFragmentedMp4;
|
||||
private final long fragmentDurationMs;
|
||||
|
||||
private long videoDurationUs;
|
||||
|
||||
private Factory(
|
||||
@Nullable MetadataProvider metadataProvider,
|
||||
boolean outputFragmentedMp4,
|
||||
long fragmentDurationMs) {
|
||||
/** Creates an instance with default values. */
|
||||
public Factory() {
|
||||
this(/* metadataProvider= */ null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
*
|
||||
* @param metadataProvider A {@link MetadataProvider}.
|
||||
*/
|
||||
public Factory(@Nullable MetadataProvider metadataProvider) {
|
||||
this.metadataProvider = metadataProvider;
|
||||
this.outputFragmentedMp4 = outputFragmentedMp4;
|
||||
this.fragmentDurationMs = fragmentDurationMs;
|
||||
videoDurationUs = C.TIME_UNSET;
|
||||
}
|
||||
|
||||
@ -167,7 +120,7 @@ public final class InAppMuxer implements Muxer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public InAppMuxer create(String path) throws MuxerException {
|
||||
public InAppMp4Muxer create(String path) throws MuxerException {
|
||||
FileOutputStream outputStream;
|
||||
try {
|
||||
outputStream = new FileOutputStream(path);
|
||||
@ -175,23 +128,14 @@ public final class InAppMuxer implements Muxer {
|
||||
throw new MuxerException("Error creating file output stream", e);
|
||||
}
|
||||
|
||||
Muxer muxer = null;
|
||||
if (outputFragmentedMp4) {
|
||||
FragmentedMp4Muxer.Builder builder = new FragmentedMp4Muxer.Builder(outputStream);
|
||||
if (fragmentDurationMs != C.TIME_UNSET) {
|
||||
builder.setFragmentDurationMs(fragmentDurationMs);
|
||||
}
|
||||
muxer = builder.build();
|
||||
} else {
|
||||
Mp4Muxer.Builder builder = new Mp4Muxer.Builder(outputStream);
|
||||
if (videoDurationUs != C.TIME_UNSET) {
|
||||
builder.setLastSampleDurationBehavior(
|
||||
LAST_SAMPLE_DURATION_BEHAVIOR_SET_FROM_END_OF_STREAM_BUFFER_OR_DUPLICATE_PREVIOUS);
|
||||
}
|
||||
muxer = builder.build();
|
||||
Mp4Muxer.Builder builder = new Mp4Muxer.Builder(outputStream);
|
||||
if (videoDurationUs != C.TIME_UNSET) {
|
||||
builder.setLastSampleDurationBehavior(
|
||||
LAST_SAMPLE_DURATION_BEHAVIOR_SET_FROM_END_OF_STREAM_BUFFER_OR_DUPLICATE_PREVIOUS);
|
||||
}
|
||||
Mp4Muxer muxer = builder.build();
|
||||
|
||||
return new InAppMuxer(muxer, metadataProvider, videoDurationUs);
|
||||
return new InAppMp4Muxer(muxer, metadataProvider, videoDurationUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -205,18 +149,18 @@ public final class InAppMuxer implements Muxer {
|
||||
}
|
||||
}
|
||||
|
||||
private static final String TAG = "InAppMuxer";
|
||||
private static final String TAG = "InAppMp4Muxer";
|
||||
private static final int TRACK_ID_UNSET = -1;
|
||||
|
||||
private final Muxer muxer;
|
||||
private final Mp4Muxer muxer;
|
||||
@Nullable private final MetadataProvider metadataProvider;
|
||||
private final long videoDurationUs;
|
||||
private final Set<Metadata.Entry> metadataEntries;
|
||||
|
||||
private int videoTrackId;
|
||||
|
||||
private InAppMuxer(
|
||||
Muxer muxer, @Nullable MetadataProvider metadataProvider, long videoDurationUs) {
|
||||
private InAppMp4Muxer(
|
||||
Mp4Muxer muxer, @Nullable MetadataProvider metadataProvider, long videoDurationUs) {
|
||||
this.muxer = muxer;
|
||||
this.metadataProvider = metadataProvider;
|
||||
this.videoDurationUs = videoDurationUs;
|
@ -66,7 +66,7 @@ public final class EncodedSampleExporterTest {
|
||||
new TransformationRequest.Builder().build(),
|
||||
new MuxerWrapper(
|
||||
/* outputPath= */ "unused",
|
||||
new InAppMuxer.Factory.Builder().build(),
|
||||
new InAppMp4Muxer.Factory(),
|
||||
mock(MuxerWrapper.Listener.class),
|
||||
MuxerWrapper.MUXER_MODE_DEFAULT,
|
||||
/* dropSamplesBeforeFirstVideoSample= */ false,
|
||||
|
@ -39,9 +39,9 @@ import org.robolectric.ParameterizedRobolectricTestRunner;
|
||||
import org.robolectric.ParameterizedRobolectricTestRunner.Parameter;
|
||||
import org.robolectric.ParameterizedRobolectricTestRunner.Parameters;
|
||||
|
||||
/** End to end parameterized tests for {@link Transformer} with {@link InAppMuxer}. */
|
||||
/** End to end parameterized tests for {@link Transformer} with {@link InAppMp4Muxer}. */
|
||||
@RunWith(ParameterizedRobolectricTestRunner.class)
|
||||
public class TransformerWithInAppMuxerEndToEndParameterizedTest {
|
||||
public class TransformerWithInAppMp4MuxerEndToEndParameterizedTest {
|
||||
|
||||
private static final String H263_3GP = "mp4/bbb_176x144_128kbps_15fps_h263.3gp";
|
||||
private static final String H264_MP4 = "mp4/sample_no_bframes.mp4";
|
||||
@ -84,15 +84,13 @@ public class TransformerWithInAppMuxerEndToEndParameterizedTest {
|
||||
@Test
|
||||
public void transmux_mp4File_outputMatchesExpected() throws Exception {
|
||||
Muxer.Factory inAppMuxerFactory =
|
||||
new InAppMuxer.Factory.Builder()
|
||||
.setMetadataProvider(
|
||||
metadataEntries ->
|
||||
// Add timestamp to make output file deterministic.
|
||||
metadataEntries.add(
|
||||
new Mp4TimestampData(
|
||||
/* creationTimestampSeconds= */ 3_000_000_000L,
|
||||
/* modificationTimestampSeconds= */ 4_000_000_000L)))
|
||||
.build();
|
||||
new InAppMp4Muxer.Factory(
|
||||
metadataEntries ->
|
||||
// Add timestamp to make output file deterministic.
|
||||
metadataEntries.add(
|
||||
new Mp4TimestampData(
|
||||
/* creationTimestampSeconds= */ 3_000_000_000L,
|
||||
/* modificationTimestampSeconds= */ 4_000_000_000L)));
|
||||
|
||||
Transformer transformer =
|
||||
new TestTransformerBuilder(context).setMuxerFactory(inAppMuxerFactory).build();
|
@ -47,9 +47,9 @@ import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/** End-to-end test for {@link Transformer} with {@link InAppMuxer}. */
|
||||
/** End-to-end test for {@link Transformer} with {@link InAppMp4Muxer}. */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class TransformerWithInAppMuxerEndToEndNonParameterizedTest {
|
||||
public class TransformerWithInAppMp4MuxerEndToEndTest {
|
||||
private static final String MP4_FILE_PATH = "asset:///media/mp4/sample_no_bframes.mp4";
|
||||
|
||||
@Rule public final TemporaryFolder outputDir = new TemporaryFolder();
|
||||
@ -67,15 +67,13 @@ public class TransformerWithInAppMuxerEndToEndNonParameterizedTest {
|
||||
String tsFilePath = "asset:///media/ts/sample_h264.ts";
|
||||
String tsFileName = "ts/sample_h264.ts";
|
||||
Muxer.Factory inAppMuxerFactory =
|
||||
new InAppMuxer.Factory.Builder()
|
||||
.setMetadataProvider(
|
||||
metadataEntries ->
|
||||
// Add timestamp to make output file deterministic.
|
||||
metadataEntries.add(
|
||||
new Mp4TimestampData(
|
||||
/* creationTimestampSeconds= */ 3_000_000_000L,
|
||||
/* modificationTimestampSeconds= */ 4_000_000_000L)))
|
||||
.build();
|
||||
new InAppMp4Muxer.Factory(
|
||||
metadataEntries ->
|
||||
// Add timestamp to make output file deterministic.
|
||||
metadataEntries.add(
|
||||
new Mp4TimestampData(
|
||||
/* creationTimestampSeconds= */ 3_000_000_000L,
|
||||
/* modificationTimestampSeconds= */ 4_000_000_000L)));
|
||||
|
||||
Transformer transformer =
|
||||
new TestTransformerBuilder(context).setMuxerFactory(inAppMuxerFactory).build();
|
||||
@ -104,14 +102,11 @@ public class TransformerWithInAppMuxerEndToEndNonParameterizedTest {
|
||||
Mp4LocationData expectedLocationData =
|
||||
new Mp4LocationData(/* latitude= */ 45f, /* longitude= */ -90f);
|
||||
Muxer.Factory inAppMuxerFactory =
|
||||
new InAppMuxer.Factory.Builder()
|
||||
.setMetadataProvider(
|
||||
metadataEntries -> {
|
||||
metadataEntries.removeIf(
|
||||
(Metadata.Entry entry) -> entry instanceof Mp4LocationData);
|
||||
metadataEntries.add(expectedLocationData);
|
||||
})
|
||||
.build();
|
||||
new InAppMp4Muxer.Factory(
|
||||
metadataEntries -> {
|
||||
metadataEntries.removeIf((Metadata.Entry entry) -> entry instanceof Mp4LocationData);
|
||||
metadataEntries.add(expectedLocationData);
|
||||
});
|
||||
Transformer transformer =
|
||||
new TestTransformerBuilder(context).setMuxerFactory(inAppMuxerFactory).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(MP4_FILE_PATH));
|
||||
@ -130,9 +125,7 @@ public class TransformerWithInAppMuxerEndToEndNonParameterizedTest {
|
||||
String xmpSampleData = "media/xmp/sample_datetime_xmp.xmp";
|
||||
byte[] xmpData = androidx.media3.test.utils.TestUtil.getByteArray(context, xmpSampleData);
|
||||
Muxer.Factory inAppMuxerFactory =
|
||||
new InAppMuxer.Factory.Builder()
|
||||
.setMetadataProvider(metadataEntries -> metadataEntries.add(new XmpData(xmpData)))
|
||||
.build();
|
||||
new InAppMp4Muxer.Factory(metadataEntries -> metadataEntries.add(new XmpData(xmpData)));
|
||||
Transformer transformer =
|
||||
new TestTransformerBuilder(context).setMuxerFactory(inAppMuxerFactory).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(MP4_FILE_PATH));
|
||||
@ -153,9 +146,7 @@ public class TransformerWithInAppMuxerEndToEndNonParameterizedTest {
|
||||
/* value= */ Util.toByteArray(captureFps),
|
||||
MdtaMetadataEntry.TYPE_INDICATOR_FLOAT32);
|
||||
Muxer.Factory inAppMuxerFactory =
|
||||
new InAppMuxer.Factory.Builder()
|
||||
.setMetadataProvider(metadataEntries -> metadataEntries.add(expectedCaptureFps))
|
||||
.build();
|
||||
new InAppMp4Muxer.Factory(metadataEntries -> metadataEntries.add(expectedCaptureFps));
|
||||
Transformer transformer =
|
||||
new TestTransformerBuilder(context).setMuxerFactory(inAppMuxerFactory).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(MP4_FILE_PATH));
|
||||
@ -181,9 +172,7 @@ public class TransformerWithInAppMuxerEndToEndNonParameterizedTest {
|
||||
/* creationTimestampSeconds= */ 3_000_000_000L,
|
||||
/* modificationTimestampSeconds= */ 4_000_000_000L);
|
||||
Muxer.Factory inAppMuxerFactory =
|
||||
new InAppMuxer.Factory.Builder()
|
||||
.setMetadataProvider(metadataEntries -> metadataEntries.add(expectedTimestampData))
|
||||
.build();
|
||||
new InAppMp4Muxer.Factory(metadataEntries -> metadataEntries.add(expectedTimestampData));
|
||||
|
||||
Transformer transformer =
|
||||
new TestTransformerBuilder(context).setMuxerFactory(inAppMuxerFactory).build();
|
||||
@ -212,13 +201,11 @@ public class TransformerWithInAppMuxerEndToEndNonParameterizedTest {
|
||||
/* value= */ Util.toByteArray(600.0f),
|
||||
MdtaMetadataEntry.TYPE_INDICATOR_FLOAT32);
|
||||
Muxer.Factory inAppMuxerFactory =
|
||||
new InAppMuxer.Factory.Builder()
|
||||
.setMetadataProvider(
|
||||
metadataEntries -> {
|
||||
metadataEntries.add(expectedStringMetadata);
|
||||
metadataEntries.add(expectedFloatMetadata);
|
||||
})
|
||||
.build();
|
||||
new InAppMp4Muxer.Factory(
|
||||
metadataEntries -> {
|
||||
metadataEntries.add(expectedStringMetadata);
|
||||
metadataEntries.add(expectedFloatMetadata);
|
||||
});
|
||||
Transformer transformer =
|
||||
new TestTransformerBuilder(context).setMuxerFactory(inAppMuxerFactory).build();
|
||||
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(MP4_FILE_PATH));
|
||||
@ -248,7 +235,7 @@ public class TransformerWithInAppMuxerEndToEndNonParameterizedTest {
|
||||
|
||||
@Test
|
||||
public void transmux_withSettingVideoDuration_writesCorrectVideoDuration() throws Exception {
|
||||
InAppMuxer.Factory inAppMuxerFactory = new InAppMuxer.Factory.Builder().build();
|
||||
InAppMp4Muxer.Factory inAppMuxerFactory = new InAppMp4Muxer.Factory();
|
||||
long expectedDurationUs = 2_000_000L;
|
||||
inAppMuxerFactory.setVideoDurationUs(expectedDurationUs);
|
||||
Transformer transformer =
|
Loading…
x
Reference in New Issue
Block a user