注意如下操作需要在GL线程中执行,否则无效
GLES30.glDeleteTextures(1, new int[]{mTextureId}, 0);
GLES30.glDeleteFramebuffers(1, new int[]{mFrameBuffer}, 0);
GLES30.glDeleteRenderbuffers(1, new int[]{mRenderBuffer}, 0);
GLES30.glDeleteTextures(1, new int[]{mInputTextureId}, 0);
GLES30.glDeleteTextures(1, new int[]{mOriginalDrawer.getOutputTextureId()}, 0);
EGL14.eglSwapBuffers(mEglDisplay, mEglSurface)
需要先变更context
EGL14.eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
EGL14.eglDestroySurface(mEglDisplay, mEglSurface);//清除EGLSurface
EGL14.eglDestroyContext(mEglDisplay, mEglContext);//清除EGLContext环境
EGL14.eglTerminate(mEglDisplay);
public void installApk(Context context, String apkFilePath) {
PackageManager packageManager = context.getPackageManager();
PackageInstaller packageInstaller = packageManager.getPackageInstaller();
packageInstaller.registerSessionCallback(sessionCallback);
PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
try {
int sessionId = packageInstaller.createSession(sessionParams);
File apkFile = new File(apkFilePath);
FileInputStream inputStream = new FileInputStream(apkFile);
PackageInstaller.Session session = packageInstaller.openSession(sessionId);
OutputStream outputStream = session.openWrite(context.getPackageName(), 0, -1);
byte[] buffer = new byte[4096];
int count;
while ((count = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, count);
}
session.fsync(outputStream);
inputStream.close();
outputStream.close();
Intent intent = new Intent(InputEventReceiverWrapper.ACTION_INSTALL_RESULT);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
session.commit(pendingIntent.getIntentSender());
} catch (Exception e) {
e.printStackTrace();
}
packageInstaller.unregisterSessionCallback(sessionCallback);
packageInstaller = null;
}
private PackageInstaller.SessionCallback sessionCallback = new PackageInstaller.SessionCallback() {
@Override
public void onCreated(int sessionId) {
Log.d(TAG, "onCreated() called with: sessionId = [" + sessionId + "]");
}
@Override
public void onBadgingChanged(int sessionId) {
Log.d(TAG, "onBadgingChanged() called with: sessionId = [" + sessionId + "]");
}
@Override
public void onActiveChanged(int sessionId, boolean active) {
Log.d(TAG, "onActiveChanged() called with: sessionId = [" + sessionId + "], active = [" + active + "]");
}
@Override
public void onProgressChanged(int sessionId, float progress) {
Log.d(TAG, "onProgressChanged() called with: sessionId = [" + sessionId + "], progress = [" + progress + "]");
}
@Override
public void onFinished(int sessionId, boolean success) {
Log.d(TAG, "onFinished() called with: sessionId = [" + sessionId + "], success = [" + success + "]");
}
};
监听com.tallresult的广播,广播会收到参数PackageInstaller.EXTRA_STATUS
PackageInstaller.STATUS_SUCCESS为安装成功
mkdir ffmpeg
cd ffmpeg
wget https://ffmpeg.org/releases/ffmpeg-6.0.tar.xz
xz -d ffmpeg-6.0.tar.xz 先解压成xz -d ffmpeg-6.0.tar
tar -zxf ffmpeg-6.0.tar -C ./
cd /home/tuly/
mkdir Ndk
cd Ndk
wget https://dl.google.com/android/repository/android-ndk-r25c-linux.zip
unzip android-ndk-r25c-linux.zip
configure
从
SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'
SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR) $(SLIBNAME)'
改为
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)$(LIBMAJOR)$(SLIBSUF)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'
按如下代码修改
set_default target_os
if test "$target_os" = android; then
cc_default="clang"
cxx_default="clang++"
fi
ar_default="${cross_prefix}${ar_default}"
cc_default="${cross_prefix}${cc_default}"
cxx_default="${cross_prefix}${cxx_default}"
nm_default="${cross_prefix}${nm_default}"
pkg_config_default="${cross_prefix}${pkg_config_default}"
ranlib_default="${cross_prefix}${ranlib_default}"
strip_default="${cross_prefix}${strip_default}"
windres_default="${cross_prefix}${windres_default}"
创建如下编译脚本build.sh 并且chmod a+x build.sh 添加执行权限
#!/usr/bin/env bash
NDK_HOME=/home/tuly/Android/Ndk/android-ndk-r25c
PREFIX=android-build
HOST_PLATFORM=linux-x86_64
ARCH="arm"
CPU="armv7-a"
MARCH="armv7-a"
APP_ABI="armeabi-v7a"
CONFIG_LOG_PATH=${PREFIX}/log
COMMON_OPTIONS=
CONFIGURATION=
APP_ABI="armeabi-v7a"
build(){
COMMON_OPTIONS="$COMMON_OPTIONS --target-os=android"
COMMON_OPTIONS="$COMMON_OPTIONS --disable-static"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-shared"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-protocols"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-cross-compile"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-optimizations"
COMMON_OPTIONS="$COMMON_OPTIONS --disable-debug"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-small"
COMMON_OPTIONS="$COMMON_OPTIONS --disable-doc"
COMMON_OPTIONS="$COMMON_OPTIONS --disable-programs"
COMMON_OPTIONS="$COMMON_OPTIONS --disable-ffmpeg"
COMMON_OPTIONS="$COMMON_OPTIONS --disable-ffplay"
COMMON_OPTIONS="$COMMON_OPTIONS --disable-ffprobe"
COMMON_OPTIONS="$COMMON_OPTIONS --disable-symver"
COMMON_OPTIONS="$COMMON_OPTIONS --disable-network"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-pthreads"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-mediacodec"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-jni"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-zlib"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-pic"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=h264"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=mpeg4"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=mjpeg"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=png"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=vorbis"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=opus"
COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=flac"
ARCH="arm"
CPU="armv7-a"
MARCH="armv7-a"
TOOLCHAINS="$NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin"
CROSS_PREFIX="$TOOLCHAINS/armv7a-linux-androideabi23-"
SYSROOT="$NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/sysroot"
EXTRA_CFLAGS="-march=$MARCH"
EXTRA_CFLAGS="$EXTRA_CFLAGS -mfloat-abi=softfp -mfpu=vfpv3-d16"
EXTRA_CFLAGS="$EXTRA_CFLAGS -I$NDK_HOME/sysroot/usr/include/arm-linux-androideabi"
EXTRA_CFLAGS="$EXTRA_CFLAGS -isysroot $NDK_HOME/sysroot"
EXTRA_LDFLAGS="-lc -lm -ldl -llog"
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,--fix-cortex-a8"
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-rpath-link=$SYSROOT/usr/lib -L$SYSROOT/usr/lib"
EXTRA_OPTIONS="--enable-neon --disable-x86asm"
echo "-------- > Start clean workspace"
make clean
echo "-------- > Start build configuration"
CONFIGURATION="$COMMON_OPTIONS"
CONFIGURATION="$CONFIGURATION --logfile=$CONFIG_LOG_PATH/config_$APP_ABI.log"
CONFIGURATION="$CONFIGURATION --prefix=$PREFIX"
CONFIGURATION="$CONFIGURATION --libdir=$PREFIX/libs/$APP_ABI"
CONFIGURATION="$CONFIGURATION --incdir=$PREFIX/includes/$APP_ABI"
CONFIGURATION="$CONFIGURATION --pkgconfigdir=$PREFIX/pkgconfig/$APP_ABI"
CONFIGURATION="$CONFIGURATION --arch=$ARCH"
CONFIGURATION="$CONFIGURATION --cpu=$CPU"
CONFIGURATION="$CONFIGURATION --cross-prefix=$CROSS_PREFIX"
CONFIGURATION="$CONFIGURATION --sysroot=$SYSROOT"
CONFIGURATION="$CONFIGURATION --extra-ldexeflags=-pie"
CONFIGURATION="$CONFIGURATION --nm=$TOOLCHAINS/llvm-nm"
CONFIGURATION="$CONFIGURATION --strip=$TOOLCHAINS/llvm-strip"
#CONFIGURATION="$CONFIGURATION --pkgconfigdir=$TOOLCHAINS/llvm-config"
CONFIGURATION="$CONFIGURATION $EXTRA_OPTIONS"
echo "-------- > Start config makefile with $CONFIGURATION --extra-cflags="${EXTRA_CFLAGS}" --extra-ldflags="${EXTRA_LDFLAGS}""
./configure ${CONFIGURATION} \
--extra-cflags="$EXTRA_CFLAGS" \
--extra-ldflags="$EXTRA_LDFLAGS"
echo "-------- > 开始编译 $APP_ABI with -j16"
make j16
echo "-------- > 开始执行make install $APP_ABI"
make install
echo "++++++++ > 编译指定abi的so文件完成 $APP_ABI"
}
echo "--------开始编译 --------"
build
echo "--------编译完成 --------"
生成的so文件在android-lib/libs/armeabi-v7a中
这样出来的图片不会出现canvas占用bitmap引起的oom异常
Bitmap originalBitmap = ImageUtils.byteToBitmap(data);
// 创建目标 Bitmap
Bitmap resizedBitmap = Bitmap.createBitmap(def_w, def_h, Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(resizedBitmap);
Rect rect = new Rect (0,0,originalBitmap.getWidth(),originalBitmap.getHeight());
RectF rectf = new RectF(0,0,def_w,def_h);
canvas.drawBitmap(originalBitmap,rect,rectf,null);
canvas.setBitmap(null);// 释放canvas对bitmap的引用 避免oom
canvas = null;
procPic(0, true, resizedBitmap);
resizedBitmap.recycle();
originalBitmap.recycle();
public static Bitmap byteToBitmap(byte[] b) {
DeLogUtils.i("图片字节:" + b.length);
BitmapFactory.Options options = new BitmapFactory.Options();
if (b.length > 2.4 * 1024 * 1024) {
options.inSampleSize = 2; //压缩图片质量 值越大,画质越低
} else if (b.length > 1.5 * 1024 * 1024)
options.inSampleSize = 2;
else if (b.length > 1 * 1024 * 1024)
options.inSampleSize = 2;
else
options.inSampleSize = 1;
options.inMutable = true;
options.inPreferredConfig = Bitmap.Config.ARGB_4444;
Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length, options);
return bitmap;
}
1.检查CaptureRequest.Builder中的FPS_RANGE是否过高,
2.检查是否使用GLRender渲染 一般Canera2的不带渲染的录像 功耗在260mA左右
3.其实特么是人家用的原生的mediarecorder录制,底层加水印,草
公司有做后台录像的功能(合法需求)。但是在录制过程中发现,播放的视频在屏幕点亮的时候呈现正常的播放速度,但是灭屏后的录制内容速度异常加快,且音视频不同步。
使用Adobe Premiere pro免费版逐帧查看音视频情况,发现视频帧数一直是正常的,但是音频波形异常,音频帧明显先于视频帧,所以猜测的是音频帧在使用mediacodec编码的时候出现了问题。
使用公司录音程序进行灭屏录音,发现音频正常,打印线程中的AudioRecord.read()的回调次数发现,无论灭屏还是亮屏时,
1s内输出的频率相近,不会受亮灭屏影响。使用后台录视频时,发现亮屏的时候的回调次数明显比灭屏的时候的audioRecord的回调次数要多很多。
确认两边audiorecord配置是否一致,
录音代码部分
采用的采样率是44100,minbuffersize是2048,audioRecord设置的bufferSizeInByte是minbuffersize8,采用的是audiorecord.read(bytes,0,bytesLength);读取的回调byte[]长度是minbufferSize4;
录视频代码部分
采用的采样率是44100,minbuffersize是4096,audioRecord设置的bufferSizeInByte是minbuffersize*2,采用的是
分配byteBuffer的方式,buffersize是 minbuffersize 回调代码是 audiorecord.read(buffer,minbuffersize);
录视频的录音部分向上同步代码。
发现audiorecord回调次数相近,但是mediacode.dequeueInputBuffer时失败,输入的数据大于缓冲区的大小
重新调整缓冲区大小
mediaformat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, minbufferSize*4);
运行正常
audiorecord.read的回调与录音功能的回调次数差不多,录制结果发现播放速度正常了。
没有深究为什么。猜想是和灭屏的时候,音轨添加的数据骤然减少有关系,导致了音视轨数据不同步。pts的时间戳对不上,就播放异常了。但是解决录制异常的问题,一定要逐帧解码看。播放速度异常不仅仅是单音轨和视轨的异常。单轨的异常就会引起录制的结果异常。其它的
如上观点可以解决部分问题,但是要求低采样率时仍然会有问题。所以最好的建议是
1.增大AudioRecorder的构造函数中的参数bufferSizeinByte
2.前台服务挂起录音
build.gradle配置
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' //GreenDao
def getGitRevision() {
return "git rev-parse --short HEAD".execute().text.trim()
}
def getGitBranch() {
def branchName
def branch = "git branch --contains HEAD".execute().text.trim()
def index = branch.indexOf('*')
if (index == -1) {
branchName = "master"
} else {
branchName = branch.substring(index + 2)
}
println "branchName " + branchName
return branchName
}
def getGitUser() {
return "git config --global --get user.name".execute().text.trim()
}
android {
compileSdkVersion 29
buildToolsVersion '29.0.3'
flavorDimensions "default"
lintOptions {
checkReleaseBuilds false
// Or, if you prefer, you can continue to check for errors in release builds,
// but continue the build even when errors are found:
abortOnError false
}
packagingOptions {
doNotStrip "*/*/libvad.dnn.so"
doNotStrip "*/*/libbd_easr_s1_merge_normal_20151216.dat.so"
}
defaultConfig {
applicationId 'com.xxxx.xx'
minSdkVersion 29
targetSdkVersion 29
def date = new Date().format("yyMMdd", TimeZone.getTimeZone("GMT+08"))
versionName "${date}"
vectorDrawables.useSupportLibrary = true
multiDexEnabled true
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
cppFlags "-frtti -fexceptions -std=c++11"
arguments "-DANDROID_STL=c++_shared"
abiFilters 'armeabi-v7a'
}
}
ndk {
abiFilters "armeabi-v7a"
}
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
useLibrary 'org.apache.http.legacy'
//GreenDao 版本
greendao {
schemaVersion 21 //数据库版本号
daoPackage 'com.xxx.xx.greendao' //设置DaoMaster、DaoSession、Dao包名
targetGenDir 'src/main/java' //设置DaoMaster、DaoSession、Dao目录
}
def commitId = getGitRevision()
def compileUser = getGitUser()
def branchInfo = getGitBranch()
productFlavors {
product1 {
applicationId "com.xxx.xx"
buildConfigField("String", "base_url", "\"192.168.100.115\"")
buildConfigField("String", "productName", "\"PDCut1\"")
buildConfigField("String", "gitCommitId", "\"${commitId}\"")
buildConfigField("String", "gitBranch", "\"${branchInfo}\"")
buildConfigField("String", "gitUser", "\"${compileUser}\"")
//resValue("string", "app_name", "product1")
dimension "default"
versionCode = 106
manifestPlaceholders = [
BaiduMapKey: "xxxxxxxxxxxxxx"]
}
product2 {
applicationId "com.xxx.xx"
buildConfigField("String", "base_url", "\"192.168.100.114\"")
buildConfigField("String", "productName", "\"PDCut2\"")
buildConfigField("String", "gitCommitId", "\"${commitId}\"")
buildConfigField("String", "gitBranch", "\"${branchInfo}\"")
buildConfigField("String", "gitUser", "\"${compileUser}\"")
//resValue("string", "app_name", "product2")
dimension "default"
versionCode = 100
manifestPlaceholders = [
BaiduMapKey: "xxxxxxxxxxxxx"]
}
}
signingConfigs {
product2 {
storeFile file('./product2.jks')
storePassword 'product2'
keyPassword 'product2'
keyAlias 'product2'
v1SigningEnabled true
v2SigningEnabled true
}
product1 {
storeFile file('./product1.jks')
storePassword 'product1'
keyPassword 'product1'
keyAlias 'product1'
v1SigningEnabled true
v2SigningEnabled true
}
}
buildTypes {
debug {
initWith release
debuggable true
zipAlignEnabled false
shrinkResources false
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
release {
debuggable false
minifyEnabled true
zipAlignEnabled true
shrinkResources true
productFlavors.product1.signingConfig signingConfigs.product1
productFlavors.product2.signingConfig signingConfigs.product2
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
applicationVariants.all { variant ->
variant.outputs.all { output ->
def outputFile = output.outputFile
def appName = variant.flavorName
if (outputFile != null && outputFile.name.endsWith('.apk')) {
def apkName = "${appName}_V${versionCode}_${versionName}_${buildType.name}_${commitId}.apk";
outputFileName = apkName
}
}
}
repositories {
flatDir {
dirs 'libs'
}
}
externalNativeBuild {
cmake {
path 'CMakeLists.txt'
}
}
dataBinding {
enabled = true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}