• libjpeg实现arm板上yuv420p转jpg


    前面一个博客中写到用纯c语言的转换代码只能在linux(ubuntu16.04)下面完成转换

    链接:http://www.cnblogs.com/zhq-blog/p/8832157.html

    但是现在又需要在arm板上面执行,emmmm···

    在网上查找了下资料,有使用ffmpeg,libjpeg,libjpeg-trubo的

    这里选用的是libjpeg来进行实现

    首先就是在Linux上面进行libjpeg库的交叉编译

    这里是参考了一个博客(亲测可用):

    https://blog.csdn.net/lihui126/article/details/43057147

    然后将编译完成的动态链接库拷贝到arm板上

    搭载好编译环境之后,然后就要编写libjpeg的转换程序了

    这个也是参考了一篇博客:

    https://blog.csdn.net/yixianfeng41/article/details/52181578

    主要是利用了里面的yuv420p_to_jpeg()这个函数

     1 int yuv420p_to_jpeg(const char * filename, const char* pdata,int image_width,int image_height, int quality)  
     2 {     
     3     struct jpeg_compress_struct cinfo;    
     4     struct jpeg_error_mgr jerr;    
     5     cinfo.err = jpeg_std_error(&jerr);    
     6     jpeg_create_compress(&cinfo);    
     7   
     8     FILE * outfile;    // target file    
     9     if ((outfile = fopen(filename, "wb")) == NULL) {    
    10         fprintf(stderr, "can't open %s
    ", filename);    
    11         exit(1);    
    12     }    
    13     jpeg_stdio_dest(&cinfo, outfile);    
    14   
    15     cinfo.image_width = image_width;  // image width and height, in pixels    
    16     cinfo.image_height = image_height;    
    17     cinfo.input_components = 3;    // # of color components per pixel    
    18     cinfo.in_color_space = JCS_YCbCr;  //colorspace of input image    
    19     jpeg_set_defaults(&cinfo);    
    20     jpeg_set_quality(&cinfo, quality, TRUE );    
    21   
    22     //////////////////////////////    
    23     //  cinfo.raw_data_in = TRUE;    
    24     cinfo.jpeg_color_space = JCS_YCbCr;    
    25     cinfo.comp_info[0].h_samp_factor = 2;    
    26     cinfo.comp_info[0].v_samp_factor = 2;    
    27     /////////////////////////    
    28   
    29     jpeg_start_compress(&cinfo, TRUE);    
    30   
    31     JSAMPROW row_pointer[1];  
    32   
    33     unsigned char *yuvbuf;  
    34     if((yuvbuf=(unsigned char *)malloc(image_width*3))!=NULL)  
    35         memset(yuvbuf,0,image_width*3);  
    36   
    37     unsigned char *ybase,*ubase;  
    38     ybase=pdata;  
    39     ubase=pdata+image_width*image_height;    
    40     int j=0;  
    41     while (cinfo.next_scanline < cinfo.image_height)   
    42     {  
    43         int idx=0;  
    44         for(int i=0;i<image_width;i++)  
    45         {   
    46             yuvbuf[idx++]=ybase[i + j * image_width];  
    47             yuvbuf[idx++]=ubase[j/2 * image_width+(i/2)*2];  
    48             yuvbuf[idx++]=ubase[j/2 * image_width+(i/2)*2+1];      
    49         }  
    50         row_pointer[0] = yuvbuf;  
    51         jpeg_write_scanlines(&cinfo, row_pointer, 1);  
    52         j++;  
    53     }  
    54     jpeg_finish_compress(&cinfo);    
    55     jpeg_destroy_compress(&cinfo);    
    56     fclose(outfile);    
    57     return 0;    
    58 }  

    解释一下部分参数的含义:

    filename -- 输出文件的名字(看清楚,是输出!!!也就是xxx.jpg

    pData -- 输入文件的数据(yuv420sp格式的!!别被函数名迷惑了!!!)

    由于我拍摄的图片是yuv420格式的,不能直接利用上面那个函数

    有两种方案可以选择:

    1.选择上面博客中的yuv420p_to_yuv420sp()函数来进行格式转换后,再调用yuv420p_to_jpeg()这个函数

    2.就是在yuv420p_to_jpeg()这个函数内部修改读取数据的方式(由原来的yuv420sp格式修改为yuv420p格式)

    鉴于本人特别懒,因此选用了第一种方案:

    但是在使用上面博客中的yuv420p_to_yuv420sp()这个函数时,发现转换过程有问题

    原来的代码是:

     1 int yuv420p_to_yuv420sp(unsigned char * yuv420p,unsigned char* yuv420sp,int width,int height)  
     2 {  
     3     if(yuv420p==NULL)  
     4         return;  
     5     int i=0,j=0;  
     6     //Y  
     7     for(i=0;i<width*height;i++)  
     8     {  
     9         yuv420sp[i]=yuv420p[i];  
    10     }  
    11   
    12     int m=0,n=0;  
    13     for(int j=0;j<width*height/2;j++)  
    14     {  
    15         if(j%2==0)  
    16            yuv420sp[j+width*height]=yuv420p[m++];  
    17         else  
    18            yuv420sp[j+width*height]=yuv420p[n++];  
    19     }  
    20 }  

                YUV420SP                                  YUV420P

    上面的m和n的取值不对,因为对于YUV420SP和YUV420P来说,前面Y的数据都是相同的,所以可以通过前面一个循环直接赋值

    但是后面在修改UV格式数据的顺序时,按照上面的写法,一开始m=0,n=0,因此需要把yuv420p[0]赋值,但是yuv420p[0]明显是Y部分的数据,不可以赋值给UV的

    因此需要修改该部分代码如下:

     1     int yuv420p_to_yuv420sp(unsigned char * yuv420p,unsigned char* yuv420sp,int width,int height)  
     2     {  
     3         if(yuv420p==NULL)  
     4             return 0;  
     5         int i=0,j=0;  
     6         //Y  
     7         for(i=0;i<width*height;i++)  
     8         {  
     9             yuv420sp[i]=yuv420p[i];  
    10         }  
    11       
    12         int m=0,n=0;  
    13         for(j=0;j<width*height/2;j++)  
    14         {  
    15             if(j%2==0)  
    16           {
    17                  yuv420sp[j+width*height]=yuv420p[width*height+m];  
    18               m++;
    19           }
    20             else 
    21           {
    22                    yuv420sp[j+width*height]=yuv420p[width*height*5/4+n];  
    23                 n++;
    24           } 
    25         }  
    26     } 

    这样修改后就没有问题了

    然后在主函数文件里面添加#include <jpeglib.h>,编译的时候记得最后加上-ljpeg参数

    就可以对YUV420p格式的数据文件进行转换了

    注:

    由于我使用的arm板上面不能执行可执行文件(连普通的helloworld程序交叉编译后都不能执行)

    因此我在编译的时候使用了-static参数进行静态编译

    但是在静态编译遇到了问题:arm-none-linux-gnueabi/bin/ld: cannot find -ljpeg collect2: ld returned 1 exit status(动态编译的时候没有)

    这个问题其实是由于在交叉编译的路径里面没有包含libjpeg库的静态链接库文件libjpeg.a

    将你编译生成的静态链接库libjpeg.a拷贝到arm-none-linux-gcc的lib目录下就再次进行静态编译就可以了

    代码已经上传到github上面(包含完整代码以及测试文件),链接如下:

    https://github.com/quinncy/yuv2jpg_linux_libjpeg

  • 相关阅读:
    Keyboarding题解
    埃及分数 解题报告
    小木棍加强版解题报告
    扩展欧几里得
    luoguP4999 烦人的数学作业
    中国剩余定理
    20201115gryz模拟赛解题报告
    扩展欧几里得算法
    斐蜀定理
    CSP2020-S游记
  • 原文地址:https://www.cnblogs.com/zhq-blog/p/8858293.html
Copyright © 2020-2023  润新知