【FFmpeg实战】Flutter音视频裁剪

news2024/12/23 15:02:58

作者:JianLee 链接:https://www.jianshu.com/p/868c8536a9b2

flutter_ffmpeg是什么?

ffmpeg是一个音视频处理库,通过命令行的形式,对音视频进行处理,而MobileFFmpeg
则是ffmpeg在移动端的实现,flutter_ffmpeg是对MobileFFmpeg的封装,是的在flutter下能够轻松的使用ffmpeg对音视频进行处理。flutter_ffmpeg包括两部分FFmpeg和FFprobe,其中FFmpeg负责音视频处理,而FFprobe主要负责查询音视频的媒体信息。

flutter_ffmpeg地址

flutter_ffmpeg使用
第一步:安装
// 在pubspec.yaml的dependencies下添加:
  flutter_ffmpeg: ^0.3.1
第二步:配置

android工程下的配置

// 在工程目录下的 /android/build.gradle下添加
ext {
    flutterFFmpegPackage  = "full-lts" 
}

注意:上面配置中的”full-lts” 是flutter__ffmpeg各个发布版本的报名,可以查看官方文档的说明。有一个值得说明的地方是,flutter_ffmpeg有中发行包,一种是 Main Release,一种是LTS Release 发行包,而他们两者支持的 Android API Level/iOS SDK和硬件架构是不一样的,总的来说,LTS版本支持的更广泛,LTS支持度大于MAIN,所以我们最好使用LTS版本。
这里我遇到一个问题,使用full-lts编码格式,会出现上传到服务器无法播放视频的情况。
所以我这里是用的:

ext {
    flutterFFmpegPackage = "full-gpl-lts"
}

另外在使用flutter_ffmpeg的时候出现类似问题:

Caused by: java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/app.domain.name-Lq_GxP1CfMArHTpLoII-YA==/base.apk"],nativeLibraryDirectories=[/data/app/app.domain.name-Lq_GxP1CfMArHTpLoII-YA==/lib/arm64, /data/app/app.domain.name-Lq_GxP1CfMArHTpLoII-YA==/base.apk!/lib/arm64-v8a, /system/lib64, /system/vendor/lib64]]] couldn't find "libmobileffmpeg_abidetect.so"
        at java.lang.Runtime.loadLibrary0(Runtime.java:1011)
        at java.lang.System.loadLibrary(System.java:1657)
        at com.arthenica.mobileffmpeg.AbiDetect.<clinit>(Unknown Source:13)
        at com.arthenica.mobileffmpeg.AbiDetect.getNativeAbi(Native Method)
        at com.arthenica.mobileffmpeg.Config.<clinit>(Unknown Source:96)
        at com.arthenica.mobileffmpeg.Config.nativeFFmpegExecute(Native Method)
        at com.arthenica.mobileffmpeg.b.a(Unknown Source:0)
        at d.b.a.a.a.a(Unknown Source:31)
        at d.b.a.a.a.doInBackground(Unknown Source:2)
        at android.os.AsyncTask$2.call(AsyncTask.java:333)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245) 
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) 
        at java.lang.Thread.run(Thread.java:764) 

通过clean可以解决

flutter clean
flutter build [artificat]

使用gpl保证裁剪视频默认使用x264(不然会出现上传视频无法播放的问题),具体可以查看flutter_ffmpeg封装编码

img

image.png

第三步:使用

flutter_ffmpge是ffmpeg在flutter上的一个实现,ffmpeg是通过命令行还进行音视频编辑的工具,因此我们使用fluter_ffmpeg自然也是运行一些命令来实现我们的功能。具体使用方法可以直接看ffluter_ffmpeg官方文档和ffmpeg官方文档,或者看一下更加通俗易懂的阮一峰文档。接下来我们主要看看flutter_ffmpeg能干什么?

flutter_ffmpge能做什么?

查看视频信息

做音视频处理,首先我们肯定想知道我们的处理是否成功,或者效果好不好,那么我们只能通过处理的视频前后的参数进行对比,因此第一步我们要求这个视频处理库详细的给我们提供音视频的信息,flutter_ffmpeg的FFProde能够很好的实现这一点,而且使用很方便:

final FlutterFFprobe _flutterFFprobe = new FlutterFFprobe();

_flutterFFprobe.getMediaInformation("<file path or uri>").then((info) {
    print("Media Information");

    print("Path: ${info.getMediaProperties()['filename']}");
    print("Format: ${info.getMediaProperties()['format_name']}");
    print("Duration: ${info.getMediaProperties()['duration']}");
    print("Start time: ${info.getMediaProperties()['start_time']}");
    print("Bitrate: ${info.getMediaProperties()['bit_rate']}");
    Map<dynamic, dynamic> tags = info.getMediaProperties()['tags'];
    if (tags != null) {
        tags.forEach((key, value) {
            print("Tag: " + key + ":" + value + "\n");
        });
    }

    if (info.getStreams() != null) {
        List<StreamInformation> streams = info.getStreams();

        if (streams.length > 0) {
            for (var stream in streams) {
                print("Stream id: ${stream.getAllProperties()['index']}");
                print("Stream type: ${stream.getAllProperties()['codec_type']}");
                print("Stream codec: ${stream.getAllProperties()['codec_name']}");
                print("Stream full codec: ${stream.getAllProperties()['codec_long_name']}");
                print("Stream format: ${stream.getAllProperties()['pix_fmt']}");
                print("Stream width: ${stream.getAllProperties()['width']}");
                print("Stream height: ${stream.getAllProperties()['height']}");
                print("Stream bitrate: ${stream.getAllProperties()['bit_rate']}");
                print("Stream sample rate: ${stream.getAllProperties()['sample_rate']}");
                print("Stream sample format: ${stream.getAllProperties()['sample_fmt']}");
                print("Stream channel layout: ${stream.getAllProperties()['channel_layout']}");
                print("Stream sar: ${stream.getAllProperties()['sample_aspect_ratio']}");
                print("Stream dar: ${stream.getAllProperties()['display_aspect_ratio']}");
                print("Stream average frame rate: ${stream.getAllProperties()['avg_frame_rate']}");
                print("Stream real frame rate: ${stream.getAllProperties()['r_frame_rate']}");
                print("Stream time base: ${stream.getAllProperties()['time_base']}");
                print("Stream codec time base: ${stream.getAllProperties()['codec_time_base']}");

                Map<dynamic, dynamic> tags = stream.getAllProperties()['tags'];
                if (tags != null) {
                  tags.forEach((key, value) {
                    print("Stream tag: " + key + ":" + value + "\n");
                  });
                }
            }
        }
    }
});

视频压缩

  • 改变帧率
ffmpeg -i Desktop/吉他.mp4  -r 20  Desktop/output1.mp4

-r 20:表示帧率设置为 20fps

  • 指定文件大小
ffmpeg -i Desktop/吉他.mp4  -fs 15MB  Desktop/output1.mp4

fs 20 : 表示文件大小最大值为15MB
把视频截了一部分 — 这种方法不推荐

  • 改变分辨率
ffmpeg -i Desktop/1.mov -s vga Desktop/1.mp4

-s vga : 指定分辨率, vga 代表 600*480,也可以换成其他的值

  • 改变码率
    视频的原码率是 2.1Mb/s ,压缩为 1.5Mb/s
ffmpeg -i Desktop/1.mov -b:v 1.5M  Desktop/1.mp4

-b:v 1.5M : 指定码率
-b:v :指定视频的码率
-b:a : 指定音频的码率
1.5M:码率的值 1.5M 表示 1.5Mb/s

裁剪视频

比如我在项目里用到上传到服务器的视频时长需要控制在60s以内的功能,我们就可以这样:

 String inputFilePath = inputFile.path;
                    String outputFilePath =
                        await FileUtils.outputFileNameStr(inputFile);
                    var ffmpeg = new FlutterFFmpeg();
                    ffmpeg
                        .execute(
                            "-i $inputFilePath -ss 0 -to 60 -c:v libx264 $outputFilePath")//这里是ffmpeg指令 裁剪60s视频
                        .then((rc) async {
                      if (rc == 0) {
                        //rc=0表示成功
                        //裁剪60s 转换 libx264
                      } else {
                        showToast('视频裁剪出现异常,请重试', context);
                        Navigator.pop(context);
                      }
                    });

转换视频格式

var ffmpeg = new FlutterFFmpeg();
  Directory tempDir = await getTemporaryDirectory();;
  var tmpVideo = tempDir.path + '/1.webm';
  var cmd = '-i ${widget.tmpPath} $tmpVideo';
  print('命令是:'+cmd);
  ffmpeg.execute(cmd).then((rc) {
    print("处理的结果是:$rc");
    if(rc == 0) {
      initController(tmpVideo); //使用临时地址可以播放
    } else {
      print('处理失败');
    }
  });

下边列出一些常用的ffmpeg指令

视频裁剪

从n开始,裁剪m秒长度的视频

// 从10s开始裁剪连续5s 也就是10-15s的视频
ffmpeg -i input.mp4 -ss 10 -t 5 output.mp4

从n秒开始,裁剪到m秒的视频

// 从10s开始,裁剪到20秒
ffmpeg -i input.mp4 -ss 10 -to 20 output.mp4
滤镜

https://www.cnblogs.com/tocy/p/ffmpeg-filter-intro.html

叠加两个视频:
ffmpeg -i 1.mp4 -i douyin.mp4 -filter_complex " blend=all_mode='overlay':all_opacity=0.2" blend.mp4
剪切100*100 的视频, 新视频的中心点和输入和视频的重合
ffmpeg -i douyin.mp4  -vf "crop=100:100" crop.mp4
在视频的上画一个框 drawbox
// red@0.5 50%的透明度红色
// t=1 线条的粗细 默认3  fill的话 自动填充
ffmpeg -i input.mp4 -vf "drawbox=10:10:30:30:red@0.5:t=1" output.mp4
ffmpeg -i input.mp4 -vf "drawbox=x=10:y=10:width=30:height=30color=red@0.5:t=1" output.mp4
在视频上画网格 drawgrid
画尺寸是20*20的网格
ffmpeg -i 1.mp4 -vf "drawgrid=width=20:height=20:color=red" output.mp4
画2*2的网格
ffmpeg -i 1.mp4 -vf "drawgrid=width=iw/2:height=ih/2:color=red:t=1:color=blue@0.5" output.mp4
在视频上写字 drawtext
ffmpeg -i 99.mp4 -vf "drawtext=fontsize=32:fontcolor=red:text='hello world':alpha=0.8" font.mp4

//前五秒显示 
// gte(t\,5) 大于等于5秒
// between(t\,5\,10)5到10秒
// lt(t\, 5)小于5秒
ffmpeg -i 99.mp4 -vf "drawtext=fontsize=32:fontcolor=red:text='hello world':enable='lt(t\,5)' " font.mp4

//水平居中 (w-text_w)/2
//垂直居中 (h-text_h)/2
ffmpeg -i 99.mp4 -vf "drawtext=fontsize=32:fontcolor=#cccccc:text='hello world':x=(w-text_w)/2" font2.mp4

//向右对齐 
ffmpeg -i 99.mp4 -vf "drawtext=fontsize=32:fontcolor=#cccccc:text='hello world':x=(w-text_w)" font2.mp4

// 水平垂直居中
ffmpeg -i 99.mp4 -vf "drawtext=fontsize=32:fontcolor=#cccccc:text='hello world':x=(w-text_w)/2:y=(h-text_h)/2" font2.mp4

// 滚动文本
ffmpeg -i 99.mp4 -vf "drawtext=fontsize=32:fontcolor=#cccccc:text='hello world':x=(w-50*t)" font2.mp4
饱和度/亮度/对比度 eq
// contrast 对比度 -1000-1000
// brightness 亮度 -1.0-1.0
// saturation 饱和度 0.0-3.0
ffmpeg -i 1.mp4 -vf "eq=saturation=3:brightness=0.3:contrast=1000" output.mp4
淡入淡出 fade
// 从第0帧开始到30帧淡入
ffmpeg -i 1.mp4 -vf "fade=t=in:s=0:n=30" output.mp4

// 从10秒开始淡出5秒
ffmpeg -i 1.mp4 -vf "fade=t=out:st=10:d=5" output.mp4
调整帧率 fps
ffmpeg -i 1.mp4 -vf "fps=fps=24" output.mp4
水平翻转视频
ffmpeg -i 1.mp4 -vf "hflip" output.mp4
倒放 reverse
ffmpeg -i input.mp4 -vf "reverse" output.mp4
旋转 rotate
旋转45度
ffmpeg -i input.mp4 -vf "rotate=PI/4"

转圈圈
ffplay -i 99.mp4 -vf "rotate=n*PI/3:c=red"

调整输出尺寸 修改输出宽度等于输入宽度的对角线
ffplay -i 99.mp4 -vf "rotate=n*PI/3:ow=hypot(iw, ih):oh=ow"
缩放 scale
ffplay -i 99.mp4 -vf "scale=100x100"
ffplay -i 99.mp4 -vf "scale=w=0.8*iw:h=0.8*ih"


// 宽度为100,iw较小的值 高度等比例缩小
ffplay -i 99.mp4 -vf "scale=w=min(100\,iw):h=-1"
合并 concat
// 视频的尺寸要一样大 如果不一样大的话 可以使用pad补边界 
ffmpeg -i 1.mp4 -i douyin.mp4 -i 3.1.mp4 -filter_complex "[0:v:0][0:a:0][1:v:0][1:a:0][2:v:0][2:a:0]concat=n=3:v=1:a=1[ov][oa]" -map "[ov]" -map "[oa]" -vsync 2 output.mp4

// 图片和视频合并 需要调整视频图片的尺寸和视频一样
ffmpeg -loop 1 -framerate 25 -t 5 -i logo.png -i 3.mp4 -filter_complex "[0]scale=1280x720[01];[01][1:v:0]concat=n=2:v=1[ov]" -map "[ov]" 33.mp4

ffmpeg -loop 1 -framerate 25 -t 5 -i logo.png -i 3.mp4 -filter_complex "[0]pad=w=1280:h=720:w=(1280-iw)/2:y=(720-ih)/2[01];[01][1:v:0]concat=n=2:v=1[ov]" -map "[ov]" 33.mp4

ffmpeg -loop 1 -framerate 29.42 -t 10 -i 1.s.jpg -i 1.mp4 -filter_complex "[0]scale=480:480, setsar=1[im];[1]scale=480:480, setsar=1[iv];[im][1:a][iv][1:a]concat=n=2:v=1:a=1[outv][outa]" -map "[outa]" -map "[outv]" output.mp4

// 图片生成视频
ffmpeg -f lavfi -t 10 -i anullsrc -loop 1 -framerate 10 -t 5 -i 1.jpg -vf "scale=664x478" -pix_fmt yuv420p output.mp4

// 添加第三条音频
 ffmpeg -i im.mp4 -i douyin.mp4 -i 1.mp3 -filter_complex "[0]scale=544x960,setsar=1[iv];[1]setsar=1[dv];[iv][0:a:0][dv][1:a:0]concat=n=2:v=1:a=1[ov][oa]" -map "[ov]" -map "[oa]" -map 2:a:0 -vsync 2 output.mp4

ffmpeg -i im.mp4 -i douyin.mp4 -i 1.mp3 -filter_complex "[0]scale=544x960,setsar=1[iv];[1]setsar=1[dv];[iv][0:a:0][dv][1:a:0]concat=n=2:v=1:a=1[ov][oa];[2:a:0][oa]amix=inputs=2:duration=first:dropout_transition=3[aa]" -map "[ov]" -map "[aa]" -vsync 2 output.mp4
提取视频缩略图
// 三秒一张 fps=1/3 
ffmpeg -i input.mp4 -vf "fps=1/3, scale=128:72" output_%d.jpg
  >>> 音视频开发 视频教程: https://ke.qq.com/course/3202131?flowToken=1031864 
  >>> 音视频开发学习资料、教学视频,免费分享有需要的可以自行添加学习交流群 739729163 领取

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/716890.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ipa上架App Store【uniapp-ios】

前置条件&#xff1a;已获取到.mobileprovision描述文件、.p12证书并打包生成ipa包 &#xff08;如果还没获取证书、描述文件等可以去看我前两篇博客&#xff1a;uniapp-ios打包步骤 、uniapp-ios打包安装测试。一篇是已经付费了即已经注册了Apple Developer Program&#xf…

迈瑞BC系列出图汇总

迈瑞的几个仪器出图需要画图&#xff0c;搞的很费劲&#xff0c;没办法&#xff0c;厂商自己不改&#xff0c;明明有图发Base64串的&#xff0c;就非两个图要自己画&#xff0c;画的方法又描述不清。每个LIS厂商都要浪费很多时间&#xff0c;没什么必要浪费在这种没意义的事情上…

Cannot find tomcat-9.0.0.M21/bin/setclasspath.sh

问题描述&#xff1a;将linux上的tomcat直接拷贝到以一个路径下&#xff0c;执行sh startup.sh 报错 解决&#xff1a;修改全局变量配置文件 1、vim /etc/profile &#xff08;主要修改如下图所标记的值 &#xff09; 2、source /etc/profile &#xff08;设置环境变量立即…

JMeter之事务控制器实践

目录 前言 事务控制器 JMeter控制器添加路径&#xff1a; Generate parent sample 1、不勾选任何选项&#xff1a; 2、勾选【Generate parent sample】 3、Include duration of timer and pre-post processors in generated sample 小结 前言 在JMeter中&#xff0c;事…

最牛整理,selenium自动化测试-鼠标/键盘操作(实战详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 selenium鼠标操作…

python爬虫快速入门

Python有其简洁明了&#xff0c;功能强大的优势&#xff0c;特别是在网络爬虫的应用上。接下来&#xff0c;我将分享一个适合Python初学者的爬虫快速入门教程。 一、Python爬虫简介 网页爬虫&#xff0c;是一种自动从互联网上获取信息的程序。在Python语言中&#xff0c;requ…

总结STM32嵌入式面试知识点

一、STM32F1和F4的区别&#xff1f; 内核不同&#xff1a;F1是Cortex-M3内核&#xff0c;F4是Cortex-M4内核&#xff1b;主频不同&#xff1a;F1主频72MHz&#xff0c;F4主频168MHz&#xff1b;浮点运算&#xff1a;F1无浮点运算单位&#xff0c;F4有&#xff1b;功能性能&…

Android Studio实现内容丰富的安卓汽车租赁平台

如需源码可以添加q-------3290510686&#xff0c;也有演示视频演示具体功能&#xff0c;源码不免费&#xff0c;尊重创作&#xff0c;尊重劳动。 项目编号101 1.开发环境 android stuido jdk1.8 eclipse mysql tomcat 2.功能介绍 安卓端&#xff1a; 1.注册登录 2.查看公告 3.查…

css重点学习

一、选择器 1.标签名选择器 div{border: 5px blue dotted;color: aquamarine;font-size: 20px;} <body><div id"div001">div标签1</div><div id"002">div标签2</div> </body> //只写出了重点部分 2.id选择器 #div0…

IMS:Activity和View处理InputEvent

IMS:Activity和View处理InputEvent 1、IMS服务处理2、Activity的DecorView界面添加3、Activity和View处理InputEvent3.1 InputEventReceiver接收InputEvent3.2 处理KeyEvent3.3 处理MotionEvent android12-release 1、IMS服务处理 关键流程EventHub -> InputReader -> In…

【BUUCTF-REVERSE刮开有奖】详解版

这道题是BUUCTF-REVERSE中的一道题目 拿到题目我们直接拖到Exeinfo_PE中查看&#xff0c;发现没有加壳&#xff0c;32位应用程序&#xff0c;打开应用程序看看&#xff1a; 打开是这样&#xff0c;我是没有找到编辑框&#xff0c;那直接拖到IDA中打开看看吧&#xff1a; 打开I…

使用python-opcua 实现modbus网关(2)

我们继续来研究如何使用python-opcua 实现opcua/modbus 网关。 opcua 开发包包含了大量的函数&#xff0c;通过研究opcua/modbus 网关的实现&#xff0c;可以了解这些函数的使用方法。由于函数过多&#xff0c;文章中函数的使用方式可能不尽合理&#xff0c;或者存在错误。希望…

从不同视角绘制三维散点图

import numpy as np from matplotlib import pyplot as plt positive_data arr_feature_pca[y_dbscan_pred ! -1, :] negative_data arr_feature_pca[y_dbscan_pred -1, :] # --------------------------------------- 定义绘图函数 ----------------------------------- d…

华为云函数工作流FunctionGraph新手操作指南

函数工作流&#xff08;FunctionGraph&#xff09;是华为云提供的一款无服务器&#xff08;Serverless&#xff09;计算服务&#xff0c;无服务器计算是一种托管服务&#xff0c;服务提供商会实时为你分配充足的资源&#xff0c;而不需要预留专用的服务器或容量&#xff0c;真正…

CRM的哪些功能对企业最有用?

企业如何在竞争激烈的市场环境中&#xff0c;提高销售效率&#xff0c;管理客户关系&#xff0c;实现业绩增长&#xff1f;适合的CRM客户管理系统就可以帮助很多。Zoho CRM是一款SaaS云端CRM系统&#xff0c;它能够帮助企业管理客户关系&#xff0c;提高销售效率&#xff0c;获…

springboot集成camunda

1、相关软件下载Camunda流程引擎快速入门——Hello World示例 2、由于camunda-modeler最新版本为5.12.0.界面不太一样。 可以安装历史版本4.12.0camunda-bpm camunda-modeler等历史版本下载 3、汉化Camunda Modeler汉化添加简体中文和繁体中文支持 4、集成如何实现Springbootca…

Android Studio实现内容丰富的安卓高校评教系统

如需源码可以添加q-------3290510686&#xff0c;也有演示视频演示具体功能&#xff0c;源码不免费&#xff0c;尊重创作&#xff0c;尊重劳动。 项目编号114 1.开发环境 android stuido jdk1.8 eclipse mysql tomcat 2.功能介绍 安卓端&#xff1a; 1.注册登录 2.查看公告 3.查…

口语理解任务源码详解系列(一)数据集构建

口语理解任务源码详解系列&#xff08;一&#xff09;数据集构建 写在前面 本系列从零开始构建口语理解项目&#xff0c;整个项目分为意图分类与槽位填充两个子任务。项目采用的数据集为ATIS航空领域口语理解数据集&#xff0c;项目源码请传送到&#xff1a;github 一、处理数据…

网络编程1—— IP地址 + 端口号 +TCP/IP协议 + 协议分层的封装与应用

文章目录 前言一、网络发展各阶段二、网络通信的三大要素1.IP地址2.端口号3.网络协议 三、TCP/IP五层网络模型各层级的用处网络设备所在分层 四、封装和分用封装分用网络传输的实际情况 总结 前言 本人是一个刚刚上路的IT新兵,菜鸟!分享一点自己的见解,如果有错误的地方欢迎各…

搞懂推荐系统中的评价指标NDCG(CG、DCG、IDCG)

这些指标都是衡量搜索引擎算法的指标。搜索引擎一般采用PI&#xff08;peritem&#xff09;的方式进行评测&#xff0c;简单地说就是逐条对搜索结果进行分等级的打分。假设我们现在在Google上搜索一个词&#xff0c;然后得到5个结果。我们对这些结果进行3个等级的区分&#xff…