关于NV21格式数据不了解的同学可自行搜索,网上资料很多,这里不做过多阐述。
NV21数据剪裁
剪裁的本质就是在原nv21数据上截取我们需要的进行二次封装即可。
/**
* nv21数据剪裁
*
* @param src 原始nv21数据
* @param srcWidth 原始nv21数据的宽
* @param srcHeight 原始nv21数据的高
* @param clipWidth 剪裁的宽度
* @param clipHeight 剪裁的高度
* @param left 剪裁的开始的左边位置,坐标相对于nv21原始数据
* @param top 剪裁的开始的上边位置,坐标相对于nv21原始数据
* @return 剪裁异常时返回null,成功时返回剪裁的nv21数据
*/
@Nullable
public static byte[] cropNV21(@NonNull byte[] src, int srcWidth, int srcHeight, int clipWidth, int clipHeight, int left, int top) {
if (src.length != srcWidth * srcHeight * 3 / 2) {
return null;
}
if (clipWidth + left > srcWidth || clipHeight + top > srcHeight) {
return null;
}
if (clipWidth == srcWidth && clipHeight == srcHeight && left == 0 && top == 0) {
return src;
}
//确保为偶数
clipWidth &= ~1;
clipHeight &= ~1;
left &= ~1;
top &= ~1;
byte[] cropBytes = new byte[clipWidth * clipHeight * 3 / 2];
int bottom = top + clipHeight;
//先复制Y数据
for (int i = top; i < bottom; i++) {
System.arraycopy(src, left + i * srcWidth, cropBytes, (i - top) * clipWidth, clipWidth);
}
//复制UV数据
int startH = srcHeight + top / 2;
int endH = srcHeight + bottom / 2;
for (int i = startH; i < endH; i++) {
System.arraycopy(src,
left + i * srcWidth,
cropBytes,
(i - startH + clipHeight) * clipWidth,
clipWidth);
}
return cropBytes;
}
NV21数据叠图
叠图的思路就是把原nv21中对应位置、大小的byte数据替换成要叠在上面的nv21数据即可。
- 贴图中无透明像素点的情况

/**
* 叠图
* 调用完成后改方法后,直接使用传入的nv21 数据即可。
*
* @param nv21 叠图最下面的图的nv21数据,大小要比被叠图的nv21数据大
* @param width 最下面叠图的nv21数据的宽
* @param height 最下面叠图的nv21数据的高
* @param left 叠图起始左边位置
* @param top 叠图起始的上边位置
* @param overlayNv21 小图的nv21数据
* @param overlayWidth 小图的宽
* @param overlayHeight 小图的高
*/
public static void overlayNV21(byte[] nv21, int width, int height, int left, int top, byte[] overlayNv21, int overlayWidth, int overlayHeight) {
if (nv21.length != width * height * 3 / 2) {
return;
}
if (overlayNv21.length != overlayWidth * overlayHeight * 3 / 2) {
return;
}
int originalOverlayWidth = overlayWidth;
int originalOverlayHeight = overlayHeight;
if (overlayWidth + left > width) {
//不符合要求,进行