小白一个,开始研究YUV,记录一下心得,如果有什么说得不对的地方,请及时纠正
最近需要实现一个YUV增加水印的功能,作为小白完全没有思路。后来一个前辈给了一个方案:将水印图案转换为YUV,覆盖到需要添加水印的地方。
ffmpeg -i waterMark.png -pix_fmt nv21 waterMark.yuv
转换为yuv之后,将该YUV数据覆盖到源yuv图像上,即可完成水印的添加,源码如下
void yuvAddWaterMark(int yuvType, int startX, int startY, unsigned char *waterMarkData,
int waterMarkW, int waterMarkH, unsigned char *yuvData, int yuvW, int yuvH) {
int i=0;
int j=0;
int k=0;
switch(yuvType) {
case NV21OR21:
for(i=startY; i<waterMarkH+startY; i++) {
memcpy(yuvData+startX+i*yuvW, waterMarkData+j*waterMarkW, waterMarkW);
j++;
}
for(i=startY/2; i<(waterMarkH+startY)/2; i++) {
memcpy(yuvData+startX+yuvW*yuvH+i*yuvW, waterMarkData+waterMarkW*waterMarkH+k*waterMarkW, waterMarkW);
k++;
}
#ifdef SAVE_RET
FILE *outPutFp = fopen("Final.yuv", "w+");
fwrite(yuvData, 1, yuvW*yuvH*3/2, outPutFp);
fclose(outPutFp);
#endif
break;
case YUV420SP:
//Not FInished
break;
default:
//Not FInished
break;
}
}
参数的含义:yuvType -------------------------- yuv类型,目前只支持NV12和NV21
startX,startY -------------------------- 需要添加水印的位置
waterMarkData -------------------------- 水印YUV数据,可以通过读取水印文件获取
waterMarkW,waterMarkH -------------------------- 水印数据的分辨率
yuvData -------------------------- 源YUV图像数据
yuvW,yuvH -------------------------- 源YUV的分辨率
测试结果如下:
添加水印前的yuv图片
添加水印后的yuv图像
但是对于一些边缘透明的png图片转换为yuv之后,边缘就会变为黑色不透明的,加了水印后可能就是这个效果
用16进制打开google logo的YUV水印文件如下:
从头到尾大致看了一下发现0x10和0x80特别多,因此可以大胆的猜测一下,在Y分量中0x10可能是黑色的,在uv分量中0x80可能是黑色的,
int fCutWaterMark(unsigned char *waterMarkSrc, unsigned char *srcYuv, int waterMarkW, int waterMarkH) {
int i;
unsigned char tmpData[waterMarkW*waterMarkH*3/2];
unsigned char tmpWaterMark[waterMarkW*waterMarkH*3/2];
memcpy(tmpData, srcYuv, waterMarkW*waterMarkH*3/2);
memcpy(tmpWaterMark, waterMarkSrc, waterMarkW*waterMarkH*3/2);
for(i=0; i<waterMarkW*waterMarkH*3/2; i++) {
if(tmpWaterMark[i]!=0x10 && tmpWaterMark[i]!=0x80 && tmpWaterMark[i]!=0xeb) {
tmpData[i] = tmpWaterMark[i];
// printf("0x%X\n", tmpData[i]);
}
}
memcpy(waterMarkSrc, tmpData, waterMarkW*waterMarkH*3/2);
#if 1
FILE *tarFp = fopen("afterCutWaterMark.yuv", "w+");
fwrite(waterMarkSrc, 1, waterMarkW*waterMarkH*3/2, tarFp);
fclose(tarFp);
#endif
return 0;
}
void cutYuv(int yuvType, unsigned char *tarYuv, unsigned char *srcYuv, int startW,
int startH, int cutW, int cutH, int srcW, int srcH)
fCutWaterMark(unsigned char *waterMarkSrc, unsigned char *srcYuv, int waterMarkW, int waterMarkH)
void yuvAddWaterMark(int yuvType, int startX, int startY, unsigned char *waterMarkData,
int waterMarkW, int waterMarkH, unsigned char *yuvData, int yuvW, int yuvH)