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