ממשקי ה-API של Transformer ב-Jetpack Media3 מיועדים ליצירת מדיה עם ביצועים טובים ואמינים. הטרנספורמר תומך במספר פעולות כולל:
- שינוי סרטון באמצעות חיתוך, שינוי קנה מידה וסיבוב
- הוספת אפקטים כמו שכבות-על ופילטרים
- עיבוד פורמטים מיוחדים כמו HDR וסרטונים בהילוך איטי
- ייצוא של פריט מדיה אחרי החלת שינויי העריכה
בדף הזה מפורטים תרחישים עיקריים לדוגמה Transformer. לקבלת פרטים נוספים, אפשר לעיין במדריכים המלאים שלנו Media3 Transformer.
שנתחיל?
כדי להתחיל, צריך להוסיף תלות במודולים Transformer, Impact ו-Common של Jetpack Media3:
implementation "androidx.media3:media3-transformer:1.4.1" implementation "androidx.media3:media3-effect:1.4.1" implementation "androidx.media3:media3-common:1.4.1"
חשוב להחליף את 1.4.1
בגרסה המועדפת של
לספרייה. ניתן לעיין
נתוני גרסה
כדי לראות את הגרסה העדכנית ביותר.
כיתות חשובות
דרגה | המטרה |
---|---|
Transformer |
איך מתחילים ומפסיקים טרנספורמציות ובודקים אם יש עדכוני התקדמות בטרנספורמציה פעילה. |
EditedMediaItem |
מייצג פריט מדיה לעיבוד ואת העריכות שיש להחיל עליו. |
Effects |
אוסף של אפקטים של וידאו ואודיו. |
הגדרת הפלט
עם Transformer.Builder
, עכשיו אפשר לציין videoMimeType
ו
הספרייה audioMimetype
על ידי הגדרת הפונקציה בלי שיהיה צורך ליצור
אובייקט TransformationRequest
.
המרת קידוד בין פורמטים
הקוד הבא מראה איך להגדיר אובייקט Transformer
פלט וידאו H.265/AVC ו-AAC אודיו:
Kotlin
val transformer = Transformer.Builder(context) .setVideoMimeType(MimeTypes.VIDEO_H265) .setAudioMimeType(MimeTypes.AUDIO_AAC) .build()
Java
Transformer transformer = new Transformer.Builder(context) .setVideoMimeType(MimeTypes.VIDEO_H265) .setAudioMimeType(MimeTypes.AUDIO_AAC) .build();
אם הפורמט של המדיה שהוזן כבר תואם לבקשת הטרנספורמציה של האודיו או וידאו, טרנספורמר עובר באופן אוטומטי לטרנספורמציה, כלומר העתקה את הדגימות הדחוסות ממאגר הקלט למאגר הפלט, שינוי. כך נמנעת עלות החישובית ואובדן איכות פוטנציאלי ומקודדים מחדש באותו פורמט.
הגדרת מצב HDR
אם קובץ המדיה והקלט הוא בפורמט HDR, אפשר לבחור מבין כמה
מצבים שונים לאופן שבו טרנספורמר מעבד את המידע של ה-HDR. סביר להניח
שרוצים להשתמש באחת מהאפשרויות הבאות: HDR_MODE_KEEP_HDR
או
HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL
.
HDR_MODE_KEEP_HDR |
HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL |
|
---|---|---|
תיאור | שימור נתוני HDR – כלומר, פורמט הפלט של HDR זהה לפורמט הקלט של HDR. | מיפוי גוונים של קלט HDR ל-SDR באמצעות מיפוי גוונים של OpenGL, כלומר פורמט הפלט יהיה ב-SDR. |
תמיכה | האפשרות הזו נתמכת ברמות API 31 ומעלה במכשירים שכוללים מקודד עם היכולת FEATURE_HdrEditing . |
נתמך ברמות API 29 ומעלה. |
שגיאות | אם היא לא נתמכת, אפשר לנסות להשתמש ב-HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL במקום זאת. |
אם אין תמיכה בפעולה הזו, הפונקציה תחזיר ExportException . |
במכשירים שתומכים ביכולות הקידוד הנדרשות עם Android 13
(רמת API 33) ואילך, אובייקטים מסוג Transformer
מאפשרים לערוך סרטוני HDR.
HDR_MODE_KEEP_HDR
הוא מצב ברירת המחדל כשיוצרים את האובייקט Composition
,
כפי שמוצג בקוד הבא:
Kotlin
val composition = Composition.Builder( ImmutableList.of(videoSequence)) .setHdrMode(HDR_MODE_KEEP_HDR) .build()
Java
Composition composition = new Composition.Builder( ImmutableList.of(videoSequence)) .setHdrMode(Composition.HDR_MODE_KEEP_HDR) .build();
הכנה של פריט מדיה
MediaItem
מייצג אודיו
או פריט סרטון באפליקציה. האפליקציה EditedMediaItem
אוספת MediaItem
לאורך
לטרנספורמציות שחלות עליו.
חיתוך סרטון
כדי להסיר קטעים לא רצויים מהסרטון, אפשר להגדיר התחלה וסיום מותאמים אישית
על ידי הוספת ClippingConfiguration
ל-MediaItem
.
Kotlin
val clippingConfiguration = MediaItem.ClippingConfiguration.Builder() .setStartPositionMs(10_000) // start at 10 seconds .setEndPositionMs(20_000) // end at 20 seconds .build() val mediaItem = MediaItem.Builder() .setUri(videoUri) .setClippingConfiguration(clippingConfiguration) .build()
Java
ClippingConfiguration clippingConfiguration = new MediaItem.ClippingConfiguration.Builder() .setStartPositionMs(10_000) // start at 10 seconds .setEndPositionMs(20_000) // end at 20 seconds .build(); MediaItem mediaItem = new MediaItem.Builder() .setUri(videoUri) .setClippingConfiguration(clippingConfiguration) .build();
שימוש באפקטים מובנים
Media3 כולל כמה אפקטים מובנים של וידאו לטרנספורמציות נפוצות, לדוגמה:
דרגה | אפקט |
---|---|
Presentation |
שינוי הגודל של פריט המדיה לפי רזולוציה או יחס גובה-רוחב |
ScaleAndRotateTransformation |
שינוי גודל פריט המדיה במכפיל או סיבוב פריט המדיה |
Crop |
חיתוך פריט המדיה למסגרת קטנה או גדולה יותר |
OverlayEffect |
מוסיפים שכבת-על של טקסט או תמונה מעל פריט המדיה |
כדי להשתמש באפקטים קוליים, אפשר להוסיף רצף של
AudioProcessor
שישנו את נתוני האודיו הגולמיים (PCM). לדוגמה, אפשר להשתמש ב-
ChannelMixingAudioProcessor
כדי לשלב ולהתאים ערוצי אודיו.
כדי להשתמש באפקטים האלה, צרו מופע של האפקט או מעבד האודיו,
מופע של Effects
עם האפקטים של האודיו והווידאו שרוצים להחיל עליהם
פריט המדיה, ואז מוסיפים את האובייקט Effects
אל EditedMediaItem
.
Kotlin
val channelMixingProcessor = ChannelMixingAudioProcessor() val rotateEffect = ScaleAndRotateTransformation.Builder().setRotationDegrees(60f).build() val cropEffect = Crop(-0.5f, 0.5f, -0.5f, 0.5f) val effects = Effects(listOf(channelMixingProcessor), listOf(rotateEffect, cropEffect)) val editedMediaItem = EditedMediaItem.Builder(mediaItem) .setEffects(effects) .build()
Java
ChannelMixingAudioProcessor channelMixingProcessor = new ChannelMixingAudioProcessor(); ScaleAndRotateTransformation rotateEffect = new ScaleAndRotateTransformation.Builder() .setRotationDegrees(60f) .build(); Crop cropEffect = new Crop(-0.5f, 0.5f, -0.5f, 0.5f); Effects effects = new Effects( ImmutableList.of(channelMixingProcessor), ImmutableList.of(rotateEffect, cropEffect) ); EditedMediaItem editedMediaItem = new EditedMediaItem.Builder(mediaItem) .setEffects(effects) .build();
יצירת אפקטים בהתאמה אישית
אם מרחיבים את האפקטים ב-Media3 אפשר ליצור אפקטים בהתאמה אישית.
ספציפיים לתרחישים לדוגמה שלכם. בדוגמה הבאה, משתמשים במחלקה משנית.
MatrixTransformation
כדי להגדיל את התצוגה של הסרטון כך שימלא את הפריים.
שני ההפעלה:
Kotlin
val zoomEffect = MatrixTransformation { presentationTimeUs -> val transformationMatrix = Matrix() // Set the scaling factor based on the playback position val scale = min(1f, presentationTimeUs / 1_000f) transformationMatrix.postScale(/* x */ scale, /* y */ scale) transformationMatrix } val editedMediaItem = EditedMediaItem.Builder(inputMediaItem) .setEffects(Effects(listOf(), listOf(zoomEffect)) .build()
Java
MatrixTransformation zoomEffect = presentationTimeUs -> { Matrix transformationMatrix = new Matrix(); // Set the scaling factor based on the playback position float scale = min(1f, presentationTimeUs / 1_000f); transformationMatrix.postScale(/* x */ scale, /* y */ scale); return transformationMatrix; }; EditedMediaItem editedMediaItem = new EditedMediaItem.Builder(inputMediaItem) .setEffects(new Effects(ImmutableList.of(), ImmutableList.of(zoomEffect))) .build();
כדי להתאים אישית את ההתנהגות של אפקט,
GlShaderProgram
השיטה queueInputFrame()
משמשת לעיבוד פריימים של קלט. לדוגמה, כדי
למנף את יכולות למידת המכונה
MediaPipe, אפשר להשתמש
MediaPipe FrameProcessor
לשלוח כל פריים באמצעות תרשים MediaPipe. אפשר לראות דוגמה לכך
אפליקציית ההדגמה של Transformer.
תצוגה מקדימה של אפקטים
ב-ExoPlayer אפשר לראות תצוגה מקדימה של האפקטים
נוסף לפריט מדיה לפני התחלת תהליך הייצוא. שימוש באותה
אובייקט Effects
לגבי EditedMediaItem
, קוראים לפונקציה setVideoEffects()
מופע של ExoPlayer.
Kotlin
val player = ExoPlayer.builder(context) .build() .also { exoPlayer -> exoPlayer.setMediaItem(inputMediaItem) exoPlayer.setVideoEffects(effects) exoPlayer.prepare() }
Java
ExoPlayer player = new ExoPlayer.builder(context).build(); player.setMediaItem(inputMediaItem); player.setVideoEffects(effects); exoPlayer.prepare();
אפשר גם לראות אפקטים קוליים בתצוגה מקדימה באמצעות ExoPlayer. כשאתם יוצרים את
במכונה ExoPlayer
, מעבירים ב-RenderersFactory
בהתאמה אישית שמגדיר את
את מעבדי האודיו של הנגן כדי להפיק אודיו אל AudioSink
שמשתמש
רצף AudioProcessor
. בדוגמה הבאה אנחנו עושים זאת על ידי שינוי
buildAudioSink()
של DefaultRenderersFactory
.
Kotlin
val player = ExoPlayer.Builder(context, object : DefaultRenderersFactory(context) { override fun buildAudioSink( context: Context, enableFloatOutput: Boolean, enableAudioTrackPlaybackParams: Boolean, enableOffload: Boolean ): AudioSink? { return DefaultAudioSink.Builder(context) .setEnableFloatOutput(enableFloatOutput) .setEnableAudioTrackPlaybackParams(enableAudioTrackPlaybackParams) .setOffloadMode(if (enableOffload) { DefaultAudioSink.OFFLOAD_MODE_ENABLED_GAPLESS_REQUIRED } else { DefaultAudioSink.OFFLOAD_MODE_DISABLED }) .setAudioProcessors(arrayOf(channelMixingProcessor)) .build() } }).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context, new DefaultRenderersFactory(context) { @Nullable @Override protected AudioSink buildAudioSink( Context context, boolean enableFloatOutput, boolean enableAudioTrackPlaybackParams, boolean enableOffload ) { return new DefaultAudioSink.Builder(context) .setEnableFloatOutput(enableFloatOutput) .setEnableAudioTrackPlaybackParams(enableAudioTrackPlaybackParams) .setOffloadMode( enableOffload ? DefaultAudioSink.OFFLOAD_MODE_ENABLED_GAPLESS_REQUIRED : DefaultAudioSink.OFFLOAD_MODE_DISABLED) .setAudioProcessors(new AudioProcessor[]{channelMixingProcessor}) .build(); } }).build();
התחלת טרנספורמציה
לסיום, יוצרים Transformer
כדי להחיל את שינויי העריכה ולהתחיל לייצא את
פריט המדיה שהתקבל.
Kotlin
val transformer = Transformer.Builder(context) .addListener(listener) .build() transformer.start(editedMediaItem, outputPath)
Java
Transformer transformer = new Transformer.Builder(context) .addListener(listener) .build(); transformer.start(editedMediaItem, outputPath);
אפשר לבטל את תהליך הייצוא באופן דומה במקרה הצורך,
Transformer.cancel()
חיפוש עדכונים לגבי ההתקדמות
השדה Transformer.start
חוזר מיד ופועל באופן אסינכרוני. כדי לשלוח שאילתה על
את ההתקדמות הנוכחית של טרנספורמציה,
Transformer.getProgress()
השיטה הזו לוקחת ProgressHolder
. אם מצב ההתקדמות זמין,
כלומר, אם ה-method מחזירה PROGRESS_STATE_AVAILABLE
, אז הפונקציה
המידע על ProgressHolder
יעודכן באחוז ההתקדמות הנוכחי.
אפשר גם לצרף
listener
אל Transformer
כדי לקבל הודעה על אירועי השלמה או שגיאה.