类名 | 功能说明 |
---|---|
TuSdkRecorderVideoCamera | 视频录制拍照 |
除了按照集成向导步骤在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)
// 设置水印,默认为空
public void setWaterMarkImage(Bitmap mWaterMarkImage)
// 设置水印位置
public void setWaterMarkPosition(WaterMarkPosition mWaterMarkPosition)
public void setRecorderVideoCameraCallback(TuSdkRecorderVideoCameraCallback recorderCallback)
指定录制相机的事件委托,该委托中有下面四个接口用来通知相机状态改变:
// 设置最小录制时长
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)
调节采集比例
/** 使用动画改编视频预览显示比例 (默认:0, 0 <= RegionRatio, 当设置为0时全屏显示) */
@Override
public void changeRegionRatio(float mRegionRatio)
/** 视频预览显示比例 (默认:0, 0 <= RegionRatio, 当设置为0时全屏显示) */
@Override
public void setRegionRatio(float regionRatio)
/** 是否能调节比例,true 是 false 否 */
@Override
public boolean canChangeRatio()
/**
* 设置曝光补偿
* @param ev 曝光补偿级数
*/
@Override
public void setExposureCompensation(int ev)
/**
* @return 获取最小曝光补偿级数
*/
@Override
public int getMinExposureCompensation()
/**
* @return 获取当前曝光补偿级数
*/
@Override
public int getCurrentExposureCompensation()
/**
* @return 获取曝光补偿基数
*/
@Override
public float getExposureCompensationStep()
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;
}
}
设置口红,腮红,眉毛,眼影,眼线,睫毛效果
TuSdkMediaCosmeticEffectData mEffect = new TuSdkMediaCosmeticEffectData();
class TuSdkMediaCosmeticEffectData{
/**
* 更新唇彩类型,颜色,透明度
*
* @param type 类型
* @param colorRGB 颜色
*/
public void updateLip(CosmeticLipFilter.CosmeticLipType type, int colorRGB)
/**
* 关闭唇彩效果
*/
public void closeLip()
/**
* 更新腮红贴纸,透明度
*
* @param sticker
*/
public void updateBlush(StickerData sticker)
/**
* 关闭腮红效果
*/
public void closeBlush()
/**
* 更新眉毛贴纸,透明度
*
* @param sticker
*/
public void updateEyebrow(StickerData sticker)
/**
* 关闭腮红效果
*/
public void closeEyebrow()
/**
* 更新眼影贴纸,透明度
*
* @param sticker
*/
public void updateEyeshadow(StickerData sticker)
/**
* 关闭眼影效果
*/
public void closeEyeshadow()
/**
* 更新眼线贴纸,透明度
*
* @param sticker
*/
public void updateEyeline(StickerData sticker)
/**
* 关闭眼线效果
*/
public void closeEyeline()
/**
* 更新睫毛贴纸,透明度
*
* @param sticker
*/
public void updateEyelash(StickerData sticker)
/**
* 关闭睫毛效果
*/
public void closeEyelash()
}
透明度调节
透明度调节通过各部位对应的key进行调节,详细key请查看demo中CosmeticPanelController.java
美妆贴纸在线部署
美妆贴纸的在线部署方式与动态贴纸一致,可直接参考动态贴纸的在线部署方式