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

原文地址:https://www.cnblogs.com/zhq-blog/p/8858293.html