androidx / media

Jetpack Media3 support libraries for media use cases, including ExoPlayer, an extensible media player for Android
Apache License 2.0
1.34k stars 315 forks source link

Preview composition crashes with EditedMediaItem.getPresentationDurationUs error #1488

Open pawaom opened 1 week ago

pawaom commented 1 week ago

Preview composition crashes with EditedMediaItem.getPresentationDurationUs error using media3_version = "1.4.0-alpha02"

I am trying this code to create a PIP video effect

private LinearProgressIndicator progressIndicator;
    ViewGroup progressViewGroup;
    private AspectRatioFrameLayout debugaspectRatioFrameLayout;
    Uri VideoUri2, VideoUri;
    TextView Video2TextView, VideoTextView;
    Button VideoButton, Video2Button, TransformButton;
    ActivityResultLauncher<String> VideoGetContent = registerForActivityResult(new ActivityResultContracts.GetContent(),
            new ActivityResultCallback<Uri>() {
                @Override
                public void onActivityResult(Uri uri) {
                    // Handle the returned Uri
                    VideoUri = uri;
                    VideoTextView.setText(VideoUri.toString());
                    MediaItem inputMediaItem = new MediaItem.Builder().setUri(VideoUri).build();
                    //  cropEffect(inputMediaItem);
                }
            });

    ActivityResultLauncher<String> AudioGetContent = registerForActivityResult(new ActivityResultContracts.GetContent(),
            uri -> {
                // Handle the returned Uri
                VideoUri2 = uri;
                Video2TextView.setText(VideoUri2.toString());
            });
    private Handler mainHandler;
    private String outputPath;
    CompositionPlayer outputPlayer;
    PlayerView outputPlayerView;

    @OptIn(markerClass = UnstableApi.class)
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.exxoplayerviewtry);

        //   progressViewGroup = findViewById(R.id.progress_view_group1);
        progressIndicator = findViewById(R.id.progress_indicator);
        VideoTextView = findViewById(R.id.textView);
        this.outputPlayerView = findViewById(R.id.output_player_view);

        Video2TextView = findViewById(R.id.textView2);
        VideoButton = findViewById(R.id.button);
        debugaspectRatioFrameLayout = findViewById(R.id.debug_aspect_ratio_frame_layout);

        VideoButton.setOnClickListener(view -> {
            // Pass in the mime type you want to let the user select
            // as the input
            VideoGetContent.launch("video/*");
        });

        Video2Button = findViewById(R.id.button2);

        Video2Button.setOnClickListener(view -> {
            // Pass in the mime type you want to let the user select
            // as the input
            AudioGetContent.launch("video/*");
        });

        TransformButton = findViewById(R.id.button3);

        TransformButton.setOnClickListener(view -> {
            // Pass in the mime type you want to let the user select
            // as the input
           // createTransform();
            PreviewComposition();
        });
    }

    public void createTransform() {
        Transformer transformer =
                new Transformer.Builder(this)
                        .setTransformationRequest(
                                new TransformationRequest.Builder().build())
                        .addListener(transformerListener)

                        .build();
        try {
            outputPath = createOutputFile().getAbsolutePath();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        transformer.start(myComposition(), outputPath);
        ProgressHolder progressHolder = new ProgressHolder();
        mainHandler = new Handler(Looper.getMainLooper());
        mainHandler.post(
                new Runnable() {
                    @Override
                    public void run() {
                        if (transformer != null
                                && transformer.getProgress(progressHolder) != PROGRESS_STATE_NOT_STARTED) {
                            progressIndicator.setProgress(progressHolder.progress);
                            mainHandler.postDelayed(/* r= */ this, /* delayMillis= */ 500);
                        }
                    }
                });
    }

    @UnstableApi
    Transformer.Listener transformerListener =
            new Transformer.Listener() {
                @Override
                public void onCompleted(Composition composition, ExportResult result) {
                    // playOutput();
                    Toast.makeText(ExoPlayerTry.this, "Done ", Toast.LENGTH_LONG).show();
                }

                @Override
                public void onError(Composition composition, ExportResult result,
                                    ExportException exception) {
                    // displayError(exception);
                    Toast.makeText(ExoPlayerTry.this, "" + exception.toString(), Toast.LENGTH_SHORT).show();
                    Log.e("TAG", "Export error", exception);
                }
            };

    private File createOutputFile() throws IOException {
        String videoFileName = "video_" + System.currentTimeMillis() + ".mp4";
        File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES), videoFileName);
        if (file.exists() && !file.delete()) {
            throw new IllegalStateException("Could not delete the previous export output file");
        }
        if (!file.createNewFile()) {
            throw new IllegalStateException("Could not create the export output file");
        }
        return file;
    }

    private void releasePlayer() {
        if (outputPlayer != null) {
            outputPlayer.release();
            outputPlayer = null;
        }
    }

    public void PreviewComposition() {
        releasePlayer();
        this.outputPlayerView.setPlayer(null);
        //Composition composition = createoOwnComposition();
        Composition composition = myComposition();
        CompositionPlayer player = new CompositionPlayer.Builder(getApplicationContext()).build();
        this.outputPlayer = player;
        this.outputPlayerView.setPlayer(outputPlayer);
        this.outputPlayerView.setControllerAutoShow(false);
        player.setComposition(composition);
        player.addListener(
                new Player.Listener() {
                    @Override
                    public void onPlayerError(PlaybackException error) {
                        Toast.makeText(getApplicationContext(), "Preview error: " + error, Toast.LENGTH_LONG)
                                .show();
                        Log.e("TAG", "Preview error", error);
                    }
                });

        player.prepare();
        player.play();
    }

    VideoCompositorSettings pictureInPictureVideoCompositorSettings =
            new VideoCompositorSettings() {
                @Override
                public Size getOutputSize(List<Size> inputSizes) {
                    return inputSizes.get(0);
                }

                @Override
                public OverlaySettings getOverlaySettings(int inputId, long presentationTimeUs) {
                    if (inputId == 0) {
                        // This tests all OverlaySettings builder variables.
                        return new OverlaySettings.Builder()
                                .setScale(.25f, .25f)
                                .setOverlayFrameAnchor(1, -1)
                                .setBackgroundFrameAnchor(.9f, -.7f)
                                .build();
                    } else {
                        return new OverlaySettings.Builder().build();
                    }
                }
            };

    private static final long ONE_FRAME_DURATION_MS = 35;

    private static EditedMediaItem editedMediaItemByClippingVideo(String uri, List<Effect> effects) {
        return new EditedMediaItem.Builder(
                MediaItem.fromUri(uri)
                        .buildUpon()
                        .setClippingConfiguration(
                                new MediaItem.ClippingConfiguration.Builder()
                                        .setEndPositionMs(ONE_FRAME_DURATION_MS)
                                        .build())
                        .build())
                .setRemoveAudio(true)
                .setEffects(
                        new Effects(/* audioProcessors= */ ImmutableList.of(), ImmutableList.copyOf(effects))).setDurationUs(1000)
                .build();
    }

    private static Composition createComposition(
            List<Effect> compositionEffects,
            List<EditedMediaItem> firstSequenceMediaItems,
            List<EditedMediaItem> secondSequenceMediaItems,
            VideoCompositorSettings videoCompositorSettings) {

        return new Composition.Builder(
                ImmutableList.of(
                        new EditedMediaItemSequence(firstSequenceMediaItems),
                        new EditedMediaItemSequence(secondSequenceMediaItems)))
                .setEffects(
                        new Effects(
                                /* audioProcessors= */ ImmutableList.of(), /* videoEffects= */ compositionEffects))
                .setVideoCompositorSettings(videoCompositorSettings)
                .build();
    }

    public Composition myComposition() {
        Composition composition =
                createComposition(
                        /* compositionEffects= */ ImmutableList.of(
                                new Contrast(0.1f),
                                Presentation.createForWidthAndHeight(
                                        500, 500, Presentation.LAYOUT_SCALE_TO_FIT)),
                        /* firstSequenceMediaItems= */ ImmutableList.of(
                                editedMediaItemByClippingVideo(
                                        String.valueOf(VideoUri),
                                        /* effects= */ ImmutableList.of(
                                                new AlphaScale(0.5f),
                                                new ScaleAndRotateTransformation.Builder()
                                                        .setRotationDegrees(180)
                                                        .build()))),
                        /* secondSequenceMediaItems= */ ImmutableList.of(
                                editedMediaItemByClippingVideo(
                                        String.valueOf(VideoUri2), /* effects= */ ImmutableList.of())),
                        pictureInPictureVideoCompositorSettings);

        return composition;
    }

This is the Preview composition method

 public void PreviewComposition() {
        releasePlayer();
        this.outputPlayerView.setPlayer(null);
        //Composition composition = createoOwnComposition();
        Composition composition = myComposition();
        CompositionPlayer player = new CompositionPlayer.Builder(getApplicationContext()).build();
        this.outputPlayer = player;
        this.outputPlayerView.setPlayer(outputPlayer);
        this.outputPlayerView.setControllerAutoShow(false);
        player.setComposition(composition);
        player.addListener(
                new Player.Listener() {
                    @Override
                    public void onPlayerError(PlaybackException error) {
                        Toast.makeText(getApplicationContext(), "Preview error: " + error, Toast.LENGTH_LONG)
                                .show();
                        Log.e("TAG", "Preview error", error);
                    }
                });

        player.prepare();
        player.play();
    }

and the my composition method

public Composition myComposition() {
        Composition composition =
                createComposition(
                        /* compositionEffects= */ ImmutableList.of(
                                new Contrast(0.1f),
                                Presentation.createForWidthAndHeight(
                                        500, 500, Presentation.LAYOUT_SCALE_TO_FIT)),
                        /* firstSequenceMediaItems= */ ImmutableList.of(
                                editedMediaItemByClippingVideo(
                                        String.valueOf(VideoUri),
                                        /* effects= */ ImmutableList.of(
                                                new AlphaScale(0.5f),
                                                new ScaleAndRotateTransformation.Builder()
                                                        .setRotationDegrees(180)
                                                        .build()))),
                        /* secondSequenceMediaItems= */ ImmutableList.of(
                                editedMediaItemByClippingVideo(
                                        String.valueOf(VideoUri2), /* effects= */ ImmutableList.of())),
                        pictureInPictureVideoCompositorSettings);

        return composition;
    }

when I try to create a video using Transformer it creates the video however When I try to preview the composition I get the following error

 FATAL EXCEPTION: main (Ask Gemini)
  Process: org.own.media14beta, PID: 20379
 java.lang.IllegalArgumentException
  at androidx.media3.common.util.Assertions.checkArgument(Assertions.java:40)
   at androidx.media3.transformer.EditedMediaItem.getPresentationDurationUs(EditedMediaItem.java:297)
   at androidx.media3.transformer.CompositionPlayer.getSequenceDurationUs(CompositionPlayer.java:809)
   at androidx.media3.transformer.CompositionPlayer.getCompositionDurationUs(CompositionPlayer.java:792)
   at androidx.media3.transformer.CompositionPlayer.setCompositionInternal(CompositionPlayer.java:586)
   at androidx.media3.transformer.CompositionPlayer.setComposition(CompositionPlayer.java:321)
   at org.own.media14beta.ExoPlayerTry.PreviewComposition(ExoPlayerTry.java:218)
   at org.own.media14beta.ExoPlayerTry.lambda$onCreate$3$org-own-media14beta-ExoPlayerTry(ExoPlayerTry.java:138)
   at org.own.media14beta.ExoPlayerTry$$ExternalSyntheticLambda3.onClick(D8$$SyntheticClass:0)
   at android.view.View.performClick(View.java:8043)
   at android.widget.TextView.performClick(TextView.java:17817)
   at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1218)
   at android.view.View.performClickInternal(View.java:8020)
   at android.view.View.-$$Nest$mperformClickInternal(Unknown Source:0)
   at android.view.View$PerformClick.run(View.java:31867)
   at android.os.Handler.handleCallback(Handler.java:958)
   at android.os.Handler.dispatchMessage(Handler.java:99)
   at android.os.Looper.loopOnce(Looper.java:230)
   at android.os.Looper.loop(Looper.java:319)
   at android.app.ActivityThread.main(ActivityThread.java:8913)
   at java.lang.reflect.Method.invoke(Native Method)
   at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:608)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
droid-girl commented 1 week ago

Hi @pawaom , Please keep in mind that CompositionPlayer is still under active development and work-in-progress and @RestrictTo to indicate that this API should not be used outside of the library. This type of Composition that you are trying to build is not supported at the moment and this is the reason you are not able to preview your Composition. CompositionPlayer only supports single video input at the moment. Please keep an eye on future releases for any announcements.

pawaom commented 1 week ago

can this be tagged as enhancement so that we can track the development