开源短视频方案Android


trinity 是一个开源的拍摄和短视频处理工具,用 kotlin 和 c++编写,实现了大部分短视频编辑软件热门功能

https://github.com/wlanjie/trinity  ( 不支持美颜 )

开发环境  NDK R20 / Kotlin 1.3.41
开源库使用  fdk-aac / ffmpeg 3.4 / libx264 / xlogger / mnnkit
特效调试
项目中使用XCODE调试特效效果,使用前需要安装GLFW
brew install glfw
然后使用XCODE打开library/src/main/cpp/opengl.xcodeproj即可
切换效果调试代码
image_process.OnAction("param/blurScreen", 0);
自动化测试
自动化测试使用 UIAUTOMATOR2具体使用请参考文档
使用方式
cd trinity
python trinity.py
然后使用
adb devices
在终端输入设备名即可

使用(注意 SDK中没有权限判断)
添加依赖
dependencies { implementation 'com.github.wla0jie:trinity:0.2.8}
权限要求
<uses-permission android:name="android.permission.CAMERA" /><uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />


录制
配置参数
val preview = findViewById<TrinityPreviewView>(R.id.preview)
创建录制接口实例
mRecord = TrinityRecord(preview)
销毁录制接口实例
mRecord.release()

回调设置
设置视频渲染回调
mRecord.setOnRenderListener(this)
设置录制进度回调
mRecord.setOnRecordingListener(this)
设置相机回调
mRecord.setCameraCallback(this)

开启预览
开始预览
mRecord.startPreview()
结束预览
mRecord.stopPreview()

设置预览类型
// 设置显示类型
// 包含裁剪显示, 原比例上下留黑显示
mRecord.setFrame(mFrame)

录制控制 /管理
切换摄像头
mRecord.switchCamera()

获取当前摄像头
// 返回当前摄像头 id
val facing = mRecord.getCameraFacing()
开关闪光灯
mRecord.flash(mFlash)

设置 zoom
// 设置焦距缩放, 0-100 100 为最大缩放
mRecord.setZoom(0)

设置曝光度
// 设置相机曝光度, 100 为最大曝光
mRecord.setExposureCompensation(0)

手动对焦
// 设置手动对焦, 参数为 x 和 y
mRecord.focus(mPointF)

设置录制视频的角度
/**
* @param rotation 旋转角度包含 0 90 180 270
*/
mRecord.setRecordRotation(0)

设置静音录制
mRecord.setMute(false)

倍速录制
/**
* @param speed 速度包含 0.25 0.5 1.0 2.0 4.0 倍速
*/
mRecord.setSpeed(mSpeed)

开始录制
开始录制一段视频
/**
* 开始录制一段视频
* @param path 录制的视频保存的地址
* @param width 录制视频的宽, SDK 中会做 16 倍整数的运算, 可能最终输出视频的宽和设置进去的不一致
* @param height 录制视频的高, SDK 中会做 16 倍整数的运算, 可能最终输出视频的宽和设置进去的不一致
* @param videoBitRate 视频输出的码率, 如果设置的是 2000, 则为 2M, 最终输出的和设置的可能有差别
* @param frameRate 视频输出的帧率
* @param useHardWareEncode 是否使用硬编码, 如果设置为 true, 而硬编码不支持,则自动切换到软编码
* @param audioSampleRate 音频的采样率
* @param audioChannel 音频的声道数
* @param audioBitRate 音频的码率
* @param duration 需要录制多少时间
* @return Int ErrorCode.SUCCESS 为成功,其它为失败
* @throws InitRecorderFailException
*/
mRecord.startRecording("/sdcard/a.mp4", 720,1280,2000, // 2M 码率 30, false, 44100, 1, // 单声道 128, // 128K 码率  Int.MAX_VALUE)

结束录制
mRecord.stopRecording()

视频编辑
初始化
创建编辑器实例
mVideoEditor = TrinityCore.createEditor(this)

设置预览画面
val surfaceView = findViewById<SurfaceView>(R.id.surface_view)
mVideoEditor.setSurfaceView(surfaceView)

导入视频
添加一个片段
val clip = MediaClip(file.absolutePath)
mVideoEditor.insertClip(clip)

根据下标添加片段
val clip = MediaClip(file.absolutePath)
mVideoEditor.insertClip(0, clip)

删除一个片段
/**
* 根据下标删除一个片段
*/
mVideoEditor.removeClip(index)

获取片段的数量
val count = mVideoEditor.getClipsCount()

根据下标获取一个片段
/**
* 如果片段不存在, 返回一个 null
*/
val clip = mVideoEditor.getClip(index)

根据下标替换一个片段
mVideoEditor.replaceClip(index, clip)

获取所有片段
/**
* 返回所有片段的集合
*/
val clips = mVideoEditor.getVideoClips()

获取所有片段的时间总长
val duration = mVideoEditor.getVideoDuration()

获取当前播放片段的进度
val current = mVideoEditor.getCurrentPosition()

获取指定片段的开始和结束时间
val timeRange = mVideoEditor.getClipTimeRange(index)

根据时间查找片段的下标
val index = mVideoEditor.getClipIndex(time)

背景音乐
添加背景音乐
/**
* @param config 背景音乐 json 内容
* 具体 json 内容如下:
* {
*    "path": "/sdcard/trinity.mp3",
*    "startTime": 0,
*    "endTime": 2000
* }

* json 参数解释:
* path: 音乐的本地地址
* startTime: 这个音乐的开始时间
* endTime: 这个音乐的结束时间 2000 代表这个音乐只播放 2 秒钟
*/
val actionId = mVideoEditor.addMusic(config)

更新背景音乐
/**
* @param config 背景音乐 json 内容
* 具体 json 内容如下:
* {
*    "path": "/sdcard/trinity.mp3",
*    "startTime": 2000,
*    "endTime": 4000
* }
* json 参数解释:
* path: 音乐的本地地址
* startTime: 这个音乐的开始时间
* endTime: 这个音乐的结束时间 4000 代表这个音乐从开始时间到结束时间播放 2 秒钟
*/
val actionId = mVideoEditor.addMusic(config)

删除背景音乐
/**
* 删除背景音乐
* @param actionId 必须为添加背景音乐时返回的 actionId
*/
mVideoEditor.deleteMusic(actionId)

添加特效
添加普通滤镜
/**
* 添加滤镜
* 如: content.json 的绝对路径为 /sdcard/Android/com.trinity.sample/cache/filters/config.json
* 传入的路径只需要 /sdcard/Android/com.trinity.sample/cache/filters 即可
* 如果当前路径不包含 config.json 则添加失败
* 具体 json 内容如下:
* {
*  "type": 0,
*  "intensity": 1.0,
*  "lut": "lut_124/lut_124.png"
* }
*
* json 参数解释:
* type: 保留字段, 目前暂无作用
* intensity: 滤镜透明度, 0.0 时和摄像头采集的无差别
* lut: 滤镜颜色表的地址, 必须为本地地址, 而且为相对路径
*      sdk 内部会进行路径拼接
* @param configPath 滤镜 config.json 的父目录
* @return 返回当前滤镜的唯一 id
*/
val actionId = mVideoEditor.addFilter(config)

更新滤镜
/**
* 更新滤镜
* @param configPath config.json 的路径, 目前对称 addFilter 说明
* @param startTime 滤镜的开始时间
* @param endTime 滤镜的结束时间
* @param actionId 需要更新哪个滤镜, 必须为 addFilter 返回的 actionId
*/
mVideoEditor.updateFilter(config, 0, 2000, actionId)

删除滤镜
/**
 * 删除滤镜
* @param actionId 需要删除哪个滤镜, 必须为 addFilter 时返回的 actionId
*/
mVideoEditor.deleteFilter(actionId) 

添加抖音特效
/**
* 添加特效
* 如: content.json 的绝对路径为 /sdcard/Android/com.trinity.sample/cache/effects/config.json
* 传入的路径只需要 /sdcard/Android/com.trinity.sample/cache/effects 即可
* 如果当前路径不包含 config.json 则添加失败
* @param configPath 滤镜 config.json 的父目录
* @return 返回当前特效的唯一 id
*/
val actionId = mVideoEditor.addAction(configPath)

更新抖音特效
/**
* 更新指定特效
* @param startTime 特效的开始时间
* @param endTime 特效的结束时间
* @param actionId 需要更新哪个特效, 必须为 addAction 返回的 actionId
*/
mVideoEditor.updateAction(0, 2000, actionId)

删除抖音特效
/**
* 删除一个特效
* @param actionId 需要删除哪个特效, 必须为 addAction 返回的 actionId
*/
mVideoEditor.deleteAction(actionId)

开始预览
播放
/**

* @param repeat 是否循环播放

*/

mVideoEditor.play(repeat)

暂停

mVideoEditor.pause()

继续播放

mVideoEditor.resume()

停止播放

mVideoEditor.stop()

释放资源

mVideoEditor.destroy()

导出视频

创建导出实例

val export = TrinityCore.createExport(this)

开始导出

/**

  * 开始导出

  * @param info 导出实体类

  * @param l 导出回调 包含成功 失败 和进度回调

  * @return Int ErrorCode.SUCCESS 为成功,其它为失败

  */

// 创建实体类, 必须传入视频输出地址 

val exportVideoInfo = VideoExportInfo("/sdcard/export.mp4")

// 使用硬解码

exportVideoInfo.mediaCodecDecode = true

// 使用硬编码

exportVideoInfo.mediaCodecEncode = true 

// 视频宽

exportVideoInfo.width = 544

// 视频高

exportVideoInfo.height = 960

// 帧率

exportVideoInfo.frameRate = 25

// 视频码率 2M

exportVideoInfo.videoBitRate = 2000

// 采样率

exportVideoInfo.sampleRate = 44100

// 声道数

exportVideoInfo.channelCount = 1

// 音频码率 128K

exportVideoInfo.audioBitRate = 128

export.export(exportVideoInfo, this)

取消

export.cancel()

释放

export.release()


转载 *** https://v2ex.com/t/673557#reply0

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 228,505评论 6 533
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 98,556评论 3 418
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 176,463评论 0 376
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,009评论 1 312
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 71,778评论 6 410
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,218评论 1 324
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,281评论 3 441
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 42,436评论 0 288
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 48,969评论 1 335
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 40,795评论 3 354
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 42,993评论 1 369
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 38,537评论 5 359
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,229评论 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 34,659评论 0 26
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 35,917评论 1 286
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 51,687评论 3 392
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 47,990评论 2 374