1 /*
2 * Copyright (c) 2014 Intel Corporation. All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sub license, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
14 * of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
19 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
20 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24 /*
25 * Simple JPEG encoder based on libVA.
26 *
27 * Usage:
28 * ./jpegenc <width> <height> <input file> <output file> <input filetype 0(I420)/1(NV12)/2(UYVY)/3(YUY2)/4(Y8)/5(RGBA)> q <quality>
29 * Currently supporting only I420/NV12/UYVY/YUY2/Y8 input file formats.
30 *
31 * NOTE: The intel-driver expects a packed header sent to it. So, the app is responsible to pack the header
32 * and send to the driver through LibVA. This unit test also showcases how to send the header to the driver.
33 */
34
35 #include <stdio.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <getopt.h>
39 #include <unistd.h>
40
41 #include <sys/time.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include <assert.h>
46 #include <time.h>
47
48 #include <pthread.h>
49
50 #include <va/va.h>
51 #include <va/va_enc_jpeg.h>
52 #include "va_display.h"
53 #include "jpegenc_utils.h"
54
55 #ifndef VA_FOURCC_I420
56 #define VA_FOURCC_I420 0x30323449
57 #endif
58
59 #define CHECK_VASTATUS(va_status,func) \
60 if (va_status != VA_STATUS_SUCCESS) { \
61 fprintf(stderr,"%s:%s (%d) failed,exit\n", __func__, func, __LINE__); \
62 exit(1); \
63 }
64
65
show_help()66 void show_help()
67 {
68 printf("Usage: ./jpegenc <width> <height> <input file> <output file> <fourcc value 0(I420)/1(NV12)/2(UYVY)/3(YUY2)/4(Y8)/5(RGBA)> q <quality>\n");
69 printf("Currently supporting only I420/NV12/UYVY/YUY2/Y8 input file formats.\n");
70 printf("Example: ./jpegenc 1024 768 input_file.yuv output.jpeg 0 50\n\n");
71 return;
72 }
73
74
jpegenc_pic_param_init(VAEncPictureParameterBufferJPEG * pic_param,int width,int height,int quality,YUVComponentSpecs yuvComp)75 void jpegenc_pic_param_init(VAEncPictureParameterBufferJPEG *pic_param, int width, int height, int quality, YUVComponentSpecs yuvComp)
76 {
77 assert(pic_param);
78
79 pic_param->picture_width = width;
80 pic_param->picture_height = height;
81 pic_param->quality = quality;
82
83 pic_param->pic_flags.bits.profile = 0; //Profile = Baseline
84 pic_param->pic_flags.bits.progressive = 0; //Sequential encoding
85 pic_param->pic_flags.bits.huffman = 1; //Uses Huffman coding
86 pic_param->pic_flags.bits.interleaved = 0; //Input format is interleaved (YUV)
87 pic_param->pic_flags.bits.differential = 0; //non-Differential Encoding
88
89 pic_param->sample_bit_depth = 8; //only 8 bit sample depth is currently supported
90 pic_param->num_scan = 1;
91 pic_param->num_components = yuvComp.num_components; // Supporting only upto 3 components maximum
92 //set component_id Ci and Tqi
93 if (yuvComp.fourcc_val == VA_FOURCC_Y800) {
94 pic_param->component_id[0] = 0;
95 pic_param->quantiser_table_selector[0] = 0;
96 } else {
97 pic_param->component_id[0] = pic_param->quantiser_table_selector[0] = 0;
98 pic_param->component_id[1] = pic_param->quantiser_table_selector[1] = 1;
99 pic_param->component_id[2] = 2;
100 pic_param->quantiser_table_selector[2] = 1;
101 }
102
103 pic_param->quality = quality;
104 }
105
jpegenc_qmatrix_init(VAQMatrixBufferJPEG * quantization_param,YUVComponentSpecs yuvComp)106 void jpegenc_qmatrix_init(VAQMatrixBufferJPEG *quantization_param, YUVComponentSpecs yuvComp)
107 {
108 int i = 0;
109 quantization_param->load_lum_quantiser_matrix = 1;
110
111 //LibVA expects the QM in zigzag order
112 for (i = 0; i < NUM_QUANT_ELEMENTS; i++) {
113 quantization_param->lum_quantiser_matrix[i] = jpeg_luma_quant[jpeg_zigzag[i]];
114 }
115
116
117 if (yuvComp.fourcc_val == VA_FOURCC_Y800) {
118 quantization_param->load_chroma_quantiser_matrix = 0;
119 } else {
120 quantization_param->load_chroma_quantiser_matrix = 1;
121 for (i = 0; i < NUM_QUANT_ELEMENTS; i++) {
122 quantization_param->chroma_quantiser_matrix[i] = jpeg_chroma_quant[jpeg_zigzag[i]];
123 }
124 }
125
126 }
127
jpegenc_hufftable_init(VAHuffmanTableBufferJPEGBaseline * hufftable_param,YUVComponentSpecs yuvComp)128 void jpegenc_hufftable_init(VAHuffmanTableBufferJPEGBaseline *hufftable_param, YUVComponentSpecs yuvComp)
129 {
130
131 hufftable_param->load_huffman_table[0] = 1; //Load Luma Hufftable
132 if (yuvComp.fourcc_val == VA_FOURCC_Y800) {
133 hufftable_param->load_huffman_table[1] = 0; //Do not load Chroma Hufftable for Y8
134 } else {
135 hufftable_param->load_huffman_table[1] = 1; //Load Chroma Hufftable for other formats
136 }
137
138 //Load Luma hufftable values
139 //Load DC codes
140 memcpy(hufftable_param->huffman_table[0].num_dc_codes, jpeg_hufftable_luma_dc + 1, 16);
141 //Load DC Values
142 memcpy(hufftable_param->huffman_table[0].dc_values, jpeg_hufftable_luma_dc + 17, 12);
143 //Load AC codes
144 memcpy(hufftable_param->huffman_table[0].num_ac_codes, jpeg_hufftable_luma_ac + 1, 16);
145 //Load AC Values
146 memcpy(hufftable_param->huffman_table[0].ac_values, jpeg_hufftable_luma_ac + 17, 162);
147 memset(hufftable_param->huffman_table[0].pad, 0, 2);
148
149
150 //Load Chroma hufftable values if needed
151 if (yuvComp.fourcc_val != VA_FOURCC_Y800) {
152 //Load DC codes
153 memcpy(hufftable_param->huffman_table[1].num_dc_codes, jpeg_hufftable_chroma_dc + 1, 16);
154 //Load DC Values
155 memcpy(hufftable_param->huffman_table[1].dc_values, jpeg_hufftable_chroma_dc + 17, 12);
156 //Load AC codes
157 memcpy(hufftable_param->huffman_table[1].num_ac_codes, jpeg_hufftable_chroma_ac + 1, 16);
158 //Load AC Values
159 memcpy(hufftable_param->huffman_table[1].ac_values, jpeg_hufftable_chroma_ac + 17, 162);
160 memset(hufftable_param->huffman_table[1].pad, 0, 2);
161
162 }
163
164 }
165
jpegenc_slice_param_init(VAEncSliceParameterBufferJPEG * slice_param,YUVComponentSpecs yuvComp)166 void jpegenc_slice_param_init(VAEncSliceParameterBufferJPEG *slice_param, YUVComponentSpecs yuvComp)
167 {
168 slice_param->restart_interval = 0;
169
170 slice_param->num_components = yuvComp.num_components;
171
172 slice_param->components[0].component_selector = 1;
173 slice_param->components[0].dc_table_selector = 0;
174 slice_param->components[0].ac_table_selector = 0;
175
176 if (yuvComp.num_components > 1) {
177 slice_param->components[1].component_selector = 2;
178 slice_param->components[1].dc_table_selector = 1;
179 slice_param->components[1].ac_table_selector = 1;
180
181 slice_param->components[2].component_selector = 3;
182 slice_param->components[2].dc_table_selector = 1;
183 slice_param->components[2].ac_table_selector = 1;
184 }
185 }
186
187
populate_quantdata(JPEGQuantSection * quantVal,int type)188 void populate_quantdata(JPEGQuantSection *quantVal, int type)
189 {
190 uint8_t zigzag_qm[NUM_QUANT_ELEMENTS];
191 int i;
192
193 quantVal->DQT = DQT;
194 quantVal->Pq = 0;
195 quantVal->Tq = type;
196 if (type == 0) {
197 for (i = 0; i < NUM_QUANT_ELEMENTS; i++) {
198 zigzag_qm[i] = jpeg_luma_quant[jpeg_zigzag[i]];
199 }
200
201 memcpy(quantVal->Qk, zigzag_qm, NUM_QUANT_ELEMENTS);
202 } else {
203 for (i = 0; i < NUM_QUANT_ELEMENTS; i++) {
204 zigzag_qm[i] = jpeg_chroma_quant[jpeg_zigzag[i]];
205 }
206 memcpy(quantVal->Qk, zigzag_qm, NUM_QUANT_ELEMENTS);
207 }
208 quantVal->Lq = 3 + NUM_QUANT_ELEMENTS;
209 }
210
populate_frame_header(JPEGFrameHeader * frameHdr,YUVComponentSpecs yuvComp,int picture_width,int picture_height)211 void populate_frame_header(JPEGFrameHeader *frameHdr, YUVComponentSpecs yuvComp, int picture_width, int picture_height)
212 {
213 int i = 0;
214
215 frameHdr->SOF = SOF0;
216 frameHdr->Lf = 8 + (3 * yuvComp.num_components); //Size of FrameHeader in bytes without the Marker SOF
217 frameHdr->P = 8;
218 frameHdr->Y = picture_height;
219 frameHdr->X = picture_width;
220 frameHdr->Nf = yuvComp.num_components;
221
222 for (i = 0; i < yuvComp.num_components; i++) {
223 frameHdr->JPEGComponent[i].Ci = i + 1;
224
225 if (i == 0) {
226 frameHdr->JPEGComponent[i].Hi = yuvComp.y_h_subsample;
227 frameHdr->JPEGComponent[i].Vi = yuvComp.y_v_subsample;
228 frameHdr->JPEGComponent[i].Tqi = 0;
229
230 } else {
231 //Analyzing the sampling factors for U/V, they are 1 for all formats except for Y8.
232 //So, it is okay to have the code below like this. For Y8, we wont reach this code.
233 frameHdr->JPEGComponent[i].Hi = yuvComp.u_h_subsample;
234 frameHdr->JPEGComponent[i].Vi = yuvComp.u_v_subsample;
235 frameHdr->JPEGComponent[i].Tqi = 1;
236 }
237 }
238 }
239
populate_huff_section_header(JPEGHuffSection * huffSectionHdr,int th,int tc)240 void populate_huff_section_header(JPEGHuffSection *huffSectionHdr, int th, int tc)
241 {
242 int i = 0, totalCodeWords = 0;
243
244 huffSectionHdr->DHT = DHT;
245 huffSectionHdr->Tc = tc;
246 huffSectionHdr->Th = th;
247
248 if (th == 0) { //If Luma
249
250 //If AC
251 if (tc == 1) {
252 memcpy(huffSectionHdr->Li, jpeg_hufftable_luma_ac + 1, NUM_AC_RUN_SIZE_BITS);
253 memcpy(huffSectionHdr->Vij, jpeg_hufftable_luma_ac + 17, NUM_AC_CODE_WORDS_HUFFVAL);
254 }
255
256 //If DC
257 if (tc == 0) {
258 memcpy(huffSectionHdr->Li, jpeg_hufftable_luma_dc + 1, NUM_DC_RUN_SIZE_BITS);
259 memcpy(huffSectionHdr->Vij, jpeg_hufftable_luma_dc + 17, NUM_DC_CODE_WORDS_HUFFVAL);
260 }
261
262 for (i = 0; i < NUM_AC_RUN_SIZE_BITS; i++) {
263 totalCodeWords += huffSectionHdr->Li[i];
264 }
265
266 huffSectionHdr->Lh = 3 + 16 + totalCodeWords;
267
268 } else { //If Chroma
269 //If AC
270 if (tc == 1) {
271 memcpy(huffSectionHdr->Li, jpeg_hufftable_chroma_ac + 1, NUM_AC_RUN_SIZE_BITS);
272 memcpy(huffSectionHdr->Vij, jpeg_hufftable_chroma_ac + 17, NUM_AC_CODE_WORDS_HUFFVAL);
273 }
274
275 //If DC
276 if (tc == 0) {
277 memcpy(huffSectionHdr->Li, jpeg_hufftable_chroma_dc + 1, NUM_DC_RUN_SIZE_BITS);
278 memcpy(huffSectionHdr->Vij, jpeg_hufftable_chroma_dc + 17, NUM_DC_CODE_WORDS_HUFFVAL);
279 }
280
281 }
282 }
283
populate_scan_header(JPEGScanHeader * scanHdr,YUVComponentSpecs yuvComp)284 void populate_scan_header(JPEGScanHeader *scanHdr, YUVComponentSpecs yuvComp)
285 {
286
287 scanHdr->SOS = SOS;
288 scanHdr->Ns = yuvComp.num_components;
289
290 //Y Component
291 scanHdr->ScanComponent[0].Csj = 1;
292 scanHdr->ScanComponent[0].Tdj = 0;
293 scanHdr->ScanComponent[0].Taj = 0;
294
295 if (yuvComp.num_components > 1) {
296 //U Component
297 scanHdr->ScanComponent[1].Csj = 2;
298 scanHdr->ScanComponent[1].Tdj = 1;
299 scanHdr->ScanComponent[1].Taj = 1;
300
301 //V Component
302 scanHdr->ScanComponent[2].Csj = 3;
303 scanHdr->ScanComponent[2].Tdj = 1;
304 scanHdr->ScanComponent[2].Taj = 1;
305 }
306
307 scanHdr->Ss = 0; //0 for Baseline
308 scanHdr->Se = 63; //63 for Baseline
309 scanHdr->Ah = 0; //0 for Baseline
310 scanHdr->Al = 0; //0 for Baseline
311
312 scanHdr->Ls = 3 + (yuvComp.num_components * 2) + 3;
313
314 }
315
316 // This method packs the header information which is to be sent to the driver through LibVA.
317 // All the information that needs to be inserted in the encoded buffer should be built and sent.
318 // It is the responsibility of the app talking to LibVA to build this header and send it.
319 // This includes Markers, Quantization tables (normalized with quality factor), Huffman tables,etc.
build_packed_jpeg_header_buffer(unsigned char ** header_buffer,YUVComponentSpecs yuvComp,int picture_width,int picture_height,uint16_t restart_interval,int quality)320 int build_packed_jpeg_header_buffer(unsigned char **header_buffer, YUVComponentSpecs yuvComp, int picture_width, int picture_height, uint16_t restart_interval, int quality)
321 {
322 bitstream bs;
323 int i = 0, j = 0;
324 uint32_t temp = 0;
325
326 bitstream_start(&bs);
327
328 //Add SOI
329 bitstream_put_ui(&bs, SOI, 16);
330
331 //Add AppData
332 bitstream_put_ui(&bs, APP0, 16); //APP0 marker
333 bitstream_put_ui(&bs, 16, 16); //Length excluding the marker
334 bitstream_put_ui(&bs, 0x4A, 8); //J
335 bitstream_put_ui(&bs, 0x46, 8); //F
336 bitstream_put_ui(&bs, 0x49, 8); //I
337 bitstream_put_ui(&bs, 0x46, 8); //F
338 bitstream_put_ui(&bs, 0x00, 8); //0
339 bitstream_put_ui(&bs, 1, 8); //Major Version
340 bitstream_put_ui(&bs, 1, 8); //Minor Version
341 bitstream_put_ui(&bs, 1, 8); //Density units 0:no units, 1:pixels per inch, 2: pixels per cm
342 bitstream_put_ui(&bs, 72, 16); //X density
343 bitstream_put_ui(&bs, 72, 16); //Y density
344 bitstream_put_ui(&bs, 0, 8); //Thumbnail width
345 bitstream_put_ui(&bs, 0, 8); //Thumbnail height
346
347 // Regarding Quantization matrices: As per JPEG Spec ISO/IEC 10918-1:1993(E), Pg-19:
348 // "applications may specify values which customize picture quality for their particular
349 // image characteristics, display devices, and viewing conditions"
350
351
352 //Normalization of quality factor
353 quality = (quality < 50) ? (5000 / quality) : (200 - (quality * 2));
354
355 //Add QTable - Y
356 JPEGQuantSection quantLuma;
357 populate_quantdata(&quantLuma, 0);
358
359 bitstream_put_ui(&bs, quantLuma.DQT, 16);
360 bitstream_put_ui(&bs, quantLuma.Lq, 16);
361 bitstream_put_ui(&bs, quantLuma.Pq, 4);
362 bitstream_put_ui(&bs, quantLuma.Tq, 4);
363 for (i = 0; i < NUM_QUANT_ELEMENTS; i++) {
364 //scale the quantization table with quality factor
365 temp = (quantLuma.Qk[i] * quality) / 100;
366 //clamp to range [1,255]
367 temp = (temp > 255) ? 255 : temp;
368 temp = (temp < 1) ? 1 : temp;
369 quantLuma.Qk[i] = (unsigned char)temp;
370 bitstream_put_ui(&bs, quantLuma.Qk[i], 8);
371 }
372
373 //Add QTable - U/V
374 if (yuvComp.fourcc_val != VA_FOURCC_Y800) {
375 JPEGQuantSection quantChroma;
376 populate_quantdata(&quantChroma, 1);
377
378 bitstream_put_ui(&bs, quantChroma.DQT, 16);
379 bitstream_put_ui(&bs, quantChroma.Lq, 16);
380 bitstream_put_ui(&bs, quantChroma.Pq, 4);
381 bitstream_put_ui(&bs, quantChroma.Tq, 4);
382 for (i = 0; i < NUM_QUANT_ELEMENTS; i++) {
383 //scale the quantization table with quality factor
384 temp = (quantChroma.Qk[i] * quality) / 100;
385 //clamp to range [1,255]
386 temp = (temp > 255) ? 255 : temp;
387 temp = (temp < 1) ? 1 : temp;
388 quantChroma.Qk[i] = (unsigned char)temp;
389 bitstream_put_ui(&bs, quantChroma.Qk[i], 8);
390 }
391 }
392
393 //Add FrameHeader
394 JPEGFrameHeader frameHdr;
395 memset(&frameHdr, 0, sizeof(JPEGFrameHeader));
396 populate_frame_header(&frameHdr, yuvComp, picture_width, picture_height);
397
398 bitstream_put_ui(&bs, frameHdr.SOF, 16);
399 bitstream_put_ui(&bs, frameHdr.Lf, 16);
400 bitstream_put_ui(&bs, frameHdr.P, 8);
401 bitstream_put_ui(&bs, frameHdr.Y, 16);
402 bitstream_put_ui(&bs, frameHdr.X, 16);
403 bitstream_put_ui(&bs, frameHdr.Nf, 8);
404 for (i = 0; i < frameHdr.Nf; i++) {
405 bitstream_put_ui(&bs, frameHdr.JPEGComponent[i].Ci, 8);
406 bitstream_put_ui(&bs, frameHdr.JPEGComponent[i].Hi, 4);
407 bitstream_put_ui(&bs, frameHdr.JPEGComponent[i].Vi, 4);
408 bitstream_put_ui(&bs, frameHdr.JPEGComponent[i].Tqi, 8);
409 }
410
411 //Add HuffTable AC and DC for Y,U/V components
412 JPEGHuffSection acHuffSectionHdr, dcHuffSectionHdr;
413
414 for (i = 0; (i < yuvComp.num_components && (i <= 1)); i++) {
415 //Add DC component (Tc = 0)
416 populate_huff_section_header(&dcHuffSectionHdr, i, 0);
417
418 bitstream_put_ui(&bs, dcHuffSectionHdr.DHT, 16);
419 bitstream_put_ui(&bs, dcHuffSectionHdr.Lh, 16);
420 bitstream_put_ui(&bs, dcHuffSectionHdr.Tc, 4);
421 bitstream_put_ui(&bs, dcHuffSectionHdr.Th, 4);
422 for (j = 0; j < NUM_DC_RUN_SIZE_BITS; j++) {
423 bitstream_put_ui(&bs, dcHuffSectionHdr.Li[j], 8);
424 }
425
426 for (j = 0; j < NUM_DC_CODE_WORDS_HUFFVAL; j++) {
427 bitstream_put_ui(&bs, dcHuffSectionHdr.Vij[j], 8);
428 }
429
430 //Add AC component (Tc = 1)
431 populate_huff_section_header(&acHuffSectionHdr, i, 1);
432
433 bitstream_put_ui(&bs, acHuffSectionHdr.DHT, 16);
434 bitstream_put_ui(&bs, acHuffSectionHdr.Lh, 16);
435 bitstream_put_ui(&bs, acHuffSectionHdr.Tc, 4);
436 bitstream_put_ui(&bs, acHuffSectionHdr.Th, 4);
437 for (j = 0; j < NUM_AC_RUN_SIZE_BITS; j++) {
438 bitstream_put_ui(&bs, acHuffSectionHdr.Li[j], 8);
439 }
440
441 for (j = 0; j < NUM_AC_CODE_WORDS_HUFFVAL; j++) {
442 bitstream_put_ui(&bs, acHuffSectionHdr.Vij[j], 8);
443 }
444
445 if (yuvComp.fourcc_val == VA_FOURCC_Y800)
446 break;
447 }
448
449 //Add Restart Interval if restart_interval is not 0
450 if (restart_interval != 0) {
451 JPEGRestartSection restartHdr;
452 restartHdr.DRI = DRI;
453 restartHdr.Lr = 4;
454 restartHdr.Ri = restart_interval;
455
456 bitstream_put_ui(&bs, restartHdr.DRI, 16);
457 bitstream_put_ui(&bs, restartHdr.Lr, 16);
458 bitstream_put_ui(&bs, restartHdr.Ri, 16);
459 }
460
461 //Add ScanHeader
462 JPEGScanHeader scanHdr;
463 populate_scan_header(&scanHdr, yuvComp);
464
465 bitstream_put_ui(&bs, scanHdr.SOS, 16);
466 bitstream_put_ui(&bs, scanHdr.Ls, 16);
467 bitstream_put_ui(&bs, scanHdr.Ns, 8);
468
469 for (i = 0; i < scanHdr.Ns; i++) {
470 bitstream_put_ui(&bs, scanHdr.ScanComponent[i].Csj, 8);
471 bitstream_put_ui(&bs, scanHdr.ScanComponent[i].Tdj, 4);
472 bitstream_put_ui(&bs, scanHdr.ScanComponent[i].Taj, 4);
473 }
474
475 bitstream_put_ui(&bs, scanHdr.Ss, 8);
476 bitstream_put_ui(&bs, scanHdr.Se, 8);
477 bitstream_put_ui(&bs, scanHdr.Ah, 4);
478 bitstream_put_ui(&bs, scanHdr.Al, 4);
479
480 bitstream_end(&bs);
481 *header_buffer = (unsigned char *)bs.buffer;
482
483 return bs.bit_offset;
484 }
485
486 //Upload the yuv image from the file to the VASurface
upload_yuv_to_surface(VADisplay va_dpy,FILE * yuv_fp,VASurfaceID surface_id,YUVComponentSpecs yuvComp,int picture_width,int picture_height,int frame_size)487 void upload_yuv_to_surface(VADisplay va_dpy, FILE *yuv_fp, VASurfaceID surface_id, YUVComponentSpecs yuvComp, int picture_width, int picture_height, int frame_size)
488 {
489
490 VAImage surface_image;
491 VAStatus va_status;
492 void *surface_p = NULL;
493 unsigned char *newImageBuffer;
494 unsigned char *y_src, *u_src, *v_src;
495 unsigned char *y_dst, *u_dst;
496 int y_size = picture_width * picture_height;
497 int u_size = 0;
498 int row, col;
499 size_t n_items;
500
501 //u_size is used for I420, NV12 formats only
502 u_size = ((picture_width >> 1) * (picture_height >> 1));
503
504 newImageBuffer = malloc(frame_size);
505 if (newImageBuffer == NULL) {
506 printf("ERROR......upload_yuv_to_surface malloc failed");
507 exit(1);
508 }
509 memset(newImageBuffer, 0, frame_size);
510 do {
511 n_items = fread(newImageBuffer, frame_size, 1, yuv_fp);
512 } while (n_items != 1);
513
514 va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
515 CHECK_VASTATUS(va_status, "vaDeriveImage");
516
517 vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
518 assert(VA_STATUS_SUCCESS == va_status);
519
520 y_src = newImageBuffer;
521 u_src = newImageBuffer + y_size; /* UV offset for NV12 */
522 v_src = newImageBuffer + y_size + u_size;
523
524 y_dst = surface_p + surface_image.offsets[0];
525 u_dst = surface_p + surface_image.offsets[1]; /* UV offset for NV12 */
526
527 if ((yuvComp.fourcc_val == VA_FOURCC_NV12) || (yuvComp.fourcc_val == VA_FOURCC_I420) ||
528 (yuvComp.fourcc_val == VA_FOURCC_Y800)) {
529
530 /* Y plane */
531 for (row = 0; row < surface_image.height; row++) {
532 memcpy(y_dst, y_src, surface_image.width);
533 y_dst += surface_image.pitches[0];
534 y_src += picture_width;
535 }
536
537 if (yuvComp.num_components > 1) {
538
539 switch (yuvComp.fourcc_val) {
540 case VA_FOURCC_NV12: {
541 for (row = 0; row < surface_image.height / 2; row++) {
542 memcpy(u_dst, u_src, surface_image.width);
543 u_dst += surface_image.pitches[1];
544 u_src += (picture_width);
545 }
546 break;
547 }
548
549 case VA_FOURCC_I420: {
550 for (row = 0; row < surface_image.height / 2; row++) {
551 for (col = 0; col < surface_image.width / 2; col++) {
552 u_dst[col * 2] = u_src[col];
553 u_dst[col * 2 + 1] = v_src[col];
554 }
555
556 u_dst += surface_image.pitches[1];
557 u_src += (picture_width / 2);
558 v_src += (picture_width / 2);
559 }
560 break;
561 }
562 }//end of switch
563 }//end of if check
564 } else if ((yuvComp.fourcc_val == VA_FOURCC_UYVY) || (yuvComp.fourcc_val == VA_FOURCC_YUY2)) {
565
566 for (row = 0; row < surface_image.height; row++) {
567 memcpy(y_dst, y_src, surface_image.width * 2);
568 y_dst += surface_image.pitches[0];
569 y_src += picture_width * 2;
570 }
571
572 } else if (yuvComp.fourcc_val == VA_FOURCC_RGBA) {
573
574 for (row = 0; row < surface_image.height; row++) {
575 memcpy(y_dst, y_src, surface_image.width * 4);
576 y_dst += surface_image.pitches[0];
577 y_src += picture_width * 4;
578 }
579 }
580
581 vaUnmapBuffer(va_dpy, surface_image.buf);
582 vaDestroyImage(va_dpy, surface_image.image_id);
583 free(newImageBuffer);
584
585 }
586
587
588
init_yuv_component(YUVComponentSpecs * yuvComponent,int yuv_type,int * surface_type,VASurfaceAttrib * fourcc)589 void init_yuv_component(YUVComponentSpecs *yuvComponent, int yuv_type, int *surface_type, VASurfaceAttrib *fourcc)
590 {
591 yuvComponent->yuv_type = yuv_type;
592
593 //<fourcc value 0(I420)/1(NV12)/2(UYVY)/3(YUY2)/4(Y8)/5(RGBA)>
594 switch (yuv_type) {
595 case 0 : //I420
596 case 1 : { //NV12
597 yuvComponent->va_surface_format = (*surface_type) = VA_RT_FORMAT_YUV420;
598 if (yuv_type == 0) {
599 yuvComponent->fourcc_val = VA_FOURCC_I420;
600 fourcc->value.value.i = VA_FOURCC_NV12;
601 } else {
602 yuvComponent->fourcc_val = fourcc->value.value.i = VA_FOURCC_NV12;
603 }
604 yuvComponent->num_components = 3;
605 yuvComponent->y_h_subsample = 2;
606 yuvComponent->y_v_subsample = 2;
607 yuvComponent->u_h_subsample = 1;
608 yuvComponent->u_v_subsample = 1;
609 yuvComponent->v_h_subsample = 1;
610 yuvComponent->v_v_subsample = 1;
611 break;
612 }
613
614 case 2: { //UYVY
615 yuvComponent->va_surface_format = (*surface_type) = VA_RT_FORMAT_YUV422;
616 yuvComponent->fourcc_val = fourcc->value.value.i = VA_FOURCC_UYVY;
617 yuvComponent->num_components = 3;
618 yuvComponent->y_h_subsample = 2;
619 yuvComponent->y_v_subsample = 1;
620 yuvComponent->u_h_subsample = 1;
621 yuvComponent->u_v_subsample = 1;
622 yuvComponent->v_h_subsample = 1;
623 yuvComponent->v_v_subsample = 1;
624 break;
625 }
626
627 case 3: { //YUY2
628 yuvComponent->va_surface_format = (*surface_type) = VA_RT_FORMAT_YUV422;
629 yuvComponent->fourcc_val = fourcc->value.value.i = VA_FOURCC_YUY2;
630 yuvComponent->num_components = 3;
631 yuvComponent->y_h_subsample = 2;
632 yuvComponent->y_v_subsample = 1;
633 yuvComponent->u_h_subsample = 1;
634 yuvComponent->u_v_subsample = 1;
635 yuvComponent->v_h_subsample = 1;
636 yuvComponent->v_v_subsample = 1;
637 break;
638 }
639
640 case 4: { //Y8
641 yuvComponent->va_surface_format = (*surface_type) = VA_RT_FORMAT_YUV400;
642 yuvComponent->fourcc_val = fourcc->value.value.i = VA_FOURCC_Y800;
643 yuvComponent->num_components = 1;
644 yuvComponent->y_h_subsample = 1;
645 yuvComponent->y_v_subsample = 1;
646 yuvComponent->u_h_subsample = 0;
647 yuvComponent->u_v_subsample = 0;
648 yuvComponent->v_h_subsample = 0;
649 yuvComponent->v_v_subsample = 0;
650 break;
651 }
652
653 case 5: { //RGBA
654 yuvComponent->va_surface_format = (*surface_type) = VA_RT_FORMAT_RGB32;
655 yuvComponent->fourcc_val = fourcc->value.value.i = VA_FOURCC_RGBA;
656 yuvComponent->num_components = 3;
657 yuvComponent->y_h_subsample = 1;
658 yuvComponent->y_v_subsample = 1;
659 yuvComponent->u_h_subsample = 1;
660 yuvComponent->u_v_subsample = 1;
661 yuvComponent->v_h_subsample = 1;
662 yuvComponent->v_v_subsample = 1;
663 break;
664 }
665
666 default: {
667 printf("Unsupported format:\n");
668 show_help();
669 break;
670 }
671
672 }
673
674 }
675
encode_input_image(FILE * yuv_fp,FILE * jpeg_fp,int picture_width,int picture_height,int frame_size,int yuv_type,int quality)676 int encode_input_image(FILE *yuv_fp, FILE *jpeg_fp, int picture_width, int picture_height, int frame_size, int yuv_type, int quality)
677 {
678 int num_entrypoints, enc_entrypoint;
679 int major_ver, minor_ver;
680 int surface_type;
681 VAEntrypoint entrypoints[5];
682 VASurfaceAttrib fourcc;
683 VAConfigAttrib attrib[2];
684 VADisplay va_dpy;
685 VAStatus va_status;
686 VAConfigID config_id;
687 VASurfaceID surface_id;
688 VAContextID context_id;
689 VABufferID pic_param_buf_id; /* Picture parameter id*/
690 VABufferID slice_param_buf_id; /* Slice parameter id, only 1 slice per frame in jpeg encode */
691 VABufferID codedbuf_buf_id; /* Output buffer id, compressed data */
692 VABufferID packed_raw_header_param_buf_id; /* Header parameter buffer id */
693 VABufferID packed_raw_header_buf_id; /* Header buffer id */
694 VABufferID qmatrix_buf_id; /* Quantization Matrix id */
695 VABufferID huffmantable_buf_id; /* Huffman table id*/
696 VAEncPictureParameterBufferJPEG pic_param; /* Picture parameter buffer */
697 VAEncSliceParameterBufferJPEG slice_param; /* Slice parameter buffer */
698 VAQMatrixBufferJPEG quantization_param; /* Quantization Matrix buffer */
699 VAHuffmanTableBufferJPEGBaseline hufftable_param; /* Huffmantable buffer */
700 YUVComponentSpecs yuvComponent;
701 int writeToFile = 1;
702
703 //Clamp the quality factor value to [1,100]
704 if (quality >= 100) quality = 100;
705 if (quality <= 0) quality = 1;
706
707 fourcc.type = VASurfaceAttribPixelFormat;
708 fourcc.flags = VA_SURFACE_ATTRIB_SETTABLE;
709 fourcc.value.type = VAGenericValueTypeInteger;
710
711 init_yuv_component(&yuvComponent, yuv_type, &surface_type, &fourcc);
712
713 /* 1. Initialize the va driver */
714 va_dpy = va_open_display();
715 va_status = vaInitialize(va_dpy, &major_ver, &minor_ver);
716 assert(va_status == VA_STATUS_SUCCESS);
717
718 /* 2. Query for the entrypoints for the JPEGBaseline profile */
719 va_status = vaQueryConfigEntrypoints(va_dpy, VAProfileJPEGBaseline, entrypoints, &num_entrypoints);
720 CHECK_VASTATUS(va_status, "vaQueryConfigEntrypoints");
721 // We need picture level encoding (VAEntrypointEncPicture). Find if it is supported.
722 for (enc_entrypoint = 0; enc_entrypoint < num_entrypoints; enc_entrypoint++) {
723 if (entrypoints[enc_entrypoint] == VAEntrypointEncPicture)
724 break;
725 }
726 if (enc_entrypoint == num_entrypoints) {
727 /* No JPEG Encode (VAEntrypointEncPicture) entry point found */
728 assert(0);
729 }
730
731 /* 3. Query for the Render Target format supported */
732 attrib[0].type = VAConfigAttribRTFormat;
733 attrib[1].type = VAConfigAttribEncJPEG;
734 vaGetConfigAttributes(va_dpy, VAProfileJPEGBaseline, VAEntrypointEncPicture, &attrib[0], 2);
735
736 // RT should be one of below.
737 if (!((attrib[0].value & VA_RT_FORMAT_YUV420) || (attrib[0].value & VA_RT_FORMAT_YUV422) || (attrib[0].value & VA_RT_FORMAT_RGB32)
738 || (attrib[0].value & VA_RT_FORMAT_YUV444) || (attrib[0].value & VA_RT_FORMAT_YUV400))) {
739 /* Did not find the supported RT format */
740 assert(0);
741 }
742
743 VAConfigAttribValEncJPEG jpeg_attrib_val;
744 jpeg_attrib_val.value = attrib[1].value;
745
746 /* Set JPEG profile attribs */
747 jpeg_attrib_val.bits.arithmatic_coding_mode = 0;
748 jpeg_attrib_val.bits.progressive_dct_mode = 0;
749 jpeg_attrib_val.bits.non_interleaved_mode = 1;
750 jpeg_attrib_val.bits.differential_mode = 0;
751
752 attrib[1].value = jpeg_attrib_val.value;
753
754 /* 4. Create Config for the profile=VAProfileJPEGBaseline, entrypoint=VAEntrypointEncPicture,
755 * with RT format attribute */
756 va_status = vaCreateConfig(va_dpy, VAProfileJPEGBaseline, VAEntrypointEncPicture,
757 &attrib[0], 2, &config_id);
758 CHECK_VASTATUS(va_status, "vaQueryConfigEntrypoints");
759
760 /* 5. Create Surface for the input picture */
761 va_status = vaCreateSurfaces(va_dpy, surface_type, picture_width, picture_height,
762 &surface_id, 1, &fourcc, 1);
763 CHECK_VASTATUS(va_status, "vaCreateSurfaces");
764
765 //Map the input yuv file to the input surface created with the surface_id
766 upload_yuv_to_surface(va_dpy, yuv_fp, surface_id, yuvComponent, picture_width, picture_height, frame_size);
767
768 /* 6. Create Context for the encode pipe*/
769 va_status = vaCreateContext(va_dpy, config_id, picture_width, picture_height,
770 VA_PROGRESSIVE, &surface_id, 1, &context_id);
771 CHECK_VASTATUS(va_status, "vaCreateContext");
772
773 /* Create buffer for Encoded data to be stored */
774 va_status = vaCreateBuffer(va_dpy, context_id, VAEncCodedBufferType,
775 frame_size, 1, NULL, &codedbuf_buf_id);
776 CHECK_VASTATUS(va_status, "vaCreateBuffer");
777
778 //Initialize the picture parameter buffer
779 pic_param.coded_buf = codedbuf_buf_id;
780 jpegenc_pic_param_init(&pic_param, picture_width, picture_height, quality, yuvComponent);
781
782 /* 7. Create buffer for the picture parameter */
783 va_status = vaCreateBuffer(va_dpy, context_id, VAEncPictureParameterBufferType,
784 sizeof(VAEncPictureParameterBufferJPEG), 1, &pic_param, &pic_param_buf_id);
785 CHECK_VASTATUS(va_status, "vaCreateBuffer");
786
787 //Load the QMatrix
788 jpegenc_qmatrix_init(&quantization_param, yuvComponent);
789
790 /* 8. Create buffer for Quantization Matrix */
791 va_status = vaCreateBuffer(va_dpy, context_id, VAQMatrixBufferType,
792 sizeof(VAQMatrixBufferJPEG), 1, &quantization_param, &qmatrix_buf_id);
793 CHECK_VASTATUS(va_status, "vaCreateBuffer");
794
795 //Load the Huffman Tables
796 jpegenc_hufftable_init(&hufftable_param, yuvComponent);
797
798 /* 9. Create buffer for Huffman Tables */
799 va_status = vaCreateBuffer(va_dpy, context_id, VAHuffmanTableBufferType,
800 sizeof(VAHuffmanTableBufferJPEGBaseline), 1, &hufftable_param, &huffmantable_buf_id);
801 CHECK_VASTATUS(va_status, "vaCreateBuffer");
802
803 //Initialize the slice parameter buffer
804 jpegenc_slice_param_init(&slice_param, yuvComponent);
805
806 /* 10. Create buffer for slice parameter */
807 va_status = vaCreateBuffer(va_dpy, context_id, VAEncSliceParameterBufferType,
808 sizeof(slice_param), 1, &slice_param, &slice_param_buf_id);
809 CHECK_VASTATUS(va_status, "vaCreateBuffer");
810
811 //Pack headers and send using Raw data buffer
812 VAEncPackedHeaderParameterBuffer packed_header_param_buffer;
813 unsigned int length_in_bits;
814 unsigned char *packed_header_buffer = NULL;
815
816 length_in_bits = build_packed_jpeg_header_buffer(&packed_header_buffer, yuvComponent, picture_width, picture_height, slice_param.restart_interval, quality);
817 packed_header_param_buffer.type = VAEncPackedHeaderRawData;
818 packed_header_param_buffer.bit_length = length_in_bits;
819 packed_header_param_buffer.has_emulation_bytes = 0;
820
821 /* 11. Create raw buffer for header */
822 va_status = vaCreateBuffer(va_dpy,
823 context_id,
824 VAEncPackedHeaderParameterBufferType,
825 sizeof(packed_header_param_buffer), 1, &packed_header_param_buffer,
826 &packed_raw_header_param_buf_id);
827 CHECK_VASTATUS(va_status, "vaCreateBuffer");
828
829 va_status = vaCreateBuffer(va_dpy,
830 context_id,
831 VAEncPackedHeaderDataBufferType,
832 (length_in_bits + 7) / 8, 1, packed_header_buffer,
833 &packed_raw_header_buf_id);
834 CHECK_VASTATUS(va_status, "vaCreateBuffer");
835
836 /* 12. Begin picture */
837 va_status = vaBeginPicture(va_dpy, context_id, surface_id);
838 CHECK_VASTATUS(va_status, "vaBeginPicture");
839
840 /* 13. Render picture for all the VA buffers created */
841 va_status = vaRenderPicture(va_dpy, context_id, &pic_param_buf_id, 1);
842 CHECK_VASTATUS(va_status, "vaRenderPicture");
843
844 va_status = vaRenderPicture(va_dpy, context_id, &qmatrix_buf_id, 1);
845 CHECK_VASTATUS(va_status, "vaRenderPicture");
846
847 va_status = vaRenderPicture(va_dpy, context_id, &huffmantable_buf_id, 1);
848 CHECK_VASTATUS(va_status, "vaRenderPicture");
849
850 va_status = vaRenderPicture(va_dpy, context_id, &slice_param_buf_id, 1);
851 CHECK_VASTATUS(va_status, "vaRenderPicture");
852
853 va_status = vaRenderPicture(va_dpy, context_id, &packed_raw_header_param_buf_id, 1);
854 CHECK_VASTATUS(va_status, "vaRenderPicture");
855
856 va_status = vaRenderPicture(va_dpy, context_id, &packed_raw_header_buf_id, 1);
857 CHECK_VASTATUS(va_status, "vaRenderPicture");
858
859 va_status = vaEndPicture(va_dpy, context_id);
860 CHECK_VASTATUS(va_status, "vaEndPicture");
861
862 if (writeToFile) {
863 VASurfaceStatus surface_status;
864 size_t w_items;
865 VACodedBufferSegment *coded_buffer_segment;
866 unsigned char *coded_mem;
867 int slice_data_length;
868
869 va_status = vaSyncSurface(va_dpy, surface_id);
870 CHECK_VASTATUS(va_status, "vaSyncSurface");
871
872 surface_status = 0;
873 va_status = vaQuerySurfaceStatus(va_dpy, surface_id, &surface_status);
874 CHECK_VASTATUS(va_status, "vaQuerySurfaceStatus");
875
876 va_status = vaMapBuffer(va_dpy, codedbuf_buf_id, (void **)(&coded_buffer_segment));
877 CHECK_VASTATUS(va_status, "vaMapBuffer");
878
879 coded_mem = coded_buffer_segment->buf;
880
881 if (coded_buffer_segment->status & VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK) {
882 vaUnmapBuffer(va_dpy, codedbuf_buf_id);
883 printf("ERROR......Coded buffer too small\n");
884 }
885
886
887 slice_data_length = coded_buffer_segment->size;
888
889 do {
890 w_items = fwrite(coded_mem, slice_data_length, 1, jpeg_fp);
891 } while (w_items != 1);
892
893 va_status = vaUnmapBuffer(va_dpy, codedbuf_buf_id);
894 CHECK_VASTATUS(va_status, "vaUnmapBuffer");
895 }
896
897 vaDestroyBuffer(va_dpy, pic_param_buf_id);
898 vaDestroyBuffer(va_dpy, qmatrix_buf_id);
899 vaDestroyBuffer(va_dpy, slice_param_buf_id);
900 vaDestroyBuffer(va_dpy, huffmantable_buf_id);
901 vaDestroyBuffer(va_dpy, codedbuf_buf_id);
902 vaDestroyBuffer(va_dpy, packed_raw_header_param_buf_id);
903 vaDestroyBuffer(va_dpy, packed_raw_header_buf_id);
904 vaDestroySurfaces(va_dpy, &surface_id, 1);
905 vaDestroyContext(va_dpy, context_id);
906 vaDestroyConfig(va_dpy, config_id);
907 vaTerminate(va_dpy);
908 va_close_display(va_dpy);
909
910 return 0;
911 }
912
913
main(int argc,char * argv[])914 int main(int argc, char *argv[])
915 {
916 FILE *yuv_fp;
917 FILE *jpeg_fp;
918 off_t file_size;
919 clock_t start_time, finish_time;
920 unsigned int duration;
921 unsigned int yuv_type = 0;
922 int quality = 0;
923 unsigned int picture_width = 0;
924 unsigned int picture_height = 0;
925 unsigned int frame_size = 0;
926
927 va_init_display_args(&argc, argv);
928
929 if (argc != 7) {
930 show_help();
931 return -1;
932 }
933
934 picture_width = atoi(argv[1]);
935 picture_height = atoi(argv[2]);
936 yuv_type = atoi(argv[5]);
937 quality = atoi(argv[6]);
938
939 //<input file type: 0(I420)/1(NV12)/2(UYVY)/3(YUY2)/4(Y8)/5(RGBA)>
940 switch (yuv_type) {
941 case 0 : //I420
942 case 1 : { //NV12
943 frame_size = picture_width * picture_height + ((picture_width * picture_height) >> 1) ;
944 break;
945 }
946
947 case 2: //UYVY
948 case 3: { //YUY2
949 frame_size = 2 * (picture_width * picture_height);
950 break;
951 }
952
953 case 4: { //Y8
954 frame_size = picture_width * picture_height;
955 break;
956 }
957
958 case 5: { //RGBA
959 frame_size = 4 * (picture_width * picture_height) ;
960 break;
961 }
962
963 default: {
964 printf("Unsupported format:\n");
965 show_help();
966 return -1;
967 }
968 }
969
970 yuv_fp = fopen(argv[3], "rb");
971 if (yuv_fp == NULL) {
972 printf("Can't open input YUV file\n");
973 return -1;
974 }
975
976 fseeko(yuv_fp, (off_t)0, SEEK_END);
977 file_size = ftello(yuv_fp);
978
979 if ((file_size < frame_size) || (file_size % frame_size)) {
980 fclose(yuv_fp);
981 printf("The YUV file's size is not correct: file_size=%zd, frame_size=%d\n", file_size, frame_size);
982 return -1;
983 }
984
985 fseeko(yuv_fp, (off_t)0, SEEK_SET);
986
987 jpeg_fp = fopen(argv[4], "wb");
988 if (jpeg_fp == NULL) {
989 fclose(yuv_fp);
990 printf("Can't open output destination jpeg file\n");
991 return -1;
992 }
993
994 start_time = clock();
995 encode_input_image(yuv_fp, jpeg_fp, picture_width, picture_height, frame_size, yuv_type, quality);
996 if (yuv_fp != NULL) fclose(yuv_fp);
997 if (jpeg_fp != NULL) fclose(jpeg_fp);
998 finish_time = clock();
999 duration = finish_time - start_time;
1000 printf("Encoding finished in %u ticks\n", duration);
1001
1002 return 0;
1003 }
1004
1005