【懒人精灵】小飞侠插件专题——FFMPEG音视频处理类

内容说明

1. OOP调用例子(推荐)

  • 使用 XfxPlugin.lua 的面向对象封装
  • 展示通过 call 方法和直接获取 ffmpegOps 对象两种方式
  • 完整的视频处理示例

2. 直接调用例子

  • 直接调用 Main 类的方式
  • 适合了解底层实现

3. 实际应用示例

包含多个实用场景:

  • 提取MP4视频第一帧图片:从视频中提取第一帧并保存为图片
  • 获取视频信息:获取视频的时长、分辨率、编码等信息
  • 视频格式转换:将视频转换为不同格式
  • 视频裁剪:截取视频的指定时间段
  • 视频合并:将多个视频合并为一个
  • 提取音频:从视频中提取音频轨道

FFMPEG 功能包括

  • 提取视频帧:提取第一帧或指定时间的帧
  • 获取视频信息:时长、分辨率、编码、帧率、比特率等
  • 视频格式转换:支持多种视频格式转换
  • 视频裁剪:截取指定时间段的视频
  • 视频合并:合并多个视频文件
  • 提取音频:从视频中提取音频轨道
  • 消息回调:支持设置回调函数,接收处理进度和状态消息

OOP调用例子

-- ============================================
-- FFMPEG 视频处理示例
-- 演示如何使用 XfxPlugin.lua 调用 FfmpegOps 进行视频处理
-- ============================================

-- 方式一:使用 XfxPlugin.lua 面向对象封装(推荐)
-- ============================================
print('========== 方式一:使用 XfxPlugin.lua 封装 ==========')

-- 加载 XfxPlugin.lua 类
local xfxModule = require('lib/XfxPlugin')

-- 创建 XFX 对象实例
local xfx = xfxModule:new({
    apkName = 'xfxPlugin-release.apk',  -- APK 文件名
})

-- 获取 ffmpegOps 对象
local ffmpegOps = xfx:getOps('ffmpegOps')
if not ffmpegOps then
    print('无法获取 ffmpegOps 对象')
    return
end

-- 检查 FFMPEG 是否可用
local isAvailable = ffmpegOps.isFFmpegAvailable()
print('FFMPEG 是否可用: ' .. tostring(isAvailable))

if not isAvailable then
    print('FFMPEG 不可用,无法继续')
    return
end

-- 获取 FFMPEG 版本信息
local version = ffmpegOps.getFFmpegVersion()
print('FFMPEG 版本: ' .. tostring(version))

-- 设置消息回调函数(需要使用 Runnable 包装)
import('java.lang.Runnable')
local callbackCount = 0
ffmpegOps.setMessageCallback(
    Runnable {
        run = function()
            callbackCount = callbackCount + 1
            print('收到回调消息 #' .. callbackCount)
        end
    }
)

-- 示例:获取视频信息
print('\n--- 获取视频信息 ---')
local videoPath = '/sdcard/test.mp4'
local videoInfo = ffmpegOps.getVideoInfo(videoPath)
print('视频信息 (JSON): ' .. videoInfo)

-- 解析 JSON 信息(如果有 jsonLib)
if jsonLib then
    local info = jsonLib.decode(videoInfo)
    if info then
        print('视频时长: ' .. tostring(info.duration) .. ' 秒')
        print('视频分辨率: ' .. tostring(info.width) .. 'x' .. tostring(info.height))
        print('视频编码: ' .. tostring(info.codec))
        if info.fps then
            print('帧率: ' .. tostring(info.fps) .. ' fps')
        end
    end
end

print('\n示例执行完成!')

直接调用例子

import('com.nx.assist.lua.LuaEngine')

-- ============================================
-- 方式二:直接调用方式(不推荐,但可以了解底层实现)
-- ============================================
print('========== 方式二:直接调用方式 ==========')

local loader = LuaEngine.loadApk('xfxPlugin-release.apk')
if not loader then
    print('Failed to load APK')
    return
end

local UtilCodeMain = loader.loadClass('com.xfx.plugin.Main')
if not UtilCodeMain then
    print('Failed to load Class')
    return
end

---- 初始化插件
-- local context = LuaEngine.getContext()
-- UtilCodeMain.init(context)

-- 获取 FfmpegOps
local ffmpegOps = UtilCodeMain.ffmpegOps()

-- 检查 FFMPEG 是否可用
local isAvailable = ffmpegOps.isFFmpegAvailable()
print('FFMPEG 是否可用: ' .. tostring(isAvailable))

-- 获取视频信息
local videoPath = '/sdcard/test.mp4'
local videoInfo = ffmpegOps.getVideoInfo(videoPath)
print('视频信息: ' .. videoInfo)

实际应用示例


local xfxModule = require('lib/XfxPlugin')

local xfx = xfxModule:new({apkName = 'xfxPlugin-release.apk'})

local ffmpegOps = xfx:getOps('ffmpegOps')

if not ffmpegOps then
    print('无法获取 ffmpegOps 对象')
    return
end

-- 检查 FFMPEG 是否可用
if not ffmpegOps.isFFmpegAvailable() then
    print('FFMPEG 不可用,请检查环境')
    return
end

-- ============================================
-- 示例 1:提取MP4视频第一帧图片(重点示例)
-- ============================================
print('========== 示例 1:提取MP4视频第一帧图片 ==========')

local function extractFirstFrameFromMP4(videoPath, outputImagePath)
    print('开始提取视频第一帧...')
    print('输入视频: ' .. videoPath)
    print('输出图片: ' .. outputImagePath)

    -- 使用同步方法提取第一帧
    local success = ffmpegOps.extractFrame(videoPath, outputImagePath)

    if success then
        print('✓ 成功提取第一帧图片: ' .. outputImagePath)

        -- 检查输出文件是否存在
        local fileOps = xfx:getOps('fileOps')
        if fileOps and fileOps.isFileExists(outputImagePath) then
            local fileSize = fileOps.getSize(outputImagePath)
            print('输出文件大小: ' .. tostring(fileSize) .. ' 字节')
        end
    else
        print('✗ 提取第一帧失败')
    end

    return success
end

-- 使用示例
local videoPath = '/sdcard/test.mp4'
local outputImagePath = '/sdcard/video_first_frame.jpg'

local success = extractFirstFrameFromMP4(videoPath, outputImagePath)

-- -- 异步方式提取第一帧(不阻塞)
-- print('\n--- 使用异步方式提取第一帧 ---')
-- ffmpegOps.extractFrameAsync(videoPath, '/sdcard/video_first_frame_async.jpg')
-- print('异步任务已启动,将在后台执行')

-- ============================================
-- 示例 2:获取视频信息
-- ============================================
print('\n========== 示例 2:获取视频信息 ==========')

local function getVideoDetails(videoPath)
    print('正在获取视频信息: ' .. videoPath)

    local infoJson = ffmpegOps.getVideoInfo(videoPath)
    print('视频信息 (JSON): ' .. infoJson)

    if jsonLib then
        local info = jsonLib.decode(infoJson)
        if info then
            print('\n【视频详细信息】')
            if info.duration then
                print('时长: ' .. tostring(info.duration) .. ' 秒')
            end
            if info.durationFormatted then
                print('时长(格式化): ' .. tostring(info.durationFormatted))
            end
            if info.width and info.height then
                print('分辨率: ' .. tostring(info.width) .. 'x' .. tostring(info.height))
            end
            if info.codec then
                print('编码: ' .. tostring(info.codec))
            end
            if info.fps then
                print('帧率: ' .. tostring(info.fps) .. ' fps')
            end
            if info.bitrate then
                print('比特率: ' .. tostring(info.bitrate) .. ' kb/s')
            end
            if info.fileSize then
                print('文件大小: ' .. tostring(info.fileSize) .. ' 字节')
            end
        end
    end

    return infoJson
end

local videoInfo = getVideoDetails('/sdcard/test.mp4')

-- ============================================
-- 示例 3:视频格式转换
-- ============================================
print('\n========== 示例 3:视频格式转换 ==========')

local function convertVideoFormat(inputPath, outputPath, targetFormat)
    print('开始转换视频格式...')
    print('输入: ' .. inputPath)
    print('输出: ' .. outputPath)
    print('目标格式: ' .. (targetFormat or '自动检测'))

    local success = ffmpegOps.convertFormat(inputPath, outputPath, targetFormat)

    if success then
        print('✓ 视频格式转换成功')
    else
        print('✗ 视频格式转换失败')
    end

    return success
end

-- 将 MP4 转换为 AVI
-- convertVideoFormat('/sdcard/test.mp4', '/sdcard/test.avi', 'avi')

-- -- 异步转换(不阻塞)
-- ffmpegOps.convertFormatAsync('/sdcard/test.mp4', '/sdcard/test_async.avi', 'avi')

-- ============================================
-- 示例 4:视频裁剪(截取指定时间段)
-- ============================================
print('\n========== 示例 4:视频裁剪 ==========')

local function trimVideoSegment(inputPath, outputPath, startTime, duration)
    print('开始裁剪视频...')
    print('输入: ' .. inputPath)
    print('输出: ' .. outputPath)
    print('开始时间: ' .. tostring(startTime) .. ' 秒')
    print('持续时间: ' .. tostring(duration or '到视频结束') .. ' 秒')

    local success = ffmpegOps.trimVideo(inputPath, outputPath, startTime, duration)

    if success then
        print('✓ 视频裁剪成功')
    else
        print('✗ 视频裁剪失败')
    end

    return success
end

-- 裁剪视频:从第 10 秒开始,持续 30 秒
-- trimVideoSegment('/sdcard/test.mp4', '/sdcard/test_video_trimmed.mp4', 10.0, 30.0)

-- 裁剪视频:从第 5 秒开始到视频结束
-- trimVideoSegment('/sdcard/test.mp4', '/sdcard/test_video_from_5s.mp4', 5.0, nil)

-- 异步裁剪
-- ffmpegOps.trimVideoAsync('/sdcard/test.mp4', '/sdcard/test_video_trimmed.mp4', 10.0, 30.0)

-- ============================================
-- 示例 5:视频合并
-- ============================================
print('\n========== 示例 5:视频合并 ==========')

local function mergeVideoFiles(videoPaths, outputPath)
    print('开始合并视频...')
    print('输入视频数量: ' .. tostring(#videoPaths))
    for i, path in ipairs(videoPaths) do
        print('  视频 ' .. i .. ': ' .. path)
    end
    print('输出: ' .. outputPath)

    local success = ffmpegOps.mergeVideos(videoPaths, outputPath)

    if success then
        print('✓ 视频合并成功')
    else
        print('✗ 视频合并失败')
    end

    return success
end

-- 合并多个视频
-- local videoList = {
--     '/sdcard/video1.mp4',
--     '/sdcard/video2.mp4',
--     '/sdcard/video3.mp4'
-- }
-- mergeVideoFiles(videoList, '/sdcard/merged_video.mp4')

-- 异步合并
-- ffmpegOps.mergeVideosAsync(videoList, '/sdcard/merged_video.mp4')

-- ============================================
-- 示例 6:提取音频
-- ============================================
print('\n========== 示例 6:提取音频 ==========')

local function extractAudioFromVideo(videoPath, audioPath, audioFormat)
    print('开始提取音频...')
    print('输入视频: ' .. videoPath)
    print('输出音频: ' .. audioPath)
    print('音频格式: ' .. (audioFormat or '自动检测'))

    local success = ffmpegOps.extractAudio(videoPath, audioPath, audioFormat)

    if success then
        print('✓ 音频提取成功')
    else
        print('✗ 音频提取失败')
    end

    return success
end

-- 提取音频为 MP3
-- extractAudioFromVideo('/sdcard/test.mp4', '/sdcard/test_audio.mp3', 'mp3')

-- 提取音频为 AAC
-- extractAudioFromVideo('/sdcard/test.mp4', '/sdcard/test_audio.aac', 'aac')

-- 异步提取
-- ffmpegOps.extractAudioAsync('/sdcard/test.mp4', '/sdcard/test_audio.mp3', 'mp3')

-- ============================================
-- 示例 7:提取指定时间的视频帧
-- ============================================
print('\n========== 示例 7:提取指定时间的视频帧 ==========')

local function extractFrameAtTime(videoPath, outputImagePath, timeOffset)
    print('开始提取视频帧...')
    print('输入视频: ' .. videoPath)
    print('输出图片: ' .. outputImagePath)
    print('时间偏移: ' .. tostring(timeOffset) .. ' 秒')

    local success = ffmpegOps.extractFrame(videoPath, outputImagePath, timeOffset)

    if success then
        print('✓ 成功提取视频帧')
    else
        print('✗ 提取视频帧失败')
    end

    return success
end

-- 提取第 N 秒的帧
-- extractFrameAtTime('/sdcard/test.mp4', '/sdcard/video_frame_at_10s.jpg', 10.0)

-- ============================================
-- 示例 8:使用消息回调
-- ============================================
print('\n========== 示例 8:使用消息回调 ==========')

local function setupMessageCallback()
    print('设置消息回调函数...')

    local messageCount = 0
    ffmpegOps.setMessageCallback(
        Runnable {
            run = function()
                messageCount = messageCount + 1
                print('收到 FFMPEG 消息回调 #' .. messageCount)
                -- 在实际应用中,可以在这里处理进度更新、完成通知等
            end
        }
    )

    print('消息回调已设置')

    -- 执行一个操作来触发回调
    print('执行视频信息获取以触发回调...')
    local videoPath = '/sdcard/test.mp4'
    local info = ffmpegOps.getVideoInfo(videoPath)
    print('视频信息获取完成')
end

-- setupMessageCallback()

-- ============================================
-- 示例 9:完整的视频处理流程
-- ============================================
print('\n========== 示例 9:完整的视频处理流程 ==========')

local function processVideoWorkflow(videoPath)
    print('开始视频处理流程...')
    print('视频路径: ' .. videoPath)

    -- 步骤 1:检查 FFMPEG 是否可用
    if not ffmpegOps.isFFmpegAvailable() then
        print('✗ FFMPEG 不可用,终止流程')
        return false
    end
    print('✓ FFMPEG 可用')

    -- 步骤 2:获取视频信息
    print('\n步骤 2:获取视频信息...')
    local infoJson = ffmpegOps.getVideoInfo(videoPath)
    print('视频信息: ' .. infoJson)

    -- 步骤 3:提取第一帧作为缩略图
    print('\n步骤 3:提取第一帧...')
    local thumbnailPath = '/sdcard/video_thumbnail.jpg'
    local success = ffmpegOps.extractFrame(videoPath, thumbnailPath)
    if success then
        print('✓ 缩略图已保存: ' .. thumbnailPath)
    else
        print('✗ 缩略图提取失败')
    end

    -- 步骤 4:提取音频(如果需要)
    print('\n步骤 4:提取音频...')
    local audioPath = '/sdcard/video_audio.mp3'
    success = ffmpegOps.extractAudio(videoPath, audioPath, 'mp3')
    if success then
        print('✓ 音频已提取: ' .. audioPath)
    else
        print('✗ 音频提取失败')
    end

    print('\n视频处理流程完成!')
    return true
end

-- 执行完整流程
processVideoWorkflow('/sdcard/test.mp4')

print('\n所有示例代码已展示完成!')
print('注意:实际使用时,请确保视频文件路径正确,并根据需要取消注释相应的示例代码。')

提取MP4视频第一帧图片

-- ============================================
-- 提取MP4视频第一帧图片 - 完整示例
-- ============================================

local xfxModule = require('lib/XfxPlugin')
local xfx = xfxModule:new({apkName = 'xfxPlugin-release.apk'})

local ffmpegOps = xfx:getOps('ffmpegOps')

if not ffmpegOps then
    print('无法获取 ffmpegOps 对象')
    return
end

-- 检查 FFMPEG 是否可用
if not ffmpegOps.isFFmpegAvailable() then
    print('FFMPEG 不可用')
    return
end

-- 视频文件路径
local videoPath = '/sdcard/test.mp4'

-- 输出图片路径(支持 jpg, png 等格式)
local outputImagePath = '/sdcard/video_first_frame.jpg'

-- 方法 1:使用同步方法(会阻塞直到完成)
print('方法 1:同步提取第一帧...')
local success = ffmpegOps.extractFrame(videoPath, outputImagePath)

if success then
    print('✓ 成功提取第一帧图片')
    print('输出文件: ' .. outputImagePath)

    -- 检查文件是否存在
    local fileOps = xfx:getOps('fileOps')
    if fileOps and fileOps.isFileExists(outputImagePath) then
        local fileSize = fileOps.getSize(outputImagePath)
        print('文件大小: ' .. tostring(fileSize) .. ' 字节')
    end
else
    print('✗ 提取第一帧失败')
end

-- 方法 2:使用异步方法(不阻塞)
print('\n方法 2:异步提取第一帧...')
ffmpegOps.extractFrameAsync(videoPath, '/sdcard/video_first_frame_async.jpg')
print('异步任务已启动,将在后台执行')

-- 方法 3:提取指定时间的帧(例如第 10 秒)
print('\n方法 3:提取第 10 秒的帧...')
local success2 = ffmpegOps.extractFrame(videoPath, '/sdcard/video_frame_10s.jpg', 10.0)
if success2 then
    print('✓ 成功提取第 10 秒的帧')
end

-- 方法 4:使用消息回调监听处理状态
print('\n方法 4:使用回调监听处理状态...')
import('java.lang.Runnable')
ffmpegOps.setMessageCallback(
    Runnable {
        run = function()
            print('收到 FFMPEG 处理消息')
        end
    }
)

-- 执行提取操作
ffmpegOps.extractFrame(videoPath, '/sdcard/video_first_frame_with_callback.jpg')
print('提取操作完成(回调已触发)')

异步消息例子


local xfxModule = require('lib/XfxPlugin')
local xfx = xfxModule:new({apkName = 'xfxPlugin-release.apk'})

local ffmpegOps = xfx:getOps('ffmpegOps')

if not ffmpegOps then
    print('无法获取 ffmpegOps 对象')
    return
end

-- 检查 FFMPEG 是否可用
if not ffmpegOps.isFFmpegAvailable() then
    print('FFMPEG 不可用')
    return
end

-- 视频文件路径
local videoPath = '/sdcard/test.mp4'

-- 输出图片路径(支持 jpg, png 等格式)
local outputImagePath = '/sdcard/video_first_frame.jpg'

-- 使用异步方法(不阻塞)
print('\n异步提取第一帧...')
ffmpegOps.extractFrameAsync(videoPath, '/sdcard/video_first_frame_async.jpg')
print('异步任务已启动,将在后台执行')

-- 使用消息回调监听处理状态
print('\n使用回调监听处理状态...')
import('java.lang.Runnable')
ffmpegOps.setMessageCallback(
    Runnable {
        run = function()
            print('收到 FFMPEG 处理消息')
        end
    }
)

sleep(30000)

注意事项

  1. 文件路径:确保输入视频文件存在且路径正确
  2. 输出路径:确保输出目录有写入权限
  3. 文件格式:输出图片格式由文件扩展名决定(.jpg, .png 等)
  4. 异步操作:异步方法不会阻塞脚本执行,适合长时间操作
  5. 回调函数:设置回调后,会在操作过程中触发,可用于显示进度
  6. 错误处理:建议在实际使用中添加错误处理和文件存在性检查

常用方法总结

方法名 说明 同步/异步
extractFrame() 提取指定时间的帧 同步
getVideoInfo() 获取视频信息 同步
convertFormat() 视频格式转换 同步
convertFormatAsync() 视频格式转换 异步
trimVideo() 裁剪视频 同步
trimVideoAsync() 裁剪视频 异步
mergeVideos() 合并视频 同步
mergeVideosAsync() 合并视频 异步
extractAudio() 提取音频 同步
extractAudioAsync() 提取音频 异步
setMessageCallback() 设置消息回调
isFFmpegAvailable() 检查 FFMPEG 是否可用 同步
getFFmpegVersion() 获取 FFMPEG 版本 同步
1. 官方交流QQ群,添加多个不批。建议使用安卓手机或电脑申请。
飞云脚本圈: 586333520飞云脚本圈
Auto.js学习交流③群:286635606
Auto.js学习交流②群:712194666(满员)
IOS免越狱自动化测试群:691997586
2. 盗版,破解有损他人权益和违法作为,请各位会员支持正版。
3. 本站部分资源来源于用户上传和网络搜集,如有侵权请提供版权证明并联系站长删除。
4.如未特别申明,本站的技术性文章均为原创,未经授权,禁止转载/搬运等侵权行为。
5.全站所有付费服务均为虚拟商品,购买后自动发货。售出后概不接受任何理由的退、换。注册即为接受此条款。
6.如果站内内容侵犯了您的权益,请联系站长删除。
飞云脚本 » 【懒人精灵】小飞侠插件专题——FFMPEG音视频处理类

企业级大数据智能营销管理系统

源码转让