1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * This file is part of FFmpeg. 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 5cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 6cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 7cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 8cabdff1aSopenharmony_ci * 9cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 10cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 11cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12cabdff1aSopenharmony_ci * Lesser General Public License for more details. 13cabdff1aSopenharmony_ci * 14cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 15cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 16cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17cabdff1aSopenharmony_ci */ 18cabdff1aSopenharmony_ci 19cabdff1aSopenharmony_ci#include <va/va.h> 20cabdff1aSopenharmony_ci#include <va/va_enc_jpeg.h> 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci#include "libavutil/avassert.h" 23cabdff1aSopenharmony_ci#include "libavutil/common.h" 24cabdff1aSopenharmony_ci#include "libavutil/internal.h" 25cabdff1aSopenharmony_ci#include "libavutil/opt.h" 26cabdff1aSopenharmony_ci#include "libavutil/pixdesc.h" 27cabdff1aSopenharmony_ci 28cabdff1aSopenharmony_ci#include "avcodec.h" 29cabdff1aSopenharmony_ci#include "bytestream.h" 30cabdff1aSopenharmony_ci#include "cbs.h" 31cabdff1aSopenharmony_ci#include "cbs_jpeg.h" 32cabdff1aSopenharmony_ci#include "codec_internal.h" 33cabdff1aSopenharmony_ci#include "jpegtables.h" 34cabdff1aSopenharmony_ci#include "mjpeg.h" 35cabdff1aSopenharmony_ci#include "put_bits.h" 36cabdff1aSopenharmony_ci#include "vaapi_encode.h" 37cabdff1aSopenharmony_ci 38cabdff1aSopenharmony_ci 39cabdff1aSopenharmony_ci// Standard JPEG quantisation tables, in zigzag order. 40cabdff1aSopenharmony_cistatic const unsigned char vaapi_encode_mjpeg_quant_luminance[64] = { 41cabdff1aSopenharmony_ci 16, 11, 12, 14, 12, 10, 16, 14, 42cabdff1aSopenharmony_ci 13, 14, 18, 17, 16, 19, 24, 40, 43cabdff1aSopenharmony_ci 26, 24, 22, 22, 24, 49, 35, 37, 44cabdff1aSopenharmony_ci 29, 40, 58, 51, 61, 60, 57, 51, 45cabdff1aSopenharmony_ci 56, 55, 64, 72, 92, 78, 64, 68, 46cabdff1aSopenharmony_ci 87, 69, 55, 56, 80, 109, 81, 87, 47cabdff1aSopenharmony_ci 95, 98, 103, 104, 103, 62, 77, 113, 48cabdff1aSopenharmony_ci 121, 112, 100, 120, 92, 101, 103, 99, 49cabdff1aSopenharmony_ci}; 50cabdff1aSopenharmony_cistatic const unsigned char vaapi_encode_mjpeg_quant_chrominance[64] = { 51cabdff1aSopenharmony_ci 17, 18, 18, 24, 21, 24, 47, 26, 52cabdff1aSopenharmony_ci 26, 47, 99, 66, 56, 66, 99, 99, 53cabdff1aSopenharmony_ci 99, 99, 99, 99, 99, 99, 99, 99, 54cabdff1aSopenharmony_ci 99, 99, 99, 99, 99, 99, 99, 99, 55cabdff1aSopenharmony_ci 99, 99, 99, 99, 99, 99, 99, 99, 56cabdff1aSopenharmony_ci 99, 99, 99, 99, 99, 99, 99, 99, 57cabdff1aSopenharmony_ci 99, 99, 99, 99, 99, 99, 99, 99, 58cabdff1aSopenharmony_ci 99, 99, 99, 99, 99, 99, 99, 99, 59cabdff1aSopenharmony_ci}; 60cabdff1aSopenharmony_ci 61cabdff1aSopenharmony_citypedef struct VAAPIEncodeMJPEGContext { 62cabdff1aSopenharmony_ci VAAPIEncodeContext common; 63cabdff1aSopenharmony_ci 64cabdff1aSopenharmony_ci // User options. 65cabdff1aSopenharmony_ci int jfif; 66cabdff1aSopenharmony_ci int huffman; 67cabdff1aSopenharmony_ci 68cabdff1aSopenharmony_ci // Derived settings. 69cabdff1aSopenharmony_ci int quality; 70cabdff1aSopenharmony_ci uint8_t jfif_data[14]; 71cabdff1aSopenharmony_ci 72cabdff1aSopenharmony_ci // Writer structures. 73cabdff1aSopenharmony_ci JPEGRawFrameHeader frame_header; 74cabdff1aSopenharmony_ci JPEGRawScan scan; 75cabdff1aSopenharmony_ci JPEGRawApplicationData jfif_header; 76cabdff1aSopenharmony_ci JPEGRawQuantisationTableSpecification quant_tables; 77cabdff1aSopenharmony_ci JPEGRawHuffmanTableSpecification huffman_tables; 78cabdff1aSopenharmony_ci 79cabdff1aSopenharmony_ci CodedBitstreamContext *cbc; 80cabdff1aSopenharmony_ci CodedBitstreamFragment current_fragment; 81cabdff1aSopenharmony_ci} VAAPIEncodeMJPEGContext; 82cabdff1aSopenharmony_ci 83cabdff1aSopenharmony_cistatic int vaapi_encode_mjpeg_write_image_header(AVCodecContext *avctx, 84cabdff1aSopenharmony_ci VAAPIEncodePicture *pic, 85cabdff1aSopenharmony_ci VAAPIEncodeSlice *slice, 86cabdff1aSopenharmony_ci char *data, size_t *data_len) 87cabdff1aSopenharmony_ci{ 88cabdff1aSopenharmony_ci VAAPIEncodeMJPEGContext *priv = avctx->priv_data; 89cabdff1aSopenharmony_ci CodedBitstreamFragment *frag = &priv->current_fragment; 90cabdff1aSopenharmony_ci int err; 91cabdff1aSopenharmony_ci 92cabdff1aSopenharmony_ci if (priv->jfif) { 93cabdff1aSopenharmony_ci err = ff_cbs_insert_unit_content(frag, -1, 94cabdff1aSopenharmony_ci JPEG_MARKER_APPN + 0, 95cabdff1aSopenharmony_ci &priv->jfif_header, NULL); 96cabdff1aSopenharmony_ci if (err < 0) 97cabdff1aSopenharmony_ci goto fail; 98cabdff1aSopenharmony_ci } 99cabdff1aSopenharmony_ci 100cabdff1aSopenharmony_ci err = ff_cbs_insert_unit_content(frag, -1, 101cabdff1aSopenharmony_ci JPEG_MARKER_DQT, 102cabdff1aSopenharmony_ci &priv->quant_tables, NULL); 103cabdff1aSopenharmony_ci if (err < 0) 104cabdff1aSopenharmony_ci goto fail; 105cabdff1aSopenharmony_ci 106cabdff1aSopenharmony_ci err = ff_cbs_insert_unit_content(frag, -1, 107cabdff1aSopenharmony_ci JPEG_MARKER_SOF0, 108cabdff1aSopenharmony_ci &priv->frame_header, NULL); 109cabdff1aSopenharmony_ci if (err < 0) 110cabdff1aSopenharmony_ci goto fail; 111cabdff1aSopenharmony_ci 112cabdff1aSopenharmony_ci if (priv->huffman) { 113cabdff1aSopenharmony_ci err = ff_cbs_insert_unit_content(frag, -1, 114cabdff1aSopenharmony_ci JPEG_MARKER_DHT, 115cabdff1aSopenharmony_ci &priv->huffman_tables, NULL); 116cabdff1aSopenharmony_ci if (err < 0) 117cabdff1aSopenharmony_ci goto fail; 118cabdff1aSopenharmony_ci } 119cabdff1aSopenharmony_ci 120cabdff1aSopenharmony_ci err = ff_cbs_insert_unit_content(frag, -1, 121cabdff1aSopenharmony_ci JPEG_MARKER_SOS, 122cabdff1aSopenharmony_ci &priv->scan, NULL); 123cabdff1aSopenharmony_ci if (err < 0) 124cabdff1aSopenharmony_ci goto fail; 125cabdff1aSopenharmony_ci 126cabdff1aSopenharmony_ci err = ff_cbs_write_fragment_data(priv->cbc, frag); 127cabdff1aSopenharmony_ci if (err < 0) { 128cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Failed to write image header.\n"); 129cabdff1aSopenharmony_ci goto fail; 130cabdff1aSopenharmony_ci } 131cabdff1aSopenharmony_ci 132cabdff1aSopenharmony_ci if (*data_len < 8 * frag->data_size) { 133cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Image header too large: " 134cabdff1aSopenharmony_ci "%zu < %zu.\n", *data_len, 8 * frag->data_size); 135cabdff1aSopenharmony_ci err = AVERROR(ENOSPC); 136cabdff1aSopenharmony_ci goto fail; 137cabdff1aSopenharmony_ci } 138cabdff1aSopenharmony_ci 139cabdff1aSopenharmony_ci // Remove the EOI at the end of the fragment. 140cabdff1aSopenharmony_ci memcpy(data, frag->data, frag->data_size - 2); 141cabdff1aSopenharmony_ci *data_len = 8 * (frag->data_size - 2); 142cabdff1aSopenharmony_ci 143cabdff1aSopenharmony_ci err = 0; 144cabdff1aSopenharmony_cifail: 145cabdff1aSopenharmony_ci ff_cbs_fragment_reset(frag); 146cabdff1aSopenharmony_ci return err; 147cabdff1aSopenharmony_ci} 148cabdff1aSopenharmony_ci 149cabdff1aSopenharmony_cistatic int vaapi_encode_mjpeg_write_extra_buffer(AVCodecContext *avctx, 150cabdff1aSopenharmony_ci VAAPIEncodePicture *pic, 151cabdff1aSopenharmony_ci int index, int *type, 152cabdff1aSopenharmony_ci char *data, size_t *data_len) 153cabdff1aSopenharmony_ci{ 154cabdff1aSopenharmony_ci VAAPIEncodeMJPEGContext *priv = avctx->priv_data; 155cabdff1aSopenharmony_ci int t, i, k; 156cabdff1aSopenharmony_ci 157cabdff1aSopenharmony_ci if (index == 0) { 158cabdff1aSopenharmony_ci // Write quantisation tables. 159cabdff1aSopenharmony_ci JPEGRawFrameHeader *fh = &priv->frame_header; 160cabdff1aSopenharmony_ci JPEGRawQuantisationTableSpecification *dqt = &priv->quant_tables; 161cabdff1aSopenharmony_ci VAQMatrixBufferJPEG *quant; 162cabdff1aSopenharmony_ci 163cabdff1aSopenharmony_ci if (*data_len < sizeof(*quant)) 164cabdff1aSopenharmony_ci return AVERROR(ENOSPC); 165cabdff1aSopenharmony_ci *type = VAQMatrixBufferType; 166cabdff1aSopenharmony_ci *data_len = sizeof(*quant); 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_ci quant = (VAQMatrixBufferJPEG*)data; 169cabdff1aSopenharmony_ci memset(quant, 0, sizeof(*quant)); 170cabdff1aSopenharmony_ci 171cabdff1aSopenharmony_ci quant->load_lum_quantiser_matrix = 1; 172cabdff1aSopenharmony_ci for (i = 0; i < 64; i++) 173cabdff1aSopenharmony_ci quant->lum_quantiser_matrix[i] = dqt->table[fh->Tq[0]].Q[i]; 174cabdff1aSopenharmony_ci 175cabdff1aSopenharmony_ci if (fh->Nf > 1) { 176cabdff1aSopenharmony_ci quant->load_chroma_quantiser_matrix = 1; 177cabdff1aSopenharmony_ci for (i = 0; i < 64; i++) 178cabdff1aSopenharmony_ci quant->chroma_quantiser_matrix[i] = 179cabdff1aSopenharmony_ci dqt->table[fh->Tq[1]].Q[i]; 180cabdff1aSopenharmony_ci } 181cabdff1aSopenharmony_ci 182cabdff1aSopenharmony_ci } else if (index == 1) { 183cabdff1aSopenharmony_ci // Write huffman tables. 184cabdff1aSopenharmony_ci JPEGRawScanHeader *sh = &priv->scan.header; 185cabdff1aSopenharmony_ci JPEGRawHuffmanTableSpecification *dht = &priv->huffman_tables; 186cabdff1aSopenharmony_ci VAHuffmanTableBufferJPEGBaseline *huff; 187cabdff1aSopenharmony_ci 188cabdff1aSopenharmony_ci if (*data_len < sizeof(*huff)) 189cabdff1aSopenharmony_ci return AVERROR(ENOSPC); 190cabdff1aSopenharmony_ci *type = VAHuffmanTableBufferType; 191cabdff1aSopenharmony_ci *data_len = sizeof(*huff); 192cabdff1aSopenharmony_ci 193cabdff1aSopenharmony_ci huff = (VAHuffmanTableBufferJPEGBaseline*)data; 194cabdff1aSopenharmony_ci memset(huff, 0, sizeof(*huff)); 195cabdff1aSopenharmony_ci 196cabdff1aSopenharmony_ci for (t = 0; t < 1 + (sh->Ns > 1); t++) { 197cabdff1aSopenharmony_ci const JPEGRawHuffmanTable *ht; 198cabdff1aSopenharmony_ci 199cabdff1aSopenharmony_ci huff->load_huffman_table[t] = 1; 200cabdff1aSopenharmony_ci 201cabdff1aSopenharmony_ci ht = &dht->table[2 * t]; 202cabdff1aSopenharmony_ci for (i = k = 0; i < 16; i++) 203cabdff1aSopenharmony_ci k += (huff->huffman_table[t].num_dc_codes[i] = ht->L[i]); 204cabdff1aSopenharmony_ci av_assert0(k <= sizeof(huff->huffman_table[t].dc_values)); 205cabdff1aSopenharmony_ci for (i = 0; i < k; i++) 206cabdff1aSopenharmony_ci huff->huffman_table[t].dc_values[i] = ht->V[i]; 207cabdff1aSopenharmony_ci 208cabdff1aSopenharmony_ci ht = &dht->table[2 * t + 1]; 209cabdff1aSopenharmony_ci for (i = k = 0; i < 16; i++) 210cabdff1aSopenharmony_ci k += (huff->huffman_table[t].num_ac_codes[i] = ht->L[i]); 211cabdff1aSopenharmony_ci av_assert0(k <= sizeof(huff->huffman_table[t].ac_values)); 212cabdff1aSopenharmony_ci for (i = 0; i < k; i++) 213cabdff1aSopenharmony_ci huff->huffman_table[t].ac_values[i] = ht->V[i]; 214cabdff1aSopenharmony_ci } 215cabdff1aSopenharmony_ci 216cabdff1aSopenharmony_ci } else { 217cabdff1aSopenharmony_ci return AVERROR_EOF; 218cabdff1aSopenharmony_ci } 219cabdff1aSopenharmony_ci return 0; 220cabdff1aSopenharmony_ci} 221cabdff1aSopenharmony_ci 222cabdff1aSopenharmony_cistatic int vaapi_encode_mjpeg_init_picture_params(AVCodecContext *avctx, 223cabdff1aSopenharmony_ci VAAPIEncodePicture *pic) 224cabdff1aSopenharmony_ci{ 225cabdff1aSopenharmony_ci VAAPIEncodeMJPEGContext *priv = avctx->priv_data; 226cabdff1aSopenharmony_ci JPEGRawFrameHeader *fh = &priv->frame_header; 227cabdff1aSopenharmony_ci JPEGRawScanHeader *sh = &priv->scan.header; 228cabdff1aSopenharmony_ci VAEncPictureParameterBufferJPEG *vpic = pic->codec_picture_params; 229cabdff1aSopenharmony_ci const AVPixFmtDescriptor *desc; 230cabdff1aSopenharmony_ci const uint8_t components_rgb[3] = { 'R', 'G', 'B' }; 231cabdff1aSopenharmony_ci const uint8_t components_yuv[3] = { 1, 2, 3 }; 232cabdff1aSopenharmony_ci const uint8_t *components; 233cabdff1aSopenharmony_ci int t, i, quant_scale, len; 234cabdff1aSopenharmony_ci 235cabdff1aSopenharmony_ci av_assert0(pic->type == PICTURE_TYPE_IDR); 236cabdff1aSopenharmony_ci 237cabdff1aSopenharmony_ci desc = av_pix_fmt_desc_get(priv->common.input_frames->sw_format); 238cabdff1aSopenharmony_ci av_assert0(desc); 239cabdff1aSopenharmony_ci if (desc->flags & AV_PIX_FMT_FLAG_RGB) 240cabdff1aSopenharmony_ci components = components_rgb; 241cabdff1aSopenharmony_ci else 242cabdff1aSopenharmony_ci components = components_yuv; 243cabdff1aSopenharmony_ci 244cabdff1aSopenharmony_ci // Frame header. 245cabdff1aSopenharmony_ci 246cabdff1aSopenharmony_ci fh->P = 8; 247cabdff1aSopenharmony_ci fh->Y = avctx->height; 248cabdff1aSopenharmony_ci fh->X = avctx->width; 249cabdff1aSopenharmony_ci fh->Nf = desc->nb_components; 250cabdff1aSopenharmony_ci 251cabdff1aSopenharmony_ci for (i = 0; i < fh->Nf; i++) { 252cabdff1aSopenharmony_ci fh->C[i] = components[i]; 253cabdff1aSopenharmony_ci fh->H[i] = 1 + (i == 0 ? desc->log2_chroma_w : 0); 254cabdff1aSopenharmony_ci fh->V[i] = 1 + (i == 0 ? desc->log2_chroma_h : 0); 255cabdff1aSopenharmony_ci 256cabdff1aSopenharmony_ci fh->Tq[i] = !!i; 257cabdff1aSopenharmony_ci } 258cabdff1aSopenharmony_ci 259cabdff1aSopenharmony_ci fh->Lf = 8 + 3 * fh->Nf; 260cabdff1aSopenharmony_ci 261cabdff1aSopenharmony_ci // JFIF header. 262cabdff1aSopenharmony_ci if (priv->jfif) { 263cabdff1aSopenharmony_ci JPEGRawApplicationData *app = &priv->jfif_header; 264cabdff1aSopenharmony_ci AVRational sar = pic->input_image->sample_aspect_ratio; 265cabdff1aSopenharmony_ci int sar_w, sar_h; 266cabdff1aSopenharmony_ci PutByteContext pbc; 267cabdff1aSopenharmony_ci 268cabdff1aSopenharmony_ci bytestream2_init_writer(&pbc, priv->jfif_data, 269cabdff1aSopenharmony_ci sizeof(priv->jfif_data)); 270cabdff1aSopenharmony_ci 271cabdff1aSopenharmony_ci bytestream2_put_buffer(&pbc, "JFIF", 5); 272cabdff1aSopenharmony_ci bytestream2_put_be16(&pbc, 0x0102); 273cabdff1aSopenharmony_ci bytestream2_put_byte(&pbc, 0); 274cabdff1aSopenharmony_ci 275cabdff1aSopenharmony_ci av_reduce(&sar_w, &sar_h, sar.num, sar.den, 65535); 276cabdff1aSopenharmony_ci if (sar_w && sar_h) { 277cabdff1aSopenharmony_ci bytestream2_put_be16(&pbc, sar_w); 278cabdff1aSopenharmony_ci bytestream2_put_be16(&pbc, sar_h); 279cabdff1aSopenharmony_ci } else { 280cabdff1aSopenharmony_ci bytestream2_put_be16(&pbc, 1); 281cabdff1aSopenharmony_ci bytestream2_put_be16(&pbc, 1); 282cabdff1aSopenharmony_ci } 283cabdff1aSopenharmony_ci 284cabdff1aSopenharmony_ci bytestream2_put_byte(&pbc, 0); 285cabdff1aSopenharmony_ci bytestream2_put_byte(&pbc, 0); 286cabdff1aSopenharmony_ci 287cabdff1aSopenharmony_ci av_assert0(bytestream2_get_bytes_left_p(&pbc) == 0); 288cabdff1aSopenharmony_ci 289cabdff1aSopenharmony_ci app->Lp = 2 + sizeof(priv->jfif_data); 290cabdff1aSopenharmony_ci app->Ap = priv->jfif_data; 291cabdff1aSopenharmony_ci app->Ap_ref = NULL; 292cabdff1aSopenharmony_ci } 293cabdff1aSopenharmony_ci 294cabdff1aSopenharmony_ci // Quantisation tables. 295cabdff1aSopenharmony_ci 296cabdff1aSopenharmony_ci if (priv->quality < 50) 297cabdff1aSopenharmony_ci quant_scale = 5000 / priv->quality; 298cabdff1aSopenharmony_ci else 299cabdff1aSopenharmony_ci quant_scale = 200 - 2 * priv->quality; 300cabdff1aSopenharmony_ci 301cabdff1aSopenharmony_ci len = 2; 302cabdff1aSopenharmony_ci 303cabdff1aSopenharmony_ci for (t = 0; t < 1 + (fh->Nf > 1); t++) { 304cabdff1aSopenharmony_ci JPEGRawQuantisationTable *quant = &priv->quant_tables.table[t]; 305cabdff1aSopenharmony_ci const uint8_t *data = t == 0 ? 306cabdff1aSopenharmony_ci vaapi_encode_mjpeg_quant_luminance : 307cabdff1aSopenharmony_ci vaapi_encode_mjpeg_quant_chrominance; 308cabdff1aSopenharmony_ci 309cabdff1aSopenharmony_ci quant->Pq = 0; 310cabdff1aSopenharmony_ci quant->Tq = t; 311cabdff1aSopenharmony_ci for (i = 0; i < 64; i++) 312cabdff1aSopenharmony_ci quant->Q[i] = av_clip(data[i] * quant_scale / 100, 1, 255); 313cabdff1aSopenharmony_ci 314cabdff1aSopenharmony_ci len += 65; 315cabdff1aSopenharmony_ci } 316cabdff1aSopenharmony_ci 317cabdff1aSopenharmony_ci priv->quant_tables.Lq = len; 318cabdff1aSopenharmony_ci 319cabdff1aSopenharmony_ci // Huffman tables. 320cabdff1aSopenharmony_ci 321cabdff1aSopenharmony_ci len = 2; 322cabdff1aSopenharmony_ci 323cabdff1aSopenharmony_ci for (t = 0; t < 2 + 2 * (fh->Nf > 1); t++) { 324cabdff1aSopenharmony_ci JPEGRawHuffmanTable *huff = &priv->huffman_tables.table[t]; 325cabdff1aSopenharmony_ci const uint8_t *lengths, *values; 326cabdff1aSopenharmony_ci int k; 327cabdff1aSopenharmony_ci 328cabdff1aSopenharmony_ci switch (t) { 329cabdff1aSopenharmony_ci case 0: 330cabdff1aSopenharmony_ci lengths = ff_mjpeg_bits_dc_luminance + 1; 331cabdff1aSopenharmony_ci values = ff_mjpeg_val_dc; 332cabdff1aSopenharmony_ci break; 333cabdff1aSopenharmony_ci case 1: 334cabdff1aSopenharmony_ci lengths = ff_mjpeg_bits_ac_luminance + 1; 335cabdff1aSopenharmony_ci values = ff_mjpeg_val_ac_luminance; 336cabdff1aSopenharmony_ci break; 337cabdff1aSopenharmony_ci case 2: 338cabdff1aSopenharmony_ci lengths = ff_mjpeg_bits_dc_chrominance + 1; 339cabdff1aSopenharmony_ci values = ff_mjpeg_val_dc; 340cabdff1aSopenharmony_ci break; 341cabdff1aSopenharmony_ci case 3: 342cabdff1aSopenharmony_ci lengths = ff_mjpeg_bits_ac_chrominance + 1; 343cabdff1aSopenharmony_ci values = ff_mjpeg_val_ac_chrominance; 344cabdff1aSopenharmony_ci break; 345cabdff1aSopenharmony_ci } 346cabdff1aSopenharmony_ci 347cabdff1aSopenharmony_ci huff->Tc = t % 2; 348cabdff1aSopenharmony_ci huff->Th = t / 2; 349cabdff1aSopenharmony_ci 350cabdff1aSopenharmony_ci for (i = k = 0; i < 16; i++) 351cabdff1aSopenharmony_ci k += (huff->L[i] = lengths[i]); 352cabdff1aSopenharmony_ci 353cabdff1aSopenharmony_ci for (i = 0; i < k; i++) 354cabdff1aSopenharmony_ci huff->V[i] = values[i]; 355cabdff1aSopenharmony_ci 356cabdff1aSopenharmony_ci len += 17 + k; 357cabdff1aSopenharmony_ci } 358cabdff1aSopenharmony_ci 359cabdff1aSopenharmony_ci priv->huffman_tables.Lh = len; 360cabdff1aSopenharmony_ci 361cabdff1aSopenharmony_ci // Scan header. 362cabdff1aSopenharmony_ci 363cabdff1aSopenharmony_ci sh->Ns = fh->Nf; 364cabdff1aSopenharmony_ci 365cabdff1aSopenharmony_ci for (i = 0; i < fh->Nf; i++) { 366cabdff1aSopenharmony_ci sh->Cs[i] = fh->C[i]; 367cabdff1aSopenharmony_ci sh->Td[i] = i > 0; 368cabdff1aSopenharmony_ci sh->Ta[i] = i > 0; 369cabdff1aSopenharmony_ci } 370cabdff1aSopenharmony_ci 371cabdff1aSopenharmony_ci sh->Ss = 0; 372cabdff1aSopenharmony_ci sh->Se = 63; 373cabdff1aSopenharmony_ci sh->Ah = 0; 374cabdff1aSopenharmony_ci sh->Al = 0; 375cabdff1aSopenharmony_ci 376cabdff1aSopenharmony_ci sh->Ls = 6 + 2 * sh->Ns; 377cabdff1aSopenharmony_ci 378cabdff1aSopenharmony_ci 379cabdff1aSopenharmony_ci *vpic = (VAEncPictureParameterBufferJPEG) { 380cabdff1aSopenharmony_ci .reconstructed_picture = pic->recon_surface, 381cabdff1aSopenharmony_ci .coded_buf = pic->output_buffer, 382cabdff1aSopenharmony_ci 383cabdff1aSopenharmony_ci .picture_width = fh->X, 384cabdff1aSopenharmony_ci .picture_height = fh->Y, 385cabdff1aSopenharmony_ci 386cabdff1aSopenharmony_ci .pic_flags.bits = { 387cabdff1aSopenharmony_ci .profile = 0, 388cabdff1aSopenharmony_ci .progressive = 0, 389cabdff1aSopenharmony_ci .huffman = 1, 390cabdff1aSopenharmony_ci .interleaved = 0, 391cabdff1aSopenharmony_ci .differential = 0, 392cabdff1aSopenharmony_ci }, 393cabdff1aSopenharmony_ci 394cabdff1aSopenharmony_ci .sample_bit_depth = fh->P, 395cabdff1aSopenharmony_ci .num_scan = 1, 396cabdff1aSopenharmony_ci .num_components = fh->Nf, 397cabdff1aSopenharmony_ci 398cabdff1aSopenharmony_ci // The driver modifies the provided quantisation tables according 399cabdff1aSopenharmony_ci // to this quality value; the middle value of 50 makes that the 400cabdff1aSopenharmony_ci // identity so that they are used unchanged. 401cabdff1aSopenharmony_ci .quality = 50, 402cabdff1aSopenharmony_ci }; 403cabdff1aSopenharmony_ci 404cabdff1aSopenharmony_ci for (i = 0; i < fh->Nf; i++) { 405cabdff1aSopenharmony_ci vpic->component_id[i] = fh->C[i]; 406cabdff1aSopenharmony_ci vpic->quantiser_table_selector[i] = fh->Tq[i]; 407cabdff1aSopenharmony_ci } 408cabdff1aSopenharmony_ci 409cabdff1aSopenharmony_ci pic->nb_slices = 1; 410cabdff1aSopenharmony_ci 411cabdff1aSopenharmony_ci return 0; 412cabdff1aSopenharmony_ci} 413cabdff1aSopenharmony_ci 414cabdff1aSopenharmony_cistatic int vaapi_encode_mjpeg_init_slice_params(AVCodecContext *avctx, 415cabdff1aSopenharmony_ci VAAPIEncodePicture *pic, 416cabdff1aSopenharmony_ci VAAPIEncodeSlice *slice) 417cabdff1aSopenharmony_ci{ 418cabdff1aSopenharmony_ci VAAPIEncodeMJPEGContext *priv = avctx->priv_data; 419cabdff1aSopenharmony_ci JPEGRawScanHeader *sh = &priv->scan.header; 420cabdff1aSopenharmony_ci VAEncSliceParameterBufferJPEG *vslice = slice->codec_slice_params; 421cabdff1aSopenharmony_ci int i; 422cabdff1aSopenharmony_ci 423cabdff1aSopenharmony_ci *vslice = (VAEncSliceParameterBufferJPEG) { 424cabdff1aSopenharmony_ci .restart_interval = 0, 425cabdff1aSopenharmony_ci .num_components = sh->Ns, 426cabdff1aSopenharmony_ci }; 427cabdff1aSopenharmony_ci 428cabdff1aSopenharmony_ci for (i = 0; i < sh->Ns; i++) { 429cabdff1aSopenharmony_ci vslice->components[i].component_selector = sh->Cs[i]; 430cabdff1aSopenharmony_ci vslice->components[i].dc_table_selector = sh->Td[i]; 431cabdff1aSopenharmony_ci vslice->components[i].ac_table_selector = sh->Ta[i]; 432cabdff1aSopenharmony_ci } 433cabdff1aSopenharmony_ci 434cabdff1aSopenharmony_ci return 0; 435cabdff1aSopenharmony_ci} 436cabdff1aSopenharmony_ci 437cabdff1aSopenharmony_cistatic av_cold int vaapi_encode_mjpeg_get_encoder_caps(AVCodecContext *avctx) 438cabdff1aSopenharmony_ci{ 439cabdff1aSopenharmony_ci VAAPIEncodeContext *ctx = avctx->priv_data; 440cabdff1aSopenharmony_ci const AVPixFmtDescriptor *desc; 441cabdff1aSopenharmony_ci 442cabdff1aSopenharmony_ci desc = av_pix_fmt_desc_get(ctx->input_frames->sw_format); 443cabdff1aSopenharmony_ci av_assert0(desc); 444cabdff1aSopenharmony_ci 445cabdff1aSopenharmony_ci ctx->surface_width = FFALIGN(avctx->width, 8 << desc->log2_chroma_w); 446cabdff1aSopenharmony_ci ctx->surface_height = FFALIGN(avctx->height, 8 << desc->log2_chroma_h); 447cabdff1aSopenharmony_ci 448cabdff1aSopenharmony_ci return 0; 449cabdff1aSopenharmony_ci} 450cabdff1aSopenharmony_ci 451cabdff1aSopenharmony_cistatic av_cold int vaapi_encode_mjpeg_configure(AVCodecContext *avctx) 452cabdff1aSopenharmony_ci{ 453cabdff1aSopenharmony_ci VAAPIEncodeContext *ctx = avctx->priv_data; 454cabdff1aSopenharmony_ci VAAPIEncodeMJPEGContext *priv = avctx->priv_data; 455cabdff1aSopenharmony_ci int err; 456cabdff1aSopenharmony_ci 457cabdff1aSopenharmony_ci priv->quality = ctx->rc_quality; 458cabdff1aSopenharmony_ci if (priv->quality < 1 || priv->quality > 100) { 459cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Invalid quality value %d " 460cabdff1aSopenharmony_ci "(must be 1-100).\n", priv->quality); 461cabdff1aSopenharmony_ci return AVERROR(EINVAL); 462cabdff1aSopenharmony_ci } 463cabdff1aSopenharmony_ci 464cabdff1aSopenharmony_ci // Hack: the implementation calls the JPEG image header (which we 465cabdff1aSopenharmony_ci // will use in the same way as a slice header) generic "raw data". 466cabdff1aSopenharmony_ci // Therefore, if after the packed header capability check we have 467cabdff1aSopenharmony_ci // PACKED_HEADER_RAW_DATA available, rewrite it as 468cabdff1aSopenharmony_ci // PACKED_HEADER_SLICE so that the header-writing code can do the 469cabdff1aSopenharmony_ci // right thing. 470cabdff1aSopenharmony_ci if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_RAW_DATA) { 471cabdff1aSopenharmony_ci ctx->va_packed_headers &= ~VA_ENC_PACKED_HEADER_RAW_DATA; 472cabdff1aSopenharmony_ci ctx->va_packed_headers |= VA_ENC_PACKED_HEADER_SLICE; 473cabdff1aSopenharmony_ci } 474cabdff1aSopenharmony_ci 475cabdff1aSopenharmony_ci err = ff_cbs_init(&priv->cbc, AV_CODEC_ID_MJPEG, avctx); 476cabdff1aSopenharmony_ci if (err < 0) 477cabdff1aSopenharmony_ci return err; 478cabdff1aSopenharmony_ci 479cabdff1aSopenharmony_ci return 0; 480cabdff1aSopenharmony_ci} 481cabdff1aSopenharmony_ci 482cabdff1aSopenharmony_cistatic const VAAPIEncodeProfile vaapi_encode_mjpeg_profiles[] = { 483cabdff1aSopenharmony_ci { FF_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT, 484cabdff1aSopenharmony_ci 8, 1, 0, 0, VAProfileJPEGBaseline }, 485cabdff1aSopenharmony_ci { FF_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT, 486cabdff1aSopenharmony_ci 8, 3, 1, 1, VAProfileJPEGBaseline }, 487cabdff1aSopenharmony_ci { FF_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT, 488cabdff1aSopenharmony_ci 8, 3, 1, 0, VAProfileJPEGBaseline }, 489cabdff1aSopenharmony_ci { FF_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT, 490cabdff1aSopenharmony_ci 8, 3, 0, 0, VAProfileJPEGBaseline }, 491cabdff1aSopenharmony_ci { FF_PROFILE_UNKNOWN } 492cabdff1aSopenharmony_ci}; 493cabdff1aSopenharmony_ci 494cabdff1aSopenharmony_cistatic const VAAPIEncodeType vaapi_encode_type_mjpeg = { 495cabdff1aSopenharmony_ci .profiles = vaapi_encode_mjpeg_profiles, 496cabdff1aSopenharmony_ci 497cabdff1aSopenharmony_ci .flags = FLAG_CONSTANT_QUALITY_ONLY | 498cabdff1aSopenharmony_ci FLAG_INTRA_ONLY, 499cabdff1aSopenharmony_ci 500cabdff1aSopenharmony_ci .get_encoder_caps = &vaapi_encode_mjpeg_get_encoder_caps, 501cabdff1aSopenharmony_ci .configure = &vaapi_encode_mjpeg_configure, 502cabdff1aSopenharmony_ci 503cabdff1aSopenharmony_ci .default_quality = 80, 504cabdff1aSopenharmony_ci 505cabdff1aSopenharmony_ci .picture_params_size = sizeof(VAEncPictureParameterBufferJPEG), 506cabdff1aSopenharmony_ci .init_picture_params = &vaapi_encode_mjpeg_init_picture_params, 507cabdff1aSopenharmony_ci 508cabdff1aSopenharmony_ci .slice_params_size = sizeof(VAEncSliceParameterBufferJPEG), 509cabdff1aSopenharmony_ci .init_slice_params = &vaapi_encode_mjpeg_init_slice_params, 510cabdff1aSopenharmony_ci 511cabdff1aSopenharmony_ci .slice_header_type = VAEncPackedHeaderRawData, 512cabdff1aSopenharmony_ci .write_slice_header = &vaapi_encode_mjpeg_write_image_header, 513cabdff1aSopenharmony_ci 514cabdff1aSopenharmony_ci .write_extra_buffer = &vaapi_encode_mjpeg_write_extra_buffer, 515cabdff1aSopenharmony_ci}; 516cabdff1aSopenharmony_ci 517cabdff1aSopenharmony_cistatic av_cold int vaapi_encode_mjpeg_init(AVCodecContext *avctx) 518cabdff1aSopenharmony_ci{ 519cabdff1aSopenharmony_ci VAAPIEncodeContext *ctx = avctx->priv_data; 520cabdff1aSopenharmony_ci 521cabdff1aSopenharmony_ci ctx->codec = &vaapi_encode_type_mjpeg; 522cabdff1aSopenharmony_ci 523cabdff1aSopenharmony_ci // The JPEG image header - see note above. 524cabdff1aSopenharmony_ci ctx->desired_packed_headers = 525cabdff1aSopenharmony_ci VA_ENC_PACKED_HEADER_RAW_DATA; 526cabdff1aSopenharmony_ci 527cabdff1aSopenharmony_ci return ff_vaapi_encode_init(avctx); 528cabdff1aSopenharmony_ci} 529cabdff1aSopenharmony_ci 530cabdff1aSopenharmony_cistatic av_cold int vaapi_encode_mjpeg_close(AVCodecContext *avctx) 531cabdff1aSopenharmony_ci{ 532cabdff1aSopenharmony_ci VAAPIEncodeMJPEGContext *priv = avctx->priv_data; 533cabdff1aSopenharmony_ci 534cabdff1aSopenharmony_ci ff_cbs_fragment_free(&priv->current_fragment); 535cabdff1aSopenharmony_ci ff_cbs_close(&priv->cbc); 536cabdff1aSopenharmony_ci 537cabdff1aSopenharmony_ci return ff_vaapi_encode_close(avctx); 538cabdff1aSopenharmony_ci} 539cabdff1aSopenharmony_ci 540cabdff1aSopenharmony_ci#define OFFSET(x) offsetof(VAAPIEncodeMJPEGContext, x) 541cabdff1aSopenharmony_ci#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) 542cabdff1aSopenharmony_cistatic const AVOption vaapi_encode_mjpeg_options[] = { 543cabdff1aSopenharmony_ci VAAPI_ENCODE_COMMON_OPTIONS, 544cabdff1aSopenharmony_ci 545cabdff1aSopenharmony_ci { "jfif", "Include JFIF header", 546cabdff1aSopenharmony_ci OFFSET(jfif), AV_OPT_TYPE_BOOL, 547cabdff1aSopenharmony_ci { .i64 = 0 }, 0, 1, FLAGS }, 548cabdff1aSopenharmony_ci { "huffman", "Include huffman tables", 549cabdff1aSopenharmony_ci OFFSET(huffman), AV_OPT_TYPE_BOOL, 550cabdff1aSopenharmony_ci { .i64 = 1 }, 0, 1, FLAGS }, 551cabdff1aSopenharmony_ci 552cabdff1aSopenharmony_ci { NULL }, 553cabdff1aSopenharmony_ci}; 554cabdff1aSopenharmony_ci 555cabdff1aSopenharmony_cistatic const FFCodecDefault vaapi_encode_mjpeg_defaults[] = { 556cabdff1aSopenharmony_ci { "b", "0" }, 557cabdff1aSopenharmony_ci { NULL }, 558cabdff1aSopenharmony_ci}; 559cabdff1aSopenharmony_ci 560cabdff1aSopenharmony_cistatic const AVClass vaapi_encode_mjpeg_class = { 561cabdff1aSopenharmony_ci .class_name = "mjpeg_vaapi", 562cabdff1aSopenharmony_ci .item_name = av_default_item_name, 563cabdff1aSopenharmony_ci .option = vaapi_encode_mjpeg_options, 564cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, 565cabdff1aSopenharmony_ci}; 566cabdff1aSopenharmony_ci 567cabdff1aSopenharmony_ciconst FFCodec ff_mjpeg_vaapi_encoder = { 568cabdff1aSopenharmony_ci .p.name = "mjpeg_vaapi", 569cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("MJPEG (VAAPI)"), 570cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 571cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_MJPEG, 572cabdff1aSopenharmony_ci .priv_data_size = sizeof(VAAPIEncodeMJPEGContext), 573cabdff1aSopenharmony_ci .init = &vaapi_encode_mjpeg_init, 574cabdff1aSopenharmony_ci FF_CODEC_RECEIVE_PACKET_CB(&ff_vaapi_encode_receive_packet), 575cabdff1aSopenharmony_ci .close = &vaapi_encode_mjpeg_close, 576cabdff1aSopenharmony_ci .p.priv_class = &vaapi_encode_mjpeg_class, 577cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DR1, 578cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, 579cabdff1aSopenharmony_ci .defaults = vaapi_encode_mjpeg_defaults, 580cabdff1aSopenharmony_ci .p.pix_fmts = (const enum AVPixelFormat[]) { 581cabdff1aSopenharmony_ci AV_PIX_FMT_VAAPI, 582cabdff1aSopenharmony_ci AV_PIX_FMT_NONE, 583cabdff1aSopenharmony_ci }, 584cabdff1aSopenharmony_ci .hw_configs = ff_vaapi_encode_hw_configs, 585cabdff1aSopenharmony_ci .p.wrapper_name = "vaapi", 586cabdff1aSopenharmony_ci}; 587