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