Transformacje

Transkodowanie między formatami

Podczas tworzenia transformatora możesz określić formaty wyjściowe audio i wideo. Na przykład poniższy kod pokazuje, jak skonfigurować transformator, aby generował wideo H.264/AVC i dźwięk AAC:

Kotlin

Transformer.Builder(context)
  .setVideoMimeType(MimeTypes.VIDEO_H264)
  .setAudioMimeType(MimeTypes.AUDIO_AAC)
  .build()

Java

new Transformer.Builder(context)
    .setVideoMimeType(MimeTypes.VIDEO_H264)
    .setAudioMimeType(MimeTypes.AUDIO_AAC)
    .build();

Jeśli format multimediów wejściowych jest zgodny z konfiguracjami audio lub wideo, transformator automatycznie przełącza się na transmuksowanie, czyli kopiowanie skompresowanych próbek z kontenera wejściowego do kontenera wyjściowego bez modyfikacji. Pozwala to uniknąć kosztów obliczeniowych i potencjalnej utraty jakości związanej z dekodowaniem i ponownym kodowaniem w tym samym formacie.

Usuwanie dźwięku lub wideo

Aby usunąć dźwięk lub wideo, użyj EditedMediaItem.Builder, na przykład:

Kotlin

EditedMediaItem.Builder(inputMediaItem).setRemoveAudio(true).build()

Java

new EditedMediaItem.Builder(inputMediaItem).setRemoveAudio(true).build();

Przycinanie klipu

Możesz usunąć wszystkie multimedia poza określonymi sygnaturami czasowymi początku i końca, ustawiając konfigurację przycinania w elemencie multimediów wejściowych. Aby na przykład utworzyć klip zawierający tylko multimedia między 10 a 20 sekundą:

Kotlin

val inputMediaItem =
  MediaItem.Builder()
    .setUri(uri)
    .setClippingConfiguration(
      MediaItem.ClippingConfiguration.Builder()
        .setStartPositionMs(10_000)
        .setEndPositionMs(20_000)
        .build()
    )
    .build()

Java

MediaItem inputMediaItem =
    new MediaItem.Builder()
        .setUri(uri)
        .setClippingConfiguration(
            new MediaItem.ClippingConfiguration.Builder()
                .setStartPositionMs(10_000)
                .setEndPositionMs(20_000)
                .build())
        .build();

Listy edycji MP4

Aby przyspieszyć przycinanie, transformator obsługuje listy edycji MP4, co pozwala na bardziej wydajne edycje „tylko przycinanie” bez pełnego ponownego transkodowania wideo. Ta metoda wykorzystuje istniejące zakodowane próbki i „reklamę przed filmem” na liście edycji, która instruuje odtwarzacz, aby rozpoczął odtwarzanie w określonym momencie, skutecznie pomijając niechciany segment początkowy.

Aby znacznie przyspieszyć edycje „tylko przycinanie”, wywołaj experimentalSetMp4EditListTrimEnabled(true).

Kotlin

Transformer.Builder(context).experimentalSetMp4EditListTrimEnabled(true).build()

Java

new Transformer.Builder(context).experimentalSetMp4EditListTrimEnabled(true).build();
Pamiętaj, że nie wszystkie odtwarzacze multimediów obsługują pozycję „reklama przed filmem”. Oznacza to, że gdy używany jest taki odtwarzacz, odtwarzanie pliku rozpocznie się od samego początku zakodowanej próbki, niezależnie od informacji na liście edycji, które mogą określać inny punkt początkowy.

Optymalizacja przycinania

Aby zmniejszyć opóźnienie przycinania początku filmu, włącz optymalizację przycinania.

Kotlin

Transformer.Builder(context).experimentalSetTrimOptimizationEnabled(true).build()

Java

new Transformer.Builder(context).experimentalSetTrimOptimizationEnabled(true).build();

Przyspiesza to eksportowanie, ponieważ dekoduje i ponownie koduje jak najmniejszą część filmu, a następnie łączy ponownie zakodowane dane z resztą oryginalnego filmu. Optymalizacja polega na możliwości połączenia części pliku wejściowego z nowo zakodowanym wyjściem, co oznacza, że format wyjściowy kodera i format wejściowy muszą być zgodne. Jeśli na przykład plik został pierwotnie utworzony na urządzeniu z inną implementacją kodera, prawdopodobnie nie będzie można zastosować optymalizacji. Aby optymalizacja się powiodła, koder dostarczony do transformatora za pomocą EncoderFactory musi mieć poziom i profil zgodne z formatem wejściowym.

Ta optymalizacja działa tylko w przypadku wejściowego pliku MP4 z jednym zasobem bez efektów, z wyjątkiem efektów wideo no-op i obrotów podzielnych przez 90 stopni. Jeśli optymalizacja się nie powiedzie, transformator automatycznie przełączy się na normalny eksport i zgłosi wynik optymalizacji w ExportResult.OptimizationResult.

Sprawdzamy tę funkcję i oczekujemy, że w przyszłej wersji przestanie być eksperymentalna.

Zmiany w filmach

EditedMediaItems mają listy procesorów audio i efektów wideo, które należy zastosować w odpowiedniej kolejności. Biblioteka zawiera implementacje efektów wideo w typowych przypadkach użycia. Możesz też napisać własne efekty i przekazać je podczas tworzenia edytowanych elementów multimediów.

Możesz zmienić skalę multimediów, co może być przydatne, aby zaoszczędzić zasoby przetwarzania lub przepustowość podczas pracy z danymi wejściowymi o bardzo wysokiej rozdzielczości, takimi jak filmy 4K lub 8K. Aby na przykład proporcjonalnie przeskalować do wysokości 480 pikseli:

Kotlin

EditedMediaItem.Builder(MediaItem.fromUri(uri))
  .setEffects(
    Effects(
      /* audioProcessors= */ listOf(),
      /* videoEffects= */ listOf(Presentation.createForHeight(480)),
    )
  )
  .build()

Java

new EditedMediaItem.Builder(MediaItem.fromUri(uri))
    .setEffects(
        new Effects(
            /* audioProcessors= */ ImmutableList.of(),
            /* videoEffects= */ ImmutableList.of(Presentation.createForHeight(480))))
    .build();

Możesz też skalować według danego współczynnika, np. aby zmniejszyć rozmiar o połowę:

Kotlin

val editedMediaItem =
  EditedMediaItem.Builder(MediaItem.fromUri(uri))
    .setEffects(
      Effects(
        /* audioProcessors= */ listOf(),
        /* videoEffects= */ listOf(
          ScaleAndRotateTransformation.Builder().setScale(.5f, .5f).build()
        ),
      )
    )
    .build()

Java

new EditedMediaItem.Builder(MediaItem.fromUri(uri))
    .setEffects(
        new Effects(
            /* audioProcessors= */ ImmutableList.of(),
            /* videoEffects= */ ImmutableList.of(
                new ScaleAndRotateTransformation.Builder().setScale(.5f, .5f).build())))
    .build();

W ten sam sposób możesz skonfigurować obrót:

Kotlin

EditedMediaItem.Builder(MediaItem.fromUri(uri))
  .setEffects(
    Effects(
      /* audioProcessors= */ listOf(),
      /* videoEffects= */ listOf(
        ScaleAndRotateTransformation.Builder().setRotationDegrees(90f).build()
      ),
    )
  )
  .build()

Java

new EditedMediaItem.Builder(MediaItem.fromUri(uri))
    .setEffects(
        new Effects(
            /* audioProcessors= */ ImmutableList.of(),
            /* videoEffects= */ ImmutableList.of(
                new ScaleAndRotateTransformation.Builder().setRotationDegrees(90f).build())))
    .build();

Niestandardowe efekty wideo

Konstruktor Effects akceptuje listę efektów audio i wideo do zastosowania. Wewnętrznie framework efektów transformatora przekształca listę efektów wideo w sekwencję programów cieniowania GL, które są stosowane w odpowiedniej kolejności. W niektórych przypadkach framework efektów może zastosować wiele efektów za pomocą jednego programu cieniowania. Na przykład jeden program cieniowania może zastosować kilka kolejnych przekształceń macierzowych, co zwiększa wydajność i jakość.

Efekty wideo są też obsługiwane w przypadku podglądu w ExoPlayer za pomocą ExoPlayer.setVideoEffects. Przykład użycia tego interfejsu API znajdziesz w aplikacji demonstracyjnej efektów.

Aplikacja w wersji demonstracyjnej zawiera przykłady niestandardowych efektów wideo.

Obraz wejściowy

Transformator obsługuje obrazy wejściowe, traktując je jako statyczne klipy wideo. Aby skonfigurować obraz jako źródło sygnału, wykonaj następujące czynności:

  • Utwórz MediaItem za pomocą MediaItem.Builder. Określ czas wyświetlania obrazu w filmie wyjściowym, wywołując setImageDurationMs.

  • Utwórz EditedMediaItem otaczający MediaItem. Określ docelową liczbę klatek na sekundę dla wygenerowanego strumienia wideo za pomocą EditedMediaItem.Builder#setFrameRate.

Ten przykład pokazuje, jak skonfigurować obraz wejściowy, aby wygenerować 5-sekundowy film z szybkością 30 klatek na sekundę:

Kotlin

val imageMediaItem =
  MediaItem.Builder()
    .setUri(imageUri)
    .setImageDurationMs(5000) // 5 seconds
    .build()

val editedImageItem =
  EditedMediaItem.Builder(imageMediaItem)
    .setFrameRate(30) // 30 frames per second
    .build()

Java

MediaItem imageMediaItem =
    new MediaItem.Builder()
        .setUri(imageUri)
        .setImageDurationMs(5000) // 5 seconds
        .build();
new EditedMediaItem.Builder(imageMediaItem)
    .setFrameRate(30) // 30 frames per second
    .build();

Edycja dźwięku

Efekty dźwiękowe są implementowane przez zastosowanie sekwencji instancji AudioProcessor do surowego dźwięku (PCM). ExoPlayer obsługuje przekazywanie procesorów audio do DefaultAudioSink.Builder, co umożliwia wyświetlanie podglądu edycji dźwięku.