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