元々は、linuxでドライブレコーダーをつくる為に、
USBカメラから取り出したyuvデータをjpegにするために作成
もちろんvideo4linux2を使ってですよ
yuvそのままだと後々面倒なので、
yuvからjpegに変換するためにlibjpegを使いました。
しかし、yuv422 packedかyuv planer の関数がなかったので、
落ちていたソースを参考に作成
GRAY, YUV422Packed と YUV420Planerの関数です。
yuv422Packed は、そのままjpegにできる方法があるかわからなかったので、
YUVのデータをBGRデータをRGBデータにするがごとく、
下のようなyuyvyuyv から
[y00][u0][y01][v0]|[y10][u1][y11][v1]
yuvyuvyuvyuvを作成してます
[y00][u0][v0]|[y01][u0][v0]|
cinfo.in_color_space = JCS_YCbCr;
としている部分がキーでしょうか
以下、ソース
FILE *fp はjpegのファイルポインタ、 *image は yuv のイメージデータです。
#define WIDTH 640 #define HEIGHT 480 #define QUALITY 90 int grey_to_jpeg(FILE *fp, unsigned char *image) { int y, x, b; unsigned char *newimage = NULL; JSAMPROW row_ptr[1]; struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); // errors get written to stderr jpeg_create_compress (&cinfo); cinfo.image_width = WIDTH; cinfo.image_height = HEIGHT; cinfo.input_components = 1; jpeg_set_defaults (&cinfo); cinfo.in_color_space = JCS_GRAYSCALE; jpeg_set_colorspace(&cinfo, JCS_GRAYSCALE); jpeg_set_quality (&cinfo, QUALITY, TRUE); cinfo.dct_method = JDCT_FLOAT; jpeg_stdio_dest (&cinfo, fp); // data written to file jpeg_start_compress (&cinfo, TRUE); newimage = (unsigned char *)malloc( WIDTH * HEIGHT); memset( newimage, 0x00, WIDTH * HEIGHT); for( y = 0, x = 0; y < HEIGHT; y++, x += WIDTH) memcpy( &newimage[x], image + (WIDTH * (fmt.ystart + y) + fmt.xstart), WIDTH); row_ptr[0] = newimage; for( y = 0, b = 0; y < HEIGHT; y++) { jpeg_write_scanlines( &cinfo, row_ptr, 1); row_ptr[0] += WIDTH; } jpeg_finish_compress (&cinfo); jpeg_destroy_compress (&cinfo); free( newimage); return 0; } int yuv422_to_jpeg(FILE *fp, unsigned char *image) { unsigned long int i, j, k, x, y; unsigned char *line = NULL, *newimage = NULL; struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); // errors get written to stderr jpeg_create_compress (&cinfo); cinfo.image_width = WIDTH; cinfo.image_height = HEIGHT; cinfo.input_components = 3; cinfo.in_color_space = JCS_YCbCr; jpeg_set_defaults (&cinfo); jpeg_set_quality (&cinfo, QUALITY, TRUE); cinfo.dct_method = JDCT_FLOAT; jpeg_suppress_tables(&cinfo, TRUE); jpeg_stdio_dest (&cinfo, fp); // data written to file jpeg_start_compress (&cinfo, TRUE); newimage = (unsigned char *)malloc(WIDTH * HEIGHT * 3); for (j=0; j < HEIGHT; j++) { for( i = 0, k = 0; i < (WIDTH * 2); i += 4, k += 6) { newimage[j * WIDTH * 3 + k + 0] = image[j * WIDTH * 2 + i + 0]; newimage[j * WIDTH * 3 + k + 1] = image[j * WIDTH * 2 + i + 3]; newimage[j * WIDTH * 3 + k + 2] = image[j * WIDTH * 2 + i + 1]; newimage[j * WIDTH * 3 + k + 3] = image[j * WIDTH * 2 + i + 2]; newimage[j * WIDTH * 3 + k + 4] = image[j * WIDTH * 2 + i + 3]; newimage[j * WIDTH * 3 + k + 5] = image[j * WIDTH * 2 + i + 1]; } } newimage = (unsigned char *)malloc( HEIGHT * WIDTH * 3); memset( newimage, 0x00, HEIGHT * WIDTH * 3); for (j=0, line = newimage; j < HEIGHT; j++,line += 3 * WIDTH) jpeg_write_scanlines(&cinfo, &line, 1); free( newimage); jpeg_finish_compress (&cinfo); jpeg_destroy_compress (&cinfo); } int yuv420p_to_jpeg(FILE *fp, unsigned char *image, CIMG_FMT fmt) { int i,j; JSAMPROW y[16],cb[16],cr[16]; // y[2][5] = color sample of row 2 and pixel column 5; (one plane) JSAMPARRAY data[3]; // t[0][2][5] = color sample 0 of row 2 and column 5 struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; data[0] = y; data[1] = cb; data[2] = cr; cinfo.err = jpeg_std_error(&jerr); // errors get written to stderr jpeg_create_compress (&cinfo); cinfo.image_width = WIDTH; cinfo.image_height = HEIGHT; cinfo.input_components = 3; jpeg_set_defaults (&cinfo); jpeg_set_colorspace(&cinfo, JCS_YCbCr); cinfo.raw_data_in = TRUE; // supply downsampled data cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 2; cinfo.comp_info[1].h_samp_factor = 1; cinfo.comp_info[1].v_samp_factor = 1; cinfo.comp_info[2].h_samp_factor = 1; cinfo.comp_info[2].v_samp_factor = 1; jpeg_set_quality (&cinfo, QUALITY, TRUE); cinfo.dct_method = JDCT_FLOAT; jpeg_stdio_dest (&cinfo, fp); // data written to file jpeg_start_compress (&cinfo, TRUE); for (j=0;j < HEIGHT;j+=16) { for (i=0;i < 16;i++) { y[i] = image + WIDTH*(i+j); if (i%2 == 0) { cb[i/2] = image + WIDTH * HEIGHT + WIDTH/2*((i+j)/2); cr[i/2] = image + WIDTH * HEIGHT + WIDTH * HEIGHT/4 + WIDTH/2*((i+j)/2); } } jpeg_write_raw_data (&cinfo, data, 16); } jpeg_finish_compress (&cinfo); jpeg_destroy_compress (&cinfo); return 0; }
サンプルの69行目にある”yuvimage”は、いきなり出てきて1度だけ使われて
以後は出てませんが、どういう類のものでしょうか?
yuvimage でなく、newimage でした。すいません。
RGB から jpeg を作成する場合、
R[0]G[0]B[0]R[1]G[1]B[1]…R[HxW]G[HxW]B[HxW]
を作りますよね。
同じようにYCbCr でも
Y[0]Cb[0]Cr[0]Y[1]Cb[1]Cr[1]…Y[HxW]Cb[HxW]Cr[HxW]
を作っていけば jpeg を作れます。
そのためのメモリが yuvimage 改 newimage になります
ありがとうございました。
すっきりしました。