תחילת העבודה

כדי להתחיל להשתמש ב-Transformer, צריך לבצע את השלבים הבאים:

  1. מוסיפים את Media3 Transformer כתלות בפרויקט.
  2. יוצרים EditedMediaItem שמייצג את המדיה לעיבוד ואת העריכות שרוצים לבצע בה.
  3. יוצרים Transformer, מתארים את הפלט הנדרש ומאזין לאירועי השלמה ושגיאה.
  4. מפעילים את פעולת הייצוא, מעבירים את EditedMediaItem לעריכה ואת נתיב הפלט. במהלך הייצוא, אפשר לשלוח שאילתה לגבי ההתקדמות הנוכחית או לבטל את הפעולה.
  5. כשהייצוא מסתיים, מטפלים בפלט לפי הצורך. לדוגמה, אפשר לשתף את הפלט עם אפליקציה אחרת או להעלות אותו לשרת.

בהמשך המאמר מפורטים השלבים האלה, ודוגמה מלאה מופיעה בTransformerActivity באפליקציית ההדגמה של הכלי לשינוי הגדרות.

הוספת Media3 Transformer כתלות

הדרך הכי קלה להתחיל להשתמש ב-Transformer היא להוסיף תלויות של Gradle בספרייה בקובץ build.gradle של מודול האפליקציה:

Kotlin

implementation("androidx.media3:media3-transformer:1.8.0")
implementation("androidx.media3:media3-effect:1.8.0")
implementation("androidx.media3:media3-common:1.8.0")

Groovy

implementation "androidx.media3:media3-transformer:1.8.0"
implementation "androidx.media3:media3-effect:1.8.0"
implementation "androidx.media3:media3-common:1.8.0"

כאשר 1.8.0 היא הגרסה המועדפת. כדי לדעת מהי הגרסה העדכנית, אפשר לעיין בהערות על הגרסה.

מידע נוסף על מודולי הספרייה שזמינים מופיע בדף Google Maven AndroidX Media3.

הפעלת התמיכה ב-Java 8

אם התמיכה ב-Java 8 לא מופעלת, צריך להפעיל אותה בכל הקבצים שתלויים ב-Transformer. לשם כך, מוסיפים את השורה הבאה לקטע: build.gradle android

compileOptions {
  targetCompatibility JavaVersion.VERSION_1_8
}

התחלת טרנספורמציה

הנה דוגמה ליצירת EditedMediaItem כדי להסיר אודיו מקובץ קלט, ואז ליצור ולהגדיר מופע של Transformer כדי לייצא וידאו בפורמט H.265/HEVC, ולהוציא את התוצאה ל-outputPath.

Kotlin

val inputMediaItem = MediaItem.fromUri("path_to_input_file")
val editedMediaItem =
    EditedMediaItem.Builder(inputMediaItem).setRemoveAudio(true).build()
val transformer = Transformer.Builder(context)
    .setVideoMimeType(MimeTypes.VIDEO_H265)
    .addListener(transformerListener)
    .build()
transformer.start(editedMediaItem, outputPath)

Java

MediaItem inputMediaItem = MediaItem.fromUri("path_to_input_file");
EditedMediaItem editedMediaItem =
    new EditedMediaItem.Builder(inputMediaItem).setRemoveAudio(true).build();
Transformer transformer =
    new Transformer.Builder(context)
        .setVideoMimeType(MimeTypes.VIDEO_H265)
        .addListener(transformerListener)
        .build();
transformer.start(editedMediaItem, outputPath);

מידע נוסף על פריטי מדיה זמין בדף פריטי מדיה ב-ExoPlayer. הקלט יכול להיות סטרימינג פרוגרסיבי או סטרימינג אדפטיבי, אבל הפלט הוא תמיד סטרימינג פרוגרסיבי. במקרים של קלט דינמי, תמיד נבחרים הרצועות ברזולוציה הכי גבוהה לצורך השינוי. הקלט יכול להיות בכל פורמט קונטיינר נתמך על ידי ExoPlayer, אבל הפלט הוא תמיד קובץ MP4.

אפשר להפעיל כמה פעולות ייצוא ברצף באותו מופע Transformer, אבל אי אפשר להפעיל כמה פעולות ייצוא בו-זמנית באותו מופע.

הערה לגבי שרשור

צריך לגשת למופעי Transformer משרשור יחיד של אפליקציה, והשיטות של listener נקראות באותו שרשור. ברוב המקרים, שרשור הבקשה יכול להיות פשוט השרשור הראשי של האפליקציה. באופן פנימי, רכיב ה-Transformer מבצע את העבודה שלו ברקע ושולח את הקריאות שלו לשיטות של listener בשרשור האפליקציה.

האזנה לאירועים

השיטה start היא אסינכרונית. היא מחזירה ערך באופן מיידי והאפליקציה מקבלת הודעה על אירועים דרך ה-listener שמועבר אל Transformer builder.

Kotlin

val transformerListener: Transformer.Listener =
    object : Transformer.Listener {
  override fun onCompleted(composition: Composition, result: ExportResult) {
    playOutput()
  }

  override fun onError(composition: Composition, result: ExportResult,
                       exception: ExportException) {
    displayError(exception)
  }
}

Java

Transformer.Listener transformerListener =
    new Transformer.Listener() {
      @Override
      public void onCompleted(Composition composition, ExportResult result) {
        playOutput();
      }

      @Override
      public void onError(Composition composition, ExportResult result,
          ExportException exception) {
        displayError(exception);
      }
    };

ExportResult כולל מידע על קובץ הפלט, כולל גודל הקובץ וקצב הביטים הממוצע של האודיו והסרטון, לפי הצורך.

קבלת עדכוני התקדמות

מתקשרים אל Transformer.getProgress כדי לשאול על ההתקדמות הנוכחית של המרה. הערך שמוחזר מציין את מצב ההתקדמות. אם מצב ההתקדמות הוא PROGRESS_STATE_AVAILABLE, הערך של ProgressHolder מתעדכן באחוז ההתקדמות הנוכחי. בדוגמה הבאה אפשר לראות איך לשלוח שאילתה מעת לעת כדי לבדוק את התקדמות ההמרה, ואיך אפשר להטמיע את המתודה updateProgressInUi כדי לעדכן את סרגל ההתקדמות.

Kotlin

transformer.start(inputMediaItem, outputPath)
val progressHolder = ProgressHolder()
mainHandler.post(
    object : Runnable {
      override fun run() {
        val progressState: @ProgressState Int = transformer.getProgress(progressHolder)
        updateProgressInUi(progressState, progressHolder)
        if (progressState != Transformer.PROGRESS_STATE_NOT_STARTED) {
          mainHandler.postDelayed(/* r= */this,  /* delayMillis= */500)
        }
      }
    }
)

Java

transformer.start(inputMediaItem, outputPath);
ProgressHolder progressHolder = new ProgressHolder();
mainHandler.post(
    new Runnable() {
      @Override
      public void run() {
        @Transformer.ProgressState int progressState = transformer.getProgress(progressHolder);
        updateProgressInUi(progressState, progressHolder);
        if (progressState != PROGRESS_STATE_NOT_STARTED) {
          mainHandler.postDelayed(/* r= */ this, /* delayMillis= */ 500);
        }
      }
    });

ביטול טרנספורמציה

אם המשתמש בוחר לצאת מתהליך הייצוא, צריך לבטל את פעולת הייצוא באמצעות Transformer.cancel. משאבים כמו רכיבי codec של וידאו בחומרה הם מוגבלים, במיוחד במכשירים ברמת כניסה, ולכן חשוב לעשות את זה כדי לפנות משאבים אם אין צורך בפלט.