1 /**************************************************************************
3 * Copyright 2013 Advanced Micro Devices, Inc.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
28 #include <tizplatform.h>
29 #include <tizkernel.h>
32 #include "entrypoint.h"
35 #include "vid_omx_common.h"
36 #include "vid_dec_common.h"
37 #include "vid_dec_h264_common.h"
39 #include "vl/vl_video_buffer.h"
40 #include "vl/vl_compositor.h"
41 #include "util/u_hash_table.h"
42 #include "util/u_surface.h"
44 #include "dri_screen.h"
47 unsigned dec_frame_delta
;
49 static enum pipe_error
hash_table_clear_item_callback(void *key
, void *value
, void *data
)
51 struct pipe_video_buffer
*video_buffer
= (struct pipe_video_buffer
*)value
;
52 video_buffer
->destroy(video_buffer
);
56 static void release_input_headers(vid_dec_PrivateType
* priv
) {
58 for (i
= 0; i
< priv
->num_in_buffers
; i
++) {
59 assert(!priv
->in_port_disabled_
);
60 if (priv
->in_buffers
[i
]->pInputPortPrivate
) {
61 vid_dec_FreeInputPortPrivate(priv
->in_buffers
[i
]);
63 (void) tiz_krn_release_buffer (tiz_get_krn (handleOf (priv
)),
64 OMX_VID_DEC_AVC_INPUT_PORT_INDEX
,
66 priv
->in_buffers
[i
] = NULL
;
68 priv
->p_inhdr_
= NULL
;
69 priv
->num_in_buffers
= 0;
72 static void release_output_header(vid_dec_PrivateType
* priv
) {
73 if (priv
->p_outhdr_
) {
74 assert(!priv
->out_port_disabled_
);
75 (void) tiz_krn_release_buffer (tiz_get_krn (handleOf (priv
)),
76 OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
,
78 priv
->p_outhdr_
= NULL
;
82 static OMX_ERRORTYPE
h264d_release_all_headers(vid_dec_PrivateType
* priv
)
85 release_input_headers(priv
);
86 release_output_header(priv
);
91 static void h264d_buffer_emptied(vid_dec_PrivateType
* priv
, OMX_BUFFERHEADERTYPE
* p_hdr
)
94 assert(priv
->in_buffers
[0] == p_hdr
);
96 if (!priv
->out_port_disabled_
) {
97 assert (p_hdr
->nFilledLen
== 0);
100 if ((p_hdr
->nFlags
& OMX_BUFFERFLAG_EOS
) != 0) {
104 (void) tiz_krn_release_buffer (tiz_get_krn (handleOf (priv
)), 0, p_hdr
);
105 priv
->p_inhdr_
= NULL
;
106 priv
->in_buffers
[0] = NULL
;
110 static void h264d_buffer_filled(vid_dec_PrivateType
* priv
, OMX_BUFFERHEADERTYPE
* p_hdr
)
114 assert(priv
->p_outhdr_
== p_hdr
);
116 if (!priv
->in_port_disabled_
) {
120 /* EOS has been received and all the input data has been consumed
121 * already, so its time to propagate the EOS flag */
122 priv
->p_outhdr_
->nFlags
|= OMX_BUFFERFLAG_EOS
;
126 (void) tiz_krn_release_buffer(tiz_get_krn (handleOf (priv
)),
127 OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
,
129 priv
->p_outhdr_
= NULL
;
133 static bool h264d_shift_buffers_left(vid_dec_PrivateType
* priv
) {
134 if (--priv
->num_in_buffers
) {
135 priv
->in_buffers
[0] = priv
->in_buffers
[1];
136 priv
->sizes
[0] = priv
->sizes
[1] - dec_frame_delta
;
137 priv
->inputs
[0] = priv
->inputs
[1] + dec_frame_delta
;
138 priv
->timestamps
[0] = priv
->timestamps
[1];
145 static OMX_BUFFERHEADERTYPE
* get_input_buffer(vid_dec_PrivateType
* priv
) {
148 if (priv
->in_port_disabled_
) {
152 if (priv
->num_in_buffers
> 1) {
153 /* The input buffer wasn't cleared last time. */
154 h264d_buffer_emptied(priv
, priv
->in_buffers
[0]);
155 if (priv
->in_buffers
[0]) {
156 /* Failed to release buffer */
159 h264d_shift_buffers_left(priv
);
162 /* Decode_frame expects new buffers each time */
163 assert(priv
->p_inhdr_
|| priv
->first_buf_in_frame
);
164 tiz_krn_claim_buffer(tiz_get_krn (handleOf (priv
)),
165 OMX_VID_DEC_AVC_INPUT_PORT_INDEX
, 0,
167 return priv
->p_inhdr_
;
170 static struct pipe_resource
* st_omx_pipe_texture_from_eglimage(EGLDisplay egldisplay
,
173 _EGLDisplay
*disp
= egldisplay
;
174 struct dri2_egl_display
*dri2_egl_dpy
= disp
->DriverData
;
175 __DRIscreen
*_dri_screen
= dri2_egl_dpy
->dri_screen
;
176 struct dri_screen
*st_dri_screen
= dri_screen(_dri_screen
);
177 __DRIimage
*_dri_image
= st_dri_screen
->lookup_egl_image(st_dri_screen
, eglimage
);
179 return _dri_image
->texture
;
182 static void get_eglimage(vid_dec_PrivateType
* priv
) {
183 OMX_PTR p_eglimage
= NULL
;
184 OMX_NATIVE_WINDOWTYPE
* p_egldisplay
= NULL
;
185 const tiz_port_t
* p_port
= NULL
;
186 struct pipe_video_buffer templat
= {};
187 struct pipe_video_buffer
*video_buffer
= NULL
;
188 struct pipe_resource
* p_res
= NULL
;
189 struct pipe_resource
*resources
[VL_NUM_COMPONENTS
];
192 tiz_krn_claim_eglimage(tiz_get_krn (handleOf (priv
)),
193 OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
,
194 priv
->p_outhdr_
, &p_eglimage
)) {
195 priv
->use_eglimage
= true;
196 p_port
= tiz_krn_get_port(tiz_get_krn (handleOf (priv
)),
197 OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
);
198 p_egldisplay
= p_port
->portdef_
.format
.video
.pNativeWindow
;
200 if (!util_hash_table_get(priv
->video_buffer_map
, priv
->p_outhdr_
)) {
201 p_res
= st_omx_pipe_texture_from_eglimage(p_egldisplay
, p_eglimage
);
205 memset(&templat
, 0, sizeof(templat
));
206 templat
.buffer_format
= p_res
->format
;
207 templat
.chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_NONE
;
208 templat
.width
= p_res
->width0
;
209 templat
.height
= p_res
->height0
;
210 templat
.interlaced
= 0;
212 memset(resources
, 0, sizeof(resources
));
213 pipe_resource_reference(&resources
[0], p_res
);
215 video_buffer
= vl_video_buffer_create_ex2(priv
->pipe
, &templat
, resources
);
217 assert(video_buffer
);
218 assert(video_buffer
->buffer_format
== p_res
->format
);
220 _mesa_hash_table_insert(priv
->video_buffer_map
, priv
->p_outhdr_
, video_buffer
);
223 (void) tiz_krn_release_buffer(tiz_get_krn (handleOf (priv
)),
224 OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
,
226 priv
->p_outhdr_
= NULL
;
230 static OMX_BUFFERHEADERTYPE
* get_output_buffer(vid_dec_PrivateType
* priv
) {
233 if (priv
->out_port_disabled_
) {
237 if (!priv
->p_outhdr_
) {
239 == tiz_krn_claim_buffer(tiz_get_krn (handleOf (priv
)),
240 OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
, 0,
242 if (priv
->p_outhdr_
) {
243 /* Check pBuffer nullity to know if an eglimage has been registered. */
244 if (!priv
->p_outhdr_
->pBuffer
) {
250 return priv
->p_outhdr_
;
253 static void reset_stream_parameters(vid_dec_PrivateType
* apriv
)
256 TIZ_INIT_OMX_PORT_STRUCT(apriv
->out_port_def_
,
257 OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
);
259 tiz_api_GetParameter (tiz_get_krn (handleOf (apriv
)), handleOf (apriv
),
260 OMX_IndexParamPortDefinition
, &(apriv
->out_port_def_
));
263 apriv
->num_in_buffers
= 0;
264 apriv
->first_buf_in_frame
= true;
266 apriv
->frame_finished
= false;
267 apriv
->frame_started
= false;
268 apriv
->picture
.h264
.field_order_cnt
[0] = apriv
->picture
.h264
.field_order_cnt
[1] = INT_MAX
;
272 /* Replacement for bellagio's omx_base_filter_BufferMgmtFunction */
273 static void h264d_manage_buffers(vid_dec_PrivateType
* priv
) {
274 bool next_is_eos
= priv
->num_in_buffers
== 2 ? !!(priv
->in_buffers
[1]->nFlags
& OMX_BUFFERFLAG_EOS
) : false;
275 vid_dec_FrameDecoded_common(priv
, priv
->in_buffers
[0], priv
->p_outhdr_
);
277 priv
->p_outhdr_
->nTimeStamp
= priv
->in_buffers
[0]->nTimeStamp
;
279 /* Realase output buffer if filled or eos
280 Keep if two input buffers are being decoded */
281 if ((!next_is_eos
) && ((priv
->p_outhdr_
->nFilledLen
> 0) || priv
->use_eglimage
|| priv
->eos_
)) {
282 h264d_buffer_filled(priv
, priv
->p_outhdr_
);
285 /* Release input buffer if possible */
286 if (priv
->in_buffers
[0]->nFilledLen
== 0) {
287 h264d_buffer_emptied(priv
, priv
->in_buffers
[0]);
291 static OMX_ERRORTYPE
decode_frame(vid_dec_PrivateType
*priv
,
292 OMX_BUFFERHEADERTYPE
*in_buf
)
294 unsigned i
= priv
->num_in_buffers
++;
295 priv
->in_buffers
[i
] = in_buf
;
296 priv
->sizes
[i
] = in_buf
->nFilledLen
;
297 priv
->inputs
[i
] = in_buf
->pBuffer
;
298 priv
->timestamps
[i
] = in_buf
->nTimeStamp
;
300 while (priv
->num_in_buffers
> (!!(in_buf
->nFlags
& OMX_BUFFERFLAG_EOS
) ? 0 : 1)) {
301 priv
->eos_
= !!(priv
->in_buffers
[0]->nFlags
& OMX_BUFFERFLAG_EOS
);
302 unsigned min_bits_left
= priv
->eos_
? 32 : MAX2(in_buf
->nFilledLen
* 8, 32);
305 vl_vlc_init(&vlc
, priv
->num_in_buffers
, priv
->inputs
, priv
->sizes
);
308 priv
->bytes_left
= vl_vlc_bits_left(&vlc
) / 8;
310 while (vl_vlc_bits_left (&vlc
) > min_bits_left
) {
311 vid_dec_h264_Decode(priv
, &vlc
, min_bits_left
);
312 vl_vlc_fillbits(&vlc
);
316 unsigned bytes
= priv
->bytes_left
- vl_vlc_bits_left(&vlc
) / 8;
318 priv
->codec
->decode_bitstream(priv
->codec
, priv
->target
, &priv
->picture
.base
,
319 1, &priv
->slice
, &bytes
);
321 if (priv
->num_in_buffers
)
322 priv
->slice
= priv
->inputs
[1];
327 if (priv
->eos_
&& priv
->frame_started
)
328 vid_dec_h264_EndFrame(priv
);
330 if (priv
->frame_finished
) {
331 priv
->frame_finished
= false;
332 h264d_manage_buffers(priv
);
333 } else if (priv
->eos_
) {
334 vid_dec_FreeInputPortPrivate(priv
->in_buffers
[0]);
335 h264d_manage_buffers(priv
);
337 priv
->in_buffers
[0]->nFilledLen
= 0;
338 h264d_buffer_emptied(priv
, priv
->in_buffers
[0]);
341 if (priv
->out_port_disabled_
) {
342 /* In case out port is disabled, h264d_buffer_emptied will fail to release input port.
343 * We need to wait before shifting the buffers in that case and check in
344 * get_input_buffer when out port is enabled to release and shift the buffers.
345 * Infinite looping occurs if buffer is not released */
346 if (priv
->num_in_buffers
== 2) {
347 /* Set the delta value for use in get_input_buffer before exiting */
348 dec_frame_delta
= MIN2((min_bits_left
- vl_vlc_bits_left(&vlc
)) / 8, priv
->sizes
[1]);
353 h264d_shift_buffers_left(priv
);
356 return OMX_ErrorNone
;
363 static void * h264d_prc_ctor(void *ap_obj
, va_list * app
)
365 vid_dec_PrivateType
*priv
= super_ctor(typeOf (ap_obj
, "h264dprc"), ap_obj
, app
);
369 priv
->first_buf_in_frame
= true;
371 priv
->in_port_disabled_
= false;
372 priv
->out_port_disabled_
= false;
373 priv
->picture
.base
.profile
= PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
;
374 priv
->profile
= PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH
;
375 reset_stream_parameters(priv
);
380 static void * h264d_prc_dtor(void *ap_obj
)
382 return super_dtor(typeOf(ap_obj
, "h264dprc"), ap_obj
);
385 static OMX_ERRORTYPE
h264d_prc_allocate_resources(void *ap_obj
, OMX_U32 a_pid
)
387 vid_dec_PrivateType
*priv
= ap_obj
;
388 struct pipe_screen
*screen
;
393 priv
->screen
= omx_get_screen();
395 return OMX_ErrorInsufficientResources
;
397 screen
= priv
->screen
->pscreen
;
398 priv
->pipe
= pipe_create_multimedia_context(screen
);
400 return OMX_ErrorInsufficientResources
;
402 if (!vl_compositor_init(&priv
->compositor
, priv
->pipe
)) {
403 priv
->pipe
->destroy(priv
->pipe
);
405 return OMX_ErrorInsufficientResources
;
408 if (!vl_compositor_init_state(&priv
->cstate
, priv
->pipe
)) {
409 vl_compositor_cleanup(&priv
->compositor
);
410 priv
->pipe
->destroy(priv
->pipe
);
412 return OMX_ErrorInsufficientResources
;
415 vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601
, NULL
, true, &csc
);
416 if (!vl_compositor_set_csc_matrix(&priv
->cstate
, (const vl_csc_matrix
*)&csc
, 1.0f
, 0.0f
)) {
417 vl_compositor_cleanup(&priv
->compositor
);
418 priv
->pipe
->destroy(priv
->pipe
);
420 return OMX_ErrorInsufficientResources
;
423 list_inithead(&priv
->codec_data
.h264
.dpb_list
);
425 priv
->video_buffer_map
= util_hash_table_create_ptr_keys();
427 return OMX_ErrorNone
;
430 static OMX_ERRORTYPE
h264d_prc_deallocate_resources(void *ap_obj
)
432 vid_dec_PrivateType
*priv
= ap_obj
;
435 /* Clear hash table */
436 util_hash_table_foreach(priv
->video_buffer_map
,
437 &hash_table_clear_item_callback
,
439 _mesa_hash_table_destroy(priv
->video_buffer_map
, NULL
);
442 vl_compositor_cleanup_state(&priv
->cstate
);
443 vl_compositor_cleanup(&priv
->compositor
);
444 priv
->pipe
->destroy(priv
->pipe
);
450 return OMX_ErrorNone
;
453 static OMX_ERRORTYPE
h264d_prc_prepare_to_transfer(void *ap_obj
, OMX_U32 a_pid
)
455 vid_dec_PrivateType
*priv
= ap_obj
;
458 TIZ_INIT_OMX_PORT_STRUCT(priv
->out_port_def_
,
459 OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
);
461 tiz_api_GetParameter(tiz_get_krn(handleOf(priv
)), handleOf(priv
),
462 OMX_IndexParamPortDefinition
, &(priv
->out_port_def_
)));
464 priv
->first_buf_in_frame
= true;
466 return OMX_ErrorNone
;
469 static OMX_ERRORTYPE
h264d_prc_transfer_and_process(void *ap_obj
, OMX_U32 a_pid
)
471 return OMX_ErrorNone
;
474 static OMX_ERRORTYPE
h264d_prc_stop_and_return(void *ap_obj
)
476 vid_dec_PrivateType
*priv
= (vid_dec_PrivateType
*) ap_obj
;
477 return h264d_release_all_headers (priv
);
480 static OMX_ERRORTYPE
h264d_prc_buffers_ready(const void *ap_obj
)
482 vid_dec_PrivateType
*priv
= (vid_dec_PrivateType
*) ap_obj
;
483 OMX_BUFFERHEADERTYPE
*in_buf
= NULL
;
484 OMX_BUFFERHEADERTYPE
*out_buf
= NULL
;
488 /* Set parameters if start of stream */
489 if (!priv
->eos_
&& priv
->first_buf_in_frame
&& (in_buf
= get_input_buffer(priv
))) {
490 decode_frame(priv
, in_buf
);
493 /* Don't get input buffer if output buffer not found */
494 while (!priv
->eos_
&& (out_buf
= get_output_buffer(priv
)) && (in_buf
= get_input_buffer(priv
))) {
495 if (!priv
->out_port_disabled_
) {
496 decode_frame(priv
, in_buf
);
500 return OMX_ErrorNone
;
503 static OMX_ERRORTYPE
h264d_prc_port_flush(const void *ap_obj
, OMX_U32 a_pid
)
505 vid_dec_PrivateType
*priv
= (vid_dec_PrivateType
*) ap_obj
;
506 if (OMX_ALL
== a_pid
|| OMX_VID_DEC_AVC_INPUT_PORT_INDEX
== a_pid
) {
507 release_input_headers(priv
);
508 reset_stream_parameters(priv
);
510 if (OMX_ALL
== a_pid
|| OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
== a_pid
) {
511 release_output_header(priv
);
513 return OMX_ErrorNone
;
516 static OMX_ERRORTYPE
h264d_prc_port_disable(const void *ap_obj
, OMX_U32 a_pid
)
518 vid_dec_PrivateType
*priv
= (vid_dec_PrivateType
*) ap_obj
;
520 if (OMX_ALL
== a_pid
|| OMX_VID_DEC_AVC_INPUT_PORT_INDEX
== a_pid
) {
521 /* Release all buffers */
522 h264d_release_all_headers(priv
);
523 reset_stream_parameters(priv
);
524 priv
->in_port_disabled_
= true;
526 if (OMX_ALL
== a_pid
|| OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
== a_pid
) {
527 release_output_header(priv
);
528 priv
->out_port_disabled_
= true;
530 return OMX_ErrorNone
;
533 static OMX_ERRORTYPE
h264d_prc_port_enable(const void *ap_obj
, OMX_U32 a_pid
)
535 vid_dec_PrivateType
* priv
= (vid_dec_PrivateType
*) ap_obj
;
537 if (OMX_ALL
== a_pid
|| OMX_VID_DEC_AVC_INPUT_PORT_INDEX
== a_pid
) {
538 if (priv
->in_port_disabled_
) {
539 reset_stream_parameters(priv
);
540 priv
->in_port_disabled_
= false;
543 if (OMX_ALL
== a_pid
|| OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX
== a_pid
) {
544 priv
->out_port_disabled_
= false;
546 return OMX_ErrorNone
;
553 static void * h264d_prc_class_ctor(void *ap_obj
, va_list * app
)
555 /* NOTE: Class methods might be added in the future. None for now. */
556 return super_ctor(typeOf(ap_obj
, "h264dprc_class"), ap_obj
, app
);
563 void * h264d_prc_class_init(void * ap_tos
, void * ap_hdl
)
565 void * tizprc
= tiz_get_type(ap_hdl
, "tizprc");
566 void * h264dprc_class
= factory_new
567 /* TIZ_CLASS_COMMENT: class type, class name, parent, size */
568 (classOf(tizprc
), "h264dprc_class", classOf(tizprc
),
569 sizeof(h264d_prc_class_t
),
570 /* TIZ_CLASS_COMMENT: */
572 /* TIZ_CLASS_COMMENT: class constructor */
573 ctor
, h264d_prc_class_ctor
,
574 /* TIZ_CLASS_COMMENT: stop value*/
576 return h264dprc_class
;
579 void * h264d_prc_init(void * ap_tos
, void * ap_hdl
)
581 void * tizprc
= tiz_get_type(ap_hdl
, "tizprc");
582 void * h264dprc_class
= tiz_get_type(ap_hdl
, "h264dprc_class");
583 TIZ_LOG_CLASS (h264dprc_class
);
584 void * h264dprc
= factory_new
585 /* TIZ_CLASS_COMMENT: class type, class name, parent, size */
586 (h264dprc_class
, "h264dprc", tizprc
, sizeof(vid_dec_PrivateType
),
587 /* TIZ_CLASS_COMMENT: */
589 /* TIZ_CLASS_COMMENT: class constructor */
590 ctor
, h264d_prc_ctor
,
591 /* TIZ_CLASS_COMMENT: class destructor */
592 dtor
, h264d_prc_dtor
,
593 /* TIZ_CLASS_COMMENT: */
594 tiz_srv_allocate_resources
, h264d_prc_allocate_resources
,
595 /* TIZ_CLASS_COMMENT: */
596 tiz_srv_deallocate_resources
, h264d_prc_deallocate_resources
,
597 /* TIZ_CLASS_COMMENT: */
598 tiz_srv_prepare_to_transfer
, h264d_prc_prepare_to_transfer
,
599 /* TIZ_CLASS_COMMENT: */
600 tiz_srv_transfer_and_process
, h264d_prc_transfer_and_process
,
601 /* TIZ_CLASS_COMMENT: */
602 tiz_srv_stop_and_return
, h264d_prc_stop_and_return
,
603 /* TIZ_CLASS_COMMENT: */
604 tiz_prc_buffers_ready
, h264d_prc_buffers_ready
,
605 /* TIZ_CLASS_COMMENT: */
606 tiz_prc_port_flush
, h264d_prc_port_flush
,
607 /* TIZ_CLASS_COMMENT: */
608 tiz_prc_port_disable
, h264d_prc_port_disable
,
609 /* TIZ_CLASS_COMMENT: */
610 tiz_prc_port_enable
, h264d_prc_port_enable
,
611 /* TIZ_CLASS_COMMENT: stop value*/