记录一下 ,在使用硬编码录制视频 ,实时的去添加水印 ;下面是效果图:
主要的流程是:先将视频流转为 bitmap 图片 ,再将图片添加上想要的水印 ,最后再将添加完水印的 bitmap 转化为 NV21 的视频流 ;
下面是 GitHub 的下载链接:https://github.com/wuqingsen/ToMp4Wu
下面是关键的代码:
/**
* 将拿到的预览帧数据转为bitmap添加水印 再讲bitmap转为帧数据
* @param dst 预览的帧数据
* @return
*/
private byte[] dealByte(byte[] dst) {
// YuvImage image = new YuvImage(dst, ImageFormat.NV21, CameraSettings.SRC_IMAGE_WIDTH,CameraSettings.SRC_IMAGE_HEIGHT, null)
// ByteArrayOutputStream stream = new ByteArrayOutputStream();
// image.compressToJpeg(new Rect(0, 0, CameraSettings.SRC_IMAGE_WIDTH,CameraSettings.SRC_IMAGE_HEIGHT), 100, stream);
// Bitmap bitmapAll = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
Bitmap bitmapAll = MainActivity.myClass.nv21ToBitmap(dst, mWidth,
mHeight);
Bitmap bitmapAllNew = bitmapAll.copy(Bitmap.Config.ARGB_8888, true);
Canvas canvas = new Canvas(bitmapAllNew);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
paint.setTextSize(40);
long a = System.currentTimeMillis();
String b = "北京市东城区雍和宫";
canvas.drawText(a + "", 100, 100, paint);
canvas.drawText(b, 100, 300, paint);
byte[] newBytes = SYUtils.bitmapToNv21(bitmapAllNew, mWidth, mHeight);
if (newBytes != null) {
return newBytes;
} else {
return null;
}
}
下面是工具类 SYUtils 中的代码:
package com.example.liuyan.testtomp4;
import android.graphics.Bitmap;
/**
* wuqingsen on 2020-12-11
* Mailbox:1243411677@qq.com
* annotation:
*/
public class SYUtils {
//bitmap转为视频流
public static byte[] bitmapToNv21(Bitmap src, int width, int height) {
if (src != null && src.getWidth() >= width && src.getHeight() >= height) {
int[] argb = new int[width * height];
src.getPixels(argb, 0, width, 0, 0, width, height);
return argbToNv21(argb, width, height);
} else {
return null;
}
}
private static byte[] argbToNv21(int[] argb, int width, int height) {
int frameSize = width * height;
int yIndex = 0;
int uvIndex = frameSize;
int index = 0;
byte[] nv21 = new byte[width * height * 3 / 2];
for (int j = 0; j < height; ++j) {
for (int i = 0; i < width; ++i) {
int R = (argb[index] & 0xFF0000) >> 16;
int G = (argb[index] & 0x00FF00) >> 8;
int B = argb[index] & 0x0000FF;
int Y = (66 * R + 129 * G + 25 * B + 128 >> 8) + 16;
int U = (-38 * R - 74 * G + 112 * B + 128 >> 8) + 128;
int V = (112 * R - 94 * G - 18 * B + 128 >> 8) + 128;
nv21[yIndex++] = (byte) (Y < 0 ? 0 : (Y > 255 ? 255 : Y));
if (j % 2 == 0 && index % 2 == 0 && uvIndex < nv21.length - 2) {
nv21[uvIndex++] = (byte) (V < 0 ? 0 : (V > 255 ? 255 : V));
nv21[uvIndex++] = (byte) (U < 0 ? 0 : (U > 255 ? 255 : U));
}
++index;
}
}
return nv21;
}
}
下面是工具类 MyClass 中的代码:
package com.example.liuyan.testtomp4;
import android.content.Context;
import android.graphics.Bitmap;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicYuvToRGB;
import android.renderscript.Type;
/**
* wuqingsen on 2020-12-11
* Mailbox:1243411677@qq.com
* annotation:
*/
public class MyClass {
private RenderScript rs;
private ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic;
private Type.Builder yuvType, rgbaType;
private Allocation in, out;
public MyClass(Context context) {
rs = RenderScript.create(context);
yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));
}
public Bitmap nv21ToBitmap(byte[] nv21, int width, int height){
if (yuvType == null){
yuvType = new Type.Builder(rs, Element.U8(rs)).setX(nv21.length);
in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT);
rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(width).setY(height);
out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT);
}
in.copyFrom(nv21);
yuvToRgbIntrinsic.setInput(in);
yuvToRgbIntrinsic.forEach(out);
Bitmap bmpout = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
out.copyTo(bmpout);
return bmpout;
}
}