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 */
ADM_vaEncodingContextH264Base()66 ADM_vaEncodingContextH264Base::ADM_vaEncodingContextH264Base()
67 {
68 aprintf("vaH264 ctor\n");
69 context_id=VA_INVALID;
70 config_id=VA_INVALID;
71
72 current_frame_encoding=0;
73
74 for(int i=0;i<VA_ENC_NB_SURFACE;i++)
75 vaEncodingBuffers[i]=NULL;;
76 for(int i=0;i<VA_ENC_NB_SURFACE;i++)
77 {
78 vaSurface[i]=NULL;
79 vaRefSurface[i]=NULL;
80 }
81 memset(&seq_param, 0, sizeof(seq_param));
82 memset(&pic_param, 0, sizeof(pic_param));
83 memset(&slice_param, 0, sizeof(slice_param));
84
85 num_ref_frames = 1;
86
87
88 numShortTerm = 0;
89 MaxPicOrderCntLsb = (2<<8);
90 Log2MaxFrameNum = 16;
91 Log2MaxPicOrderCntLsb = 8;
92
93
94 // RC
95 initial_qp = 15;
96 minimal_qp = 0;
97 rc_mode = VA_RC_CBR; //VA_RC_CQP;
98 aprintf("/vaH264 ctor\n");
99 tmpBuffer=NULL;
100 }
101 /**
102 *
103 */
~ADM_vaEncodingContextH264Base()104 ADM_vaEncodingContextH264Base::~ADM_vaEncodingContextH264Base()
105 {
106 aprintf("vaH264 dtor\n");
107 if(context_id!=VA_INVALID)
108 {
109 vaDestroyContext(admLibVA::getDisplay(),context_id);
110 context_id=VA_INVALID;
111 }
112 if(config_id!=VA_INVALID)
113 {
114 vaDestroyConfig(admLibVA::getDisplay(),config_id);
115 config_id=VA_INVALID;
116 }
117 for(int i=0;i<VA_ENC_NB_SURFACE;i++)
118 {
119 if(vaSurface[i])
120 {
121 delete vaSurface[i];
122 vaSurface[i]=NULL;
123 }
124 if(vaRefSurface[i])
125 {
126 delete vaRefSurface[i];
127 vaRefSurface[i]=NULL;
128 }
129
130 }
131 aprintf("/vaH264 dtor\n");
132 }
133 /**
134 *
135 * @param width
136 * @param height
137 * @param knownSurfaces
138 * @return
139 */
setup(int width,int height,int frameInc,std::vector<ADM_vaSurface * > knownSurfaces)140 bool ADM_vaEncodingContextH264Base::setup( int width, int height, int frameInc,std::vector<ADM_vaSurface *>knownSurfaces)
141 {
142 ADM_info("vaH264 setup\n");
143
144 h264=vaGetH264EncoderProfile();
145 if(h264->profile==VAProfileNone)
146 {
147 ADM_error("No H264 encoding support\n");
148 return false;
149 }
150
151
152 VAStatus va_status;
153 frame_width=width;
154 frame_height=height;
155 frame_width_mbaligned=(width+15)&~15;
156 frame_height_mbaligned=(height+15)&~15;
157 int i;
158 usSecondsToFrac(frameInc,&frameNum,&frameDen);
159 ADM_info("xFps : %d : %d\n",frameNum,frameDen);
160 // marshall new config...
161
162 // copy common part
163 int nAttrib=h264->newAttributes.count();
164 int outAttrib=0;
165 VAConfigAttrib *ttrib=new VAConfigAttrib[nAttrib+1];
166 const VAConfigAttrib *old=h264->newAttributes.getPointer();
167 memcpy(ttrib,old,nAttrib*sizeof(VAConfigAttrib));
168
169 // add rate control, it is per instance
170 ttrib[outAttrib].type=VAConfigAttribRateControl;
171 ttrib[outAttrib].value=VA_RC_CBR;
172 outAttrib++;
173
174 CHECK_VA_STATUS_BOOL( vaCreateConfig(admLibVA::getDisplay(), h264->profile, VAEntrypointEncSlice, ttrib, outAttrib, &config_id));
175
176 int n=knownSurfaces.size();
177 VASurfaceID *tmp_surfaceId = new VASurfaceID[n];
178 for(int i=0;i<n;i++)
179 {
180 tmp_surfaceId[i]=knownSurfaces[i]->surface;
181 }
182
183 /* Create a context for this encode pipe */
184 CHECK_VA_STATUS_BOOL( vaCreateContext(admLibVA::getDisplay(), config_id,
185 frame_width_mbaligned, frame_height_mbaligned,
186 VA_PROGRESSIVE,
187 tmp_surfaceId, n,
188 &context_id));
189
190 delete [] ttrib;
191 delete [] tmp_surfaceId;
192 tmp_surfaceId=NULL;
193
194 int codedbuf_size = (frame_width_mbaligned * frame_height_mbaligned * 400) / (16*16);
195
196 for (i = 0; i < SURFACE_NUM; i++)
197 {
198 vaEncodingBuffers[i]= ADM_vaEncodingBuffers::allocate(context_id,codedbuf_size);
199 if(!vaEncodingBuffers[i])
200 {
201 ADM_warning("Cannot create encoding buffer %d\n",i);
202 return false;;
203 }
204 }
205
206 // Allocate VAImage
207
208 for(int i=0;i<VA_ENC_NB_SURFACE;i++)
209 {
210 vaSurface[i]=ADM_vaSurface::allocateWithSurface(width,height);
211 if(!vaSurface[i])
212 {
213 ADM_warning("Cannot allocate surface\n");
214 return false;
215 }
216
217 vaRefSurface[i]=ADM_vaSurface::allocateWithSurface(width,height);
218 if(!vaRefSurface[i])
219 {
220 ADM_warning("Cannot allocate ref surface\n");
221 return false;
222 }
223 }
224 tmpBuffer=new uint8_t[codedbuf_size];
225 render_sequence();
226 ADM_info("/vaH264 setup\n");
227 return true;
228 }
229
230
231 //-- Global Header
232
generateExtraData(int * size,uint8_t ** data)233 bool ADM_vaEncodingContextH264Base::generateExtraData(int *size, uint8_t **data)
234 {
235 aprintf("vaH264 extraData\n");
236 vaBitstream sps,pps;
237
238 fillSeqParam();
239 sps_rbsp(&sps);
240
241 fillPPS(0,FRAME_IDR);
242 pps_rbsp(&pps);
243
244 sps.stop();
245 pps.stop();
246
247 int spsLen=sps.lengthInBytes();
248 int ppsLen=pps.lengthInBytes();
249
250 *data =new uint8_t[spsLen+ppsLen+20];
251
252 uint8_t *p=*data;
253 *p++=1;
254 *p++=sps.getPointer()[0];
255 *p++=sps.getPointer()[1];
256 *p++=sps.getPointer()[2];
257 *p++=0xff;
258 // SPS
259 *p++=0xe1;
260 *p++=(1+spsLen)>>8;
261 *p++=(1+spsLen)&0xff;
262 *p++=NAL_SPS; // SPS NALU
263 memcpy(p,sps.getPointer(),spsLen);
264 p+=spsLen;
265 // PPS
266 *p++=1;
267 *p++=(1+ppsLen)>>8;
268 *p++=(1+ppsLen)&0xff;
269 *p++=NAL_PPS;
270 memcpy(p,pps.getPointer(),ppsLen);
271 p+=ppsLen;
272 *size=(intptr_t)(p)-(intptr_t)*data;
273
274 mixDump(*data,*size);
275
276 aprintf("/vaH264 extraData\n");
277 return true;
278 }
279 /**
280 *
281 * @param in
282 * @param out
283 * @return
284 */
encode(ADMImage * in,ADMBitstream * out)285 bool ADM_vaEncodingContextH264Base::encode(ADMImage *in, ADMBitstream *out)
286 {
287 aprintf("Encoding frame %d, H264 AVC\n",current_frame_encoding);
288 vaFrameType current_frame_type;
289 if(!vaSurface[current_frame_encoding%SURFACE_NUM]->fromAdmImage(in))
290 {
291 ADM_warning("Failed to upload image to vaSurface\n");
292 return false;
293 }
294
295 encoding2display_order(current_frame_encoding, vaH264Settings.IntraPeriod, ¤t_frame_type);
296 aprintf("Encoding order = %d, frame type=%d\n",(int)current_frame_encoding,current_frame_type);
297 int current_slot= (current_frame_encoding % SURFACE_NUM);
298
299 CHECK_VA_STATUS_BOOL(vaBeginPicture(admLibVA::getDisplay(), context_id, vaSurface[current_slot]->surface));
300
301
302
303 if (current_frame_type == FRAME_IDR)
304 {
305 out->flags = AVI_KEY_FRAME;
306 }else
307 {
308 out->flags = AVI_P_FRAME;
309 }
310 render_picture(current_frame_encoding,current_frame_type);
311 render_slice(current_frame_encoding,current_frame_type);
312 CHECK_VA_STATUS_BOOL( vaEndPicture(admLibVA::getDisplay(),context_id));
313 //--
314
315 CHECK_VA_STATUS_BOOL( vaSyncSurface(admLibVA::getDisplay(), vaSurface[current_frame_encoding % SURFACE_NUM]->surface));
316
317 #if 0 // Heavy convert
318
319 int len=vaEncodingBuffers[current_frame_encoding % SURFACE_NUM]->read(tmpBuffer, out->bufferSize);
320 int l=ADM_unescapeH264(len-4,tmpBuffer+4,out->data+4);
321 out->data[0]=l>>24;
322 out->data[1]=l>>16;
323 out->data[2]=l>>8;
324 out->data[3]=l>>0;
325 out->len=l+4;
326
327 #else // light convert, no escape
328 out->len=vaEncodingBuffers[current_frame_encoding % SURFACE_NUM]->read(out->data, out->bufferSize);
329 ADM_assert(out->len>=0);
330
331 // Set NAL Size (wtf ?)
332 int l=out->len-4;
333 out->data[0]=l>>24;
334 out->data[1]=l>>16;
335 out->data[2]=l>>8;
336 out->data[3]=l>>0;
337 #endif
338 /* reload a new frame data */
339
340 update_ReferenceFrames(current_frame_type);
341 current_frame_encoding++;
342 out->pts=in->Pts;
343 out->dts=out->pts;
344 return true;
345 }
346
347 // EOF
348