desc:record、push代码

main
xiaowusky 2 years ago
parent 9952ebfe69
commit f0a7a69eae

@ -33,6 +33,7 @@ import org.easydarwin.TxtOverlay
import org.easydarwin.video.EasyPlayerClient import org.easydarwin.video.EasyPlayerClient
import java.io.File import java.io.File
class HomeActivity : NoOptionsActivity() { class HomeActivity : NoOptionsActivity() {
private var warnDialog: ConfirmDialog? = null private var warnDialog: ConfirmDialog? = null
@ -101,7 +102,7 @@ class HomeActivity : NoOptionsActivity() {
*/ */
private fun setForCamera() { private fun setForCamera() {
mClient = EasyPlayerClient(this@HomeActivity, mBinding.surface, null) { mClient = EasyPlayerClient(this@HomeActivity, mBinding.surface, null) {
// RecordHelper.onFrameAvailable(it) RecordHelper.onFrameAvailable(mBinding.surface)
if (!AppData.hasCameraData()) { if (!AppData.hasCameraData()) {
AppData.setCameraData(true) AppData.setCameraData(true)
changeViewStatus() changeViewStatus()

@ -1,81 +1,55 @@
package com.yinuo.safetywatcher.watcher.utils package com.yinuo.safetywatcher.watcher.utils
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.ImageFormat
import android.graphics.Rect
import android.graphics.YuvImage
import android.opengl.EGL14 import android.opengl.EGL14
import android.os.Handler
import android.os.HandlerThread
import android.view.TextureView
import com.common.commonlib.CommonApplication import com.common.commonlib.CommonApplication
import com.common.commonlib.utils.BitmapUtils import com.common.commonlib.utils.BitmapUtils
import com.yinuo.library.vlc.encoder.BaseMovieEncoder.EncoderConfig import com.yinuo.library.vlc.encoder.BaseMovieEncoder.EncoderConfig
import com.yinuo.library.vlc.encoder.MovieEncoder1 import com.yinuo.library.vlc.encoder.MovieEncoder1
import org.easydarwin.TxtOverlay import org.easydarwin.TxtOverlay
import org.easydarwin.sw.JNIUtil
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.util.concurrent.BlockingQueue
import java.util.concurrent.LinkedBlockingQueue
object RecordHelper { object RecordHelper {
private val mVideoEncoder: MovieEncoder1 private val mVideoEncoder: MovieEncoder1
val width = 1920 private const val width = 1920
val height = 1080 private const val height = 1080
val utils by lazy { val utils by lazy {
NV21ToBitmap(CommonApplication.getContext()) NV21ToBitmap(CommonApplication.getContext())
} }
private val mTaskQueue: BlockingQueue<ByteArray> = LinkedBlockingQueue() private val workHandler by lazy {
val mHandlerThread = HandlerThread("recordAndEncode")
mHandlerThread.start()
Handler(mHandlerThread.looper)
}
init { init {
mVideoEncoder = MovieEncoder1(CommonApplication.getContext(), width, height, true) mVideoEncoder = MovieEncoder1(CommonApplication.getContext(), width, height, true)
Thread { }
while (true) {
val take = mTaskQueue.take()
if (take != null) {
val overLayBitmap: Bitmap? = TxtOverlay.getOverlayBitmap()
val dst = ByteArray(take.size)
JNIUtil.ConvertFromI420(take, dst, width, height, 2)
var mVideoBitmap = utils.nv21ToBitmap(dst, width, height) fun onFrameAvailable(view: TextureView) {
if (overLayBitmap != null && mVideoBitmap != null) { if (!mVideoEncoder.isRecording) {
mVideoBitmap = BitmapUtils.mergeBitmap(mVideoBitmap!!, overLayBitmap) return
} }
val baos2 = ByteArrayOutputStream() workHandler.post {
mVideoBitmap?.compress(Bitmap.CompressFormat.PNG, 100, baos2) val nanoTime = System.nanoTime()
val data = baos2.toByteArray() var bitmap = view.bitmap
mVideoEncoder.frameAvailable(data, System.nanoTime()) bitmap?.let {
val overLayBitmap: Bitmap? = TxtOverlay.getOverlayBitmap()
overLayBitmap?.let {
bitmap = BitmapUtils.mergeBitmap(bitmap!!, overLayBitmap)
} }
} }
}.start() val buffer = ByteBuffer.allocate(bitmap!!.getByteCount())
} bitmap!!.copyPixelsToBuffer(buffer)
bitmap!!.recycle()
fun onFrameAvailable(buffer: ByteBuffer) { mVideoEncoder.frameAvailable(buffer.array(), nanoTime)
val input = ByteArray(buffer.capacity())
buffer.clear()
buffer[input]
TxtOverlay.setShowTip("111@2222")
val overLayBitmap: Bitmap? = TxtOverlay.getOverlayBitmap()
val dst = ByteArray(buffer.capacity())
JNIUtil.ConvertFromI420(input, dst, width, height, 2)
val yuvimage = YuvImage(dst, ImageFormat.NV21, width, height, null)
val baos = ByteArrayOutputStream()
yuvimage.compressToJpeg(Rect(0, 0, width, height), 80, baos)
val toByteArray = baos.toByteArray()
var mVideoBitmap = BitmapFactory.decodeByteArray(toByteArray, 0, toByteArray.size)
baos.close()
if (overLayBitmap != null && mVideoBitmap != null) {
mVideoBitmap = BitmapUtils.mergeBitmap(mVideoBitmap!!, overLayBitmap)
} }
val yuvByBitmap = getYUVByBitmap(mVideoBitmap)
buffer.clear()
buffer.limit(yuvByBitmap!!.size)
buffer.put(yuvByBitmap)
} }
fun startRecording() { fun startRecording() {
@ -89,151 +63,4 @@ object RecordHelper {
mVideoEncoder.stopRecording() mVideoEncoder.stopRecording()
} }
} }
fun rgb2YCbCr420(pixels: IntArray, width: Int, height: Int): ByteArray {
val len = width * height
// yuv格式数组大小y亮度占len长度u,v各占len/4长度。
val yuv = ByteArray(len * 3 / 2)
var y: Int
var u: Int
var v: Int
for (i in 0 until height) {
for (j in 0 until width) {
// 屏蔽ARGB的透明度值
val rgb = pixels[i * width + j] and 0x00FFFFFF
// 像素的颜色顺序为bgr移位运算。
val r = rgb and 0xFF
val g = rgb shr 8 and 0xFF
val b = rgb shr 16 and 0xFF
// 套用公式
y = (66 * r + 129 * g + 25 * b + 128 shr 8) + 16
u = (-38 * r - 74 * g + 112 * b + 128 shr 8) + 128
v = (112 * r - 94 * g - 18 * b + 128 shr 8) + 128
// rgb2yuv
// y = (int) (0.299 * r + 0.587 * g + 0.114 * b);
// u = (int) (-0.147 * r - 0.289 * g + 0.437 * b);
// v = (int) (0.615 * r - 0.515 * g - 0.1 * b);
// RGB转换YCbCr
// y = (int) (0.299 * r + 0.587 * g + 0.114 * b);
// u = (int) (-0.1687 * r - 0.3313 * g + 0.5 * b + 128);
// if (u > 255)
// u = 255;
// v = (int) (0.5 * r - 0.4187 * g - 0.0813 * b + 128);
// if (v > 255)
// v = 255;
// 调整
y = if (y < 16) 16 else if (y > 255) 255 else y
u = if (u < 0) 0 else if (u > 255) 255 else u
v = if (v < 0) 0 else if (v > 255) 255 else v
// 赋值
yuv[i * width + j] = y.toByte()
yuv[len + ((i shr 1) * width) + (j and 1.inv()) + 0] = u.toByte()
yuv[len + (+(i shr 1) * width) + (j and 1.inv()) + 1] = v.toByte()
}
}
return yuv
}
fun decodeYUV420SP(
rgbBuf: ByteArray?, yuv420sp: ByteArray?,
width: Int, height: Int
) {
val frameSize = width * height
if (rgbBuf == null) throw NullPointerException("buffer 'rgbBuf' is null")
if (rgbBuf.size < frameSize * 3) throw IllegalArgumentException(
("buffer 'rgbBuf' size "
+ rgbBuf.size + " < minimum ") + frameSize * 3
)
if (yuv420sp == null) throw NullPointerException("buffer 'yuv420sp' is null")
if (yuv420sp.size < frameSize * 3 / 2) throw IllegalArgumentException(
("buffer 'yuv420sp' size "
+ yuv420sp.size + " < minimum " + (frameSize * 3 / 2))
)
var i = 0
var y = 0
var uvp = 0
var u = 0
var v = 0
var y1192 = 0
var r = 0
var g = 0
var b = 0
var j = 0
var yp = 0
while (j < height) {
uvp = frameSize + (j shr 1) * width
u = 0
v = 0
i = 0
while (i < width) {
y = (0xff and (yuv420sp[yp].toInt())) - 16
if (y < 0) y = 0
if ((i and 1) == 0) {
v = (0xff and yuv420sp[uvp++].toInt()) - 128
u = (0xff and yuv420sp[uvp++].toInt()) - 128
}
y1192 = 1192 * y
r = (y1192 + 1634 * v)
g = (y1192 - (833 * v) - (400 * u))
b = (y1192 + 2066 * u)
if (r < 0) r = 0 else if (r > 262143) r = 262143
if (g < 0) g = 0 else if (g > 262143) g = 262143
if (b < 0) b = 0 else if (b > 262143) b = 262143
rgbBuf[yp * 3] = (r shr 10).toByte()
rgbBuf[yp * 3 + 1] = (g shr 10).toByte()
rgbBuf[yp * 3 + 2] = (b shr 10).toByte()
i++
yp++
}
j++
}
}
/*
* 获取位图的RGB数据
*/
fun getRGBByBitmap(bitmap: Bitmap?): ByteArray? {
if (bitmap == null) {
return null
}
val width = bitmap.width
val height = bitmap.height
val size = width * height
val pixels = IntArray(size)
bitmap.getPixels(pixels, 0, width, 0, 0, width, height)
return convertColorToByte(pixels)
}
/*
* 获取位图的YUV数据
*/
fun getYUVByBitmap(bitmap: Bitmap?): ByteArray? {
if (bitmap == null) {
return null
}
val width = bitmap.width
val height = bitmap.height
val size = width * height
val pixels = IntArray(size)
bitmap.getPixels(pixels, 0, width, 0, 0, width, height)
// byte[] data = convertColorToByte(pixels);
return rgb2YCbCr420(pixels, width, height)
}
/*
* 像素数组转化为RGB数组
*/
fun convertColorToByte(color: IntArray?): ByteArray? {
if (color == null) {
return null
}
val data = ByteArray(color.size * 3)
for (i in color.indices) {
data[i * 3] = ((color[i] shr 16) and 0xff).toByte()
data[i * 3 + 1] = ((color[i] shr 8) and 0xff).toByte()
data[i * 3 + 2] = (color[i] and 0xff).toByte()
}
return data
}
} }

@ -926,16 +926,16 @@ public class EasyPlayerClient implements Client.SourceCallBack {
Log.i(TAG, String.format("config codec:%s", format)); Log.i(TAG, String.format("config codec:%s", format));
MediaCodec codec = MediaCodec.createByCodecName(ci.getName()); MediaCodec codec = MediaCodec.createByCodecName(ci.getName());
codec.configure(format, i420callback != null ? null : mSurface, null, 0); codec.configure(format, mSurface, null, 0);
codec.setVideoScalingMode(MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT); codec.setVideoScalingMode(MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT);
codec.start(); codec.start();
mCodec = codec; mCodec = codec;
if (i420callback != null) { // if (i420callback != null) {
final VideoCodec.VideoDecoderLite decoder = new VideoCodec.VideoDecoderLite(); // final VideoCodec.VideoDecoderLite decoder = new VideoCodec.VideoDecoderLite();
decoder.create(mSurface, frameInfo.codec == EASY_SDK_VIDEO_CODEC_H264); // decoder.create(mSurface, frameInfo.codec == EASY_SDK_VIDEO_CODEC_H264);
displayer = decoder; // displayer = decoder;
} // }
} catch (Throwable e) { } catch (Throwable e) {
if (mCodec != null) { if (mCodec != null) {
mCodec.release(); mCodec.release();
@ -1129,47 +1129,47 @@ public class EasyPlayerClient implements Client.SourceCallBack {
} }
if (i420callback != null && outputBuffer != null) { if (i420callback != null && outputBuffer != null) {
if (sliceHeight != realHeight) { // if (sliceHeight != realHeight) {
ByteBuffer tmp = ByteBuffer.allocateDirect(realWidth * realHeight * 3 / 2); // ByteBuffer tmp = ByteBuffer.allocateDirect(realWidth * realHeight * 3 / 2);
outputBuffer.clear(); // outputBuffer.clear();
outputBuffer.limit(realWidth * realHeight); // outputBuffer.limit(realWidth * realHeight);
tmp.put(outputBuffer); // tmp.put(outputBuffer);
//
outputBuffer.clear(); // outputBuffer.clear();
outputBuffer.position(realWidth * sliceHeight); // outputBuffer.position(realWidth * sliceHeight);
outputBuffer.limit((realWidth * sliceHeight + realWidth * realHeight / 4)); // outputBuffer.limit((realWidth * sliceHeight + realWidth * realHeight / 4));
tmp.put(outputBuffer); // tmp.put(outputBuffer);
//
outputBuffer.clear(); // outputBuffer.clear();
outputBuffer.position(realWidth * sliceHeight + realWidth * realHeight / 4); // outputBuffer.position(realWidth * sliceHeight + realWidth * realHeight / 4);
outputBuffer.limit((realWidth * sliceHeight + realWidth * realHeight / 4 + realWidth * realHeight / 4)); // outputBuffer.limit((realWidth * sliceHeight + realWidth * realHeight / 4 + realWidth * realHeight / 4));
tmp.put(outputBuffer); // tmp.put(outputBuffer);
//
tmp.clear(); // tmp.clear();
outputBuffer = tmp; // outputBuffer = tmp;
} // }
if (mColorFormat == COLOR_FormatYUV420SemiPlanar if (mColorFormat == COLOR_FormatYUV420SemiPlanar
|| mColorFormat == COLOR_FormatYUV420PackedSemiPlanar || mColorFormat == COLOR_FormatYUV420PackedSemiPlanar
|| mColorFormat == COLOR_TI_FormatYUV420PackedSemiPlanar) { || mColorFormat == COLOR_TI_FormatYUV420PackedSemiPlanar) {
byte[] in = new byte[realWidth * realHeight * 3 / 2]; // byte[] in = new byte[realWidth * realHeight * 3 / 2];
outputBuffer.clear(); // outputBuffer.clear();
outputBuffer.get(in); // outputBuffer.get(in);
//
// yuvuv_to_yuv // // yuvuv_to_yuv
JNIUtil.yuvConvert(in, realWidth, realHeight, 4); // JNIUtil.yuvConvert(in, realWidth, realHeight, 4);
// // 旋转90或180或270度 //// // 旋转90或180或270度
// yuvRotate(in, 0, realWidth, realHeight, 90); //// yuvRotate(in, 0, realWidth, realHeight, 90);
//
ByteBuffer tmp = ByteBuffer.allocateDirect(realWidth * realHeight * 3 / 2); // ByteBuffer tmp = ByteBuffer.allocateDirect(realWidth * realHeight * 3 / 2);
tmp.clear(); // tmp.clear();
tmp.put(in); // tmp.put(in);
i420callback.onI420Data(tmp); i420callback.onI420Data(null);
// 旋转90或270度则宽高需要互换 // // 旋转90或270度则宽高需要互换
displayer.decoder_decodeBuffer(tmp, realWidth, realHeight); // displayer.decoder_decodeBuffer(tmp, realWidth, realHeight);
} }
} }
@ -1183,7 +1183,7 @@ public class EasyPlayerClient implements Client.SourceCallBack {
} }
// Log.d(TAG,String.format("sleep:%d", newSleepUs/1000)); // Log.d(TAG,String.format("sleep:%d", newSleepUs/1000));
Thread.sleep(newSleepUs / 1000); Thread.sleep(newSleepUs / 1000);
mCodec.releaseOutputBuffer(index, i420callback == null); mCodec.releaseOutputBuffer(index, true);
} }
if (firstTime) { if (firstTime) {

Loading…
Cancel
Save