1 /* ********************************************************************* *\
2
3 Copyright (C) 2013 Intel Corporation. All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7 - Redistributions of source code must retain the above copyright notice,
8 this list of conditions and the following disclaimer.
9 - Redistributions in binary form must reproduce the above copyright notice,
10 this list of conditions and the following disclaimer in the documentation
11 and/or other materials provided with the distribution.
12 - Neither the name of Intel Corporation nor the names of its contributors
13 may be used to endorse or promote products derived from this software
14 without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 \* ********************************************************************* */
28
29 #include "handbrake/project.h"
30
31 #if HB_PROJECT_FEATURE_QSV
32
33 #include "handbrake/handbrake.h"
34 #include "handbrake/hbffmpeg.h"
35 #include "handbrake/qsv_filter_pp.h"
36 #include "handbrake/qsv_filter.h"
37 #include "handbrake/qsv_libav.h"
38 #include "handbrake/qsv_memory.h"
39 #include "handbrake/qsv_common.h"
40
41 static int hb_qsv_filter_pre_init( hb_filter_object_t * filter,
42 hb_filter_init_t * init );
43 static int hb_qsv_filter_pre_work( hb_filter_object_t * filter,
44 hb_buffer_t ** buf_in,
45 hb_buffer_t ** buf_out );
46 static hb_filter_info_t * hb_qsv_filter_pre_info( hb_filter_object_t * filter );
47 static void hb_qsv_filter_pre_close( hb_filter_object_t * filter );
48
49 static int hb_qsv_filter_post_init( hb_filter_object_t * filter,
50 hb_filter_init_t * init );
51 static int hb_qsv_filter_post_work( hb_filter_object_t * filter,
52 hb_buffer_t ** buf_in,
53 hb_buffer_t ** buf_out );
54 static hb_filter_info_t * hb_qsv_filter_post_info(hb_filter_object_t * filter);
55 static void hb_qsv_filter_post_close( hb_filter_object_t * filter );
56
57
58 hb_filter_object_t hb_filter_qsv_pre =
59 {
60 .id = HB_FILTER_QSV_PRE,
61 .enforce_order = 1,
62 .name = "Quick Sync Video user filter (pre)",
63 .settings = NULL,
64 .init = hb_qsv_filter_pre_init,
65 .work = hb_qsv_filter_pre_work,
66 .close = hb_qsv_filter_pre_close,
67 .info = hb_qsv_filter_pre_info,
68 };
69
70 hb_filter_object_t hb_filter_qsv_post =
71 {
72 .id = HB_FILTER_QSV_POST,
73 .enforce_order = 1,
74 .name = "Quick Sync Video user filter (post)",
75 .settings = NULL,
76 .init = hb_qsv_filter_post_init,
77 .work = hb_qsv_filter_post_work,
78 .close = hb_qsv_filter_post_close,
79 .info = hb_qsv_filter_post_info,
80 };
81
82
filter_pre_init(hb_qsv_context * qsv,hb_filter_private_t * pv)83 static int filter_pre_init( hb_qsv_context* qsv, hb_filter_private_t * pv ){
84 mfxStatus sts = MFX_ERR_NONE;
85 int i=0;
86
87 if(!qsv) return 3;
88
89 hb_qsv_space *prev_vpp = 0;
90
91 if(!qsv->vpp_space){
92 qsv->vpp_space = hb_qsv_list_init(HAVE_THREADS);
93 // note some change as : when no size changes -> no VPP used
94 // impact on : prev_vpp
95 }
96
97 if(!pv->vpp_space){
98 for(i=0; i<hb_qsv_list_count(qsv->vpp_space);i++){
99 hb_qsv_space *qsv_vpp = hb_qsv_list_item( qsv->vpp_space, i );
100 if(qsv_vpp->type == HB_QSV_VPP_USER){
101 pv->vpp_space = qsv_vpp;
102 break;
103 }
104 else
105 if(qsv_vpp->type == HB_QSV_VPP_DEFAULT){
106 prev_vpp = qsv_vpp;
107 }
108
109 }
110 }
111
112 if(!pv->vpp_space){
113 pv->vpp_space = calloc( 1, sizeof( hb_qsv_space ));
114 pv->vpp_space->type = HB_QSV_VPP_USER;
115 hb_qsv_list_add( qsv->vpp_space, pv->vpp_space );
116 hb_qsv_add_context_usage(qsv,HAVE_THREADS);
117 }
118 else
119 if(pv->vpp_space->is_init_done ) return 1;
120
121 if(!qsv->dec_space || !qsv->dec_space->is_init_done) return 2;
122
123 hb_qsv_space *qsv_vpp = pv->vpp_space;
124
125 HB_QSV_ZERO_MEMORY(qsv_vpp->m_mfxVideoParam);
126
127
128 if (prev_vpp)
129 {
130 memcpy( &qsv_vpp->m_mfxVideoParam.vpp, &prev_vpp->m_mfxVideoParam.vpp, sizeof(prev_vpp->m_mfxVideoParam.vpp));
131 }
132 else
133 {
134 HB_QSV_ZERO_MEMORY(qsv_vpp->m_mfxVideoParam);
135
136 // FrameRate is important for VPP to start with
137 if( qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtN == 0 &&
138 qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtD == 0 ){
139 qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtN = pv->job->title->vrate.num;
140 qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtD = pv->job->title->vrate.den;
141 }
142
143 qsv_vpp->m_mfxVideoParam.vpp.In.FourCC = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FourCC;
144 qsv_vpp->m_mfxVideoParam.vpp.In.ChromaFormat = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.ChromaFormat;
145 qsv_vpp->m_mfxVideoParam.vpp.In.CropX = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.CropX;
146 qsv_vpp->m_mfxVideoParam.vpp.In.CropY = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.CropY;
147 qsv_vpp->m_mfxVideoParam.vpp.In.CropW = pv->job->title->geometry.width;
148 qsv_vpp->m_mfxVideoParam.vpp.In.CropH = pv->job->title->geometry.height;
149 qsv_vpp->m_mfxVideoParam.vpp.In.PicStruct = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.PicStruct;
150 qsv_vpp->m_mfxVideoParam.vpp.In.FrameRateExtN = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtN;
151 qsv_vpp->m_mfxVideoParam.vpp.In.FrameRateExtD = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtD;
152 qsv_vpp->m_mfxVideoParam.vpp.In.AspectRatioW = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioW;
153 qsv_vpp->m_mfxVideoParam.vpp.In.AspectRatioH = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioH;
154 qsv_vpp->m_mfxVideoParam.vpp.In.Width = HB_QSV_ALIGN16(pv->job->title->geometry.width);
155 qsv_vpp->m_mfxVideoParam.vpp.In.Height = (MFX_PICSTRUCT_PROGRESSIVE == qsv_vpp->m_mfxVideoParam.vpp.In.PicStruct)?
156 HB_QSV_ALIGN16(pv->job->title->geometry.height) : HB_QSV_ALIGN32(pv->job->title->geometry.height);
157
158 qsv_vpp->m_mfxVideoParam.vpp.Out.FourCC = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FourCC;
159 qsv_vpp->m_mfxVideoParam.vpp.Out.ChromaFormat = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.ChromaFormat;
160 qsv_vpp->m_mfxVideoParam.vpp.Out.CropX = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.CropX;
161 qsv_vpp->m_mfxVideoParam.vpp.Out.CropY = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.CropY;
162 qsv_vpp->m_mfxVideoParam.vpp.Out.CropW = pv->job->title->geometry.width;
163 qsv_vpp->m_mfxVideoParam.vpp.Out.CropH = pv->job->title->geometry.height;
164 qsv_vpp->m_mfxVideoParam.vpp.Out.PicStruct = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.PicStruct;
165 qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtN = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtN;
166 qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtD = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtD;
167 qsv_vpp->m_mfxVideoParam.vpp.Out.AspectRatioW = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioW;
168 qsv_vpp->m_mfxVideoParam.vpp.Out.AspectRatioH = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioH;
169 qsv_vpp->m_mfxVideoParam.vpp.Out.Width = HB_QSV_ALIGN16(pv->job->title->geometry.width);
170 qsv_vpp->m_mfxVideoParam.vpp.Out.Height = (MFX_PICSTRUCT_PROGRESSIVE == qsv_vpp->m_mfxVideoParam.vpp.In.PicStruct)?
171 HB_QSV_ALIGN16(pv->job->title->geometry.height) : HB_QSV_ALIGN32(pv->job->title->geometry.height);
172
173 memset(&qsv_vpp->request, 0, sizeof(mfxFrameAllocRequest)*2);
174 }
175
176 qsv_vpp->m_mfxVideoParam.IOPattern = MFX_IOPATTERN_IN_OPAQUE_MEMORY | MFX_IOPATTERN_OUT_OPAQUE_MEMORY;
177
178 qsv_vpp->surface_num = FFMIN(prev_vpp ? prev_vpp->surface_num : qsv->dec_space->surface_num/2, HB_QSV_SURFACE_NUM);
179
180 for(i = 0; i < qsv_vpp->surface_num; i++){
181 qsv_vpp->p_surfaces[i] = av_mallocz( sizeof(mfxFrameSurface1) );
182 HB_QSV_CHECK_POINTER(qsv_vpp->p_surfaces[i], MFX_ERR_MEMORY_ALLOC);
183 memcpy(&(qsv_vpp->p_surfaces[i]->Info), &(qsv_vpp->m_mfxVideoParam.vpp.Out), sizeof(mfxFrameInfo));
184 }
185
186 qsv_vpp->sync_num = FFMIN(prev_vpp ? prev_vpp->sync_num : qsv->dec_space->sync_num, HB_QSV_SYNC_NUM);
187 for (i = 0; i < qsv_vpp->sync_num; i++){
188 qsv_vpp->p_syncp[i] = av_mallocz(sizeof(hb_qsv_sync));
189 HB_QSV_CHECK_POINTER(qsv_vpp->p_syncp[i], MFX_ERR_MEMORY_ALLOC);
190 qsv_vpp->p_syncp[i]->p_sync = av_mallocz(sizeof(mfxSyncPoint));
191 HB_QSV_CHECK_POINTER(qsv_vpp->p_syncp[i]->p_sync, MFX_ERR_MEMORY_ALLOC);
192 }
193
194 memset(&qsv_vpp->ext_opaque_alloc, 0, sizeof(mfxExtOpaqueSurfaceAlloc));
195 qsv_vpp->m_mfxVideoParam.NumExtParam = qsv_vpp->p_ext_param_num = 1;
196
197 qsv_vpp->p_ext_params = av_mallocz(sizeof(mfxExtBuffer *)*qsv_vpp->p_ext_param_num);
198 HB_QSV_CHECK_POINTER(qsv_vpp->p_ext_params, MFX_ERR_MEMORY_ALLOC);
199
200 qsv_vpp->m_mfxVideoParam.ExtParam = qsv_vpp->p_ext_params;
201
202 qsv_vpp->ext_opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION;
203 qsv_vpp->ext_opaque_alloc.Header.BufferSz = sizeof(mfxExtOpaqueSurfaceAlloc);
204 qsv_vpp->p_ext_params[0] = (mfxExtBuffer*)&qsv_vpp->ext_opaque_alloc;
205
206 if(prev_vpp){
207 qsv_vpp->ext_opaque_alloc.In.Surfaces = prev_vpp->p_surfaces;
208 qsv_vpp->ext_opaque_alloc.In.NumSurface = prev_vpp->surface_num;
209 }
210 else{
211 qsv_vpp->ext_opaque_alloc.In.Surfaces = qsv->dec_space->p_surfaces;
212 qsv_vpp->ext_opaque_alloc.In.NumSurface = qsv->dec_space->surface_num;
213 }
214 qsv_vpp->ext_opaque_alloc.In.Type = qsv->dec_space->request[0].Type;
215
216 qsv_vpp->ext_opaque_alloc.Out.Surfaces = qsv_vpp->p_surfaces;
217 qsv_vpp->ext_opaque_alloc.Out.NumSurface = qsv_vpp->surface_num;
218 qsv_vpp->ext_opaque_alloc.Out.Type = qsv->dec_space->request[0].Type;
219
220 pv->qsv_user = hb_list_init();
221
222 qsv_filter_t *plugin = av_mallocz( sizeof(qsv_filter_t) );
223
224 plugin->pv = pv;
225 plugin->plug.pthis = plugin;
226 plugin->plug.PluginInit = qsv_PluginInit;
227 plugin->plug.PluginClose = qsv_PluginClose;
228 plugin->plug.GetPluginParam = qsv_GetPluginParam;
229 plugin->plug.Submit = qsv_Submit;
230 plugin->plug.Execute = qsv_Execute;
231 plugin->plug.FreeResources = qsv_FreeResources;
232
233 hb_list_add(pv->qsv_user,plugin);
234
235 sts=MFXVideoUSER_Register(qsv->mfx_session,0,&plugin->plug);
236 HB_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
237
238 plugin_init(plugin,&qsv_vpp->m_mfxVideoParam);
239
240 qsv_vpp->is_init_done = 1;
241
242 return 0;
243 }
244
hb_qsv_filter_pre_info(hb_filter_object_t * filter)245 static hb_filter_info_t * hb_qsv_filter_pre_info( hb_filter_object_t * filter )
246 {
247 hb_filter_private_t * pv = filter->private_data;
248 hb_filter_info_t * info;
249
250 if( !pv )
251 return NULL;
252
253 info = calloc(1, sizeof(hb_filter_info_t));
254 info->human_readable_desc = malloc(128);
255 info->human_readable_desc[0] = 0;
256
257 snprintf(info->human_readable_desc, 128, "copy data to system memory");
258
259 return info;
260 }
hb_qsv_filter_pre_init(hb_filter_object_t * filter,hb_filter_init_t * init)261 static int hb_qsv_filter_pre_init( hb_filter_object_t * filter,
262 hb_filter_init_t * init ){
263 filter->private_data = calloc( 1, sizeof(struct hb_filter_private_s) );
264 hb_filter_private_t * pv = filter->private_data;
265 pv->job = init->job;
266
267 pv->pre.frame_go = 0;
268 pv->pre.frame_completed = hb_cond_init();
269 pv->pre.frame_completed_lock = hb_lock_init();
270
271 pv->post.frame_go = 0;
272 pv->post.frame_completed = hb_cond_init();
273 pv->post.frame_completed_lock = hb_lock_init();
274
275 pv->pre_busy.frame_go = 0;
276 pv->pre_busy.frame_completed = hb_cond_init();
277 pv->pre_busy.frame_completed_lock = hb_lock_init();
278
279 pv->post_busy.frame_go = 0;
280 pv->post_busy.frame_completed = hb_cond_init();
281 pv->post_busy.frame_completed_lock = hb_lock_init();
282
283 pv->list = hb_list_init();
284
285 // just to remind:
286 // PIX_FMT_YUV420P, ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples) , 3 planes: Y, U, V
287 // PIX_FMT_NV12, ///< planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V)
288 pv->sws_context_from_nv12 = hb_sws_get_context(
289 pv->job->title->geometry.width, pv->job->title->geometry.height,
290 AV_PIX_FMT_NV12, pv->job->color_range,
291 pv->job->title->geometry.width, pv->job->title->geometry.height,
292 AV_PIX_FMT_YUV420P, pv->job->color_range,
293 SWS_LANCZOS|SWS_ACCURATE_RND, SWS_CS_DEFAULT);
294 pv->sws_context_to_nv12 = hb_sws_get_context(
295 pv->job->title->geometry.width, pv->job->title->geometry.height,
296 AV_PIX_FMT_YUV420P, pv->job->color_range,
297 pv->job->title->geometry.width, pv->job->title->geometry.height,
298 AV_PIX_FMT_NV12, pv->job->color_range,
299 SWS_LANCZOS|SWS_ACCURATE_RND, SWS_CS_DEFAULT);
300 return 0;
301 }
pre_process_frame(hb_buffer_t * in,hb_qsv_context * qsv,hb_filter_private_t * pv)302 int pre_process_frame(hb_buffer_t *in, hb_qsv_context* qsv, hb_filter_private_t * pv ){
303
304 // 1 if have results , 0 otherwise
305 int ret = 1;
306
307 hb_qsv_list* received_item = in->qsv_details.qsv_atom;
308
309 mfxStatus sts = MFX_ERR_NONE;
310 mfxFrameSurface1 *work_surface = NULL;
311 hb_qsv_stage* stage = 0;
312
313 hb_qsv_space *qsv_vpp = pv->vpp_space;
314
315 if (received_item)
316 {
317 stage = hb_qsv_get_last_stage( received_item );
318 work_surface = stage->out.p_surface;
319 }
320
321 int sync_idx = hb_qsv_get_free_sync(qsv_vpp, qsv);
322 int surface_idx = -1;
323
324 for (;;)
325 {
326 if (sync_idx == -1)
327 {
328 hb_error("qsv: Not enough resources allocated for the preprocessing filter");
329 ret = 0;
330 break;
331 }
332
333 if (sts == MFX_ERR_MORE_SURFACE || sts == MFX_ERR_NONE)
334 surface_idx = hb_qsv_get_free_surface(qsv_vpp, qsv, &(qsv_vpp->m_mfxVideoParam.vpp.Out), QSV_PART_ANY);
335 if (surface_idx == -1) {
336 hb_error("qsv: Not enough resources allocated for the preprocessing filter");
337 ret = 0;
338 break;
339 }
340
341 sts = MFXVideoUSER_ProcessFrameAsync(qsv->mfx_session, (void * const*)&work_surface, 1, (void * const*)&qsv_vpp->p_surfaces[surface_idx] , 1, qsv_vpp->p_syncp[sync_idx]->p_sync);
342
343 if (MFX_ERR_MORE_DATA == sts)
344 {
345 if (!qsv_vpp->pending)
346 {
347 qsv_vpp->pending = hb_qsv_list_init(0);
348 }
349
350 // if we have no results, we should not miss resource(s)
351 hb_qsv_list_add( qsv_vpp->pending, received_item);
352
353 ff_qsv_atomic_dec(&qsv_vpp->p_syncp[sync_idx]->in_use);
354
355 ret = 0;
356 break;
357 }
358
359 if( MFX_ERR_MORE_SURFACE == sts || MFX_ERR_NONE <= sts){
360 if( MFX_ERR_MORE_SURFACE == sts )
361 continue;
362
363 if (qsv_vpp->p_surfaces[surface_idx] && MFX_WRN_DEVICE_BUSY != sts )
364 ff_qsv_atomic_inc(&qsv_vpp->p_surfaces[surface_idx]->Data.Locked);
365 }
366
367 HB_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
368
369 if (MFX_ERR_NONE <= sts ) // repeat the call if warning and no output
370 {
371 if (MFX_WRN_DEVICE_BUSY == sts){
372 hb_lock(pv->pre_busy.frame_completed_lock);
373 while(!pv->pre_busy.frame_go){
374 hb_cond_timedwait(pv->pre_busy.frame_completed,pv->pre_busy.frame_completed_lock,1000);
375 if(*pv->job->die)
376 break;
377 }
378 pv->pre_busy.frame_go = 0;
379 hb_unlock(pv->pre_busy.frame_completed_lock);
380
381 continue;
382 }
383 hb_lock(pv->pre.frame_completed_lock);
384 while(!pv->pre.frame_go){
385 hb_cond_timedwait(pv->pre.frame_completed,pv->pre.frame_completed_lock,1000);
386 if(*pv->job->die)
387 break;
388 }
389 pv->pre.frame_go = 0;
390 hb_unlock(pv->pre.frame_completed_lock);
391
392 in = pv->pre.out;
393
394 if (work_surface){
395 ff_qsv_atomic_dec(&work_surface->Data.Locked);
396 }
397
398 // inserting for the future, will be locked until very ready
399 if(stage){
400 hb_qsv_stage* new_stage = hb_qsv_stage_init();
401
402 new_stage->type = HB_QSV_VPP_USER;
403 new_stage->in.p_surface = work_surface;
404 new_stage->out.p_surface = qsv_vpp->p_surfaces[surface_idx];
405 new_stage->out.sync = qsv_vpp->p_syncp[sync_idx];
406 hb_qsv_add_stagee( &received_item, new_stage,HAVE_THREADS );
407
408 // add pending resources for the proper reclaim later
409 if( qsv_vpp->pending ){
410 if( hb_qsv_list_count(qsv_vpp->pending)>0 ){
411 new_stage->pending = qsv_vpp->pending;
412 }
413 qsv_vpp->pending = 0;
414
415 // making free via decrement for all pending
416 int i = 0;
417 for (i = hb_qsv_list_count(new_stage->pending); i > 0; i--){
418 hb_qsv_list *atom_list = hb_qsv_list_item(new_stage->pending, i-1);
419 hb_qsv_stage *stage = hb_qsv_get_last_stage( atom_list );
420 mfxFrameSurface1 *work_surface = stage->out.p_surface;
421 if (work_surface)
422 ff_qsv_atomic_dec(&work_surface->Data.Locked);
423 }
424 }
425 }
426
427 break;
428 }
429
430 ff_qsv_atomic_dec(&qsv_vpp->p_syncp[sync_idx]->in_use);
431
432 if (MFX_ERR_NOT_ENOUGH_BUFFER == sts)
433 HB_DEBUG_ASSERT(1, "The bitstream buffer size is insufficient.");
434
435 break;
436 }
437
438 return ret;
439 }
440
hb_qsv_filter_pre_work(hb_filter_object_t * filter,hb_buffer_t ** buf_in,hb_buffer_t ** buf_out)441 static int hb_qsv_filter_pre_work( hb_filter_object_t * filter,
442 hb_buffer_t ** buf_in,
443 hb_buffer_t ** buf_out ){
444 hb_filter_private_t * pv = filter->private_data;
445 hb_buffer_t * in = *buf_in;
446 hb_buffer_t * out = *buf_out;
447 int sts = 0;
448
449 hb_qsv_context* qsv = pv->job->qsv.ctx;
450
451 if(!in->qsv_details.filter_details)
452 in->qsv_details.filter_details = pv;
453
454 if (in->s.flags & HB_BUF_FLAG_EOF)
455 {
456 *buf_out = in;
457 *buf_in = NULL;
458 return HB_FILTER_DONE;
459 }
460
461 while(1){
462 int ret = filter_pre_init(qsv,pv);
463 if(ret >= 2)
464 hb_qsv_sleep(1);
465 else
466 break;
467 }
468
469 pv->pre.in = in;
470 pv->pre.out = in;
471
472 sts = pre_process_frame(in, qsv, pv);
473
474 if(sts){
475 hb_list_add(pv->list,out);
476 }
477
478 if( hb_list_count(pv->list) ){
479 *buf_out = hb_list_item(pv->list,0);
480 hb_list_rem(pv->list,*buf_out);
481 *buf_in = NULL;
482 }
483 else{
484 *buf_in = NULL;
485 *buf_out = in;
486 }
487
488 return HB_FILTER_OK;
489 }
hb_qsv_filter_pre_close(hb_filter_object_t * filter)490 static void hb_qsv_filter_pre_close( hb_filter_object_t * filter ){
491 int i = 0;
492 mfxStatus sts = MFX_ERR_NONE;
493
494 hb_filter_private_t * pv = filter->private_data;
495
496 if ( !pv )
497 {
498 return;
499 }
500
501 sws_freeContext(pv->sws_context_to_nv12);
502 sws_freeContext(pv->sws_context_from_nv12);
503
504 hb_qsv_context* qsv = pv->job->qsv.ctx;
505 if(qsv && qsv->vpp_space && hb_qsv_list_count(qsv->vpp_space) > 0 ){
506 if(pv->qsv_user && qsv->mfx_session){
507
508 sts=MFXVideoUSER_Unregister(qsv->mfx_session,0);
509 HB_QSV_CHECK_RET(sts, MFX_ERR_NONE, sts);
510
511 for(i=hb_list_count(pv->qsv_user);i>0;i--){
512 qsv_filter_t *plugin = hb_list_item(pv->qsv_user,i-1);
513 hb_list_rem(pv->qsv_user,plugin);
514 plugin_close(plugin);
515 }
516 hb_list_close(&pv->qsv_user);
517 }
518
519 // closing local stuff
520 qsv_filter_close(qsv,HB_QSV_VPP_USER);
521
522 // closing the common stuff
523 hb_qsv_context_clean(qsv,hb_qsv_full_path_is_enabled(pv->job));
524 }
525 hb_cond_close(&pv->pre.frame_completed);
526 hb_lock_close(&pv->pre.frame_completed_lock);
527
528 hb_cond_close(&pv->post.frame_completed);
529 hb_lock_close(&pv->post.frame_completed_lock);
530
531 hb_cond_close(&pv->pre_busy.frame_completed);
532 hb_lock_close(&pv->pre_busy.frame_completed_lock);
533
534 hb_cond_close(&pv->post_busy.frame_completed);
535 hb_lock_close(&pv->post_busy.frame_completed_lock);
536
537 hb_list_close( &pv->list );
538
539 free( pv );
540 filter->private_data = NULL;
541 }
542
543
hb_qsv_filter_post_info(hb_filter_object_t * filter)544 static hb_filter_info_t * hb_qsv_filter_post_info( hb_filter_object_t * filter )
545 {
546 hb_filter_private_t * pv = filter->private_data;
547 hb_filter_info_t * info;
548
549 if( !pv )
550 return NULL;
551
552 info = calloc(1, sizeof(hb_filter_info_t));
553 info->human_readable_desc = malloc(128);
554 info->human_readable_desc[0] = 0;
555
556 snprintf(info->human_readable_desc, 128, "copy data to opaque memory");
557
558 return info;
559 }
hb_qsv_filter_post_init(hb_filter_object_t * filter,hb_filter_init_t * init)560 static int hb_qsv_filter_post_init( hb_filter_object_t * filter,
561 hb_filter_init_t * init ){
562 filter->private_data = calloc( 1, sizeof(struct hb_filter_private_s) );
563 hb_filter_private_t * pv = filter->private_data;
564 pv->job = init->job;
565 return 0;
566 }
hb_qsv_filter_post_work(hb_filter_object_t * filter,hb_buffer_t ** buf_in,hb_buffer_t ** buf_out)567 static int hb_qsv_filter_post_work( hb_filter_object_t * filter,
568 hb_buffer_t ** buf_in,
569 hb_buffer_t ** buf_out ){
570 hb_filter_private_t * pv = filter->private_data;
571 hb_buffer_t * in = *buf_in;
572 hb_buffer_t * out = *buf_out;
573
574 if (in->s.flags & HB_BUF_FLAG_EOF)
575 {
576 *buf_out = in;
577 *buf_in = NULL;
578 return HB_FILTER_DONE;
579 }
580
581 hb_qsv_context* qsv = pv->job->qsv.ctx;
582 pv = in->qsv_details.filter_details;
583
584 if (!pv)
585 {
586 *buf_out = NULL;
587 *buf_in = NULL;
588 return HB_FILTER_OK;
589 }
590
591 while(1){
592 int ret = filter_pre_init(qsv,pv);
593 if(ret >= 2)
594 hb_qsv_sleep(1);
595 else
596 break;
597 }
598
599 pv->post.in = in;
600 pv->post.out = out;
601
602 // signal: input is prepared, can start inserting data back into pipeline
603 hb_lock(pv->post.frame_completed_lock);
604 pv->post.frame_go = 1;
605 hb_cond_broadcast(pv->post.frame_completed);
606 hb_unlock(pv->post.frame_completed_lock);
607
608 // wait: on signal that data is ready
609 hb_lock(pv->post_busy.frame_completed_lock);
610 while(!pv->post_busy.frame_go){
611 hb_cond_timedwait(pv->post_busy.frame_completed,pv->post_busy.frame_completed_lock,1000);
612 if(*pv->job->die)
613 break;
614 }
615 pv->post_busy.frame_go = 0;
616 hb_unlock(pv->post_busy.frame_completed_lock);
617
618 if (pv->post.status == HB_FILTER_OK || pv->post.status == HB_FILTER_DONE)
619 {
620 *buf_out = in;
621 }
622 else
623 {
624 *buf_out = NULL;
625 pv->post.status = HB_FILTER_OK;
626 }
627 *buf_in = NULL;
628
629 return HB_FILTER_OK;
630 }
hb_qsv_filter_post_close(hb_filter_object_t * filter)631 static void hb_qsv_filter_post_close( hb_filter_object_t * filter ){
632 hb_filter_private_t * pv = filter->private_data;
633
634 if ( !pv )
635 {
636 return;
637 }
638
639 free( pv );
640 filter->private_data = NULL;
641 }
642
643
qsv_PluginInit(mfxHDL pthis,mfxCoreInterface * core)644 mfxStatus MFX_CDECL qsv_PluginInit(mfxHDL pthis, mfxCoreInterface *core){
645 mfxStatus sts = MFX_ERR_NONE;
646
647 if(core && pthis){
648 qsv_filter_t *plugin = pthis;
649 plugin->core = core;
650
651 plugin->pluginparam.MaxThreadNum = 1;
652 plugin->pluginparam.ThreadPolicy = MFX_THREADPOLICY_SERIAL;
653 }
654 else
655 sts = MFX_ERR_NULL_PTR;
656
657 return sts;
658 }
qsv_PluginClose(mfxHDL pthis)659 mfxStatus MFX_CDECL qsv_PluginClose (mfxHDL pthis){
660 mfxStatus sts = MFX_ERR_NONE;
661 return sts;
662 }
qsv_GetPluginParam(mfxHDL pthis,mfxPluginParam * par)663 mfxStatus MFX_CDECL qsv_GetPluginParam(mfxHDL pthis, mfxPluginParam *par){
664 mfxStatus sts = MFX_ERR_NONE;
665
666 if(pthis){
667 qsv_filter_t *plugin = pthis;
668 *par = plugin->pluginparam;
669 }
670 else
671 sts = MFX_ERR_NULL_PTR;
672 return sts;
673 }
qsv_Submit(mfxHDL pthis,const mfxHDL * in,mfxU32 in_num,const mfxHDL * out,mfxU32 out_num,mfxThreadTask * task)674 mfxStatus MFX_CDECL qsv_Submit(mfxHDL pthis, const mfxHDL *in, mfxU32 in_num, const mfxHDL *out, mfxU32 out_num, mfxThreadTask *task){
675 mfxStatus sts = MFX_ERR_NONE;
676
677 qsv_filter_t *plugin = pthis;
678
679 mfxFrameSurface1 *surface_in = (mfxFrameSurface1 *)in[0];
680 mfxFrameSurface1 *surface_out = (mfxFrameSurface1 *)out[0];
681 mfxFrameSurface1 *real_surface_in = surface_in;
682 mfxFrameSurface1 *real_surface_out = surface_out;
683
684 sts = plugin->core->GetRealSurface(plugin->core->pthis, surface_in, &real_surface_in);
685 HB_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, MFX_ERR_MEMORY_ALLOC);
686
687 sts = plugin->core->GetRealSurface(plugin->core->pthis, surface_out, &real_surface_out);
688 HB_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, MFX_ERR_MEMORY_ALLOC);
689
690 int task_idx = get_free_task(plugin->tasks);
691
692 if (task_idx == -1)
693 {
694 return MFX_WRN_DEVICE_BUSY;
695 }
696
697 plugin->core->IncreaseReference(plugin->core->pthis, &(real_surface_in->Data));
698 plugin->core->IncreaseReference(plugin->core->pthis, &(real_surface_out->Data));
699
700 // to preserve timing if other filters are used in-between
701 surface_out->Data.TimeStamp = surface_in->Data.TimeStamp;
702 surface_out->Data.FrameOrder = surface_in->Data.FrameOrder;
703
704 qsv_filter_task_t *current_task = hb_list_item(plugin->tasks,task_idx);
705 current_task->in = real_surface_in;
706 current_task->out = real_surface_out;
707 current_task->busy = 1;
708 current_task->pv = plugin->pv;
709
710 *task = (mfxThreadTask)current_task;
711
712 return sts;
713 }
qsv_Execute(mfxHDL pthis,mfxThreadTask task,mfxU32 uid_p,mfxU32 uid_a)714 mfxStatus MFX_CDECL qsv_Execute(mfxHDL pthis, mfxThreadTask task, mfxU32 uid_p, mfxU32 uid_a){
715 mfxStatus sts = MFX_ERR_NONE;
716
717 qsv_filter_task_t *current_task = (qsv_filter_task_t *)task;
718
719 sts = (current_task->processor.process)(current_task,0);
720 HB_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
721
722 sts = MFX_TASK_DONE;
723 return sts;
724 }
qsv_FreeResources(mfxHDL pthis,mfxThreadTask task,mfxStatus sts)725 mfxStatus MFX_CDECL qsv_FreeResources(mfxHDL pthis, mfxThreadTask task, mfxStatus sts){
726
727 qsv_filter_t *plugin = pthis;
728 qsv_filter_task_t *current_task = (qsv_filter_task_t *)task;
729
730 plugin->core->DecreaseReference(plugin->core->pthis, &(current_task->in->Data));
731 plugin->core->DecreaseReference(plugin->core->pthis, &(current_task->out->Data));
732
733 current_task->busy = 0;
734
735 hb_lock(plugin->pv->pre_busy.frame_completed_lock);
736 plugin->pv->pre_busy.frame_go = 1;
737 hb_cond_broadcast(plugin->pv->pre_busy.frame_completed);
738 hb_unlock(plugin->pv->pre_busy.frame_completed_lock);
739
740 return MFX_ERR_NONE;
741 }
742
plugin_init(qsv_filter_t * plugin,mfxVideoParam * param)743 mfxStatus plugin_init(qsv_filter_t* plugin, mfxVideoParam *param){
744 mfxStatus sts = MFX_ERR_NONE;
745
746 if(plugin->is_init_done) return sts;
747
748 plugin->videoparam = param;
749
750 mfxExtOpaqueSurfaceAlloc* plugin_opaque_alloc = NULL;
751
752 plugin_opaque_alloc = (mfxExtOpaqueSurfaceAlloc*) get_ext_buffer(plugin->videoparam->ExtParam,
753 plugin->videoparam->NumExtParam, MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION);
754
755 if(!plugin_opaque_alloc || !plugin_opaque_alloc->In.Surfaces || !plugin_opaque_alloc->Out.Surfaces)
756 return MFX_ERR_INVALID_VIDEO_PARAM;
757
758 sts = plugin->core->MapOpaqueSurface(plugin->core->pthis, plugin_opaque_alloc->In.NumSurface,
759 plugin_opaque_alloc->In.Type, plugin_opaque_alloc->In.Surfaces);
760 HB_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
761
762
763 sts = plugin->core->MapOpaqueSurface(plugin->core->pthis, plugin_opaque_alloc->Out.NumSurface,
764 plugin_opaque_alloc->Out.Type, plugin_opaque_alloc->Out.Surfaces);
765 HB_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
766
767
768 plugin->tasks = hb_list_init();
769 qsv_filter_task_t *task = calloc( 1, sizeof( qsv_filter_task_t ));
770
771 task->processor.process = process_filter;
772 task->processor.alloc = &plugin->core->FrameAllocator;
773 task->processor.core = plugin->core;
774
775 hb_list_add(plugin->tasks,task);
776
777 plugin->is_init_done = 1;
778
779 return sts;
780 }
781
plugin_close(qsv_filter_t * plugin)782 mfxStatus plugin_close(qsv_filter_t* plugin){
783 int i = 0;
784 mfxStatus sts = MFX_ERR_NONE;
785
786 if(!plugin->is_init_done) return sts;
787
788 mfxExtOpaqueSurfaceAlloc* plugin_opaque_alloc = NULL;
789
790 plugin_opaque_alloc = (mfxExtOpaqueSurfaceAlloc*) get_ext_buffer(plugin->videoparam->ExtParam,
791 plugin->videoparam->NumExtParam, MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION);
792
793 if(!plugin_opaque_alloc || !plugin_opaque_alloc->In.Surfaces || !plugin_opaque_alloc->Out.Surfaces)
794 return MFX_ERR_INVALID_VIDEO_PARAM;
795
796 sts = plugin->core->UnmapOpaqueSurface(plugin->core->pthis, plugin_opaque_alloc->In.NumSurface,
797 plugin_opaque_alloc->In.Type, plugin_opaque_alloc->In.Surfaces);
798 HB_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
799
800
801 sts = plugin->core->UnmapOpaqueSurface(plugin->core->pthis, plugin_opaque_alloc->Out.NumSurface,
802 plugin_opaque_alloc->Out.Type, plugin_opaque_alloc->Out.Surfaces);
803 HB_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
804
805 if(plugin->tasks){
806 for(i=hb_list_count(plugin->tasks);i>0;i--){
807 qsv_filter_task_t *task = hb_list_item(plugin->tasks,i-1);
808 hb_list_rem(plugin->tasks,task);
809 free(task);
810 }
811 hb_list_close(&plugin->tasks);
812 }
813
814 plugin->is_init_done = 0;
815
816 return sts;
817 }
818
get_ext_buffer(mfxExtBuffer ** buffers,mfxU32 buffers_num,mfxU32 buffer_id)819 mfxExtBuffer* get_ext_buffer(mfxExtBuffer** buffers, mfxU32 buffers_num, mfxU32 buffer_id){
820 int i = 0;
821 if(!buffers) return 0;
822 for(i=0;i<buffers_num;i++){
823 if(!buffers[i]) continue;
824 if(buffers[i]->BufferId == buffer_id)
825 return buffers[i];
826 }
827 return 0;
828 }
829
get_free_task(hb_list_t * tasks)830 int get_free_task(hb_list_t* tasks){
831 int ret = -1;
832 int i = 0;
833 for(i=0;i<hb_list_count(tasks);i++){
834 qsv_filter_task_t* task = hb_list_item(tasks,i);
835 if(!task->busy){
836 ret = i;
837 break;
838 }
839 }
840 return ret;
841 }
842
lock_frame(mfxFrameAllocator * alloc,mfxFrameSurface1 * surface)843 mfxStatus lock_frame(mfxFrameAllocator *alloc,mfxFrameSurface1 *surface){
844 mfxStatus sts = MFX_ERR_NONE;
845 // prevent double lock
846 if (surface->Data.Y != 0 && surface->Data.MemId !=0){
847 return MFX_ERR_UNSUPPORTED;
848 }
849 // not allocated, therefore no lock
850 if (surface->Data.Y != 0){
851 return MFX_ERR_NONE;
852 }
853 sts = alloc->Lock(alloc->pthis,surface->Data.MemId,&surface->Data);
854 return sts;
855 }
856
unlock_frame(mfxFrameAllocator * alloc,mfxFrameSurface1 * surface)857 mfxStatus unlock_frame(mfxFrameAllocator *alloc,mfxFrameSurface1 *surface){
858 mfxStatus sts = MFX_ERR_NONE;
859 // not allocated
860 if (surface->Data.Y != 0 && surface->Data.MemId == 0){
861 return MFX_ERR_NONE;
862 }
863 // not locked
864 if (surface->Data.Y == 0){
865 return MFX_ERR_NONE;
866 }
867 sts = alloc->Unlock(alloc->pthis,surface->Data.MemId,&surface->Data);
868 return sts;
869 }
870
871
process_filter(qsv_filter_task_t * task,void * params)872 int process_filter(qsv_filter_task_t* task, void* params){
873 mfxStatus sts = MFX_ERR_NONE;
874
875 if (MFX_ERR_NONE != (sts = lock_frame(task->processor.alloc,task->in)))return sts;
876 if (MFX_ERR_NONE != (sts = lock_frame(task->processor.alloc,task->out)))
877 {
878 unlock_frame(task->processor.alloc,task->in);
879 return sts;
880 }
881
882 qsv_nv12_to_yuv420(task->pv->sws_context_from_nv12,task->pv->pre.out, task->in, task->processor.core);
883
884 // signal: input is prepared, converted from pipeline into internal buffer
885 hb_lock(task->pv->pre.frame_completed_lock);
886 task->pv->pre.frame_go = 1;
887 hb_cond_broadcast(task->pv->pre.frame_completed);
888 hb_unlock(task->pv->pre.frame_completed_lock);
889
890 // wait: input is prepared, converted from pipeline into internal buffer
891 hb_lock(task->pv->post.frame_completed_lock);
892 while(!task->pv->post.frame_go){
893 hb_cond_timedwait(task->pv->post.frame_completed,task->pv->post.frame_completed_lock,1000);
894 if(*task->pv->job->die)
895 break;
896 }
897 task->pv->post.frame_go = 0;
898 hb_unlock(task->pv->post.frame_completed_lock);
899
900 // this is just a simple fun/test case
901 #if 0
902 {
903 int i = 0;
904 char *cur_line;
905 char* luma = task->pv->post.in->plane[0].data;
906 int pitch = task->pv->post.in->plane[0].stride;
907 int h = task->pv->post.in->plane[0].height;
908 int w = task->pv->post.in->plane[0].width;
909 for (i = 0; i < h; i++){
910
911 cur_line = luma + i * pitch;
912 if(i>h/4 && i < 3*h/4 && i % 5 == 0 )
913 memset(cur_line, 0 , w );
914 }
915 }
916 #endif
917
918 if(task->pv->post.in)
919 {
920 qsv_yuv420_to_nv12(task->pv->sws_context_to_nv12, task->out, task->pv->post.in);
921 }
922
923 // signal: output is prepared, converted from internal buffer into pipeline
924 hb_lock(task->pv->post_busy.frame_completed_lock);
925 task->pv->post_busy.frame_go = 1;
926 hb_cond_broadcast(task->pv->post_busy.frame_completed);
927 hb_unlock(task->pv->post_busy.frame_completed_lock);
928
929 unlock_frame(task->processor.alloc,task->in);
930 unlock_frame(task->processor.alloc,task->out);
931
932 return sts;
933 }
934
935 #endif // HB_PROJECT_FEATURE_QSV
936