2 * gstvaapiencoder_jpeg.c - JPEG encoder
4 * Copyright (C) 2015 Intel Corporation
5 * Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
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.
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.
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
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"
35 #include "gstvaapidebug.h"
37 /* Define default rate control mode ("constant-qp") */
38 #define DEFAULT_RATECONTROL GST_VAAPI_RATECONTROL_NONE
40 /* Supported set of VA rate controls, within this implementation */
41 #define SUPPORTED_RATECONTROLS \
42 (GST_VAAPI_RATECONTROL_MASK (NONE))
44 /* Supported set of tuning options, within this implementation */
45 #define SUPPORTED_TUNE_OPTIONS \
46 (GST_VAAPI_ENCODER_TUNE_MASK (NONE))
48 /* Supported set of VA packed headers, within this implementation */
49 #define SUPPORTED_PACKED_HEADERS \
50 (VA_ENC_PACKED_HEADER_RAW_DATA)
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
57 /* ------------------------------------------------------------------------- */
58 /* --- JPEG Encoder --- */
59 /* ------------------------------------------------------------------------- */
61 #define GST_VAAPI_ENCODER_JPEG_CAST(encoder) \
62 ((GstVaapiEncoderJpeg *)(encoder))
64 struct _GstVaapiEncoderJpeg
66 GstVaapiEncoder parent_instance;
67 GstVaapiProfile profile;
69 GstJpegQuantTables quant_tables;
70 GstJpegQuantTables scaled_quant_tables;
71 gboolean has_quant_tables;
72 GstJpegHuffmanTables huff_tables;
73 gboolean has_huff_tables;
74 gint cwidth[GST_VIDEO_MAX_COMPONENTS];
75 gint cheight[GST_VIDEO_MAX_COMPONENTS];
76 gint h_samp[GST_VIDEO_MAX_COMPONENTS];
77 gint v_samp[GST_VIDEO_MAX_COMPONENTS];
83 /* based on upstream gst-plugins-good jpegencoder */
85 generate_sampling_factors (GstVaapiEncoderJpeg * encoder)
90 vinfo = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
92 if (GST_VIDEO_INFO_FORMAT (vinfo) == GST_VIDEO_FORMAT_ENCODED) {
93 /* Use native I420 format */
94 encoder->n_components = 3;
95 for (i = 0; i < encoder->n_components; ++i) {
97 encoder->h_samp[i] = encoder->v_samp[i] = 2;
99 encoder->h_samp[i] = encoder->v_samp[i] = 1;
100 GST_DEBUG ("sampling factors: %d %d", encoder->h_samp[i],
106 encoder->n_components = GST_VIDEO_INFO_N_COMPONENTS (vinfo);
108 encoder->h_max_samp = 0;
109 encoder->v_max_samp = 0;
110 for (i = 0; i < encoder->n_components; ++i) {
111 encoder->cwidth[i] = GST_VIDEO_INFO_COMP_WIDTH (vinfo, i);
112 encoder->cheight[i] = GST_VIDEO_INFO_COMP_HEIGHT (vinfo, i);
114 GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (vinfo)) / encoder->cwidth[i];
115 encoder->h_max_samp = MAX (encoder->h_max_samp, encoder->h_samp[i]);
117 GST_ROUND_UP_4 (GST_VIDEO_INFO_HEIGHT (vinfo)) / encoder->cheight[i];
118 encoder->v_max_samp = MAX (encoder->v_max_samp, encoder->v_samp[i]);
120 /* samp should only be 1, 2 or 4 */
121 g_assert (encoder->h_max_samp <= 4);
122 g_assert (encoder->v_max_samp <= 4);
125 /* maximum is invariant, as one of the components should have samp 1 */
126 for (i = 0; i < encoder->n_components; ++i) {
127 encoder->h_samp[i] = encoder->h_max_samp / encoder->h_samp[i];
128 encoder->v_samp[i] = encoder->v_max_samp / encoder->v_samp[i];
129 GST_DEBUG ("sampling factors: %d %d", encoder->h_samp[i],
134 /* Derives the profile that suits best to the configuration */
135 static GstVaapiEncoderStatus
136 ensure_profile (GstVaapiEncoderJpeg * encoder)
138 /* Always start from "simple" profile for maximum compatibility */
139 encoder->profile = GST_VAAPI_PROFILE_JPEG_BASELINE;
141 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
144 /* Derives the profile supported by the underlying hardware */
146 ensure_hw_profile (GstVaapiEncoderJpeg * encoder)
148 GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder);
149 GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_PICTURE_ENCODE;
150 GstVaapiProfile profile, profiles[2];
151 guint i, num_profiles = 0;
153 profiles[num_profiles++] = encoder->profile;
155 profile = GST_VAAPI_PROFILE_UNKNOWN;
156 for (i = 0; i < num_profiles; i++) {
157 if (gst_vaapi_display_has_encoder (display, profiles[i], entrypoint)) {
158 profile = profiles[i];
162 if (profile == GST_VAAPI_PROFILE_UNKNOWN)
163 goto error_unsupported_profile;
165 GST_VAAPI_ENCODER_CAST (encoder)->profile = profile;
169 error_unsupported_profile:
171 GST_ERROR ("unsupported HW profile (0x%08x)", encoder->profile);
176 static GstVaapiEncoderStatus
177 set_context_info (GstVaapiEncoder * base_encoder)
179 GstVaapiEncoderJpeg *encoder = GST_VAAPI_ENCODER_JPEG_CAST (base_encoder);
180 GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
182 /* Maximum sizes for common headers (in bytes) */
185 MAX_APP_HDR_SIZE = 20,
186 MAX_FRAME_HDR_SIZE = 19,
187 MAX_QUANT_TABLE_SIZE = 138,
188 MAX_HUFFMAN_TABLE_SIZE = 432,
189 MAX_SCAN_HDR_SIZE = 14
192 if (!ensure_hw_profile (encoder))
193 return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
195 base_encoder->num_ref_frames = 0;
197 /* Only YUV 4:2:0 formats are supported for now. */
198 base_encoder->codedbuf_size = GST_ROUND_UP_16 (vip->width) *
199 GST_ROUND_UP_16 (vip->height) * 3 / 2;
201 base_encoder->codedbuf_size += MAX_APP_HDR_SIZE + MAX_FRAME_HDR_SIZE +
202 MAX_QUANT_TABLE_SIZE + MAX_HUFFMAN_TABLE_SIZE + MAX_SCAN_HDR_SIZE;
204 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
208 fill_picture (GstVaapiEncoderJpeg * encoder,
209 GstVaapiEncPicture * picture,
210 GstVaapiCodedBuffer * codedbuf, GstVaapiSurfaceProxy * surface)
212 VAEncPictureParameterBufferJPEG *const pic_param = picture->param;
214 memset (pic_param, 0, sizeof (VAEncPictureParameterBufferJPEG));
216 pic_param->reconstructed_picture =
217 GST_VAAPI_SURFACE_PROXY_SURFACE_ID (surface);
218 pic_param->picture_width = GST_VAAPI_ENCODER_WIDTH (encoder);
219 pic_param->picture_height = GST_VAAPI_ENCODER_HEIGHT (encoder);
220 pic_param->coded_buf = GST_VAAPI_OBJECT_ID (codedbuf);
222 pic_param->pic_flags.bits.profile = 0; /* Profile = Baseline */
223 pic_param->pic_flags.bits.progressive = 0; /* Sequential encoding */
224 pic_param->pic_flags.bits.huffman = 1; /* Uses Huffman coding */
225 pic_param->pic_flags.bits.interleaved = 0; /* Input format is non interleaved (YUV) */
226 pic_param->pic_flags.bits.differential = 0; /* non-Differential Encoding */
227 pic_param->sample_bit_depth = 8;
228 pic_param->num_scan = 1;
229 pic_param->num_components = encoder->n_components;
230 pic_param->quality = encoder->quality;
235 ensure_picture (GstVaapiEncoderJpeg * encoder, GstVaapiEncPicture * picture,
236 GstVaapiCodedBufferProxy * codedbuf_proxy, GstVaapiSurfaceProxy * surface)
238 GstVaapiCodedBuffer *const codedbuf =
239 GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy);
241 if (!fill_picture (encoder, picture, codedbuf, surface))
247 /* This is a work-around: Normalize the quality factor and scale QM
248 * values similar to what VA-Intel driver is doing. Otherwise the
249 * generated packed headers will be wrong, since the driver itself
250 * is scaling the QM values using the normalized quality factor */
252 generate_scaled_qm (GstJpegQuantTables * quant_tables,
253 GstJpegQuantTables * scaled_quant_tables, guint quality)
255 guint qt_val, nm_quality, i;
256 nm_quality = quality == 0 ? 1 : quality;
258 (nm_quality < 50) ? (5000 / nm_quality) : (200 - (nm_quality * 2));
260 g_assert (quant_tables != NULL);
261 g_assert (scaled_quant_tables != NULL);
263 for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) {
265 qt_val = (quant_tables->quant_tables[0].quant_table[i] * nm_quality) / 100;
266 scaled_quant_tables->quant_tables[0].quant_table[i] =
267 CLAMP (qt_val, 1, 255);
269 qt_val = (quant_tables->quant_tables[1].quant_table[i] * nm_quality) / 100;
270 scaled_quant_tables->quant_tables[1].quant_table[i] =
271 CLAMP (qt_val, 1, 255);
276 fill_quantization_table (GstVaapiEncoderJpeg * encoder,
277 GstVaapiEncPicture * picture)
279 VAQMatrixBufferJPEG *q_matrix;
284 picture->q_matrix = GST_VAAPI_ENC_Q_MATRIX_NEW (JPEG, encoder);
285 if (!picture->q_matrix) {
286 GST_ERROR ("failed to allocate quantiser table");
287 return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
289 q_matrix = picture->q_matrix->param;
291 if (!encoder->has_quant_tables) {
292 gst_jpeg_get_default_quantization_tables (&encoder->quant_tables);
293 encoder->has_quant_tables = TRUE;
294 generate_scaled_qm (&encoder->quant_tables, &encoder->scaled_quant_tables,
297 q_matrix->load_lum_quantiser_matrix = 1;
298 for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) {
299 q_matrix->lum_quantiser_matrix[i] =
300 encoder->quant_tables.quant_tables[0].quant_table[i];
303 q_matrix->load_chroma_quantiser_matrix = 1;
304 for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) {
305 q_matrix->chroma_quantiser_matrix[i] =
306 encoder->quant_tables.quant_tables[1].quant_table[i];
313 ensure_quantization_table (GstVaapiEncoderJpeg * encoder,
314 GstVaapiEncPicture * picture)
318 if (!fill_quantization_table (encoder, picture))
325 fill_huffman_table (GstVaapiEncoderJpeg * encoder, GstVaapiEncPicture * picture)
327 VAHuffmanTableBufferJPEGBaseline *huffman_table;
332 picture->huf_table = GST_VAAPI_ENC_HUFFMAN_TABLE_NEW (JPEGBaseline, encoder);
333 if (!picture->huf_table) {
334 GST_ERROR ("failed to allocate Huffman tables");
335 return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
337 huffman_table = picture->huf_table->param;
339 num_tables = MIN (G_N_ELEMENTS (huffman_table->huffman_table),
340 GST_JPEG_MAX_SCAN_COMPONENTS);
342 if (!encoder->has_huff_tables) {
343 gst_jpeg_get_default_huffman_tables (&encoder->huff_tables);
344 encoder->has_huff_tables = TRUE;
347 for (i = 0; i < num_tables; i++) {
348 huffman_table->load_huffman_table[i] =
349 encoder->huff_tables.dc_tables[i].valid
350 && encoder->huff_tables.ac_tables[i].valid;
351 if (!huffman_table->load_huffman_table[i])
354 memcpy (huffman_table->huffman_table[i].num_dc_codes,
355 encoder->huff_tables.dc_tables[i].huf_bits,
356 sizeof (huffman_table->huffman_table[i].num_dc_codes));
357 memcpy (huffman_table->huffman_table[i].dc_values,
358 encoder->huff_tables.dc_tables[i].huf_values,
359 sizeof (huffman_table->huffman_table[i].dc_values));
360 memcpy (huffman_table->huffman_table[i].num_ac_codes,
361 encoder->huff_tables.ac_tables[i].huf_bits,
362 sizeof (huffman_table->huffman_table[i].num_ac_codes));
363 memcpy (huffman_table->huffman_table[i].ac_values,
364 encoder->huff_tables.ac_tables[i].huf_values,
365 sizeof (huffman_table->huffman_table[i].ac_values));
366 memset (huffman_table->huffman_table[i].pad,
367 0, sizeof (huffman_table->huffman_table[i].pad));
374 ensure_huffman_table (GstVaapiEncoderJpeg * encoder,
375 GstVaapiEncPicture * picture)
379 if (!fill_huffman_table (encoder, picture))
386 fill_slices (GstVaapiEncoderJpeg * encoder, GstVaapiEncPicture * picture)
388 VAEncSliceParameterBufferJPEG *slice_param;
389 GstVaapiEncSlice *slice;
390 VAEncPictureParameterBufferJPEG *const pic_param = picture->param;
392 slice = GST_VAAPI_ENC_SLICE_NEW (JPEG, encoder);
393 g_assert (slice && slice->param_id != VA_INVALID_ID);
394 slice_param = slice->param;
396 slice_param->restart_interval = 0;
397 slice_param->num_components = pic_param->num_components;
399 slice_param->components[0].component_selector = 1;
400 slice_param->components[0].dc_table_selector = 0;
401 slice_param->components[0].ac_table_selector = 0;
403 slice_param->components[1].component_selector = 2;
404 slice_param->components[1].dc_table_selector = 1;
405 slice_param->components[1].ac_table_selector = 1;
407 slice_param->components[2].component_selector = 3;
408 slice_param->components[2].dc_table_selector = 1;
409 slice_param->components[2].ac_table_selector = 1;
411 gst_vaapi_enc_picture_add_slice (picture, slice);
412 gst_vaapi_codec_object_replace (&slice, NULL);
418 ensure_slices (GstVaapiEncoderJpeg * encoder, GstVaapiEncPicture * picture)
422 if (!fill_slices (encoder, picture))
429 generate_frame_hdr (GstJpegFrameHdr * frame_hdr, GstVaapiEncoderJpeg * encoder,
430 GstVaapiEncPicture * picture)
432 VAEncPictureParameterBufferJPEG *const pic_param = picture->param;
435 memset (frame_hdr, 0, sizeof (GstJpegFrameHdr));
436 frame_hdr->sample_precision = 8;
437 frame_hdr->width = pic_param->picture_width;
438 frame_hdr->height = pic_param->picture_height;
439 frame_hdr->num_components = pic_param->num_components;
441 for (i = 0; i < frame_hdr->num_components; i++) {
442 frame_hdr->components[i].identifier = i + 1;
443 frame_hdr->components[i].horizontal_factor = encoder->h_samp[i];
444 frame_hdr->components[i].vertical_factor = encoder->v_samp[i];
446 frame_hdr->components[i].quant_table_selector = 0;
448 frame_hdr->components[i].quant_table_selector = 1;
453 generate_scan_hdr (GstJpegScanHdr * scan_hdr, GstVaapiEncPicture * picture)
456 VAEncPictureParameterBufferJPEG *const pic_param = picture->param;
458 memset (scan_hdr, 0, sizeof (GstJpegScanHdr));
459 scan_hdr->num_components = pic_param->num_components;
461 scan_hdr->components[0].component_selector = 1;
462 scan_hdr->components[0].dc_selector = 0;
463 scan_hdr->components[0].ac_selector = 0;
467 scan_hdr->components[1].component_selector = 2;
468 scan_hdr->components[1].dc_selector = 1;
469 scan_hdr->components[1].ac_selector = 1;
472 scan_hdr->components[2].component_selector = 3;
473 scan_hdr->components[2].dc_selector = 1;
474 scan_hdr->components[2].ac_selector = 1;
478 bs_write_jpeg_header (GstBitWriter * bs, GstVaapiEncoderJpeg * encoder,
479 GstVaapiEncPicture * picture)
481 GstJpegFrameHdr frame_hdr;
482 GstJpegScanHdr scan_hdr;
485 gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
486 gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_SOI, 8);
487 gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
488 gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_APP_MIN, 8);
489 gst_bit_writer_put_bits_uint16 (bs, 16, 16);
490 gst_bit_writer_put_bits_uint8 (bs, 0x4A, 8); //J
491 gst_bit_writer_put_bits_uint8 (bs, 0x46, 8); //F
492 gst_bit_writer_put_bits_uint8 (bs, 0x49, 8); //I
493 gst_bit_writer_put_bits_uint8 (bs, 0x46, 8); //F
494 gst_bit_writer_put_bits_uint8 (bs, 0x00, 8); //0
495 gst_bit_writer_put_bits_uint8 (bs, 1, 8); //Major Version
496 gst_bit_writer_put_bits_uint8 (bs, 1, 8); //Minor Version
497 gst_bit_writer_put_bits_uint8 (bs, 0, 8); //Density units 0:no units, 1:pixels per inch, 2: pixels per cm
498 gst_bit_writer_put_bits_uint16 (bs, 1, 16); //X density (pixel-aspect-ratio)
499 gst_bit_writer_put_bits_uint16 (bs, 1, 16); //Y density (pixel-aspect-ratio)
500 gst_bit_writer_put_bits_uint8 (bs, 0, 8); //Thumbnail width
501 gst_bit_writer_put_bits_uint8 (bs, 0, 8); //Thumbnail height
503 /* Add quantization table */
504 if (!encoder->has_quant_tables) {
505 gst_jpeg_get_default_quantization_tables (&encoder->quant_tables);
506 generate_scaled_qm (&encoder->quant_tables, &encoder->scaled_quant_tables,
508 encoder->has_quant_tables = TRUE;
511 gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
512 gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_DQT, 8);
513 gst_bit_writer_put_bits_uint16 (bs, 3 + GST_JPEG_MAX_QUANT_ELEMENTS, 16); //Lq
514 gst_bit_writer_put_bits_uint8 (bs, encoder->quant_tables.quant_tables[0].quant_precision, 4); //Pq
515 gst_bit_writer_put_bits_uint8 (bs, 0, 4); //Tq
516 for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) {
517 gst_bit_writer_put_bits_uint16 (bs,
518 encoder->scaled_quant_tables.quant_tables[0].quant_table[i], 8);
520 gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
521 gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_DQT, 8);
522 gst_bit_writer_put_bits_uint16 (bs, 3 + GST_JPEG_MAX_QUANT_ELEMENTS, 16); //Lq
523 gst_bit_writer_put_bits_uint8 (bs, encoder->quant_tables.quant_tables[1].quant_precision, 4); //Pq
524 gst_bit_writer_put_bits_uint8 (bs, 1, 4); //Tq
525 for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) {
526 gst_bit_writer_put_bits_uint16 (bs,
527 encoder->scaled_quant_tables.quant_tables[1].quant_table[i], 8);
530 /*Add frame header */
531 generate_frame_hdr (&frame_hdr, encoder, picture);
532 gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
533 gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_SOF_MIN, 8);
534 gst_bit_writer_put_bits_uint16 (bs, 8 + (3 * 3), 16); //lf, Size of FrameHeader in bytes without the Marker SOF
535 gst_bit_writer_put_bits_uint8 (bs, frame_hdr.sample_precision, 8);
536 gst_bit_writer_put_bits_uint16 (bs, frame_hdr.height, 16);
537 gst_bit_writer_put_bits_uint16 (bs, frame_hdr.width, 16);
538 gst_bit_writer_put_bits_uint8 (bs, frame_hdr.num_components, 8);
539 for (i = 0; i < frame_hdr.num_components; i++) {
540 gst_bit_writer_put_bits_uint8 (bs, frame_hdr.components[i].identifier, 8);
541 gst_bit_writer_put_bits_uint8 (bs,
542 frame_hdr.components[i].horizontal_factor, 4);
543 gst_bit_writer_put_bits_uint8 (bs, frame_hdr.components[i].vertical_factor,
545 gst_bit_writer_put_bits_uint8 (bs,
546 frame_hdr.components[i].quant_table_selector, 8);
549 /* Add Huffman table */
550 if (!encoder->has_huff_tables) {
551 gst_jpeg_get_default_huffman_tables (&encoder->huff_tables);
552 encoder->has_huff_tables = TRUE;
554 for (i = 0; i < 2; i++) {
555 gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
556 gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_DHT, 8);
557 gst_bit_writer_put_bits_uint16 (bs, 0x1F, 16); //length of table
558 gst_bit_writer_put_bits_uint8 (bs, 0, 4);
559 gst_bit_writer_put_bits_uint8 (bs, i, 4);
560 for (j = 0; j < NUM_DC_RUN_SIZE_BITS; j++) {
561 gst_bit_writer_put_bits_uint8 (bs,
562 encoder->huff_tables.dc_tables[i].huf_bits[j], 8);
565 for (j = 0; j < NUM_DC_CODE_WORDS_HUFFVAL; j++) {
566 gst_bit_writer_put_bits_uint8 (bs,
567 encoder->huff_tables.dc_tables[i].huf_values[j], 8);
570 gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
571 gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_DHT, 8);
572 gst_bit_writer_put_bits_uint16 (bs, 0xB5, 16); //length of table
573 gst_bit_writer_put_bits_uint8 (bs, 1, 4);
574 gst_bit_writer_put_bits_uint8 (bs, i, 4);
575 for (j = 0; j < NUM_AC_RUN_SIZE_BITS; j++) {
576 gst_bit_writer_put_bits_uint8 (bs,
577 encoder->huff_tables.ac_tables[i].huf_bits[j], 8);
580 for (j = 0; j < NUM_AC_CODE_WORDS_HUFFVAL; j++) {
581 gst_bit_writer_put_bits_uint8 (bs,
582 encoder->huff_tables.ac_tables[i].huf_values[j], 8);
587 generate_scan_hdr (&scan_hdr, picture);
588 gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
589 gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_SOS, 8);
590 gst_bit_writer_put_bits_uint16 (bs, 12, 16); //Length of Scan
591 gst_bit_writer_put_bits_uint8 (bs, scan_hdr.num_components, 8);
593 for (i = 0; i < scan_hdr.num_components; i++) {
594 gst_bit_writer_put_bits_uint8 (bs,
595 scan_hdr.components[i].component_selector, 8);
596 gst_bit_writer_put_bits_uint8 (bs, scan_hdr.components[i].dc_selector, 4);
597 gst_bit_writer_put_bits_uint8 (bs, scan_hdr.components[i].ac_selector, 4);
599 gst_bit_writer_put_bits_uint8 (bs, 0, 8); //0 for Baseline
600 gst_bit_writer_put_bits_uint8 (bs, 63, 8); //63 for Baseline
601 gst_bit_writer_put_bits_uint8 (bs, 0, 4); //0 for Baseline
602 gst_bit_writer_put_bits_uint8 (bs, 0, 4); //0 for Baseline
608 add_packed_header (GstVaapiEncoderJpeg * encoder, GstVaapiEncPicture * picture)
610 GstVaapiEncPackedHeader *packed_raw_data_hdr;
612 VAEncPackedHeaderParameterBuffer packed_raw_data_hdr_param = { 0 };
613 guint32 data_bit_size;
616 gst_bit_writer_init (&bs, 128 * 8);
617 bs_write_jpeg_header (&bs, encoder, picture);
618 data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
619 data = GST_BIT_WRITER_DATA (&bs);
621 packed_raw_data_hdr_param.type = VAEncPackedHeaderRawData;
622 packed_raw_data_hdr_param.bit_length = data_bit_size;
623 packed_raw_data_hdr_param.has_emulation_bytes = 0;
625 packed_raw_data_hdr =
626 gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
627 &packed_raw_data_hdr_param, sizeof (packed_raw_data_hdr_param), data,
628 (data_bit_size + 7) / 8);
629 g_assert (packed_raw_data_hdr);
631 gst_vaapi_enc_picture_add_packed_header (picture, packed_raw_data_hdr);
632 gst_vaapi_codec_object_replace (&packed_raw_data_hdr, NULL);
634 gst_bit_writer_clear (&bs, TRUE);
640 ensure_packed_headers (GstVaapiEncoderJpeg * encoder,
641 GstVaapiEncPicture * picture)
645 if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
646 VA_ENC_PACKED_HEADER_RAW_DATA)
647 && !add_packed_header (encoder, picture))
648 goto error_create_packed_hdr;
652 error_create_packed_hdr:
654 GST_ERROR ("failed to create packed raw data header buffer");
659 static GstVaapiEncoderStatus
660 gst_vaapi_encoder_jpeg_encode (GstVaapiEncoder * base_encoder,
661 GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf)
663 GstVaapiEncoderJpeg *const encoder =
664 GST_VAAPI_ENCODER_JPEG_CAST (base_encoder);
665 GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
666 GstVaapiSurfaceProxy *reconstruct = NULL;
668 reconstruct = gst_vaapi_encoder_create_surface (base_encoder);
670 g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE (reconstruct));
672 if (!ensure_picture (encoder, picture, codedbuf, reconstruct))
674 if (!ensure_quantization_table (encoder, picture))
676 if (!ensure_huffman_table (encoder, picture))
678 if (!ensure_slices (encoder, picture))
680 if (!ensure_packed_headers (encoder, picture))
682 if (!gst_vaapi_enc_picture_encode (picture))
685 gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder),
688 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
691 gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder),
696 static GstVaapiEncoderStatus
697 gst_vaapi_encoder_jpeg_flush (GstVaapiEncoder * base_encoder)
699 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
702 static GstVaapiEncoderStatus
703 gst_vaapi_encoder_jpeg_reordering (GstVaapiEncoder * base_encoder,
704 GstVideoCodecFrame * frame, GstVaapiEncPicture ** output)
706 GstVaapiEncoderJpeg *const encoder =
707 GST_VAAPI_ENCODER_JPEG_CAST (base_encoder);
708 GstVaapiEncPicture *picture = NULL;
709 GstVaapiEncoderStatus status = GST_VAAPI_ENCODER_STATUS_SUCCESS;
712 return GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
714 picture = GST_VAAPI_ENC_PICTURE_NEW (JPEG, encoder, frame);
716 GST_WARNING ("create JPEG picture failed, frame timestamp:%"
717 GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts));
718 return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
725 static GstVaapiEncoderStatus
726 gst_vaapi_encoder_jpeg_reconfigure (GstVaapiEncoder * base_encoder)
728 GstVaapiEncoderJpeg *const encoder =
729 GST_VAAPI_ENCODER_JPEG_CAST (base_encoder);
730 GstVaapiEncoderStatus status;
732 status = ensure_profile (encoder);
733 if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
736 /* generate sampling factors (A.1.1) */
737 generate_sampling_factors (encoder);
739 return set_context_info (base_encoder);
743 gst_vaapi_encoder_jpeg_init (GstVaapiEncoder * base_encoder)
745 GstVaapiEncoderJpeg *const encoder =
746 GST_VAAPI_ENCODER_JPEG_CAST (base_encoder);
748 encoder->has_quant_tables = FALSE;
749 memset (&encoder->quant_tables, 0, sizeof (encoder->quant_tables));
750 memset (&encoder->scaled_quant_tables, 0,
751 sizeof (encoder->scaled_quant_tables));
752 encoder->has_huff_tables = FALSE;
753 memset (&encoder->huff_tables, 0, sizeof (encoder->huff_tables));
759 gst_vaapi_encoder_jpeg_finalize (GstVaapiEncoder * base_encoder)
763 static GstVaapiEncoderStatus
764 gst_vaapi_encoder_jpeg_set_property (GstVaapiEncoder * base_encoder,
765 gint prop_id, const GValue * value)
767 GstVaapiEncoderJpeg *const encoder =
768 GST_VAAPI_ENCODER_JPEG_CAST (base_encoder);
771 case GST_VAAPI_ENCODER_JPEG_PROP_QUALITY:
772 encoder->quality = g_value_get_uint (value);
775 return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER;
777 return GST_VAAPI_ENCODER_STATUS_SUCCESS;
780 GST_VAAPI_ENCODER_DEFINE_CLASS_DATA (JPEG);
782 static inline const GstVaapiEncoderClass *
783 gst_vaapi_encoder_jpeg_class (void)
785 static const GstVaapiEncoderClass GstVaapiEncoderJpegClass = {
786 GST_VAAPI_ENCODER_CLASS_INIT (Jpeg, jpeg),
787 .set_property = gst_vaapi_encoder_jpeg_set_property,
789 return &GstVaapiEncoderJpegClass;
793 * gst_vaapi_encoder_jpeg_new:
794 * @display: a #GstVaapiDisplay
796 * Creates a new #GstVaapiEncoder for JPEG encoding.
798 * Return value: the newly allocated #GstVaapiEncoder object
801 gst_vaapi_encoder_jpeg_new (GstVaapiDisplay * display)
803 return gst_vaapi_encoder_new (gst_vaapi_encoder_jpeg_class (), display);
807 * gst_vaapi_encoder_jpeg_get_default_properties:
809 * Determines the set of common and jpeg specific encoder properties.
810 * The caller owns an extra reference to the resulting array of
811 * #GstVaapiEncoderPropInfo elements, so it shall be released with
812 * g_ptr_array_unref() after usage.
814 * Return value: the set of encoder properties for #GstVaapiEncoderJpeg,
815 * or %NULL if an error occurred.
818 gst_vaapi_encoder_jpeg_get_default_properties (void)
820 const GstVaapiEncoderClass *const klass = gst_vaapi_encoder_jpeg_class ();
823 props = gst_vaapi_encoder_properties_get_default (klass);
827 GST_VAAPI_ENCODER_PROPERTIES_APPEND (props,
828 GST_VAAPI_ENCODER_JPEG_PROP_QUALITY,
829 g_param_spec_uint ("quality",
832 0, 100, 50, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));