ExoPlayer Transformer Demo 实战指南:视频编辑导出与 MediaPipe 帧处理集成
ExoPlayer Transformer Demo 实战指南视频编辑导出与 MediaPipe 帧处理集成【免费下载链接】ExoPlayerAn extensible media player for Android项目地址: https://gitcode.com/gh_mirrors/exop/ExoPlayer本篇指南以 ExoPlayer 仓库中的demos/transformer演示应用为核心完整讲解如何利用 Transformer API 对媒体进行编辑与重编码导出例如移除音轨或视频轨、转码、缩放旋转、叠加特效与字幕等并重点剖析该 Demo 与 MediaPipe 深度集成、构建withMediaPipe变体的完整手工步骤与底层原理。读者读完可掌握 Transformer 核心 API 的调用链路、演示应用的全部可配置项以及从 MediaPipe 源码树构建 AAR 并接入 Android 工程的端到端流程。一、Transformer Demo 是什么demos/transformer/README.md 明确指出这是一个用于演示Transformer API修改视频能力的示例应用典型场景如移除音频或视频轨。Transformer 是 ExoPlayer 提供的媒体变换与导出框架负责将输入媒体解码、按需施加音视频效果Effects、重新编码并封装Mux为新的输出文件。该 Demo 的目录结构如下demos/transformer/build.gradleGradle 构建配置定义了noMediaPipe与withMediaPipe两个 product flavordemos/transformer/BUILD.bazel供 MediaPipe 源码树复用的 Bazel 构建目标src/main/基础版源码核心类位于com.google.android.exoplayer2.transformerdemo包包括TransformerActivity、ConfigurationActivity、MatrixTransformationFactory、PeriodicVignetteShaderProgram、TimerOverlay等src/withMediaPipe/MediaPipe 增强版源码包含 MediaPipeShaderProgram.java 与 edge_detector_mediapipe_graph.pbtxtMediaPipe 图定义。需要说明的是从源码中的Deprecated注解与注释可以看出com.google.android.exoplayer2包已处于弃用状态官方建议迁移到androidx.media3仓库根目录还提供了 media3-migration.sh 迁移脚本但本 Demo 所演示的 API 用法与集成思路在当前仓库版本中依然完整可用。二、构建与运行 Demo原文档指出构建运行说明见 demos/README.md。结合该文件运行方式分为两种2.1 从 Android Studio 运行File - New - Import Project选择 ExoPlayer 仓库根目录在 Run Configuration 下拉列表中选择demo-transformer点击 Run。2.2 使用 Gradle 命令行运行在仓库根目录打开终端# 列出所有工程Demo 工程以 demo 开头 ./gradlew projects # 查看 demo 工程可用任务Install tasks 节下的任务用于安装 ./gradlew :demo-transformer:tasks # 执行安装任务例如安装无解码器扩展的 debug 版本 ./gradlew :demo-transformer:installNoDecoderExtensionsDebug由 demos/transformer/build.gradle 可见该工程minSdkVersion 21启用了multiDexEnabled与 core library desugaring运行时依赖library-effect、library-core、library-dash、library-transformer、library-ui等本地模块。由于存在noMediaPipe/withMediaPipe两个 flavor安装任务名中会包含对应 flavor例如installNoMediaPipeDebug与installWithMediaPipeDebug。三、演示应用功能全景ConfigurationActivity 的配置项应用由两个 Activity 组成ConfigurationActivity配置导出参数与TransformerActivity执行导出并对比播放。ConfigurationActivity通过Intent的Bundle把参数传给TransformerActivity对应关系与完整常量定义见 ConfigurationActivity.java。3.1 输入源选择预设文件内置 17 个测试媒体覆盖 720p H.264AAC、1080p H.265、4K 竖屏 H.264、8K H.265、360p VP8Vorbis、180p 长视频、慢动作 240fps、非方形像素 DASH、HDR10 与 HLG 等类型还包括 JPG 静态图片按 5 秒、30fps 播放与仅视频无音频的样本本地文件通过系统文件选择器video/*选取需要运行时权限Android 13 为READ_MEDIA_VIDEO更低版本为READ_EXTERNAL_STORAGE外部 Intent也可由其他应用以ACTION_VIEW方式传入媒体 URI。3.2 轨道级编辑与转码配置项说明实现要点对应源码Remove audio / Remove video移除音频或视频轨二者互斥勾选其一会自动取消另一个映射到EditedMediaItem.setRemoveAudio()/setRemoveVideo()Audio MIME type音频编码格式可选 AAC、AMR-NB、AMR-WBTransformationRequest.Builder.setAudioMimeType()Video MIME type视频编码格式可选 H.263、H.264、MP4VAndroid 7.0 额外提供 H.265setVideoMimeType()Force audio track即使输入只有视频轨也强制输出音频轨Composition.Builder.experimentalSetForceAudioTrack()Flatten for slow motion展平慢动作SEF 元数据视频EditedMediaItem.setFlattenForSlowMotion()3.3 几何变换与裁剪Resolution height输出分辨率高度144/240/360/480/720/1080/1440/2160通过Presentation.createForHeight()实现Scale缩放系数-1,-1为镜像、1,1原尺寸、.5,1、.5,.5、2,2等对应ScaleAndRotateTransformation.Builder().setScale(sx, sy)Rotate旋转角度0/10/45/60/90/180 度对应setRotationDegrees()Trim通过 RangeSlider 选择起止秒数内部转为毫秒最终通过MediaItem.ClippingConfiguration设置startPositionMs/endPositionMs。3.4 HDR 模式下拉框提供四种 HDR 处理策略映射到TransformationRequest.HdrModeKeep HDRHDR_MODE_KEEP_HDR保持 HDR 输出MediaCodec tone-map HDR to SDR由 MediaCodec 完成色调映射OpenGL tone-map HDR to SDR由 OpenGL 着色器完成色调映射Force Interpret HDR as SDR实验性强制把 HDR 当作 SDR 解释。注意预设文件中 HDR10 / HLG 样本的描述注明“encoding may fail编码可能失败”演示了高动态范围素材在导出时的现实约束。3.5 音视频效果Effects视频效果13 项可在多选对话框中组合Dizzy crop画面沿椭圆轨迹移动并放大裁切Edge detector (Media Pipe)基于 MediaPipe 的边缘检测见第五节Color filters灰度 / 反色 / 怀旧 SepiaSepia 使用 W3C sRGB 矩阵代码注释特别说明仅为演示内部线性 RGB 空间下并非严格正确Map White to Green Color Lookup Table自定义 3×3×3 LUT 将白色映射为绿色SingleColorLut.createFromCubeRGB Adjustments红/绿/蓝三通道增益滑杆HSL Adjustments色相 / 饱和度 / 明度调整Contrast对比度Periodic vignette周期性暗角自定义GlShaderProgram可调中心与内外半径3D spin绕 Y 轴 3D 旋转 透视投影MatrixTransformationFactory.createSpin3dEffect()用frustumMrotateM构造矩阵Zoom in start前 2 秒从单点线性放大到全幅Overlay logo timer叠加应用图标与计时器DrawableOverlayTimerOverlayCustom Bitmap Overlay叠加自定义图片可调透明度Custom Text Overlay叠加自定义文本11 种预设颜色可调透明度。其中 3D spin、Zoom in、Dizzy crop 的实现细节见 MatrixTransformationFactory.java它们均基于presentationTimeUs逐帧计算变换矩阵直观展示了时间驱动型矩阵特效的写法。音频效果3 项High pitched音调升高SonicAudioProcessor.setPitch(2f)Sample rate of 48000Hz输出采样率 48kHzsetOutputSampleRateHz(48_000)Skip silence跳过静音段SilenceSkippingAudioProcessor.setEnabled(true)。3.6 导出行为开关Enable fallback允许编码器回退DefaultEncoderFactory.Builder().setEnableFallback(true)即首选编码器不可用时尝试其他编码器Enable debug preview导出过程中实时预览输出画面setDebugViewProviderDemoDebugViewProvider通过CountDownLatch等待 Surface 创建完成Abort slow export勾选后使用限制输出延迟的DefaultMuxer.Factory(maxDelayBetweenSamplesMsC.TIME_UNSET)并在导出过慢时中止源码中DefaultMuxer相关注释表明其为慢导出调试场景设计。四、导出流程的源码级剖析TransformerActivityTransformerActivity完整展示了 Transformer API 的标准调用链路见 TransformerActivity.java核心流程如下创建输出文件在getExternalCacheDir()下生成transformer-output.mp4若文件已存在先删除再重建构造 MediaItem按裁剪参数构建MediaItemsetClippingConfiguration构造 TransformerTransformer.Builder设置TransformationRequestMIME 类型、HDR 模式、EncoderFactory含 fallback 开关、MuxerFactory慢导出中止开关、DebugViewProvider并注册Transformer.Listener构造 CompositionEditedMediaItem.Builder(mediaItem)上设置移除音轨/视频轨、flattenForSlowMotion、Effects(audioProcessors, videoEffects)图片输入会额外设置setDurationUs(5_000_000)5 秒与setFrameRate(30)代码注释图片输入时自动生效音视频输入时自动忽略随后包装为EditedMediaItemSequence与Composition启动导出transformer.start(composition, filePath)并启动一个 500ms 周期的Handler轮询transformer.getProgress(progressHolder)刷新进度条与耗时Stopwatch计时完成与对比播放onCompleted中把输入与输出MediaItem分别交给两个ExoPlayer在StyledPlayerView中并排播放对比JPG 图片输入则用DataSourceBitmapLoader加载位图显示错误与清理onError弹出 Toast 并记录日志onStop中调用transformer.cancel()取消导出、释放播放器并删除缓存输出文件。这正是 Transformer 入门最常见的“解码 → 处理 → 编码 → 封装 → 回放对比”完整闭环可直接作为自研导出功能的最小可运行模板。五、MediaPipe 帧处理集成重点原文档的核心章节是MediaPipe frame processing demo启用 MediaPipe 集成需要额外的手工步骤因为它要求在 MediaPipe 自己的源码树中用 Bazel 构建 AAR再把 AAR 与图的二进制 proto 拷入本 Demo。下面是原文档步骤的完整展开。5.1 步骤一安装 MediaPipe首先按照 MediaPipe 官方安装指引getting_started/install.html在本地准备好 MediaPipe 源码检出checkout并确保环境可运行 Bazel。5.2 步骤二把构建配置与图定义复制到 MediaPipe 源码树将 Demo 的 Bazel 构建配置与 MediaPipe 图文本 proto 复制到 MediaPipe 源码树中从而复用 MediaPipe 的 workspace 直接构建 AARcd path to MediaPipe checkout MEDIAPIPE_ROOT$(pwd) MEDIAPIPE_TRANSFORMER_ROOT${MEDIAPIPE_ROOT}/mediapipe/java/com/google/mediapipe/transformer cd path to the transformer demo (containing this readme) TRANSFORMER_DEMO_ROOT$(pwd) mkdir -p ${MEDIAPIPE_TRANSFORMER_ROOT} mkdir -p ${TRANSFORMER_DEMO_ROOT}/libs cp ${TRANSFORMER_DEMO_ROOT}/BUILD.bazel ${MEDIAPIPE_TRANSFORMER_ROOT}/BUILD cp ${TRANSFORMER_DEMO_ROOT}/src/withMediaPipe/assets/edge_detector_mediapipe_graph.pbtxt \ ${MEDIAPIPE_TRANSFORMER_ROOT}被复制的 BUILD.bazel 定义了两个构建目标edge_detector_mediapipe_aarmediapipe_aar规则声明依赖luminance_calculator与sobel_edges_calculator两个 Calculator用于产出 Android AARedge_detector_binary_graphmediapipe_binary_graph规则把edge_detector_mediapipe_graph.pbtxt编译为edge_detector_mediapipe_graph.binarypb。5.3 步骤三用 Bazel 构建 AAR 与二进制 proto在 MediaPipe 根目录执行以下命令构建 AAR 与图二进制 proto 并拷贝回 Democd ${MEDIAPIPE_ROOT} bazel build -c opt --stripALWAYS \ --host_crosstool_topbazel_tools//tools/cpp:toolchain \ --fat_apk_cpuarm64-v8a,armeabi-v7a \ --legacy_whole_archive0 \ --features-legacy_whole_archive \ --copt-fvisibilityhidden \ --copt-ffunction-sections \ --copt-fdata-sections \ --copt-fstack-protector \ --copt-Oz \ --copt-fomit-frame-pointer \ --copt-DABSL_MIN_LOG_LEVEL2 \ --linkopt-Wl,--gc-sections,--strip-all \ mediapipe/java/com/google/mediapipe/transformer:edge_detector_mediapipe_aar.aar cp bazel-bin/mediapipe/java/com/google/mediapipe/transformer/edge_detector_mediapipe_aar.aar \ ${TRANSFORMER_DEMO_ROOT}/libs bazel build mediapipe/java/com/google/mediapipe/transformer:edge_detector_binary_graph cp bazel-bin/mediapipe/java/com/google/mediapipe/transformer/edge_detector_mediapipe_graph.binarypb \ ${TRANSFORMER_DEMO_ROOT}/src/withMediaPipe/assets其中--fat_apk_cpuarm64-v8a,armeabi-v7a指定产物包含 64 位与 32 位 ARM 原生库一系列--copt/--linkopt用于裁剪符号、压缩体积、隐藏可见性-fvisibilityhidden并移除未使用代码段。构建结束后libs/目录下应出现edge_detector_mediapipe_aar.aarsrc/withMediaPipe/assets/下应出现edge_detector_mediapipe_graph.binarypb。5.4 步骤四Gradle 同步并选择 withMediaPipe 变体在 Android Studio 中执行 Gradle Sync然后选择withMediaPipebuild variant 构建运行并在效果列表中选择Edge detector (Media Pipe)即可看到边缘检测特效。原文档特别强调该变体只有在 AAR 存在时才会出现——其机制见 demos/transformer/build.gradleflavorDimensions mediaPipe productFlavors { noMediaPipe { dimension mediaPipe } withMediaPipe { dimension mediaPipe } } // Ignore the withMediaPipe variant if the MediaPipe AAR is not present. if (!project.file(libs/edge_detector_mediapipe_aar.aar).exists()) { variantFilter { variant - def names variant.flavors*.name if (names.contains(withMediaPipe)) { setIgnore(true) } } }当libs/edge_detector_mediapipe_aar.aar不存在时variantFilter会忽略withMediaPipe变体工程退化为纯noMediaPipe版本。此外withMediaPipe变体独有依赖还包括com.google.flogger:flogger及其 system-backend、com.google.code.findbugs:jsr305、com.google.protobuf:protobuf-javalite:3.19.1withMediaPipeImplementation fileTree(dir: libs, include: [*.aar]) withMediaPipeImplementation com.google.flogger:flogger:latest.release withMediaPipeImplementation com.google.flogger:flogger-system-backend:latest.release withMediaPipeImplementation com.google.code.findbugs:jsr305:latest.release withMediaPipeImplementation com.google.protobuf:protobuf-javalite:3.19.15.5 MediaPipe 图定义分析edge_detector_mediapipe_graph.pbtxt 定义了一个极简的两节点计算图# Demo MediaPipe graph that shows edges using a SobelEdgesCalculator. input_stream: input_video output_stream: output_video node: { calculator: LuminanceCalculator input_stream: input_video output_stream: luma_video } node: { calculator: SobelEdgesCalculator input_stream: luma_video output_stream: output_video }输入流input_video先经LuminanceCalculator转为灰度亮度流luma_video再由SobelEdgesCalculator用 Sobel 算子提取边缘输出output_video。这与BUILD.bazel中声明的两个 Calculator 依赖一一对应构成完整的“图像 → 亮度 → 边缘检测”流水线。5.6 MediaPipeShaderProgramGlShaderProgram 桥接实现在TransformerActivity.createVideoEffectsFromBundle中勾选 Edge detector 时通过反射加载com.google.android.exoplayer2.transformerdemo.MediaPipeShaderProgramClass? clazz Class.forName(com.google.android.exoplayer2.transformerdemo.MediaPipeShaderProgram);并以其为GlEffect工厂构造参数为graphName edge_detector_mediapipe_graph.binarypb、isSingleFrameGraph true、inputStreamName input_video、outputStreamName output_video。若类加载失败即未构建 withMediaPipe 变体会弹 Toast 提示no_media_pipe_error并跳过该效果——这也是普通变体下菜单项仍可见但不可用的原因。MediaPipeShaderProgram.java 实现了GlShaderProgram接口把 MediaPipe 的FrameProcessor桥接进 Transformer 的 GL 管线构造时加载mediapipe_jni原生库LibraryLoader并尝试加载opencv_java3失败则忽略并非所有构建配置都单独需要 OpenCV参数useHdr为true时直接checkArgument抛错——当前 MediaPipeShaderProgram 不支持 HDR 颜色输入纹理按线性 RGB BT.709 处理通过FrameProcessor消费AppTextureFrame输出帧包装为GlTextureInfo交给OutputListenersetOnWillAddFrameListener标记帧是否被接受isSingleFrameGraph true时采用同步入队调用onNewFrame后waitUntilReleasedWithGpuSync()等待 GPU 同步释放false时用单线程 Executor 循环重试直至帧被接受代码注释指出这可能在 MediaPipe 无容量时浪费 CPU/内存属已知权衡flush()直接抛出UnsupportedOperationException——该 Demo 的 MediaPipe 效果不支持 seek/seek 相关操作signalEndOfCurrentInputStream()等待图空闲后回调onCurrentOutputStreamEnded()release()中取消待处理 Future、关闭线程池并frameProcessor.close()。这些细节揭示了把任意 MediaPipe 图接入 Transformer 效果管线的完整范式实现GlShaderProgram四个监听器、桥接FrameProcessor、并遵守“单帧图同步 / 多帧图异步”两种背压策略。六、常见问题与已知限制综合原文档与源码注释可归纳以下注意事项withMediaPipe变体不出现原因几乎都是libs/edge_detector_mediapipe_aar.aar缺失请回查 5.2/5.3 步骤的拷贝是否成功MediaPipe 效果不支持 HDRMediaPipeShaderProgram构造时对useHdrtrue直接抛异常MediaPipe 效果不支持 seekflush()未实现播放列表中时间戳需单调递增否则 MediaPipe 会报错源码注释TODO(b/238302213)记录了这一待办HDR 导出可能失败预设的 HDR10/HLG 样本描述注明 encoding may fail选择 HDR 素材前需了解目标设备的编码能力包迁移提示Demo 源码基于已弃用的com.google.android.exoplayer2命名空间新项目建议按官方迁移指南迁移至androidx.media3。七、总结demos/transformer是学习 Transformer API 与 MediaPipe 集成的完整范例ConfigurationActivity展示了数十种可组合的编辑参数TransformerActivity展示了从MediaItem/EditedMediaItem/Composition到Transformer.start()的导出闭环而withMediaPipeflavor 则演示了“MediaPipe 源码树构建 AAR → Gradle 变体接入 →GlShaderProgram桥接”的三段式集成路径。无论你是要搭建基础的视频剪辑导出功能还是希望在导出管线中注入自定义 GPU/MediaPipe 实时算法本 Demo 的每一处源码都是可以直接参考的落地样板。延伸阅读仓库内demos/transformer/README.md、demos/README.md、demos/transformer/build.gradle、demos/transformer/BUILD.bazel、TransformerActivity.java、ConfigurationActivity.java、MediaPipeShaderProgram.java、edge_detector_mediapipe_graph.pbtxt。【免费下载链接】ExoPlayerAn extensible media player for Android项目地址: https://gitcode.com/gh_mirrors/exop/ExoPlayer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考