* 音視頻入門文章目錄 *html
libyuv
libyuv 是 Google 開源的實現各類 YUV 與 RGB 之間相互轉換、旋轉、縮放等的庫。它是跨平臺的,可在 Windows、Linux、Mac、Android 等操做系統,x8六、x6四、arm 架構上進行編譯運行,支持 SSE、AVX、NEON 等 SIMD 指令加速。git
準備工做
一張圖片
下載 rainbow-700x700.bmp BMP 圖片 或者 本身準備一張圖片(知道分辨率,如:700x700)github
FFmpeg 工具包
根據本身的系統,下載 FFmpeg Static 工具包。ide
獲得所需的 yuv420p 文件
將上面準備的圖片轉換成 YUV420P 格式:工具
ffmpeg -i rainbow.bmp -video_size 700x700 -pix_fmt yuv420p rainbow-yuv420p.yuv
查看 YUV 文件
ffplay -f rawvideo -pixel_format yuv420p -video_size 700x700 rainbow-yuv420p.yuv
libyuv 操做 YUV
YUV 裁剪
[rainbow-yuv420p.yuv] -> [rainbow-yuv420p-clip-x-y.yuv]ui
#include <stdio.h> #include <stdint.h> #include "libyuv.h" void clip(uint8_t *srcYuvData, uint8_t *dstYuvData, int width, int height, int cropX, int cropY, int cropWidth, int cropHeight) { ConvertToI420( srcYuvData, width*height*3/2, dstYuvData, cropWidth, dstYuvData+cropWidth*cropHeight, (cropWidth+1)/2, dstYuvData+cropWidth*cropHeight+((cropWidth+1)/2)*((cropHeight+1)/2), (cropWidth+1)/2, cropX, cropY, width, height, cropWidth, cropHeight, kRotate0, FOURCC_YU12); } int main() { uint32_t width = 700, height = 700; uint32_t clipWidth = 200, clipHeight = 200; uint8_t YUV[width*height*3/2]; uint8_t YUV_CLIP[clipWidth*clipHeight*3/2]; FILE *yuv420pFile = fopen("/Users/staff/Desktop/rainbow-yuv420p.yuv", "rb"); fread(YUV, sizeof(YUV), 1, yuv420pFile); clip(YUV, YUV_CLIP, width, height, 0, 0, clipWidth, clipHeight); FILE *yuvClipFile = fopen("/Users/staff/Desktop/rainbow-yuv420p-clip-0-0.yuv", "wb"); fwrite(YUV_CLIP, sizeof(YUV_CLIP), 1, yuvClipFile); fclose(yuvClipFile); fclose(yuv420pFile); return 0; }
YUV 縮放
[rainbow-yuv420p.yuv] -> [rainbow-yuv420p-scale-X.yuv]google
#include <stdio.h> #include <stdint.h> #include "libyuv.h" void scale(uint8_t *srcYuvData, uint8_t *dstYuvData, int width, int height, int dstWidth, int dstHeight) { I420Scale( srcYuvData, width, srcYuvData+width*height, (width+1)/2, srcYuvData+width*height+((width+1)/2)*((height+1)/2), (width+1)/2, width, height, dstYuvData, dstWidth, dstYuvData+dstWidth*dstWidth, (dstWidth+1)/2, dstYuvData+dstWidth*dstHeight+((dstWidth+1)/2)*((dstHeight+1)/2), (dstWidth+1)/2, dstWidth, dstHeight, kFilterNone ); } int main() { uint32_t width = 700, height = 700; uint32_t dstWidth = 100, dstHeight = 100; uint8_t YUV[width*height*3/2]; uint8_t YUV_SCALE[dstWidth*dstHeight*3/2]; FILE *yuv420pFile = fopen("/Users/staff/Desktop/rainbow-yuv420p.yuv", "rb"); fread(YUV, sizeof(YUV), 1, yuv420pFile); scale(YUV, YUV_SCALE, width, height, dstWidth, dstHeight); FILE *yuvScaleFile = fopen("/Users/staff/Desktop/rainbow-yuv420p-scale-6.yuv", "wb"); fwrite(YUV_SCALE, sizeof(YUV_SCALE), 1, yuvScaleFile); fclose(yuvScaleFile); fclose(yuv420pFile); return 0; }
YUV 旋轉
[rainbow-yuv420p.yuv] -> [rainbow-yuv420p-rotation-90.yuv]spa
#include <stdio.h> #include <stdint.h> #include "libyuv.h" void rotation(uint8_t *srcYuvData, uint8_t *dstYuvData, int width, int height) { I420Rotate( srcYuvData, width, srcYuvData+width*height, (width+1)/2, srcYuvData+width*height+((width+1)/2)*((height+1)/2), (width+1)/2, dstYuvData, width, dstYuvData+width*height, (width+1)/2, dstYuvData+width*height+((width+1)/2)*((height+1)/2), (width+1)/2, width, height, kRotate90 ); } int main() { uint32_t width = 700, height = 700; uint8_t YUV[width*height*3/2]; uint8_t YUV_ROTATION[width*height*3/2]; FILE *yuv420pFile = fopen("/Users/staff/Desktop/rainbow-yuv420p.yuv", "rb"); fread(YUV, sizeof(YUV), 1, yuv420pFile); rotation(YUV, YUV_ROTATION, width, height); FILE *yuvRotationFile = fopen("/Users/staff/Desktop/rainbow-yuv420p-rotation-90.yuv", "wb"); fwrite(YUV_ROTATION, sizeof(YUV_ROTATION), 1, yuvRotationFile); fclose(yuvRotationFile); fclose(yuv420pFile); return 0; }
YUV 鏡像
[rainbow-yuv420p-rotation-90.yuv] -> [rainbow-yuv420p-rotation-90-mirror.yuv]操作系統
#include <stdio.h> #include <stdint.h> #include "libyuv.h" void mirror(uint8_t *srcYuvData, uint8_t *dstYuvData, int width, int height) { I420Mirror( srcYuvData, width, srcYuvData+width*height, (width+1)/2, srcYuvData+width*height+((width+1)/2)*((height+1)/2), (width+1)/2, dstYuvData, width, dstYuvData+width*height, (width+1)/2, dstYuvData+width*height+((width+1)/2)*((height+1)/2), (width+1)/2, width, height ); } int main() { uint32_t width = 700, height = 700; uint8_t YUV[width*height*3/2]; uint8_t YUV_MIRROR[width*height*3/2]; FILE *yuv420pFile = fopen("/Users/staff/Desktop/rainbow-yuv420p-rotation-90.yuv", "rb"); fread(YUV, sizeof(YUV), 1, yuv420pFile); mirror(YUV, YUV_MIRROR, width, height); FILE *yuvMirrorFile = fopen("/Users/staff/Desktop/rainbow-yuv420p-rotation-90-mirror.yuv", "wb"); fwrite(YUV_MIRROR, sizeof(YUV_MIRROR), 1, yuvMirrorFile); fclose(yuvMirrorFile); fclose(yuv420pFile); return 0; }
YUV 混合
[rainbow-yuv420p.yuv] -> [rainbow-yuv420p-blend.yuv]
#include <stdio.h> #include <stdint.h> #include <string.h> #include "libyuv.h" void blend(uint8_t *srcYuvData, uint8_t *dstYuvData, int width, int height) { uint8_t YUV_ROTATION[width*height*3/2]; I420Rotate( srcYuvData, width, srcYuvData+width*height, (width+1)/2, srcYuvData+width*height+((width+1)/2)*((height+1)/2), (width+1)/2, YUV_ROTATION, width, YUV_ROTATION+width*height, (width+1)/2, YUV_ROTATION+width*height+((width+1)/2)*((height+1)/2), (width+1)/2, width, height, kRotate90 ); // 透明度 uint8_t alpha[width*height]; memset(alpha, 0X88, width*height); I420Blend( srcYuvData, width, srcYuvData+width*height, (width+1)/2, srcYuvData+width*height+((width+1)/2)*((height+1)/2), (width+1)/2, YUV_ROTATION, width, YUV_ROTATION+width*height, (width+1)/2, YUV_ROTATION+width*height+((width+1)/2)*((height+1)/2), (width+1)/2, alpha, width, dstYuvData, width, dstYuvData+width*height, (width+1)/2, dstYuvData+width*height+((width+1)/2)*((height+1)/2), (width+1)/2, width, height ); } int main() { uint32_t width = 700, height = 700; uint8_t YUV[width*height*3/2]; uint8_t YUV_BLEND[width*height*3/2]; FILE *yuv420pFile = fopen("/Users/staff/Desktop/rainbow-yuv420p.yuv", "rb"); fread(YUV, sizeof(YUV), 1, yuv420pFile); blend(YUV, YUV_BLEND, width, height); FILE *yuvBlendFile = fopen("/Users/staff/Desktop/rainbow-yuv420p-blend.yuv", "wb"); fwrite(YUV_BLEND, sizeof(YUV_BLEND), 1, yuvBlendFile); fclose(yuvBlendFile); fclose(yuv420pFile); return 0; }
參考資料:
內容有誤?聯繫做者:
原文出處:https://www.cnblogs.com/binglingziyu/p/audio-video-basic-10-libyuv-usage.html