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\n", 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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM