使用AndroidX Media3的Transformer API加工视频文件

使用AndroidX Media3的Transformer API加工视频文件

Media3的Transformer API提供了一套强大的工具来对媒体文件进行处理、转换和增强。下面将详细介绍如何使用Transformer API来加工视频文件。

一、环境配置与基础概念

1. 添加Gradle依赖

dependencies {
    // Transformer核心库
    implementation 'androidx.media3:media3-transformer:1.1.1'
    // 视频处理支持
    implementation 'androidx.media3:media3-effect:1.1.1'
    // GPU加速支持
    implementation 'androidx.media3:media3-gl:1.1.1'
    // 基础库
    implementation 'androidx.media3:media3-common:1.1.1'
}

2. 添加权限

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 如果使用相机输入 -->
<uses-permission android:name="android.permission.CAMERA" />

3. Transformer核心概念

变换操作
应用变换
转码
剪辑
合并
添加滤镜
改变分辨率
调整速度
添加水印
输入视频
MediaItem
Transformer
变换操作
输出视频

二、基础用法:转换视频格式

1. 简单格式转换(MP4转MP4)

public void convertVideoFormat(Context context, Uri inputUri, Uri outputUri) {
    // 创建输入媒体项
    MediaItem mediaItem = MediaItem.fromUri(inputUri);
    
    // 创建Transformer
    Transformer transformer = new Transformer.Builder(context)
        .setOutputMimeType(MimeTypes.VIDEO_MP4) // 输出MP4格式
        .build();
    
    // 设置监听器
    transformer.start(mediaItem, outputUri);
    
    // 添加监听器(可选)
    transformer.addListener(new Transformer.Listener() {
        @Override
        public void onCompleted(Composition composition, @Nullable TransformationResult result) {
            Log.d("Transformer", "转换完成: " + outputUri);
        }
        
        @Override
        public void onError(Composition composition, TransformationException e) {
            Log.e("Transformer", "转换错误: " + e.getMessage());
        }
    });
}

2. 转换指定参数

public void convertWithParams(Context context, Uri inputUri, Uri outputUri) {
    Transformer transformer = new Transformer.Builder(context)
        .setOutputMimeType(MimeTypes.VIDEO_MP4)
        .setEncoderFactory(
            new DefaultEncoderFactory.Builder(context)
                .setEnableFallback(false) // 禁用备用编码器
                .build())
        .setVideoMimeEncoderSettings(
            new VideoEncoderSettings.Builder()
                .setBitrate(4000000) // 4Mbps
                .setFrameRate(30)
                .setWidth(1280)
                .setHeight(720)
                .build())
        .setAudioMimeEncoderSettings(
            new AudioEncoderSettings.Builder()
                .setBitrate(128000) // 128kbps
                .setSampleRate(44100)
                .setChannelCount(2)
                .build())
        .build();
    
    transformer.start(MediaItem.fromUri(inputUri), outputUri);
}

三、高级变换操作

1. 视频剪辑

public void trimVideo(Context context, Uri inputUri, Uri outputUri) {
    // 剪辑从第5秒到第15秒的片段
    long startMs = 5_000;   // 5秒
    long endMs = 15_000;   // 15秒
    
    MediaItem mediaItem = new MediaItem.Builder()
        .setUri(inputUri)
        .setClippingConfiguration(
            new MediaItem.ClippingConfiguration.Builder()
                .setStartPositionMs(startMs)
                .setEndPositionMs(endMs)
                .build())
        .build();
    
    new Transformer.Builder(context)
        .build()
        .start(mediaItem, outputUri);
}

2. 改变播放速度

public void changeVideoSpeed(Context context, Uri inputUri, Uri outputUri, float speedFactor) {
    MediaItem mediaItem = new MediaItem.Builder()
        .setUri(inputUri)
        .build();
    
    Composition composition = new Composition.Builder(
        new EditedMediaItemSequence(
            new EditedMediaItem.Builder(mediaItem)
                .setEffects(
                    new Effects(
                        Collections.emptyList(),
                        Collections.singletonList(
                            new SpeedChangeProcessor(speedFactor))))
                .build()))
        .build();
    
    new Transformer.Builder(context)
        .build()
        .start(composition, outputUri);
}

3. 添加视频滤镜

public void applyVideoFilter(Context context, Uri inputUri, Uri outputUri) {
    // 创建RGB调色滤镜
    RgbAdjustment rgbAdjustment = new RgbAdjustment.Builder()
        .setRedScale(1.2f) // 增加红色
        .setGreenScale(0.9f) // 减少绿色
        .setBlueScale(1.1f) // 增加蓝色
        .build();
    
    // 创建灰度滤镜
    GrayscaleFilter grayscaleFilter = new GrayscaleFilter();
    
    // 创建链式滤镜 - 先应用灰度,再应用调色
    ScaleToFitTransformation scaleToFit = ScaleToFitTransformation.DEFAULT;
    ImmutableList<Effect> videoEffects = new ImmutableList.Builder<Effect>()
        .add(grayscaleFilter)
        .add(rgbAdjustment)
        .build();
    
    MediaItem mediaItem = new MediaItem.Builder()
        .setUri(inputUri)
        .build();
    
    EditedMediaItem editedMediaItem = new EditedMediaItem.Builder(mediaItem)
        .setEffects(new Effects(videoEffects, Collections.emptyList()))
        .build();
    
    Composition composition = new Composition.Builder(
        new EditedMediaItemSequence(editedMediaItem))
        .build();
    
    new Transformer.Builder(context)
        .build()
        .start(composition, outputUri);
}

4. 添加水印

public void addWatermark(Context context, Uri inputUri, Uri outputUri, Bitmap watermarkBitmap) {
    // 创建水印覆盖
    OverlaySettings overlaySettings = new OverlaySettings.Builder()
        .setAnchor(OverlaySettings.ANCHOR_TYPE_TOP | OverlaySettings.ANCHOR_TYPE_RIGHT)
        .setHorizontalOffset(0.05f) // 5%边距
        .setVerticalOffset(0.05f)    // 5%边距
        .setScale(0.2f) // 原始尺寸的20%
        .build();
    
    // 创建位图覆盖
    BitmapOverlay bitmapOverlay = BitmapOverlay.createStaticBitmapOverlay(
        watermarkBitmap, overlaySettings);
    
    // 创建叠加层效果
    OverlayEffect overlayEffect = new OverlayEffect(Collections.singletonList(bitmapOverlay));
    
    // 应用到视频
    MediaItem mediaItem = new MediaItem.Builder()
        .setUri(inputUri)
        .build();
    
    EditedMediaItem editedMediaItem = new EditedMediaItem.Builder(mediaItem)
        .setEffects(new Effects(Collections.singletonList(overlayEffect), Collections.emptyList()))
        .build();
    
    Composition composition = new Composition.Builder(
        new EditedMediaItemSequence(editedMediaItem))
        .build();
    
    new Transformer.Builder(context)
        .build()
        .start(composition, outputUri);
}

四、视频合并与分割

1. 合并多个视频

public void mergeVideos(Context context, List<Uri> inputUris, Uri outputUri) {
    List<Sequence> sequences = new ArrayList<>();
    
    // 为每个输入文件创建一个序列
    for (Uri uri : inputUris) {
        MediaItem mediaItem = new MediaItem.Builder()
            .setUri(uri)
            .build();
        
        sequences.add(new EditedMediaItemSequence(mediaItem));
    }
    
    // 添加背景音乐
    MediaItem audioItem = new MediaItem.Builder()
        .setUri("asset:///background_music.mp3")
        .build();
    
    Sequence audioSequence = new EditedMediaItemSequence(
        new EditedMediaItem.Builder(audioItem).build());
    
    sequences.add(audioSequence);
    
    // 构建组合
    Composition composition = new Composition.Builder(sequences)
        .setEffects(
            new Composition.Effects(Collections.singletonList(
                // 混音设置:降低音频音量
                new ChangeVolume(0.7f))))
        .build();
    
    // 执行转换
    new Transformer.Builder(context)
        .build()
        .start(composition, outputUri);
}

2. 分割视频(创建视频片段)

public void splitVideo(
    Context context, 
    Uri inputUri, 
    File outputDir, 
    int segmentDurationSec
) {
    MediaItem mediaItem = MediaItem.fromUri(inputUri);
    
    for (int i = 0; ; i++) {
        long startMs = i * segmentDurationSec * 1000L;
        long endMs = startMs + segmentDurationSec * 1000L;
        
        if (startMs >= mediaItem.clippingConfiguration.endPositionMs) {
            break; // 超过视频长度
        }
        
        // 设置剪辑范围
        MediaItem clippedItem = new MediaItem.Builder()
            .setUri(inputUri)
            .setClippingConfiguration(
                new MediaItem.ClippingConfiguration.Builder()
                    .setStartPositionMs(startMs)
                    .setEndPositionMs(Math.min(endMs, mediaItem.clippingConfiguration.endPositionMs))
                    .build())
            .build();
        
        // 创建输出路径
        Uri outputUri = Uri.fromFile(new File(outputDir, "segment_" + i + ".mp4"));
        
        // 启动转换
        new Transformer.Builder(context)
            .build()
            .start(clippedItem, outputUri);
    }
}

五、复杂编辑组合

1. 创建画中画效果

public void pictureInPicture(
    Context context, 
    Uri mainVideoUri, 
    Uri pipVideoUri, 
    Uri outputUri
) {
    // 主视频轨道
    EditedMediaItem mainItem = new EditedMediaItem.Builder(MediaItem.fromUri(mainVideoUri))
        .setRemoveAudio(false)
        .build();
    
    // 画中画视频轨道
    ScaleToFitTransformation pipTransformation = new ScaleToFitTransformation(
        MatrixUtil.createScale(0.3f, 0.3f),  // 缩放30%
        MatrixUtil.createTranslation(0.7f, 0.7f)); // 位置
    
    Effects pipEffects = new Effects(
        Collections.singletonList(pipTransformation), 
        Collections.emptyList());
    
    EditedMediaItem pipItem = new EditedMediaItem.Builder(MediaItem.fromUri(pipVideoUri))
        .setEffects(pipEffects)
        .setRemoveAudio(true) // 移除画中画音频
        .build();
    
    // 组合视频序列
    Composition composition = new Composition.Builder(
        new Sequence(mainItem),
        new Sequence(pipItem))
        .build();
    
    // 执行转换
    new Transformer.Builder(context)
        .build()
        .start(composition, outputUri);
}

2. 添加片头片尾

public void addIntroOutro(
    Context context, 
    Uri mainVideoUri, 
    Uri introUri, 
    Uri outroUri, 
    Uri outputUri
) {
    // 创建片头
    EditedMediaItem intro = new EditedMediaItem.Builder(MediaItem.fromUri(introUri))
        .setRemoveAudio(false)
        .build();
    
    // 创建主视频
    EditedMediaItem main = new EditedMediaItem.Builder(MediaItem.fromUri(mainVideoUri))
        .setRemoveAudio(false)
        .build();
    
    // 创建片尾
    EditedMediaItem outro = new EditedMediaItem.Builder(MediaItem.fromUri(outroUri))
        .setRemoveAudio(false)
        .build();
    
    // 组合所有序列
    Composition composition = new Composition.Builder(
        new Sequence(intro),
        new Sequence(main),
        new Sequence(outro))
        .build();
    
    // 执行转换
    new Transformer.Builder(context)
        .build()
        .start(composition, outputUri);
}

六、性能优化与高级配置

1. GPU加速处理

public void gpuAcceleratedTransform(Context context, Uri inputUri, Uri outputUri) {
    Transformer transformer = new Transformer.Builder(context)
        .setVideoEffects(
            new Effects(
                Collections.singletonList(new RgbAdjustment()), // GPU支持滤镜
                Collections.emptyList()))
        .setEncoderFactory(
            new DefaultEncoderFactory.Builder(context)
                .setEnableSdrToneMapping(true) // 启用HDR转SDR
                .build())
        .setRendererFactory(
            new TransformerUtil.createDefaultRendererFactory(context)
                .setEnableDecoderFallback(true))
        .build();
    
    transformer.start(MediaItem.fromUri(inputUri), outputUri);
}

2. 内存优化策略

public void optimizedTransform(Context context, Uri inputUri, Uri outputUri) {
    // 配置内存优化策略
    DefaultAllocator allocator = new DefaultAllocator(true, 1024 * 1024); // 1MB块大小
    LoadControl loadControl = new DefaultLoadControl.Builder()
        .setAllocator(allocator)
        .setBufferDurationsMs(3000, 5000, 1000, 2000)
        .setPrioritizeTimeOverSizeThresholds(true)
        .setTargetBufferBytes(C.LENGTH_UNSET)
        .build();
    
    // 创建转换器
    Transformer transformer = new Transformer.Builder(context)
        .setLoadControl(loadControl)
        .setEncoderFactory(
            new DefaultEncoderFactory.Builder(context)
                .setEnableAsyncQueueing(true) // 异步编码
                .build())
        .build();
    
    transformer.start(MediaItem.fromUri(inputUri), outputUri);
}

3. 进度监控与取消

public void transformWithProgress(Context context, Uri inputUri, Uri outputUri) {
    Transformer transformer = new Transformer.Builder(context)
        .build();
    
    UUID jobId = UUID.randomUUID();
    TransformationRequest transformationRequest = new TransformationRequest.Builder()
        .build();
    
    transformer.start(MediaItem.fromUri(inputUri), outputUri);
    
    // 添加进度监听器
    transformer.addListener(new Transformer.Listener() {
        @Override
        public void onTransformationProgressed(Composition composition, TransformationResult result) {
            float progress = (float) result.progress * 100;
            Log.i("Transformer", "进度: " + progress + "%");
        }
        
        // ... 其他回调方法
    });
    
    // 取消示例
    new Handler(Looper.getMainLooper()).postDelayed(() -> {
        if (transformer.getState() == Transformer.STATE_STARTED) {
            transformer.cancel();
            Log.i("Transformer", "转换已取消");
        }
    }, 5000); // 5秒后取消
}

七、实战案例:创建视频处理管道

完整的视频处理流程

public void processVideoPipeline(Context context, Uri inputUri, Uri outputUri) {
    // 1. 创建复杂效果组合
    RgbAdjustment colorEffect = new RgbAdjustment.Builder()
        .setRedScale(1.1f)
        .setGreenScale(0.95f)
        .setBlueScale(1.05f)
        .build();
    
    Bitmap watermark = BitmapFactory.decodeResource(context.getResources(), R.drawable.watermark);
    BitmapOverlay watermarkOverlay = BitmapOverlay.createStaticBitmapOverlay(
        watermark,
        new OverlaySettings.Builder()
            .setScale(0.15f)
            .setAnchor(OverlaySettings.ANCHOR_TYPE_BOTTOM | OverlaySettings.ANCHOR_TYPE_RIGHT)
            .setHorizontalOffset(0.05f)
            .setVerticalOffset(0.05f)
            .build());
    
    OverlayEffect overlayEffect = new OverlayEffect(Collections.singletonList(watermarkOverlay));
    
    // 2. 添加背景音乐
    EditedMediaItem audioItem = new EditedMediaItem.Builder(
        MediaItem.fromUri("asset:///background_music.mp3"))
        .setEffects(new Effects(Collections.emptyList(), 
            Collections.singletonList(new ChangeVolume(0.5f))))
        .build();
    
    // 3. 配置视频源
    EditedMediaItem videoItem = new EditedMediaItem.Builder(MediaItem.fromUri(inputUri))
        .setEffects(new Effects(
            Arrays.asList(colorEffect, overlayEffect),
            Collections.emptyList()))
        .build();
    
    // 4. 添加片头片尾
    EditedMediaItem introItem = new EditedMediaItem.Builder(
        MediaItem.fromUri("asset:///intro.mp4"))
        .build();
    
    EditedMediaItem outroItem = new EditedMediaItem.Builder(
        MediaItem.fromUri("asset:///outro.mp4"))
        .build();
    
    // 5. 创建时间线
    Sequence introSequence = new Sequence(introItem);
    Sequence videoSequence = new Sequence(videoItem);
    Sequence outroSequence = new Sequence(outroItem);
    Sequence audioSequence = new Sequence(audioItem);
    
    // 6. 构建组合
    Composition composition = new Composition.Builder(
        introSequence,
        videoSequence,
        outroSequence,
        audioSequence)
        .setEffects(new Composition.Effects(
            Collections.singletonList(new ScaleToFitTransformation())))
        .setAudioMixingParameters(
            new AudioMixingParameters.Builder()
                .setVideoVolume(1.0f)    // 主视频音量100%
                .setAudioTrackVolume(0.5f, 0) // 音频轨道50% (第一个轨道)
                .build())
        .build();
    
    // 7. 配置转换器
    Transformer transformer = new Transformer.Builder(context)
        .setOutputMimeType(MimeTypes.VIDEO_MP4)
        .setEncoderFactory(
            new DefaultEncoderFactory.Builder(context)
                .setEnableHdrEditing(true)
                .build())
        .setVideoEffects(
            new Effects(
                Collections.singletonList(new Contrast(1.2f)), // 整体增强对比度
                Collections.emptyList()))
        .build();
    
    // 8. 开始处理
    transformer.start(composition, outputUri);
}

八、常见问题解决

1. 错误处理与恢复

public void transformWithErrorHandling(Context context, Uri inputUri, Uri outputUri) {
    Transformer transformer = new Transformer.Builder(context)
        .build();
    
    transformer.addListener(new Transformer.Listener() {
        @Override
        public void onError(Composition composition, TransformationException e) {
            if (e.errorCode == TransformationException.ERROR_CODE_DECODING_FAILED) {
                Log.e("Transformer", "解码失败,尝试软解...");
                
                // 尝试软解
                Transformer softDecoderTransformer = new Transformer.Builder(context)
                    .setDecoderFactory(
                        new DefaultDecoderFactory.Builder()
                            .setForceSoftwareRenderer(true)
                            .build())
                    .build();
                    
                softDecoderTransformer.start(composition, outputUri);
            }
        }
        
        // ... 其他回调
    });
    
    transformer.start(MediaItem.fromUri(inputUri), outputUri);
}

2. 性能优化表

问题优化方案效果
卡顿严重降低分辨率(720p->480p)CPU降低40%
处理速度慢启用硬件编码器速度提升3-5倍
内存占用高设置帧缓冲区限制内存减少50%
输出文件大降低码率(6Mbps->3Mbps)文件大小减半
手机发热降低帧率(30fps->24fps)温度降低5°C

3. 兼容性配置

public Transformer createCompatibleTransformer(Context context) {
    return new Transformer.Builder(context)
        .setEncoderFactory(
            new DefaultEncoderFactory.Builder(context)
                .setEnableFallback(true)  // 支持备用编码器
                .setEnableAsyncQueueing(true)
                .build())
        .setDecoderFactory(
            new DefaultDecoderFactory.Builder()
                .setForceSoftwareRenderer(false)
                .setEnableFallback(true)  // 支持备用解码器
                .build())
        .setRenderersFactory(
            new DefaultRenderersFactory(context)
                .setExtensionRendererMode(RendererCapabilities.EXTENSION_RENDERER_MODE_ON)
                .build())
        .build();
}

总结

通过Media3的Transformer API,您可以实现强大的视频处理功能:

  1. 基础转换:格式转换、参数调整
  2. 编辑功能:剪辑、合并、分割
  3. 效果处理:滤镜、水印、速度调节
  4. 高级组合:画中画、片头片尾添加
  5. 性能优化:硬件加速、内存控制

核心优势:

  • 现代API:基于最新的AndroidX Media3库
  • 强大效果:支持滤镜、变速、裁剪等复杂操作
  • GPU加速:利用设备GPU提升处理速度
  • 灵活组合:通过Composition组合多个媒体源
  • 进度控制:实时监控与取消操作

最佳实践建议:

  1. 尽量使用硬件加速
  2. 对大文件分块处理
  3. 合理控制内存使用
  4. 添加进度反馈和错误处理
  5. 根据目标设备优化输出参数

Transformer API适用于多种场景:

  • 社交媒体应用:视频预处理
  • 内容创作工具:添加特效
  • 视频编辑应用:拼接剪辑
  • 企业应用:添加水印或LOGO
  • 多媒体系统:格式转换

通过本指南,您应该能够构建高效的视频处理功能,满足各种视频加工需求。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值