In the previous blog, it was written that the conversion code in pure C language can only be converted under linux (ubuntu16.04)
Link: http://www.cnblogs.com/zhq-blog/p/8832157.html
But now it needs to be executed on the arm board, emmmmm...
I found the following information on the Internet, there are those using ffmpeg, libjpeg, libjpeg-trubo
Here is libjpeg to implement
The first is to cross-compile the libjpeg library on Linux
Here is a reference to a blog (pro-test available):
https://blog.csdn.net/lihui126/article/details/43057147
Then copy the compiled dynamic link library to the arm board
After the compilation environment is installed, the conversion program for libjpeg must be written.
This is also a reference to a blog:
https://blog.csdn.net/yixianfeng41/article/details/52181578
It mainly uses the function yuv420p_to_jpeg() inside
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 }
Explain the meaning of some parameters:
filename -- the name of the output file (see clearly, it is the output!!! That is xxx.jpg )
pData -- the data of the input file ( in yuv420sp format !! Don't be fooled by the function name!!!)
Since the pictures I took are in yuv420 format, the above function cannot be used directly
There are two options to choose from:
1. Select the yuv420p_to_yuv420sp() function in the blog above to perform format conversion, and then call the yuv420p_to_jpeg() function
2. It is to modify the way of reading data inside the yuv420p_to_jpeg() function (modified from the original yuv420sp format to yuv420p format)
Since I am very lazy, I chose the first option:
But when using the yuv420p_to_yuv420sp() function in the above blog, I found that there is a problem with the conversion process
The original code was:
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
The values of m and n above are wrong, because for YUV420SP and YUV420P, the previous Y data is the same, so it can be directly assigned through the previous loop
However, when modifying the sequence of UV format data later, according to the above writing method, m=0, n=0 at the beginning, so yuv420p[0] needs to be assigned, but yuv420p[0] is obviously the data of the Y part, and cannot be assigned for UV
Therefore, this part of the code needs to be modified as follows:
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 }
After this modification, there is no problem
Then add #include <jpeglib.h> in the main function file, remember to add the -ljpeg parameter at the end when compiling
You can convert data files in YUV420p format
Note:
Because the executable file cannot be executed on the arm board I use (even the ordinary helloworld program cannot be executed after cross-compiling)
So I used the -static parameter to compile statically when compiling
But I encountered a problem in static compilation: arm-none-linux-gnueabi/bin/ld: cannot find -ljpeg collect2: ld returned 1 exit status (not during dynamic compilation)
This problem is actually due to the fact that there is no static link library file libjpeg.a that contains the libjpeg library in the cross-compiled path.
Copy the static link library libjpeg.a you compiled to the lib directory of arm-none-linux-gcc and then perform static compilation again.
The code has been uploaded to github (including complete code and test files), the link is as follows:
https://github.com/quinncy/yuv2jpg_linux_libjpeg