1 /***************************************************************************
2 \fn libvaEnc_plugin
3 \brief Plugin to use libva hw encoder (intel mostly)
4 -------------------
5
6 copyright : (C) 2018 by mean
7 email : fixounet@free.fr
8 ***************************************************************************/
9
10 /***************************************************************************
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 ***************************************************************************/
18 /***************************************************************************/
19 /* Derived from libva sample code */
20 /*
21 * Copyright (c) 2007-2013 Intel Corporation. All Rights Reserved.
22 *
23 * Permission is hereby granted, free of charge, to any person obtaining a
24 * copy of this software and associated documentation files (the
25 * "Software"), to deal in the Software without restriction, including
26 * without limitation the rights to use, copy, modify, merge, publish,
27 * distribute, sub license, and/or sell copies of the Software, and to
28 * permit persons to whom the Software is furnished to do so, subject to
29 * the following conditions:
30 *
31 * The above copyright notice and this permission notice (including the
32 * next paragraph) shall be included in all copies or substantial portions
33 * of the Software.
34 *
35 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
36 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
37 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
38 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
39 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
40 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
41 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
42 */
43 /***************************************************************************
44 * *
45 * This program is free software; you can redistribute it and/or modify *
46 * it under the terms of the GNU General Public License as published by *
47 * the Free Software Foundation; either version 2 of the License, or *
48 * (at your option) any later version. *
49 * *
50 ***************************************************************************/
51 #include "ADM_default.h"
52 #include "ADM_bitstream.h"
53 #include "ADM_coreVideoEncoder.h"
54 #include "ADM_videoInfoExtractor.h"
55
56
57 #include "va/va.h"
58 #include "va/va_enc_h264.h"
59 #include "ADM_coreLibVA_buffer.h"
60 #include "ADM_libVaEncodingContextH264.h"
61
62
63 /**
64 *
65 * @param header_buffer
66 * @return
67 */
build_packed_pic_buffer(vaBitstream * bs)68 bool ADM_vaEncodingContextH264AnnexB::build_packed_pic_buffer(vaBitstream *bs)
69 {
70 bs->startCodePrefix();
71 bs->nalHeader(NAL_REF_IDC_HIGH, NAL_PPS);
72 pps_rbsp(bs);
73 bs->startCodePrefix();
74 return true; // Offset
75 }
76
77 /**
78 *
79 * @param header_buffer
80 * @return
81 */
build_packed_seq_buffer(vaBitstream * bs)82 bool ADM_vaEncodingContextH264AnnexB::build_packed_seq_buffer(vaBitstream *bs)
83 {
84 bs->startCodePrefix();
85 bs->nalHeader(NAL_REF_IDC_HIGH, NAL_SPS);
86 sps_rbsp(bs);
87 bs->stop();
88 return true;
89 }
90
91 /**
92 *
93 * @param init_cpb_removal_length
94 * @param init_cpb_removal_delay
95 * @param init_cpb_removal_delay_offset
96 * @param cpb_removal_length
97 * @param cpb_removal_delay
98 * @param dpb_output_length
99 * @param dpb_output_delay
100 * @param sei_buffer
101 * @return
102 */
build_packed_sei_buffer_timing(vaBitstream * bs,unsigned int init_cpb_removal_length,unsigned int init_cpb_removal_delay,unsigned int init_cpb_removal_delay_offset,unsigned int cpb_removal_length,unsigned int cpb_removal_delay,unsigned int dpb_output_length,unsigned int dpb_output_delay)103 bool ADM_vaEncodingContextH264AnnexB::build_packed_sei_buffer_timing(vaBitstream *bs,
104 unsigned int init_cpb_removal_length,
105 unsigned int init_cpb_removal_delay,
106 unsigned int init_cpb_removal_delay_offset,
107 unsigned int cpb_removal_length,
108 unsigned int cpb_removal_delay,
109 unsigned int dpb_output_length,
110 unsigned int dpb_output_delay)
111 {
112 unsigned char *byte_buf;
113 int bp_byte_size, i, pic_byte_size;
114
115
116 // sei _bp
117 vaBitstream sei_bp;
118 sei_bp.put_ue(0);
119 sei_bp.put_ui(init_cpb_removal_delay, cpb_removal_length);
120 sei_bp.put_ui(init_cpb_removal_delay_offset, cpb_removal_length);
121 sei_bp.add1BitIfNotaligned();
122 sei_bp.stop();
123 bp_byte_size = (sei_bp.lengthInBits() + 7) / 8;
124
125 // sei_pic
126 vaBitstream sei_pic;
127
128 sei_pic.put_ui(cpb_removal_delay, cpb_removal_length);
129 sei_pic.put_ui(dpb_output_delay, dpb_output_length);
130 sei_pic.add1BitIfNotaligned();
131 sei_pic.stop();
132 pic_byte_size = (sei_bp.lengthInBits() + 7) / 8;
133 //--- nal
134 vaBitstream nal;
135
136 nal.startCodePrefix();
137 nal.nalHeader(NAL_REF_IDC_NONE, NAL_SEI);
138
139 /* Write the SEI buffer period data */
140 nal.put_ui(0, 8);
141 nal.put_ui(bp_byte_size, 8);
142
143
144 //------------ Merge-------------
145
146 byte_buf = sei_bp.getPointer();
147 for (i = 0; i < bp_byte_size; i++)
148 {
149 nal.put_ui(byte_buf[i], 8);
150 }
151
152 /* write the SEI timing data */
153 nal.put_ui(0x01, 8);
154 nal.put_ui(pic_byte_size, 8);
155
156 byte_buf = sei_pic.getPointer();
157 for (i = 0; i < pic_byte_size; i++)
158 {
159 nal.put_ui(byte_buf[i], 8);
160 }
161
162 nal.rbspTrailingBits();
163 nal.stop();
164 return true;
165 }
166
167 /**
168 *
169 * @param header_buffer
170 * @return
171 */
build_packed_slice_buffer(vaBitstream * bs)172 bool ADM_vaEncodingContextH264AnnexB::build_packed_slice_buffer(vaBitstream *bs)
173 {
174 int is_idr = !!pic_param.pic_fields.bits.idr_pic_flag;
175 int is_ref = !!pic_param.pic_fields.bits.reference_pic_flag;
176
177 bs->startCodePrefix();
178 if (IS_I_SLICE(slice_param.slice_type))
179 {
180 bs->nalHeader(NAL_REF_IDC_HIGH, is_idr ? NAL_IDR : NAL_NON_IDR);
181 }
182 else if (IS_P_SLICE(slice_param.slice_type))
183 {
184 bs->nalHeader(NAL_REF_IDC_MEDIUM, NAL_NON_IDR);
185 }
186 else
187 {
188 assert(IS_B_SLICE(slice_param.slice_type));
189 bs->nalHeader(is_ref ? NAL_REF_IDC_LOW : NAL_REF_IDC_NONE, NAL_NON_IDR);
190 }
191 slice_header(bs);
192 bs->stop();
193 return true;
194 }
195
196 /**
197 *
198 */
render_packedslice()199 bool ADM_vaEncodingContextH264AnnexB::render_packedslice()
200 {
201 VAEncPackedHeaderParameterBuffer packedheader_param_buffer;
202 VABufferID packedslice_para_bufid, packedslice_data_bufid, render_id[2];
203 unsigned int length_in_bits;
204
205 VAStatus va_status;
206 vaBitstream bs;
207 build_packed_slice_buffer(&bs);
208 length_in_bits = bs.lengthInBits();
209
210 packedheader_param_buffer.type = VAEncPackedHeaderSlice;
211 packedheader_param_buffer.bit_length = length_in_bits;
212 packedheader_param_buffer.has_emulation_bytes = 0;
213
214 CHECK_VA_STATUS_BOOL(vaCreateBuffer(admLibVA::getDisplay(),
215 context_id,
216 VAEncPackedHeaderParameterBufferType,
217 sizeof (packedheader_param_buffer), 1, &packedheader_param_buffer,
218 &packedslice_para_bufid));
219
220
221 CHECK_VA_STATUS_BOOL(vaCreateBuffer(admLibVA::getDisplay(),
222 context_id,
223 VAEncPackedHeaderDataBufferType,
224 (length_in_bits + 7) / 8, 1, bs.getPointer(),
225 &packedslice_data_bufid));
226
227
228 render_id[0] = packedslice_para_bufid;
229 render_id[1] = packedslice_data_bufid;
230 CHECK_VA_STATUS_BOOL(vaRenderPicture(admLibVA::getDisplay(), context_id, render_id, 2));
231
232 return true;
233 }
234
235
236 /**
237 *
238 */
render_packedsei(int frameNumber)239 bool ADM_vaEncodingContextH264AnnexB::render_packedsei(int frameNumber)
240 {
241 VAEncPackedHeaderParameterBuffer packed_header_param_buffer;
242 VABufferID packed_sei_header_param_buf_id, packed_sei_buf_id, render_id[2];
243 unsigned int length_in_bits /*offset_in_bytes*/;
244
245 VAStatus va_status;
246 vaBitstream bs;
247 int init_cpb_size, target_bit_rate, i_initial_cpb_removal_delay_length, i_initial_cpb_removal_delay;
248 int i_cpb_removal_delay, i_dpb_output_delay_length, i_cpb_removal_delay_length;
249
250 /* it comes for the bps defined in SPS */
251 target_bit_rate = VA_BITRATE;
252 init_cpb_size = (target_bit_rate * 8) >> 10;
253 i_initial_cpb_removal_delay = init_cpb_size * 0.5 * 1024 / target_bit_rate * 90000;
254
255 i_cpb_removal_delay = 2;
256 i_initial_cpb_removal_delay_length = 24;
257 i_cpb_removal_delay_length = 24;
258 i_dpb_output_delay_length = 24;
259
260
261 build_packed_sei_buffer_timing(&bs,
262 i_initial_cpb_removal_delay_length,
263 i_initial_cpb_removal_delay,
264 0,
265 i_cpb_removal_delay_length,
266 i_cpb_removal_delay * frameNumber,
267 i_dpb_output_delay_length,
268 0);
269 length_in_bits = bs.lengthInBits();
270 //offset_in_bytes = 0;
271 packed_header_param_buffer.type = VAEncPackedHeaderRawData;
272 packed_header_param_buffer.bit_length = length_in_bits;
273 packed_header_param_buffer.has_emulation_bytes = 0;
274
275 CHECK_VA_STATUS_BOOL(vaCreateBuffer(admLibVA::getDisplay(),
276 context_id,
277 VAEncPackedHeaderParameterBufferType,
278 sizeof (packed_header_param_buffer), 1, &packed_header_param_buffer,
279 &packed_sei_header_param_buf_id));
280
281
282 CHECK_VA_STATUS_BOOL(vaCreateBuffer(admLibVA::getDisplay(),
283 context_id,
284 VAEncPackedHeaderDataBufferType,
285 (length_in_bits + 7) / 8, 1, bs.getPointer(),
286 &packed_sei_buf_id));
287
288
289
290 render_id[0] = packed_sei_header_param_buf_id;
291 render_id[1] = packed_sei_buf_id;
292 CHECK_VA_STATUS_BOOL(vaRenderPicture(admLibVA::getDisplay(), context_id, render_id, 2));
293
294 return true;
295 }
296
297 /**
298 *
299 * @return
300 */
render_packedpicture(void)301 bool ADM_vaEncodingContextH264AnnexB::render_packedpicture(void)
302 {
303 VAEncPackedHeaderParameterBuffer packedheader_param_buffer;
304 VABufferID packedpic_para_bufid, packedpic_data_bufid, render_id[2];
305 unsigned int length_in_bits;
306
307 VAStatus va_status;
308 vaBitstream bs;
309
310
311 build_packed_pic_buffer(&bs);
312 length_in_bits = bs.lengthInBits();
313 packedheader_param_buffer.type = VAEncPackedHeaderPicture;
314 packedheader_param_buffer.bit_length = length_in_bits;
315 packedheader_param_buffer.has_emulation_bytes = 0;
316
317 CHECK_VA_STATUS_BOOL(vaCreateBuffer(admLibVA::getDisplay(),
318 context_id,
319 VAEncPackedHeaderParameterBufferType,
320 sizeof (packedheader_param_buffer), 1, &packedheader_param_buffer,
321 &packedpic_para_bufid));
322
323
324 CHECK_VA_STATUS_BOOL(vaCreateBuffer(admLibVA::getDisplay(),
325 context_id,
326 VAEncPackedHeaderDataBufferType,
327 (length_in_bits + 7) / 8, 1, bs.getPointer(),
328 &packedpic_data_bufid));
329
330
331 render_id[0] = packedpic_para_bufid;
332 render_id[1] = packedpic_data_bufid;
333 CHECK_VA_STATUS_BOOL(vaRenderPicture(admLibVA::getDisplay(), context_id, render_id, 2));
334
335
336 return true;
337 }
338
339 /**
340 *
341 * @return
342 */
render_packedsequence(void)343 bool ADM_vaEncodingContextH264AnnexB::render_packedsequence(void)
344 {
345 VAEncPackedHeaderParameterBuffer packedheader_param_buffer;
346 VABufferID packedseq_para_bufid, packedseq_data_bufid, render_id[2];
347 unsigned int length_in_bits;
348
349 VAStatus va_status;
350 vaBitstream bs;
351
352 build_packed_seq_buffer(&bs);
353 length_in_bits = bs.lengthInBits();
354
355 packedheader_param_buffer.type = VAEncPackedHeaderSequence;
356
357 packedheader_param_buffer.bit_length = length_in_bits; /*length_in_bits*/
358 packedheader_param_buffer.has_emulation_bytes = 0;
359 CHECK_VA_STATUS_BOOL(vaCreateBuffer(admLibVA::getDisplay(),
360 context_id,
361 VAEncPackedHeaderParameterBufferType,
362 sizeof (packedheader_param_buffer), 1, &packedheader_param_buffer,
363 &packedseq_para_bufid));
364
365
366 CHECK_VA_STATUS_BOOL(vaCreateBuffer(admLibVA::getDisplay(),
367 context_id,
368 VAEncPackedHeaderDataBufferType,
369 (length_in_bits + 7) / 8, 1, bs.getPointer(),
370 &packedseq_data_bufid));
371
372
373 render_id[0] = packedseq_para_bufid;
374 render_id[1] = packedseq_data_bufid;
375 CHECK_VA_STATUS_BOOL(vaRenderPicture(admLibVA::getDisplay(), context_id, render_id, 2));
376
377 return true;
378 }
379
380
381 /**
382 *
383 * @return
384 */
render_hrd(void)385 bool ADM_vaEncodingContextH264AnnexB::render_hrd(void)
386 {
387 VABufferID misc_parameter_hrd_buf_id;
388 VAStatus va_status;
389 VAEncMiscParameterBuffer *misc_param;
390 VAEncMiscParameterHRD *misc_hrd_param;
391
392 CHECK_VA_STATUS_BOOL(vaCreateBuffer(admLibVA::getDisplay(), context_id,
393 VAEncMiscParameterBufferType,
394 sizeof (VAEncMiscParameterBuffer) + sizeof (VAEncMiscParameterHRD),
395 1,
396 NULL,
397 &misc_parameter_hrd_buf_id));
398
399
400 vaMapBuffer(admLibVA::getDisplay(),
401 misc_parameter_hrd_buf_id,
402 (void **) &misc_param);
403 misc_param->type = VAEncMiscParameterTypeHRD;
404 misc_hrd_param = (VAEncMiscParameterHRD *) misc_param->data;
405
406 if (VA_BITRATE > 0)
407 {
408 misc_hrd_param->initial_buffer_fullness = VA_BITRATE* 1024 * 4;
409 misc_hrd_param->buffer_size = VA_BITRATE * 1024 * 8;
410 }
411 else
412 {
413 misc_hrd_param->initial_buffer_fullness = 0;
414 misc_hrd_param->buffer_size = 0;
415 }
416 vaUnmapBuffer(admLibVA::getDisplay(), misc_parameter_hrd_buf_id);
417
418 CHECK_VA_STATUS_BOOL(vaRenderPicture(admLibVA::getDisplay(), context_id, &misc_parameter_hrd_buf_id, 1));
419
420
421 return true;
422 }
423 //--
424
425
426 /**
427 *
428 * @return
429 */
render_slice(int frameNumber,vaFrameType frameType)430 bool ADM_vaEncodingContextH264AnnexB::render_slice(int frameNumber,vaFrameType frameType)
431 {
432 VABufferID slice_param_buf;
433 VAStatus va_status;
434 int i;
435
436 update_RefPicList(frameType);
437
438 /* one frame, one slice */
439 slice_param.macroblock_address = 0;
440 slice_param.num_macroblocks = frame_width_mbaligned * frame_height_mbaligned / (16 * 16); /* Measured by MB */
441 switch(frameType)
442 {
443 case FRAME_IDR:
444 slice_param.slice_type =SLICE_TYPE_I;
445 if (frameNumber)
446 slice_param.idr_pic_id++;
447 for (i = 0; i < 32; i++)
448 {
449 slice_param.RefPicList0[i].picture_id = VA_INVALID_SURFACE;
450 slice_param.RefPicList0[i].flags = VA_PICTURE_H264_INVALID;
451 slice_param.RefPicList1[i].picture_id = VA_INVALID_SURFACE;
452 slice_param.RefPicList1[i].flags = VA_PICTURE_H264_INVALID;
453
454 }
455 break;
456 case FRAME_P:
457 {
458 slice_param.slice_type=SLICE_TYPE_P;
459 int refpiclist0_max = h264->h264_maxref_p0;
460 memcpy(slice_param.RefPicList0, RefPicList0_P, refpiclist0_max * sizeof (VAPictureH264));
461 for (i = refpiclist0_max; i < 32; i++)
462 {
463 slice_param.RefPicList0[i].picture_id = VA_INVALID_SURFACE;
464 slice_param.RefPicList0[i].flags = VA_PICTURE_H264_INVALID;
465 }
466 }
467 break;
468 case FRAME_B:
469 {
470 slice_param.slice_type=SLICE_TYPE_B;
471 int refpiclist0_max = h264->h264_maxref_p0;
472 int refpiclist1_max = h264->h264_maxref_p1;
473
474 memcpy(slice_param.RefPicList0, RefPicList0_B, refpiclist0_max * sizeof (VAPictureH264));
475 for (i = refpiclist0_max; i < 32; i++)
476 {
477 slice_param.RefPicList0[i].picture_id = VA_INVALID_SURFACE;
478 slice_param.RefPicList0[i].flags = VA_PICTURE_H264_INVALID;
479 }
480
481 memcpy(slice_param.RefPicList1, RefPicList1_B, refpiclist1_max * sizeof (VAPictureH264));
482 for (i = refpiclist1_max; i < 32; i++)
483 {
484 slice_param.RefPicList1[i].picture_id = VA_INVALID_SURFACE;
485 slice_param.RefPicList1[i].flags = VA_PICTURE_H264_INVALID;
486 }
487 }
488 break;
489 default:
490 ADM_assert(0);
491 break;
492 }
493
494 slice_param.slice_alpha_c0_offset_div2 = 0;
495 slice_param.slice_beta_offset_div2 = 0;
496 slice_param.direct_spatial_mv_pred_flag = 1;
497 slice_param.pic_order_cnt_lsb = (frameNumber - gop_start) % MaxPicOrderCntLsb;
498
499
500 render_packedslice();
501
502 CHECK_VA_STATUS_BOOL(vaCreateBuffer(admLibVA::getDisplay(), context_id, VAEncSliceParameterBufferType,
503 sizeof (slice_param), 1, &slice_param, &slice_param_buf));
504 CHECK_VA_STATUS_BOOL(vaRenderPicture(admLibVA::getDisplay(), context_id, &slice_param_buf, 1));
505 return true;
506 }
507
508
509
510 /**
511 *
512 * @param in
513 * @param out
514 * @return
515 */
516
517
generateExtraData(int * size,uint8_t ** data)518 bool ADM_vaEncodingContextH264AnnexB::generateExtraData(int *size, uint8_t **data)
519 {
520 if(extraDataNeeded)
521 return ADM_vaEncodingContextH264Base::generateExtraData(size, data);
522
523 ADM_info("vaH264 extraData\n");
524
525 *size=0;
526 *data=NULL;
527 ADM_info("/vaH264 extraData\n");
528 return true;
529 }
encode(ADMImage * in,ADMBitstream * out)530 bool ADM_vaEncodingContextH264AnnexB::encode(ADMImage *in, ADMBitstream *out)
531 {
532 if(extraDataNeeded)
533 return ADM_vaEncodingContextH264Base::encode(in, out);
534
535 vaFrameType current_frame_type;
536 aprintf("Encoding frame %d, H264 AnnexB\n",current_frame_encoding);
537 if(!vaSurface[current_frame_encoding%SURFACE_NUM]->fromAdmImage(in))
538 {
539 ADM_warning("Failed to upload image to vaSurface\n");
540 return false;
541 }
542
543 encoding2display_order(current_frame_encoding, vaH264Settings.IntraPeriod, ¤t_frame_type);
544 aprintf("Encoding order = %d, frame type=%d\n",(int)current_frame_encoding,current_frame_type);
545 if (current_frame_type == FRAME_IDR)
546 {
547 numShortTerm = 0;
548 }
549 int current_slot= (current_frame_encoding % SURFACE_NUM);
550
551 CHECK_VA_STATUS_BOOL(vaBeginPicture(admLibVA::getDisplay(), context_id, vaSurface[current_slot]->surface));
552
553
554 if (current_frame_type == FRAME_IDR)
555 {
556 render_sequence();
557 render_picture(current_frame_encoding,current_frame_type);
558 render_packedsequence();
559 render_packedpicture();
560 out->flags = AVI_KEY_FRAME;
561 }
562 else
563 {
564 out->flags = AVI_P_FRAME;
565 render_picture(current_frame_encoding,current_frame_type);
566 }
567 render_slice(current_frame_encoding,current_frame_type);
568 CHECK_VA_STATUS_BOOL( vaEndPicture(admLibVA::getDisplay(),context_id));
569 //--
570
571 CHECK_VA_STATUS_BOOL( vaSyncSurface(admLibVA::getDisplay(), vaSurface[current_frame_encoding % SURFACE_NUM]->surface));
572
573 out->len=vaEncodingBuffers[current_frame_encoding % SURFACE_NUM]->read(out->data, out->bufferSize);
574 ADM_assert(out->len>=0);
575
576 /* reload a new frame data */
577
578 update_ReferenceFrames(current_frame_type);
579 current_frame_encoding++;
580 out->pts=in->Pts;
581 out->dts=out->pts;
582 return true;
583 }
584
ADM_vaEncodingContextH264AnnexB(bool withExtraData)585 ADM_vaEncodingContextH264AnnexB::ADM_vaEncodingContextH264AnnexB(bool withExtraData)
586 {
587 extraDataNeeded=withExtraData;
588 }
~ADM_vaEncodingContextH264AnnexB()589 ADM_vaEncodingContextH264AnnexB::~ADM_vaEncodingContextH264AnnexB()
590 {
591
592 }
593
594 // EOF
595