需求:
現在有個需求,就是需要使用手機實現錄像,在視頻中添加時間水印,並且在錄像過程中,實現拍照功能,在網上查找了資料,決定使用七牛的SDK來實現這個功能,在錄像中拍照,在七牛中使用 截幀回調可以實現。
效果:
開始錄像
拍照
保存視頻
例子下載
https://download.csdn.net/download/ljp345775/12543119
思路:
實現錄像和拍照的功能不算很難,照着官方的開發文檔弄就可以了,就是這個在錄像視頻中添加時間水印,我的思路是通過服務每秒發送一次廣播,然後,接收到廣播以後,就改變一次水印。跟我以前寫過一篇通過服務和廣播實現多界面共享計時器的思路差不多,有興趣的可以看一下:android中利用service和廣播實現多個activity共享計時器
實現步驟:
- 導入jar包
從官網下載需要的jar包,然後導入到項目
官方地址:https://github.com/pili-engineering/PLDroidShortVideo/archive/v3.1.1.zip
如果覺得官方下載的慢,也可以下載我寫的例子,裏面有我下載好的。
官方的jar包所在位置如下:
導入到項目中以後如下圖:
- 初始化SDK
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
//初始化
PLShortVideoEnv.init(getApplicationContext());
}
}
- 申請權限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
- 主要代碼實現
- 初始化錄製對象
/**
* 初始化錄製對象
*/
private void initRecorder(String name) {
mShortVideoRecorder = new PLShortVideoRecorder();
mShortVideoRecorder.setRecordStateListener(this);
// 攝像頭採集選項
PLCameraSetting cameraSetting = new PLCameraSetting();
//後攝像頭
cameraSetting.setCameraId(PLCameraSetting.CAMERA_FACING_ID.CAMERA_FACING_BACK);
cameraSetting.setCameraPreviewSizeRatio(PLCameraSetting.CAMERA_PREVIEW_SIZE_RATIO.RATIO_16_9);
cameraSetting.setCameraPreviewSizeLevel(PLCameraSetting.CAMERA_PREVIEW_SIZE_LEVEL.PREVIEW_SIZE_LEVEL_720P);
// 麥克風採集選項
PLMicrophoneSetting microphoneSetting = new PLMicrophoneSetting();
// 視頻編碼選項
PLVideoEncodeSetting videoEncodeSetting = new PLVideoEncodeSetting(this);
videoEncodeSetting.setEncodingSizeLevel(PLVideoEncodeSetting.VIDEO_ENCODING_SIZE_LEVEL.VIDEO_ENCODING_SIZE_LEVEL_480P_2); // 480x480
videoEncodeSetting.setEncodingBitrate(1000 * 1024); // 1000kbps
videoEncodeSetting.setEncodingFps(25);
videoEncodeSetting.setHWCodecEnabled(true); // true:硬編 false:軟編
// 音頻編碼選項
PLAudioEncodeSetting audioEncodeSetting = new PLAudioEncodeSetting();
audioEncodeSetting.setHWCodecEnabled(true); // true:硬編 false:軟編
// 美顏選項
// PLFaceBeautySetting faceBeautySetting = new PLFaceBeautySetting(1.0f, 0.5f, 0.5f);
// 錄製選項
recordSetting = new PLRecordSetting();
recordSetting.setMaxRecordDuration(600 * 1000); // 10s
String s = FileUtils.getVideoPath(mActivity, "test");
recordSetting.setVideoCacheDir(getRootPath(mActivity));
recordSetting.setVideoFilepath(s);
// 設置錄製速度 (默認爲 1.0)
// PLShortVideoRecorder.setRecordSpeed(1.0);
mShortVideoRecorder.prepare(glsurfaceview, cameraSetting, microphoneSetting,
videoEncodeSetting, audioEncodeSetting, null, recordSetting);
//用來設置時間水印
mWatermarkSetting = new PLWatermarkSetting();
}
- 拍照
/**
* ===============截圖
*/
private void screenshot() {
mShortVideoRecorder.captureFrame(new PLCaptureFrameListener() {
@Override
public void onFrameCaptured(PLVideoFrame capturedFrame) {
if (capturedFrame == null) {
return;
}
Log.i("aaa", "captured frame width: " + capturedFrame.getWidth() + " height: " + capturedFrame.getHeight() + " timestamp: " + capturedFrame.getTimestampMs());
try {
String photoName = getPhotoName();
String picturePath = getRootFile(mActivity) + "/test/" + photoName;
Log.e("aaa", "onFrameCaptured: " + picturePath);
FileOutputStream fos = new FileOutputStream(picturePath);
capturedFrame.toBitmap().compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
runOnUiThread(new Runnable() {
@Override
public void run() {
Log.e("aaa", "圖片以保存");
Toast.makeText(mActivity, photoName + " 保存成功", Toast.LENGTH_SHORT).show();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
- 視頻保存
/**
* =======保存視頻
*/
private void stopAndSaveVideo() {
// 結束一段視頻
mShortVideoRecorder.endSection();
mShortVideoRecorder.concatSections(new PLVideoSaveListener() {
@Override
public void onSaveVideoSuccess(String s) {
Log.e("aaa", "onSaveVideoSuccess: " + s);
runOnUiThread(new Runnable() {
@Override
public void run() {
ToastUtil.showToast(mActivity, "視頻保存完成");
}
});
}
@Override
public void onSaveVideoFailed(int i) {
Log.e("aaa", "onSaveVideoFailed: " + i);
}
@Override
public void onSaveVideoCanceled() {
Log.e("aaa", "onSaveVideoCanceled: ");
}
@Override
public void onProgressUpdate(final float v) {
Log.e("aaa", "onProgressUpdate: " + v);
runOnUiThread(new Runnable() {
@Override
public void run() {
ToastUtil.showToast(mActivity, "" + v);
}
});
}
});
}
- 廣播接收器
public class TimeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String intentAction = intent.getAction();
if (intentAction.equals("com.ljp.recorddemo.service.timer")) {
String time = intent.getStringExtra("time");
Bitmap bitmap = fromText(50, time);
mWatermarkSetting.setPosition(0.50f, 0.05f);
mWatermarkSetting.setBitmap(bitmap);
mShortVideoRecorder.setWatermark(mWatermarkSetting);
}
}
}
- 服務
/**
* 作者:Administrator
* 時間:2020/6/22 0022 13:08
* 描述:時間服務
*/
public class TimerService extends Service {
private Timer timer = null;
private TimerTask timerTask = null;
private int i = 0;
@Override
public void onCreate() {
super.onCreate();
//在創建service的時候開始計時
if(timer==null&&timerTask==null){
timer = new Timer();
timerTask = new TimerTask() {
@Override
public void run() {
i++;
//沒執行一次就發送一次廣播
Intent intent = new Intent();
String time1 = FileUtils.getTime1();
intent.putExtra("time", time1);
intent.setAction("com.ljp.recorddemo.service.timer");
sendBroadcast(intent);
}
};
timer.schedule(timerTask,0,1000);
}
}
@Override
public void onDestroy() {
super.onDestroy();
if(timerTask!=null){
timerTask.cancel();
timerTask=null;
}
if(timer!=null){
timer.cancel();
timer=null;
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
額外功能:
在這個例子中,需要申請權限,我使用的是嚴振杰老師的permission:2.0.0-rc11,比較好用,我還發現了一個老師的另外一個好用的項目,就是AndServer,就是在手機端搭建服務器的,我也寫了一個例子,有興趣的可以看一下
Android利用Andserver搭建服務器