02-05-06 FFmpeg音视频处理
·
02-05-06 FFmpeg音视频处理
1. 概述
FFmpeg是开源的音视频处理工具集,支持几乎所有音视频格式的编解码、转码、剪辑、滤镜处理。在Android开发中,通过JNI调用FFmpeg可实现强大的音视频处理能力。
1.1 FFmpeg架构
libavformat - 封装格式处理(MP4/MKV/FLV)
libavcodec - 编解码器(H.264/AAC)
libavfilter - 滤镜处理(水印/美颜)
libswscale - 视频缩放/色彩转换
libswresample- 音频重采样
libavutil - 工具库
2. Android集成FFmpeg
2.1 编译FFmpeg
# 编译脚本 build_ffmpeg.sh
#!/bin/bash
NDK=/path/to/ndk
API=21
ARCH=arm64-v8a
./configure \
--prefix=./android/$ARCH \
--enable-cross-compile \
--target-os=android \
--arch=aarch64 \
--cpu=armv8-a \
--cc=$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android$API-clang \
--enable-shared \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--enable-small \
--enable-jni \
--enable-mediacodec \
--enable-decoder=h264_mediacodec
make clean
make -j8
make install
2.2 JNI封装
// FFmpegNative.kt - FFmpeg JNI接口
object FFmpegNative {
init {
System.loadLibrary("ffmpeg-jni")
}
external fun executeCommand(command: Array<String>): Int
external fun getFFmpegVersion(): String
external fun cancelExecution()
}
// 使用示例
class FFmpegHelper {
fun convertVideo(inputPath: String, outputPath: String) {
val command = arrayOf(
"ffmpeg",
"-i", inputPath,
"-c:v", "libx264",
"-preset", "medium",
"-crf", "23",
"-c:a", "aac",
"-b:a", "128k",
outputPath
)
val result = FFmpegNative.executeCommand(command)
if (result == 0) {
Log.d(TAG, "转码成功")
} else {
Log.e(TAG, "转码失败")
}
}
}
3. 常用功能
3.1 视频转码
class VideoTranscoder {
// H.265转H.264
fun convertH265ToH264(input: String, output: String) {
val cmd = arrayOf(
"ffmpeg", "-i", input,
"-c:v", "libx264",
"-preset", "fast",
"-crf", "22",
"-c:a", "copy",
output
)
FFmpegNative.executeCommand(cmd)
}
// 压缩视频
fun compressVideo(input: String, output: String, targetSizeMB: Int) {
// 计算目标码率
val duration = getVideoDuration(input)
val targetBitrate = (targetSizeMB * 8 * 1024 / duration).toInt()
val cmd = arrayOf(
"ffmpeg", "-i", input,
"-b:v", "${targetBitrate}k",
"-maxrate", "${targetBitrate * 1.5}k",
"-bufsize", "${targetBitrate * 2}k",
output
)
FFmpegNative.executeCommand(cmd)
}
}
3.2 视频剪辑
class VideoEditor {
// 截取视频片段
fun trimVideo(input: String, output: String, startTime: String, duration: String) {
val cmd = arrayOf(
"ffmpeg", "-ss", startTime,
"-i", input,
"-t", duration,
"-c", "copy",
output
)
FFmpegNative.executeCommand(cmd)
}
// 合并视频
fun mergeVideos(inputFiles: List<String>, output: String) {
// 生成concat列表文件
val listFile = File.createTempFile("concat", ".txt")
listFile.writeText(inputFiles.joinToString("\n") { "file '$it'" })
val cmd = arrayOf(
"ffmpeg",
"-f", "concat",
"-safe", "0",
"-i", listFile.absolutePath,
"-c", "copy",
output
)
FFmpegNative.executeCommand(cmd)
listFile.delete()
}
}
3.3 滤镜处理
class VideoFilter {
// 添加水印
fun addWatermark(input: String, watermark: String, output: String) {
val cmd = arrayOf(
"ffmpeg", "-i", input,
"-i", watermark,
"-filter_complex", "overlay=10:10",
output
)
FFmpegNative.executeCommand(cmd)
}
// 视频旋转
fun rotateVideo(input: String, output: String, degrees: Int) {
val transpose = when (degrees) {
90 -> "transpose=1"
180 -> "transpose=2,transpose=2"
270 -> "transpose=2"
else -> return
}
val cmd = arrayOf(
"ffmpeg", "-i", input,
"-vf", transpose,
output
)
FFmpegNative.executeCommand(cmd)
}
// 视频缩放
fun scaleVideo(input: String, output: String, width: Int, height: Int) {
val cmd = arrayOf(
"ffmpeg", "-i", input,
"-vf", "scale=$width:$height",
output
)
FFmpegNative.executeCommand(cmd)
}
}
4. 高级应用
4.1 提取音视频流
class StreamExtractor {
// 提取视频流(无音频)
fun extractVideo(input: String, output: String) {
val cmd = arrayOf(
"ffmpeg", "-i", input,
"-vcodec", "copy",
"-an", // 无音频
output
)
FFmpegNative.executeCommand(cmd)
}
// 提取音频流
fun extractAudio(input: String, output: String) {
val cmd = arrayOf(
"ffmpeg", "-i", input,
"-vn", // 无视频
"-acodec", "copy",
output
)
FFmpegNative.executeCommand(cmd)
}
}
4.2 音视频合成
class MediaMuxer {
// 合成音视频
fun muxAudioVideo(videoFile: String, audioFile: String, output: String) {
val cmd = arrayOf(
"ffmpeg",
"-i", videoFile,
"-i", audioFile,
"-c:v", "copy",
"-c:a", "aac",
"-strict", "experimental",
output
)
FFmpegNative.executeCommand(cmd)
}
// 替换音频
fun replaceAudio(videoFile: String, newAudioFile: String, output: String) {
val cmd = arrayOf(
"ffmpeg",
"-i", videoFile,
"-i", newAudioFile,
"-c:v", "copy",
"-c:a", "aac",
"-map", "0:v:0",
"-map", "1:a:0",
"-shortest",
output
)
FFmpegNative.executeCommand(cmd)
}
}
4.3 生成缩略图
class ThumbnailGenerator {
fun generateThumbnail(videoPath: String, outputPath: String, timeSeconds: Int) {
val cmd = arrayOf(
"ffmpeg",
"-ss", timeSeconds.toString(),
"-i", videoPath,
"-vframes", "1",
"-vf", "scale=320:-1",
outputPath
)
FFmpegNative.executeCommand(cmd)
}
// 生成多个缩略图
fun generateMultipleThumbnails(videoPath: String, outputDir: String, count: Int) {
val duration = getVideoDuration(videoPath)
val interval = duration / (count + 1)
for (i in 1..count) {
val time = interval * i
val outputPath = "$outputDir/thumb_$i.jpg"
generateThumbnail(videoPath, outputPath, time.toInt())
}
}
}
5. 性能优化
5.1 硬件加速
class HardwareAccelerator {
// 使用MediaCodec硬件编码
fun encodeWithMediaCodec(input: String, output: String) {
val cmd = arrayOf(
"ffmpeg", "-i", input,
"-c:v", "h264_mediacodec", // 使用MediaCodec
"-b:v", "2M",
output
)
FFmpegNative.executeCommand(cmd)
}
}
5.2 多线程处理
class BatchProcessor {
private val executor = Executors.newFixedThreadPool(4)
fun processBatch(files: List<String>, operation: (String) -> Unit) {
files.forEach { file ->
executor.submit {
operation(file)
}
}
}
}
总结
FFmpeg是音视频处理的瑞士军刀,本文涵盖:
- Android集成:编译与JNI封装
- 基础功能:转码、剪辑、滤镜
- 高级应用:流提取、音视频合成、缩略图生成
- 性能优化:硬件加速、多线程
关键要点:
- 通过JNI调用FFmpeg C API
- 命令行方式灵活但性能略低
- 硬件加速显著提升性能
下一篇预告:《OpenGL ES视频渲染》
火山引擎视频云技术社区,是面向 AI 音视频开发者的技术交流平台。这里汇聚源自抖音、豆包等亿级 DAU 产品的 RTC、直播、点播、AI 媒体处理、音视频互动技术,提供接入指南、最佳实践、性能调优、场景案例、Demo 代码、开源项目、白皮书和 API 文档。社区汇聚官方工程师与一线开发者,为 AI 视频通话、数字人、AI 视频处理等应用的开发与落地提供技术支持。
更多推荐
所有评论(0)