package com.yixia.videoeditor.adapter;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.util.Log;
public class UtilityAdapter {
static {
System.loadLibrary("utility");
}
/** 初始化底层库 */
public static native void FFmpegInit(Object context, String settings);
/** 获取当前转码时间 */
public static native int FFmpegVideoGetTransTime(int flag);
/** 开始播放器数据的录制 */
public static native boolean VitamioStartRecord(String yuv, String pcm);
/** 停止播放器数据的录制 */
public static native int VitamioStopRecord(int flag);
/** 获取视频回调指针 */
public static native int GetVitamioVideoCallbackPointer(int flag);
/** 获取音频回调指针 */
public static native int GetVitamioAudioCallbackPointer(int flag);
/** 获取视频旋转信息 */
public static native int VideoGetMetadataRotate(String filename);
/**
* 执行ffmpeg命令 tag 任务的唯一标识,如果标识为"",以阻塞方式运行,否则以异步方式运行 FFmpegRun("",
* "ffmpeg -i \"生成的mp4\" -y -f image2 -ss 1 -t 0.001 -s 480x480 \"输出.jpg\" "
* )
*
* @param strtag
* 任务的唯一标识,如果标识为"",以阻塞方式运行,否则以异步方式运行
* @param strcmd
* 命令行
* @return 返回执行结果
*/
public static native int FFmpegRun(String tag, String cmd);
/** 结束异步执行的ffmpeg */
public static native void FFmpegKill(String tag);
/** 检测ffmpeg实例是否正在运行 */
public static native boolean FFmpegIsRunning(String tag);
/** 获取视频信息,相当于调用ffprobe */
public static native String FFmpegVideoGetInfo(String filename);
/**
* 传入参数width,height为surfaceview创建时给出的,后面的outwidth,outheight为输出的视频高宽,初始化时传入0,0,返回纹理id
* @param width surfaceview创建时给出的
* @param height surfaceview创建时给出的
* @return
*/
public static native int RenderViewInit(int width, int height);
/** 设置摄像头预览数据尺寸,摄像头旋转、翻转设置 */
public static final int FLIPTYPE_NORMAL = 0x0;
/** 设置摄像头预览数据尺寸,摄像头旋转、翻转设置 */
public static final int FLIPTYPE_HORIZONTAL = 0x1;
/** 设置摄像头预览数据尺寸,摄像头旋转、翻转设置 */
public static final int FLIPTYPE_VERTICAL = 0x2;
/**
* 设置输入参数
*
* @param inw 视频输入宽
* @param inh 视频输入高
* @param org 后置摄像头0,前置摄像头180
* @param flip 后置摄像头FLIPTYPE_NORMAL,前摄像头FLIPTYPE_HORIZONTAL
*/
public static native void RenderInputSettings(int inw, int inh, int org, int flip);
//设置输出视频流尺寸,采样率
public static final int OUTPUTFORMAT_YUV = 0x1;
public static final int OUTPUTFORMAT_RGBA = 0x2;
public static final int OUTPUTFORMAT_MASK_ZIP = 0x4;
public static final int OUTPUTFORMAT_MASK_NEED_LASTSNAP = 0x8;
public static final int OUTPUTFORMAT_MASK_HARDWARE_ACC = 0x10;
public static final int OUTPUTFORMAT_MASK_MP4 = 0x20;
/**
* 设置视频输出参数
*
* @param outw 视频输出宽
* @param outh 视频输出高
* @param outfps 视频输出帧率
* @param format 视频输出格式,参考OUTPUTFORMAT_*
*/
public static native void RenderOutputSettings(int outw, int outh, int outfps, int format);
//设置特效
public static final int FILTERTYPE_FILTER = 0;
public static final int FILTERTYPE_FRAME = 1;
public static native void RenderSetFilter(int type, String filter);
//进行显示
public static native void RenderStep();
//提供摄像头数据
public static native void RenderDataYuv(byte[] yuv);
/** 提供录音数据,必须是44100Hz,1channel,16bit unsigned */
public static native void RenderDataPcm(byte[] pcm);
/** 获取最后一帧数据,如果失败会返回一副全透明的图,如果内存失败,会返回空,alpha的值为0-1,0为全透明 */
public static native int[] RenderGetDataArgb(float alpha);
/** 设置输出数据文件,设置完就开始录制 */
public static native boolean RenderOpenOutputFile(String video, String audio);
/** 关闭输出数据文件,关闭后就停止录制 */
public static native void RenderCloseOutputFile();
/** 关闭输出数据文件,关闭后就停止录制 */
public static native boolean RenderIsOutputJobFinish();
/** 暂停录制 */
public static native void RenderPause(boolean pause);
/** 暂停特效 */
public static void FilterParserPause(boolean pause) {
if (mAudioTrack != null) {
if (pause) {
mAudioTrack.pause();
} else {
mAudioTrack.play();
}
}
RenderPause(pause);
}
/**
* 特效处理器
*
* @param settings 特效设置: inv=/sdcard/v.rgb; ina=/sdcard/p.pcm; out=/sdcard/o.mp4; text=/sdcard/txt.png
* @param surface Surface
* @param holder SurfaceHolder
*/
public static native boolean FilterParserInit(String strings, Object surface);
//查询目前特效处理信息
public static final int FILTERINFO_PROCESSEDFRAME = 0; ///<从开始累计已处理的帧数
public static final int FILTERINFO_CACHEDFRAME = 1; ///<目前可用的帧数
public static final int FILTERINFO_STARTPLAY = 2; ///<开始播放
public static final int FILTERINFO_PAUSEPLAY = 3; ///<暂停播放
public static final int FILTERINFO_PROGRESS = 4; ///<当前处理进度
public static final int FILTERINFO_TOTALMS = 5; ///<经特效处理后,文件的时长,单位毫秒
public static final int FILTERINFO_CAUSEGC = 6; ///<清理渲染使用的缓存
public static native int FilterParserInfo(int mode);
/** 停止特效处理 */
public static native void FilterParserFree();
//特效组处理
public static final int PARSERACTION_INIT = 0; ///<设置全局的属性,在一开始进入预览界面时调用
public static final int PARSERACTION_UPDATE = 1; ///<设置摄像头相关属性,在摄像头打开时调用
public static final int PARSERACTION_START = 2; ///<设置开始捕捉,并指定保存的文件
public static final int PARSERACTION_STOP = 3; ///<设置停止捕捉
public static final int PARSERACTION_FREE = 4; ///<释放占用,这时没完成的进度也会被取消
public static final int PARSERACTION_PROGRESS = 5; ///<查询处理的进度
/**
* 特效处理
*
* @param settings
* @param actiontype
* @return
*/
public static native int FilterParserAction(String settings, int actiontype);
public static native boolean SaveData(String filename, int[] data, int flag);
private static volatile boolean gInitialized;
public static boolean isInitialized(){
return gInitialized;
}
/** 初始化 */
public static void initFilterParser() {
if (!gInitialized) {
gInitialized = true;
FilterParserAction("", PARSERACTION_INIT);
}
}
public static void freeFilterParser() {
gInitialized = false;
FilterParserAction("", PARSERACTION_FREE);
}
/**
* 变声
*
* @param inPath wav音频输入
* @param outPath wav音频输出
* @param tempoChange 变速(语速增加%xx)
* @param pitch // 音幅变调
* @param pitchSemitone //音程变调
*/
public static native int SoundEffect(String inPath, String outPath, float tempoChange, float pitch, int pitchSemitone);
protected static AudioTrack mAudioTrack;
/** 底层音频初始化 */
@SuppressWarnings("deprecation")
public static boolean ndkAudioInit() {
int desiredFrames = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);// * 8;
//desiredFrames = 101376
if (mAudioTrack == null) {
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, desiredFrames, AudioTrack.MODE_STREAM);
// Instantiating AudioTrack can "succeed" without an exception and the track may still be invalid
// Ref: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/media/java/android/media/AudioTrack.java
// Ref: http://developer.android.com/reference/android/media/AudioTrack.html#getState()
if (mAudioTrack.getState() != AudioTrack.STATE_INITIALIZED) {
mAudioTrack = null;
Log.w("ndkAudio", "Init failed!");
return false;
}
mAudioTrack.play();
}
return true;
}
/** 底层音频输出 */
public static void ndkAudioWrite(short[] buffer, int cnt) {
int limitcount = 100;
int result;
for (int i = 0; i < cnt;) {
limitcount--;
if (limitcount <= 0) {
Log.e("ndkAudio", "avoid dead loop");
break;
}
result = mAudioTrack.write(buffer, i, cnt - i);
if (result > 0) {
i += result;
} else if (result == 0) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// Nom nom
}
} else {
Log.w("ndkAudio", "write failed!");
return;
}
}
}
public static void ndkAudioQuit() {
if (mAudioTrack != null) {
mAudioTrack.stop();
mAudioTrack.release();
mAudioTrack = null;
}
}
//key
public static final int NOTIFYKEY_PLAYSTATE = 1;
/** 播放发生缓冲时报告 */
public static final int NOTIFYVALUE_BUFFEREMPTY = 0;
/** 恢复播放时报告 */
public static final int NOTIFYVALUE_BUFFERFULL = 1;
/** 播放完成时报告 */
public static final int NOTIFYVALUE_PLAYFINISH = 2;
/** 无法播放时报告 */
public static final int NOTIFYVALUE_HAVEERROR = 3;
/** 底层回调 */
public static int ndkNotify(int key, int value) {
if (mOnNativeListener != null) {
mOnNativeListener.ndkNotify(key, value);
} else {
Log.e("ndkNotify", "ndkNotify key:" + key + ", value: " + value);
}
return 0;
}
/** 注册监听回调 */
public static void registerNativeListener(OnNativeListener l) {
mOnNativeListener = l;
}
private static OnNativeListener mOnNativeListener;
/** 底层通知 */
public static interface OnNativeListener {
public void ndkNotify(int key, int value);
}
}