完成 android 基本功能

This commit is contained in:
2021-10-01 15:12:35 +08:00
parent 4517f62403
commit f4c3fde0a9
59 changed files with 4052 additions and 137 deletions
+955
View File
@@ -0,0 +1,955 @@
package com.mabeijianxi.smallvideorecord2;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.hardware.Camera.Area;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.PreviewCallback;
import android.hardware.Camera.Size;
import android.os.Build;
import android.os.CountDownTimer;
import android.text.TextUtils;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import com.mabeijianxi.smallvideorecord2.jniinterface.FFmpegBridge;
import com.mabeijianxi.smallvideorecord2.model.BaseMediaBitrateConfig;
import com.mabeijianxi.smallvideorecord2.model.MediaObject;
import com.mabeijianxi.smallvideorecord2.Log;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
/**
* 视频录制抽象类
*/
public abstract class MediaRecorderBase implements Callback, PreviewCallback, IMediaRecorder {
public static boolean NEED_FULL_SCREEN = false;
/**
* 小视频高度
*/
public static int SMALL_VIDEO_HEIGHT = 480;
/**
* 小视频宽度
*/
public static int SMALL_VIDEO_WIDTH = 360;
/**
* 未知错误
*/
public static final int MEDIA_ERROR_UNKNOWN = 1;
/**
* 预览画布设置错误
*/
public static final int MEDIA_ERROR_CAMERA_SET_PREVIEW_DISPLAY = 101;
/**
* 预览错误
*/
public static final int MEDIA_ERROR_CAMERA_PREVIEW = 102;
/**
* 自动对焦错误
*/
public static final int MEDIA_ERROR_CAMERA_AUTO_FOCUS = 103;
public static final int AUDIO_RECORD_ERROR_UNKNOWN = 0;
/**
* 采样率设置不支持
*/
public static final int AUDIO_RECORD_ERROR_SAMPLERATE_NOT_SUPPORT = 1;
/**
* 最小缓存获取失败
*/
public static final int AUDIO_RECORD_ERROR_GET_MIN_BUFFER_SIZE_NOT_SUPPORT = 2;
/**
* 创建AudioRecord失败
*/
public static final int AUDIO_RECORD_ERROR_CREATE_FAILED = 3;
/**
* 视频码率 1M
*/
public static final int VIDEO_BITRATE_NORMAL = 1024;
/**
* 视频码率 1.5M(默认)
*/
public static final int VIDEO_BITRATE_MEDIUM = 1536;
/**
* 视频码率 2M
*/
public static final int VIDEO_BITRATE_HIGH = 2048;
/**
* 开始转码
*/
protected static final int MESSAGE_ENCODE_START = 0;
/**
* 转码进度
*/
protected static final int MESSAGE_ENCODE_PROGRESS = 1;
/**
* 转码完成
*/
protected static final int MESSAGE_ENCODE_COMPLETE = 2;
/**
* 转码失败
*/
protected static final int MESSAGE_ENCODE_ERROR = 3;
/**
* 最大帧率
*/
protected static int MAX_FRAME_RATE = 20;
/**
* 最小帧率
*/
protected static int MIN_FRAME_RATE = 8;
protected static int CAPTURE_THUMBNAILS_TIME = 1;
protected BaseMediaBitrateConfig compressConfig;
/**
* 摄像头对象
*/
protected Camera camera;
/**
* 摄像头参数
*/
protected Camera.Parameters mParameters = null;
/**
* 摄像头支持的预览尺寸集合
*/
protected List<Size> mSupportedPreviewSizes;
/**
* 画布
*/
protected SurfaceHolder mSurfaceHolder;
/**
* 声音录制
*/
protected AudioRecorder mAudioRecorder;
/**
* 拍摄存储对象
*/
protected MediaObject mMediaObject;
/**
* 转码监听器
*/
protected OnEncodeListener mOnEncodeListener;
/**
* 录制错误监听
*/
protected OnErrorListener mOnErrorListener;
/**
* 录制已经准备就绪的监听
*/
protected OnPreparedListener mOnPreparedListener;
/**
* 帧率
*/
protected int mFrameRate = MAX_FRAME_RATE;
/**
* 摄像头类型(前置/后置),默认后置
*/
protected int mCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
/**
* 视频码率
*/
protected static int mVideoBitrate;
public static int mSupportedPreviewWidth = 0;
/**
* 状态标记
*/
protected boolean mPrepared, mStartPreview, mSurfaceCreated;
/**
* 是否正在录制
*/
protected volatile boolean mRecording;
/**
* PreviewFrame调用次数,测试用
*/
protected volatile long mPreviewFrameCallCount = 0;
private String mFrameRateCmd="";
private int screenWidth;
private int screenHeight;
public MediaRecorderBase() {
}
public void setScreen(int screenWidth, int screenHeight) {
this.screenWidth = screenWidth;
this.screenHeight = screenHeight;
}
/**
* 设置预览输出SurfaceHolder
*
* @param sh
*/
@SuppressWarnings("deprecation")
public void setSurfaceHolder(SurfaceHolder sh) {
if (sh != null) {
sh.addCallback(this);
if (!DeviceUtils.hasHoneycomb()) {
sh.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
}
}
public void setRecordState(boolean state){
this.mRecording=state;
}
public boolean getRecordState(){
return mRecording;
}
/**
* 设置转码监听
*/
public void setOnEncodeListener(OnEncodeListener l) {
this.mOnEncodeListener = l;
}
/**
* 设置预处理监听
*/
public void setOnPreparedListener(OnPreparedListener l) {
mOnPreparedListener = l;
}
/**
* 设置错误监听
*/
public void setOnErrorListener(OnErrorListener l) {
mOnErrorListener = l;
}
/**
* 是否前置摄像头
*/
public boolean isFrontCamera() {
return mCameraId == Camera.CameraInfo.CAMERA_FACING_FRONT;
}
/**
* 是否支持前置摄像头
*/
@SuppressLint("NewApi")
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
public static boolean isSupportFrontCamera() {
if (!DeviceUtils.hasGingerbread()) {
return false;
}
int numberOfCameras = Camera.getNumberOfCameras();
if (2 == numberOfCameras) {
return true;
}
return false;
}
/**
* 切换前置/后置摄像头
*/
public void switchCamera(int cameraFacingFront) {
switch (cameraFacingFront) {
case Camera.CameraInfo.CAMERA_FACING_FRONT:
case Camera.CameraInfo.CAMERA_FACING_BACK:
mCameraId = cameraFacingFront;
stopPreview();
startPreview();
break;
}
}
/**
* 切换前置/后置摄像头
*/
public void switchCamera() {
if (mCameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
switchCamera(Camera.CameraInfo.CAMERA_FACING_FRONT);
} else {
switchCamera(Camera.CameraInfo.CAMERA_FACING_BACK);
}
}
/**
* 自动对焦
*
* @param cb
* @return
*/
public boolean autoFocus(AutoFocusCallback cb) {
if (camera != null) {
try {
camera.cancelAutoFocus();
if (mParameters != null) {
String mode = getAutoFocusMode();
if (StringUtils.isNotEmpty(mode)) {
mParameters.setFocusMode(mode);
camera.setParameters(mParameters);
}
}
camera.autoFocus(cb);
return true;
} catch (Exception e) {
if (mOnErrorListener != null) {
mOnErrorListener.onVideoError(MEDIA_ERROR_CAMERA_AUTO_FOCUS, 0);
}
if (e != null) {
Log.e("autoFocus", e);
}
}
}
return false;
}
/**
* 连续自动对焦
*/
private String getAutoFocusMode() {
if (mParameters != null) {
//持续对焦是指当场景发生变化时,相机会主动去调节焦距来达到被拍摄的物体始终是清晰的状态。
List<String> focusModes = mParameters.getSupportedFocusModes();
if ((Build.MODEL.startsWith("GT-I950") || Build.MODEL.endsWith("SCH-I959") || Build.MODEL.endsWith("MEIZU MX3")) && isSupported(focusModes, "continuous-picture")) {
return "continuous-picture";
} else if (isSupported(focusModes, "continuous-video")) {
return "continuous-video";
} else if (isSupported(focusModes, "auto")) {
return "auto";
}
}
return null;
}
/**
* 手动对焦
*
* @param focusAreas 对焦区域
* @return
*/
@SuppressLint("NewApi")
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public boolean manualFocus(AutoFocusCallback cb, List<Area> focusAreas) {
if (camera != null && focusAreas != null && mParameters != null && DeviceUtils.hasICS()) {
try {
camera.cancelAutoFocus();
// getMaxNumFocusAreas检测设备是否支持
if (mParameters.getMaxNumFocusAreas() > 0) {
// mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO);//
// Macro(close-up) focus mode
mParameters.setFocusAreas(focusAreas);
}
if (mParameters.getMaxNumMeteringAreas() > 0)
mParameters.setMeteringAreas(focusAreas);
mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO);
camera.setParameters(mParameters);
camera.autoFocus(cb);
return true;
} catch (Exception e) {
if (mOnErrorListener != null) {
mOnErrorListener.onVideoError(MEDIA_ERROR_CAMERA_AUTO_FOCUS, 0);
}
if (e != null)
Log.e("autoFocus", e);
}
}
return false;
}
/**
* 切换闪关灯,默认关闭
*/
public boolean toggleFlashMode() {
if (mParameters != null) {
try {
final String mode = mParameters.getFlashMode();
if (TextUtils.isEmpty(mode) || Camera.Parameters.FLASH_MODE_OFF.equals(mode))
setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
else
setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
return true;
} catch (Exception e) {
Log.e("toggleFlashMode", e);
}
}
return false;
}
/**
* 设置闪光灯
*
* @param value
*/
private boolean setFlashMode(String value) {
if (mParameters != null && camera != null) {
try {
if (Camera.Parameters.FLASH_MODE_TORCH.equals(value) || Camera.Parameters.FLASH_MODE_OFF.equals(value)) {
mParameters.setFlashMode(value);
camera.setParameters(mParameters);
}
return true;
} catch (Exception e) {
Log.e("setFlashMode", e);
}
}
return false;
}
/**
* 设置码率
*/
public void setVideoBitRate(int bitRate) {
if (bitRate > 0)
mVideoBitrate = bitRate;
}
/**
* 开始预览
*/
public void prepare() {
mPrepared = true;
if (mSurfaceCreated)
startPreview();
}
/**
* 设置视频临时存储文件夹
*
* @param key 视频输出的名称,同目录下唯一,一般取系统当前时间
* @param path 文件夹路径
* @return 录制信息对象
*/
public MediaObject setOutputDirectory(String key, String path) {
if (StringUtils.isNotEmpty(path)) {
File f = new File(path);
if (f != null) {
if (f.exists()) {
//已经存在,删除
if (f.isDirectory())
FileUtils.deleteDir(f);
else
FileUtils.deleteFile(f);
}
if (f.mkdirs()) {
mMediaObject = new MediaObject(key, path, mVideoBitrate);
}
}
}
return mMediaObject;
}
/**
* 设置视频信息
*/
public void setMediaObject(MediaObject mediaObject) {
this.mMediaObject = mediaObject;
}
public void stopRecord() {
mRecording = false;
setStopDate();
}
public void setStopDate() {
// 判断数据是否处理完,处理完了关闭输出流
if (mMediaObject != null) {
MediaObject.MediaPart part = mMediaObject.getCurrentPart();
if (part != null && part.recording) {
part.recording = false;
part.endTime = System.currentTimeMillis();
part.duration = (int) (part.endTime - part.startTime);
part.cutStartTime = 0;
part.cutEndTime = part.duration;
// 检测视频大小是否大于0,否则丢弃(注意有音频没视频的情况下音频也会丢弃)
// File videoFile = new File(part.mediaPath);
// if (videoFile != null && videoFile.length() < 1) {
// mMediaObject.removePart(part, true);
// }
}
}
}
/**
* 停止所有块的写入
*/
private void stopAllRecord() {
mRecording = false;
if (mMediaObject != null && mMediaObject.getMedaParts() != null) {
for (MediaObject.MediaPart part : mMediaObject.getMedaParts()) {
if (part != null && part.recording) {
part.recording = false;
part.endTime = System.currentTimeMillis();
part.duration = (int) (part.endTime - part.startTime);
part.cutStartTime = 0;
part.cutEndTime = part.duration;
// 检测视频大小是否大于0,否则丢弃(注意有音频没视频的情况下音频也会丢弃)
File videoFile = new File(part.mediaPath);
if (videoFile != null && videoFile.length() < 1) {
mMediaObject.removePart(part, true);
}
}
}
}
}
/**
* 检测是否支持指定特性
*/
private boolean isSupported(List<String> list, String key) {
return list != null && list.contains(key);
}
/**
* 预处理一些拍摄参数
* 注意:自动对焦参数cam_mode和cam-mode可能有些设备不支持,导致视频画面变形,需要判断一下,已知有"GT-N7100", "GT-I9308"会存在这个问题
*/
@SuppressWarnings("deprecation")
protected void prepareCameraParaments() {
if (mParameters == null)
return;
List<Integer> rates = mParameters.getSupportedPreviewFrameRates();
if (rates != null) {
if (rates.contains(MAX_FRAME_RATE)) {
mFrameRate = MAX_FRAME_RATE;
} else {
boolean findFrame = false;
Collections.sort(rates);
for (int i = rates.size() - 1; i >= 0; i--) {
if (rates.get(i) <= MAX_FRAME_RATE) {
mFrameRate = rates.get(i);
findFrame = true;
break;
}
}
if (!findFrame) {
mFrameRate = rates.get(0);
}
}
}
mParameters.setPreviewFrameRate(mFrameRate);
// mParameters.setPreviewFpsRange(15 * 1000, 20 * 1000);
// TODO 设置浏览尺寸
boolean findWidth = false;
float ratio = screenHeight / screenWidth;
for (int i = mSupportedPreviewSizes.size() - 1; i >= 0; i--) {
Size size = mSupportedPreviewSizes.get(i);
Log.d("width: " + size.width + ", height: " + size.height + ", ratio: " + ((float)size.width / size.height) + ", target: " + ratio);
if (size.height >= SMALL_VIDEO_HEIGHT && ((float)size.width / size.height) == ratio) {
mSupportedPreviewWidth = size.width;
checkFullWidth(mSupportedPreviewWidth,SMALL_VIDEO_WIDTH);
if (NEED_FULL_SCREEN) {
SMALL_VIDEO_HEIGHT = size.height;
}
findWidth = true;
break;
}
}
if (!findWidth) {
Log.e(getClass().getSimpleName(), "传入高度不支持或未找到对应宽度,请按照要求重新设置,否则会出现一些严重问题");
mSupportedPreviewWidth = 640;
checkFullWidth(640,360);
SMALL_VIDEO_HEIGHT = 480;
}
mParameters.setPreviewSize(mSupportedPreviewWidth, SMALL_VIDEO_HEIGHT);
// 设置输出视频流尺寸,采样率
mParameters.setPreviewFormat(ImageFormat.YV12);
//设置自动连续对焦
String mode = getAutoFocusMode();
if (StringUtils.isNotEmpty(mode)) {
mParameters.setFocusMode(mode);
}
//设置人像模式,用来拍摄人物相片,如证件照。数码相机会把光圈调到最大,做出浅景深的效果。而有些相机还会使用能够表现更强肤色效果的色调、对比度或柔化效果进行拍摄,以突出人像主体。
// if (mCameraId == Camera.CameraInfo.CAMERA_FACING_FRONT && isSupported(mParameters.getSupportedSceneModes(), Camera.Parameters.SCENE_MODE_PORTRAIT))
// mParameters.setSceneMode(Camera.Parameters.SCENE_MODE_PORTRAIT);
if (isSupported(mParameters.getSupportedWhiteBalance(), "auto"))
mParameters.setWhiteBalance("auto");
//是否支持视频防抖
if ("true".equals(mParameters.get("video-stabilization-supported")))
mParameters.set("video-stabilization", "true");
// mParameters.set("recording-hint", "false");
//
// mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
if (!DeviceUtils.isDevice("GT-N7100", "GT-I9308", "GT-I9300")) {
mParameters.set("cam_mode", 1);
mParameters.set("cam-mode", 1);
}
}
private void checkFullWidth(int trueValue, int falseValue) {
if(NEED_FULL_SCREEN){
SMALL_VIDEO_WIDTH=trueValue;
}else {
SMALL_VIDEO_WIDTH = falseValue;
}
}
/**
* 开始预览
*/
public void startPreview() {
if (mStartPreview || mSurfaceHolder == null || !mPrepared)
return;
else
mStartPreview = true;
try {
if (mCameraId == Camera.CameraInfo.CAMERA_FACING_BACK)
camera = Camera.open();
else
camera = Camera.open(mCameraId);
camera.setDisplayOrientation(90);
try {
camera.setPreviewDisplay(mSurfaceHolder);
} catch (IOException e) {
if (mOnErrorListener != null) {
mOnErrorListener.onVideoError(MEDIA_ERROR_CAMERA_SET_PREVIEW_DISPLAY, 0);
}
Log.e("setPreviewDisplay fail " + e.getMessage());
}
//设置摄像头参数
mParameters = camera.getParameters();
mSupportedPreviewSizes = mParameters.getSupportedPreviewSizes();// 获取支持的尺寸
prepareCameraParaments();
camera.setParameters(mParameters);
setPreviewCallback();
camera.startPreview();
onStartPreviewSuccess();
if (mOnPreparedListener != null)
mOnPreparedListener.onPrepared();
} catch (Exception e) {
e.printStackTrace();
if (mOnErrorListener != null) {
mOnErrorListener.onVideoError(MEDIA_ERROR_CAMERA_PREVIEW, 0);
}
Log.e("startPreview fail :" + e.getMessage());
}
}
/**
* 预览调用成功,子类可以做一些操作
*/
protected void onStartPreviewSuccess() {
}
/**
* 设置回调
*/
protected void setPreviewCallback() {
Size size = mParameters.getPreviewSize();
if (size != null) {
int buffSize = size.width * size.height * 3/2;
try {
camera.addCallbackBuffer(new byte[buffSize]);
camera.addCallbackBuffer(new byte[buffSize]);
camera.addCallbackBuffer(new byte[buffSize]);
camera.setPreviewCallbackWithBuffer(this);
} catch (OutOfMemoryError e) {
Log.e("startPreview...setPreviewCallback...", e);
}
Log.d("startPreview...setPreviewCallbackWithBuffer...width:" + size.width + " height:" + size.height);
} else {
camera.setPreviewCallback(this);
}
}
/**
* 停止预览
*/
public void stopPreview() {
if (camera != null) {
try {
camera.stopPreview();
camera.setPreviewCallback(null);
// camera.lock();
camera.release();
} catch (Exception e) {
Log.e("stopPreview...");
}
camera = null;
}
mStartPreview = false;
}
/**
* 释放资源
*/
public void release() {
FFmpegBridge.nativeRelease();
stopAllRecord();
// 停止视频预览
stopPreview();
// 停止音频录制
if (mAudioRecorder != null) {
mAudioRecorder.interrupt();
mAudioRecorder = null;
}
mSurfaceHolder = null;
mPrepared = false;
mSurfaceCreated = false;
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
this.mSurfaceHolder = holder;
this.mSurfaceCreated = true;
if (mPrepared && !mStartPreview)
startPreview();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
this.mSurfaceHolder = holder;
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mSurfaceHolder = null;
mSurfaceCreated = false;
}
@Override
public void onAudioError(int what, String message) {
if (mOnErrorListener != null)
mOnErrorListener.onAudioError(what, message);
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
camera.addCallbackBuffer(data);
}
/**
* 测试PreviewFrame回调次数,时间1分钟
*/
public void testPreviewFrameCallCount() {
new CountDownTimer(1 * 60 * 1000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
Log.e("[Vitamio Recorder]", "testFrameRate..." + mPreviewFrameCallCount);
mPreviewFrameCallCount = 0;
}
@Override
public void onFinish() {
}
}.start();
}
/**
* 接收音频数据
*/
@Override
public void receiveAudioData(byte[] sampleBuffer, int len) {
}
protected String getScaleWH(){
return "";
}
/**
* 预处理监听
*/
public interface OnPreparedListener {
/**
* 预处理完毕,可以开始录制了
*/
void onPrepared();
}
/**
* 错误监听
*/
public interface OnErrorListener {
/**
* 视频录制错误
*
* @param what
* @param extra
*/
void onVideoError(int what, int extra);
/**
* 音频录制错误
*
* @param what
* @param message
*/
void onAudioError(int what, String message);
}
/**
* 转码接口
*/
public interface OnEncodeListener {
/**
* 开始转码
*/
void onEncodeStart();
/**
* 转码进度
*/
void onEncodeProgress(int progress);
/**
* 转码完成
*/
void onEncodeComplete();
/**
* 转码失败
*/
void onEncodeError();
}
protected Boolean doCompress(boolean mergeFlag) {
if (compressConfig != null) {
String vbr = " -vbr 4 ";
if (compressConfig != null && compressConfig.getMode() == BaseMediaBitrateConfig.MODE.CBR) {
vbr = "";
}
String scaleWH = getScaleWH();
if(!TextUtils.isEmpty(scaleWH)){
scaleWH="-s "+scaleWH;
}else {
scaleWH="";
}
String cmd_transcoding = String.format("ffmpeg -threads 16 -i %s -c:v libx264 %s %s %s -c:a libfdk_aac %s %s %s %s",
mMediaObject.getOutputTempVideoPath(),
getBitrateModeCommand(compressConfig, "", false),
getBitrateCrfSize(compressConfig, "-crf 28", false),
getBitrateVelocity(compressConfig, "-preset:v ultrafast", false),
vbr,
getFrameRateCmd(),
scaleWH,
mMediaObject.getOutputTempTranscodingVideoPath()
);
boolean transcodingFlag = FFmpegBridge.jxFFmpegCMDRun( cmd_transcoding) == 0;
boolean captureFlag = FFMpegUtils.captureThumbnails(mMediaObject.getOutputTempTranscodingVideoPath(), mMediaObject.getOutputVideoThumbPath(), String.valueOf(CAPTURE_THUMBNAILS_TIME));
FileUtils.deleteCacheFile(mMediaObject.getOutputDirectory());
boolean result = mergeFlag && captureFlag && transcodingFlag;
return result;
} else {
boolean captureFlag = FFMpegUtils.captureThumbnails(mMediaObject.getOutputTempVideoPath(), mMediaObject.getOutputVideoThumbPath(), String.valueOf(CAPTURE_THUMBNAILS_TIME));
FileUtils.deleteCacheFile2TS(mMediaObject.getOutputDirectory());
boolean result = captureFlag && mergeFlag;
return result;
}
}
protected String getFrameRateCmd() {
return mFrameRateCmd;
}
protected void setTranscodingFrameRate(int rate){
this.mFrameRateCmd=String.format(" -r %d",rate);
}
protected String getBitrateModeCommand(BaseMediaBitrateConfig config, String defualtCmd, boolean needSymbol) {
String add = "";
if (TextUtils.isEmpty(defualtCmd)) {
defualtCmd = "";
}
if (config != null) {
if (config.getMode() == BaseMediaBitrateConfig.MODE.VBR) {
if (needSymbol) {
add = String.format(" -x264opts \"bitrate=%d:vbv-maxrate=%d\" ", config.getBitrate(), config.getMaxBitrate());
} else {
add = String.format(" -x264opts bitrate=%d:vbv-maxrate=%d ", config.getBitrate(), config.getMaxBitrate());
}
return add;
} else if (config.getMode() == BaseMediaBitrateConfig.MODE.CBR) {
if (needSymbol) {
add = String.format(" -x264opts \"bitrate=%d:vbv-bufsize=%d:nal_hrd=cbr\" ", config.getBitrate(), config.getBufSize());
} else {
add = String.format(" -x264opts bitrate=%d:vbv-bufsize=%d:nal_hrd=cbr ", config.getBitrate(), config.getBufSize());
}
return add;
}
}
return defualtCmd;
}
protected String getBitrateCrfSize(BaseMediaBitrateConfig config, String defualtCmd, boolean nendSymbol) {
if (TextUtils.isEmpty(defualtCmd)) {
defualtCmd = "";
}
String add = "";
if (config != null && config.getMode() == BaseMediaBitrateConfig.MODE.AUTO_VBR && config.getCrfSize() > 0) {
if (nendSymbol) {
add = String.format("-crf \"%d\" ", config.getCrfSize());
} else {
add = String.format("-crf %d ", config.getCrfSize());
}
} else {
return defualtCmd;
}
return add;
}
protected String getBitrateVelocity(BaseMediaBitrateConfig config, String defualtCmd, boolean nendSymbol) {
if (TextUtils.isEmpty(defualtCmd)) {
defualtCmd = "";
}
String add = "";
if (config != null && !TextUtils.isEmpty(config.getVelocity())) {
if (nendSymbol) {
add = String.format("-preset \"%s\" ", config.getVelocity());
} else {
add = String.format("-preset %s ", config.getVelocity());
}
} else {
return defualtCmd;
}
return add;
}
}