-
提供短视频的拍摄、编辑、合成、上传等基础功能。
-
提供播放器支持。
1 短视频
2 上传
3 播放器
- 短视频拍摄、编辑、合成部分,包含断点录制、分段回删、美颜、大眼、瘦脸、滤镜、贴纸、视频剪辑、视频压缩、本地转码在内的 30 多种功能,支持自定义界面和二次开发。
- Eclipse 或 Android Studio 1.3 + ,Android 系统 4.3 +
- 使用短视频 SDK 需要授权(key)。请提供应用名称、申请使用的 SDK 版本、使用的平台(安卓、iOS)、包名给您的商务经理,或者联系我们 来获取授权。
1、联系我们 获取资源文件,导入至 lib 以及 assert 目录。
1、打开全局 Application
文件,全局 Application
类可以选择继承 TuSdkApplication
或不继承,然后在 onCreate
方法中使用 TuSdk.init()
方法来进行初始化,并将复制的密钥作为该方法的参数,如下:
@Override
public void onCreate()
{
TuSdk.enableDebugLog(true);
// 初始化SDK (请将目标项目所对应的密钥放在这里)
TuSdk.init(this.getApplicationContext(), "12aa4847a3a9ce68-04-ewdjn1");
}
2、为方便开发时定位错误,可打开 TuSDK 的调试日志,即在初始化密钥之前添加以下代码(放在初始化密钥之后无效):
TuSdk.enableDebugLog(true);
发布应用时请关闭日志。
在 AndroidManifest.xml
中,首先定义程序需要的权限:
<!-- 访问网络 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 获取WIFI信息 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 允许访问GPS -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 允许应用程序写数据到外部存储设备(主要是SD卡) -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 在sdcard中创建/删除文件的权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<!-- 请求访问使用照相设备 -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- 开启闪光灯权限 -->
<uses-permission android:name="android.permission.FLASHLIGHT" />
<!-- 访问麦克风 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.camera.flash" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_LOGS" />
然后定义应用的全局 Application
对象,设置 allowBackup
、hardwareAccelerated
和 largeHeap
三个重要选项为 true
。
<application
android:name="org.lasque.tusdk.TuApplication"
android:allowBackup="true"
android:hardwareAccelerated="true"
android:largeHeap="true"
</application>
除了按照集成向导步骤在AndroidManifest.xml加上权限外,在Android 6.0后都需申请动态权限,以下是打开相机所需申请的权限: String[] permissions = new String[]{ Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO };
创建并配置 TuSdkRecorderVideoCamera
对象,代码如下:
RelativeLayout cameraView = (RelativeLayout) findViewById(R.id.lsq_cameraView);
// 录制相机配置,目前只支持硬编
TuSdkRecorderCameraSetting captureSetting = new TuSdkRecorderCameraSetting();
TuSdkRecorderVideoCamera videoCamera = new TuSdkRecorderVideoCameraImpl(getBaseContext(),cameraView,captureSetting);
构造方法中需要传入下面三个参数:
(1)当前上下文(Context
)
(2)相机采集配置(TuSdkRecorderCameraSetting
)
(3)相机视图容器(RelativeLayout
)
TuSDKVideoCaptureSetting
中可以对相机采集时的多项属性进行设置,包括:
-
facing
,相机朝向(默认:CameraFacing.Front
前置) -
相机视图容器是一个
RelativeLayout
布局,一般在 XML 布局文件中指定,传入TuSDKRecordVideoCamera
构造方法中后,会将相机预览视图加载在该视图容器中。
获取录制相机对象后,可以对该相机的属性进行一些设置。
-
开启或关闭动态贴纸
// 是否开启动态贴纸(默认: false) public void setEnableLiveSticker(boolean enableLiveStickr)
-
开启或关闭自动持续对焦
// 禁用自动持续对焦 (默认: false) public void setDisableContinueFocus(boolean disableContinueFoucs)
-
设置水印(图片最大边长不宜超过 500)
// 设置水印,默认为空 public void setWaterMarkImage(Bitmap mWaterMarkImage) // 设置水印位置 public void setWaterMarkPosition(WaterMarkPosition mWaterMarkPosition)
-
设置视频录制结果委托
public void setRecorderVideoCameraCallback(TuSdkRecorderVideoCameraCallback recorderCallback)
指定录制相机的事件委托,该委托中有下面四个接口用来通知相机状态改变:
-
设置最小、最大录制时长(单位:/s)
// 设置最小录制时长 public void setMinRecordingTime(int minRecordingTime) // 设置最大录制时长 public void setMaxRecordingTime(int maxRecordingTime)
-
设置相机事件委托
使用 setDelegate(TuSDKVideoCameraDelegate)
设置相机事件委托,详细可以参看 demo 中的使用示例
-
设置相机拍照监听
public void setCameraListener(TuSdkCameraListener cameraListener)
-
设置特效改变监听
public void setMediaEffectChangeListener(TuSdkMediaEffectChangeListener mediaEffectChangeListener)
-
设置人脸检测结果回调
public void setFaceDetectionCallback(TuSdkFaceDetectionCallback faceDetectionCallback)
-
设置视频编码配置
public final void setVideoEncoderSetting(TuSdkRecorderVideoEncoderSetting videoEncoderSetting)
可以设置视频编码时的参数,包括:
videoSize
,输出视频尺寸(默认:TuSdkSize(320, 480)
)
videoQuality
,视频质量
mediacodecAVCIFrameInterval
,I 帧时间间隔 (默认:1)
enableAllKeyFrame
是否最大限度输出 I 帧,默认false
推荐使用 SDK 默认的编码配置,如下:
// 推荐编码配置
TuSdkRecorderVideoEncoderSetting encoderSetting = TuSdkRecorderVideoEncoderSetting.getDefaultRecordSetting();
mVideoCamera.setVideoEncoderSetting(encoderSetting);
-
保存系统相册
// 保存系统相册 (默认保存, 当设置为 false 时, 保存为临时文件) public void setSaveToAlbum(boolean mSaveToAlbum) // 保存到系统相册的相册名称 public void setSaveToAlbumName(String mSaveToAlbumName)
当设置 false 可 TuSdkRecorderVideoCameraCallback
回调中获取result.
-
添加开启人脸检测
public void setEnableFaceDetection(boolean enableFaceDetection)
-
是否启用音频录制
public void setEnableAudioCapture(boolean mEnableAudioCapture)
SDK 提供了多个操作相机的方法,供用户操作相机开启、关闭、恢复、暂停,如下:
-
启动相机采集
startCameraCapture()
-
停止相机采集
stopCameraCapture()
-
恢复相机采集
resumeCameraCapture()
-
暂停相机采集
pauseCameraCapture()
同时,这些方法需要配合所在 Activity 的生命周期中使用,如下:
@Override
protected void onResume()
{
super.onResume();
resumeCameraCapture();
}
@Override
protected void onPause()
{
super.onPause();
pauseCameraCapture();
}
@Override
protected void onDestroy()
{
super.onDestroy();
stopCameraCapture();
if (mVideoCamera != null) {
mVideoCamera.destroy();
}
}
录制相机对象可以通过下面四个接口控制开启、暂停和停止录制动作,以及判断是否正在录制中:
-
开始录制
startRecording()
-
暂停录制
pauseRecording()
-
结束录制
stopRecording()
-
判断是否正在录制中
isRecording()
-
录制结果
配合setSaveToAlbum
,设置true将视频保存到相册,设置false
通过TuSDKVideoResult
获取对应视频的临时文件,可进行自定义操作。
// 设置录制委托
public void setVideoDelegate(TuSDKRecordVideoCameraDelegate mDelegate)
/** 录制相机事件委托 */
public static interface TuSdkRecorderVideoCameraCallback
{
/**
* 视频录制结果
*
* @param result
* 视频结果
*/
void onMovieRecordComplete(TuSDKVideoResult result);
/**
* 录制进度改变 (运行在主线程)
*
* @param progress 当前录制进度( 0 - 1 ) 相对于mMaxRecordingTime
* @param durationTime 当前录制持续时间 单位:/s
*/
void onMovieRecordProgressChanged(float progress, float durationTime);
/**
* 录制状态改变
* @param state
*/
void onMovieRecordStateChanged(RecordState state);
/**
* 录制出错
*
*/
void onMovieRecordFailed(RecordError error);
}
-
相机状态
/** 相机运行状态 */ public enum CameraState { /** 未知状态 */ StateUnknow, /** 正在启动 */ StateStarting, /** 已经启动 */ StateStarted, /** 正在拍摄 */ StateCapturing, /** 拍摄完成 */ StateCaptured }
-
录制状态
/** 录制状态 */ public enum RecordState { /** 录制中 */ Recording, /** 正在保存视频 */ Saving, /** 暂停录制 */ Paused, /** 录制完成 */ RecordCompleted, /** 已取消 */ Canceled, }
-
错误状态
/** 录制时错误 */ public enum RecordError { /** 未知错误 */ Unknow, /** 可用空间不足 */ NotEnoughSpace, /** 无效的录制时间(录制时间较短无法生成视频) */ InvalidRecordingTime, /** 低于最小录制时间 */ LessMinRecordingTime, /** 超过最大录制时间 */ MoreMaxDuration, /** 保存失败 */ SaveFailed, }
-
拍摄图片
captureImage()
-
可通过
TuSdkCameraListener
获取拍照结果/** Video Camera Delegate */ public static interface TuSdkCameraListener { /** * 滤镜更改事件,每次调用 switchFilter 切换滤镜后即触发该事件,运行在主线程 * * @param filter 新的滤镜对象 * @since V3.2.0 */ void onFilterChanged(FilterWrap filter); /** * 相机状态改变 (如需操作UI线程, 请检查当前线程是否为主线程) * * @param camera * 相机对象 * @param newState * 相机运行状态 */ void onVideoCameraStateChanged(TuSdkStillCameraAdapter.CameraState newState); /** * 获取截屏图片 * * @param camera * 相机对象 * @param bitmap * 图片 */ void onVideoCameraScreenShot(Bitmap bitmap); }
使用自定义 RegionHandler
可以实现把相机预览视图(非全屏时)上下左右移动指定距离的功能。 可以新建子类继承 RegionDefaultHandler
,然后子类中重写下面三个方法:
void setWrapSize(TuSdkSize size)
RectF recalculate(float ratio, TuSdkSize size)
RectF changeWithRatio(float ratio, RegionChangerListener listener)
然后使用 mVideoCamera.setRegionHandler(RegionHandler)
方法将自己的子类设置进去,最后使用 mVideoCamera.changeRegionRatio(float)
方法刷新视图,使 regionHandler
生效。 以 1:1 视图为例:
// 刷新视图,使 regionHandler 生效, 1:1 视图
mVideoCamera.changeRegionRatio(1.0f);
在 Demo 中是以 1:1 视图显示的,如果要修改成全屏显示,需要修改两个地方:
-
删除自定义的
RegionHandler
-
将
mVideoCamera.changeRegionRatio(1.0f)
中的参数修改为 0
- 特效数据改变监听
可以根据返回TuSdkMediaEffectData数据类型分类处理。
/**
* 特效数据改变
*
* @since V3.2.0
**/
public static interface TuSdkMediaEffectChangeListener {
/**
* 一个新的特效将要被应用
*
* @param mediaEffectData 将要应用的特效数据
* @since V3.2.0
*/
void didApplyingMediaEffect(TuSdkMediaEffectData mediaEffectData);
/**
* 特效将要被移除的特效
*
* @param mediaEffects
* @since V3.2.0
*/
void didRemoveMediaEffect(List<TuSdkMediaEffectData> mediaEffects);
}
可以返回人脸检测到的FaceDetectionResultType
和人脸个数。
/**
* 人脸检测结果委托
*
* @since V3.2.0
*/
public enum FaceDetectionResultType {
/**
* Succeed
*/
FaceDetected,
/**
* No face is detected
*/
NoFaceDetected,
}
/**
* 人脸检测委托
*
* @since V3.2.0
*/
public interface TuSdkFaceDetectionCallback {
/**
* 人脸检测结果
*
* @param resultType 人脸检测结果类型
* @param faceCount 检测到的人脸数量
* @since V3.2.0
*/
void onFaceDetectionResult(FaceDetectionResultType resultType, int faceCount);
}
可以在打包下载的资源文件中找到 lsq_tusdk_configs.json
文件,之前在控制台所打包的滤镜资源会在这个文件中显示,比如"name":"lsq_filter_VideoFair"
,则该滤镜的 filterCode
即为 VideoFair
,需注意大小写。 可以将需要用到的 filterCode
放到一个滤镜数组中,切换滤镜时从该数组中取出 filterCode
即可,如下:
// 要支持多款滤镜,直接添加到数组即可
private String[] videoFilters = new String[]{"VideoFair"};
Demo中滤镜列表使用FilterRecyclerAdapter
和RecyclerView
实现
this.mFilterAdapter.setFilterList(Arrays.asList(Constants.VIDEOFILTERS));
详细实现可以参考短视频 Demo 中的示例。
同时用户也可以使用自己的列表来显示滤镜,并可以自定义滤镜的缩略图(替换掉对应名称的图片即可)。
-
通过滤镜 Code 使用普通滤镜
mCamera.addMediaEffectData(new TuSdkMediaFilterEffectData(code));
-
通过滤镜 Code 使用动漫滤镜
mCamera.addMediaEffectData(new TuSdkMediaComicEffectData(code));
通过 TuSdkMediaEffectChangeListener
返回的TuSdkMediaEffectData
进行滤镜参数调节,滤镜调节包含效果mixied
等,我们提供了专门的参数调节View可进行快捷设置。
mFilterConfigView.setFilterArgs(mediaEffectData,filterArg);
// 获取滤镜返回的调节参数
List<SelesParameters.FilterArg> filterArgs = mediaEffectData.getFilterArgs()
// 设置最大值限制范围 默认1.0,smoothing、mixied建议0.7,whitening建议 0.6
filterArg.setMaxValueFactor(factor);
// 设置对应的百分比值
filterArg.setPrecentValue(precentValue);
// 提交修改后的参数
mediaEffectData.submitFilterParameter();
设置微整形特效
// 添加一个默认微整形特效
TuSdkMediaPlasticFaceEffect plasticFaceEffect = new TuSdkMediaPlasticFaceEffect();
mCamera.addMediaEffectData(plasticFaceEffect);
// 以下为改变默认值进行提交参数
for (SelesParameters.FilterArg arg : plasticFaceEffect.getFilterArgs()) {
if (arg.equalsKey("eyeSize")) {// 大眼
arg.setMaxValueFactor(0.85f);// 最大值限制
}
if (arg.equalsKey("chinSize")) {// 瘦脸
arg.setMaxValueFactor(0.8f);// 最大值限制
}
if (arg.equalsKey("noseSize")) {// 瘦鼻
arg.setMaxValueFactor(0.6f);// 最大值限制
}
}
for (String key : mDefaultBeautyPercentParams.keySet()) {
submitPlasticFaceParamter(key,mDefaultBeautyPercentParams.get(key));
}
详细实现可以参考短视频 Demo 中的示例。
设置美肤特效 true 自然(精准)美颜 false 极致美颜
TuSdkMediaSkinFaceEffect skinFaceEffect = new TuSdkMediaSkinFaceEffect(true);
// 美白
SelesParameters.FilterArg whiteningArgs = skinFaceEffect.getFilterArg("whitening");
whiteningArgs.setMaxValueFactor(0.6f);//设置最大值限制
// 磨皮
SelesParameters.FilterArg smoothingArgs = skinFaceEffect.getFilterArg("smoothing");
smoothingArgs.setMaxValueFactor(0.7f);//设置最大值限制
whiteningArgs.setPrecentValue(0.3f);//设置默认显示
smoothingArgs.setPrecentValue(0.6f);//设置默认显示
mCamera.addMediaEffectData(skinFaceEffect);
详细实现可以参考短视频 Demo 中的示例。
Demo中贴纸使用ViewPager
和Fragment
进行分类页面展示。 同时用户也可以使用自己的列表来显示贴纸,详细实现可以参考短视频 Demo。
/**
* 设置道具适配器
*/
public void init(final FragmentManager fm){
// 添加贴纸道具分类数据
mPropsItemCategories.addAll(PropsItemStickerCategory.allCategories());
// 添加哈哈镜道具分类
mPropsItemCategories.addAll(PropsItemMonsterCategory.allCategories());
mPropsItemPagerAdapter = new PropsItemPagerAdapter(fm, new PropsItemPagerAdapter.DataSource() {
@Override
public Fragment frament(int pageIndex) {
PropsItemCategory category = mPropsItemCategories.get(pageIndex);
switch (category.getMediaEffectType()) {
case TuSdKMediaEffectDataTypeSticker: {
StickerPropsItemPageFragment fragment = new StickerPropsItemPageFragment(pageIndex, mPropsItemCategories.get(pageIndex).getItems());
fragment.setItemDelegate(mStickerPropsItemDelegate);
return fragment;
}
default: {
PropsItemMonsterPageFragment fragment = new PropsItemMonsterPageFragment(pageIndex, mPropsItemCategories.get(pageIndex).getItems());
fragment.setItemDelegate(mPropsItemDelegate);
return fragment;
}
}
}
@Override
public int pageCount() {
return mPropsItemCategories.size();
}
});
mPropsItemViewPager.setAdapter(mPropsItemPagerAdapter);
mPropsItemTabPagerIndicator.setViewPager(mPropsItemViewPager,0);
mPropsItemTabPagerIndicator.setDefaultVisibleCounts(mPropsItemCategories.size());
List<String> itemTitles = new ArrayList<>();
for (PropsItemCategory category : mPropsItemCategories)
itemTitles.add(category.getName());
mPropsItemTabPagerIndicator.setTabItems(itemTitles);
}
贴纸道具主要实现部分StickerPropsItemPageFragment
,请参考Demo实现。
-
贴纸应用和取消
// 应用贴纸 TuSdkMediaStickerEffectData mediaStickerEffectData = new TuSdkMediaStickerEffectData(itemData); mVideoCamera.addMediaEffectData(mediaStickerEffectData); // 移除贴纸 mVideoCamera.removeMediaEffectsWithType(TuSdkMediaEffectData.TuSdkMediaEffectDataType.TuSdKMediaEffectDataTypeSticker);
-
贴纸下载
请参考Demo中StickerRecyclerAdapter
类
通过TuSDKOnlineStickerDownloader
下载器进行贴纸下载控制
// 初始下载器
mStickerDownloader = new TuSDKOnlineStickerDownloader();
// 设置下载回到
mStickerDownloader.setDelegate(this);
// 下载贴纸
public final void downloadStickerGroup(StickerGroup stickerGroup)
/**
* 下载事件委托
*
* @author gh.li
*
*/
public static interface TuSDKOnlineStickerDownloaderDelegate
{
/**
* 下载进度改变
*
* @param stickerGroupId
* 贴纸分组
* @param progress
* 当前进度
* @param status
* 状态
*/
public void onDownloadProgressChanged(long stickerGroupId, float progress, DownloadTaskStatus status);
}
- 动态贴纸配置分类
在资源文件夹raw下配置 customstickercategories.json
,格式如下
{
"categories": [
{
"categoryName": "搞怪cos",
"stickers": [
{
"name": "晕",
"id": "1622",
"previewImage": "/stickerGroup/img?id=1622"
},
{
"name": "京剧花旦",
"id": "1591",
"previewImage": "/stickerGroup/img?id=1591"
}
}]
}
动态贴纸资源需是控制台在线资源与打包资源里的动态贴纸,贴纸详情可在点击贴纸图片或者点击查看按钮查询
categoryName
组名 name
可使用官网预设名称,也可自定义
id
使用官网贴纸资源id
previewImage
id=官网贴纸资源id
- 获取动态贴纸配置分类文件
贴纸根据集成文档进行上线、打包等操作。
打包过的动态贴纸资源可在贴纸列表里直接使用,在线贴纸如果没有下载过则在列表里显示下载图标,下载至本地后才能使用。
/**
* 获取所有贴纸分类
*
* @return List<PropsItemStickerCategory>
*/
public static List<PropsItemStickerCategory> allCategories() {
List<PropsItemStickerCategory> categories = new ArrayList<>();
try {
InputStream stream = TuSdkContext.context().getResources().openRawResource(R.raw.customstickercategories);
if (stream == null) return null;
byte buffer[] = new byte[stream.available()];
stream.read(buffer);
String json = new String(buffer, "UTF-8");
JSONObject jsonObject = JsonHelper.json(json);
JSONArray jsonArray = jsonObject.getJSONArray("categories");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject item = jsonArray.getJSONObject(i);
// 该分类下的所有贴纸道具
List<PropsItemSticker> propsItems = new ArrayList<PropsItemSticker>();
JSONArray jsonArrayGroup = item.getJSONArray("stickers");
for (int j = 0; j < jsonArrayGroup.length(); j++) {
JSONObject itemGroup = jsonArrayGroup.getJSONObject(j);
StickerGroup group = new StickerGroup();
group.groupId = itemGroup.optLong("id");
group.previewName = itemGroup.optString("previewImage");
group.name = itemGroup.optString("name");
PropsItemSticker propsItem = new PropsItemSticker(group);
propsItems.add(propsItem);
}
// 该贴纸道具分类
PropsItemStickerCategory category = new PropsItemStickerCategory(propsItems);
category.setName(item.getString("categoryName"));
categories.add(category);
}
} catch (Exception e) {
e.printStackTrace();
}
return categories;
}
详细实现可以参考短视频 Demo 中的示例。
哈哈镜道具主要实现部分PropsItemMonsterPageFragment
,请参考Demo实现。
-
哈哈镜应用和取消
// 应用哈哈镜 TuSDKMediaMonsterFaceEffect monsterFaceEffect = new TuSDKMediaMonsterFaceEffect(monsterFaceType); mVideoCamera.addMediaEffectData(monsterFaceEffect); // 移除哈哈镜 mVideoCamera.removeMediaEffectsWithType(TuSdkMediaEffectData.TuSdkMediaEffectDataType.TuSdkMediaEffectDataTypeMonsterFace);
-
哈哈镜分类
/** * 获取所有哈哈镜分类 * * @return List<PropsItemMonsterCategory> */ public static List<PropsItemMonsterCategory> allCategories() { TuSDKMonsterFaceWrap.TuSDKMonsterFaceType[] faceTypes = { TuSDKMonsterFaceTypeBigNose, // 大鼻子 TuSDKMonsterFaceTypePapayaFace, // 木瓜脸 TuSDKMonsterFaceTypePieFace, // 大饼脸 TuSDKMonsterFaceTypeSmallEyes, // 眯眯眼 TuSDKMonsterFaceTypeSnakeFace, // 蛇精脸 TuSDKMonsterFaceTypeSquareFace, // 国字脸 TuSDKMonsterFaceTypeThickLips // 厚嘴唇 }; // 缩略图后缀 String[] faceTypeTitles = { "bignose", "papaya", "pie", "smalleyes", "snake", "square", "thicklips" }; List<PropsItemMonsterCategory> categories = new ArrayList<>(); List<PropsItemMonster> monsters = new ArrayList<>(); for (int i = 0; i<faceTypes.length; i++) { PropsItemMonster monster = new PropsItemMonster(faceTypes[i]); monster.setThumbName(faceTypeTitles[i]); monsters.add(monster); } PropsItemMonsterCategory monsterCategory = new PropsItemMonsterCategory(monsters); monsterCategory.setName(TuSdkContext.getString(R.string.lsq_face_monster)); categories.add(monsterCategory); return categories; }
-
变调参数设置须在点击录制按钮前调用,支持断点录制下不同声调的变换
public void setSoundPitchType(TuSdkAudioPitchEngine.TuSdkSoundPitchType soundPitchType)
-
支持的声调:正常,怪兽,大叔,女生,萝莉
public enum TuSdkSoundPitchType { //正常 Normal, //怪兽 Monster, //大叔 Uncle, //女生 Girl, //萝莉 Lolita; }
设置正常、快速、极快、慢速、极慢多种模式。
-
设置快速模式
public void setSpeedMode(SpeedMode speedMode)
/** 速率模式 */ public enum SpeedMode { NORMAL, // 正常 FAST1, // 快速 FAST2, // 极快 Slow1, // 慢速 Slow2; // 极慢
private float mSpeedRate;
SpeedMode(float speedRate) { this.mSpeedRate = speedRate; }
}
类名
功能说明
MovieAlbumActivity
对视频列表进行选择
其中需要说明这几个参数
/* 最小视频时长(单位:ms) */
private static int MIN_VIDEO_DURATION = 3000;
/* 最大视频时长(单位:ms) */
private static int MAX_VIDEO_DURATION = 60000;
/** 最大边长限制 **/
private static final int MAX_SIZE = 3840;
最大边长限制,我们限制在了4K以下,因为不同的厂商的手机对4K的支持不同,我们统一限制视频为4K以下的视频可以编辑
类名
功能说明
MovieEditorCutActivity
编辑-裁剪页面
TuSdkMediaMutableFilePlayer
视频播放器(支持多文件)
TuSdkMediaFilesCuterImpl
裁剪器(支持多文件)
TuSdkVideoImageExtractor
封面抽取(支持多文件)
- 传入视频路径列表
进入MovieEditorCutActivity
需要在打开这个activity
的时候通过Bundle
传入视频路径,SerializableExtr
的name
为videoPaths
-
获取视频裁剪栏缩略图,用于裁剪栏的展示。
/** 加载视频缩略图 */ public void loadVideoThumbList() { List<TuSdkMediaDataSource> sourceList = new ArrayList<>(); for (MovieInfo movieInfo : mVideoPaths) sourceList.add(TuSdkMediaDataSource.create(movieInfo.getPath()).get(0)); /** 准备视频缩略图抽取器 */ final TuSdkVideoImageExtractor imageThumbExtractor = new TuSdkVideoImageExtractor(sourceList); imageThumbExtractor //.setOutputImageSize(TuSdkSize.create(50,50)) // 设置抽取的缩略图大小 .setExtractFrameCount(20) // 设置抽取的图片数量 .setImageListener(new TuSdkVideoImageExtractorListener() { /** * 输出一帧略图信息 * * @param videoImage 视频图片 * @since v3.2.1 */ public void onOutputFrameImage(final TuSdkVideoImageExtractor.VideoImage videoImage) { ThreadHelper.post(new Runnable() { @Override public void run() { mEditorCutView.addBitmap(videoImage.bitmap); if(!isSetDuration) { float duration = mVideoPlayer.durationUs() / 1000000.0f; mEditorCutView.setRangTime(duration); mEditorCutView.setTotalTime(mVideoPlayer.durationUs()); if(duration >0) isSetDuration = true; } mEditorCutView.setMinCutTimeUs(mMinCutTimeUs/(float)mDurationTimeUs); } }); } /** * 抽取器抽取完成 * * @since v3.2.1 */ @Override public void onImageExtractorCompleted(List<TuSdkVideoImageExtractor.VideoImage> videoImagesList) { /** 注意: videoImagesList 需要开发者自己释放 bitmap */ imageThumbExtractor.release(); } }) .extractImages(); // 抽取图片 }
-
裁剪控制器会对视频本身进行裁剪处理,导出视频并保存到临时文件夹中,用户可自定义处理。
/** * 开始合成视频 */ private void startCompound(){ if (cuter != null) { return; } isCutting = true; List<TuSdkMediaDataSource> sourceList = new ArrayList<>(); // 遍历视频源 for (MovieInfo movieInfo : mVideoPaths) { sourceList.add(TuSdkMediaDataSource.create(movieInfo.getPath()).get(0)); } // 准备切片时间 TuSdkMediaTimeSlice tuSdkMediaTimeSlice = new TuSdkMediaTimeSlice(mLeftTimeRangUs,mRightTimeRangUs); tuSdkMediaTimeSlice.speed = mVideoPlayer.speed(); // 准备裁剪对象 cuter = new TuSdkMediaFilesCuterImpl(); // 设置裁剪切片时间 cuter.setTimeSlice(tuSdkMediaTimeSlice); // 设置数据源 cuter.setMediaDataSources(sourceList); // 设置文件输出路径 cuter.setOutputFilePath(getOutputTempFilePath().getPath()); // 准备视频格式 MediaFormat videoFormat = TuSdkMediaFormat.buildSafeVideoEncodecFormat( cuter.preferredOutputSize().width, cuter.preferredOutputSize().height, 30, TuSdkVideoQuality.RECORD_MEDIUM2.getBitrate(), MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface, 0, 0); // 设置视频输出格式 cuter.setOutputVideoFormat(videoFormat); // 设置音频输出格式 cuter.setOutputAudioFormat(TuSdkMediaFormat.buildSafeAudioEncodecFormat()); // 开始裁剪 cuter.run(new TuSdkMediaProgress() { /** * 裁剪进度回调 * @param progress 进度百分比 0-1 * @param mediaDataSource 当前处理的视频媒体源 * @param index 当前处理的视频索引 * @param total 总共需要处理的文件数 */ @Override public void onProgress(final float progress, TuSdkMediaDataSource mediaDataSource, int index, int total) { ThreadHelper.post(new Runnable() { @Override public void run() { mLoadContent.setVisibility(View.VISIBLE); mLoadProgress.setValue(progress * 100); } }); } /** * 裁剪结束回调 * @param e 如果成功则为Null * @param outputFile 输出文件路径 * @param total 处理文件总数 */ @Override public void onCompleted(Exception e, TuSdkMediaDataSource outputFile, int total) { isCutting = false; ThreadHelper.post(new Runnable() { @Override public void run() { setEnable(true); mLoadContent.setVisibility(View.GONE); mLoadProgress.setValue(0); mPlayBtn.setVisibility(mVideoPlayer.isPause()?View.VISIBLE:View.GONE); } }); Intent intent = new Intent(MovieEditorCutActivity.this,MovieEditorActivity.class); intent.putExtra("videoPath", outputFile.getPath()); startActivity(intent); cuter = null; } }); }
-
视频裁剪可以对输出视频设置时间范围、画布裁剪、图像裁剪等,示例如下:
// 设置裁剪切片 public void setTimeSlice(TuSdkMediaTimeSlice slice) // 设置数据源 public final void setMediaDataSources(List mediaDataSources) // 设置输出文件路径 public void setOutputFilePath(String filePath) // 设置输出视频格式 public int setOutputVideoFormat(MediaFormat videoFormat) // 设置输出音频格式 public int setOutputAudioFormat(MediaFormat audioFormat) // 进行裁剪 public boolean run(TuSdkMediaProgress progress)
裁剪的回调为
/** 媒体处理进度接口 */
public interface TuSdkMediaProgress {
/**
* 执行进度 [主线程]
*
* @param progress 进度百分比 0-1
* @param mediaDataSource 当前处理的视频媒体源
* @param index 当前处理的视频索引
* @param total 总共需要处理的文件数
*/
void onProgress(float progress, TuSdkMediaDataSource mediaDataSource, int index, int total);
/***
* 完成转码 [主线程]
* @param e 如果成功则为Null
* @param outputFile 输出文件路径
* @param total 处理文件总数
*/
void onCompleted(Exception e, TuSdkMediaDataSource outputFile, int total);
}
由MovieEditorCutActivity
转码后,进入了视频编辑MovieEditorActivity
页面,
类名
功能描述
MovieEditorActivity
视频编辑页面
MovieEditorController
视频编辑控制器
TuSdkMovieEditor
视频编辑器
视频编辑的功能是由TuSdkMovieEditor
提供,Demo界面以及相关操作,都在MovieEditorController
里以操作组件的方式封装
- 视频编辑控制器的结构与组成
类名
功能描述
EditorHomeComponent
视频编辑主页面组件
EditorFilterComponent
滤镜效果组件
EditorMVComponent
MV效果组件
EditorMusicComponent
配音效果组件
EditorTextComponent
文字效果组件
EditorEffectComponent
特效组件(包括场景特效、时间特效、魔法特效)
在MovieEditorController
的构造方法中需要初始化视频编辑器,以下是一个最简单的视频加载逻辑。
/**
* context 当前context
* holderView 视频播放器的父容器
* options 视频配置项
**/
TuSdkMovieEditor mMovieEditor = new TuSdkMovieEditorImpl(context, holderView, options);
//之前经历过MovieEditorCutActivity裁剪加载 则不用开启转码
mMovieEditor.setEnableTranscode(false);
//加载视频
mMovieEditor.loadVideo();
接口描述:
-
设置转码
/** * 是否开启转码 * * @param isEnableTranscode true 开启 false 不开启 默认开启 */ public void setEnableTranscode(boolean isEnableTranscode);
-
加载视频
/** * 加载视频 * * @since 3.0 */ void loadVideo();
-
保存视频
/** * 保存视频 * * @since 3.0 */ void saveVideo();
简单使用方式如下:
TuSdkMovieEditor.TuSdkMovieEditorOptions defaultOptions = TuSdkMovieEditor.TuSdkMovieEditorOptions.defaultOptions();
defaultOptions
// 设置视频数据源
.setVideoDataSource(new TuSdkMediaDataSource(mVideoPath))
// 设置是否保存或者播放原音
.setIncludeAudioInVideo(true)
// 设置MovieEditor销毁时是否自动清除缓存音频解码信息
.setClearAudioDecodeCacheInfoOnDestory(false)
// 设置时间线模式
.setPictureEffectReferTimelineType(TuSdkMediaEffectReferInputTimelineType)
// 设置水印
.setWaterImage(BitmapHelper.getBitmapFormRaw(this, R.raw.sample_watermark), TuSdkWaterMarkOption.WaterMarkPosition.TopRight, true);
接口描述:
-
设置视频数据源
public TuSdkMovieEditorOptions setVideoDataSource(TuSdkMediaDataSource videoDataSource);
-
设置影片保存路径
public TuSdkMovieEditorOptions setMovieOutputFilePath(File movieOutputFilePath);
-
设置视频裁剪区域
public TuSdkMovieEditorOptions setCutTimeRange(TuSDKTimeRange cutTimeRange);
-
设置画布裁剪区域
public TuSdkMovieEditorOptions setCanvasRectF(RectF canvasRect);
-
设置是否保存视频原音 默认 true
public TuSdkMovieEditorOptions setIncludeAudioInVideo(boolean includeAudioInVideo);
-
设置视频画面特效参照时间线类型
public TuSdkMovieEditorOptions setPictureEffectReferTimelineType(TuSdkMediaPictureEffectReferTimelineType timelineType);
-
设置视频输出的宽高
public TuSdkMovieEditorOptions setOutputSize(TuSdkSize outputSize);
-
设置是否将视频保存到相册 默认:true
public TuSdkMovieEditorOptions setSaveToAlbum(Boolean saveToAlbum);
-
保存到系统相册的相册名称 (saveToAlbum 为true时可用)
public TuSdkMovieEditorOptions setSaveToAlbumName(String saveToAlbumName);
-
MovieEditor销毁时是否自动清除音频缓存信息(默认:false 设置为false下次再次使用时可加快载入速度)
public TuSdkMovieEditorOptions setClearAudioDecodeCacheInfoOnDestory(boolean clearAudioDecodeCacheInfoOnDestory);
-
设置水印图片
/**
- waterImage 水印图片 (Bitmap)
- watermarkPosition 水印的位置
- isRecycleWaterImage 是否回收水印图片(Bitmap) **/ public TuSdkMovieEditorOptions setWaterImage(Bitmap waterImage, TuSdkWaterMarkOption.WaterMarkPosition watermarkPosition, boolean isRecycleWaterImage)
视频编辑TuSdkMovieEditor
中由一下几个组件组成,调用的时候通过一下不同的功能组件调用不同的API
TuSdkEditorTranscoder
转码器 如果没有预转码或者开启了转码,则由此转码器进行视频的裁剪与处理TuSdkEditorPlayer
播放器 编辑内的播放器,负责控制时间特效,以及相关播放的APITuSdkEditorEffector
特效器 负责特效 添加 删除相关的APITuSdkEditorAudioMixer
混音器 混音相关的APITuSdkEditorSaver
保存器 最后保存视频的相关API
相关特效分为普通特效和时间特效两种 普通特效:
特效类名
功能描述
TuSDKMediaTextEffectData
文字贴纸特效
TuSDKMediaParticleEffectData
魔法特效
TuSDKMediaStickerAudioEffectData
MV特效
TuSDKMediaFilterEffectData
滤镜效果
TuSDKMediaStickerEffectData
贴纸特效
TuSDKMediaAudioEffectData
配音特效
TuSDKMediaSceneEffectData
场景特效
TuSDKMediaComicEffectData
卡通特效
上述特效由TuSdkEditorEffector
特效器进行_添加_ 、_删除_的操作,下列三种是时间特效,由TuSdkEditorPlayer
管理
特效类名
功能描述
TuSDKMediaReversalTimeEffect
倒序时间特效
TuSDKMediaRepeatTimeEffect
反复时间特效
TuSDKMediaSlowTimeEffect
慢动作时间特效
在EditorFilterComponent
中mFilterRecyclerView
的Item
点击回调内,回去到当前点击的滤镜的code
(通过mFilterRecyclerAdapter.setFilterList(filterList)
设置)
-
滤镜列表,获取滤镜前往 TuSDK.bundle/others/lsq_tusdk_configs.json
-
TuSDK 滤镜信息介绍 @see-https://tusdk.com/docs/ios/self-customize-filter
TuSDKMediaFilterEffectData mediaFilterEffectData = new TuSDKMediaFilterEffectData(code); getMovieEditor().getEditorEffector().addMediaEffectData(filterEffectData);
滤镜的改变回调可以通过TuSdkEditorEffector
来设置
//设置滤镜改变的回调
getEditorEffector().setFilterChangeListener(mFilterChangeListener);
在EditorMVComponent
中的mMvRecyclerView
的Item
点击回调内
/********************* 添加 *************/
if (mMusicMap != null && mMusicMap.containsKey(groupId)) {
//带音效的MV
Uri uri = Uri.parse("android.resource://" + getEditorController().getActivity().getPackageName() + "/" + mMusicMap.get(groupId));
//创建MV数据类
TuSDKMediaStickerAudioEffectData stickerAudioEffectDat = new TuSDKMediaStickerAudioEffectData(new TuSdkMediaDataSource(context, uri), itemData);
//设置时间范围
stickerAudioEffectDat.setAtTimeRange(TuSDKTimeRange.makeRange(0, Float.MAX_VALUE));
//设置MV的背景音效是否循环播放
stickerAudioEffectDat.getMediaAudioEffectData().getAudioEntry().setLooping(true);
//添加MV效果
getEditorEffector().addMediaEffectData(stickerAudioEffectDat);
} else {
//纯贴纸的MV
TuSDKMediaStickerEffectData stickerEffectData = new TuSDKMediaStickerEffectData(itemData);
//设置时间范围
stickerEffectData.setAtTimeRange(TuSDKTimeRange.makeRange(0, Float.MAX_VALUE));
//添加MV效果
getMovieEditor().getEditorEffector().addMediaEffectData(stickerEffectData);
}
在EditorMusicComponent
中的mMusicRecycle
的Item
点击中
//创建音频特效对象
TuSDKMediaAudioEffectData audioEffectData = new TuSDKMediaAudioEffectData(new TuSdkMediaDataSource(context, audioPathUri));
//设置时间
audioEffectData.setAtTimeRange(TuSDKTimeRange.makeTimeUsRange(0, getEditorPlayer().getOutputTotalTimeUS()));
加载音频回调是在混音器中加入
getEditorMixer().addTaskStateListener(mAudioDecoderTask);
回调的状态有
/**
* 当前执行类状态
*/
public enum State {
/** 空闲状态 **/
Idle,
/** 正在解码 **/
Decoding,
/** 解码完成 **/
Complete,
/** 已取消 **/
Cancelled
}
音频录音回调
/**
* 录音裁剪进度监听
*/
public interface OnAudioRecordCuterListener {
/**
* 当前执行的进度
*
* @param percent 当前进度的百分比 (0 ~ 1)
* @param currentTimeUS 当前执行的时间(微秒)
* @param totalTimeUS 总时长 (微秒)
*/
void onProgressChanged(float percent, long currentTimeUS, long totalTimeUS);
/**
* 输出完毕
*
* @param outputFile 输出完成的文件
*/
void onComplete(File outputFile);
}
文字功能在EditorTextComponent
中,添加一个文字特效
/**
* 将数据转成公用的 TuSDKMediaEffectData
*
* @param sticker 贴纸数据
* @param bitmap 文字生成的图片
* @param offsetX 相对视频左上角X轴的位置
* @param offsetY 相对视频左上角Y轴的位置
* @param rotation 旋转的角度
* @param startTimeUs 文字特效开始的时间
* @param stopTimeUs 文字特效结束的时间
* @param stickerSize 当前StickerView的宽高(计算比例用)
*/
//创建一个文字贴纸包装类
TuSDKTextStickerImage stickerImage = new TuSDKTextStickerImage();
//创建文字贴纸数据类
TextStickerData stickerData = new TextStickerData(bitmap, bitmap.getWidth(), bitmap.getHeight(), 0, offsetX, offsetY, rotation);
stickerImage.setCurrentSticker(stickerData);
//设置设计画布的宽高
stickerImage.setDesignScreenSize(stickerSize);
//创建文字特效类
TuSDKMediaTextEffectData mediaTextEffectData = new TuSDKMediaTextEffectData(stickerImage);
//设置当前文字特效的时间
mediaTextEffectData.setAtTimeRange(TuSDKTimeRange.makeTimeUsRange(startTimeUs, stopTimeUs
//添加特效
getEditorEffector().addMediaEffectData(textMediaEffectData)
特效里分为场景特效 、 时间特效、魔法特效 三种,在EditorEffectComponent
中,分为三个Fragment
ScreenEffectFragment
场景特效FragmentTimeEffectFragment
时间特效FragmentMagicEffectFragment
魔法特效Fragment
添加一个场景特效
//创建一个场景特效数据类
TuSDKMediaSceneEffectData mediaSceneEffectData = new TuSDKMediaSceneEffectData(mScreenCode);
//设置场景特效的时间
mediaSceneEffectData.setAtTimeRange(TuSDKTimeRange.makeTimeUsRange(starTimeUs, endTimeUs));
//添加当前场景特效
getEditorEffector().addMediaEffectData(mediaSceneEffectData);
删除一个场景特效
getEditorEffector().removeMediaEffectData(mediaEffectData);
-
反复特效
//实例化反复特效数据类 TuSDKMediaRepeatTimeEffect repeatTimeEffect = new TuSDKMediaRepeatTimeEffect(); //设置开始与结束的时间范围 repeatTimeEffect.setTimeRange(startTimeUS, endTimeUS); //设置反复的次数 repeatTimeEffect.setRepeatCount(2); //是否裁剪多余的时间 repeatTimeEffect.setDropOverTime(false); //应用时间特效 getEditorPlayer().setTimeEffect(repeatTimeEffect);
-
慢动作
//实例化慢动作特效数据 TuSDKMediaSlowTimeEffect slowTimeEffect = new TuSDKMediaSlowTimeEffect(); //设置慢动作的时间范围 slowTimeEffect.setTimeRange(startTimeUS, endTimeUS); //设置慢动作的速率 slowTimeEffect.setSpeed(0.6f); //应用时间特效 getEditorPlayer().setTimeEffect(slowTimeEffect);
-
时光倒流
//实例化时光倒流特效数据 TuSDKMediaReversalTimeEffect reversalTimeEffect = new TuSDKMediaReversalTimeEffect(); //应用时间特效 getEditorPlayer().setTimeEffect(reversalTimeEffect);
-
清除时间特效
getEditorPlayer().clearTimeEffect();
-
魔法特效的添加
//实例化魔法效果 TuSDKMediaParticleEffectData effectModel = new TuSDKMediaParticleEffectData(mCurrentMagicCode); //设置粒子大小 effectModel.setSize(mMagicConfig.getSize()); //设置粒子颜色 effectModel.setColor(mMagicConfig.getColor());
//设置粒子位置(持续的移动不断的put 参考Demo中的MagicEffectFragment) effectModel.putPoint(getEditorPlayer().getCurrentTimeUs(), pointF); //预览魔法特效 getEditorEffector().addMediaEffectData(effectModel);
保存视频调用TuSdkMovieEditor.saveVideo()
,保存的回调可以在saveVieo()
之前向保存器内添加回调
getEditorSaver().addSaverProgressListener(mSaveProgressListener);
该回调为
//保存进度监听
interface TuSdkSaverProgressListener {
/**
* 当前进度
*
* @param progress
* @since v3.0
*/
void onProgress(float progress);
/**
* 保存完成
*
* @param outputFile
* @since v3.0
*/
void onCompleted(TuSdkMediaDataSource outputFile);
/**
* 保存错误
*
* @param e
* @since v3.0
*/
void onError(Exception e);
}
类名
功能说明
TuSDKAACAudioFileEncoder
AAC音频文件编码器
TuSDKAverageAudioMixer
音频混合器
(参考Demo中AudioMixedActivity
)
-
初始化音频混合对象
TuSDKAverageAudioMixer audioMixer = new TuSDKAverageAudioMixer(); //设置混音回调 audioMixer.setOnAudioMixDelegate(mAudioMixerDelegate);
这里需要设置一个混音的回调
mAudioMixerDelegate
/** * 音频混合Delegate */ private TuSDKAudioMixer.OnAudioMixerDelegate mAudioMixerDelegate = new TuSDKAudioMixer.OnAudioMixerDelegate() { /** * 混合状态改变事件 */ @Override public void onStateChanged(TuSDKAudioMixer.State state) { if (state == TuSDKAudioMixer.State.Complete) { // 停止AAC编码器 mAACFileEncoder.stop(); TuSdk.messageHub().showSuccess(AudioMixedActivity.this, "混合完成"); } else if (state == Decoding || state == Mixing) { TuSdk.messageHub().setStatus(AudioMixedActivity.this, "混合中"); } else if (state == TuSDKAudioMixer.State.Cancelled) { //删除混合的音频文件 delMixedFile(); } } /** * 当前解析到主背景音乐信息时回调该方法,其他音乐将参考该信息进行混合 */ @Override public void onReayTrunkTrackInfo(TuSDKAudioInfo rawInfo) { } @Override public void onMixingError(int errorCode) { TuSdk.messageHub().showError(AudioMixedActivity.this, "混合失败"); } /** * 混合后的音频数据(未经编码) */ @Override public void onMixed(byte[] mixedBytes) { // 编码音频数据 mAACFileEncoder.queueAudio(mixedBytes); } };
混音的状态是在
TuSDKAudioMixer.State
这个枚举中,有以下几种状态/** * 混音状态 */ public enum State { /** 空闲状态 */ Idle, /** 正在解码 */ Decoding, /** 解码完成 */ Decoded, /** 混合中 */ Mixing, /** 混合完成 */ Complete, /** 已取消 */ Cancelled }
我们看到在回调中用到了
TuSDKAACAudioFileEncoder
AAC文件编码器 ,AAC文件编码器的初始化方式为 -
初始化AAC音频文件编码器
/** AAC 音频文件编码器,可将混合的音频数据编码为AAC文件 */ TuSDKAACAudioFileEncoder mAACFileEncoder = new TuSDKAACAudioFileEncoder(); // 初始化音频编码器 mAACFileEncoder.initEncoder(TuSDKAudioEncoderSetting.defaultEncoderSetting()); // 设置输入路径 mAACFileEncoder.setOutputFilePath(getMixedAudioPath());
在初始化调用initEncoder
的时候,我们会传入一个TuSDKAudioEncoderSetting
对象,这个是音频编码器的设置,主要用来设置以下的参数
/** TuSDKAudioEncoderSetting **/
/** 录制的音频数据格式 默认:AudioFormat.ENCODING_PCM_16BIT */
public int audioFormat;
/** 录制的音频采样率 默认:44100 */
public int sampleRate;
/** 录制的音频通道设置 AudioFormat.CHANNEL_IN_MONO 或 AudioFormat.CHANNEL_IN_STEREO 默认:AudioFormat.CHANNEL_IN_STEREO */
public int channelConfig;
/** 音频质量 默认:AudioQuality.MEDIUM1 */
public AudioQuality audioQuality;
/** 默认:MediaCodecInfo.CodecProfileLevel.AACObjectLC */
public int mediacodecAACProfile;
/** 音道数 默认:2 */
public int mediacodecAACChannelCount;
/** 是否启用音频缓冲区 */
public boolean enableBuffers;
如果不需要自定义参数的话,直接调用TuSDKAudioEncoderSetting.defaultEncoderSetting()
获取默认配置即可
-
多音轨开始混合
/** 启动AAC文件编码器 **/ mAACFileEncoder.start(); /** 向音频混合器输入需要混合的音频对象列表 **/ mAudioMixer.mixAudios(getAudioEntryList());
getAudioEntryList()
为获取音频对象TuSDKAudioEntry
列表-
获取音频文件列表
音频对象为
TuSDKAudioEntry.java
支持URI
和Path
两种形式,其中可支持的操作有/**
- 设置改音频是否为主背景
- @param trunk 其他音频混合时将参考该音频 */ public TuSDKAudioEntry setTrunk(boolean trunk);
/**
- 设置是否循环
- @param looping true : 在背景音乐中循环 */ public TuSDKAudioEntry setLooping(boolean looping);
/**
- 该音频在主干音频的位置 (mTrunk == true时 忽略该设置)
- @param timeRange 时间区间 */ public TuSDKAudioEntry setTimeRange(TuSDKTimeRange timeRange);
/**
- 设置裁剪区域
- @param cutTimeRange 裁剪时间区间 */ public TuSDKAudioEntry setCutTimeRange(TuSDKTimeRange cutTimeRange)
/**
- 设置音量
- @param volume (0f - 1f) */ public TuSDKAudioEntry setVolume(float volume);
-
类名
功能说明
TuSDKMP4MovieMixer
对视频和多个音频进行混合
(参考Demo中的TuSDKMP4MovieMixer
)
-
初始化混合器
混合器采用了建造者模式去构建,构建方式如下
TuSDKMP4MovieMixer mMP4MovieMixer = new TuSDKMP4MovieMixer(); mMP4MovieMixer.setDelegate(this) .setOutputFilePath(getMixedVideoPath()) // 设置输出路径 .setVideoSoundVolume(1.0f) // 设置音乐音量 .setClearAudioDecodeCacheInfoOnCompleted(true); // 设置音视频混合完成后是否清除缓存信息 默认:true (false:再次混合时可加快混合速度)
这边会设置一个回调 OnMP4MovieMixerDelegate
这个回调内部有这几个方法
/**
* 音视频混合Delegate
*/
public interface OnMP4MovieMixerDelegate
{
/**
* 混合状态改变
* @param state
* @see TuSDKMP4MovieMixer.State
*/
void onStateChanged(TuSDKMP4MovieMixer.State state);
/**
* 错误状态
* @param code
* @see ErrorCode
*/
void onErrrCode(ErrorCode code);
/**
* 混合完成
* @param result 视频混合结果
*/
void onMixerComplete(TuSDKVideoResult result);
}
-
开始混合
// mVideoDataSource : 视频路径 mAudioTracks : 待混合的音频数据 true : 是否混合视频原音 mMP4MovieMixer.mix(TuSDKMediaDataSource.create(getVideoPath()), mAudioEntryList, false);
开始混合的时候需要传入
- 视频的路径
TuSDKMediaDataSource
- 待混合的音频数据
mAudioEntryList
(TuSDKAudioEntry
列表,多音轨混合有详细介绍) - 是否混合视频原音
- 视频的路径
这三个设置
-
状态和错误码
-
/** * TuSDKMP4VideoMixer 状态信息 */ public enum State { /** 空闲状态 */ Idle, /** 正在解码 */ Decoding, /** 解码完成 */ Decoded, /** 混合中 */ Mixing, /** 已取消 */ Cancelled, /** 混合视频 */ Failed } /** * 错误码 */ public enum ErrorCode { /** 不支持的视频格式 */ UnsupportedVideoFormat, }
类名
功能说明
TuSDKVideoImageExtractor
视频帧提取器
(参考Demo中MovieThumbActivity
)
-
视频帧提取器用法
//获取出的每帧图片大小 TuSdkSize tuSdkSize = TuSdkSize.create(TuSdkContext.dip2px(56), TuSdkContext.dip2px(30)); //创建视频帧提取器 TuSDKVideoImageExtractor extractor = TuSDKVideoImageExtractor.createExtractor(); //设置输出图片大小 extractor.setOutputImageSize(tuSdkSize) //设置视频数据源 .setVideoDataSource(TuSDKMediaDataSource.create(getVideoPath())) //设置分离图片的数量 .setExtractFrameCount(15); //设置分离回调,开始提取图片 extractor.asyncExtractImageList(mImageExtractorDelegate);
这里会设置分离的回调,回调的方法为
public interface TuSDKVideoImageExtractorDelegate
{
/** 此方法是在所有图片分离完毕之后回调 只会回调一次 **/
void onVideoImageListDidLoaded(List<Bitmap> images);
/** 此方法是在每分离出一张图片就会回调一次 **/
void onVideoNewImageLoaded(Bitmap bitmap);
}
- 精确提取视频帧
在TuSDKVideoImageExtractor
中调用此方法可以精确提取视频帧
/**
* 获取指定时间的视频缩略图 单位:微秒
*
* @param frameTimeUs 侦时间 单位:微妙
* @param quality 质量 0-100
* @return Bitmap
*/
public Bitmap getFrameAtTime(long frameTimeUs, int quality)
类名
功能说明
TuSdkMediaSuit.merge()
多视频拼接
-
多视频拼接使用方法
TuSdkMediaSuit.merge(mMoviePathList, muxerPath, ouputVideoFormat, ouputAudioFormat, mediaProgress);
mMoviePathList
待合成视频列表muxerPath
最终生成的文件路径ouputVideoFormat
输出的视频格式ouputAudioFormat
输出的音频格式mediaProgress
进度回调
进度的回调有以下几个方法
/** 媒体处理进度接口 */
public interface TuSdkMediaProgress {
/**
* 执行进度 [主线程]
*
* @param progress 进度百分比 0-1
* @param mediaDataSource 当前处理的视频媒体源
* @param index 当前处理的视频索引
* @param total 总共需要处理的文件数
*/
void onProgress(float progress, TuSdkMediaDataSource mediaDataSource, int index, int total);
/***
* 完成转码 [主线程]
* @param e 如果成功则为Null
* @param outputFile 输出文件路径
* @param total 处理文件总数
*/
void onCompleted(Exception e, TuSdkMediaDataSource outputFile, int total);
}
类名
功能说明
TuSdkMediaSuit.cuter()
视频裁剪
(参考Demo中的 MovieCutActivity
)
-
视频裁剪使用方法
TuSdkMediaSuit.cuter(inputMediaSource, outputFilePath, ouputVideoFormat, ouputAudioFormat, orientation,rectDrawF, rectCutF, timeSlice, mCuterMediaProgress);
inputMediaSource
输入的视频源outputFilePath
输出的地址ouputVideoFormat
输出的视频格式信息ouputAudioFormat
输入的视频格式信息orientation
设置输出视频方向 详见ImageOrientation
timeSlice
设置时间的范围
类名
功能说明
TuSDKAudioFileRecorder
音频录制器
(参考Demo中的AudioRecordActivity
)
-
初始化音频录制器
TuSDKAudioFileRecorder mAudioRecorder = new TuSDKAudioFileRecorder(); //设置输出文件类型 mAudioRecorder.setOutputFormat(TuSDKAudioFileRecorder.OutputFormat.AAC); //设置文件录制回调 mAudioRecorder.setAudioRecordDelegate(mRecordAudioDelegate);
文件输出类型可以设置为PCM
和AAC
两种文件类型
回调接口有以下几个方法
/** 录音事件回调 */
public static interface TuSDKRecordAudioDelegate
{
/**
* 录制完成
*
* @param file
*/
public void onAudioRecordComplete(File file);
/**
* 录制状态改变
*
* @param state @see RecordState
*/
void onAudioRecordStateChanged(RecordState state);
/**
* 错误信息回调
*
* @param error @see RecordError
*/
void onAudioRecordError(RecordError error);
}
开始、暂停、继续、结束的方法分别是
//开始录制
mAudioRecorder.start();
//暂停录制
mAudioRecorder.pauseRecord();
//继续录制
mAudioRecorder.resumeRecord();
//结束录制
mAudioRecorder.stop();
类名
功能名称
TuSdkAudioPitchEngine
音频变声
目前音频特效类型有以下几种:
//正常
TuSdkSoundPitchType.Normal
//怪兽
TuSdkSoundPitchType.Monster
//大叔
TuSdkSoundPitchType.Uncle
//女生
TuSdkSoundPitchType.Girl
//萝莉
TuSdkSoundPitchType.Lolita
-
将 PCM 数据放入
TuSdkAudioPitchEngine
队列中/***
- 处理音频数据
- @param byteBuffer 输入缓存
- @param bufferInfo 缓存信息
- @return 是否已处理 */ void processInputBuffer(ByteBuffer byteBuffer, MediaCodec.BufferInfo bufferInfo);
-
通知
TuSdkAudioPitchEngine
输入的 PCM 音频信息变更/**
- 更新音频信息
- @param inputAudioInfo 新的音频信息 */ void changeAudioInfo(TuSdkAudioInfo inputAudioInfo);
-
清除缓存并重置音频处理器
/**
- 重置处理器 */ void reset();
-
释放当前音频处理器
/**
- 释放处理器 */ void release();
// setp1: 初始化输入的音频信息
TuSdkAudioInfo inputAudioInfo = new TuSdkAudioInfo(TuSdkMediaFormat.buildSafeAudioEncodecFormat());
// setp2: 初始化 TuSdkAudioPitchEngine
TuSdkAudioPitchEngine audioPitchEngine = new TuSdkAudioPitchEngine(inputAudioInfo);
// setp3: 设置 TuSdkAudioPitchEngine 处理回调
audioPitchEngine.setOutputBufferDelegate(mAudioPitchEngineOutputBufferDelegate);
// setp4: 设置当前需要的音效
audioPitchEngine.setSoundPitchType(TuSdkAudioPitchEngine.TuSdkSoundPitchType.Normal);
// setp5: 在输出PCM数据的地方调用
audioPitchEngine.processInputBuffer(outputByteBuffer, bufferInfo);
// setp6: 经过TuSdkAudioPitchEngine处理后的数据在会在回调中返回
/** 音频处理数据输出委托 **/
interface TuSdKAudioEngineOutputBufferDelegate {
void onProcess(ByteBuffer byteBuffer, MediaCodec.BufferInfo bufferInfo);
}
// 在这里添加后续处理逻辑,可用于编码,播放,或写入文件。
1.导入上传依赖:compile 'com.upyun:upyun-android-sdk:2.1.0'
- 表单上传
//空间名
String SPACE = "formtest";
//操作员
String OPERATER = "one";
//密码
String PASSWORD = "***";
//上传路径
String savePath = "/uploads/{year}{mon}{day}/{random32}{.suffix}";
final Map<String, Object> paramsMap = new HashMap<>();
//上传空间
paramsMap.put(Params.BUCKET, SPACE);
//保存路径
paramsMap.put(Params.SAVE_KEY, savePath);
//添加 CONTENT_LENGTH 参数使用大文件表单上传
paramsMap.put(Params.CONTENT_LENGTH, file.length());
//可选参数(详情见api文档介绍)
paramsMap.put(Params.CONTENT_MD5, UpYunUtils.md5Hex(file));
paramsMap.put(Params.RETURN_URL, "httpbin.org/post");
//上传结果回调
UpCompleteListener completeListener = new UpCompleteListener() {
@Override
public void onComplete(boolean isSuccess, String result) {
Log.e(TAG, isSuccess + ":" + result);
}
};
//进度条回调
UpProgressListener progressListener = new UpProgressListener() {
@Override
public void onRequestProgress(final long bytesWrite, final long contentLength) {
Log.e(TAG, (100 * bytesWrite) / contentLength + "%");
}
};
UploadEngine.getInstance().formUpload(file, paramsMap, OPERATER, UpYunUtils.md5(PASSWORD), completeListener, progressListener);
- 断点续传
//空间名
String SPACE = "formtest";
//操作员
String OPERATER = "one";
//密码
String PASSWORD = "***";
//上传路径
String path = "/test.mp4";
//初始化断点续传
ResumeUploader uploader = new ResumeUploader(SPACE, OPERATER, UpYunUtils.md5(PASSWORD));
//设置 MD5 校验
uploader.setCheckMD5(true);
//设置进度监听
uploader.setOnProgressListener(new UpProgressListener() {
@Override
public void onRequestProgress(long bytesWrite, long contentLength) {
Log.e(TAG, bytesWrite + ":" + contentLength);
}
});
uploader.upload(file, path, null, new UpCompleteListener() {
@Override
public void onComplete(boolean isSuccess, String result) {
Log.e(TAG, "isSuccess:" + isSuccess + " result:" + result);
}
});
-
支持在线视频协议:
HLS
,RTMP
,HTTP-FLV
等 -
支持本地视频播放
-
支持设置窗口大小和全屏设置
-
支持缓冲大小设置
-
提供 UpVideoView 控件
-
支持 ARM, ARMv7a, ARM64v8a, X86 主流芯片体系架构
UPYUN
播放器 SDK
。功能完备接口简练,可以快速安装使用, 灵活性强可以满足复杂定制需求。
Android 2.3 (API 9) 及其以上
导入 upplayer module 使用:compile project(':upplayer')
直接使用控件 UpVideoView
//设置播放地址
upVideoView.setVideoPath(path);
//开始播放
upVideoView.start();
//暂停播放
upVideoView.pause();
//停止释放播放器
upVideoView.release(true);
//设置默认缓存区大小 (需在setVideoPath 或者 resume 前执行生效)
upVideoView.setBufferSize(int size);
//拖拽
upVideoView.seekTo(int msec)