תחילת העבודה

כדי להתחיל להשתמש ב-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.7.1")
implementation("androidx.media3:media3-effect:1.7.1")
implementation("androidx.media3:media3-common:1.7.1")

מגניב

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

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

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

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

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

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 של וידאו בחומרה הם מוגבלים, במיוחד במכשירים ברמה נמוכה, ולכן חשוב לעשות את זה כדי לפנות משאבים אם לא צריך את הפלט.