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,    &current_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