Path: blob/21.2-virgl/src/gallium/frontends/omx/tizonia/h264dprc.c
4561 views
/**************************************************************************1*2* Copyright 2013 Advanced Micro Devices, Inc.3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the7* "Software"), to deal in the Software without restriction, including8* without limitation the rights to use, copy, modify, merge, publish,9* distribute, sub license, and/or sell copies of the Software, and to10* permit persons to whom the Software is furnished to do so, subject to11* the following conditions:12*13* The above copyright notice and this permission notice (including the14* next paragraph) shall be included in all copies or substantial portions15* of the Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS18* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.20* IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR21* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,22* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE23* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.24*25**************************************************************************/2627#include <tizplatform.h>28#include <tizkernel.h>29#include <tizutils.h>3031#include "entrypoint.h"32#include "h264d.h"33#include "h264dprc.h"34#include "vid_omx_common.h"35#include "vid_dec_common.h"36#include "vid_dec_h264_common.h"3738#include "vl/vl_video_buffer.h"39#include "vl/vl_compositor.h"40#include "util/u_hash_table.h"41#include "util/u_surface.h"4243#include "dri_screen.h"44#include "egl_dri2.h"4546unsigned dec_frame_delta;4748static enum pipe_error hash_table_clear_item_callback(void *key, void *value, void *data)49{50struct pipe_video_buffer *video_buffer = (struct pipe_video_buffer *)value;51video_buffer->destroy(video_buffer);52return PIPE_OK;53}5455static void release_input_headers(vid_dec_PrivateType* priv) {56int i;57for (i = 0; i < priv->num_in_buffers; i++) {58assert(!priv->in_port_disabled_);59if (priv->in_buffers[i]->pInputPortPrivate) {60vid_dec_FreeInputPortPrivate(priv->in_buffers[i]);61}62(void) tiz_krn_release_buffer (tiz_get_krn (handleOf (priv)),63OMX_VID_DEC_AVC_INPUT_PORT_INDEX,64priv->in_buffers[i]);65priv->in_buffers[i] = NULL;66}67priv->p_inhdr_ = NULL;68priv->num_in_buffers = 0;69}7071static void release_output_header(vid_dec_PrivateType* priv) {72if (priv->p_outhdr_) {73assert(!priv->out_port_disabled_);74(void) tiz_krn_release_buffer (tiz_get_krn (handleOf (priv)),75OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX,76priv->p_outhdr_);77priv->p_outhdr_ = NULL;78}79}8081static OMX_ERRORTYPE h264d_release_all_headers(vid_dec_PrivateType* priv)82{83assert(priv);84release_input_headers(priv);85release_output_header(priv);8687return OMX_ErrorNone;88}8990static void h264d_buffer_emptied(vid_dec_PrivateType* priv, OMX_BUFFERHEADERTYPE * p_hdr)91{92assert(priv);93assert(priv->in_buffers[0] == p_hdr);9495if (!priv->out_port_disabled_) {96assert (p_hdr->nFilledLen == 0);97p_hdr->nOffset = 0;9899if ((p_hdr->nFlags & OMX_BUFFERFLAG_EOS) != 0) {100priv->eos_ = true;101}102103(void) tiz_krn_release_buffer (tiz_get_krn (handleOf (priv)), 0, p_hdr);104priv->p_inhdr_ = NULL;105priv->in_buffers[0] = NULL;106}107}108109static void h264d_buffer_filled(vid_dec_PrivateType* priv, OMX_BUFFERHEADERTYPE * p_hdr)110{111assert(priv);112assert(p_hdr);113assert(priv->p_outhdr_ == p_hdr);114115if (!priv->in_port_disabled_) {116p_hdr->nOffset = 0;117118if (priv->eos_) {119/* EOS has been received and all the input data has been consumed120* already, so its time to propagate the EOS flag */121priv->p_outhdr_->nFlags |= OMX_BUFFERFLAG_EOS;122priv->eos_ = false;123}124125(void) tiz_krn_release_buffer(tiz_get_krn (handleOf (priv)),126OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX,127p_hdr);128priv->p_outhdr_ = NULL;129}130}131132static bool h264d_shift_buffers_left(vid_dec_PrivateType* priv) {133if (--priv->num_in_buffers) {134priv->in_buffers[0] = priv->in_buffers[1];135priv->sizes[0] = priv->sizes[1] - dec_frame_delta;136priv->inputs[0] = priv->inputs[1] + dec_frame_delta;137priv->timestamps[0] = priv->timestamps[1];138139return true;140}141return false;142}143144static OMX_BUFFERHEADERTYPE * get_input_buffer(vid_dec_PrivateType* priv) {145assert(priv);146147if (priv->in_port_disabled_) {148return NULL;149}150151if (priv->num_in_buffers > 1) {152/* The input buffer wasn't cleared last time. */153h264d_buffer_emptied(priv, priv->in_buffers[0]);154if (priv->in_buffers[0]) {155/* Failed to release buffer */156return NULL;157}158h264d_shift_buffers_left(priv);159}160161/* Decode_frame expects new buffers each time */162assert(priv->p_inhdr_ || priv->first_buf_in_frame);163tiz_krn_claim_buffer(tiz_get_krn (handleOf (priv)),164OMX_VID_DEC_AVC_INPUT_PORT_INDEX, 0,165&priv->p_inhdr_);166return priv->p_inhdr_;167}168169static struct pipe_resource * st_omx_pipe_texture_from_eglimage(EGLDisplay egldisplay,170EGLImage eglimage)171{172_EGLDisplay *disp = egldisplay;173struct dri2_egl_display *dri2_egl_dpy = disp->DriverData;174__DRIscreen *_dri_screen = dri2_egl_dpy->dri_screen;175struct dri_screen *st_dri_screen = dri_screen(_dri_screen);176__DRIimage *_dri_image = st_dri_screen->lookup_egl_image(st_dri_screen, eglimage);177178return _dri_image->texture;179}180181static void get_eglimage(vid_dec_PrivateType* priv) {182OMX_PTR p_eglimage = NULL;183OMX_NATIVE_WINDOWTYPE * p_egldisplay = NULL;184const tiz_port_t * p_port = NULL;185struct pipe_video_buffer templat = {};186struct pipe_video_buffer *video_buffer = NULL;187struct pipe_resource * p_res = NULL;188struct pipe_resource *resources[VL_NUM_COMPONENTS];189190if (OMX_ErrorNone ==191tiz_krn_claim_eglimage(tiz_get_krn (handleOf (priv)),192OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX,193priv->p_outhdr_, &p_eglimage)) {194priv->use_eglimage = true;195p_port = tiz_krn_get_port(tiz_get_krn (handleOf (priv)),196OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX);197p_egldisplay = p_port->portdef_.format.video.pNativeWindow;198199if (!util_hash_table_get(priv->video_buffer_map, priv->p_outhdr_)) {200p_res = st_omx_pipe_texture_from_eglimage(p_egldisplay, p_eglimage);201202assert(p_res);203204memset(&templat, 0, sizeof(templat));205templat.buffer_format = p_res->format;206templat.width = p_res->width0;207templat.height = p_res->height0;208templat.interlaced = 0;209210memset(resources, 0, sizeof(resources));211pipe_resource_reference(&resources[0], p_res);212213video_buffer = vl_video_buffer_create_ex2(priv->pipe, &templat, resources);214215assert(video_buffer);216assert(video_buffer->buffer_format == p_res->format);217218_mesa_hash_table_insert(priv->video_buffer_map, priv->p_outhdr_, video_buffer);219}220} else {221(void) tiz_krn_release_buffer(tiz_get_krn (handleOf (priv)),222OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX,223priv->p_outhdr_);224priv->p_outhdr_ = NULL;225}226}227228static OMX_BUFFERHEADERTYPE * get_output_buffer(vid_dec_PrivateType* priv) {229assert (priv);230231if (priv->out_port_disabled_) {232return NULL;233}234235if (!priv->p_outhdr_) {236if (OMX_ErrorNone237== tiz_krn_claim_buffer(tiz_get_krn (handleOf (priv)),238OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX, 0,239&priv->p_outhdr_)) {240if (priv->p_outhdr_) {241/* Check pBuffer nullity to know if an eglimage has been registered. */242if (!priv->p_outhdr_->pBuffer) {243get_eglimage(priv);244}245}246}247}248return priv->p_outhdr_;249}250251static void reset_stream_parameters(vid_dec_PrivateType* apriv)252{253assert(apriv);254TIZ_INIT_OMX_PORT_STRUCT(apriv->out_port_def_,255OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX);256257tiz_api_GetParameter (tiz_get_krn (handleOf (apriv)), handleOf (apriv),258OMX_IndexParamPortDefinition, &(apriv->out_port_def_));259260apriv->p_inhdr_ = 0;261apriv->num_in_buffers = 0;262apriv->first_buf_in_frame = true;263apriv->eos_ = false;264apriv->frame_finished = false;265apriv->frame_started = false;266apriv->picture.h264.field_order_cnt[0] = apriv->picture.h264.field_order_cnt[1] = INT_MAX;267apriv->slice = NULL;268}269270/* Replacement for bellagio's omx_base_filter_BufferMgmtFunction */271static void h264d_manage_buffers(vid_dec_PrivateType* priv) {272bool next_is_eos = priv->num_in_buffers == 2 ? !!(priv->in_buffers[1]->nFlags & OMX_BUFFERFLAG_EOS) : false;273vid_dec_FrameDecoded_common(priv, priv->in_buffers[0], priv->p_outhdr_);274275priv->p_outhdr_->nTimeStamp = priv->in_buffers[0]->nTimeStamp;276277/* Realase output buffer if filled or eos278Keep if two input buffers are being decoded */279if ((!next_is_eos) && ((priv->p_outhdr_->nFilledLen > 0) || priv->use_eglimage || priv->eos_)) {280h264d_buffer_filled(priv, priv->p_outhdr_);281}282283/* Release input buffer if possible */284if (priv->in_buffers[0]->nFilledLen == 0) {285h264d_buffer_emptied(priv, priv->in_buffers[0]);286}287}288289static OMX_ERRORTYPE decode_frame(vid_dec_PrivateType*priv,290OMX_BUFFERHEADERTYPE *in_buf)291{292unsigned i = priv->num_in_buffers++;293priv->in_buffers[i] = in_buf;294priv->sizes[i] = in_buf->nFilledLen;295priv->inputs[i] = in_buf->pBuffer;296priv->timestamps[i] = in_buf->nTimeStamp;297298while (priv->num_in_buffers > (!!(in_buf->nFlags & OMX_BUFFERFLAG_EOS) ? 0 : 1)) {299priv->eos_ = !!(priv->in_buffers[0]->nFlags & OMX_BUFFERFLAG_EOS);300unsigned min_bits_left = priv->eos_ ? 32 : MAX2(in_buf->nFilledLen * 8, 32);301struct vl_vlc vlc;302303vl_vlc_init(&vlc, priv->num_in_buffers, priv->inputs, priv->sizes);304305if (priv->slice)306priv->bytes_left = vl_vlc_bits_left(&vlc) / 8;307308while (vl_vlc_bits_left (&vlc) > min_bits_left) {309vid_dec_h264_Decode(priv, &vlc, min_bits_left);310vl_vlc_fillbits(&vlc);311}312313if (priv->slice) {314unsigned bytes = priv->bytes_left - vl_vlc_bits_left(&vlc) / 8;315316priv->codec->decode_bitstream(priv->codec, priv->target, &priv->picture.base,3171, &priv->slice, &bytes);318319if (priv->num_in_buffers)320priv->slice = priv->inputs[1];321else322priv->slice = NULL;323}324325if (priv->eos_ && priv->frame_started)326vid_dec_h264_EndFrame(priv);327328if (priv->frame_finished) {329priv->frame_finished = false;330h264d_manage_buffers(priv);331} else if (priv->eos_) {332vid_dec_FreeInputPortPrivate(priv->in_buffers[0]);333h264d_manage_buffers(priv);334} else {335priv->in_buffers[0]->nFilledLen = 0;336h264d_buffer_emptied(priv, priv->in_buffers[0]);337}338339if (priv->out_port_disabled_) {340/* In case out port is disabled, h264d_buffer_emptied will fail to release input port.341* We need to wait before shifting the buffers in that case and check in342* get_input_buffer when out port is enabled to release and shift the buffers.343* Infinite looping occurs if buffer is not released */344if (priv->num_in_buffers == 2) {345/* Set the delta value for use in get_input_buffer before exiting */346dec_frame_delta = MIN2((min_bits_left - vl_vlc_bits_left(&vlc)) / 8, priv->sizes[1]);347}348break;349}350351h264d_shift_buffers_left(priv);352}353354return OMX_ErrorNone;355}356357/*358* h264dprc359*/360361static void * h264d_prc_ctor(void *ap_obj, va_list * app)362{363vid_dec_PrivateType*priv = super_ctor(typeOf (ap_obj, "h264dprc"), ap_obj, app);364assert(priv);365priv->p_inhdr_ = 0;366priv->p_outhdr_ = 0;367priv->first_buf_in_frame = true;368priv->eos_ = false;369priv->in_port_disabled_ = false;370priv->out_port_disabled_ = false;371priv->picture.base.profile = PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH;372priv->profile = PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH;373reset_stream_parameters(priv);374375return priv;376}377378static void * h264d_prc_dtor(void *ap_obj)379{380return super_dtor(typeOf(ap_obj, "h264dprc"), ap_obj);381}382383static OMX_ERRORTYPE h264d_prc_allocate_resources(void *ap_obj, OMX_U32 a_pid)384{385vid_dec_PrivateType*priv = ap_obj;386struct pipe_screen *screen;387vl_csc_matrix csc;388389assert (priv);390391priv->screen = omx_get_screen();392if (!priv->screen)393return OMX_ErrorInsufficientResources;394395screen = priv->screen->pscreen;396priv->pipe = pipe_create_multimedia_context(screen);397if (!priv->pipe)398return OMX_ErrorInsufficientResources;399400if (!vl_compositor_init(&priv->compositor, priv->pipe)) {401priv->pipe->destroy(priv->pipe);402priv->pipe = NULL;403return OMX_ErrorInsufficientResources;404}405406if (!vl_compositor_init_state(&priv->cstate, priv->pipe)) {407vl_compositor_cleanup(&priv->compositor);408priv->pipe->destroy(priv->pipe);409priv->pipe = NULL;410return OMX_ErrorInsufficientResources;411}412413vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, true, &csc);414if (!vl_compositor_set_csc_matrix(&priv->cstate, (const vl_csc_matrix *)&csc, 1.0f, 0.0f)) {415vl_compositor_cleanup(&priv->compositor);416priv->pipe->destroy(priv->pipe);417priv->pipe = NULL;418return OMX_ErrorInsufficientResources;419}420421list_inithead(&priv->codec_data.h264.dpb_list);422423priv->video_buffer_map = util_hash_table_create_ptr_keys();424425return OMX_ErrorNone;426}427428static OMX_ERRORTYPE h264d_prc_deallocate_resources(void *ap_obj)429{430vid_dec_PrivateType*priv = ap_obj;431assert(priv);432433/* Clear hash table */434util_hash_table_foreach(priv->video_buffer_map,435&hash_table_clear_item_callback,436NULL);437_mesa_hash_table_destroy(priv->video_buffer_map, NULL);438439if (priv->pipe) {440vl_compositor_cleanup_state(&priv->cstate);441vl_compositor_cleanup(&priv->compositor);442priv->pipe->destroy(priv->pipe);443}444445if (priv->screen)446omx_put_screen();447448return OMX_ErrorNone;449}450451static OMX_ERRORTYPE h264d_prc_prepare_to_transfer(void *ap_obj, OMX_U32 a_pid)452{453vid_dec_PrivateType*priv = ap_obj;454assert(priv);455456TIZ_INIT_OMX_PORT_STRUCT(priv->out_port_def_,457OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX);458tiz_check_omx(459tiz_api_GetParameter(tiz_get_krn(handleOf(priv)), handleOf(priv),460OMX_IndexParamPortDefinition, &(priv->out_port_def_)));461462priv->first_buf_in_frame = true;463priv->eos_ = false;464return OMX_ErrorNone;465}466467static OMX_ERRORTYPE h264d_prc_transfer_and_process(void *ap_obj, OMX_U32 a_pid)468{469return OMX_ErrorNone;470}471472static OMX_ERRORTYPE h264d_prc_stop_and_return(void *ap_obj)473{474vid_dec_PrivateType*priv = (vid_dec_PrivateType*) ap_obj;475return h264d_release_all_headers (priv);476}477478static OMX_ERRORTYPE h264d_prc_buffers_ready(const void *ap_obj)479{480vid_dec_PrivateType*priv = (vid_dec_PrivateType*) ap_obj;481OMX_BUFFERHEADERTYPE *in_buf = NULL;482OMX_BUFFERHEADERTYPE *out_buf = NULL;483484assert(priv);485486/* Set parameters if start of stream */487if (!priv->eos_ && priv->first_buf_in_frame && (in_buf = get_input_buffer(priv))) {488decode_frame(priv, in_buf);489}490491/* Don't get input buffer if output buffer not found */492while (!priv->eos_ && (out_buf = get_output_buffer(priv)) && (in_buf = get_input_buffer(priv))) {493if (!priv->out_port_disabled_) {494decode_frame(priv, in_buf);495}496}497498return OMX_ErrorNone;499}500501static OMX_ERRORTYPE h264d_prc_port_flush(const void *ap_obj, OMX_U32 a_pid)502{503vid_dec_PrivateType*priv = (vid_dec_PrivateType*) ap_obj;504if (OMX_ALL == a_pid || OMX_VID_DEC_AVC_INPUT_PORT_INDEX == a_pid) {505release_input_headers(priv);506reset_stream_parameters(priv);507}508if (OMX_ALL == a_pid || OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX == a_pid) {509release_output_header(priv);510}511return OMX_ErrorNone;512}513514static OMX_ERRORTYPE h264d_prc_port_disable(const void *ap_obj, OMX_U32 a_pid)515{516vid_dec_PrivateType*priv = (vid_dec_PrivateType*) ap_obj;517assert(priv);518if (OMX_ALL == a_pid || OMX_VID_DEC_AVC_INPUT_PORT_INDEX == a_pid) {519/* Release all buffers */520h264d_release_all_headers(priv);521reset_stream_parameters(priv);522priv->in_port_disabled_ = true;523}524if (OMX_ALL == a_pid || OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX == a_pid) {525release_output_header(priv);526priv->out_port_disabled_ = true;527}528return OMX_ErrorNone;529}530531static OMX_ERRORTYPE h264d_prc_port_enable(const void *ap_obj, OMX_U32 a_pid)532{533vid_dec_PrivateType* priv = (vid_dec_PrivateType*) ap_obj;534assert(priv);535if (OMX_ALL == a_pid || OMX_VID_DEC_AVC_INPUT_PORT_INDEX == a_pid) {536if (priv->in_port_disabled_) {537reset_stream_parameters(priv);538priv->in_port_disabled_ = false;539}540}541if (OMX_ALL == a_pid || OMX_VID_DEC_AVC_OUTPUT_PORT_INDEX == a_pid) {542priv->out_port_disabled_ = false;543}544return OMX_ErrorNone;545}546547/*548* h264d_prc_class549*/550551static void * h264d_prc_class_ctor(void *ap_obj, va_list * app)552{553/* NOTE: Class methods might be added in the future. None for now. */554return super_ctor(typeOf(ap_obj, "h264dprc_class"), ap_obj, app);555}556557/*558* initialization559*/560561void * h264d_prc_class_init(void * ap_tos, void * ap_hdl)562{563void * tizprc = tiz_get_type(ap_hdl, "tizprc");564void * h264dprc_class = factory_new565/* TIZ_CLASS_COMMENT: class type, class name, parent, size */566(classOf(tizprc), "h264dprc_class", classOf(tizprc),567sizeof(h264d_prc_class_t),568/* TIZ_CLASS_COMMENT: */569ap_tos, ap_hdl,570/* TIZ_CLASS_COMMENT: class constructor */571ctor, h264d_prc_class_ctor,572/* TIZ_CLASS_COMMENT: stop value*/5730);574return h264dprc_class;575}576577void * h264d_prc_init(void * ap_tos, void * ap_hdl)578{579void * tizprc = tiz_get_type(ap_hdl, "tizprc");580void * h264dprc_class = tiz_get_type(ap_hdl, "h264dprc_class");581TIZ_LOG_CLASS (h264dprc_class);582void * h264dprc = factory_new583/* TIZ_CLASS_COMMENT: class type, class name, parent, size */584(h264dprc_class, "h264dprc", tizprc, sizeof(vid_dec_PrivateType),585/* TIZ_CLASS_COMMENT: */586ap_tos, ap_hdl,587/* TIZ_CLASS_COMMENT: class constructor */588ctor, h264d_prc_ctor,589/* TIZ_CLASS_COMMENT: class destructor */590dtor, h264d_prc_dtor,591/* TIZ_CLASS_COMMENT: */592tiz_srv_allocate_resources, h264d_prc_allocate_resources,593/* TIZ_CLASS_COMMENT: */594tiz_srv_deallocate_resources, h264d_prc_deallocate_resources,595/* TIZ_CLASS_COMMENT: */596tiz_srv_prepare_to_transfer, h264d_prc_prepare_to_transfer,597/* TIZ_CLASS_COMMENT: */598tiz_srv_transfer_and_process, h264d_prc_transfer_and_process,599/* TIZ_CLASS_COMMENT: */600tiz_srv_stop_and_return, h264d_prc_stop_and_return,601/* TIZ_CLASS_COMMENT: */602tiz_prc_buffers_ready, h264d_prc_buffers_ready,603/* TIZ_CLASS_COMMENT: */604tiz_prc_port_flush, h264d_prc_port_flush,605/* TIZ_CLASS_COMMENT: */606tiz_prc_port_disable, h264d_prc_port_disable,607/* TIZ_CLASS_COMMENT: */608tiz_prc_port_enable, h264d_prc_port_enable,609/* TIZ_CLASS_COMMENT: stop value*/6100);611612return h264dprc;613}614615616