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