encoder: jpeg: Fix the packed header generation
[platform/upstream/gstreamer.git] / gst-libs / gst / vaapi / gstvaapiencoder_jpeg.c
1 /*
2  *  gstvaapiencoder_jpeg.c - JPEG encoder
3  *
4  *  Copyright (C) 2015 Intel Corporation
5  *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public License
9  *  as published by the Free Software Foundation; either version 2.1
10  *  of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free
19  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  *  Boston, MA 02110-1301 USA
21  */
22
23 #include "sysdeps.h"
24 #include <va/va.h>
25 #include <va/va_enc_jpeg.h>
26 #include <gst/base/gstbitwriter.h>
27 #include <gst/codecparsers/gstjpegparser.h>
28 #include "gstvaapicompat.h"
29 #include "gstvaapiencoder_priv.h"
30 #include "gstvaapiencoder_jpeg.h"
31 #include "gstvaapicodedbufferproxy_priv.h"
32 #include "gstvaapisurface.h"
33
34 #define DEBUG 1
35 #include "gstvaapidebug.h"
36
37 /* Define default rate control mode ("constant-qp") */
38 #define DEFAULT_RATECONTROL GST_VAAPI_RATECONTROL_NONE
39
40 /* Supported set of VA rate controls, within this implementation */
41 #define SUPPORTED_RATECONTROLS                  \
42   (GST_VAAPI_RATECONTROL_MASK (NONE))
43
44 /* Supported set of tuning options, within this implementation */
45 #define SUPPORTED_TUNE_OPTIONS \
46   (GST_VAAPI_ENCODER_TUNE_MASK (NONE))
47
48 /* Supported set of VA packed headers, within this implementation */
49 #define SUPPORTED_PACKED_HEADERS                \
50   (VA_ENC_PACKED_HEADER_RAW_DATA)
51
52 #define NUM_DC_RUN_SIZE_BITS 16
53 #define NUM_AC_RUN_SIZE_BITS 16
54 #define NUM_AC_CODE_WORDS_HUFFVAL 162
55 #define NUM_DC_CODE_WORDS_HUFFVAL 12
56
57 /* ------------------------------------------------------------------------- */
58 /* --- JPEG Encoder                                                      --- */
59 /* ------------------------------------------------------------------------- */
60
61 #define GST_VAAPI_ENCODER_JPEG_CAST(encoder) \
62     ((GstVaapiEncoderJpeg *)(encoder))
63
64 struct _GstVaapiEncoderJpeg
65 {
66   GstVaapiEncoder parent_instance;
67   GstVaapiProfile profile;
68   guint quality;
69   GstJpegQuantTables quant_tables;
70   GstJpegQuantTables scaled_quant_tables;
71   gboolean has_quant_tables;
72   GstJpegHuffmanTables huff_tables;
73   gboolean has_huff_tables;
74   gint cwidth[GST_VIDEO_MAX_COMPONENTS];
75   gint cheight[GST_VIDEO_MAX_COMPONENTS];
76   gint h_samp[GST_VIDEO_MAX_COMPONENTS];
77   gint v_samp[GST_VIDEO_MAX_COMPONENTS];
78   gint h_max_samp;
79   gint v_max_samp;
80   guint n_components;
81 };
82
83 /* based on upstream gst-plugins-good jpegencoder */
84 static void
85 generate_sampling_factors (GstVaapiEncoderJpeg * encoder)
86 {
87   GstVideoInfo *vinfo;
88   gint i;
89
90   vinfo = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
91
92   if (GST_VIDEO_INFO_FORMAT (vinfo) == GST_VIDEO_FORMAT_ENCODED) {
93     /* Use native I420 format */
94     encoder->n_components = 3;
95     for (i = 0; i < encoder->n_components; ++i) {
96       if (i == 0)
97         encoder->h_samp[i] = encoder->v_samp[i] = 2;
98       else
99         encoder->h_samp[i] = encoder->v_samp[i] = 1;
100       GST_DEBUG ("sampling factors: %d %d", encoder->h_samp[i],
101           encoder->v_samp[i]);
102     }
103     return;
104   }
105
106   encoder->n_components = GST_VIDEO_INFO_N_COMPONENTS (vinfo);
107
108   encoder->h_max_samp = 0;
109   encoder->v_max_samp = 0;
110   for (i = 0; i < encoder->n_components; ++i) {
111     encoder->cwidth[i] = GST_VIDEO_INFO_COMP_WIDTH (vinfo, i);
112     encoder->cheight[i] = GST_VIDEO_INFO_COMP_HEIGHT (vinfo, i);
113     encoder->h_samp[i] =
114         GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (vinfo)) / encoder->cwidth[i];
115     encoder->h_max_samp = MAX (encoder->h_max_samp, encoder->h_samp[i]);
116     encoder->v_samp[i] =
117         GST_ROUND_UP_4 (GST_VIDEO_INFO_HEIGHT (vinfo)) / encoder->cheight[i];
118     encoder->v_max_samp = MAX (encoder->v_max_samp, encoder->v_samp[i]);
119   }
120   /* samp should only be 1, 2 or 4 */
121   g_assert (encoder->h_max_samp <= 4);
122   g_assert (encoder->v_max_samp <= 4);
123
124   /* now invert */
125   /* maximum is invariant, as one of the components should have samp 1 */
126   for (i = 0; i < encoder->n_components; ++i) {
127     encoder->h_samp[i] = encoder->h_max_samp / encoder->h_samp[i];
128     encoder->v_samp[i] = encoder->v_max_samp / encoder->v_samp[i];
129     GST_DEBUG ("sampling factors: %d %d", encoder->h_samp[i],
130         encoder->v_samp[i]);
131   }
132 }
133
134 /* Derives the profile that suits best to the configuration */
135 static GstVaapiEncoderStatus
136 ensure_profile (GstVaapiEncoderJpeg * encoder)
137 {
138   /* Always start from "simple" profile for maximum compatibility */
139   encoder->profile = GST_VAAPI_PROFILE_JPEG_BASELINE;
140
141   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
142 }
143
144 /* Derives the profile supported by the underlying hardware */
145 static gboolean
146 ensure_hw_profile (GstVaapiEncoderJpeg * encoder)
147 {
148   GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder);
149   GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_PICTURE_ENCODE;
150   GstVaapiProfile profile, profiles[2];
151   guint i, num_profiles = 0;
152
153   profiles[num_profiles++] = encoder->profile;
154
155   profile = GST_VAAPI_PROFILE_UNKNOWN;
156   for (i = 0; i < num_profiles; i++) {
157     if (gst_vaapi_display_has_encoder (display, profiles[i], entrypoint)) {
158       profile = profiles[i];
159       break;
160     }
161   }
162   if (profile == GST_VAAPI_PROFILE_UNKNOWN)
163     goto error_unsupported_profile;
164
165   GST_VAAPI_ENCODER_CAST (encoder)->profile = profile;
166   return TRUE;
167
168   /* ERRORS */
169 error_unsupported_profile:
170   {
171     GST_ERROR ("unsupported HW profile (0x%08x)", encoder->profile);
172     return FALSE;
173   }
174 }
175
176 static GstVaapiEncoderStatus
177 set_context_info (GstVaapiEncoder * base_encoder)
178 {
179   GstVaapiEncoderJpeg *encoder = GST_VAAPI_ENCODER_JPEG_CAST (base_encoder);
180   GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
181
182   /* Maximum sizes for common headers (in bytes) */
183   enum
184   {
185     MAX_APP_HDR_SIZE = 20,
186     MAX_FRAME_HDR_SIZE = 19,
187     MAX_QUANT_TABLE_SIZE = 138,
188     MAX_HUFFMAN_TABLE_SIZE = 432,
189     MAX_SCAN_HDR_SIZE = 14
190   };
191
192   if (!ensure_hw_profile (encoder))
193     return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
194
195   base_encoder->num_ref_frames = 0;
196
197   /* Only YUV 4:2:0 formats are supported for now. */
198   base_encoder->codedbuf_size = GST_ROUND_UP_16 (vip->width) *
199       GST_ROUND_UP_16 (vip->height) * 3 / 2;
200
201   base_encoder->codedbuf_size += MAX_APP_HDR_SIZE + MAX_FRAME_HDR_SIZE +
202       MAX_QUANT_TABLE_SIZE + MAX_HUFFMAN_TABLE_SIZE + MAX_SCAN_HDR_SIZE;
203
204   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
205 }
206
207 static gboolean
208 fill_picture (GstVaapiEncoderJpeg * encoder,
209     GstVaapiEncPicture * picture,
210     GstVaapiCodedBuffer * codedbuf, GstVaapiSurfaceProxy * surface)
211 {
212   VAEncPictureParameterBufferJPEG *const pic_param = picture->param;
213
214   memset (pic_param, 0, sizeof (VAEncPictureParameterBufferJPEG));
215
216   pic_param->reconstructed_picture =
217       GST_VAAPI_SURFACE_PROXY_SURFACE_ID (surface);
218   pic_param->picture_width = GST_VAAPI_ENCODER_WIDTH (encoder);
219   pic_param->picture_height = GST_VAAPI_ENCODER_HEIGHT (encoder);
220   pic_param->coded_buf = GST_VAAPI_OBJECT_ID (codedbuf);
221
222   pic_param->pic_flags.bits.profile = 0;        /* Profile = Baseline */
223   pic_param->pic_flags.bits.progressive = 0;    /* Sequential encoding */
224   pic_param->pic_flags.bits.huffman = 1;        /* Uses Huffman coding */
225   pic_param->pic_flags.bits.interleaved = 0;    /* Input format is non interleaved (YUV) */
226   pic_param->pic_flags.bits.differential = 0;   /* non-Differential Encoding */
227   pic_param->sample_bit_depth = 8;
228   pic_param->num_scan = 1;
229   pic_param->num_components = encoder->n_components;
230   pic_param->quality = encoder->quality;
231   return TRUE;
232 }
233
234 static gboolean
235 ensure_picture (GstVaapiEncoderJpeg * encoder, GstVaapiEncPicture * picture,
236     GstVaapiCodedBufferProxy * codedbuf_proxy, GstVaapiSurfaceProxy * surface)
237 {
238   GstVaapiCodedBuffer *const codedbuf =
239       GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy);
240
241   if (!fill_picture (encoder, picture, codedbuf, surface))
242     return FALSE;
243
244   return TRUE;
245 }
246
247 /* This is a work-around: Normalize the quality factor and scale QM
248  * values similar to what VA-Intel driver is doing. Otherwise the
249  * generated packed headers will be wrong, since the driver itself
250  * is scaling the QM values using the normalized quality factor */
251 static void
252 generate_scaled_qm (GstJpegQuantTables * quant_tables,
253     GstJpegQuantTables * scaled_quant_tables, guint quality)
254 {
255   guint qt_val, nm_quality, i;
256   nm_quality = quality == 0 ? 1 : quality;
257   nm_quality =
258       (nm_quality < 50) ? (5000 / nm_quality) : (200 - (nm_quality * 2));
259
260   g_assert (quant_tables != NULL);
261   g_assert (scaled_quant_tables != NULL);
262
263   for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) {
264     /* Luma QM */
265     qt_val = (quant_tables->quant_tables[0].quant_table[i] * nm_quality) / 100;
266     scaled_quant_tables->quant_tables[0].quant_table[i] =
267         CLAMP (qt_val, 1, 255);
268     /* Chroma QM */
269     qt_val = (quant_tables->quant_tables[1].quant_table[i] * nm_quality) / 100;
270     scaled_quant_tables->quant_tables[1].quant_table[i] =
271         CLAMP (qt_val, 1, 255);
272   }
273 }
274
275 static gboolean
276 fill_quantization_table (GstVaapiEncoderJpeg * encoder,
277     GstVaapiEncPicture * picture)
278 {
279   VAQMatrixBufferJPEG *q_matrix;
280   int i;
281
282   g_assert (picture);
283
284   picture->q_matrix = GST_VAAPI_ENC_Q_MATRIX_NEW (JPEG, encoder);
285   if (!picture->q_matrix) {
286     GST_ERROR ("failed to allocate quantiser table");
287     return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
288   }
289   q_matrix = picture->q_matrix->param;
290
291   if (!encoder->has_quant_tables) {
292     gst_jpeg_get_default_quantization_tables (&encoder->quant_tables);
293     encoder->has_quant_tables = TRUE;
294     generate_scaled_qm (&encoder->quant_tables, &encoder->scaled_quant_tables,
295         encoder->quality);
296   }
297   q_matrix->load_lum_quantiser_matrix = 1;
298   for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) {
299     q_matrix->lum_quantiser_matrix[i] =
300         encoder->quant_tables.quant_tables[0].quant_table[i];
301   }
302
303   q_matrix->load_chroma_quantiser_matrix = 1;
304   for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) {
305     q_matrix->chroma_quantiser_matrix[i] =
306         encoder->quant_tables.quant_tables[1].quant_table[i];
307   }
308
309   return TRUE;
310 }
311
312 static gboolean
313 ensure_quantization_table (GstVaapiEncoderJpeg * encoder,
314     GstVaapiEncPicture * picture)
315 {
316   g_assert (picture);
317
318   if (!fill_quantization_table (encoder, picture))
319     return FALSE;
320
321   return TRUE;
322 }
323
324 static gboolean
325 fill_huffman_table (GstVaapiEncoderJpeg * encoder, GstVaapiEncPicture * picture)
326 {
327   VAHuffmanTableBufferJPEGBaseline *huffman_table;
328   guint i, num_tables;
329
330   g_assert (picture);
331
332   picture->huf_table = GST_VAAPI_ENC_HUFFMAN_TABLE_NEW (JPEGBaseline, encoder);
333   if (!picture->huf_table) {
334     GST_ERROR ("failed to allocate Huffman tables");
335     return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
336   }
337   huffman_table = picture->huf_table->param;
338
339   num_tables = MIN (G_N_ELEMENTS (huffman_table->huffman_table),
340       GST_JPEG_MAX_SCAN_COMPONENTS);
341
342   if (!encoder->has_huff_tables) {
343     gst_jpeg_get_default_huffman_tables (&encoder->huff_tables);
344     encoder->has_huff_tables = TRUE;
345   }
346
347   for (i = 0; i < num_tables; i++) {
348     huffman_table->load_huffman_table[i] =
349         encoder->huff_tables.dc_tables[i].valid
350         && encoder->huff_tables.ac_tables[i].valid;
351     if (!huffman_table->load_huffman_table[i])
352       continue;
353
354     memcpy (huffman_table->huffman_table[i].num_dc_codes,
355         encoder->huff_tables.dc_tables[i].huf_bits,
356         sizeof (huffman_table->huffman_table[i].num_dc_codes));
357     memcpy (huffman_table->huffman_table[i].dc_values,
358         encoder->huff_tables.dc_tables[i].huf_values,
359         sizeof (huffman_table->huffman_table[i].dc_values));
360     memcpy (huffman_table->huffman_table[i].num_ac_codes,
361         encoder->huff_tables.ac_tables[i].huf_bits,
362         sizeof (huffman_table->huffman_table[i].num_ac_codes));
363     memcpy (huffman_table->huffman_table[i].ac_values,
364         encoder->huff_tables.ac_tables[i].huf_values,
365         sizeof (huffman_table->huffman_table[i].ac_values));
366     memset (huffman_table->huffman_table[i].pad,
367         0, sizeof (huffman_table->huffman_table[i].pad));
368   }
369
370   return TRUE;
371 }
372
373 static gboolean
374 ensure_huffman_table (GstVaapiEncoderJpeg * encoder,
375     GstVaapiEncPicture * picture)
376 {
377   g_assert (picture);
378
379   if (!fill_huffman_table (encoder, picture))
380     return FALSE;
381
382   return TRUE;
383 }
384
385 static gboolean
386 fill_slices (GstVaapiEncoderJpeg * encoder, GstVaapiEncPicture * picture)
387 {
388   VAEncSliceParameterBufferJPEG *slice_param;
389   GstVaapiEncSlice *slice;
390   VAEncPictureParameterBufferJPEG *const pic_param = picture->param;
391
392   slice = GST_VAAPI_ENC_SLICE_NEW (JPEG, encoder);
393   g_assert (slice && slice->param_id != VA_INVALID_ID);
394   slice_param = slice->param;
395
396   slice_param->restart_interval = 0;
397   slice_param->num_components = pic_param->num_components;
398
399   slice_param->components[0].component_selector = 1;
400   slice_param->components[0].dc_table_selector = 0;
401   slice_param->components[0].ac_table_selector = 0;
402
403   slice_param->components[1].component_selector = 2;
404   slice_param->components[1].dc_table_selector = 1;
405   slice_param->components[1].ac_table_selector = 1;
406
407   slice_param->components[2].component_selector = 3;
408   slice_param->components[2].dc_table_selector = 1;
409   slice_param->components[2].ac_table_selector = 1;
410
411   gst_vaapi_enc_picture_add_slice (picture, slice);
412   gst_vaapi_codec_object_replace (&slice, NULL);
413
414   return TRUE;
415 }
416
417 static gboolean
418 ensure_slices (GstVaapiEncoderJpeg * encoder, GstVaapiEncPicture * picture)
419 {
420   g_assert (picture);
421
422   if (!fill_slices (encoder, picture))
423     return FALSE;
424
425   return TRUE;
426 }
427
428 static void
429 generate_frame_hdr (GstJpegFrameHdr * frame_hdr, GstVaapiEncoderJpeg * encoder,
430     GstVaapiEncPicture * picture)
431 {
432   VAEncPictureParameterBufferJPEG *const pic_param = picture->param;
433   guint i;
434
435   memset (frame_hdr, 0, sizeof (GstJpegFrameHdr));
436   frame_hdr->sample_precision = 8;
437   frame_hdr->width = pic_param->picture_width;
438   frame_hdr->height = pic_param->picture_height;
439   frame_hdr->num_components = pic_param->num_components;
440
441   for (i = 0; i < frame_hdr->num_components; i++) {
442     frame_hdr->components[i].identifier = i + 1;
443     frame_hdr->components[i].horizontal_factor = encoder->h_samp[i];
444     frame_hdr->components[i].vertical_factor = encoder->v_samp[i];
445     if (i == 0)
446       frame_hdr->components[i].quant_table_selector = 0;
447     else
448       frame_hdr->components[i].quant_table_selector = 1;
449   }
450 }
451
452 static void
453 generate_scan_hdr (GstJpegScanHdr * scan_hdr, GstVaapiEncPicture * picture)
454 {
455
456   VAEncPictureParameterBufferJPEG *const pic_param = picture->param;
457
458   memset (scan_hdr, 0, sizeof (GstJpegScanHdr));
459   scan_hdr->num_components = pic_param->num_components;
460   //Y Component
461   scan_hdr->components[0].component_selector = 1;
462   scan_hdr->components[0].dc_selector = 0;
463   scan_hdr->components[0].ac_selector = 0;
464
465
466   //U Component
467   scan_hdr->components[1].component_selector = 2;
468   scan_hdr->components[1].dc_selector = 1;
469   scan_hdr->components[1].ac_selector = 1;
470
471   //V Component
472   scan_hdr->components[2].component_selector = 3;
473   scan_hdr->components[2].dc_selector = 1;
474   scan_hdr->components[2].ac_selector = 1;
475 }
476
477 static gboolean
478 bs_write_jpeg_header (GstBitWriter * bs, GstVaapiEncoderJpeg * encoder,
479     GstVaapiEncPicture * picture)
480 {
481   GstJpegFrameHdr frame_hdr;
482   GstJpegScanHdr scan_hdr;
483   guint i, j;
484
485   gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
486   gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_SOI, 8);
487   gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
488   gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_APP_MIN, 8);
489   gst_bit_writer_put_bits_uint16 (bs, 16, 16);
490   gst_bit_writer_put_bits_uint8 (bs, 0x4A, 8);  //J
491   gst_bit_writer_put_bits_uint8 (bs, 0x46, 8);  //F
492   gst_bit_writer_put_bits_uint8 (bs, 0x49, 8);  //I
493   gst_bit_writer_put_bits_uint8 (bs, 0x46, 8);  //F
494   gst_bit_writer_put_bits_uint8 (bs, 0x00, 8);  //0
495   gst_bit_writer_put_bits_uint8 (bs, 1, 8);     //Major Version
496   gst_bit_writer_put_bits_uint8 (bs, 1, 8);     //Minor Version
497   gst_bit_writer_put_bits_uint8 (bs, 0, 8);     //Density units 0:no units, 1:pixels per inch, 2: pixels per cm
498   gst_bit_writer_put_bits_uint16 (bs, 1, 16);   //X density (pixel-aspect-ratio)
499   gst_bit_writer_put_bits_uint16 (bs, 1, 16);   //Y density (pixel-aspect-ratio)
500   gst_bit_writer_put_bits_uint8 (bs, 0, 8);     //Thumbnail width
501   gst_bit_writer_put_bits_uint8 (bs, 0, 8);     //Thumbnail height
502
503   /* Add  quantization table */
504   if (!encoder->has_quant_tables) {
505     gst_jpeg_get_default_quantization_tables (&encoder->quant_tables);
506     generate_scaled_qm (&encoder->quant_tables, &encoder->scaled_quant_tables,
507         encoder->quality);
508     encoder->has_quant_tables = TRUE;
509   }
510
511   gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
512   gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_DQT, 8);
513   gst_bit_writer_put_bits_uint16 (bs, 3 + GST_JPEG_MAX_QUANT_ELEMENTS, 16);     //Lq
514   gst_bit_writer_put_bits_uint8 (bs, encoder->quant_tables.quant_tables[0].quant_precision, 4); //Pq
515   gst_bit_writer_put_bits_uint8 (bs, 0, 4);     //Tq
516   for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) {
517     gst_bit_writer_put_bits_uint16 (bs,
518         encoder->scaled_quant_tables.quant_tables[0].quant_table[i], 8);
519   }
520   gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
521   gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_DQT, 8);
522   gst_bit_writer_put_bits_uint16 (bs, 3 + GST_JPEG_MAX_QUANT_ELEMENTS, 16);     //Lq
523   gst_bit_writer_put_bits_uint8 (bs, encoder->quant_tables.quant_tables[1].quant_precision, 4); //Pq
524   gst_bit_writer_put_bits_uint8 (bs, 1, 4);     //Tq
525   for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) {
526     gst_bit_writer_put_bits_uint16 (bs,
527         encoder->scaled_quant_tables.quant_tables[1].quant_table[i], 8);
528   }
529
530   /*Add frame header */
531   generate_frame_hdr (&frame_hdr, encoder, picture);
532   gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
533   gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_SOF_MIN, 8);
534   gst_bit_writer_put_bits_uint16 (bs, 8 + (3 * 3), 16); //lf, Size of FrameHeader in bytes without the Marker SOF
535   gst_bit_writer_put_bits_uint8 (bs, frame_hdr.sample_precision, 8);
536   gst_bit_writer_put_bits_uint16 (bs, frame_hdr.height, 16);
537   gst_bit_writer_put_bits_uint16 (bs, frame_hdr.width, 16);
538   gst_bit_writer_put_bits_uint8 (bs, frame_hdr.num_components, 8);
539   for (i = 0; i < frame_hdr.num_components; i++) {
540     gst_bit_writer_put_bits_uint8 (bs, frame_hdr.components[i].identifier, 8);
541     gst_bit_writer_put_bits_uint8 (bs,
542         frame_hdr.components[i].horizontal_factor, 4);
543     gst_bit_writer_put_bits_uint8 (bs, frame_hdr.components[i].vertical_factor,
544         4);
545     gst_bit_writer_put_bits_uint8 (bs,
546         frame_hdr.components[i].quant_table_selector, 8);
547   }
548
549   /* Add Huffman table */
550   if (!encoder->has_huff_tables) {
551     gst_jpeg_get_default_huffman_tables (&encoder->huff_tables);
552     encoder->has_huff_tables = TRUE;
553   }
554   for (i = 0; i < 2; i++) {
555     gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
556     gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_DHT, 8);
557     gst_bit_writer_put_bits_uint16 (bs, 0x1F, 16);      //length of table
558     gst_bit_writer_put_bits_uint8 (bs, 0, 4);
559     gst_bit_writer_put_bits_uint8 (bs, i, 4);
560     for (j = 0; j < NUM_DC_RUN_SIZE_BITS; j++) {
561       gst_bit_writer_put_bits_uint8 (bs,
562           encoder->huff_tables.dc_tables[i].huf_bits[j], 8);
563     }
564
565     for (j = 0; j < NUM_DC_CODE_WORDS_HUFFVAL; j++) {
566       gst_bit_writer_put_bits_uint8 (bs,
567           encoder->huff_tables.dc_tables[i].huf_values[j], 8);
568     }
569
570     gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
571     gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_DHT, 8);
572     gst_bit_writer_put_bits_uint16 (bs, 0xB5, 16);      //length of table
573     gst_bit_writer_put_bits_uint8 (bs, 1, 4);
574     gst_bit_writer_put_bits_uint8 (bs, i, 4);
575     for (j = 0; j < NUM_AC_RUN_SIZE_BITS; j++) {
576       gst_bit_writer_put_bits_uint8 (bs,
577           encoder->huff_tables.ac_tables[i].huf_bits[j], 8);
578     }
579
580     for (j = 0; j < NUM_AC_CODE_WORDS_HUFFVAL; j++) {
581       gst_bit_writer_put_bits_uint8 (bs,
582           encoder->huff_tables.ac_tables[i].huf_values[j], 8);
583     }
584   }
585
586   /* Add ScanHeader */
587   generate_scan_hdr (&scan_hdr, picture);
588   gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
589   gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_SOS, 8);
590   gst_bit_writer_put_bits_uint16 (bs, 12, 16);  //Length of Scan
591   gst_bit_writer_put_bits_uint8 (bs, scan_hdr.num_components, 8);
592
593   for (i = 0; i < scan_hdr.num_components; i++) {
594     gst_bit_writer_put_bits_uint8 (bs,
595         scan_hdr.components[i].component_selector, 8);
596     gst_bit_writer_put_bits_uint8 (bs, scan_hdr.components[i].dc_selector, 4);
597     gst_bit_writer_put_bits_uint8 (bs, scan_hdr.components[i].ac_selector, 4);
598   }
599   gst_bit_writer_put_bits_uint8 (bs, 0, 8);     //0 for Baseline
600   gst_bit_writer_put_bits_uint8 (bs, 63, 8);    //63 for Baseline
601   gst_bit_writer_put_bits_uint8 (bs, 0, 4);     //0 for Baseline
602   gst_bit_writer_put_bits_uint8 (bs, 0, 4);     //0 for Baseline
603
604   return TRUE;
605 }
606
607 static gboolean
608 add_packed_header (GstVaapiEncoderJpeg * encoder, GstVaapiEncPicture * picture)
609 {
610   GstVaapiEncPackedHeader *packed_raw_data_hdr;
611   GstBitWriter bs;
612   VAEncPackedHeaderParameterBuffer packed_raw_data_hdr_param = { 0 };
613   guint32 data_bit_size;
614   guint8 *data;
615
616   gst_bit_writer_init (&bs, 128 * 8);
617   bs_write_jpeg_header (&bs, encoder, picture);
618   data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
619   data = GST_BIT_WRITER_DATA (&bs);
620
621   packed_raw_data_hdr_param.type = VAEncPackedHeaderRawData;
622   packed_raw_data_hdr_param.bit_length = data_bit_size;
623   packed_raw_data_hdr_param.has_emulation_bytes = 0;
624
625   packed_raw_data_hdr =
626       gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
627       &packed_raw_data_hdr_param, sizeof (packed_raw_data_hdr_param), data,
628       (data_bit_size + 7) / 8);
629   g_assert (packed_raw_data_hdr);
630
631   gst_vaapi_enc_picture_add_packed_header (picture, packed_raw_data_hdr);
632   gst_vaapi_codec_object_replace (&packed_raw_data_hdr, NULL);
633
634   gst_bit_writer_clear (&bs, TRUE);
635
636   return TRUE;
637 }
638
639 static gboolean
640 ensure_packed_headers (GstVaapiEncoderJpeg * encoder,
641     GstVaapiEncPicture * picture)
642 {
643   g_assert (picture);
644
645   if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
646           VA_ENC_PACKED_HEADER_RAW_DATA)
647       && !add_packed_header (encoder, picture))
648     goto error_create_packed_hdr;
649
650   return TRUE;
651
652 error_create_packed_hdr:
653   {
654     GST_ERROR ("failed to create packed raw data header buffer");
655     return FALSE;
656   }
657 }
658
659 static GstVaapiEncoderStatus
660 gst_vaapi_encoder_jpeg_encode (GstVaapiEncoder * base_encoder,
661     GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf)
662 {
663   GstVaapiEncoderJpeg *const encoder =
664       GST_VAAPI_ENCODER_JPEG_CAST (base_encoder);
665   GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
666   GstVaapiSurfaceProxy *reconstruct = NULL;
667
668   reconstruct = gst_vaapi_encoder_create_surface (base_encoder);
669
670   g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE (reconstruct));
671
672   if (!ensure_picture (encoder, picture, codedbuf, reconstruct))
673     goto error;
674   if (!ensure_quantization_table (encoder, picture))
675     goto error;
676   if (!ensure_huffman_table (encoder, picture))
677     goto error;
678   if (!ensure_slices (encoder, picture))
679     goto error;
680   if (!ensure_packed_headers (encoder, picture))
681     goto error;
682   if (!gst_vaapi_enc_picture_encode (picture))
683     goto error;
684   if (reconstruct)
685     gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder),
686         reconstruct);
687
688   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
689 error:
690   if (reconstruct)
691     gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder),
692         reconstruct);
693   return ret;
694 }
695
696 static GstVaapiEncoderStatus
697 gst_vaapi_encoder_jpeg_flush (GstVaapiEncoder * base_encoder)
698 {
699   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
700 }
701
702 static GstVaapiEncoderStatus
703 gst_vaapi_encoder_jpeg_reordering (GstVaapiEncoder * base_encoder,
704     GstVideoCodecFrame * frame, GstVaapiEncPicture ** output)
705 {
706   GstVaapiEncoderJpeg *const encoder =
707       GST_VAAPI_ENCODER_JPEG_CAST (base_encoder);
708   GstVaapiEncPicture *picture = NULL;
709   GstVaapiEncoderStatus status = GST_VAAPI_ENCODER_STATUS_SUCCESS;
710
711   if (!frame)
712     return GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
713
714   picture = GST_VAAPI_ENC_PICTURE_NEW (JPEG, encoder, frame);
715   if (!picture) {
716     GST_WARNING ("create JPEG picture failed, frame timestamp:%"
717         GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts));
718     return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
719   }
720
721   *output = picture;
722   return status;
723 }
724
725 static GstVaapiEncoderStatus
726 gst_vaapi_encoder_jpeg_reconfigure (GstVaapiEncoder * base_encoder)
727 {
728   GstVaapiEncoderJpeg *const encoder =
729       GST_VAAPI_ENCODER_JPEG_CAST (base_encoder);
730   GstVaapiEncoderStatus status;
731
732   status = ensure_profile (encoder);
733   if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
734     return status;
735
736   /* generate sampling factors (A.1.1) */
737   generate_sampling_factors (encoder);
738
739   return set_context_info (base_encoder);
740 }
741
742 static gboolean
743 gst_vaapi_encoder_jpeg_init (GstVaapiEncoder * base_encoder)
744 {
745   GstVaapiEncoderJpeg *const encoder =
746       GST_VAAPI_ENCODER_JPEG_CAST (base_encoder);
747
748   encoder->has_quant_tables = FALSE;
749   memset (&encoder->quant_tables, 0, sizeof (encoder->quant_tables));
750   memset (&encoder->scaled_quant_tables, 0,
751       sizeof (encoder->scaled_quant_tables));
752   encoder->has_huff_tables = FALSE;
753   memset (&encoder->huff_tables, 0, sizeof (encoder->huff_tables));
754
755   return TRUE;
756 }
757
758 static void
759 gst_vaapi_encoder_jpeg_finalize (GstVaapiEncoder * base_encoder)
760 {
761 }
762
763 static GstVaapiEncoderStatus
764 gst_vaapi_encoder_jpeg_set_property (GstVaapiEncoder * base_encoder,
765     gint prop_id, const GValue * value)
766 {
767   GstVaapiEncoderJpeg *const encoder =
768       GST_VAAPI_ENCODER_JPEG_CAST (base_encoder);
769
770   switch (prop_id) {
771     case GST_VAAPI_ENCODER_JPEG_PROP_QUALITY:
772       encoder->quality = g_value_get_uint (value);
773       break;
774     default:
775       return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER;
776   }
777   return GST_VAAPI_ENCODER_STATUS_SUCCESS;
778 }
779
780 GST_VAAPI_ENCODER_DEFINE_CLASS_DATA (JPEG);
781
782 static inline const GstVaapiEncoderClass *
783 gst_vaapi_encoder_jpeg_class (void)
784 {
785   static const GstVaapiEncoderClass GstVaapiEncoderJpegClass = {
786     GST_VAAPI_ENCODER_CLASS_INIT (Jpeg, jpeg),
787     .set_property = gst_vaapi_encoder_jpeg_set_property,
788   };
789   return &GstVaapiEncoderJpegClass;
790 }
791
792 /**
793  * gst_vaapi_encoder_jpeg_new:
794  * @display: a #GstVaapiDisplay
795  *
796  * Creates a new #GstVaapiEncoder for JPEG encoding.
797  *
798  * Return value: the newly allocated #GstVaapiEncoder object
799  */
800 GstVaapiEncoder *
801 gst_vaapi_encoder_jpeg_new (GstVaapiDisplay * display)
802 {
803   return gst_vaapi_encoder_new (gst_vaapi_encoder_jpeg_class (), display);
804 }
805
806 /**
807  * gst_vaapi_encoder_jpeg_get_default_properties:
808  *
809  * Determines the set of common and jpeg specific encoder properties.
810  * The caller owns an extra reference to the resulting array of
811  * #GstVaapiEncoderPropInfo elements, so it shall be released with
812  * g_ptr_array_unref() after usage.
813  *
814  * Return value: the set of encoder properties for #GstVaapiEncoderJpeg,
815  *   or %NULL if an error occurred.
816  */
817 GPtrArray *
818 gst_vaapi_encoder_jpeg_get_default_properties (void)
819 {
820   const GstVaapiEncoderClass *const klass = gst_vaapi_encoder_jpeg_class ();
821   GPtrArray *props;
822
823   props = gst_vaapi_encoder_properties_get_default (klass);
824   if (!props)
825     return NULL;
826
827   GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
828       GST_VAAPI_ENCODER_JPEG_PROP_QUALITY,
829       g_param_spec_uint ("quality",
830           "Quality factor",
831           "Quality factor",
832           0, 100, 50, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
833   return props;
834 }