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 java.io.File
class HomeActivity : NoOptionsActivity() {
private var warnDialog: ConfirmDialog? = null
@ -101,7 +102,7 @@ class HomeActivity : NoOptionsActivity() {
*/
private fun setForCamera() {
mClient = EasyPlayerClient(this@HomeActivity, mBinding.surface, null) {
// RecordHelper.onFrameAvailable(it)
RecordHelper.onFrameAvailable(mBinding.surface)
if (!AppData.hasCameraData()) {
AppData.setCameraData(true)
changeViewStatus()

@ -1,81 +1,55 @@
package com.yinuo.safetywatcher.watcher.utils
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.os.Handler
import android.os.HandlerThread
import android.view.TextureView
import com.common.commonlib.CommonApplication
import com.common.commonlib.utils.BitmapUtils
import com.yinuo.library.vlc.encoder.BaseMovieEncoder.EncoderConfig
import com.yinuo.library.vlc.encoder.MovieEncoder1
import org.easydarwin.TxtOverlay
import org.easydarwin.sw.JNIUtil
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.nio.ByteBuffer
import java.util.concurrent.BlockingQueue
import java.util.concurrent.LinkedBlockingQueue
object RecordHelper {
private val mVideoEncoder: MovieEncoder1
val width = 1920
val height = 1080
private const val width = 1920
private const val height = 1080
val utils by lazy {
NV21ToBitmap(CommonApplication.getContext())
}
private val mTaskQueue: BlockingQueue<ByteArray> = LinkedBlockingQueue()
private val workHandler by lazy {
val mHandlerThread = HandlerThread("recordAndEncode")
mHandlerThread.start()
Handler(mHandlerThread.looper)
}
init {
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)
if (overLayBitmap != null && mVideoBitmap != null) {
mVideoBitmap = BitmapUtils.mergeBitmap(mVideoBitmap!!, overLayBitmap)
}
val baos2 = ByteArrayOutputStream()
mVideoBitmap?.compress(Bitmap.CompressFormat.PNG, 100, baos2)
val data = baos2.toByteArray()
mVideoEncoder.frameAvailable(data, System.nanoTime())
fun onFrameAvailable(view: TextureView) {
if (!mVideoEncoder.isRecording) {
return
}
workHandler.post {
val nanoTime = System.nanoTime()
var bitmap = view.bitmap
bitmap?.let {
val overLayBitmap: Bitmap? = TxtOverlay.getOverlayBitmap()
overLayBitmap?.let {
bitmap = BitmapUtils.mergeBitmap(bitmap!!, overLayBitmap)
}
}
}.start()
}
fun onFrameAvailable(buffer: ByteBuffer) {
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 buffer = ByteBuffer.allocate(bitmap!!.getByteCount())
bitmap!!.copyPixelsToBuffer(buffer)
bitmap!!.recycle()
mVideoEncoder.frameAvailable(buffer.array(), nanoTime)
}
val yuvByBitmap = getYUVByBitmap(mVideoBitmap)
buffer.clear()
buffer.limit(yuvByBitmap!!.size)
buffer.put(yuvByBitmap)
}
fun startRecording() {
@ -89,151 +63,4 @@ object RecordHelper {
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));
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.start();
mCodec = codec;
if (i420callback != null) {
final VideoCodec.VideoDecoderLite decoder = new VideoCodec.VideoDecoderLite();
decoder.create(mSurface, frameInfo.codec == EASY_SDK_VIDEO_CODEC_H264);
displayer = decoder;
}
// if (i420callback != null) {
// final VideoCodec.VideoDecoderLite decoder = new VideoCodec.VideoDecoderLite();
// decoder.create(mSurface, frameInfo.codec == EASY_SDK_VIDEO_CODEC_H264);
// displayer = decoder;
// }
} catch (Throwable e) {
if (mCodec != null) {
mCodec.release();
@ -1129,47 +1129,47 @@ public class EasyPlayerClient implements Client.SourceCallBack {
}
if (i420callback != null && outputBuffer != null) {
if (sliceHeight != realHeight) {
ByteBuffer tmp = ByteBuffer.allocateDirect(realWidth * realHeight * 3 / 2);
outputBuffer.clear();
outputBuffer.limit(realWidth * realHeight);
tmp.put(outputBuffer);
outputBuffer.clear();
outputBuffer.position(realWidth * sliceHeight);
outputBuffer.limit((realWidth * sliceHeight + realWidth * realHeight / 4));
tmp.put(outputBuffer);
outputBuffer.clear();
outputBuffer.position(realWidth * sliceHeight + realWidth * realHeight / 4);
outputBuffer.limit((realWidth * sliceHeight + realWidth * realHeight / 4 + realWidth * realHeight / 4));
tmp.put(outputBuffer);
tmp.clear();
outputBuffer = tmp;
}
// if (sliceHeight != realHeight) {
// ByteBuffer tmp = ByteBuffer.allocateDirect(realWidth * realHeight * 3 / 2);
// outputBuffer.clear();
// outputBuffer.limit(realWidth * realHeight);
// tmp.put(outputBuffer);
//
// outputBuffer.clear();
// outputBuffer.position(realWidth * sliceHeight);
// outputBuffer.limit((realWidth * sliceHeight + realWidth * realHeight / 4));
// tmp.put(outputBuffer);
//
// outputBuffer.clear();
// outputBuffer.position(realWidth * sliceHeight + realWidth * realHeight / 4);
// outputBuffer.limit((realWidth * sliceHeight + realWidth * realHeight / 4 + realWidth * realHeight / 4));
// tmp.put(outputBuffer);
//
// tmp.clear();
// outputBuffer = tmp;
// }
if (mColorFormat == COLOR_FormatYUV420SemiPlanar
|| mColorFormat == COLOR_FormatYUV420PackedSemiPlanar
|| mColorFormat == COLOR_TI_FormatYUV420PackedSemiPlanar) {
byte[] in = new byte[realWidth * realHeight * 3 / 2];
outputBuffer.clear();
outputBuffer.get(in);
// yuvuv_to_yuv
JNIUtil.yuvConvert(in, realWidth, realHeight, 4);
// // 旋转90或180或270度
// yuvRotate(in, 0, realWidth, realHeight, 90);
ByteBuffer tmp = ByteBuffer.allocateDirect(realWidth * realHeight * 3 / 2);
tmp.clear();
tmp.put(in);
// byte[] in = new byte[realWidth * realHeight * 3 / 2];
// outputBuffer.clear();
// outputBuffer.get(in);
//
// // yuvuv_to_yuv
// JNIUtil.yuvConvert(in, realWidth, realHeight, 4);
//// // 旋转90或180或270度
//// yuvRotate(in, 0, realWidth, realHeight, 90);
//
// ByteBuffer tmp = ByteBuffer.allocateDirect(realWidth * realHeight * 3 / 2);
// tmp.clear();
// tmp.put(in);
i420callback.onI420Data(tmp);
i420callback.onI420Data(null);
// 旋转90或270度则宽高需要互换
displayer.decoder_decodeBuffer(tmp, realWidth, realHeight);
// // 旋转90或270度则宽高需要互换
// 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));
Thread.sleep(newSleepUs / 1000);
mCodec.releaseOutputBuffer(index, i420callback == null);
mCodec.releaseOutputBuffer(index, true);
}
if (firstTime) {

Loading…
Cancel
Save