1 /* ********************************************************************* *\
3 Copyright (C) 2013 Intel Corporation. All rights reserved.
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.
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.
27 \* ********************************************************************* */
33 #include "libavcodec/qsv.h"
34 #include "qsv_filter_pp.h"
35 #include "qsv_filter.h"
36 #include "qsv_memory.h"
39 static int hb_qsv_filter_pre_init( hb_filter_object_t
* filter
,
40 hb_filter_init_t
* init
);
41 static int hb_qsv_filter_pre_work( hb_filter_object_t
* filter
,
42 hb_buffer_t
** buf_in
,
43 hb_buffer_t
** buf_out
);
44 static int hb_qsv_filter_pre_info( hb_filter_object_t
* filter
,
45 hb_filter_info_t
* info
);
46 static void hb_qsv_filter_pre_close( hb_filter_object_t
* filter
);
48 static int hb_qsv_filter_post_init( hb_filter_object_t
* filter
,
49 hb_filter_init_t
* init
);
50 static int hb_qsv_filter_post_work( hb_filter_object_t
* filter
,
51 hb_buffer_t
** buf_in
,
52 hb_buffer_t
** buf_out
);
53 static int hb_qsv_filter_post_info( hb_filter_object_t
* filter
,
54 hb_filter_info_t
* info
);
55 static void hb_qsv_filter_post_close( hb_filter_object_t
* filter
);
58 hb_filter_object_t hb_filter_qsv_pre
=
60 .id
= HB_FILTER_QSV_PRE
,
62 .name
= "Quick Sync Video user filter (pre)",
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
,
70 hb_filter_object_t hb_filter_qsv_post
=
72 .id
= HB_FILTER_QSV_POST
,
74 .name
= "Quick Sync Video user filter (post)",
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
,
83 static int filter_pre_init( av_qsv_context
* qsv
, hb_filter_private_t
* pv
){
84 mfxStatus sts
= MFX_ERR_NONE
;
89 av_qsv_space
*prev_vpp
= 0;
92 qsv
->vpp_space
= av_qsv_list_init(HAVE_THREADS
);
93 // note some change as : when no size changes -> no VPP used
94 // impact on : prev_vpp
98 for(i
=0; i
<av_qsv_list_count(qsv
->vpp_space
);i
++){
99 av_qsv_space
*qsv_vpp
= av_qsv_list_item( qsv
->vpp_space
, i
);
100 if(qsv_vpp
->type
== AV_QSV_VPP_USER
){
101 pv
->vpp_space
= qsv_vpp
;
105 if(qsv_vpp
->type
== AV_QSV_VPP_DEFAULT
){
113 pv
->vpp_space
= calloc( 1, sizeof( av_qsv_space
));
114 pv
->vpp_space
->type
= AV_QSV_VPP_USER
;
115 av_qsv_list_add( qsv
->vpp_space
, pv
->vpp_space
);
116 av_qsv_add_context_usage(qsv
,HAVE_THREADS
);
119 if(pv
->vpp_space
->is_init_done
) return 1;
121 if(!qsv
->dec_space
|| !qsv
->dec_space
->is_init_done
) return 2;
123 av_qsv_space
*qsv_vpp
= pv
->vpp_space
;
125 AV_QSV_ZERO_MEMORY(qsv_vpp
->m_mfxVideoParam
);
130 memcpy( &qsv_vpp
->m_mfxVideoParam
.vpp
, &prev_vpp
->m_mfxVideoParam
.vpp
, sizeof(prev_vpp
->m_mfxVideoParam
.vpp
));
134 AV_QSV_ZERO_MEMORY(qsv_vpp
->m_mfxVideoParam
);
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
;
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
= AV_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 AV_QSV_ALIGN16(pv
->job
->title
->geometry
.height
) : AV_QSV_ALIGN32(pv
->job
->title
->geometry
.height
);
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
= AV_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 AV_QSV_ALIGN16(pv
->job
->title
->geometry
.height
) : AV_QSV_ALIGN32(pv
->job
->title
->geometry
.height
);
173 memset(&qsv_vpp
->request
, 0, sizeof(mfxFrameAllocRequest
)*2);
176 qsv_vpp
->m_mfxVideoParam
.IOPattern
= MFX_IOPATTERN_IN_OPAQUE_MEMORY
| MFX_IOPATTERN_OUT_OPAQUE_MEMORY
;
178 qsv_vpp
->surface_num
= FFMIN(prev_vpp
? prev_vpp
->surface_num
: qsv
->dec_space
->surface_num
/2, AV_QSV_SURFACE_NUM
);
180 for(i
= 0; i
< qsv_vpp
->surface_num
; i
++){
181 qsv_vpp
->p_surfaces
[i
] = av_mallocz( sizeof(mfxFrameSurface1
) );
182 AV_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
));
186 qsv_vpp
->sync_num
= FFMIN(prev_vpp
? prev_vpp
->sync_num
: qsv
->dec_space
->sync_num
, AV_QSV_SYNC_NUM
);
187 for (i
= 0; i
< qsv_vpp
->sync_num
; i
++){
188 qsv_vpp
->p_syncp
[i
] = av_mallocz(sizeof(av_qsv_sync
));
189 AV_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 AV_QSV_CHECK_POINTER(qsv_vpp
->p_syncp
[i
]->p_sync
, MFX_ERR_MEMORY_ALLOC
);
194 memset(&qsv_vpp
->ext_opaque_alloc
, 0, sizeof(mfxExtOpaqueSurfaceAlloc
));
195 qsv_vpp
->m_mfxVideoParam
.NumExtParam
= qsv_vpp
->p_ext_param_num
= 1;
197 qsv_vpp
->p_ext_params
= av_mallocz(sizeof(mfxExtBuffer
*)*qsv_vpp
->p_ext_param_num
);
198 AV_QSV_CHECK_POINTER(qsv_vpp
->p_ext_params
, MFX_ERR_MEMORY_ALLOC
);
200 qsv_vpp
->m_mfxVideoParam
.ExtParam
= qsv_vpp
->p_ext_params
;
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
;
207 qsv_vpp
->ext_opaque_alloc
.In
.Surfaces
= prev_vpp
->p_surfaces
;
208 qsv_vpp
->ext_opaque_alloc
.In
.NumSurface
= prev_vpp
->surface_num
;
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
;
214 qsv_vpp
->ext_opaque_alloc
.In
.Type
= qsv
->dec_space
->request
[0].Type
;
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
;
220 pv
->qsv_user
= hb_list_init();
222 qsv_filter_t
*plugin
= av_mallocz( sizeof(qsv_filter_t
) );
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
;
233 hb_list_add(pv
->qsv_user
,plugin
);
235 sts
=MFXVideoUSER_Register(qsv
->mfx_session
,0,&plugin
->plug
);
236 AV_QSV_CHECK_RESULT(sts
, MFX_ERR_NONE
, sts
);
238 plugin_init(plugin
,&qsv_vpp
->m_mfxVideoParam
);
240 qsv_vpp
->is_init_done
= 1;
245 static int hb_qsv_filter_pre_info( hb_filter_object_t
* filter
,
246 hb_filter_info_t
* info
){
247 hb_filter_private_t
* pv
= filter
->private_data
;
251 sprintf(info
->human_readable_desc
, "copy data to system memory");
255 static int hb_qsv_filter_pre_init( hb_filter_object_t
* filter
,
256 hb_filter_init_t
* init
){
257 filter
->private_data
= calloc( 1, sizeof(struct hb_filter_private_s
) );
258 hb_filter_private_t
* pv
= filter
->private_data
;
261 pv
->pre
.frame_go
= 0;
262 pv
->pre
.frame_completed
= hb_cond_init();
263 pv
->pre
.frame_completed_lock
= hb_lock_init();
265 pv
->post
.frame_go
= 0;
266 pv
->post
.frame_completed
= hb_cond_init();
267 pv
->post
.frame_completed_lock
= hb_lock_init();
269 pv
->pre_busy
.frame_go
= 0;
270 pv
->pre_busy
.frame_completed
= hb_cond_init();
271 pv
->pre_busy
.frame_completed_lock
= hb_lock_init();
273 pv
->post_busy
.frame_go
= 0;
274 pv
->post_busy
.frame_completed
= hb_cond_init();
275 pv
->post_busy
.frame_completed_lock
= hb_lock_init();
277 pv
->list
= hb_list_init();
280 // PIX_FMT_YUV420P, ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples) , 3 planes: Y, U, V
281 // 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)
282 pv
->sws_context_from_nv12
= hb_sws_get_context(
283 pv
->job
->title
->geometry
.width
, pv
->job
->title
->geometry
.height
,
285 pv
->job
->title
->geometry
.width
, pv
->job
->title
->geometry
.height
,
287 SWS_LANCZOS
|SWS_ACCURATE_RND
);
288 pv
->sws_context_to_nv12
= hb_sws_get_context(
289 pv
->job
->title
->geometry
.width
, pv
->job
->title
->geometry
.height
,
291 pv
->job
->title
->geometry
.width
, pv
->job
->title
->geometry
.height
,
293 SWS_LANCZOS
|SWS_ACCURATE_RND
);
296 int pre_process_frame(hb_buffer_t
*in
, av_qsv_context
* qsv
, hb_filter_private_t
* pv
){
298 // 1 if have results , 0 otherwise
301 av_qsv_list
* received_item
= in
->qsv_details
.qsv_atom
;
303 mfxStatus sts
= MFX_ERR_NONE
;
304 mfxFrameSurface1
*work_surface
= NULL
;
305 av_qsv_stage
* stage
= 0;
307 av_qsv_space
*qsv_vpp
= pv
->vpp_space
;
311 stage
= av_qsv_get_last_stage( received_item
);
312 work_surface
= stage
->out
.p_surface
;
315 int sync_idx
= av_qsv_get_free_sync(qsv_vpp
, qsv
);
316 int surface_idx
= -1;
322 hb_error("qsv: Not enough resources allocated for the preprocessing filter");
327 if (sts
== MFX_ERR_MORE_SURFACE
|| sts
== MFX_ERR_NONE
)
328 surface_idx
= av_qsv_get_free_surface(qsv_vpp
, qsv
, &(qsv_vpp
->m_mfxVideoParam
.vpp
.Out
), QSV_PART_ANY
);
329 if (surface_idx
== -1) {
330 hb_error("qsv: Not enough resources allocated for the preprocessing filter");
335 sts
= MFXVideoUSER_ProcessFrameAsync(qsv
->mfx_session
, &work_surface
, 1, &qsv_vpp
->p_surfaces
[surface_idx
] , 1, qsv_vpp
->p_syncp
[sync_idx
]->p_sync
);
337 if (MFX_ERR_MORE_DATA
== sts
)
339 if (!qsv_vpp
->pending
)
341 qsv_vpp
->pending
= av_qsv_list_init(0);
344 // if we have no results, we should not miss resource(s)
345 av_qsv_list_add( qsv_vpp
->pending
, received_item
);
347 ff_qsv_atomic_dec(&qsv_vpp
->p_syncp
[sync_idx
]->in_use
);
353 if( MFX_ERR_MORE_SURFACE
== sts
|| MFX_ERR_NONE
<= sts
){
354 if( MFX_ERR_MORE_SURFACE
== sts
)
357 if (qsv_vpp
->p_surfaces
[surface_idx
] && MFX_WRN_DEVICE_BUSY
!= sts
)
358 ff_qsv_atomic_inc(&qsv_vpp
->p_surfaces
[surface_idx
]->Data
.Locked
);
361 AV_QSV_CHECK_RESULT(sts
, MFX_ERR_NONE
, sts
);
363 if (MFX_ERR_NONE
<= sts
) // repeat the call if warning and no output
365 if (MFX_WRN_DEVICE_BUSY
== sts
){
366 hb_lock(pv
->pre_busy
.frame_completed_lock
);
367 while(!pv
->pre_busy
.frame_go
){
368 hb_cond_timedwait(pv
->pre_busy
.frame_completed
,pv
->pre_busy
.frame_completed_lock
,1000);
372 pv
->pre_busy
.frame_go
= 0;
373 hb_unlock(pv
->pre_busy
.frame_completed_lock
);
377 hb_lock(pv
->pre
.frame_completed_lock
);
378 while(!pv
->pre
.frame_go
){
379 hb_cond_timedwait(pv
->pre
.frame_completed
,pv
->pre
.frame_completed_lock
,1000);
383 pv
->pre
.frame_go
= 0;
384 hb_unlock(pv
->pre
.frame_completed_lock
);
389 ff_qsv_atomic_dec(&work_surface
->Data
.Locked
);
392 // inserting for the future, will be locked until very ready
394 av_qsv_stage
* new_stage
= av_qsv_stage_init();
396 new_stage
->type
= AV_QSV_VPP_USER
;
397 new_stage
->in
.p_surface
= work_surface
;
398 new_stage
->out
.p_surface
= qsv_vpp
->p_surfaces
[surface_idx
];
399 new_stage
->out
.sync
= qsv_vpp
->p_syncp
[sync_idx
];
400 av_qsv_add_stagee( &received_item
, new_stage
,HAVE_THREADS
);
402 // add pending resources for the proper reclaim later
403 if( qsv_vpp
->pending
){
404 if( av_qsv_list_count(qsv_vpp
->pending
)>0 ){
405 new_stage
->pending
= qsv_vpp
->pending
;
407 qsv_vpp
->pending
= 0;
409 // making free via decrement for all pending
411 for (i
= av_qsv_list_count(new_stage
->pending
); i
> 0; i
--){
412 av_qsv_list
*atom_list
= av_qsv_list_item(new_stage
->pending
, i
-1);
413 av_qsv_stage
*stage
= av_qsv_get_last_stage( atom_list
);
414 mfxFrameSurface1
*work_surface
= stage
->out
.p_surface
;
416 ff_qsv_atomic_dec(&work_surface
->Data
.Locked
);
424 ff_qsv_atomic_dec(&qsv_vpp
->p_syncp
[sync_idx
]->in_use
);
426 if (MFX_ERR_NOT_ENOUGH_BUFFER
== sts
)
427 HB_DEBUG_ASSERT(1, "The bitstream buffer size is insufficient.");
435 static int hb_qsv_filter_pre_work( hb_filter_object_t
* filter
,
436 hb_buffer_t
** buf_in
,
437 hb_buffer_t
** buf_out
){
438 hb_filter_private_t
* pv
= filter
->private_data
;
439 hb_buffer_t
* in
= *buf_in
;
440 hb_buffer_t
* out
= *buf_out
;
443 av_qsv_context
* qsv
= pv
->job
->qsv
.ctx
;
445 if(!in
->qsv_details
.filter_details
)
446 in
->qsv_details
.filter_details
= pv
;
448 if (in
->s
.flags
& HB_BUF_FLAG_EOF
)
452 return HB_FILTER_DONE
;
456 int ret
= filter_pre_init(qsv
,pv
);
466 sts
= pre_process_frame(in
, qsv
, pv
);
469 hb_list_add(pv
->list
,out
);
472 if( hb_list_count(pv
->list
) ){
473 *buf_out
= hb_list_item(pv
->list
,0);
474 hb_list_rem(pv
->list
,*buf_out
);
484 static void hb_qsv_filter_pre_close( hb_filter_object_t
* filter
){
486 mfxStatus sts
= MFX_ERR_NONE
;
488 hb_filter_private_t
* pv
= filter
->private_data
;
495 sws_freeContext(pv
->sws_context_to_nv12
);
496 sws_freeContext(pv
->sws_context_from_nv12
);
498 av_qsv_context
* qsv
= pv
->job
->qsv
.ctx
;
499 if(qsv
&& qsv
->vpp_space
&& av_qsv_list_count(qsv
->vpp_space
) > 0 ){
500 if(pv
->qsv_user
&& qsv
->mfx_session
){
502 sts
=MFXVideoUSER_Unregister(qsv
->mfx_session
,0);
503 AV_QSV_CHECK_RESULT(sts
, MFX_ERR_NONE
, sts
);
505 for(i
=hb_list_count(pv
->qsv_user
);i
>0;i
--){
506 qsv_filter_t
*plugin
= hb_list_item(pv
->qsv_user
,i
-1);
507 hb_list_rem(pv
->qsv_user
,plugin
);
508 plugin_close(plugin
);
510 hb_list_close(&pv
->qsv_user
);
513 // closing local stuff
514 qsv_filter_close(qsv
,AV_QSV_VPP_USER
);
516 // closing the commong stuff
517 av_qsv_context_clean(qsv
);
519 hb_cond_close(&pv
->pre
.frame_completed
);
520 hb_lock_close(&pv
->pre
.frame_completed_lock
);
522 hb_cond_close(&pv
->post
.frame_completed
);
523 hb_lock_close(&pv
->post
.frame_completed_lock
);
525 hb_cond_close(&pv
->pre_busy
.frame_completed
);
526 hb_lock_close(&pv
->pre_busy
.frame_completed_lock
);
528 hb_cond_close(&pv
->post_busy
.frame_completed
);
529 hb_lock_close(&pv
->post_busy
.frame_completed_lock
);
531 hb_list_close( &pv
->list
);
534 filter
->private_data
= NULL
;
538 static int hb_qsv_filter_post_info( hb_filter_object_t
* filter
,
539 hb_filter_info_t
* info
){
540 hb_filter_private_t
* pv
= filter
->private_data
;
544 sprintf(info
->human_readable_desc
, "copy data to opaque memory");
548 static int hb_qsv_filter_post_init( hb_filter_object_t
* filter
,
549 hb_filter_init_t
* init
){
550 filter
->private_data
= calloc( 1, sizeof(struct hb_filter_private_s
) );
551 hb_filter_private_t
* pv
= filter
->private_data
;
555 static int hb_qsv_filter_post_work( hb_filter_object_t
* filter
,
556 hb_buffer_t
** buf_in
,
557 hb_buffer_t
** buf_out
){
558 hb_filter_private_t
* pv
= filter
->private_data
;
559 hb_buffer_t
* in
= *buf_in
;
560 hb_buffer_t
* out
= *buf_out
;
562 if (in
->s
.flags
& HB_BUF_FLAG_EOF
)
566 return HB_FILTER_DONE
;
569 av_qsv_context
* qsv
= pv
->job
->qsv
.ctx
;
570 pv
= in
->qsv_details
.filter_details
;
580 int ret
= filter_pre_init(qsv
,pv
);
590 // signal: input is prepared, can start inserting data back into pipeline
591 hb_lock(pv
->post
.frame_completed_lock
);
592 pv
->post
.frame_go
= 1;
593 hb_cond_broadcast(pv
->post
.frame_completed
);
594 hb_unlock(pv
->post
.frame_completed_lock
);
596 // wait: on signal that data is ready
597 hb_lock(pv
->post_busy
.frame_completed_lock
);
598 while(!pv
->post_busy
.frame_go
){
599 hb_cond_timedwait(pv
->post_busy
.frame_completed
,pv
->post_busy
.frame_completed_lock
,1000);
603 pv
->post_busy
.frame_go
= 0;
604 hb_unlock(pv
->post_busy
.frame_completed_lock
);
606 if (pv
->post
.status
== HB_FILTER_OK
|| pv
->post
.status
== HB_FILTER_DONE
)
613 pv
->post
.status
= HB_FILTER_OK
;
619 static void hb_qsv_filter_post_close( hb_filter_object_t
* filter
){
620 hb_filter_private_t
* pv
= filter
->private_data
;
628 filter
->private_data
= NULL
;
632 mfxStatus MFX_CDECL
qsv_PluginInit(mfxHDL pthis
, mfxCoreInterface
*core
){
633 mfxStatus sts
= MFX_ERR_NONE
;
636 qsv_filter_t
*plugin
= pthis
;
639 plugin
->pluginparam
.MaxThreadNum
= 1;
640 plugin
->pluginparam
.ThreadPolicy
= MFX_THREADPOLICY_SERIAL
;
643 sts
= MFX_ERR_NULL_PTR
;
647 mfxStatus MFX_CDECL
qsv_PluginClose (mfxHDL pthis
){
648 mfxStatus sts
= MFX_ERR_NONE
;
651 mfxStatus MFX_CDECL
qsv_GetPluginParam(mfxHDL pthis
, mfxPluginParam
*par
){
652 mfxStatus sts
= MFX_ERR_NONE
;
655 qsv_filter_t
*plugin
= pthis
;
656 *par
= plugin
->pluginparam
;
659 sts
= MFX_ERR_NULL_PTR
;
662 mfxStatus MFX_CDECL
qsv_Submit(mfxHDL pthis
, const mfxHDL
*in
, mfxU32 in_num
, const mfxHDL
*out
, mfxU32 out_num
, mfxThreadTask
*task
){
663 mfxStatus sts
= MFX_ERR_NONE
;
665 qsv_filter_t
*plugin
= pthis
;
667 mfxFrameSurface1
*surface_in
= (mfxFrameSurface1
*)in
[0];
668 mfxFrameSurface1
*surface_out
= (mfxFrameSurface1
*)out
[0];
669 mfxFrameSurface1
*real_surface_in
= surface_in
;
670 mfxFrameSurface1
*real_surface_out
= surface_out
;
672 sts
= plugin
->core
->GetRealSurface(plugin
->core
->pthis
, surface_in
, &real_surface_in
);
673 AV_QSV_CHECK_RESULT(sts
, MFX_ERR_NONE
, MFX_ERR_MEMORY_ALLOC
);
675 sts
= plugin
->core
->GetRealSurface(plugin
->core
->pthis
, surface_out
, &real_surface_out
);
676 AV_QSV_CHECK_RESULT(sts
, MFX_ERR_NONE
, MFX_ERR_MEMORY_ALLOC
);
678 int task_idx
= get_free_task(plugin
->tasks
);
682 return MFX_WRN_DEVICE_BUSY
;
685 plugin
->core
->IncreaseReference(plugin
->core
->pthis
, &(real_surface_in
->Data
));
686 plugin
->core
->IncreaseReference(plugin
->core
->pthis
, &(real_surface_out
->Data
));
688 // to preserve timing if other filters are used in-between
689 surface_out
->Data
.TimeStamp
= surface_in
->Data
.TimeStamp
;
690 surface_out
->Data
.FrameOrder
= surface_in
->Data
.FrameOrder
;
692 qsv_filter_task_t
*current_task
= hb_list_item(plugin
->tasks
,task_idx
);
693 current_task
->in
= real_surface_in
;
694 current_task
->out
= real_surface_out
;
695 current_task
->busy
= 1;
696 current_task
->pv
= plugin
->pv
;
698 *task
= (mfxThreadTask
)current_task
;
702 mfxStatus MFX_CDECL
qsv_Execute(mfxHDL pthis
, mfxThreadTask task
, mfxU32 uid_p
, mfxU32 uid_a
){
703 mfxStatus sts
= MFX_ERR_NONE
;
705 qsv_filter_task_t
*current_task
= (qsv_filter_task_t
*)task
;
706 qsv_filter_t
*plugin
= pthis
;
708 sts
= (current_task
->processor
.process
)(current_task
,0);
709 AV_QSV_CHECK_RESULT(sts
, MFX_ERR_NONE
, sts
);
714 mfxStatus MFX_CDECL
qsv_FreeResources(mfxHDL pthis
, mfxThreadTask task
, mfxStatus sts
){
716 qsv_filter_t
*plugin
= pthis
;
717 qsv_filter_task_t
*current_task
= (qsv_filter_task_t
*)task
;
719 plugin
->core
->DecreaseReference(plugin
->core
->pthis
, &(current_task
->in
->Data
));
720 plugin
->core
->DecreaseReference(plugin
->core
->pthis
, &(current_task
->out
->Data
));
722 current_task
->busy
= 0;
724 hb_lock(plugin
->pv
->pre_busy
.frame_completed_lock
);
725 plugin
->pv
->pre_busy
.frame_go
= 1;
726 hb_cond_broadcast(plugin
->pv
->pre_busy
.frame_completed
);
727 hb_unlock(plugin
->pv
->pre_busy
.frame_completed_lock
);
732 mfxStatus
plugin_init(qsv_filter_t
* plugin
, mfxVideoParam
*param
){
733 mfxStatus sts
= MFX_ERR_NONE
;
735 if(plugin
->is_init_done
) return sts
;
737 plugin
->videoparam
= param
;
739 mfxExtOpaqueSurfaceAlloc
* plugin_opaque_alloc
= NULL
;
741 plugin_opaque_alloc
= (mfxExtOpaqueSurfaceAlloc
*) get_ext_buffer(plugin
->videoparam
->ExtParam
,
742 plugin
->videoparam
->NumExtParam
, MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION
);
744 if(!plugin_opaque_alloc
|| !plugin_opaque_alloc
->In
.Surfaces
|| !plugin_opaque_alloc
->Out
.Surfaces
)
745 return MFX_ERR_INVALID_VIDEO_PARAM
;
747 sts
= plugin
->core
->MapOpaqueSurface(plugin
->core
->pthis
, plugin_opaque_alloc
->In
.NumSurface
,
748 plugin_opaque_alloc
->In
.Type
, plugin_opaque_alloc
->In
.Surfaces
);
749 AV_QSV_CHECK_RESULT(sts
, MFX_ERR_NONE
, sts
);
752 sts
= plugin
->core
->MapOpaqueSurface(plugin
->core
->pthis
, plugin_opaque_alloc
->Out
.NumSurface
,
753 plugin_opaque_alloc
->Out
.Type
, plugin_opaque_alloc
->Out
.Surfaces
);
754 AV_QSV_CHECK_RESULT(sts
, MFX_ERR_NONE
, sts
);
757 plugin
->tasks
= hb_list_init();
758 qsv_filter_task_t
*task
= calloc( 1, sizeof( qsv_filter_task_t
));
760 task
->processor
.process
= process_filter
;
761 task
->processor
.alloc
= &plugin
->core
->FrameAllocator
;
762 task
->processor
.core
= plugin
->core
;
764 hb_list_add(plugin
->tasks
,task
);
766 plugin
->is_init_done
= 1;
771 mfxStatus
plugin_close(qsv_filter_t
* plugin
){
773 mfxStatus sts
= MFX_ERR_NONE
;
775 if(!plugin
->is_init_done
) return sts
;
777 mfxExtOpaqueSurfaceAlloc
* plugin_opaque_alloc
= NULL
;
779 plugin_opaque_alloc
= (mfxExtOpaqueSurfaceAlloc
*) get_ext_buffer(plugin
->videoparam
->ExtParam
,
780 plugin
->videoparam
->NumExtParam
, MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION
);
782 if(!plugin_opaque_alloc
|| !plugin_opaque_alloc
->In
.Surfaces
|| !plugin_opaque_alloc
->Out
.Surfaces
)
783 return MFX_ERR_INVALID_VIDEO_PARAM
;
785 sts
= plugin
->core
->UnmapOpaqueSurface(plugin
->core
->pthis
, plugin_opaque_alloc
->In
.NumSurface
,
786 plugin_opaque_alloc
->In
.Type
, plugin_opaque_alloc
->In
.Surfaces
);
787 AV_QSV_CHECK_RESULT(sts
, MFX_ERR_NONE
, sts
);
790 sts
= plugin
->core
->UnmapOpaqueSurface(plugin
->core
->pthis
, plugin_opaque_alloc
->Out
.NumSurface
,
791 plugin_opaque_alloc
->Out
.Type
, plugin_opaque_alloc
->Out
.Surfaces
);
792 AV_QSV_CHECK_RESULT(sts
, MFX_ERR_NONE
, sts
);
795 for(i
=hb_list_count(plugin
->tasks
);i
>0;i
--){
796 qsv_filter_task_t
*task
= hb_list_item(plugin
->tasks
,i
-1);
797 hb_list_rem(plugin
->tasks
,task
);
800 hb_list_close(&plugin
->tasks
);
803 plugin
->is_init_done
= 0;
808 mfxExtBuffer
* get_ext_buffer(mfxExtBuffer
** buffers
, mfxU32 buffers_num
, mfxU32 buffer_id
){
810 if(!buffers
) return 0;
811 for(i
=0;i
<buffers_num
;i
++){
812 if(!buffers
[i
]) continue;
813 if(buffers
[i
]->BufferId
== buffer_id
)
819 int get_free_task(hb_list_t
* tasks
){
822 for(i
=0;i
<hb_list_count(tasks
);i
++){
823 qsv_filter_task_t
* task
= hb_list_item(tasks
,i
);
832 mfxStatus
lock_frame(mfxFrameAllocator
*alloc
,mfxFrameSurface1
*surface
){
833 mfxStatus sts
= MFX_ERR_NONE
;
834 // prevent double lock
835 if (surface
->Data
.Y
!= 0 && surface
->Data
.MemId
!=0){
836 return MFX_ERR_UNSUPPORTED
;
838 // not allocated, therefore no lock
839 if (surface
->Data
.Y
!= 0){
842 sts
= alloc
->Lock(alloc
->pthis
,surface
->Data
.MemId
,&surface
->Data
);
846 mfxStatus
unlock_frame(mfxFrameAllocator
*alloc
,mfxFrameSurface1
*surface
){
847 mfxStatus sts
= MFX_ERR_NONE
;
849 if (surface
->Data
.Y
!= 0 && surface
->Data
.MemId
== 0){
853 if (surface
->Data
.Y
== 0){
856 sts
= alloc
->Unlock(alloc
->pthis
,surface
->Data
.MemId
,&surface
->Data
);
861 int process_filter(qsv_filter_task_t
* task
, void* params
){
862 mfxStatus sts
= MFX_ERR_NONE
;
864 if (MFX_ERR_NONE
!= (sts
= lock_frame(task
->processor
.alloc
,task
->in
)))return sts
;
865 if (MFX_ERR_NONE
!= (sts
= lock_frame(task
->processor
.alloc
,task
->out
)))
867 unlock_frame(task
->processor
.alloc
,task
->in
);
871 qsv_nv12_to_yuv420(task
->pv
->sws_context_from_nv12
,task
->pv
->pre
.out
, task
->in
, task
->processor
.core
);
873 // signal: input is prepared, converted from pipeline into internal buffer
874 hb_lock(task
->pv
->pre
.frame_completed_lock
);
875 task
->pv
->pre
.frame_go
= 1;
876 hb_cond_broadcast(task
->pv
->pre
.frame_completed
);
877 hb_unlock(task
->pv
->pre
.frame_completed_lock
);
879 // wait: input is prepared, converted from pipeline into internal buffer
880 hb_lock(task
->pv
->post
.frame_completed_lock
);
881 while(!task
->pv
->post
.frame_go
){
882 hb_cond_timedwait(task
->pv
->post
.frame_completed
,task
->pv
->post
.frame_completed_lock
,1000);
883 if(*task
->pv
->job
->die
)
886 task
->pv
->post
.frame_go
= 0;
887 hb_unlock(task
->pv
->post
.frame_completed_lock
);
889 // this is just a simple fun/test case
894 char* luma
= task
->pv
->post
.in
->plane
[0].data
;
895 int pitch
= task
->pv
->post
.in
->plane
[0].stride
;
896 int h
= task
->pv
->post
.in
->plane
[0].height
;
897 int w
= task
->pv
->post
.in
->plane
[0].width
;
898 for (i
= 0; i
< h
; i
++){
900 cur_line
= luma
+ i
* pitch
;
901 if(i
>h
/4 && i
< 3*h
/4 && i
% 5 == 0 )
902 memset(cur_line
, 0 , w
);
907 if(task
->pv
->post
.in
)
909 qsv_yuv420_to_nv12(task
->pv
->sws_context_to_nv12
, task
->out
, task
->pv
->post
.in
);
912 // signal: output is prepared, converted from internal buffer into pipeline
913 hb_lock(task
->pv
->post_busy
.frame_completed_lock
);
914 task
->pv
->post_busy
.frame_go
= 1;
915 hb_cond_broadcast(task
->pv
->post_busy
.frame_completed
);
916 hb_unlock(task
->pv
->post_busy
.frame_completed_lock
);
918 unlock_frame(task
->processor
.alloc
,task
->in
);
919 unlock_frame(task
->processor
.alloc
,task
->out
);