Scaling of NV12 format pictures based on libyuv library

tags: libyuv library  NV12 zoom

There are too few online tutorials on using the libyuv library to scale the NV12 format under Linux. It is simply a torment for the blogger, because my ability to read the source code is really poor! ! ! But no matter what, write down the income of the past few days, hoping to help everyone.

1. Introduction to libyuv library

libyuv is Google's open source library that realizes conversion, rotation, and scaling between various YUV and RGB. It is cross-platform, can be compiled and run on Windows, Linux, Mac, Android and other operating systems, x86, x64, arm architecture, and supports SIMD instruction acceleration such as SSE, AVX, and NEON.

Compile method (note that the gcc version must be above 4.8 for compilation), clone the libyuv library to the local warehouse, enter the libyuv directory, and compile:

git clone https://github.com/lemenkov/libyuv.git
cd libyuv
make -f linux.mk

A static library of libyuv.a will be generated in the current directory. I did not compile and install libyuv locally. Just extract the libyuv.a static library and include header files and run them separately (the required files are downloaded from the attachment).
Run make to generate an executable file. Execute the executable file to reduce the picture in NV12 format with 1920*1080 pixels to 1280*720.


2. Introduction to YUV420

Libyuv cannot directly scale images in NV12 format. You must first convert NV12 to I420 (the memory distribution format is the same as YV12). In fact, NV12 and YV12 belong to YUV420, but the memory distribution of UV components is different. Let's first understand the difference between the two. Without further ado, the picture above (pay attention to the memory distribution of the UV component, YV12 is stored sequentially in each of the three components of YUV, while the UV component of NV12 is stored interleaved):

In fact, for this conversion based on the libyuv library, the memory distribution of the following YV12 is more correct (the red box is the Y component, the blue is the U component, and the yellow box is the V component. Note that this is for the specified YUV components The memory range is very important!!! For example: For a picture with YV12 pixels of WxH, the Y component is W and the UV is W/2):

That's it for basic knowledge.


3. The program realizes the reduction of NV12 format pictures

Implementation algorithm: use libyuv::NV12ToI420() function of libyuv library to convert NV12 to I420, then use libyuv::I420Scale() function to reduce I420 from pixel 1920*1080 to 1280*720, and finally use libyuv::I420ToNV12() Convert function back to NV12 format

#include <stdio.h>
#include <stdlib.h>
#include "libyuv.h"

int NV12Scale(uint8 *psrc_buf, int psrc_w, int psrc_h, uint8 *pdst_buf, int pdst_w, int pdst_h, libyuv::FilterModeEnum pfmode);

int main(int argc, const char *argv[])
{
    const int src_w = 1920;
    const int src_h = 1080;
    const int dst_w = 1280;
    const int dst_h =  720;

    libyuv::FilterModeEnum fmode = libyuv::kFilterNone;

    char inputPathname[30]  = "videotestsrc_1920x1080.nv12";
    char outputPathname[30] = "videotestdst_1280x720.nv12";

    FILE * fin  = fopen(inputPathname,  "rb");
    FILE * fout = fopen(outputPathname, "wb+");

    /* Allocate memory for nv12 */
    uint8 *src_buf = (uint8 *)malloc((src_w * src_h * 3) >> 1);
    uint8 *dst_buf = (uint8 *)malloc((dst_w * dst_h * 3) >> 1);

    /* Read file data to buffer */
    fread(src_buf, sizeof(uint8), (src_w * src_h * 3) >> 1, fin);

    /* Scale NV12 */
    NV12Scale(src_buf, src_w, src_h, dst_buf, dst_w, dst_h, fmode);

    /* Write the data to file */
    fwrite(dst_buf, sizeof(uint8), (dst_w * dst_h * 3) >> 1, fout);

    free(src_buf);
    free(dst_buf);

    fclose(fin);
    fclose(fout);

    return 0;
}

int NV12Scale(uint8 *psrc_buf, int psrc_w, int psrc_h, uint8 *pdst_buf, int pdst_w, int pdst_h, libyuv::FilterModeEnum pfmode)
{
    uint8 *i420_buf1 = (uint8 *)malloc((psrc_w * psrc_h * 3) >> 1);
    uint8 *i420_buf2 = (uint8 *)malloc((pdst_w * pdst_h * 3) >> 1);

    /* NV12_1920x1080 -> I420_1920x1080 */
    libyuv::NV12ToI420(&psrc_buf[0],                           psrc_w,
                       &psrc_buf[psrc_w * psrc_h],             psrc_w,
                       &i420_buf1[0],                          psrc_w,
                       &i420_buf1[psrc_w * psrc_h],            psrc_w >> 1,
                       &i420_buf1[(psrc_w * psrc_h * 5) >> 2], psrc_w >> 1,
                       psrc_w, psrc_h);

    /* I420_1920x1080 -> I420_1280x720 */
    libyuv::I420Scale(&i420_buf1[0],                          psrc_w,
                      &i420_buf1[psrc_w * psrc_h],            psrc_w >> 1,
                      &i420_buf1[(psrc_w * psrc_h * 5) >> 2], psrc_w >> 1,
                      psrc_w, psrc_h,
                      &i420_buf2[0],                          pdst_w,
                      &i420_buf2[pdst_w * pdst_h],            pdst_w >> 1,
                      &i420_buf2[(pdst_w * pdst_h * 5) >> 2], pdst_w >> 1,
                      pdst_w, pdst_h,
                      pfmode);

    /* I420_1280x720 -> NV12_1280x720 */
    libyuv::I420ToNV12(&i420_buf2[0],                          pdst_w,
                       &i420_buf2[pdst_w * pdst_h],            pdst_w >> 1,
                       &i420_buf2[(pdst_w * pdst_h * 5) >> 2], pdst_w >> 1,
                       &pdst_buf[0],                           pdst_w,
                       &pdst_buf[pdst_w * pdst_h],             pdst_w,
                       pdst_w,pdst_h);

    free(i420_buf1);
    free(i420_buf2);

    return 0;
}

4. Accessories

Program, test NV12 file and libyuv static library and header file.

yuv viewer (yvplayer).


5. NV12 plus rectangular box effect

If you want to know about the effect of adding rectangular boxes on NV12 format pictures, you can read my other blog post.
Set the rectangular border of nv12

Intelligent Recommendation

RGBA, YUV color format and the use of libyuv

Recently, because of work needs, libyuv has to be used. Because when I wrote and recorded the video before, I also used rgb to yuv. I made a realization based on the information on the Internet. I rec...

Convert jpg pictures to yuv420 (nv12) data file

Code function: Convert all JPG files under the folder into YuV files of the same name. The yuv file is the data bit of the yuv420 (NV12) format. The file content is yyyyyyyyyy ... uvuvuv ......

YUV image format conversion: YUYV to NV12 (YUV420SP)

  First confirm the sampling format of YUYV and NV12, YUYV belongs to YUV4:2:2 sampling, and NV12 belongs to YUV4:2:0 sampling. The sampling method is shown below:       ...

The difference of video image format NV21-NV12-YUV420P

YUV420p: also called planer plane mode, Y, U, V are on different planes, that is, three planes YUV420sp, called two-planer, Y is a plane, and UV is stored in the same plane.   NV12 format: ios mo...

More Recommendation

Automatic scaling of pictures (img)

I recently used this for public welfare projects. According to the automatic scaling of the parent container, and maintain the original proportion of the picture. So you can set the size of the parent...

Qt realizes the scaling of pictures

demand demand analysis Code Override paintEvent Code analysis Rewrite wheelEventQWheelEvent event Code analysis demand Seen while chatting I think the picture zoom control is more useful, so I decided...

Scaling of BMP pictures

Readbmp reads BMP file SaveBMP Save the scaled BMP file Other bloggers from ReadBMP Savebmp ImageStretch performs zoom operation on BMP files main transmission of BMP file path Effect:   Reduce a...

Preliminary Study on YUV Format (1)---Two Ways of NV12 Format to RGB24

The latest NV12 format that requires ffmpeg to hard decode the video is converted to RGB24 by operating the pixel instead of using the sws_getContext function. Two methods were found online, the tests...

Copyright  DMCA © 2018-2026 - All Rights Reserved - www.programmersought.com  User Notice

Top