diff options
author | Gurkirpal Singh <[email protected]> | 2018-01-20 05:12:06 +0530 |
---|---|---|
committer | Julien Isorce <[email protected]> | 2018-03-06 13:07:03 +0000 |
commit | bb5e27fab6087a5c1528a5faf507acce700e883c (patch) | |
tree | 8c0bff83d1c599b20d75a62b998255615ae435ea /src/gallium/state_trackers/omx | |
parent | e96e6f60f705c04a3d437eea9fe308826b494c67 (diff) |
st/omx/bellagio: Rename st and target directories
v2: Refactor out screen functions to st/omx
Allows to keep all the code under st/omx (st/omx/tizonia and
st/omx/bellagio).
Reverts targets/omx_bellagio to omx as additions to existing files
is enough to compile for both bellagio and tizonia.
* autotools changes:
--enable-omx -> --enable-omx-bellagio
* meson changes:
-Dgallium-omx=false -> -Dgallium-omx=disabled
-Dgallium-omx=true -> -Dgallium-omx=bellagio
Acked-by: Leo Liu <[email protected]>
Reviewed-by: Julien Isorce <[email protected]>
Diffstat (limited to 'src/gallium/state_trackers/omx')
-rw-r--r-- | src/gallium/state_trackers/omx/Makefile.am | 39 | ||||
-rw-r--r-- | src/gallium/state_trackers/omx/Makefile.sources | 1 | ||||
-rw-r--r-- | src/gallium/state_trackers/omx/bellagio/Makefile.am | 36 | ||||
-rw-r--r-- | src/gallium/state_trackers/omx/bellagio/Makefile.sources | 10 | ||||
-rw-r--r-- | src/gallium/state_trackers/omx/bellagio/entrypoint.c | 152 | ||||
-rw-r--r-- | src/gallium/state_trackers/omx/bellagio/entrypoint.h | 48 | ||||
-rw-r--r-- | src/gallium/state_trackers/omx/bellagio/vid_dec.c | 644 | ||||
-rw-r--r-- | src/gallium/state_trackers/omx/bellagio/vid_dec.h | 148 | ||||
-rw-r--r-- | src/gallium/state_trackers/omx/bellagio/vid_dec_h264.c | 1032 | ||||
-rw-r--r-- | src/gallium/state_trackers/omx/bellagio/vid_dec_h265.c | 1013 | ||||
-rw-r--r-- | src/gallium/state_trackers/omx/bellagio/vid_dec_mpeg12.c | 383 | ||||
-rw-r--r-- | src/gallium/state_trackers/omx/bellagio/vid_enc.c | 1280 | ||||
-rw-r--r-- | src/gallium/state_trackers/omx/bellagio/vid_enc.h | 96 | ||||
-rw-r--r-- | src/gallium/state_trackers/omx/meson.build | 38 |
14 files changed, 4920 insertions, 0 deletions
diff --git a/src/gallium/state_trackers/omx/Makefile.am b/src/gallium/state_trackers/omx/Makefile.am new file mode 100644 index 00000000000..ea72787919c --- /dev/null +++ b/src/gallium/state_trackers/omx/Makefile.am @@ -0,0 +1,39 @@ +# Copyright © 2012 Intel Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +include Makefile.sources +include $(top_srcdir)/src/gallium/Automake.inc + +SUBDIRS = bellagio + +AM_CFLAGS = \ + $(GALLIUM_CFLAGS) \ + $(VISIBILITY_CFLAGS) \ + $(VL_CFLAGS) \ + $(XCB_DRI3_CFLAGS) \ + $(OMX_BELLAGIO_CFLAGS) + +noinst_LTLIBRARIES = libomxtracker_common.la + +libomxtracker_common_la_SOURCES = $(C_SOURCES) + +EXTRA_DIST = meson.build diff --git a/src/gallium/state_trackers/omx/Makefile.sources b/src/gallium/state_trackers/omx/Makefile.sources new file mode 100644 index 00000000000..9103ca899db --- /dev/null +++ b/src/gallium/state_trackers/omx/Makefile.sources @@ -0,0 +1 @@ +C_SOURCES := diff --git a/src/gallium/state_trackers/omx/bellagio/Makefile.am b/src/gallium/state_trackers/omx/bellagio/Makefile.am new file mode 100644 index 00000000000..3e542ab0f26 --- /dev/null +++ b/src/gallium/state_trackers/omx/bellagio/Makefile.am @@ -0,0 +1,36 @@ +# Copyright © 2012 Intel Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +include Makefile.sources +include $(top_srcdir)/src/gallium/Automake.inc + +AM_CFLAGS = \ + -I$(top_srcdir)/src/gallium/state_trackers/omx \ + $(GALLIUM_CFLAGS) \ + $(VISIBILITY_CFLAGS) \ + $(VL_CFLAGS) \ + $(XCB_DRI3_CFLAGS) \ + $(OMX_BELLAGIO_CFLAGS) + +noinst_LTLIBRARIES = libomxtracker.la + +libomxtracker_la_SOURCES = $(C_SOURCES) diff --git a/src/gallium/state_trackers/omx/bellagio/Makefile.sources b/src/gallium/state_trackers/omx/bellagio/Makefile.sources new file mode 100644 index 00000000000..ab60ce803cb --- /dev/null +++ b/src/gallium/state_trackers/omx/bellagio/Makefile.sources @@ -0,0 +1,10 @@ +C_SOURCES := \ + entrypoint.c \ + entrypoint.h \ + vid_dec.c \ + vid_dec.h \ + vid_dec_mpeg12.c \ + vid_dec_h264.c \ + vid_dec_h265.c \ + vid_enc.c \ + vid_enc.h diff --git a/src/gallium/state_trackers/omx/bellagio/entrypoint.c b/src/gallium/state_trackers/omx/bellagio/entrypoint.c new file mode 100644 index 00000000000..251cc7d65d5 --- /dev/null +++ b/src/gallium/state_trackers/omx/bellagio/entrypoint.c @@ -0,0 +1,152 @@ +/************************************************************************** + * + * Copyright 2013 Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* + * Authors: + * Christian König <[email protected]> + * + */ + +#include <assert.h> +#include <string.h> +#include <stdbool.h> + +#if defined(HAVE_X11_PLATFORM) +#include <X11/Xlib.h> +#else +#define XOpenDisplay(x) NULL +#define XCloseDisplay(x) +#define Display void +#endif + +#include "os/os_thread.h" +#include "util/u_memory.h" +#include "loader/loader.h" + +#include "entrypoint.h" +#include "vid_dec.h" +#include "vid_enc.h" + +static mtx_t omx_lock = _MTX_INITIALIZER_NP; +static Display *omx_display = NULL; +static struct vl_screen *omx_screen = NULL; +static unsigned omx_usecount = 0; +static const char *omx_render_node = NULL; +static int drm_fd; + +int omx_component_library_Setup(stLoaderComponentType **stComponents) +{ + OMX_ERRORTYPE r; + + if (stComponents == NULL) + return 2; + + /* component 0 - video decoder */ + r = vid_dec_LoaderComponent(stComponents[0]); + if (r != OMX_ErrorNone) + return OMX_ErrorInsufficientResources; + + /* component 1 - video encoder */ + r = vid_enc_LoaderComponent(stComponents[1]); + if (r != OMX_ErrorNone) + return OMX_ErrorInsufficientResources; + + return 2; +} + +struct vl_screen *omx_get_screen(void) +{ + static bool first_time = true; + mtx_lock(&omx_lock); + + if (!omx_screen) { + if (first_time) { + omx_render_node = debug_get_option("OMX_RENDER_NODE", NULL); + first_time = false; + } + if (omx_render_node) { + drm_fd = loader_open_device(omx_render_node); + if (drm_fd < 0) + goto error; + + omx_screen = vl_drm_screen_create(drm_fd); + if (!omx_screen) { + close(drm_fd); + goto error; + } + } else { + omx_display = XOpenDisplay(NULL); + if (!omx_display) + goto error; + + omx_screen = vl_dri3_screen_create(omx_display, 0); + if (!omx_screen) + omx_screen = vl_dri2_screen_create(omx_display, 0); + if (!omx_screen) { + XCloseDisplay(omx_display); + goto error; + } + } + } + + ++omx_usecount; + + mtx_unlock(&omx_lock); + return omx_screen; + +error: + mtx_unlock(&omx_lock); + return NULL; +} + +void omx_put_screen(void) +{ + mtx_lock(&omx_lock); + if ((--omx_usecount) == 0) { + omx_screen->destroy(omx_screen); + omx_screen = NULL; + + if (omx_render_node) + close(drm_fd); + else + XCloseDisplay(omx_display); + } + mtx_unlock(&omx_lock); +} + +OMX_ERRORTYPE omx_workaround_Destructor(OMX_COMPONENTTYPE *comp) +{ + omx_base_component_PrivateType* priv = (omx_base_component_PrivateType*)comp->pComponentPrivate; + + priv->state = OMX_StateInvalid; + tsem_up(priv->messageSem); + + /* wait for thread to exit */ + pthread_join(priv->messageHandlerThread, NULL); + + return omx_base_component_Destructor(comp); +} diff --git a/src/gallium/state_trackers/omx/bellagio/entrypoint.h b/src/gallium/state_trackers/omx/bellagio/entrypoint.h new file mode 100644 index 00000000000..7625d7a5b03 --- /dev/null +++ b/src/gallium/state_trackers/omx/bellagio/entrypoint.h @@ -0,0 +1,48 @@ +/************************************************************************** + * + * Copyright 2013 Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* + * Authors: + * Christian König <[email protected]> + * + */ + +#ifndef OMX_ENTRYPOINT_H +#define OMX_ENTRYPOINT_H + +#include <bellagio/st_static_component_loader.h> + +#include "vl/vl_winsys.h" + +PUBLIC extern int omx_component_library_Setup(stLoaderComponentType **stComponents); + +struct vl_screen *omx_get_screen(void); +void omx_put_screen(void); + +OMX_ERRORTYPE omx_workaround_Destructor(OMX_COMPONENTTYPE *comp); + +#endif diff --git a/src/gallium/state_trackers/omx/bellagio/vid_dec.c b/src/gallium/state_trackers/omx/bellagio/vid_dec.c new file mode 100644 index 00000000000..f9fe19f63f0 --- /dev/null +++ b/src/gallium/state_trackers/omx/bellagio/vid_dec.c @@ -0,0 +1,644 @@ +/************************************************************************** + * + * Copyright 2013 Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* + * Authors: + * Christian König <[email protected]> + * + */ + + +#include <assert.h> + +#include <OMX_Video.h> + +/* bellagio defines a DEBUG macro that we don't want */ +#ifndef DEBUG +#include <bellagio/omxcore.h> +#undef DEBUG +#else +#include <bellagio/omxcore.h> +#endif + +#include "pipe/p_screen.h" +#include "pipe/p_video_codec.h" +#include "util/u_memory.h" +#include "util/u_surface.h" +#include "vl/vl_video_buffer.h" +#include "vl/vl_vlc.h" + +#include "entrypoint.h" +#include "vid_dec.h" + +static OMX_ERRORTYPE vid_dec_Constructor(OMX_COMPONENTTYPE *comp, OMX_STRING name); +static OMX_ERRORTYPE vid_dec_Destructor(OMX_COMPONENTTYPE *comp); +static OMX_ERRORTYPE vid_dec_SetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param); +static OMX_ERRORTYPE vid_dec_GetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param); +static OMX_ERRORTYPE vid_dec_MessageHandler(OMX_COMPONENTTYPE *comp, internalRequestMessageType *msg); +static OMX_ERRORTYPE vid_dec_DecodeBuffer(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf); +static OMX_ERRORTYPE vid_dec_FreeDecBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf); +static void vid_dec_FrameDecoded(OMX_COMPONENTTYPE *comp, OMX_BUFFERHEADERTYPE* input, OMX_BUFFERHEADERTYPE* output); + +OMX_ERRORTYPE vid_dec_LoaderComponent(stLoaderComponentType *comp) +{ + comp->componentVersion.s.nVersionMajor = 0; + comp->componentVersion.s.nVersionMinor = 0; + comp->componentVersion.s.nRevision = 0; + comp->componentVersion.s.nStep = 1; + comp->name_specific_length = 3; + + comp->name = CALLOC(1, OMX_MAX_STRINGNAME_SIZE); + if (comp->name == NULL) + goto error; + + comp->name_specific = CALLOC(comp->name_specific_length, sizeof(char *)); + if (comp->name_specific == NULL) + goto error; + + comp->role_specific = CALLOC(comp->name_specific_length, sizeof(char *)); + if (comp->role_specific == NULL) + goto error; + + comp->name_specific[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE); + if (comp->name_specific[0] == NULL) + goto error_specific; + + comp->name_specific[1] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE); + if (comp->name_specific[1] == NULL) + goto error_specific; + + comp->name_specific[2] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE); + if (comp->name_specific[2] == NULL) + goto error_specific; + + comp->role_specific[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE); + if (comp->role_specific[0] == NULL) + goto error_specific; + + comp->role_specific[1] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE); + if (comp->role_specific[1] == NULL) + goto error_specific; + + comp->role_specific[2] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE); + if (comp->role_specific[2] == NULL) + goto error_specific; + + strcpy(comp->name, OMX_VID_DEC_BASE_NAME); + strcpy(comp->name_specific[0], OMX_VID_DEC_MPEG2_NAME); + strcpy(comp->name_specific[1], OMX_VID_DEC_AVC_NAME); + strcpy(comp->name_specific[2], OMX_VID_DEC_HEVC_NAME); + + strcpy(comp->role_specific[0], OMX_VID_DEC_MPEG2_ROLE); + strcpy(comp->role_specific[1], OMX_VID_DEC_AVC_ROLE); + strcpy(comp->role_specific[2], OMX_VID_DEC_HEVC_ROLE); + + comp->constructor = vid_dec_Constructor; + + return OMX_ErrorNone; + +error_specific: + FREE(comp->role_specific[2]); + FREE(comp->role_specific[1]); + FREE(comp->role_specific[0]); + FREE(comp->name_specific[2]); + FREE(comp->name_specific[1]); + FREE(comp->name_specific[0]); + +error: + FREE(comp->role_specific); + FREE(comp->name_specific); + + FREE(comp->name); + + return OMX_ErrorInsufficientResources; +} + +static OMX_ERRORTYPE vid_dec_Constructor(OMX_COMPONENTTYPE *comp, OMX_STRING name) +{ + vid_dec_PrivateType *priv; + omx_base_video_PortType *port; + struct pipe_screen *screen; + OMX_ERRORTYPE r; + int i; + + assert(!comp->pComponentPrivate); + + priv = comp->pComponentPrivate = CALLOC(1, sizeof(vid_dec_PrivateType)); + if (!priv) + return OMX_ErrorInsufficientResources; + + r = omx_base_filter_Constructor(comp, name); + if (r) + return r; + + priv->profile = PIPE_VIDEO_PROFILE_UNKNOWN; + + if (!strcmp(name, OMX_VID_DEC_MPEG2_NAME)) + priv->profile = PIPE_VIDEO_PROFILE_MPEG2_MAIN; + + if (!strcmp(name, OMX_VID_DEC_AVC_NAME)) + priv->profile = PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH; + + if (!strcmp(name, OMX_VID_DEC_HEVC_NAME)) + priv->profile = PIPE_VIDEO_PROFILE_HEVC_MAIN; + + priv->BufferMgmtCallback = vid_dec_FrameDecoded; + priv->messageHandler = vid_dec_MessageHandler; + priv->destructor = vid_dec_Destructor; + + comp->SetParameter = vid_dec_SetParameter; + comp->GetParameter = vid_dec_GetParameter; + + priv->screen = omx_get_screen(); + if (!priv->screen) + return OMX_ErrorInsufficientResources; + + screen = priv->screen->pscreen; + priv->pipe = screen->context_create(screen, NULL, 0); + if (!priv->pipe) + return OMX_ErrorInsufficientResources; + + if (!vl_compositor_init(&priv->compositor, priv->pipe)) { + priv->pipe->destroy(priv->pipe); + priv->pipe = NULL; + return OMX_ErrorInsufficientResources; + } + + if (!vl_compositor_init_state(&priv->cstate, priv->pipe)) { + vl_compositor_cleanup(&priv->compositor); + priv->pipe->destroy(priv->pipe); + priv->pipe = NULL; + return OMX_ErrorInsufficientResources; + } + + priv->sPortTypesParam[OMX_PortDomainVideo].nStartPortNumber = 0; + priv->sPortTypesParam[OMX_PortDomainVideo].nPorts = 2; + priv->ports = CALLOC(2, sizeof(omx_base_PortType *)); + if (!priv->ports) + return OMX_ErrorInsufficientResources; + + for (i = 0; i < 2; ++i) { + priv->ports[i] = CALLOC(1, sizeof(omx_base_video_PortType)); + if (!priv->ports[i]) + return OMX_ErrorInsufficientResources; + + base_video_port_Constructor(comp, &priv->ports[i], i, i == 0); + } + + port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX]; + strcpy(port->sPortParam.format.video.cMIMEType,"video/MPEG2"); + port->sPortParam.nBufferCountMin = 8; + port->sPortParam.nBufferCountActual = 8; + port->sPortParam.nBufferSize = DEFAULT_OUT_BUFFER_SIZE; + port->sPortParam.format.video.nFrameWidth = 176; + port->sPortParam.format.video.nFrameHeight = 144; + port->sPortParam.format.video.eCompressionFormat = OMX_VIDEO_CodingMPEG2; + port->sVideoParam.eCompressionFormat = OMX_VIDEO_CodingMPEG2; + port->Port_SendBufferFunction = vid_dec_DecodeBuffer; + port->Port_FreeBuffer = vid_dec_FreeDecBuffer; + + port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX]; + port->sPortParam.nBufferCountActual = 8; + port->sPortParam.nBufferCountMin = 4; + port->sPortParam.format.video.nFrameWidth = 176; + port->sPortParam.format.video.nFrameHeight = 144; + port->sPortParam.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar; + port->sVideoParam.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar; + + return OMX_ErrorNone; +} + +static OMX_ERRORTYPE vid_dec_Destructor(OMX_COMPONENTTYPE *comp) +{ + vid_dec_PrivateType* priv = comp->pComponentPrivate; + int i; + + if (priv->ports) { + for (i = 0; i < priv->sPortTypesParam[OMX_PortDomainVideo].nPorts; ++i) { + if(priv->ports[i]) + priv->ports[i]->PortDestructor(priv->ports[i]); + } + FREE(priv->ports); + priv->ports=NULL; + } + + if (priv->pipe) { + vl_compositor_cleanup_state(&priv->cstate); + vl_compositor_cleanup(&priv->compositor); + priv->pipe->destroy(priv->pipe); + } + + if (priv->screen) + omx_put_screen(); + + return omx_workaround_Destructor(comp); +} + +static OMX_ERRORTYPE vid_dec_SetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param) +{ + OMX_COMPONENTTYPE *comp = handle; + vid_dec_PrivateType *priv = comp->pComponentPrivate; + OMX_ERRORTYPE r; + + if (!param) + return OMX_ErrorBadParameter; + + switch(idx) { + case OMX_IndexParamPortDefinition: { + OMX_PARAM_PORTDEFINITIONTYPE *def = param; + + r = omx_base_component_SetParameter(handle, idx, param); + if (r) + return r; + + if (def->nPortIndex == OMX_BASE_FILTER_INPUTPORT_INDEX) { + omx_base_video_PortType *port; + unsigned framesize = def->format.video.nFrameWidth * def->format.video.nFrameHeight; + + port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX]; + port->sPortParam.nBufferSize = framesize * 512 / (16*16); + + port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX]; + port->sPortParam.format.video.nFrameWidth = def->format.video.nFrameWidth; + port->sPortParam.format.video.nFrameHeight = def->format.video.nFrameHeight; + port->sPortParam.format.video.nStride = def->format.video.nFrameWidth; + port->sPortParam.format.video.nSliceHeight = def->format.video.nFrameHeight; + port->sPortParam.nBufferSize = framesize*3/2; + + priv->callbacks->EventHandler(comp, priv->callbackData, OMX_EventPortSettingsChanged, + OMX_BASE_FILTER_OUTPUTPORT_INDEX, 0, NULL); + } + break; + } + case OMX_IndexParamStandardComponentRole: { + OMX_PARAM_COMPONENTROLETYPE *role = param; + + r = checkHeader(param, sizeof(OMX_PARAM_COMPONENTROLETYPE)); + if (r) + return r; + + if (!strcmp((char *)role->cRole, OMX_VID_DEC_MPEG2_ROLE)) { + priv->profile = PIPE_VIDEO_PROFILE_MPEG2_MAIN; + } else if (!strcmp((char *)role->cRole, OMX_VID_DEC_AVC_ROLE)) { + priv->profile = PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH; + } else if (!strcmp((char *)role->cRole, OMX_VID_DEC_HEVC_ROLE)) { + priv->profile = PIPE_VIDEO_PROFILE_HEVC_MAIN; + } else { + return OMX_ErrorBadParameter; + } + + break; + } + case OMX_IndexParamVideoPortFormat: { + OMX_VIDEO_PARAM_PORTFORMATTYPE *format = param; + omx_base_video_PortType *port; + + r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE)); + if (r) + return r; + + if (format->nPortIndex > 1) + return OMX_ErrorBadPortIndex; + + port = (omx_base_video_PortType *)priv->ports[format->nPortIndex]; + memcpy(&port->sVideoParam, format, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE)); + break; + } + default: + return omx_base_component_SetParameter(handle, idx, param); + } + return OMX_ErrorNone; +} + +static OMX_ERRORTYPE vid_dec_GetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param) +{ + OMX_COMPONENTTYPE *comp = handle; + vid_dec_PrivateType *priv = comp->pComponentPrivate; + OMX_ERRORTYPE r; + + if (!param) + return OMX_ErrorBadParameter; + + switch(idx) { + case OMX_IndexParamStandardComponentRole: { + OMX_PARAM_COMPONENTROLETYPE *role = param; + + r = checkHeader(param, sizeof(OMX_PARAM_COMPONENTROLETYPE)); + if (r) + return r; + + if (priv->profile == PIPE_VIDEO_PROFILE_MPEG2_MAIN) + strcpy((char *)role->cRole, OMX_VID_DEC_MPEG2_ROLE); + else if (priv->profile == PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH) + strcpy((char *)role->cRole, OMX_VID_DEC_AVC_ROLE); + else if (priv->profile == PIPE_VIDEO_PROFILE_HEVC_MAIN) + strcpy((char *)role->cRole, OMX_VID_DEC_HEVC_ROLE); + + break; + } + + case OMX_IndexParamVideoInit: + r = checkHeader(param, sizeof(OMX_PORT_PARAM_TYPE)); + if (r) + return r; + + memcpy(param, &priv->sPortTypesParam[OMX_PortDomainVideo], sizeof(OMX_PORT_PARAM_TYPE)); + break; + + case OMX_IndexParamVideoPortFormat: { + OMX_VIDEO_PARAM_PORTFORMATTYPE *format = param; + omx_base_video_PortType *port; + + r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE)); + if (r) + return r; + + if (format->nPortIndex > 1) + return OMX_ErrorBadPortIndex; + + port = (omx_base_video_PortType *)priv->ports[format->nPortIndex]; + memcpy(format, &port->sVideoParam, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE)); + break; + } + + default: + return omx_base_component_GetParameter(handle, idx, param); + + } + return OMX_ErrorNone; +} + +static OMX_ERRORTYPE vid_dec_MessageHandler(OMX_COMPONENTTYPE* comp, internalRequestMessageType *msg) +{ + vid_dec_PrivateType* priv = comp->pComponentPrivate; + + if (msg->messageType == OMX_CommandStateSet) { + if ((msg->messageParam == OMX_StateIdle ) && (priv->state == OMX_StateLoaded)) { + if (priv->profile == PIPE_VIDEO_PROFILE_MPEG2_MAIN) + vid_dec_mpeg12_Init(priv); + else if (priv->profile == PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH) + vid_dec_h264_Init(priv); + else if (priv->profile == PIPE_VIDEO_PROFILE_HEVC_MAIN) + vid_dec_h265_Init(priv); + + } else if ((msg->messageParam == OMX_StateLoaded) && (priv->state == OMX_StateIdle)) { + if (priv->shadow) { + priv->shadow->destroy(priv->shadow); + priv->shadow = NULL; + } + if (priv->codec) { + priv->codec->destroy(priv->codec); + priv->codec = NULL; + } + } + } + + return omx_base_component_MessageHandler(comp, msg); +} + +void vid_dec_NeedTarget(vid_dec_PrivateType *priv) +{ + struct pipe_video_buffer templat = {}; + struct vl_screen *omx_screen; + struct pipe_screen *pscreen; + + omx_screen = priv->screen; + assert(omx_screen); + + pscreen = omx_screen->pscreen; + assert(pscreen); + + if (!priv->target) { + memset(&templat, 0, sizeof(templat)); + + templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420; + templat.width = priv->codec->width; + templat.height = priv->codec->height; + templat.buffer_format = pscreen->get_video_param( + pscreen, + PIPE_VIDEO_PROFILE_UNKNOWN, + PIPE_VIDEO_ENTRYPOINT_BITSTREAM, + PIPE_VIDEO_CAP_PREFERED_FORMAT + ); + templat.interlaced = pscreen->get_video_param( + pscreen, + PIPE_VIDEO_PROFILE_UNKNOWN, + PIPE_VIDEO_ENTRYPOINT_BITSTREAM, + PIPE_VIDEO_CAP_PREFERS_INTERLACED + ); + priv->target = priv->pipe->create_video_buffer(priv->pipe, &templat); + } +} + +static void vid_dec_FreeInputPortPrivate(OMX_BUFFERHEADERTYPE *buf) +{ + struct pipe_video_buffer *vbuf = buf->pInputPortPrivate; + if (!vbuf) + return; + + vbuf->destroy(vbuf); + buf->pInputPortPrivate = NULL; +} + +static OMX_ERRORTYPE vid_dec_DecodeBuffer(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf) +{ + OMX_COMPONENTTYPE* comp = port->standCompContainer; + vid_dec_PrivateType *priv = comp->pComponentPrivate; + unsigned i = priv->num_in_buffers++; + OMX_ERRORTYPE r; + + priv->in_buffers[i] = buf; + priv->sizes[i] = buf->nFilledLen; + priv->inputs[i] = buf->pBuffer; + priv->timestamps[i] = buf->nTimeStamp; + + while (priv->num_in_buffers > (!!(buf->nFlags & OMX_BUFFERFLAG_EOS) ? 0 : 1)) { + bool eos = !!(priv->in_buffers[0]->nFlags & OMX_BUFFERFLAG_EOS); + unsigned min_bits_left = eos ? 32 : MAX2(buf->nFilledLen * 8, 32); + struct vl_vlc vlc; + + vl_vlc_init(&vlc, priv->num_in_buffers, priv->inputs, priv->sizes); + + if (priv->slice) + priv->bytes_left = vl_vlc_bits_left(&vlc) / 8; + + while (vl_vlc_bits_left(&vlc) > min_bits_left) { + priv->Decode(priv, &vlc, min_bits_left); + vl_vlc_fillbits(&vlc); + } + + if (priv->slice) { + unsigned bytes = priv->bytes_left - vl_vlc_bits_left(&vlc) / 8; + + priv->codec->decode_bitstream(priv->codec, priv->target, &priv->picture.base, + 1, &priv->slice, &bytes); + + if (priv->num_in_buffers) + priv->slice = priv->inputs[1]; + else + priv->slice = NULL; + } + + if (eos && priv->frame_started) + priv->EndFrame(priv); + + if (priv->frame_finished) { + priv->frame_finished = false; + priv->in_buffers[0]->nFilledLen = priv->in_buffers[0]->nAllocLen; + r = base_port_SendBufferFunction(port, priv->in_buffers[0]); + } else if (eos) { + vid_dec_FreeInputPortPrivate(priv->in_buffers[0]); + priv->in_buffers[0]->nFilledLen = priv->in_buffers[0]->nAllocLen; + r = base_port_SendBufferFunction(port, priv->in_buffers[0]); + } else { + priv->in_buffers[0]->nFilledLen = 0; + r = port->ReturnBufferFunction(port, priv->in_buffers[0]); + } + + if (--priv->num_in_buffers) { + unsigned delta = MIN2((min_bits_left - vl_vlc_bits_left(&vlc)) / 8, priv->sizes[1]); + + priv->in_buffers[0] = priv->in_buffers[1]; + priv->sizes[0] = priv->sizes[1] - delta; + priv->inputs[0] = priv->inputs[1] + delta; + priv->timestamps[0] = priv->timestamps[1]; + } + + if (r) + return r; + } + + return OMX_ErrorNone; +} + +static OMX_ERRORTYPE vid_dec_FreeDecBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf) +{ + vid_dec_FreeInputPortPrivate(buf); + return base_port_FreeBuffer(port, idx, buf); +} + +static void vid_dec_FillOutput(vid_dec_PrivateType *priv, struct pipe_video_buffer *buf, + OMX_BUFFERHEADERTYPE* output) +{ + omx_base_PortType *port = priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX]; + OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video; + + struct pipe_sampler_view **views; + unsigned i, j; + unsigned width, height; + + views = buf->get_sampler_view_planes(buf); + + for (i = 0; i < 2 /* NV12 */; i++) { + if (!views[i]) continue; + width = def->nFrameWidth; + height = def->nFrameHeight; + vl_video_buffer_adjust_size(&width, &height, i, buf->chroma_format, buf->interlaced); + for (j = 0; j < views[i]->texture->array_size; ++j) { + struct pipe_box box = {0, 0, j, width, height, 1}; + struct pipe_transfer *transfer; + uint8_t *map, *dst; + map = priv->pipe->transfer_map(priv->pipe, views[i]->texture, 0, + PIPE_TRANSFER_READ, &box, &transfer); + if (!map) + return; + + dst = ((uint8_t*)output->pBuffer + output->nOffset) + j * def->nStride + + i * def->nFrameWidth * def->nFrameHeight; + util_copy_rect(dst, + views[i]->texture->format, + def->nStride * views[i]->texture->array_size, 0, 0, + box.width, box.height, map, transfer->stride, 0, 0); + + pipe_transfer_unmap(priv->pipe, transfer); + } + } +} + +static void vid_dec_FrameDecoded(OMX_COMPONENTTYPE *comp, OMX_BUFFERHEADERTYPE* input, + OMX_BUFFERHEADERTYPE* output) +{ + vid_dec_PrivateType *priv = comp->pComponentPrivate; + bool eos = !!(input->nFlags & OMX_BUFFERFLAG_EOS); + OMX_TICKS timestamp; + + if (!input->pInputPortPrivate) { + input->pInputPortPrivate = priv->Flush(priv, ×tamp); + if (timestamp != OMX_VID_DEC_TIMESTAMP_INVALID) + input->nTimeStamp = timestamp; + } + + if (input->pInputPortPrivate) { + if (output->pInputPortPrivate && !priv->disable_tunnel) { + struct pipe_video_buffer *tmp, *vbuf, *new_vbuf; + + tmp = output->pOutputPortPrivate; + vbuf = input->pInputPortPrivate; + if (vbuf->interlaced) { + /* re-allocate the progressive buffer */ + omx_base_video_PortType *port; + struct pipe_video_buffer templat = {}; + struct u_rect src_rect, dst_rect; + + port = (omx_base_video_PortType *) + priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX]; + memset(&templat, 0, sizeof(templat)); + templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420; + templat.width = port->sPortParam.format.video.nFrameWidth; + templat.height = port->sPortParam.format.video.nFrameHeight; + templat.buffer_format = PIPE_FORMAT_NV12; + templat.interlaced = false; + new_vbuf = priv->pipe->create_video_buffer(priv->pipe, &templat); + + /* convert the interlaced to the progressive */ + src_rect.x0 = dst_rect.x0 = 0; + src_rect.x1 = dst_rect.x1 = templat.width; + src_rect.y0 = dst_rect.y0 = 0; + src_rect.y1 = dst_rect.y1 = templat.height; + + vl_compositor_yuv_deint_full(&priv->cstate, &priv->compositor, + input->pInputPortPrivate, new_vbuf, + &src_rect, &dst_rect, VL_COMPOSITOR_WEAVE); + + /* set the progrssive buffer for next round */ + vbuf->destroy(vbuf); + input->pInputPortPrivate = new_vbuf; + } + output->pOutputPortPrivate = input->pInputPortPrivate; + input->pInputPortPrivate = tmp; + } else { + vid_dec_FillOutput(priv, input->pInputPortPrivate, output); + } + output->nFilledLen = output->nAllocLen; + output->nTimeStamp = input->nTimeStamp; + } + + if (eos && input->pInputPortPrivate) + vid_dec_FreeInputPortPrivate(input); + else + input->nFilledLen = 0; +} diff --git a/src/gallium/state_trackers/omx/bellagio/vid_dec.h b/src/gallium/state_trackers/omx/bellagio/vid_dec.h new file mode 100644 index 00000000000..7a10e750d91 --- /dev/null +++ b/src/gallium/state_trackers/omx/bellagio/vid_dec.h @@ -0,0 +1,148 @@ +/************************************************************************** + * + * Copyright 2013 Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* + * Authors: + * Christian König <[email protected]> + * + */ + +#ifndef OMX_VID_DEC_H +#define OMX_VID_DEC_H + +#include <string.h> + +#include <OMX_Types.h> +#include <OMX_Component.h> +#include <OMX_Core.h> + +#include <bellagio/st_static_component_loader.h> +#include <bellagio/omx_base_filter.h> +#include <bellagio/omx_base_video_port.h> + +#include "pipe/p_video_state.h" +#include "os/os_thread.h" +#include "util/list.h" + +#include "vl/vl_compositor.h" + +#define OMX_VID_DEC_BASE_NAME "OMX.mesa.video_decoder" + +#define OMX_VID_DEC_MPEG2_NAME "OMX.mesa.video_decoder.mpeg2" +#define OMX_VID_DEC_MPEG2_ROLE "video_decoder.mpeg2" + +#define OMX_VID_DEC_AVC_NAME "OMX.mesa.video_decoder.avc" +#define OMX_VID_DEC_AVC_ROLE "video_decoder.avc" + +#define OMX_VID_DEC_HEVC_NAME "OMX.mesa.video_decoder.hevc" +#define OMX_VID_DEC_HEVC_ROLE "video_decoder.hevc" + +#define OMX_VID_DEC_TIMESTAMP_INVALID ((OMX_TICKS) -1) + +struct vl_vlc; + +DERIVEDCLASS(vid_dec_PrivateType, omx_base_filter_PrivateType) +#define vid_dec_PrivateType_FIELDS omx_base_filter_PrivateType_FIELDS \ + enum pipe_video_profile profile; \ + struct vl_screen *screen; \ + struct pipe_context *pipe; \ + struct pipe_video_codec *codec; \ + void (*Decode)(vid_dec_PrivateType *priv, struct vl_vlc *vlc, unsigned min_bits_left); \ + void (*EndFrame)(vid_dec_PrivateType *priv); \ + struct pipe_video_buffer *(*Flush)(vid_dec_PrivateType *priv, OMX_TICKS *timestamp); \ + struct pipe_video_buffer *target, *shadow; \ + union { \ + struct { \ + uint8_t intra_matrix[64]; \ + uint8_t non_intra_matrix[64]; \ + } mpeg12; \ + struct { \ + unsigned nal_ref_idc; \ + bool IdrPicFlag; \ + unsigned idr_pic_id; \ + unsigned pic_order_cnt_lsb; \ + unsigned pic_order_cnt_msb; \ + unsigned delta_pic_order_cnt_bottom; \ + unsigned delta_pic_order_cnt[2]; \ + unsigned prevFrameNumOffset; \ + struct pipe_h264_sps sps[32]; \ + struct pipe_h264_pps pps[256]; \ + struct list_head dpb_list; \ + unsigned dpb_num; \ + } h264; \ + struct { \ + unsigned temporal_id; \ + unsigned level_idc; \ + unsigned pic_width_in_luma_samples; \ + unsigned pic_height_in_luma_samples; \ + bool IdrPicFlag; \ + int slice_prev_poc; \ + void *ref_pic_set_list; \ + void *rps; \ + struct pipe_h265_sps sps[16]; \ + struct pipe_h265_pps pps[64]; \ + struct list_head dpb_list; \ + unsigned dpb_num; \ + } h265; \ + } codec_data; \ + union { \ + struct pipe_picture_desc base; \ + struct pipe_mpeg12_picture_desc mpeg12; \ + struct pipe_h264_picture_desc h264; \ + struct pipe_h265_picture_desc h265; \ + } picture; \ + unsigned num_in_buffers; \ + OMX_BUFFERHEADERTYPE *in_buffers[2]; \ + const void *inputs[2]; \ + unsigned sizes[2]; \ + OMX_TICKS timestamps[2]; \ + OMX_TICKS timestamp; \ + bool first_buf_in_frame; \ + bool frame_finished; \ + bool frame_started; \ + unsigned bytes_left; \ + const void *slice; \ + bool disable_tunnel; \ + struct vl_compositor compositor; \ + struct vl_compositor_state cstate; +ENDCLASS(vid_dec_PrivateType) + +OMX_ERRORTYPE vid_dec_LoaderComponent(stLoaderComponentType *comp); + +/* used by MPEG12 and H264 implementation */ +void vid_dec_NeedTarget(vid_dec_PrivateType *priv); + +/* vid_dec_mpeg12.c */ +void vid_dec_mpeg12_Init(vid_dec_PrivateType *priv); + +/* vid_dec_h264.c */ +void vid_dec_h264_Init(vid_dec_PrivateType *priv); + +/* vid_dec_h265.c */ +void vid_dec_h265_Init(vid_dec_PrivateType *priv); + +#endif diff --git a/src/gallium/state_trackers/omx/bellagio/vid_dec_h264.c b/src/gallium/state_trackers/omx/bellagio/vid_dec_h264.c new file mode 100644 index 00000000000..7ea71c1046b --- /dev/null +++ b/src/gallium/state_trackers/omx/bellagio/vid_dec_h264.c @@ -0,0 +1,1032 @@ +/************************************************************************** + * + * Copyright 2013 Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* + * Authors: + * Christian König <[email protected]> + * + */ + +#include "pipe/p_video_codec.h" +#include "util/u_memory.h" +#include "util/u_video.h" +#include "vl/vl_rbsp.h" +#include "vl/vl_zscan.h" + +#include "entrypoint.h" +#include "vid_dec.h" + +#define DPB_MAX_SIZE 5 + +struct dpb_list { + struct list_head list; + struct pipe_video_buffer *buffer; + OMX_TICKS timestamp; + int poc; +}; + +static const uint8_t Default_4x4_Intra[16] = { + 6, 13, 20, 28, 13, 20, 28, 32, + 20, 28, 32, 37, 28, 32, 37, 42 +}; + +static const uint8_t Default_4x4_Inter[16] = { + 10, 14, 20, 24, 14, 20, 24, 27, + 20, 24, 27, 30, 24, 27, 30, 34 +}; + +static const uint8_t Default_8x8_Intra[64] = { + 6, 10, 13, 16, 18, 23, 25, 27, + 10, 11, 16, 18, 23, 25, 27, 29, + 13, 16, 18, 23, 25, 27, 29, 31, + 16, 18, 23, 25, 27, 29, 31, 33, + 18, 23, 25, 27, 29, 31, 33, 36, + 23, 25, 27, 29, 31, 33, 36, 38, + 25, 27, 29, 31, 33, 36, 38, 40, + 27, 29, 31, 33, 36, 38, 40, 42 +}; + +static const uint8_t Default_8x8_Inter[64] = { + 9, 13, 15, 17, 19, 21, 22, 24, + 13, 13, 17, 19, 21, 22, 24, 25, + 15, 17, 19, 21, 22, 24, 25, 27, + 17, 19, 21, 22, 24, 25, 27, 28, + 19, 21, 22, 24, 25, 27, 28, 30, + 21, 22, 24, 25, 27, 28, 30, 32, + 22, 24, 25, 27, 28, 30, 32, 33, + 24, 25, 27, 28, 30, 32, 33, 35 +}; + +static void vid_dec_h264_Decode(vid_dec_PrivateType *priv, struct vl_vlc *vlc, unsigned min_bits_left); +static void vid_dec_h264_EndFrame(vid_dec_PrivateType *priv); +static struct pipe_video_buffer *vid_dec_h264_Flush(vid_dec_PrivateType *priv, OMX_TICKS *timestamp); + +void vid_dec_h264_Init(vid_dec_PrivateType *priv) +{ + priv->picture.base.profile = PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH; + + priv->Decode = vid_dec_h264_Decode; + priv->EndFrame = vid_dec_h264_EndFrame; + priv->Flush = vid_dec_h264_Flush; + + LIST_INITHEAD(&priv->codec_data.h264.dpb_list); + priv->picture.h264.field_order_cnt[0] = priv->picture.h264.field_order_cnt[1] = INT_MAX; + priv->first_buf_in_frame = true; +} + +static void vid_dec_h264_BeginFrame(vid_dec_PrivateType *priv) +{ + //TODO: sane buffer handling + + if (priv->frame_started) + return; + + if (!priv->codec) { + struct pipe_video_codec templat = {}; + omx_base_video_PortType *port; + + port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX]; + templat.profile = priv->profile; + templat.entrypoint = PIPE_VIDEO_ENTRYPOINT_BITSTREAM; + templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420; + templat.max_references = priv->picture.h264.num_ref_frames; + templat.expect_chunked_decode = true; + templat.width = port->sPortParam.format.video.nFrameWidth; + templat.height = port->sPortParam.format.video.nFrameHeight; + templat.level = priv->picture.h264.pps->sps->level_idc; + + priv->codec = priv->pipe->create_video_codec(priv->pipe, &templat); + } + + vid_dec_NeedTarget(priv); + + if (priv->first_buf_in_frame) + priv->timestamp = priv->timestamps[0]; + priv->first_buf_in_frame = false; + + priv->picture.h264.num_ref_frames = priv->picture.h264.pps->sps->max_num_ref_frames; + + priv->picture.h264.slice_count = 0; + priv->codec->begin_frame(priv->codec, priv->target, &priv->picture.base); + priv->frame_started = true; +} + +static struct pipe_video_buffer *vid_dec_h264_Flush(vid_dec_PrivateType *priv, + OMX_TICKS *timestamp) +{ + struct dpb_list *entry, *result = NULL; + struct pipe_video_buffer *buf; + + /* search for the lowest poc and break on zeros */ + LIST_FOR_EACH_ENTRY(entry, &priv->codec_data.h264.dpb_list, list) { + + if (result && entry->poc == 0) + break; + + if (!result || entry->poc < result->poc) + result = entry; + } + + if (!result) + return NULL; + + buf = result->buffer; + if (timestamp) + *timestamp = result->timestamp; + + --priv->codec_data.h264.dpb_num; + LIST_DEL(&result->list); + FREE(result); + + return buf; +} + +static void vid_dec_h264_EndFrame(vid_dec_PrivateType *priv) +{ + struct dpb_list *entry; + struct pipe_video_buffer *tmp; + bool top_field_first; + OMX_TICKS timestamp; + + if (!priv->frame_started) + return; + + priv->codec->end_frame(priv->codec, priv->target, &priv->picture.base); + priv->frame_started = false; + + // TODO: implement frame number handling + priv->picture.h264.frame_num_list[0] = priv->picture.h264.frame_num; + priv->picture.h264.field_order_cnt_list[0][0] = priv->picture.h264.frame_num; + priv->picture.h264.field_order_cnt_list[0][1] = priv->picture.h264.frame_num; + + top_field_first = priv->picture.h264.field_order_cnt[0] < priv->picture.h264.field_order_cnt[1]; + + if (priv->picture.h264.field_pic_flag && priv->picture.h264.bottom_field_flag != top_field_first) + return; + + /* add the decoded picture to the dpb list */ + entry = CALLOC_STRUCT(dpb_list); + if (!entry) + return; + + priv->first_buf_in_frame = true; + entry->buffer = priv->target; + entry->timestamp = priv->timestamp; + entry->poc = MIN2(priv->picture.h264.field_order_cnt[0], priv->picture.h264.field_order_cnt[1]); + LIST_ADDTAIL(&entry->list, &priv->codec_data.h264.dpb_list); + ++priv->codec_data.h264.dpb_num; + priv->target = NULL; + priv->picture.h264.field_order_cnt[0] = priv->picture.h264.field_order_cnt[1] = INT_MAX; + + if (priv->codec_data.h264.dpb_num <= DPB_MAX_SIZE) + return; + + tmp = priv->in_buffers[0]->pInputPortPrivate; + priv->in_buffers[0]->pInputPortPrivate = vid_dec_h264_Flush(priv, ×tamp); + priv->in_buffers[0]->nTimeStamp = timestamp; + priv->target = tmp; + priv->frame_finished = priv->in_buffers[0]->pInputPortPrivate != NULL; +} + +static void vui_parameters(struct vl_rbsp *rbsp) +{ + // TODO +} + +static void scaling_list(struct vl_rbsp *rbsp, uint8_t *scalingList, unsigned sizeOfScalingList, + const uint8_t *defaultList, const uint8_t *fallbackList) +{ + unsigned lastScale = 8, nextScale = 8; + const int *list; + unsigned i; + + /* (pic|seq)_scaling_list_present_flag[i] */ + if (!vl_rbsp_u(rbsp, 1)) { + if (fallbackList) + memcpy(scalingList, fallbackList, sizeOfScalingList); + return; + } + + list = (sizeOfScalingList == 16) ? vl_zscan_normal_16 : vl_zscan_normal; + for (i = 0; i < sizeOfScalingList; ++i ) { + + if (nextScale != 0) { + signed delta_scale = vl_rbsp_se(rbsp); + nextScale = (lastScale + delta_scale + 256) % 256; + if (i == 0 && nextScale == 0) { + memcpy(scalingList, defaultList, sizeOfScalingList); + return; + } + } + scalingList[list[i]] = nextScale == 0 ? lastScale : nextScale; + lastScale = scalingList[list[i]]; + } +} + +static struct pipe_h264_sps *seq_parameter_set_id(vid_dec_PrivateType *priv, struct vl_rbsp *rbsp) +{ + unsigned id = vl_rbsp_ue(rbsp); + if (id >= ARRAY_SIZE(priv->codec_data.h264.sps)) + return NULL; /* invalid seq_parameter_set_id */ + + return &priv->codec_data.h264.sps[id]; +} + +static void seq_parameter_set(vid_dec_PrivateType *priv, struct vl_rbsp *rbsp) +{ + struct pipe_h264_sps *sps; + unsigned profile_idc, level_idc; + unsigned i; + + /* Sequence parameter set */ + profile_idc = vl_rbsp_u(rbsp, 8); + + /* constraint_set0_flag */ + vl_rbsp_u(rbsp, 1); + + /* constraint_set1_flag */ + vl_rbsp_u(rbsp, 1); + + /* constraint_set2_flag */ + vl_rbsp_u(rbsp, 1); + + /* constraint_set3_flag */ + vl_rbsp_u(rbsp, 1); + + /* constraint_set4_flag */ + vl_rbsp_u(rbsp, 1); + + /* constraint_set5_flag */ + vl_rbsp_u(rbsp, 1); + + /* reserved_zero_2bits */ + vl_rbsp_u(rbsp, 2); + + /* level_idc */ + level_idc = vl_rbsp_u(rbsp, 8); + + sps = seq_parameter_set_id(priv, rbsp); + if (!sps) + return; + + memset(sps, 0, sizeof(*sps)); + memset(sps->ScalingList4x4, 16, sizeof(sps->ScalingList4x4)); + memset(sps->ScalingList8x8, 16, sizeof(sps->ScalingList8x8)); + + sps->level_idc = level_idc; + + if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 244 || + profile_idc == 44 || profile_idc == 83 || profile_idc == 86 || profile_idc == 118 || + profile_idc == 128 || profile_idc == 138) { + + sps->chroma_format_idc = vl_rbsp_ue(rbsp); + + if (sps->chroma_format_idc == 3) + sps->separate_colour_plane_flag = vl_rbsp_u(rbsp, 1); + + sps->bit_depth_luma_minus8 = vl_rbsp_ue(rbsp); + + sps->bit_depth_chroma_minus8 = vl_rbsp_ue(rbsp); + + /* qpprime_y_zero_transform_bypass_flag */ + vl_rbsp_u(rbsp, 1); + + sps->seq_scaling_matrix_present_flag = vl_rbsp_u(rbsp, 1); + if (sps->seq_scaling_matrix_present_flag) { + + scaling_list(rbsp, sps->ScalingList4x4[0], 16, Default_4x4_Intra, Default_4x4_Intra); + scaling_list(rbsp, sps->ScalingList4x4[1], 16, Default_4x4_Intra, sps->ScalingList4x4[0]); + scaling_list(rbsp, sps->ScalingList4x4[2], 16, Default_4x4_Intra, sps->ScalingList4x4[1]); + scaling_list(rbsp, sps->ScalingList4x4[3], 16, Default_4x4_Inter, Default_4x4_Inter); + scaling_list(rbsp, sps->ScalingList4x4[4], 16, Default_4x4_Inter, sps->ScalingList4x4[3]); + scaling_list(rbsp, sps->ScalingList4x4[5], 16, Default_4x4_Inter, sps->ScalingList4x4[4]); + + scaling_list(rbsp, sps->ScalingList8x8[0], 64, Default_8x8_Intra, Default_8x8_Intra); + scaling_list(rbsp, sps->ScalingList8x8[1], 64, Default_8x8_Inter, Default_8x8_Inter); + if (sps->chroma_format_idc == 3) { + scaling_list(rbsp, sps->ScalingList8x8[2], 64, Default_8x8_Intra, sps->ScalingList8x8[0]); + scaling_list(rbsp, sps->ScalingList8x8[3], 64, Default_8x8_Inter, sps->ScalingList8x8[1]); + scaling_list(rbsp, sps->ScalingList8x8[4], 64, Default_8x8_Intra, sps->ScalingList8x8[2]); + scaling_list(rbsp, sps->ScalingList8x8[5], 64, Default_8x8_Inter, sps->ScalingList8x8[3]); + } + } + } else if (profile_idc == 183) + sps->chroma_format_idc = 0; + else + sps->chroma_format_idc = 1; + + sps->log2_max_frame_num_minus4 = vl_rbsp_ue(rbsp); + + sps->pic_order_cnt_type = vl_rbsp_ue(rbsp); + + if (sps->pic_order_cnt_type == 0) + sps->log2_max_pic_order_cnt_lsb_minus4 = vl_rbsp_ue(rbsp); + else if (sps->pic_order_cnt_type == 1) { + sps->delta_pic_order_always_zero_flag = vl_rbsp_u(rbsp, 1); + + sps->offset_for_non_ref_pic = vl_rbsp_se(rbsp); + + sps->offset_for_top_to_bottom_field = vl_rbsp_se(rbsp); + + sps->num_ref_frames_in_pic_order_cnt_cycle = vl_rbsp_ue(rbsp); + + for (i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; ++i) + sps->offset_for_ref_frame[i] = vl_rbsp_se(rbsp); + } + + sps->max_num_ref_frames = vl_rbsp_ue(rbsp); + + /* gaps_in_frame_num_value_allowed_flag */ + vl_rbsp_u(rbsp, 1); + + /* pic_width_in_mbs_minus1 */ + vl_rbsp_ue(rbsp); + + /* pic_height_in_map_units_minus1 */ + vl_rbsp_ue(rbsp); + + sps->frame_mbs_only_flag = vl_rbsp_u(rbsp, 1); + if (!sps->frame_mbs_only_flag) + sps->mb_adaptive_frame_field_flag = vl_rbsp_u(rbsp, 1); + + sps->direct_8x8_inference_flag = vl_rbsp_u(rbsp, 1); + + /* frame_cropping_flag */ + if (vl_rbsp_u(rbsp, 1)) { + /* frame_crop_left_offset */ + vl_rbsp_ue(rbsp); + + /* frame_crop_right_offset */ + vl_rbsp_ue(rbsp); + + /* frame_crop_top_offset */ + vl_rbsp_ue(rbsp); + + /* frame_crop_bottom_offset */ + vl_rbsp_ue(rbsp); + } + + /* vui_parameters_present_flag */ + if (vl_rbsp_u(rbsp, 1)) + vui_parameters(rbsp); +} + +static struct pipe_h264_pps *pic_parameter_set_id(vid_dec_PrivateType *priv, struct vl_rbsp *rbsp) +{ + unsigned id = vl_rbsp_ue(rbsp); + if (id >= ARRAY_SIZE(priv->codec_data.h264.pps)) + return NULL; /* invalid pic_parameter_set_id */ + + return &priv->codec_data.h264.pps[id]; +} + +static void picture_parameter_set(vid_dec_PrivateType *priv, struct vl_rbsp *rbsp) +{ + struct pipe_h264_sps *sps; + struct pipe_h264_pps *pps; + unsigned i; + + pps = pic_parameter_set_id(priv, rbsp); + if (!pps) + return; + + memset(pps, 0, sizeof(*pps)); + + sps = pps->sps = seq_parameter_set_id(priv, rbsp); + if (!sps) + return; + + memcpy(pps->ScalingList4x4, sps->ScalingList4x4, sizeof(pps->ScalingList4x4)); + memcpy(pps->ScalingList8x8, sps->ScalingList8x8, sizeof(pps->ScalingList8x8)); + + pps->entropy_coding_mode_flag = vl_rbsp_u(rbsp, 1); + + pps->bottom_field_pic_order_in_frame_present_flag = vl_rbsp_u(rbsp, 1); + + pps->num_slice_groups_minus1 = vl_rbsp_ue(rbsp); + if (pps->num_slice_groups_minus1 > 0) { + pps->slice_group_map_type = vl_rbsp_ue(rbsp); + + if (pps->slice_group_map_type == 0) { + + for (i = 0; i <= pps->num_slice_groups_minus1; ++i) + /* run_length_minus1[i] */ + vl_rbsp_ue(rbsp); + + } else if (pps->slice_group_map_type == 2) { + + for (i = 0; i <= pps->num_slice_groups_minus1; ++i) { + /* top_left[i] */ + vl_rbsp_ue(rbsp); + + /* bottom_right[i] */ + vl_rbsp_ue(rbsp); + } + + } else if (pps->slice_group_map_type >= 3 && pps->slice_group_map_type <= 5) { + + /* slice_group_change_direction_flag */ + vl_rbsp_u(rbsp, 1); + + pps->slice_group_change_rate_minus1 = vl_rbsp_ue(rbsp); + + } else if (pps->slice_group_map_type == 6) { + + unsigned pic_size_in_map_units_minus1; + + pic_size_in_map_units_minus1 = vl_rbsp_ue(rbsp); + + for (i = 0; i <= pic_size_in_map_units_minus1; ++i) + /* slice_group_id[i] */ + vl_rbsp_u(rbsp, log2(pps->num_slice_groups_minus1 + 1)); + } + } + + pps->num_ref_idx_l0_default_active_minus1 = vl_rbsp_ue(rbsp); + + pps->num_ref_idx_l1_default_active_minus1 = vl_rbsp_ue(rbsp); + + pps->weighted_pred_flag = vl_rbsp_u(rbsp, 1); + + pps->weighted_bipred_idc = vl_rbsp_u(rbsp, 2); + + pps->pic_init_qp_minus26 = vl_rbsp_se(rbsp); + + /* pic_init_qs_minus26 */ + vl_rbsp_se(rbsp); + + pps->chroma_qp_index_offset = vl_rbsp_se(rbsp); + + pps->deblocking_filter_control_present_flag = vl_rbsp_u(rbsp, 1); + + pps->constrained_intra_pred_flag = vl_rbsp_u(rbsp, 1); + + pps->redundant_pic_cnt_present_flag = vl_rbsp_u(rbsp, 1); + + if (vl_rbsp_more_data(rbsp)) { + pps->transform_8x8_mode_flag = vl_rbsp_u(rbsp, 1); + + /* pic_scaling_matrix_present_flag */ + if (vl_rbsp_u(rbsp, 1)) { + + scaling_list(rbsp, pps->ScalingList4x4[0], 16, Default_4x4_Intra, + sps->seq_scaling_matrix_present_flag ? NULL : Default_4x4_Intra); + scaling_list(rbsp, pps->ScalingList4x4[1], 16, Default_4x4_Intra, pps->ScalingList4x4[0]); + scaling_list(rbsp, pps->ScalingList4x4[2], 16, Default_4x4_Intra, pps->ScalingList4x4[1]); + scaling_list(rbsp, pps->ScalingList4x4[3], 16, Default_4x4_Inter, + sps->seq_scaling_matrix_present_flag ? NULL : Default_4x4_Inter); + scaling_list(rbsp, pps->ScalingList4x4[4], 16, Default_4x4_Inter, pps->ScalingList4x4[3]); + scaling_list(rbsp, pps->ScalingList4x4[5], 16, Default_4x4_Inter, pps->ScalingList4x4[4]); + + if (pps->transform_8x8_mode_flag) { + scaling_list(rbsp, pps->ScalingList8x8[0], 64, Default_8x8_Intra, + sps->seq_scaling_matrix_present_flag ? NULL : Default_8x8_Intra); + scaling_list(rbsp, pps->ScalingList8x8[1], 64, Default_8x8_Inter, + sps->seq_scaling_matrix_present_flag ? NULL : Default_8x8_Inter); + if (sps->chroma_format_idc == 3) { + scaling_list(rbsp, pps->ScalingList8x8[2], 64, Default_8x8_Intra, pps->ScalingList8x8[0]); + scaling_list(rbsp, pps->ScalingList8x8[3], 64, Default_8x8_Inter, pps->ScalingList8x8[1]); + scaling_list(rbsp, pps->ScalingList8x8[4], 64, Default_8x8_Intra, pps->ScalingList8x8[2]); + scaling_list(rbsp, pps->ScalingList8x8[5], 64, Default_8x8_Inter, pps->ScalingList8x8[3]); + } + } + } + + pps->second_chroma_qp_index_offset = vl_rbsp_se(rbsp); + } +} + +static void ref_pic_list_mvc_modification(vid_dec_PrivateType *priv, struct vl_rbsp *rbsp) +{ + // TODO + assert(0); +} + +static void ref_pic_list_modification(vid_dec_PrivateType *priv, struct vl_rbsp *rbsp, + enum pipe_h264_slice_type slice_type) +{ + unsigned modification_of_pic_nums_idc; + + if (slice_type != 2 && slice_type != 4) { + /* ref_pic_list_modification_flag_l0 */ + if (vl_rbsp_u(rbsp, 1)) { + do { + modification_of_pic_nums_idc = vl_rbsp_ue(rbsp); + if (modification_of_pic_nums_idc == 0 || + modification_of_pic_nums_idc == 1) + /* abs_diff_pic_num_minus1 */ + vl_rbsp_ue(rbsp); + else if (modification_of_pic_nums_idc == 2) + /* long_term_pic_num */ + vl_rbsp_ue(rbsp); + } while (modification_of_pic_nums_idc != 3); + } + } + + if (slice_type == 1) { + /* ref_pic_list_modification_flag_l1 */ + if (vl_rbsp_u(rbsp, 1)) { + do { + modification_of_pic_nums_idc = vl_rbsp_ue(rbsp); + if (modification_of_pic_nums_idc == 0 || + modification_of_pic_nums_idc == 1) + /* abs_diff_pic_num_minus1 */ + vl_rbsp_ue(rbsp); + else if (modification_of_pic_nums_idc == 2) + /* long_term_pic_num */ + vl_rbsp_ue(rbsp); + } while (modification_of_pic_nums_idc != 3); + } + } +} + +static void pred_weight_table(vid_dec_PrivateType *priv, struct vl_rbsp *rbsp, + struct pipe_h264_sps *sps, enum pipe_h264_slice_type slice_type) +{ + unsigned ChromaArrayType = sps->separate_colour_plane_flag ? 0 : sps->chroma_format_idc; + unsigned i, j; + + /* luma_log2_weight_denom */ + vl_rbsp_ue(rbsp); + + if (ChromaArrayType != 0) + /* chroma_log2_weight_denom */ + vl_rbsp_ue(rbsp); + + for (i = 0; i <= priv->picture.h264.num_ref_idx_l0_active_minus1; ++i) { + /* luma_weight_l0_flag */ + if (vl_rbsp_u(rbsp, 1)) { + /* luma_weight_l0[i] */ + vl_rbsp_se(rbsp); + /* luma_offset_l0[i] */ + vl_rbsp_se(rbsp); + } + if (ChromaArrayType != 0) { + /* chroma_weight_l0_flag */ + if (vl_rbsp_u(rbsp, 1)) { + for (j = 0; j < 2; ++j) { + /* chroma_weight_l0[i][j] */ + vl_rbsp_se(rbsp); + /* chroma_offset_l0[i][j] */ + vl_rbsp_se(rbsp); + } + } + } + } + + if (slice_type == 1) { + for (i = 0; i <= priv->picture.h264.num_ref_idx_l1_active_minus1; ++i) { + /* luma_weight_l1_flag */ + if (vl_rbsp_u(rbsp, 1)) { + /* luma_weight_l1[i] */ + vl_rbsp_se(rbsp); + /* luma_offset_l1[i] */ + vl_rbsp_se(rbsp); + } + if (ChromaArrayType != 0) { + /* chroma_weight_l1_flag */ + if (vl_rbsp_u(rbsp, 1)) { + for (j = 0; j < 2; ++j) { + /* chroma_weight_l1[i][j] */ + vl_rbsp_se(rbsp); + /* chroma_offset_l1[i][j] */ + vl_rbsp_se(rbsp); + } + } + } + } + } +} + +static void dec_ref_pic_marking(vid_dec_PrivateType *priv, struct vl_rbsp *rbsp, + bool IdrPicFlag) +{ + unsigned memory_management_control_operation; + + if (IdrPicFlag) { + /* no_output_of_prior_pics_flag */ + vl_rbsp_u(rbsp, 1); + /* long_term_reference_flag */ + vl_rbsp_u(rbsp, 1); + } else { + /* adaptive_ref_pic_marking_mode_flag */ + if (vl_rbsp_u(rbsp, 1)) { + do { + memory_management_control_operation = vl_rbsp_ue(rbsp); + + if (memory_management_control_operation == 1 || + memory_management_control_operation == 3) + /* difference_of_pic_nums_minus1 */ + vl_rbsp_ue(rbsp); + + if (memory_management_control_operation == 2) + /* long_term_pic_num */ + vl_rbsp_ue(rbsp); + + if (memory_management_control_operation == 3 || + memory_management_control_operation == 6) + /* long_term_frame_idx */ + vl_rbsp_ue(rbsp); + + if (memory_management_control_operation == 4) + /* max_long_term_frame_idx_plus1 */ + vl_rbsp_ue(rbsp); + } while (memory_management_control_operation != 0); + } + } +} + +static void slice_header(vid_dec_PrivateType *priv, struct vl_rbsp *rbsp, + unsigned nal_ref_idc, unsigned nal_unit_type) +{ + enum pipe_h264_slice_type slice_type; + struct pipe_h264_pps *pps; + struct pipe_h264_sps *sps; + unsigned frame_num, prevFrameNum; + bool IdrPicFlag = nal_unit_type == 5; + + if (IdrPicFlag != priv->codec_data.h264.IdrPicFlag) + vid_dec_h264_EndFrame(priv); + + priv->codec_data.h264.IdrPicFlag = IdrPicFlag; + + /* first_mb_in_slice */ + vl_rbsp_ue(rbsp); + + slice_type = vl_rbsp_ue(rbsp) % 5; + + pps = pic_parameter_set_id(priv, rbsp); + if (!pps) + return; + + sps = pps->sps; + if (!sps) + return; + + if (pps != priv->picture.h264.pps) + vid_dec_h264_EndFrame(priv); + + priv->picture.h264.pps = pps; + + if (sps->separate_colour_plane_flag == 1 ) + /* colour_plane_id */ + vl_rbsp_u(rbsp, 2); + + frame_num = vl_rbsp_u(rbsp, sps->log2_max_frame_num_minus4 + 4); + + if (frame_num != priv->picture.h264.frame_num) + vid_dec_h264_EndFrame(priv); + + prevFrameNum = priv->picture.h264.frame_num; + priv->picture.h264.frame_num = frame_num; + + priv->picture.h264.field_pic_flag = 0; + priv->picture.h264.bottom_field_flag = 0; + + if (!sps->frame_mbs_only_flag) { + unsigned field_pic_flag = vl_rbsp_u(rbsp, 1); + + if (!field_pic_flag && field_pic_flag != priv->picture.h264.field_pic_flag) + vid_dec_h264_EndFrame(priv); + + priv->picture.h264.field_pic_flag = field_pic_flag; + + if (priv->picture.h264.field_pic_flag) { + unsigned bottom_field_flag = vl_rbsp_u(rbsp, 1); + + if (bottom_field_flag != priv->picture.h264.bottom_field_flag) + vid_dec_h264_EndFrame(priv); + + priv->picture.h264.bottom_field_flag = bottom_field_flag; + } + } + + if (IdrPicFlag) { + unsigned idr_pic_id = vl_rbsp_ue(rbsp); + + if (idr_pic_id != priv->codec_data.h264.idr_pic_id) + vid_dec_h264_EndFrame(priv); + + priv->codec_data.h264.idr_pic_id = idr_pic_id; + } + + if (sps->pic_order_cnt_type == 0) { + unsigned log2_max_pic_order_cnt_lsb = sps->log2_max_pic_order_cnt_lsb_minus4 + 4; + unsigned max_pic_order_cnt_lsb = 1 << log2_max_pic_order_cnt_lsb; + int pic_order_cnt_lsb = vl_rbsp_u(rbsp, log2_max_pic_order_cnt_lsb); + int pic_order_cnt_msb; + + if (pic_order_cnt_lsb != priv->codec_data.h264.pic_order_cnt_lsb) + vid_dec_h264_EndFrame(priv); + + if (IdrPicFlag) { + priv->codec_data.h264.pic_order_cnt_msb = 0; + priv->codec_data.h264.pic_order_cnt_lsb = 0; + } + + if ((pic_order_cnt_lsb < priv->codec_data.h264.pic_order_cnt_lsb) && + (priv->codec_data.h264.pic_order_cnt_lsb - pic_order_cnt_lsb) >= (max_pic_order_cnt_lsb / 2)) + pic_order_cnt_msb = priv->codec_data.h264.pic_order_cnt_msb + max_pic_order_cnt_lsb; + + else if ((pic_order_cnt_lsb > priv->codec_data.h264.pic_order_cnt_lsb) && + (pic_order_cnt_lsb - priv->codec_data.h264.pic_order_cnt_lsb) > (max_pic_order_cnt_lsb / 2)) + pic_order_cnt_msb = priv->codec_data.h264.pic_order_cnt_msb - max_pic_order_cnt_lsb; + + else + pic_order_cnt_msb = priv->codec_data.h264.pic_order_cnt_msb; + + priv->codec_data.h264.pic_order_cnt_msb = pic_order_cnt_msb; + priv->codec_data.h264.pic_order_cnt_lsb = pic_order_cnt_lsb; + + if (pps->bottom_field_pic_order_in_frame_present_flag && !priv->picture.h264.field_pic_flag) { + unsigned delta_pic_order_cnt_bottom = vl_rbsp_se(rbsp); + + if (delta_pic_order_cnt_bottom != priv->codec_data.h264.delta_pic_order_cnt_bottom) + vid_dec_h264_EndFrame(priv); + + priv->codec_data.h264.delta_pic_order_cnt_bottom = delta_pic_order_cnt_bottom; + } + + if (!priv->picture.h264.field_pic_flag) { + priv->picture.h264.field_order_cnt[0] = pic_order_cnt_msb + pic_order_cnt_lsb; + priv->picture.h264.field_order_cnt[1] = priv->picture.h264.field_order_cnt [0] + + priv->codec_data.h264.delta_pic_order_cnt_bottom; + } else if (!priv->picture.h264.bottom_field_flag) + priv->picture.h264.field_order_cnt[0] = pic_order_cnt_msb + pic_order_cnt_lsb; + else + priv->picture.h264.field_order_cnt[1] = pic_order_cnt_msb + pic_order_cnt_lsb; + + } else if (sps->pic_order_cnt_type == 1) { + unsigned MaxFrameNum = 1 << (sps->log2_max_frame_num_minus4 + 4); + unsigned FrameNumOffset, absFrameNum, expectedPicOrderCnt; + + if (!sps->delta_pic_order_always_zero_flag) { + unsigned delta_pic_order_cnt[2]; + + delta_pic_order_cnt[0] = vl_rbsp_se(rbsp); + + if (delta_pic_order_cnt[0] != priv->codec_data.h264.delta_pic_order_cnt[0]) + vid_dec_h264_EndFrame(priv); + + priv->codec_data.h264.delta_pic_order_cnt[0] = delta_pic_order_cnt[0]; + + if (pps->bottom_field_pic_order_in_frame_present_flag && !priv->picture.h264.field_pic_flag) { + delta_pic_order_cnt[1] = vl_rbsp_se(rbsp); + + if (delta_pic_order_cnt[1] != priv->codec_data.h264.delta_pic_order_cnt[1]) + vid_dec_h264_EndFrame(priv); + + priv->codec_data.h264.delta_pic_order_cnt[1] = delta_pic_order_cnt[1]; + } + } + + if (IdrPicFlag) + FrameNumOffset = 0; + else if (prevFrameNum > frame_num) + FrameNumOffset = priv->codec_data.h264.prevFrameNumOffset + MaxFrameNum; + else + FrameNumOffset = priv->codec_data.h264.prevFrameNumOffset; + + priv->codec_data.h264.prevFrameNumOffset = FrameNumOffset; + + if (sps->num_ref_frames_in_pic_order_cnt_cycle != 0) + absFrameNum = FrameNumOffset + frame_num; + else + absFrameNum = 0; + + if (nal_ref_idc == 0 && absFrameNum > 0) + absFrameNum = absFrameNum - 1; + + if (absFrameNum > 0) { + unsigned picOrderCntCycleCnt = (absFrameNum - 1) / sps->num_ref_frames_in_pic_order_cnt_cycle; + unsigned frameNumInPicOrderCntCycle = (absFrameNum - 1) % sps->num_ref_frames_in_pic_order_cnt_cycle; + signed ExpectedDeltaPerPicOrderCntCycle = 0; + unsigned i; + + for (i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; ++i) + ExpectedDeltaPerPicOrderCntCycle += sps->offset_for_ref_frame[i]; + + expectedPicOrderCnt = picOrderCntCycleCnt * ExpectedDeltaPerPicOrderCntCycle; + for (i = 0; i <= frameNumInPicOrderCntCycle; ++i) + expectedPicOrderCnt += sps->offset_for_ref_frame[i]; + + } else + expectedPicOrderCnt = 0; + + if (nal_ref_idc == 0) + expectedPicOrderCnt += sps->offset_for_non_ref_pic; + + if (!priv->picture.h264.field_pic_flag) { + priv->picture.h264.field_order_cnt[0] = expectedPicOrderCnt + priv->codec_data.h264.delta_pic_order_cnt[0]; + priv->picture.h264.field_order_cnt[1] = priv->picture.h264.field_order_cnt[0] + + sps->offset_for_top_to_bottom_field + priv->codec_data.h264.delta_pic_order_cnt[1]; + + } else if (!priv->picture.h264.bottom_field_flag) + priv->picture.h264.field_order_cnt[0] = expectedPicOrderCnt + priv->codec_data.h264.delta_pic_order_cnt[0]; + else + priv->picture.h264.field_order_cnt[1] = expectedPicOrderCnt + sps->offset_for_top_to_bottom_field + + priv->codec_data.h264.delta_pic_order_cnt[0]; + + } else if (sps->pic_order_cnt_type == 2) { + unsigned MaxFrameNum = 1 << (sps->log2_max_frame_num_minus4 + 4); + unsigned FrameNumOffset, tempPicOrderCnt; + + if (IdrPicFlag) + FrameNumOffset = 0; + else if (prevFrameNum > frame_num) + FrameNumOffset = priv->codec_data.h264.prevFrameNumOffset + MaxFrameNum; + else + FrameNumOffset = priv->codec_data.h264.prevFrameNumOffset; + + priv->codec_data.h264.prevFrameNumOffset = FrameNumOffset; + + if (IdrPicFlag) + tempPicOrderCnt = 0; + else if (nal_ref_idc == 0) + tempPicOrderCnt = 2 * (FrameNumOffset + frame_num) - 1; + else + tempPicOrderCnt = 2 * (FrameNumOffset + frame_num); + + if (!priv->picture.h264.field_pic_flag) { + priv->picture.h264.field_order_cnt[0] = tempPicOrderCnt; + priv->picture.h264.field_order_cnt[1] = tempPicOrderCnt; + + } else if (!priv->picture.h264.bottom_field_flag) + priv->picture.h264.field_order_cnt[0] = tempPicOrderCnt; + else + priv->picture.h264.field_order_cnt[1] = tempPicOrderCnt; + } + + if (pps->redundant_pic_cnt_present_flag) + /* redundant_pic_cnt */ + vl_rbsp_ue(rbsp); + + if (slice_type == PIPE_H264_SLICE_TYPE_B) + /* direct_spatial_mv_pred_flag */ + vl_rbsp_u(rbsp, 1); + + priv->picture.h264.num_ref_idx_l0_active_minus1 = pps->num_ref_idx_l0_default_active_minus1; + priv->picture.h264.num_ref_idx_l1_active_minus1 = pps->num_ref_idx_l1_default_active_minus1; + + if (slice_type == PIPE_H264_SLICE_TYPE_P || + slice_type == PIPE_H264_SLICE_TYPE_SP || + slice_type == PIPE_H264_SLICE_TYPE_B) { + + /* num_ref_idx_active_override_flag */ + if (vl_rbsp_u(rbsp, 1)) { + priv->picture.h264.num_ref_idx_l0_active_minus1 = vl_rbsp_ue(rbsp); + + if (slice_type == PIPE_H264_SLICE_TYPE_B) + priv->picture.h264.num_ref_idx_l1_active_minus1 = vl_rbsp_ue(rbsp); + } + } + + if (nal_unit_type == 20 || nal_unit_type == 21) + ref_pic_list_mvc_modification(priv, rbsp); + else + ref_pic_list_modification(priv, rbsp, slice_type); + + if ((pps->weighted_pred_flag && (slice_type == PIPE_H264_SLICE_TYPE_P || slice_type == PIPE_H264_SLICE_TYPE_SP)) || + (pps->weighted_bipred_idc == 1 && slice_type == PIPE_H264_SLICE_TYPE_B)) + pred_weight_table(priv, rbsp, sps, slice_type); + + if (nal_ref_idc != 0) + dec_ref_pic_marking(priv, rbsp, IdrPicFlag); + + if (pps->entropy_coding_mode_flag && slice_type != PIPE_H264_SLICE_TYPE_I && slice_type != PIPE_H264_SLICE_TYPE_SI) + /* cabac_init_idc */ + vl_rbsp_ue(rbsp); + + /* slice_qp_delta */ + vl_rbsp_se(rbsp); + + if (slice_type == PIPE_H264_SLICE_TYPE_SP || slice_type == PIPE_H264_SLICE_TYPE_SI) { + if (slice_type == PIPE_H264_SLICE_TYPE_SP) + /* sp_for_switch_flag */ + vl_rbsp_u(rbsp, 1); + + /*slice_qs_delta */ + vl_rbsp_se(rbsp); + } + + if (pps->deblocking_filter_control_present_flag) { + unsigned disable_deblocking_filter_idc = vl_rbsp_ue(rbsp); + + if (disable_deblocking_filter_idc != 1) { + /* slice_alpha_c0_offset_div2 */ + vl_rbsp_se(rbsp); + + /* slice_beta_offset_div2 */ + vl_rbsp_se(rbsp); + } + } + + if (pps->num_slice_groups_minus1 > 0 && pps->slice_group_map_type >= 3 && pps->slice_group_map_type <= 5) + /* slice_group_change_cycle */ + vl_rbsp_u(rbsp, 2); +} + +static void vid_dec_h264_Decode(vid_dec_PrivateType *priv, struct vl_vlc *vlc, unsigned min_bits_left) +{ + unsigned nal_ref_idc, nal_unit_type; + + if (!vl_vlc_search_byte(vlc, vl_vlc_bits_left(vlc) - min_bits_left, 0x00)) + return; + + if (vl_vlc_peekbits(vlc, 24) != 0x000001) { + vl_vlc_eatbits(vlc, 8); + return; + } + + if (priv->slice) { + unsigned bytes = priv->bytes_left - (vl_vlc_bits_left(vlc) / 8); + ++priv->picture.h264.slice_count; + priv->codec->decode_bitstream(priv->codec, priv->target, &priv->picture.base, + 1, &priv->slice, &bytes); + priv->slice = NULL; + } + + vl_vlc_eatbits(vlc, 24); + + /* forbidden_zero_bit */ + vl_vlc_eatbits(vlc, 1); + + nal_ref_idc = vl_vlc_get_uimsbf(vlc, 2); + + if (nal_ref_idc != priv->codec_data.h264.nal_ref_idc && + (nal_ref_idc * priv->codec_data.h264.nal_ref_idc) == 0) + vid_dec_h264_EndFrame(priv); + + priv->codec_data.h264.nal_ref_idc = nal_ref_idc; + + nal_unit_type = vl_vlc_get_uimsbf(vlc, 5); + + if (nal_unit_type != 1 && nal_unit_type != 5) + vid_dec_h264_EndFrame(priv); + + if (nal_unit_type == 7) { + struct vl_rbsp rbsp; + vl_rbsp_init(&rbsp, vlc, ~0); + seq_parameter_set(priv, &rbsp); + + } else if (nal_unit_type == 8) { + struct vl_rbsp rbsp; + vl_rbsp_init(&rbsp, vlc, ~0); + picture_parameter_set(priv, &rbsp); + + } else if (nal_unit_type == 1 || nal_unit_type == 5) { + /* Coded slice of a non-IDR or IDR picture */ + unsigned bits = vl_vlc_valid_bits(vlc); + unsigned bytes = bits / 8 + 4; + struct vl_rbsp rbsp; + uint8_t buf[8]; + const void *ptr = buf; + unsigned i; + + buf[0] = 0x0; + buf[1] = 0x0; + buf[2] = 0x1; + buf[3] = (nal_ref_idc << 5) | nal_unit_type; + for (i = 4; i < bytes; ++i) + buf[i] = vl_vlc_peekbits(vlc, bits) >> ((bytes - i - 1) * 8); + + priv->bytes_left = (vl_vlc_bits_left(vlc) - bits) / 8; + priv->slice = vlc->data; + + vl_rbsp_init(&rbsp, vlc, 128); + slice_header(priv, &rbsp, nal_ref_idc, nal_unit_type); + + vid_dec_h264_BeginFrame(priv); + + ++priv->picture.h264.slice_count; + priv->codec->decode_bitstream(priv->codec, priv->target, &priv->picture.base, + 1, &ptr, &bytes); + } + + /* resync to byte boundary */ + vl_vlc_eatbits(vlc, vl_vlc_valid_bits(vlc) % 8); +} diff --git a/src/gallium/state_trackers/omx/bellagio/vid_dec_h265.c b/src/gallium/state_trackers/omx/bellagio/vid_dec_h265.c new file mode 100644 index 00000000000..3242dbe11c8 --- /dev/null +++ b/src/gallium/state_trackers/omx/bellagio/vid_dec_h265.c @@ -0,0 +1,1013 @@ +/************************************************************************** + * + * Copyright 2016 Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "pipe/p_video_codec.h" +#include "util/u_memory.h" +#include "util/u_video.h" +#include "vl/vl_rbsp.h" + +#include "entrypoint.h" +#include "vid_dec.h" + +#define DPB_MAX_SIZE 32 +#define MAX_NUM_REF_PICS 16 + +enum { + NAL_UNIT_TYPE_TRAIL_N = 0, + NAL_UNIT_TYPE_TRAIL_R = 1, + NAL_UNIT_TYPE_TSA_N = 2, + NAL_UNIT_TYPE_TSA_R = 3, + NAL_UNIT_TYPE_STSA_N = 4, + NAL_UNIT_TYPE_STSA_R = 5, + NAL_UNIT_TYPE_RADL_N = 6, + NAL_UNIT_TYPE_RADL_R = 7, + NAL_UNIT_TYPE_RASL_N = 8, + NAL_UNIT_TYPE_RASL_R = 9, + NAL_UNIT_TYPE_BLA_W_LP = 16, + NAL_UNIT_TYPE_BLA_W_RADL = 17, + NAL_UNIT_TYPE_BLA_N_LP = 18, + NAL_UNIT_TYPE_IDR_W_RADL = 19, + NAL_UNIT_TYPE_IDR_N_LP = 20, + NAL_UNIT_TYPE_CRA = 21, + NAL_UNIT_TYPE_SPS = 33, + NAL_UNIT_TYPE_PPS = 34, +}; + +static const uint8_t Default_8x8_Intra[64] = { + 16, 16, 16, 16, 17, 18, 21, 24, + 16, 16, 16, 16, 17, 19, 22, 25, + 16, 16, 17, 18, 20, 22, 25, 29, + 16, 16, 18, 21, 24, 27, 31, 36, + 17, 17, 20, 24, 30, 35, 41, 47, + 18, 19, 22, 27, 35, 44, 54, 65, + 21, 22, 25, 31, 41, 54, 70, 88, + 24, 25, 29, 36, 47, 65, 88, 115 +}; + +static const uint8_t Default_8x8_Inter[64] = { + 16, 16, 16, 16, 17, 18, 20, 24, + 16, 16, 16, 17, 18, 20, 24, 25, + 16, 16, 17, 18, 20, 24, 25, 28, + 16, 17, 18, 20, 24, 25, 28, 33, + 17, 18, 20, 24, 25, 28, 33, 41, + 18, 20, 24, 25, 28, 33, 41, 54, + 20, 24, 25, 28, 33, 41, 54, 71, + 24, 25, 28, 33, 41, 54, 71, 91 +}; + +struct dpb_list { + struct list_head list; + struct pipe_video_buffer *buffer; + OMX_TICKS timestamp; + unsigned poc; +}; + +struct ref_pic_set { + unsigned num_pics; + unsigned num_neg_pics; + unsigned num_pos_pics; + unsigned num_delta_poc; + int delta_poc[MAX_NUM_REF_PICS]; + bool used[MAX_NUM_REF_PICS]; +}; + +static bool is_idr_picture(unsigned nal_unit_type) +{ + return (nal_unit_type == NAL_UNIT_TYPE_IDR_W_RADL || + nal_unit_type == NAL_UNIT_TYPE_IDR_N_LP); +} + +/* broken link access picture */ +static bool is_bla_picture(unsigned nal_unit_type) +{ + return (nal_unit_type == NAL_UNIT_TYPE_BLA_W_LP || + nal_unit_type == NAL_UNIT_TYPE_BLA_W_RADL || + nal_unit_type == NAL_UNIT_TYPE_BLA_N_LP); +} + +/* random access point picture */ +static bool is_rap_picture(unsigned nal_unit_type) +{ + return (nal_unit_type >= NAL_UNIT_TYPE_BLA_W_LP && + nal_unit_type <= NAL_UNIT_TYPE_CRA); +} + +static bool is_slice_picture(unsigned nal_unit_type) +{ + return (nal_unit_type <= NAL_UNIT_TYPE_RASL_R || + is_rap_picture(nal_unit_type)); +} + +static void set_poc(vid_dec_PrivateType *priv, + unsigned nal_unit_type, int i) +{ + priv->picture.h265.CurrPicOrderCntVal = i; + + if (priv->codec_data.h265.temporal_id == 0 && + (nal_unit_type == NAL_UNIT_TYPE_TRAIL_R || + nal_unit_type == NAL_UNIT_TYPE_TSA_R || + nal_unit_type == NAL_UNIT_TYPE_STSA_R || + is_rap_picture(nal_unit_type))) + priv->codec_data.h265.slice_prev_poc = i; +} + +static unsigned get_poc(vid_dec_PrivateType *priv) +{ + return priv->picture.h265.CurrPicOrderCntVal; +} + +static void profile_tier(struct vl_rbsp *rbsp) +{ + int i; + + /* general_profile_space */ + vl_rbsp_u(rbsp, 2); + + /* general_tier_flag */ + vl_rbsp_u(rbsp, 1); + + /* general_profile_idc */ + vl_rbsp_u(rbsp, 5); + + /* general_profile_compatibility_flag */ + for(i = 0; i < 32; ++i) + vl_rbsp_u(rbsp, 1); + + /* general_progressive_source_flag */ + vl_rbsp_u(rbsp, 1); + + /* general_interlaced_source_flag */ + vl_rbsp_u(rbsp, 1); + + /* general_non_packed_constraint_flag */ + vl_rbsp_u(rbsp, 1); + + /* general_frame_only_constraint_flag */ + vl_rbsp_u(rbsp, 1); + + /* general_reserved_zero_44bits */ + vl_rbsp_u(rbsp, 16); + vl_rbsp_u(rbsp, 16); + vl_rbsp_u(rbsp, 12); +} + +static unsigned profile_tier_level(struct vl_rbsp *rbsp, + int max_sublayers_minus1) +{ + bool sub_layer_profile_present_flag[6]; + bool sub_layer_level_present_flag[6]; + unsigned level_idc; + int i; + + profile_tier(rbsp); + + /* general_level_idc */ + level_idc = vl_rbsp_u(rbsp, 8); + + for (i = 0; i < max_sublayers_minus1; ++i) { + sub_layer_profile_present_flag[i] = vl_rbsp_u(rbsp, 1); + sub_layer_level_present_flag[i] = vl_rbsp_u(rbsp, 1); + } + + if (max_sublayers_minus1 > 0) + for (i = max_sublayers_minus1; i < 8; ++i) + /* reserved_zero_2bits */ + vl_rbsp_u(rbsp, 2); + + for (i = 0; i < max_sublayers_minus1; ++i) { + if (sub_layer_profile_present_flag[i]) + profile_tier(rbsp); + + if (sub_layer_level_present_flag[i]) + /* sub_layer_level_idc */ + vl_rbsp_u(rbsp, 8); + } + + return level_idc; +} + +static void scaling_list_data(vid_dec_PrivateType *priv, + struct vl_rbsp *rbsp, struct pipe_h265_sps *sps) +{ + unsigned size_id, matrix_id; + unsigned scaling_list_len[4] = { 16, 64, 64, 64 }; + uint8_t scaling_list4x4[6][64] = { }; + int i; + + uint8_t (*scaling_list_data[4])[6][64] = { + (uint8_t (*)[6][64])scaling_list4x4, + (uint8_t (*)[6][64])sps->ScalingList8x8, + (uint8_t (*)[6][64])sps->ScalingList16x16, + (uint8_t (*)[6][64])sps->ScalingList32x32 + }; + uint8_t (*scaling_list_dc_coeff[2])[6] = { + (uint8_t (*)[6])sps->ScalingListDCCoeff16x16, + (uint8_t (*)[6])sps->ScalingListDCCoeff32x32 + }; + + for (size_id = 0; size_id < 4; ++size_id) { + + for (matrix_id = 0; matrix_id < ((size_id == 3) ? 2 : 6); ++matrix_id) { + bool scaling_list_pred_mode_flag = vl_rbsp_u(rbsp, 1); + + if (!scaling_list_pred_mode_flag) { + /* scaling_list_pred_matrix_id_delta */; + unsigned matrix_id_with_delta = matrix_id - vl_rbsp_ue(rbsp); + + if (matrix_id != matrix_id_with_delta) { + memcpy((*scaling_list_data[size_id])[matrix_id], + (*scaling_list_data[size_id])[matrix_id_with_delta], + scaling_list_len[size_id]); + if (size_id > 1) + (*scaling_list_dc_coeff[size_id - 2])[matrix_id] = + (*scaling_list_dc_coeff[size_id - 2])[matrix_id_with_delta]; + } else { + const uint8_t *d; + + if (size_id == 0) + memset((*scaling_list_data[0])[matrix_id], 16, 16); + else { + if (size_id < 3) + d = (matrix_id < 3) ? Default_8x8_Intra : Default_8x8_Inter; + else + d = (matrix_id < 1) ? Default_8x8_Intra : Default_8x8_Inter; + memcpy((*scaling_list_data[size_id])[matrix_id], d, + scaling_list_len[size_id]); + } + if (size_id > 1) + (*scaling_list_dc_coeff[size_id - 2])[matrix_id] = 16; + } + } else { + int next_coef = 8; + int coef_num = MIN2(64, (1 << (4 + (size_id << 1)))); + + if (size_id > 1) { + /* scaling_list_dc_coef_minus8 */ + next_coef = vl_rbsp_se(rbsp) + 8; + (*scaling_list_dc_coeff[size_id - 2])[matrix_id] = next_coef; + } + + for (i = 0; i < coef_num; ++i) { + /* scaling_list_delta_coef */ + next_coef = (next_coef + vl_rbsp_se(rbsp) + 256) % 256; + (*scaling_list_data[size_id])[matrix_id][i] = next_coef; + } + } + } + } + + for (i = 0; i < 6; ++i) + memcpy(sps->ScalingList4x4[i], scaling_list4x4[i], 16); + + return; +} + +static void st_ref_pic_set(vid_dec_PrivateType *priv, struct vl_rbsp *rbsp, + struct ref_pic_set *rps, struct pipe_h265_sps *sps, + unsigned idx) +{ + bool inter_rps_pred_flag; + unsigned delta_idx_minus1; + int delta_poc; + int i; + + inter_rps_pred_flag = (idx != 0) ? (vl_rbsp_u(rbsp, 1)) : false; + + if (inter_rps_pred_flag) { + struct ref_pic_set *ref_rps; + unsigned sign, abs; + int delta_rps; + bool used; + int j; + + if (idx == sps->num_short_term_ref_pic_sets) + delta_idx_minus1 = vl_rbsp_ue(rbsp); + else + delta_idx_minus1 = 0; + + ref_rps = (struct ref_pic_set *) + priv->codec_data.h265.ref_pic_set_list + idx - (delta_idx_minus1 + 1); + + /* delta_rps_sign */ + sign = vl_rbsp_u(rbsp, 1); + /* abs_delta_rps_minus1 */ + abs = vl_rbsp_ue(rbsp); + delta_rps = (1 - 2 * sign) * (abs + 1); + + rps->num_neg_pics = 0; + rps->num_pos_pics = 0; + rps->num_pics = 0; + + for(i = 0 ; i <= ref_rps->num_pics; ++i) { + /* used_by_curr_pic_flag */ + if (!vl_rbsp_u(rbsp, 1)) + /* use_delta_flag */ + vl_rbsp_u(rbsp, 1); + else { + delta_poc = delta_rps + + ((i < ref_rps->num_pics)? ref_rps->delta_poc[i] : 0); + rps->delta_poc[rps->num_pics] = delta_poc; + rps->used[rps->num_pics] = true; + if (delta_poc < 0) + rps->num_neg_pics++; + else + rps->num_pos_pics++; + rps->num_pics++; + } + } + + rps->num_delta_poc = ref_rps->num_pics; + + /* sort delta poc */ + for (i = 1; i < rps->num_pics; ++i) { + delta_poc = rps->delta_poc[i]; + used = rps->used[i]; + for (j = i - 1; j >= 0; j--) { + if (delta_poc < rps->delta_poc[j]) { + rps->delta_poc[j + 1] = rps->delta_poc[j]; + rps->used[j + 1] = rps->used[j]; + rps->delta_poc[j] = delta_poc; + rps->used[j] = used; + } + } + } + + for (i = 0 , j = rps->num_neg_pics - 1; + i < rps->num_neg_pics >> 1; i++, j--) { + delta_poc = rps->delta_poc[i]; + used = rps->used[i]; + rps->delta_poc[i] = rps->delta_poc[j]; + rps->used[i] = rps->used[j]; + rps->delta_poc[j] = delta_poc; + rps->used[j] = used; + } + } else { + /* num_negative_pics */ + rps->num_neg_pics = vl_rbsp_ue(rbsp); + /* num_positive_pics */ + rps->num_pos_pics = vl_rbsp_ue(rbsp); + rps->num_pics = rps->num_neg_pics + rps->num_pos_pics; + + delta_poc = 0; + for(i = 0 ; i < rps->num_neg_pics; ++i) { + /* delta_poc_s0_minus1 */ + delta_poc -= (vl_rbsp_ue(rbsp) + 1); + rps->delta_poc[i] = delta_poc; + /* used_by_curr_pic_s0_flag */ + rps->used[i] = vl_rbsp_u(rbsp, 1); + } + + delta_poc = 0; + for(i = rps->num_neg_pics; i < rps->num_pics; ++i) { + /* delta_poc_s1_minus1 */ + delta_poc += (vl_rbsp_ue(rbsp) + 1); + rps->delta_poc[i] = delta_poc; + /* used_by_curr_pic_s1_flag */ + rps->used[i] = vl_rbsp_u(rbsp, 1); + } + } +} + +static struct pipe_h265_sps *seq_parameter_set_id(vid_dec_PrivateType *priv, + struct vl_rbsp *rbsp) +{ + unsigned id = vl_rbsp_ue(rbsp); + + if (id >= ARRAY_SIZE(priv->codec_data.h265.sps)) + return NULL; + + return &priv->codec_data.h265.sps[id]; +} + +static void seq_parameter_set(vid_dec_PrivateType *priv, struct vl_rbsp *rbsp) +{ + struct pipe_h265_sps *sps; + int sps_max_sub_layers_minus1; + unsigned i; + + /* sps_video_parameter_set_id */ + vl_rbsp_u(rbsp, 4); + + /* sps_max_sub_layers_minus1 */ + sps_max_sub_layers_minus1 = vl_rbsp_u(rbsp, 3); + + assert(sps_max_sub_layers_minus1 <= 6); + + /* sps_temporal_id_nesting_flag */ + vl_rbsp_u(rbsp, 1); + + priv->codec_data.h265.level_idc = + profile_tier_level(rbsp, sps_max_sub_layers_minus1); + + sps = seq_parameter_set_id(priv, rbsp); + if (!sps) + return; + + memset(sps, 0, sizeof(*sps)); + + sps->chroma_format_idc = vl_rbsp_ue(rbsp); + + if (sps->chroma_format_idc == 3) + sps->separate_colour_plane_flag = vl_rbsp_u(rbsp, 1); + + priv->codec_data.h265.pic_width_in_luma_samples = + sps->pic_width_in_luma_samples = vl_rbsp_ue(rbsp); + + priv->codec_data.h265.pic_height_in_luma_samples = + sps->pic_height_in_luma_samples = vl_rbsp_ue(rbsp); + + /* conformance_window_flag */ + if (vl_rbsp_u(rbsp, 1)) { + /* conf_win_left_offset */ + vl_rbsp_ue(rbsp); + /* conf_win_right_offset */ + vl_rbsp_ue(rbsp); + /* conf_win_top_offset */ + vl_rbsp_ue(rbsp); + /* conf_win_bottom_offset */ + vl_rbsp_ue(rbsp); + } + + sps->bit_depth_luma_minus8 = vl_rbsp_ue(rbsp); + sps->bit_depth_chroma_minus8 = vl_rbsp_ue(rbsp); + sps->log2_max_pic_order_cnt_lsb_minus4 = vl_rbsp_ue(rbsp); + + /* sps_sub_layer_ordering_info_present_flag */ + i = vl_rbsp_u(rbsp, 1) ? 0 : sps_max_sub_layers_minus1; + for (; i <= sps_max_sub_layers_minus1; ++i) { + sps->sps_max_dec_pic_buffering_minus1 = vl_rbsp_ue(rbsp); + /* sps_max_num_reorder_pics */ + vl_rbsp_ue(rbsp); + /* sps_max_latency_increase_plus */ + vl_rbsp_ue(rbsp); + } + + sps->log2_min_luma_coding_block_size_minus3 = vl_rbsp_ue(rbsp); + sps->log2_diff_max_min_luma_coding_block_size = vl_rbsp_ue(rbsp); + sps->log2_min_transform_block_size_minus2 = vl_rbsp_ue(rbsp); + sps->log2_diff_max_min_transform_block_size = vl_rbsp_ue(rbsp); + sps->max_transform_hierarchy_depth_inter = vl_rbsp_ue(rbsp); + sps->max_transform_hierarchy_depth_intra = vl_rbsp_ue(rbsp); + + sps->scaling_list_enabled_flag = vl_rbsp_u(rbsp, 1); + if (sps->scaling_list_enabled_flag) + /* sps_scaling_list_data_present_flag */ + if (vl_rbsp_u(rbsp, 1)) + scaling_list_data(priv, rbsp, sps); + + sps->amp_enabled_flag = vl_rbsp_u(rbsp, 1); + sps->sample_adaptive_offset_enabled_flag = vl_rbsp_u(rbsp, 1); + sps->pcm_enabled_flag = vl_rbsp_u(rbsp, 1); + if (sps->pcm_enabled_flag) { + sps->pcm_sample_bit_depth_luma_minus1 = vl_rbsp_u(rbsp, 4); + sps->pcm_sample_bit_depth_chroma_minus1 = vl_rbsp_u(rbsp, 4); + sps->log2_min_pcm_luma_coding_block_size_minus3 = vl_rbsp_ue(rbsp); + sps->log2_diff_max_min_pcm_luma_coding_block_size = vl_rbsp_ue(rbsp); + sps->pcm_loop_filter_disabled_flag = vl_rbsp_u(rbsp, 1); + } + + sps->num_short_term_ref_pic_sets = vl_rbsp_ue(rbsp); + + for (i = 0; i < sps->num_short_term_ref_pic_sets; ++i) { + struct ref_pic_set *rps; + + rps = (struct ref_pic_set *) + priv->codec_data.h265.ref_pic_set_list + i; + st_ref_pic_set(priv, rbsp, rps, sps, i); + } + + sps->long_term_ref_pics_present_flag = vl_rbsp_u(rbsp, 1); + if (sps->long_term_ref_pics_present_flag) { + sps->num_long_term_ref_pics_sps = vl_rbsp_ue(rbsp); + for (i = 0; i < sps->num_long_term_ref_pics_sps; ++i) { + /* lt_ref_pic_poc_lsb_sps */ + vl_rbsp_u(rbsp, sps->log2_max_pic_order_cnt_lsb_minus4 + 4); + /* used_by_curr_pic_lt_sps_flag */ + vl_rbsp_u(rbsp, 1); + } + } + + sps->sps_temporal_mvp_enabled_flag = vl_rbsp_u(rbsp, 1); + sps->strong_intra_smoothing_enabled_flag = vl_rbsp_u(rbsp, 1); +} + +static struct pipe_h265_pps *pic_parameter_set_id(vid_dec_PrivateType *priv, + struct vl_rbsp *rbsp) +{ + unsigned id = vl_rbsp_ue(rbsp); + + if (id >= ARRAY_SIZE(priv->codec_data.h265.pps)) + return NULL; + + return &priv->codec_data.h265.pps[id]; +} + +static void picture_parameter_set(vid_dec_PrivateType *priv, + struct vl_rbsp *rbsp) +{ + struct pipe_h265_sps *sps; + struct pipe_h265_pps *pps; + int i; + + pps = pic_parameter_set_id(priv, rbsp); + if (!pps) + return; + + memset(pps, 0, sizeof(*pps)); + sps = pps->sps = seq_parameter_set_id(priv, rbsp); + if (!sps) + return; + + pps->dependent_slice_segments_enabled_flag = vl_rbsp_u(rbsp, 1); + pps->output_flag_present_flag = vl_rbsp_u(rbsp, 1); + pps->num_extra_slice_header_bits = vl_rbsp_u(rbsp, 3); + pps->sign_data_hiding_enabled_flag = vl_rbsp_u(rbsp, 1); + pps->cabac_init_present_flag = vl_rbsp_u(rbsp, 1); + + pps->num_ref_idx_l0_default_active_minus1 = vl_rbsp_ue(rbsp); + pps->num_ref_idx_l1_default_active_minus1 = vl_rbsp_ue(rbsp); + pps->init_qp_minus26 = vl_rbsp_se(rbsp); + pps->constrained_intra_pred_flag = vl_rbsp_u(rbsp, 1); + pps->transform_skip_enabled_flag = vl_rbsp_u(rbsp, 1); + + pps->cu_qp_delta_enabled_flag = vl_rbsp_u(rbsp, 1); + if (pps->cu_qp_delta_enabled_flag) + pps->diff_cu_qp_delta_depth = vl_rbsp_ue(rbsp); + + pps->pps_cb_qp_offset = vl_rbsp_se(rbsp); + pps->pps_cr_qp_offset = vl_rbsp_se(rbsp); + pps->pps_slice_chroma_qp_offsets_present_flag = vl_rbsp_u(rbsp, 1); + + pps->weighted_pred_flag = vl_rbsp_u(rbsp, 1); + pps->weighted_bipred_flag = vl_rbsp_u(rbsp, 1); + + pps->transquant_bypass_enabled_flag = vl_rbsp_u(rbsp, 1); + pps->tiles_enabled_flag = vl_rbsp_u(rbsp, 1); + pps->entropy_coding_sync_enabled_flag = vl_rbsp_u(rbsp, 1); + + if (pps->tiles_enabled_flag) { + pps->num_tile_columns_minus1 = vl_rbsp_ue(rbsp); + pps->num_tile_rows_minus1 = vl_rbsp_ue(rbsp); + + pps->uniform_spacing_flag = vl_rbsp_u(rbsp, 1); + if (!pps->uniform_spacing_flag) { + for (i = 0; i < pps->num_tile_columns_minus1; ++i) + pps->column_width_minus1[i] = vl_rbsp_ue(rbsp); + + for (i = 0; i < pps->num_tile_rows_minus1; ++i) + pps->row_height_minus1[i] = vl_rbsp_ue(rbsp); + } + + if (!pps->num_tile_columns_minus1 || !pps->num_tile_rows_minus1) + pps->loop_filter_across_tiles_enabled_flag = vl_rbsp_u(rbsp, 1); + } + + pps->pps_loop_filter_across_slices_enabled_flag = vl_rbsp_u(rbsp, 1); + + pps->deblocking_filter_control_present_flag = vl_rbsp_u(rbsp, 1); + if (pps->deblocking_filter_control_present_flag) { + pps->deblocking_filter_override_enabled_flag = vl_rbsp_u(rbsp, 1); + pps->pps_deblocking_filter_disabled_flag = vl_rbsp_u(rbsp, 1); + if (!pps->pps_deblocking_filter_disabled_flag) { + pps->pps_beta_offset_div2 = vl_rbsp_se(rbsp); + pps->pps_tc_offset_div2 = vl_rbsp_se(rbsp); + } + } + + /* pps_scaling_list_data_present_flag */ + if (vl_rbsp_u(rbsp, 1)) + scaling_list_data(priv, rbsp, sps); + + pps->lists_modification_present_flag = vl_rbsp_u(rbsp, 1); + pps->log2_parallel_merge_level_minus2 = vl_rbsp_ue(rbsp); + pps->slice_segment_header_extension_present_flag = vl_rbsp_u(rbsp, 1); +} + +static void vid_dec_h265_BeginFrame(vid_dec_PrivateType *priv) +{ + if (priv->frame_started) + return; + + if (!priv->codec) { + struct pipe_video_codec templat = {}; + omx_base_video_PortType *port = (omx_base_video_PortType *) + priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX]; + + templat.profile = priv->profile; + templat.entrypoint = PIPE_VIDEO_ENTRYPOINT_BITSTREAM; + templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420; + templat.expect_chunked_decode = true; + templat.width = priv->codec_data.h265.pic_width_in_luma_samples; + templat.height = priv->codec_data.h265.pic_height_in_luma_samples; + templat.level = priv->codec_data.h265.level_idc; + priv->codec = priv->pipe->create_video_codec(priv->pipe, &templat); + + /* disable transcode tunnel if video size is different from coded size */ + if (priv->codec_data.h265.pic_width_in_luma_samples != + port->sPortParam.format.video.nFrameWidth || + priv->codec_data.h265.pic_height_in_luma_samples != + port->sPortParam.format.video.nFrameHeight) + priv->disable_tunnel = true; + } + + vid_dec_NeedTarget(priv); + + if (priv->first_buf_in_frame) + priv->timestamp = priv->timestamps[0]; + priv->first_buf_in_frame = false; + + priv->codec->begin_frame(priv->codec, priv->target, &priv->picture.base); + priv->frame_started = true; +} + +static struct pipe_video_buffer *vid_dec_h265_Flush(vid_dec_PrivateType *priv, + OMX_TICKS *timestamp) +{ + struct dpb_list *entry, *result = NULL; + struct pipe_video_buffer *buf; + + /* search for the lowest poc and break on zeros */ + LIST_FOR_EACH_ENTRY(entry, &priv->codec_data.h265.dpb_list, list) { + + if (result && entry->poc == 0) + break; + + if (!result || entry->poc < result->poc) + result = entry; + } + + if (!result) + return NULL; + + buf = result->buffer; + if (timestamp) + *timestamp = result->timestamp; + + --priv->codec_data.h265.dpb_num; + LIST_DEL(&result->list); + FREE(result); + + return buf; +} + +static void vid_dec_h265_EndFrame(vid_dec_PrivateType *priv) +{ + struct dpb_list *entry = NULL; + struct pipe_video_buffer *tmp; + struct ref_pic_set *rps; + int i; + OMX_TICKS timestamp; + + if (!priv->frame_started) + return; + + priv->picture.h265.NumPocStCurrBefore = 0; + priv->picture.h265.NumPocStCurrAfter = 0; + memset(priv->picture.h265.RefPicSetStCurrBefore, 0, 8); + memset(priv->picture.h265.RefPicSetStCurrAfter, 0, 8); + for (i = 0; i < MAX_NUM_REF_PICS; ++i) { + priv->picture.h265.ref[i] = NULL; + priv->picture.h265.PicOrderCntVal[i] = 0; + } + + rps = priv->codec_data.h265.rps; + + if (rps) { + unsigned bf = 0, af = 0; + + priv->picture.h265.NumDeltaPocsOfRefRpsIdx = rps->num_delta_poc; + for (i = 0; i < rps->num_pics; ++i) { + priv->picture.h265.PicOrderCntVal[i] = + rps->delta_poc[i] + get_poc(priv); + + LIST_FOR_EACH_ENTRY(entry, &priv->codec_data.h265.dpb_list, list) { + if (entry->poc == priv->picture.h265.PicOrderCntVal[i]) { + priv->picture.h265.ref[i] = entry->buffer; + break; + } + } + + if (rps->used[i]) { + if (i < rps->num_neg_pics) { + priv->picture.h265.NumPocStCurrBefore++; + priv->picture.h265.RefPicSetStCurrBefore[bf++] = i; + } else { + priv->picture.h265.NumPocStCurrAfter++; + priv->picture.h265.RefPicSetStCurrAfter[af++] = i; + } + } + } + } + + priv->codec->end_frame(priv->codec, priv->target, &priv->picture.base); + priv->frame_started = false; + + /* add the decoded picture to the dpb list */ + entry = CALLOC_STRUCT(dpb_list); + if (!entry) + return; + + priv->first_buf_in_frame = true; + entry->buffer = priv->target; + entry->timestamp = priv->timestamp; + entry->poc = get_poc(priv); + + LIST_ADDTAIL(&entry->list, &priv->codec_data.h265.dpb_list); + ++priv->codec_data.h265.dpb_num; + priv->target = NULL; + + if (priv->codec_data.h265.dpb_num <= DPB_MAX_SIZE) + return; + + tmp = priv->in_buffers[0]->pInputPortPrivate; + priv->in_buffers[0]->pInputPortPrivate = vid_dec_h265_Flush(priv, ×tamp); + priv->in_buffers[0]->nTimeStamp = timestamp; + priv->target = tmp; + priv->frame_finished = priv->in_buffers[0]->pInputPortPrivate != NULL; + if (priv->frame_finished && + (priv->in_buffers[0]->nFlags & OMX_BUFFERFLAG_EOS)) + FREE(priv->codec_data.h265.ref_pic_set_list); +} + +static void slice_header(vid_dec_PrivateType *priv, struct vl_rbsp *rbsp, + unsigned nal_unit_type) +{ + struct pipe_h265_pps *pps; + struct pipe_h265_sps *sps; + bool first_slice_segment_in_pic_flag; + bool dependent_slice_segment_flag = false; + struct ref_pic_set *rps; + unsigned poc_lsb, poc_msb, slice_prev_poc; + unsigned max_poc_lsb, prev_poc_lsb, prev_poc_msb; + unsigned num_st_rps; + int i; + + if (priv->picture.h265.IDRPicFlag != is_idr_picture(nal_unit_type)) + vid_dec_h265_EndFrame(priv); + + priv->picture.h265.IDRPicFlag = is_idr_picture(nal_unit_type); + + first_slice_segment_in_pic_flag = vl_rbsp_u(rbsp, 1); + + if (is_rap_picture(nal_unit_type)) + /* no_output_of_prior_pics_flag */ + vl_rbsp_u(rbsp, 1); + + pps = pic_parameter_set_id(priv, rbsp); + if (!pps) + return; + + sps = pps->sps; + if (!sps) + return; + + if (pps != priv->picture.h265.pps) + vid_dec_h265_EndFrame(priv); + + priv->picture.h265.pps = pps; + + if (priv->picture.h265.RAPPicFlag != is_rap_picture(nal_unit_type)) + vid_dec_h265_EndFrame(priv); + priv->picture.h265.RAPPicFlag = is_rap_picture(nal_unit_type); + + num_st_rps = sps->num_short_term_ref_pic_sets; + + if (priv->picture.h265.CurrRpsIdx != num_st_rps) + vid_dec_h265_EndFrame(priv); + priv->picture.h265.CurrRpsIdx = num_st_rps; + + if (!first_slice_segment_in_pic_flag) { + int size, num; + int bits_slice_segment_address = 0; + + if (pps->dependent_slice_segments_enabled_flag) + dependent_slice_segment_flag = vl_rbsp_u(rbsp, 1); + + size = 1 << (sps->log2_min_luma_coding_block_size_minus3 + 3 + + sps->log2_diff_max_min_luma_coding_block_size); + + num = ((sps->pic_width_in_luma_samples + size - 1) / size) * + ((sps->pic_height_in_luma_samples + size - 1) / size); + + while (num > (1 << bits_slice_segment_address)) + bits_slice_segment_address++; + + /* slice_segment_address */ + vl_rbsp_u(rbsp, bits_slice_segment_address); + } + + if (dependent_slice_segment_flag) + return; + + for (i = 0; i < pps->num_extra_slice_header_bits; ++i) + /* slice_reserved_flag */ + vl_rbsp_u(rbsp, 1); + + /* slice_type */ + vl_rbsp_ue(rbsp); + + if (pps->output_flag_present_flag) + /* pic output flag */ + vl_rbsp_u(rbsp, 1); + + if (sps->separate_colour_plane_flag) + /* colour_plane_id */ + vl_rbsp_u(rbsp, 2); + + if (is_idr_picture(nal_unit_type)) { + set_poc(priv, nal_unit_type, 0); + return; + } + + /* slice_pic_order_cnt_lsb */ + poc_lsb = + vl_rbsp_u(rbsp, sps->log2_max_pic_order_cnt_lsb_minus4 + 4); + + slice_prev_poc = (int)priv->codec_data.h265.slice_prev_poc; + max_poc_lsb = 1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4); + + prev_poc_lsb = slice_prev_poc & (max_poc_lsb - 1); + prev_poc_msb = slice_prev_poc - prev_poc_lsb; + + if ((poc_lsb < prev_poc_lsb) && + ((prev_poc_lsb - poc_lsb ) >= (max_poc_lsb / 2))) + poc_msb = prev_poc_msb + max_poc_lsb; + + else if ((poc_lsb > prev_poc_lsb ) && + ((poc_lsb - prev_poc_lsb) > (max_poc_lsb / 2))) + poc_msb = prev_poc_msb - max_poc_lsb; + + else + poc_msb = prev_poc_msb; + + if (is_bla_picture(nal_unit_type)) + poc_msb = 0; + + if (get_poc(priv) != poc_msb + poc_lsb) + vid_dec_h265_EndFrame(priv); + + set_poc(priv, nal_unit_type, (poc_msb + poc_lsb)); + + /* short_term_ref_pic_set_sps_flag */ + if (!vl_rbsp_u(rbsp, 1)) { + rps = (struct ref_pic_set *) + priv->codec_data.h265.ref_pic_set_list + num_st_rps; + st_ref_pic_set(priv, rbsp, rps, sps, num_st_rps); + + } else if (num_st_rps > 1) { + int num_bits = 0; + unsigned idx; + + while ((1 << num_bits) < num_st_rps) + num_bits++; + + if (num_bits > 0) + /* short_term_ref_pic_set_idx */ + idx = vl_rbsp_u(rbsp, num_bits); + else + idx = 0; + + rps = (struct ref_pic_set *) + priv->codec_data.h265.ref_pic_set_list + idx; + } else + rps = (struct ref_pic_set *) + priv->codec_data.h265.ref_pic_set_list; + + if (is_bla_picture(nal_unit_type)) { + rps->num_neg_pics = 0; + rps->num_pos_pics = 0; + rps->num_pics = 0; + } + + priv->codec_data.h265.rps = rps; + + return; +} + +static void vid_dec_h265_Decode(vid_dec_PrivateType *priv, + struct vl_vlc *vlc, + unsigned min_bits_left) +{ + unsigned nal_unit_type; + unsigned nuh_layer_id; + unsigned nuh_temporal_id_plus1; + + if (!vl_vlc_search_byte(vlc, vl_vlc_bits_left(vlc) - min_bits_left, 0x00)) + return; + + if (vl_vlc_peekbits(vlc, 24) != 0x000001) { + vl_vlc_eatbits(vlc, 8); + return; + } + + if (priv->slice) { + unsigned bytes = priv->bytes_left - (vl_vlc_bits_left(vlc) / 8); + + priv->codec->decode_bitstream(priv->codec, priv->target, + &priv->picture.base, 1, + &priv->slice, &bytes); + priv->slice = NULL; + } + + vl_vlc_eatbits(vlc, 24); + + /* forbidden_zero_bit */ + vl_vlc_eatbits(vlc, 1); + + if (vl_vlc_valid_bits(vlc) < 15) + vl_vlc_fillbits(vlc); + + nal_unit_type = vl_vlc_get_uimsbf(vlc, 6); + + /* nuh_layer_id */ + nuh_layer_id = vl_vlc_get_uimsbf(vlc, 6); + + /* nuh_temporal_id_plus1 */ + nuh_temporal_id_plus1 = vl_vlc_get_uimsbf(vlc, 3); + priv->codec_data.h265.temporal_id = nuh_temporal_id_plus1 - 1; + + if (!is_slice_picture(nal_unit_type)) + vid_dec_h265_EndFrame(priv); + + if (nal_unit_type == NAL_UNIT_TYPE_SPS) { + struct vl_rbsp rbsp; + + vl_rbsp_init(&rbsp, vlc, ~0); + seq_parameter_set(priv, &rbsp); + + } else if (nal_unit_type == NAL_UNIT_TYPE_PPS) { + struct vl_rbsp rbsp; + + vl_rbsp_init(&rbsp, vlc, ~0); + picture_parameter_set(priv, &rbsp); + + } else if (is_slice_picture(nal_unit_type)) { + unsigned bits = vl_vlc_valid_bits(vlc); + unsigned bytes = bits / 8 + 5; + struct vl_rbsp rbsp; + uint8_t buf[9]; + const void *ptr = buf; + unsigned i; + + buf[0] = 0x0; + buf[1] = 0x0; + buf[2] = 0x1; + buf[3] = nal_unit_type << 1 | nuh_layer_id >> 5; + buf[4] = nuh_layer_id << 3 | nuh_temporal_id_plus1; + for (i = 5; i < bytes; ++i) + buf[i] = vl_vlc_peekbits(vlc, bits) >> ((bytes - i - 1) * 8); + + priv->bytes_left = (vl_vlc_bits_left(vlc) - bits) / 8; + priv->slice = vlc->data; + + vl_rbsp_init(&rbsp, vlc, 128); + slice_header(priv, &rbsp, nal_unit_type); + + vid_dec_h265_BeginFrame(priv); + + priv->codec->decode_bitstream(priv->codec, priv->target, + &priv->picture.base, 1, + &ptr, &bytes); + } + + /* resync to byte boundary */ + vl_vlc_eatbits(vlc, vl_vlc_valid_bits(vlc) % 8); +} + +void vid_dec_h265_Init(vid_dec_PrivateType *priv) +{ + priv->picture.base.profile = PIPE_VIDEO_PROFILE_HEVC_MAIN; + + LIST_INITHEAD(&priv->codec_data.h265.dpb_list); + priv->codec_data.h265.ref_pic_set_list = (struct ref_pic_set *) + CALLOC(MAX_NUM_REF_PICS, sizeof(struct ref_pic_set)); + + priv->Decode = vid_dec_h265_Decode; + priv->EndFrame = vid_dec_h265_EndFrame; + priv->Flush = vid_dec_h265_Flush; + priv->first_buf_in_frame = true; +} diff --git a/src/gallium/state_trackers/omx/bellagio/vid_dec_mpeg12.c b/src/gallium/state_trackers/omx/bellagio/vid_dec_mpeg12.c new file mode 100644 index 00000000000..f64c2b83fa5 --- /dev/null +++ b/src/gallium/state_trackers/omx/bellagio/vid_dec_mpeg12.c @@ -0,0 +1,383 @@ +/************************************************************************** + * + * Copyright 2013 Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* + * Authors: + * Christian König <[email protected]> + * + */ + +#include "pipe/p_video_codec.h" +#include "vl/vl_vlc.h" +#include "vl/vl_zscan.h" + +#include "vid_dec.h" + +static uint8_t default_intra_matrix[64] = { + 8, 16, 19, 22, 26, 27, 29, 34, + 16, 16, 22, 24, 27, 29, 34, 37, + 19, 22, 26, 27, 29, 34, 34, 38, + 22, 22, 26, 27, 29, 34, 37, 40, + 22, 26, 27, 29, 32, 35, 40, 48, + 26, 27, 29, 32, 35, 40, 48, 58, + 26, 27, 29, 34, 38, 46, 56, 69, + 27, 29, 35, 38, 46, 56, 69, 83 +}; + +static uint8_t default_non_intra_matrix[64] = { + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16 +}; + +static void vid_dec_mpeg12_Decode(vid_dec_PrivateType *priv, struct vl_vlc *vlc, unsigned min_bits_left); +static void vid_dec_mpeg12_EndFrame(vid_dec_PrivateType *priv); +static struct pipe_video_buffer *vid_dec_mpeg12_Flush(vid_dec_PrivateType *priv, OMX_TICKS *timestamp); + +void vid_dec_mpeg12_Init(vid_dec_PrivateType *priv) +{ + struct pipe_video_codec templat = {}; + omx_base_video_PortType *port; + + port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX]; + templat.profile = priv->profile; + templat.entrypoint = PIPE_VIDEO_ENTRYPOINT_BITSTREAM; + templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420; + templat.max_references = 2; + templat.expect_chunked_decode = true; + templat.width = port->sPortParam.format.video.nFrameWidth; + templat.height = port->sPortParam.format.video.nFrameHeight; + + priv->codec = priv->pipe->create_video_codec(priv->pipe, &templat); + + priv->picture.base.profile = PIPE_VIDEO_PROFILE_MPEG2_MAIN; + priv->picture.mpeg12.intra_matrix = default_intra_matrix; + priv->picture.mpeg12.non_intra_matrix = default_non_intra_matrix; + + priv->Decode = vid_dec_mpeg12_Decode; + priv->EndFrame = vid_dec_mpeg12_EndFrame; + priv->Flush = vid_dec_mpeg12_Flush; +} + +static void BeginFrame(vid_dec_PrivateType *priv) +{ + if (priv->picture.mpeg12.picture_coding_type != PIPE_MPEG12_PICTURE_CODING_TYPE_B) { + priv->picture.mpeg12.ref[0] = priv->picture.mpeg12.ref[1]; + priv->picture.mpeg12.ref[1] = NULL; + } + + if (priv->target == priv->picture.mpeg12.ref[0]) { + struct pipe_video_buffer *tmp = priv->target; + priv->target = priv->shadow; + priv->shadow = tmp; + } + + vid_dec_NeedTarget(priv); + + priv->codec->begin_frame(priv->codec, priv->target, &priv->picture.base); + priv->frame_started = true; +} + +static void vid_dec_mpeg12_EndFrame(vid_dec_PrivateType *priv) +{ + struct pipe_video_buffer *done; + + priv->codec->end_frame(priv->codec, priv->target, &priv->picture.base); + priv->frame_started = false; + + if (priv->picture.mpeg12.picture_coding_type != PIPE_MPEG12_PICTURE_CODING_TYPE_B) { + + priv->picture.mpeg12.ref[1] = priv->target; + done = priv->picture.mpeg12.ref[0]; + if (!done) { + priv->target = NULL; + return; + } + + } else + done = priv->target; + + priv->frame_finished = true; + priv->target = priv->in_buffers[0]->pInputPortPrivate; + priv->in_buffers[0]->pInputPortPrivate = done; +} + +static struct pipe_video_buffer *vid_dec_mpeg12_Flush(vid_dec_PrivateType *priv, OMX_TICKS *timestamp) +{ + struct pipe_video_buffer *result = priv->picture.mpeg12.ref[1]; + priv->picture.mpeg12.ref[1] = NULL; + if (timestamp) + *timestamp = OMX_VID_DEC_TIMESTAMP_INVALID; + return result; +} + +static void vid_dec_mpeg12_Decode(vid_dec_PrivateType *priv, struct vl_vlc *vlc, unsigned min_bits_left) +{ + uint8_t code; + unsigned i; + + if (!vl_vlc_search_byte(vlc, vl_vlc_bits_left(vlc) - min_bits_left, 0x00)) + return; + + if (vl_vlc_peekbits(vlc, 24) != 0x000001) { + vl_vlc_eatbits(vlc, 8); + return; + } + + if (priv->slice) { + unsigned bytes = priv->bytes_left - (vl_vlc_bits_left(vlc) / 8); + priv->codec->decode_bitstream(priv->codec, priv->target, &priv->picture.base, + 1, &priv->slice, &bytes); + priv->slice = NULL; + } + + vl_vlc_eatbits(vlc, 24); + code = vl_vlc_get_uimsbf(vlc, 8); + + if (priv->frame_started && (code == 0x00 || code > 0xAF)) + vid_dec_mpeg12_EndFrame(priv); + + if (code == 0xB3) { + /* sequence header code */ + vl_vlc_fillbits(vlc); + + /* horizontal_size_value */ + vl_vlc_get_uimsbf(vlc, 12); + + /* vertical_size_value */ + vl_vlc_get_uimsbf(vlc, 12); + + /* aspect_ratio_information */ + vl_vlc_get_uimsbf(vlc, 4); + + /* frame_rate_code */ + vl_vlc_get_uimsbf(vlc, 4); + + vl_vlc_fillbits(vlc); + + /* bit_rate_value */ + vl_vlc_get_uimsbf(vlc, 18); + + /* marker_bit */ + vl_vlc_get_uimsbf(vlc, 1); + + /* vbv_buffer_size_value */ + vl_vlc_get_uimsbf(vlc, 10); + + /* constrained_parameters_flag */ + vl_vlc_get_uimsbf(vlc, 1); + + vl_vlc_fillbits(vlc); + + /* load_intra_quantiser_matrix */ + if (vl_vlc_get_uimsbf(vlc, 1)) { + /* intra_quantiser_matrix */ + priv->picture.mpeg12.intra_matrix = priv->codec_data.mpeg12.intra_matrix; + for (i = 0; i < 64; ++i) { + priv->codec_data.mpeg12.intra_matrix[vl_zscan_normal[i]] = vl_vlc_get_uimsbf(vlc, 8); + vl_vlc_fillbits(vlc); + } + } else + priv->picture.mpeg12.intra_matrix = default_intra_matrix; + + /* load_non_intra_quantiser_matrix */ + if (vl_vlc_get_uimsbf(vlc, 1)) { + /* non_intra_quantiser_matrix */ + priv->picture.mpeg12.non_intra_matrix = priv->codec_data.mpeg12.non_intra_matrix; + for (i = 0; i < 64; ++i) { + priv->codec_data.mpeg12.non_intra_matrix[i] = vl_vlc_get_uimsbf(vlc, 8); + vl_vlc_fillbits(vlc); + } + } else + priv->picture.mpeg12.non_intra_matrix = default_non_intra_matrix; + + } else if (code == 0x00) { + /* picture start code */ + vl_vlc_fillbits(vlc); + + /* temporal_reference */ + vl_vlc_get_uimsbf(vlc, 10); + + priv->picture.mpeg12.picture_coding_type = vl_vlc_get_uimsbf(vlc, 3); + + /* vbv_delay */ + vl_vlc_get_uimsbf(vlc, 16); + + vl_vlc_fillbits(vlc); + if (priv->picture.mpeg12.picture_coding_type == 2 || + priv->picture.mpeg12.picture_coding_type == 3) { + priv->picture.mpeg12.full_pel_forward_vector = vl_vlc_get_uimsbf(vlc, 1); + /* forward_f_code */ + priv->picture.mpeg12.f_code[0][0] = vl_vlc_get_uimsbf(vlc, 3) - 1; + priv->picture.mpeg12.f_code[0][1] = priv->picture.mpeg12.f_code[0][0]; + } else { + priv->picture.mpeg12.full_pel_forward_vector = 0; + priv->picture.mpeg12.f_code[0][1] = priv->picture.mpeg12.f_code[0][0] = 14; + } + + if (priv->picture.mpeg12.picture_coding_type == 3) { + priv->picture.mpeg12.full_pel_backward_vector = vl_vlc_get_uimsbf(vlc, 1); + /* backward_f_code */ + priv->picture.mpeg12.f_code[1][0] = vl_vlc_get_uimsbf(vlc, 3) - 1; + priv->picture.mpeg12.f_code[1][1] = priv->picture.mpeg12.f_code[1][0]; + } else { + priv->picture.mpeg12.full_pel_backward_vector = 0; + priv->picture.mpeg12.f_code[0][1] = priv->picture.mpeg12.f_code[0][0] = 14; + } + + /* extra_bit_picture */ + while (vl_vlc_get_uimsbf(vlc, 1)) { + /* extra_information_picture */ + vl_vlc_get_uimsbf(vlc, 8); + vl_vlc_fillbits(vlc); + } + + } else if (code == 0xB5) { + /* extension start code */ + vl_vlc_fillbits(vlc); + + /* extension_start_code_identifier */ + switch (vl_vlc_get_uimsbf(vlc, 4)) { + case 0x3: /* quant matrix extension */ + + /* load_intra_quantiser_matrix */ + if (vl_vlc_get_uimsbf(vlc, 1)) { + /* intra_quantiser_matrix */ + priv->picture.mpeg12.intra_matrix = priv->codec_data.mpeg12.intra_matrix; + for (i = 0; i < 64; ++i) { + priv->codec_data.mpeg12.intra_matrix[vl_zscan_normal[i]] = vl_vlc_get_uimsbf(vlc, 8); + vl_vlc_fillbits(vlc); + } + } else + priv->picture.mpeg12.intra_matrix = default_intra_matrix; + + /* load_non_intra_quantiser_matrix */ + if (vl_vlc_get_uimsbf(vlc, 1)) { + /* non_intra_quantiser_matrix */ + priv->picture.mpeg12.non_intra_matrix = priv->codec_data.mpeg12.non_intra_matrix; + for (i = 0; i < 64; ++i) { + priv->codec_data.mpeg12.non_intra_matrix[i] = vl_vlc_get_uimsbf(vlc, 8); + vl_vlc_fillbits(vlc); + } + } else + priv->picture.mpeg12.intra_matrix = default_non_intra_matrix; + + break; + + case 0x8: /* picture coding extension */ + + priv->picture.mpeg12.f_code[0][0] = vl_vlc_get_uimsbf(vlc, 4) - 1; + priv->picture.mpeg12.f_code[0][1] = vl_vlc_get_uimsbf(vlc, 4) - 1; + priv->picture.mpeg12.f_code[1][0] = vl_vlc_get_uimsbf(vlc, 4) - 1; + priv->picture.mpeg12.f_code[1][1] = vl_vlc_get_uimsbf(vlc, 4) - 1; + priv->picture.mpeg12.intra_dc_precision = vl_vlc_get_uimsbf(vlc, 2); + priv->picture.mpeg12.picture_structure = vl_vlc_get_uimsbf(vlc, 2); + priv->picture.mpeg12.top_field_first = vl_vlc_get_uimsbf(vlc, 1); + priv->picture.mpeg12.frame_pred_frame_dct = vl_vlc_get_uimsbf(vlc, 1); + priv->picture.mpeg12.concealment_motion_vectors = vl_vlc_get_uimsbf(vlc, 1); + priv->picture.mpeg12.q_scale_type = vl_vlc_get_uimsbf(vlc, 1); + priv->picture.mpeg12.intra_vlc_format = vl_vlc_get_uimsbf(vlc, 1); + priv->picture.mpeg12.alternate_scan = vl_vlc_get_uimsbf(vlc, 1); + + /* repeat_first_field */ + vl_vlc_get_uimsbf(vlc, 1); + + /* chroma_420_type */ + vl_vlc_get_uimsbf(vlc, 1); + + vl_vlc_fillbits(vlc); + + /* progressive_frame */ + vl_vlc_get_uimsbf(vlc, 1); + + /* composite_display_flag */ + if (vl_vlc_get_uimsbf(vlc, 1)) { + + /* v_axis */ + vl_vlc_get_uimsbf(vlc, 1); + + /* field_sequence */ + vl_vlc_get_uimsbf(vlc, 3); + + /* sub_carrier */ + vl_vlc_get_uimsbf(vlc, 1); + + /* burst_amplitude */ + vl_vlc_get_uimsbf(vlc, 7); + + /* sub_carrier_phase */ + vl_vlc_get_uimsbf(vlc, 8); + } + break; + } + + } else if (code <= 0xAF) { + /* slice start */ + unsigned bytes = (vl_vlc_valid_bits(vlc) / 8) + 4; + uint8_t buf[12]; + const void *ptr = buf; + unsigned i; + + if (!priv->frame_started) + BeginFrame(priv); + + buf[0] = 0x00; + buf[1] = 0x00; + buf[2] = 0x01; + buf[3] = code; + for (i = 4; i < bytes; ++i) + buf[i] = vl_vlc_get_uimsbf(vlc, 8); + + priv->codec->decode_bitstream(priv->codec, priv->target, &priv->picture.base, + 1, &ptr, &bytes); + + priv->bytes_left = vl_vlc_bits_left(vlc) / 8; + priv->slice = vlc->data; + + } else if (code == 0xB2) { + /* user data start */ + + } else if (code == 0xB4) { + /* sequence error */ + } else if (code == 0xB7) { + /* sequence end */ + } else if (code == 0xB8) { + /* group start */ + } else if (code >= 0xB9) { + /* system start */ + } else { + /* reserved */ + } + + /* resync to byte boundary */ + vl_vlc_eatbits(vlc, vl_vlc_valid_bits(vlc) % 8); +} diff --git a/src/gallium/state_trackers/omx/bellagio/vid_enc.c b/src/gallium/state_trackers/omx/bellagio/vid_enc.c new file mode 100644 index 00000000000..2a777bbb91b --- /dev/null +++ b/src/gallium/state_trackers/omx/bellagio/vid_enc.c @@ -0,0 +1,1280 @@ +/************************************************************************** + * + * Copyright 2013 Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* + * Authors: + * Christian König <[email protected]> + * + */ + + +#include <assert.h> + +#include <OMX_Video.h> + +/* bellagio defines a DEBUG macro that we don't want */ +#ifndef DEBUG +#include <bellagio/omxcore.h> +#undef DEBUG +#else +#include <bellagio/omxcore.h> +#endif + +#include <bellagio/omx_base_video_port.h> + +#include "pipe/p_screen.h" +#include "pipe/p_video_codec.h" +#include "util/u_memory.h" +#include "vl/vl_video_buffer.h" + +#include "entrypoint.h" +#include "vid_enc.h" + +struct encode_task { + struct list_head list; + + struct pipe_video_buffer *buf; + unsigned pic_order_cnt; + struct pipe_resource *bitstream; + void *feedback; +}; + +struct input_buf_private { + struct list_head tasks; + + struct pipe_resource *resource; + struct pipe_transfer *transfer; +}; + +struct output_buf_private { + struct pipe_resource *bitstream; + struct pipe_transfer *transfer; +}; + +static OMX_ERRORTYPE vid_enc_Constructor(OMX_COMPONENTTYPE *comp, OMX_STRING name); +static OMX_ERRORTYPE vid_enc_Destructor(OMX_COMPONENTTYPE *comp); +static OMX_ERRORTYPE vid_enc_SetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param); +static OMX_ERRORTYPE vid_enc_GetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param); +static OMX_ERRORTYPE vid_enc_SetConfig(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR config); +static OMX_ERRORTYPE vid_enc_GetConfig(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR config); +static OMX_ERRORTYPE vid_enc_MessageHandler(OMX_COMPONENTTYPE *comp, internalRequestMessageType *msg); +static OMX_ERRORTYPE vid_enc_AllocateInBuffer(omx_base_PortType *port, OMX_INOUT OMX_BUFFERHEADERTYPE **buf, + OMX_IN OMX_U32 idx, OMX_IN OMX_PTR private, OMX_IN OMX_U32 size); +static OMX_ERRORTYPE vid_enc_UseInBuffer(omx_base_PortType *port, OMX_BUFFERHEADERTYPE **buf, OMX_U32 idx, + OMX_PTR private, OMX_U32 size, OMX_U8 *mem); +static OMX_ERRORTYPE vid_enc_FreeInBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf); +static OMX_ERRORTYPE vid_enc_EncodeFrame(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf); +static OMX_ERRORTYPE vid_enc_AllocateOutBuffer(omx_base_PortType *comp, OMX_INOUT OMX_BUFFERHEADERTYPE **buf, + OMX_IN OMX_U32 idx, OMX_IN OMX_PTR private, OMX_IN OMX_U32 size); +static OMX_ERRORTYPE vid_enc_FreeOutBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf); +static void vid_enc_BufferEncoded(OMX_COMPONENTTYPE *comp, OMX_BUFFERHEADERTYPE* input, OMX_BUFFERHEADERTYPE* output); + +static void enc_ReleaseTasks(struct list_head *head); + +OMX_ERRORTYPE vid_enc_LoaderComponent(stLoaderComponentType *comp) +{ + comp->componentVersion.s.nVersionMajor = 0; + comp->componentVersion.s.nVersionMinor = 0; + comp->componentVersion.s.nRevision = 0; + comp->componentVersion.s.nStep = 1; + comp->name_specific_length = 1; + comp->constructor = vid_enc_Constructor; + + comp->name = CALLOC(1, OMX_MAX_STRINGNAME_SIZE); + if (!comp->name) + return OMX_ErrorInsufficientResources; + + comp->name_specific = CALLOC(1, sizeof(char *)); + if (!comp->name_specific) + goto error_arrays; + + comp->role_specific = CALLOC(1, sizeof(char *)); + if (!comp->role_specific) + goto error_arrays; + + comp->name_specific[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE); + if (comp->name_specific[0] == NULL) + goto error_specific; + + comp->role_specific[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE); + if (comp->role_specific[0] == NULL) + goto error_specific; + + strcpy(comp->name, OMX_VID_ENC_BASE_NAME); + strcpy(comp->name_specific[0], OMX_VID_ENC_AVC_NAME); + strcpy(comp->role_specific[0], OMX_VID_ENC_AVC_ROLE); + + return OMX_ErrorNone; + +error_specific: + FREE(comp->role_specific[0]); + FREE(comp->name_specific[0]); + +error_arrays: + FREE(comp->role_specific); + FREE(comp->name_specific); + + FREE(comp->name); + + return OMX_ErrorInsufficientResources; +} + +static OMX_ERRORTYPE vid_enc_Constructor(OMX_COMPONENTTYPE *comp, OMX_STRING name) +{ + vid_enc_PrivateType *priv; + omx_base_video_PortType *port; + struct pipe_screen *screen; + OMX_ERRORTYPE r; + int i; + + assert(!comp->pComponentPrivate); + + priv = comp->pComponentPrivate = CALLOC(1, sizeof(vid_enc_PrivateType)); + if (!priv) + return OMX_ErrorInsufficientResources; + + r = omx_base_filter_Constructor(comp, name); + if (r) + return r; + + priv->BufferMgmtCallback = vid_enc_BufferEncoded; + priv->messageHandler = vid_enc_MessageHandler; + priv->destructor = vid_enc_Destructor; + + comp->SetParameter = vid_enc_SetParameter; + comp->GetParameter = vid_enc_GetParameter; + comp->GetConfig = vid_enc_GetConfig; + comp->SetConfig = vid_enc_SetConfig; + + priv->screen = omx_get_screen(); + if (!priv->screen) + return OMX_ErrorInsufficientResources; + + screen = priv->screen->pscreen; + if (!screen->get_video_param(screen, PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH, + PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_SUPPORTED)) + return OMX_ErrorBadParameter; + + priv->s_pipe = screen->context_create(screen, NULL, 0); + if (!priv->s_pipe) + return OMX_ErrorInsufficientResources; + + if (!vl_compositor_init(&priv->compositor, priv->s_pipe)) { + priv->s_pipe->destroy(priv->s_pipe); + priv->s_pipe = NULL; + return OMX_ErrorInsufficientResources; + } + + if (!vl_compositor_init_state(&priv->cstate, priv->s_pipe)) { + vl_compositor_cleanup(&priv->compositor); + priv->s_pipe->destroy(priv->s_pipe); + priv->s_pipe = NULL; + return OMX_ErrorInsufficientResources; + } + + priv->t_pipe = screen->context_create(screen, NULL, 0); + if (!priv->t_pipe) + return OMX_ErrorInsufficientResources; + + priv->sPortTypesParam[OMX_PortDomainVideo].nStartPortNumber = 0; + priv->sPortTypesParam[OMX_PortDomainVideo].nPorts = 2; + priv->ports = CALLOC(2, sizeof(omx_base_PortType *)); + if (!priv->ports) + return OMX_ErrorInsufficientResources; + + for (i = 0; i < 2; ++i) { + priv->ports[i] = CALLOC(1, sizeof(omx_base_video_PortType)); + if (!priv->ports[i]) + return OMX_ErrorInsufficientResources; + + base_video_port_Constructor(comp, &priv->ports[i], i, i == 0); + } + + port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX]; + port->sPortParam.format.video.nFrameWidth = 176; + port->sPortParam.format.video.nFrameHeight = 144; + port->sPortParam.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar; + port->sVideoParam.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar; + port->sPortParam.nBufferCountActual = 8; + port->sPortParam.nBufferCountMin = 4; + + port->Port_SendBufferFunction = vid_enc_EncodeFrame; + port->Port_AllocateBuffer = vid_enc_AllocateInBuffer; + port->Port_UseBuffer = vid_enc_UseInBuffer; + port->Port_FreeBuffer = vid_enc_FreeInBuffer; + + port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX]; + strcpy(port->sPortParam.format.video.cMIMEType,"video/H264"); + port->sPortParam.format.video.nFrameWidth = 176; + port->sPortParam.format.video.nFrameHeight = 144; + port->sPortParam.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC; + port->sVideoParam.eCompressionFormat = OMX_VIDEO_CodingAVC; + + port->Port_AllocateBuffer = vid_enc_AllocateOutBuffer; + port->Port_FreeBuffer = vid_enc_FreeOutBuffer; + + priv->bitrate.eControlRate = OMX_Video_ControlRateDisable; + priv->bitrate.nTargetBitrate = 0; + + priv->quant.nQpI = OMX_VID_ENC_QUANT_I_FRAMES_DEFAULT; + priv->quant.nQpP = OMX_VID_ENC_QUANT_P_FRAMES_DEFAULT; + priv->quant.nQpB = OMX_VID_ENC_QUANT_B_FRAMES_DEFAULT; + + priv->profile_level.eProfile = OMX_VIDEO_AVCProfileBaseline; + priv->profile_level.eLevel = OMX_VIDEO_AVCLevel51; + + priv->force_pic_type.IntraRefreshVOP = OMX_FALSE; + priv->frame_num = 0; + priv->pic_order_cnt = 0; + priv->restricted_b_frames = debug_get_bool_option("OMX_USE_RESTRICTED_B_FRAMES", FALSE); + + priv->scale.xWidth = OMX_VID_ENC_SCALING_WIDTH_DEFAULT; + priv->scale.xHeight = OMX_VID_ENC_SCALING_WIDTH_DEFAULT; + + LIST_INITHEAD(&priv->free_tasks); + LIST_INITHEAD(&priv->used_tasks); + LIST_INITHEAD(&priv->b_frames); + LIST_INITHEAD(&priv->stacked_tasks); + + return OMX_ErrorNone; +} + +static OMX_ERRORTYPE vid_enc_Destructor(OMX_COMPONENTTYPE *comp) +{ + vid_enc_PrivateType* priv = comp->pComponentPrivate; + int i; + + enc_ReleaseTasks(&priv->free_tasks); + enc_ReleaseTasks(&priv->used_tasks); + enc_ReleaseTasks(&priv->b_frames); + enc_ReleaseTasks(&priv->stacked_tasks); + + if (priv->ports) { + for (i = 0; i < priv->sPortTypesParam[OMX_PortDomainVideo].nPorts; ++i) { + if(priv->ports[i]) + priv->ports[i]->PortDestructor(priv->ports[i]); + } + FREE(priv->ports); + priv->ports=NULL; + } + + for (i = 0; i < OMX_VID_ENC_NUM_SCALING_BUFFERS; ++i) + if (priv->scale_buffer[i]) + priv->scale_buffer[i]->destroy(priv->scale_buffer[i]); + + if (priv->s_pipe) { + vl_compositor_cleanup_state(&priv->cstate); + vl_compositor_cleanup(&priv->compositor); + priv->s_pipe->destroy(priv->s_pipe); + } + + if (priv->t_pipe) + priv->t_pipe->destroy(priv->t_pipe); + + if (priv->screen) + omx_put_screen(); + + return omx_workaround_Destructor(comp); +} + +static OMX_ERRORTYPE enc_AllocateBackTexture(omx_base_PortType *port, + struct pipe_resource **resource, + struct pipe_transfer **transfer, + OMX_U8 **map) +{ + OMX_COMPONENTTYPE* comp = port->standCompContainer; + vid_enc_PrivateType *priv = comp->pComponentPrivate; + struct pipe_resource buf_templ; + struct pipe_box box = {}; + OMX_U8 *ptr; + + memset(&buf_templ, 0, sizeof buf_templ); + buf_templ.target = PIPE_TEXTURE_2D; + buf_templ.format = PIPE_FORMAT_I8_UNORM; + buf_templ.bind = PIPE_BIND_LINEAR; + buf_templ.usage = PIPE_USAGE_STAGING; + buf_templ.flags = 0; + buf_templ.width0 = port->sPortParam.format.video.nFrameWidth; + buf_templ.height0 = port->sPortParam.format.video.nFrameHeight * 3 / 2; + buf_templ.depth0 = 1; + buf_templ.array_size = 1; + + *resource = priv->s_pipe->screen->resource_create(priv->s_pipe->screen, &buf_templ); + if (!*resource) + return OMX_ErrorInsufficientResources; + + box.width = (*resource)->width0; + box.height = (*resource)->height0; + box.depth = (*resource)->depth0; + ptr = priv->s_pipe->transfer_map(priv->s_pipe, *resource, 0, PIPE_TRANSFER_WRITE, &box, transfer); + if (map) + *map = ptr; + + return OMX_ErrorNone; +} + +static OMX_ERRORTYPE vid_enc_SetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param) +{ + OMX_COMPONENTTYPE *comp = handle; + vid_enc_PrivateType *priv = comp->pComponentPrivate; + OMX_ERRORTYPE r; + + if (!param) + return OMX_ErrorBadParameter; + + switch(idx) { + case OMX_IndexParamPortDefinition: { + OMX_PARAM_PORTDEFINITIONTYPE *def = param; + + r = omx_base_component_SetParameter(handle, idx, param); + if (r) + return r; + + if (def->nPortIndex == OMX_BASE_FILTER_INPUTPORT_INDEX) { + omx_base_video_PortType *port; + unsigned framesize; + struct pipe_resource *resource; + struct pipe_transfer *transfer; + + port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX]; + enc_AllocateBackTexture(priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX], + &resource, &transfer, NULL); + port->sPortParam.format.video.nStride = transfer->stride; + pipe_transfer_unmap(priv->s_pipe, transfer); + pipe_resource_reference(&resource, NULL); + + framesize = port->sPortParam.format.video.nStride * + port->sPortParam.format.video.nFrameHeight; + port->sPortParam.format.video.nSliceHeight = port->sPortParam.format.video.nFrameHeight; + port->sPortParam.nBufferSize = framesize * 3 / 2; + + port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX]; + port->sPortParam.nBufferSize = framesize * 512 / (16*16); + + priv->frame_rate = def->format.video.xFramerate; + + priv->callbacks->EventHandler(comp, priv->callbackData, OMX_EventPortSettingsChanged, + OMX_BASE_FILTER_OUTPUTPORT_INDEX, 0, NULL); + } + break; + } + case OMX_IndexParamStandardComponentRole: { + OMX_PARAM_COMPONENTROLETYPE *role = param; + + r = checkHeader(param, sizeof(OMX_PARAM_COMPONENTROLETYPE)); + if (r) + return r; + + if (strcmp((char *)role->cRole, OMX_VID_ENC_AVC_ROLE)) { + return OMX_ErrorBadParameter; + } + + break; + } + case OMX_IndexParamVideoBitrate: { + OMX_VIDEO_PARAM_BITRATETYPE *bitrate = param; + + r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_BITRATETYPE)); + if (r) + return r; + + priv->bitrate = *bitrate; + + break; + } + case OMX_IndexParamVideoQuantization: { + OMX_VIDEO_PARAM_QUANTIZATIONTYPE *quant = param; + + r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_QUANTIZATIONTYPE)); + if (r) + return r; + + priv->quant = *quant; + + break; + } + case OMX_IndexParamVideoProfileLevelCurrent: { + OMX_VIDEO_PARAM_PROFILELEVELTYPE *profile_level = param; + + r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_PROFILELEVELTYPE)); + if (r) + return r; + + priv->profile_level = *profile_level; + + break; + } + default: + return omx_base_component_SetParameter(handle, idx, param); + } + return OMX_ErrorNone; +} + +static OMX_ERRORTYPE vid_enc_GetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param) +{ + OMX_COMPONENTTYPE *comp = handle; + vid_enc_PrivateType *priv = comp->pComponentPrivate; + OMX_ERRORTYPE r; + + if (!param) + return OMX_ErrorBadParameter; + + switch(idx) { + case OMX_IndexParamStandardComponentRole: { + OMX_PARAM_COMPONENTROLETYPE *role = param; + + r = checkHeader(param, sizeof(OMX_PARAM_COMPONENTROLETYPE)); + if (r) + return r; + + strcpy((char *)role->cRole, OMX_VID_ENC_AVC_ROLE); + break; + } + case OMX_IndexParamVideoInit: + r = checkHeader(param, sizeof(OMX_PORT_PARAM_TYPE)); + if (r) + return r; + + memcpy(param, &priv->sPortTypesParam[OMX_PortDomainVideo], sizeof(OMX_PORT_PARAM_TYPE)); + break; + + case OMX_IndexParamVideoPortFormat: { + OMX_VIDEO_PARAM_PORTFORMATTYPE *format = param; + omx_base_video_PortType *port; + + r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE)); + if (r) + return r; + + if (format->nPortIndex > 1) + return OMX_ErrorBadPortIndex; + if (format->nIndex >= 1) + return OMX_ErrorNoMore; + + port = (omx_base_video_PortType *)priv->ports[format->nPortIndex]; + memcpy(format, &port->sVideoParam, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE)); + break; + } + case OMX_IndexParamVideoBitrate: { + OMX_VIDEO_PARAM_BITRATETYPE *bitrate = param; + + r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_BITRATETYPE)); + if (r) + return r; + + bitrate->eControlRate = priv->bitrate.eControlRate; + bitrate->nTargetBitrate = priv->bitrate.nTargetBitrate; + + break; + } + case OMX_IndexParamVideoQuantization: { + OMX_VIDEO_PARAM_QUANTIZATIONTYPE *quant = param; + + r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_QUANTIZATIONTYPE)); + if (r) + return r; + + quant->nQpI = priv->quant.nQpI; + quant->nQpP = priv->quant.nQpP; + quant->nQpB = priv->quant.nQpB; + + break; + } + case OMX_IndexParamVideoProfileLevelCurrent: { + OMX_VIDEO_PARAM_PROFILELEVELTYPE *profile_level = param; + + r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_PROFILELEVELTYPE)); + if (r) + return r; + + profile_level->eProfile = priv->profile_level.eProfile; + profile_level->eLevel = priv->profile_level.eLevel; + + break; + } + default: + return omx_base_component_GetParameter(handle, idx, param); + } + return OMX_ErrorNone; +} + +static OMX_ERRORTYPE vid_enc_SetConfig(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR config) +{ + OMX_COMPONENTTYPE *comp = handle; + vid_enc_PrivateType *priv = comp->pComponentPrivate; + OMX_ERRORTYPE r; + int i; + + if (!config) + return OMX_ErrorBadParameter; + + switch(idx) { + case OMX_IndexConfigVideoIntraVOPRefresh: { + OMX_CONFIG_INTRAREFRESHVOPTYPE *type = config; + + r = checkHeader(config, sizeof(OMX_CONFIG_INTRAREFRESHVOPTYPE)); + if (r) + return r; + + priv->force_pic_type = *type; + + break; + } + case OMX_IndexConfigCommonScale: { + OMX_CONFIG_SCALEFACTORTYPE *scale = config; + + r = checkHeader(config, sizeof(OMX_CONFIG_SCALEFACTORTYPE)); + if (r) + return r; + + if (scale->xWidth < 176 || scale->xHeight < 144) + return OMX_ErrorBadParameter; + + for (i = 0; i < OMX_VID_ENC_NUM_SCALING_BUFFERS; ++i) { + if (priv->scale_buffer[i]) { + priv->scale_buffer[i]->destroy(priv->scale_buffer[i]); + priv->scale_buffer[i] = NULL; + } + } + + priv->scale = *scale; + if (priv->scale.xWidth != 0xffffffff && priv->scale.xHeight != 0xffffffff) { + struct pipe_video_buffer templat = {}; + + templat.buffer_format = PIPE_FORMAT_NV12; + templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420; + templat.width = priv->scale.xWidth; + templat.height = priv->scale.xHeight; + templat.interlaced = false; + for (i = 0; i < OMX_VID_ENC_NUM_SCALING_BUFFERS; ++i) { + priv->scale_buffer[i] = priv->s_pipe->create_video_buffer(priv->s_pipe, &templat); + if (!priv->scale_buffer[i]) + return OMX_ErrorInsufficientResources; + } + } + + break; + } + default: + return omx_base_component_SetConfig(handle, idx, config); + } + + return OMX_ErrorNone; +} + +static OMX_ERRORTYPE vid_enc_GetConfig(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR config) +{ + OMX_COMPONENTTYPE *comp = handle; + vid_enc_PrivateType *priv = comp->pComponentPrivate; + OMX_ERRORTYPE r; + + if (!config) + return OMX_ErrorBadParameter; + + switch(idx) { + case OMX_IndexConfigCommonScale: { + OMX_CONFIG_SCALEFACTORTYPE *scale = config; + + r = checkHeader(config, sizeof(OMX_CONFIG_SCALEFACTORTYPE)); + if (r) + return r; + + scale->xWidth = priv->scale.xWidth; + scale->xHeight = priv->scale.xHeight; + + break; + } + default: + return omx_base_component_GetConfig(handle, idx, config); + } + + return OMX_ErrorNone; +} + +static enum pipe_video_profile enc_TranslateOMXProfileToPipe(unsigned omx_profile) +{ + switch (omx_profile) { + case OMX_VIDEO_AVCProfileBaseline: + return PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE; + case OMX_VIDEO_AVCProfileMain: + return PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN; + case OMX_VIDEO_AVCProfileExtended: + return PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED; + case OMX_VIDEO_AVCProfileHigh: + return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH; + case OMX_VIDEO_AVCProfileHigh10: + return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10; + case OMX_VIDEO_AVCProfileHigh422: + return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH422; + case OMX_VIDEO_AVCProfileHigh444: + return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH444; + default: + return PIPE_VIDEO_PROFILE_UNKNOWN; + } +} + +static unsigned enc_TranslateOMXLevelToPipe(unsigned omx_level) +{ + switch (omx_level) { + case OMX_VIDEO_AVCLevel1: + case OMX_VIDEO_AVCLevel1b: + return 10; + case OMX_VIDEO_AVCLevel11: + return 11; + case OMX_VIDEO_AVCLevel12: + return 12; + case OMX_VIDEO_AVCLevel13: + return 13; + case OMX_VIDEO_AVCLevel2: + return 20; + case OMX_VIDEO_AVCLevel21: + return 21; + case OMX_VIDEO_AVCLevel22: + return 22; + case OMX_VIDEO_AVCLevel3: + return 30; + case OMX_VIDEO_AVCLevel31: + return 31; + case OMX_VIDEO_AVCLevel32: + return 32; + case OMX_VIDEO_AVCLevel4: + return 40; + case OMX_VIDEO_AVCLevel41: + return 41; + default: + case OMX_VIDEO_AVCLevel42: + return 42; + case OMX_VIDEO_AVCLevel5: + return 50; + case OMX_VIDEO_AVCLevel51: + return 51; + } +} + +static OMX_ERRORTYPE vid_enc_MessageHandler(OMX_COMPONENTTYPE* comp, internalRequestMessageType *msg) +{ + vid_enc_PrivateType* priv = comp->pComponentPrivate; + + if (msg->messageType == OMX_CommandStateSet) { + if ((msg->messageParam == OMX_StateIdle ) && (priv->state == OMX_StateLoaded)) { + + struct pipe_video_codec templat = {}; + omx_base_video_PortType *port; + + port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX]; + + templat.profile = enc_TranslateOMXProfileToPipe(priv->profile_level.eProfile); + templat.level = enc_TranslateOMXLevelToPipe(priv->profile_level.eLevel); + templat.entrypoint = PIPE_VIDEO_ENTRYPOINT_ENCODE; + templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420; + templat.width = priv->scale_buffer[priv->current_scale_buffer] ? + priv->scale.xWidth : port->sPortParam.format.video.nFrameWidth; + templat.height = priv->scale_buffer[priv->current_scale_buffer] ? + priv->scale.xHeight : port->sPortParam.format.video.nFrameHeight; + + if (templat.profile == PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE) { + struct pipe_screen *screen = priv->screen->pscreen; + templat.max_references = 1; + priv->stacked_frames_num = + screen->get_video_param(screen, + PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH, + PIPE_VIDEO_ENTRYPOINT_ENCODE, + PIPE_VIDEO_CAP_STACKED_FRAMES); + } else { + templat.max_references = OMX_VID_ENC_P_PERIOD_DEFAULT; + priv->stacked_frames_num = 1; + } + priv->codec = priv->s_pipe->create_video_codec(priv->s_pipe, &templat); + + } else if ((msg->messageParam == OMX_StateLoaded) && (priv->state == OMX_StateIdle)) { + if (priv->codec) { + priv->codec->destroy(priv->codec); + priv->codec = NULL; + } + } + } + + return omx_base_component_MessageHandler(comp, msg); +} + +static OMX_ERRORTYPE vid_enc_AllocateInBuffer(omx_base_PortType *port, OMX_INOUT OMX_BUFFERHEADERTYPE **buf, + OMX_IN OMX_U32 idx, OMX_IN OMX_PTR private, OMX_IN OMX_U32 size) +{ + struct input_buf_private *inp; + OMX_ERRORTYPE r; + + r = base_port_AllocateBuffer(port, buf, idx, private, size); + if (r) + return r; + + inp = (*buf)->pInputPortPrivate = CALLOC_STRUCT(input_buf_private); + if (!inp) { + base_port_FreeBuffer(port, idx, *buf); + return OMX_ErrorInsufficientResources; + } + + LIST_INITHEAD(&inp->tasks); + + FREE((*buf)->pBuffer); + r = enc_AllocateBackTexture(port, &inp->resource, &inp->transfer, &(*buf)->pBuffer); + if (r) { + FREE(inp); + base_port_FreeBuffer(port, idx, *buf); + return r; + } + + return OMX_ErrorNone; +} + +static OMX_ERRORTYPE vid_enc_UseInBuffer(omx_base_PortType *port, OMX_BUFFERHEADERTYPE **buf, OMX_U32 idx, + OMX_PTR private, OMX_U32 size, OMX_U8 *mem) +{ + struct input_buf_private *inp; + OMX_ERRORTYPE r; + + r = base_port_UseBuffer(port, buf, idx, private, size, mem); + if (r) + return r; + + inp = (*buf)->pInputPortPrivate = CALLOC_STRUCT(input_buf_private); + if (!inp) { + base_port_FreeBuffer(port, idx, *buf); + return OMX_ErrorInsufficientResources; + } + + LIST_INITHEAD(&inp->tasks); + + return OMX_ErrorNone; +} + +static OMX_ERRORTYPE vid_enc_FreeInBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf) +{ + OMX_COMPONENTTYPE* comp = port->standCompContainer; + vid_enc_PrivateType *priv = comp->pComponentPrivate; + struct input_buf_private *inp = buf->pInputPortPrivate; + + if (inp) { + enc_ReleaseTasks(&inp->tasks); + if (inp->transfer) + pipe_transfer_unmap(priv->s_pipe, inp->transfer); + pipe_resource_reference(&inp->resource, NULL); + FREE(inp); + } + buf->pBuffer = NULL; + + return base_port_FreeBuffer(port, idx, buf); +} + +static OMX_ERRORTYPE vid_enc_AllocateOutBuffer(omx_base_PortType *port, OMX_INOUT OMX_BUFFERHEADERTYPE **buf, + OMX_IN OMX_U32 idx, OMX_IN OMX_PTR private, OMX_IN OMX_U32 size) +{ + OMX_ERRORTYPE r; + + r = base_port_AllocateBuffer(port, buf, idx, private, size); + if (r) + return r; + + FREE((*buf)->pBuffer); + (*buf)->pBuffer = NULL; + (*buf)->pOutputPortPrivate = CALLOC(1, sizeof(struct output_buf_private)); + if (!(*buf)->pOutputPortPrivate) { + base_port_FreeBuffer(port, idx, *buf); + return OMX_ErrorInsufficientResources; + } + + return OMX_ErrorNone; +} + +static OMX_ERRORTYPE vid_enc_FreeOutBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf) +{ + OMX_COMPONENTTYPE* comp = port->standCompContainer; + vid_enc_PrivateType *priv = comp->pComponentPrivate; + + if (buf->pOutputPortPrivate) { + struct output_buf_private *outp = buf->pOutputPortPrivate; + if (outp->transfer) + pipe_transfer_unmap(priv->t_pipe, outp->transfer); + pipe_resource_reference(&outp->bitstream, NULL); + FREE(outp); + buf->pOutputPortPrivate = NULL; + } + buf->pBuffer = NULL; + + return base_port_FreeBuffer(port, idx, buf); +} + +static struct encode_task *enc_NeedTask(omx_base_PortType *port) +{ + OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video; + OMX_COMPONENTTYPE* comp = port->standCompContainer; + vid_enc_PrivateType *priv = comp->pComponentPrivate; + + struct pipe_video_buffer templat = {}; + struct encode_task *task; + + if (!LIST_IS_EMPTY(&priv->free_tasks)) { + task = LIST_ENTRY(struct encode_task, priv->free_tasks.next, list); + LIST_DEL(&task->list); + return task; + } + + /* allocate a new one */ + task = CALLOC_STRUCT(encode_task); + if (!task) + return NULL; + + templat.buffer_format = PIPE_FORMAT_NV12; + templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420; + templat.width = def->nFrameWidth; + templat.height = def->nFrameHeight; + templat.interlaced = false; + + task->buf = priv->s_pipe->create_video_buffer(priv->s_pipe, &templat); + if (!task->buf) { + FREE(task); + return NULL; + } + + return task; +} + +static void enc_MoveTasks(struct list_head *from, struct list_head *to) +{ + to->prev->next = from->next; + from->next->prev = to->prev; + from->prev->next = to; + to->prev = from->prev; + LIST_INITHEAD(from); +} + +static void enc_ReleaseTasks(struct list_head *head) +{ + struct encode_task *i, *next; + + if (!head || !head->next) + return; + + LIST_FOR_EACH_ENTRY_SAFE(i, next, head, list) { + pipe_resource_reference(&i->bitstream, NULL); + i->buf->destroy(i->buf); + FREE(i); + } +} + +static OMX_ERRORTYPE enc_LoadImage(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf, + struct pipe_video_buffer *vbuf) +{ + OMX_COMPONENTTYPE* comp = port->standCompContainer; + vid_enc_PrivateType *priv = comp->pComponentPrivate; + OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video; + struct pipe_box box = {}; + struct input_buf_private *inp = buf->pInputPortPrivate; + + if (!inp->resource) { + struct pipe_sampler_view **views; + void *ptr; + + views = vbuf->get_sampler_view_planes(vbuf); + if (!views) + return OMX_ErrorInsufficientResources; + + ptr = buf->pBuffer; + box.width = def->nFrameWidth; + box.height = def->nFrameHeight; + box.depth = 1; + priv->s_pipe->texture_subdata(priv->s_pipe, views[0]->texture, 0, + PIPE_TRANSFER_WRITE, &box, + ptr, def->nStride, 0); + ptr = ((uint8_t*)buf->pBuffer) + (def->nStride * box.height); + box.width = def->nFrameWidth / 2; + box.height = def->nFrameHeight / 2; + box.depth = 1; + priv->s_pipe->texture_subdata(priv->s_pipe, views[1]->texture, 0, + PIPE_TRANSFER_WRITE, &box, + ptr, def->nStride, 0); + } else { + struct pipe_blit_info blit; + struct vl_video_buffer *dst_buf = (struct vl_video_buffer *)vbuf; + + pipe_transfer_unmap(priv->s_pipe, inp->transfer); + + box.width = def->nFrameWidth; + box.height = def->nFrameHeight; + box.depth = 1; + + priv->s_pipe->resource_copy_region(priv->s_pipe, + dst_buf->resources[0], + 0, 0, 0, 0, inp->resource, 0, &box); + + memset(&blit, 0, sizeof(blit)); + blit.src.resource = inp->resource; + blit.src.format = inp->resource->format; + + blit.src.box.x = 0; + blit.src.box.y = def->nFrameHeight; + blit.src.box.width = def->nFrameWidth; + blit.src.box.height = def->nFrameHeight / 2 ; + blit.src.box.depth = 1; + + blit.dst.resource = dst_buf->resources[1]; + blit.dst.format = blit.dst.resource->format; + + blit.dst.box.width = def->nFrameWidth / 2; + blit.dst.box.height = def->nFrameHeight / 2; + blit.dst.box.depth = 1; + blit.filter = PIPE_TEX_FILTER_NEAREST; + + blit.mask = PIPE_MASK_G; + priv->s_pipe->blit(priv->s_pipe, &blit); + + blit.src.box.x = 1; + blit.mask = PIPE_MASK_R; + priv->s_pipe->blit(priv->s_pipe, &blit); + priv->s_pipe->flush(priv->s_pipe, NULL, 0); + + box.width = inp->resource->width0; + box.height = inp->resource->height0; + box.depth = inp->resource->depth0; + buf->pBuffer = priv->s_pipe->transfer_map(priv->s_pipe, inp->resource, 0, + PIPE_TRANSFER_WRITE, &box, + &inp->transfer); + } + + return OMX_ErrorNone; +} + +static void enc_ScaleInput(omx_base_PortType *port, struct pipe_video_buffer **vbuf, unsigned *size) +{ + OMX_COMPONENTTYPE* comp = port->standCompContainer; + vid_enc_PrivateType *priv = comp->pComponentPrivate; + OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video; + struct pipe_video_buffer *src_buf = *vbuf; + struct vl_compositor *compositor = &priv->compositor; + struct vl_compositor_state *s = &priv->cstate; + struct pipe_sampler_view **views; + struct pipe_surface **dst_surface; + unsigned i; + + if (!priv->scale_buffer[priv->current_scale_buffer]) + return; + + views = src_buf->get_sampler_view_planes(src_buf); + dst_surface = priv->scale_buffer[priv->current_scale_buffer]->get_surfaces + (priv->scale_buffer[priv->current_scale_buffer]); + vl_compositor_clear_layers(s); + + for (i = 0; i < VL_MAX_SURFACES; ++i) { + struct u_rect src_rect; + if (!views[i] || !dst_surface[i]) + continue; + src_rect.x0 = 0; + src_rect.y0 = 0; + src_rect.x1 = def->nFrameWidth; + src_rect.y1 = def->nFrameHeight; + if (i > 0) { + src_rect.x1 /= 2; + src_rect.y1 /= 2; + } + vl_compositor_set_rgba_layer(s, compositor, 0, views[i], &src_rect, NULL, NULL); + vl_compositor_render(s, compositor, dst_surface[i], NULL, false); + } + *size = priv->scale.xWidth * priv->scale.xHeight * 2; + *vbuf = priv->scale_buffer[priv->current_scale_buffer++]; + priv->current_scale_buffer %= OMX_VID_ENC_NUM_SCALING_BUFFERS; +} + +static void enc_GetPictureParamPreset(struct pipe_h264_enc_picture_desc *picture) +{ + picture->motion_est.enc_disable_sub_mode = 0x000000fe; + picture->motion_est.enc_ime2_search_range_x = 0x00000001; + picture->motion_est.enc_ime2_search_range_y = 0x00000001; + picture->pic_ctrl.enc_constraint_set_flags = 0x00000040; +} + +static void enc_ControlPicture(omx_base_PortType *port, struct pipe_h264_enc_picture_desc *picture) +{ + OMX_COMPONENTTYPE* comp = port->standCompContainer; + vid_enc_PrivateType *priv = comp->pComponentPrivate; + struct pipe_h264_enc_rate_control *rate_ctrl = &picture->rate_ctrl; + + switch (priv->bitrate.eControlRate) { + case OMX_Video_ControlRateVariable: + rate_ctrl->rate_ctrl_method = PIPE_H264_ENC_RATE_CONTROL_METHOD_VARIABLE; + break; + case OMX_Video_ControlRateConstant: + rate_ctrl->rate_ctrl_method = PIPE_H264_ENC_RATE_CONTROL_METHOD_CONSTANT; + break; + case OMX_Video_ControlRateVariableSkipFrames: + rate_ctrl->rate_ctrl_method = PIPE_H264_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP; + break; + case OMX_Video_ControlRateConstantSkipFrames: + rate_ctrl->rate_ctrl_method = PIPE_H264_ENC_RATE_CONTROL_METHOD_CONSTANT_SKIP; + break; + default: + rate_ctrl->rate_ctrl_method = PIPE_H264_ENC_RATE_CONTROL_METHOD_DISABLE; + break; + } + + rate_ctrl->frame_rate_den = OMX_VID_ENC_CONTROL_FRAME_RATE_DEN_DEFAULT; + rate_ctrl->frame_rate_num = ((priv->frame_rate) >> 16) * rate_ctrl->frame_rate_den; + + if (rate_ctrl->rate_ctrl_method != PIPE_H264_ENC_RATE_CONTROL_METHOD_DISABLE) { + if (priv->bitrate.nTargetBitrate < OMX_VID_ENC_BITRATE_MIN) + rate_ctrl->target_bitrate = OMX_VID_ENC_BITRATE_MIN; + else if (priv->bitrate.nTargetBitrate < OMX_VID_ENC_BITRATE_MAX) + rate_ctrl->target_bitrate = priv->bitrate.nTargetBitrate; + else + rate_ctrl->target_bitrate = OMX_VID_ENC_BITRATE_MAX; + rate_ctrl->peak_bitrate = rate_ctrl->target_bitrate; + if (rate_ctrl->target_bitrate < OMX_VID_ENC_BITRATE_MEDIAN) + rate_ctrl->vbv_buffer_size = MIN2((rate_ctrl->target_bitrate * 2.75), OMX_VID_ENC_BITRATE_MEDIAN); + else + rate_ctrl->vbv_buffer_size = rate_ctrl->target_bitrate; + + if (rate_ctrl->frame_rate_num) { + unsigned long long t = rate_ctrl->target_bitrate; + t *= rate_ctrl->frame_rate_den; + rate_ctrl->target_bits_picture = t / rate_ctrl->frame_rate_num; + } else { + rate_ctrl->target_bits_picture = rate_ctrl->target_bitrate; + } + rate_ctrl->peak_bits_picture_integer = rate_ctrl->target_bits_picture; + rate_ctrl->peak_bits_picture_fraction = 0; + } + + picture->quant_i_frames = priv->quant.nQpI; + picture->quant_p_frames = priv->quant.nQpP; + picture->quant_b_frames = priv->quant.nQpB; + + picture->frame_num = priv->frame_num; + picture->ref_idx_l0 = priv->ref_idx_l0; + picture->ref_idx_l1 = priv->ref_idx_l1; + picture->enable_vui = (picture->rate_ctrl.frame_rate_num != 0); + enc_GetPictureParamPreset(picture); +} + +static void enc_HandleTask(omx_base_PortType *port, struct encode_task *task, + enum pipe_h264_enc_picture_type picture_type) +{ + OMX_COMPONENTTYPE* comp = port->standCompContainer; + vid_enc_PrivateType *priv = comp->pComponentPrivate; + unsigned size = priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX]->sPortParam.nBufferSize; + struct pipe_video_buffer *vbuf = task->buf; + struct pipe_h264_enc_picture_desc picture = {}; + + /* -------------- scale input image --------- */ + enc_ScaleInput(port, &vbuf, &size); + priv->s_pipe->flush(priv->s_pipe, NULL, 0); + + /* -------------- allocate output buffer --------- */ + task->bitstream = pipe_buffer_create(priv->s_pipe->screen, + PIPE_BIND_VERTEX_BUFFER, + PIPE_USAGE_STAGING, /* map for read */ + size); + + picture.picture_type = picture_type; + picture.pic_order_cnt = task->pic_order_cnt; + picture.base.profile = enc_TranslateOMXProfileToPipe(priv->profile_level.eProfile); + picture.base.entry_point = PIPE_VIDEO_ENTRYPOINT_ENCODE; + if (priv->restricted_b_frames && picture_type == PIPE_H264_ENC_PICTURE_TYPE_B) + picture.not_referenced = true; + enc_ControlPicture(port, &picture); + + /* -------------- encode frame --------- */ + priv->codec->begin_frame(priv->codec, vbuf, &picture.base); + priv->codec->encode_bitstream(priv->codec, vbuf, task->bitstream, &task->feedback); + priv->codec->end_frame(priv->codec, vbuf, &picture.base); +} + +static void enc_ClearBframes(omx_base_PortType *port, struct input_buf_private *inp) +{ + OMX_COMPONENTTYPE* comp = port->standCompContainer; + vid_enc_PrivateType *priv = comp->pComponentPrivate; + struct encode_task *task; + + if (LIST_IS_EMPTY(&priv->b_frames)) + return; + + task = LIST_ENTRY(struct encode_task, priv->b_frames.prev, list); + LIST_DEL(&task->list); + + /* promote last from to P frame */ + priv->ref_idx_l0 = priv->ref_idx_l1; + enc_HandleTask(port, task, PIPE_H264_ENC_PICTURE_TYPE_P); + LIST_ADDTAIL(&task->list, &inp->tasks); + priv->ref_idx_l1 = priv->frame_num++; + + /* handle B frames */ + LIST_FOR_EACH_ENTRY(task, &priv->b_frames, list) { + enc_HandleTask(port, task, PIPE_H264_ENC_PICTURE_TYPE_B); + if (!priv->restricted_b_frames) + priv->ref_idx_l0 = priv->frame_num; + priv->frame_num++; + } + + enc_MoveTasks(&priv->b_frames, &inp->tasks); +} + +static OMX_ERRORTYPE vid_enc_EncodeFrame(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf) +{ + OMX_COMPONENTTYPE* comp = port->standCompContainer; + vid_enc_PrivateType *priv = comp->pComponentPrivate; + struct input_buf_private *inp = buf->pInputPortPrivate; + enum pipe_h264_enc_picture_type picture_type; + struct encode_task *task; + unsigned stacked_num = 0; + OMX_ERRORTYPE err; + + enc_MoveTasks(&inp->tasks, &priv->free_tasks); + task = enc_NeedTask(port); + if (!task) + return OMX_ErrorInsufficientResources; + + if (buf->nFilledLen == 0) { + if (buf->nFlags & OMX_BUFFERFLAG_EOS) { + buf->nFilledLen = buf->nAllocLen; + enc_ClearBframes(port, inp); + enc_MoveTasks(&priv->stacked_tasks, &inp->tasks); + priv->codec->flush(priv->codec); + } + return base_port_SendBufferFunction(port, buf); + } + + if (buf->pOutputPortPrivate) { + struct pipe_video_buffer *vbuf = buf->pOutputPortPrivate; + buf->pOutputPortPrivate = task->buf; + task->buf = vbuf; + } else { + /* ------- load input image into video buffer ---- */ + err = enc_LoadImage(port, buf, task->buf); + if (err != OMX_ErrorNone) { + FREE(task); + return err; + } + } + + /* -------------- determine picture type --------- */ + if (!(priv->pic_order_cnt % OMX_VID_ENC_IDR_PERIOD_DEFAULT) || + priv->force_pic_type.IntraRefreshVOP) { + enc_ClearBframes(port, inp); + picture_type = PIPE_H264_ENC_PICTURE_TYPE_IDR; + priv->force_pic_type.IntraRefreshVOP = OMX_FALSE; + priv->frame_num = 0; + } else if (priv->codec->profile == PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE || + !(priv->pic_order_cnt % OMX_VID_ENC_P_PERIOD_DEFAULT) || + (buf->nFlags & OMX_BUFFERFLAG_EOS)) { + picture_type = PIPE_H264_ENC_PICTURE_TYPE_P; + } else { + picture_type = PIPE_H264_ENC_PICTURE_TYPE_B; + } + + task->pic_order_cnt = priv->pic_order_cnt++; + + if (picture_type == PIPE_H264_ENC_PICTURE_TYPE_B) { + /* put frame at the tail of the queue */ + LIST_ADDTAIL(&task->list, &priv->b_frames); + } else { + /* handle I or P frame */ + priv->ref_idx_l0 = priv->ref_idx_l1; + enc_HandleTask(port, task, picture_type); + LIST_ADDTAIL(&task->list, &priv->stacked_tasks); + LIST_FOR_EACH_ENTRY(task, &priv->stacked_tasks, list) { + ++stacked_num; + } + if (stacked_num == priv->stacked_frames_num) { + struct encode_task *t; + t = LIST_ENTRY(struct encode_task, priv->stacked_tasks.next, list); + LIST_DEL(&t->list); + LIST_ADDTAIL(&t->list, &inp->tasks); + } + priv->ref_idx_l1 = priv->frame_num++; + + /* handle B frames */ + LIST_FOR_EACH_ENTRY(task, &priv->b_frames, list) { + enc_HandleTask(port, task, PIPE_H264_ENC_PICTURE_TYPE_B); + if (!priv->restricted_b_frames) + priv->ref_idx_l0 = priv->frame_num; + priv->frame_num++; + } + + enc_MoveTasks(&priv->b_frames, &inp->tasks); + } + + if (LIST_IS_EMPTY(&inp->tasks)) + return port->ReturnBufferFunction(port, buf); + else + return base_port_SendBufferFunction(port, buf); +} + +static void vid_enc_BufferEncoded(OMX_COMPONENTTYPE *comp, OMX_BUFFERHEADERTYPE* input, OMX_BUFFERHEADERTYPE* output) +{ + vid_enc_PrivateType *priv = comp->pComponentPrivate; + struct output_buf_private *outp = output->pOutputPortPrivate; + struct input_buf_private *inp = input->pInputPortPrivate; + struct encode_task *task; + struct pipe_box box = {}; + unsigned size; + + if (!inp || LIST_IS_EMPTY(&inp->tasks)) { + input->nFilledLen = 0; /* mark buffer as empty */ + enc_MoveTasks(&priv->used_tasks, &inp->tasks); + return; + } + + task = LIST_ENTRY(struct encode_task, inp->tasks.next, list); + LIST_DEL(&task->list); + LIST_ADDTAIL(&task->list, &priv->used_tasks); + + if (!task->bitstream) + return; + + /* ------------- map result buffer ----------------- */ + + if (outp->transfer) + pipe_transfer_unmap(priv->t_pipe, outp->transfer); + + pipe_resource_reference(&outp->bitstream, task->bitstream); + pipe_resource_reference(&task->bitstream, NULL); + + box.width = outp->bitstream->width0; + box.height = outp->bitstream->height0; + box.depth = outp->bitstream->depth0; + + output->pBuffer = priv->t_pipe->transfer_map(priv->t_pipe, outp->bitstream, 0, + PIPE_TRANSFER_READ_WRITE, + &box, &outp->transfer); + + /* ------------- get size of result ----------------- */ + + priv->codec->get_feedback(priv->codec, task->feedback, &size); + + output->nOffset = 0; + output->nFilledLen = size; /* mark buffer as full */ + + /* all output buffers contain exactly one frame */ + output->nFlags = OMX_BUFFERFLAG_ENDOFFRAME; +} diff --git a/src/gallium/state_trackers/omx/bellagio/vid_enc.h b/src/gallium/state_trackers/omx/bellagio/vid_enc.h new file mode 100644 index 00000000000..0a215031c8b --- /dev/null +++ b/src/gallium/state_trackers/omx/bellagio/vid_enc.h @@ -0,0 +1,96 @@ +/************************************************************************** + * + * Copyright 2013 Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* + * Authors: + * Christian König <[email protected]> + * + */ + +#ifndef OMX_VID_ENC_H +#define OMX_VID_ENC_H + +#include <OMX_Types.h> +#include <OMX_Component.h> +#include <OMX_Core.h> + +#include <bellagio/st_static_component_loader.h> +#include <bellagio/omx_base_filter.h> + +#include "util/list.h" + +#include "vl/vl_defines.h" +#include "vl/vl_compositor.h" + +#define OMX_VID_ENC_BASE_NAME "OMX.mesa.video_encoder" +#define OMX_VID_ENC_AVC_NAME "OMX.mesa.video_encoder.avc" +#define OMX_VID_ENC_AVC_ROLE "video_encoder.avc" + +#define OMX_VID_ENC_BITRATE_MIN 64000 +#define OMX_VID_ENC_BITRATE_MEDIAN 2000000 +#define OMX_VID_ENC_BITRATE_MAX 240000000 +#define OMX_VID_ENC_CONTROL_FRAME_RATE_DEN_DEFAULT 1001 +#define OMX_VID_ENC_QUANT_I_FRAMES_DEFAULT 0x1c +#define OMX_VID_ENC_QUANT_P_FRAMES_DEFAULT 0x1c +#define OMX_VID_ENC_QUANT_B_FRAMES_DEFAULT 0x1c +#define OMX_VID_ENC_SCALING_WIDTH_DEFAULT 0xffffffff +#define OMX_VID_ENC_SCALING_HEIGHT_DEFAULT 0xffffffff +#define OMX_VID_ENC_IDR_PERIOD_DEFAULT 1000 +#define OMX_VID_ENC_P_PERIOD_DEFAULT 3 + +#define OMX_VID_ENC_NUM_SCALING_BUFFERS 4 + +DERIVEDCLASS(vid_enc_PrivateType, omx_base_filter_PrivateType) +#define vid_enc_PrivateType_FIELDS omx_base_filter_PrivateType_FIELDS \ + struct vl_screen *screen; \ + struct pipe_context *s_pipe; \ + struct pipe_context *t_pipe; \ + struct pipe_video_codec *codec; \ + struct list_head free_tasks; \ + struct list_head used_tasks; \ + struct list_head b_frames; \ + struct list_head stacked_tasks; \ + OMX_U32 frame_rate; \ + OMX_U32 frame_num; \ + OMX_U32 pic_order_cnt; \ + OMX_U32 ref_idx_l0, ref_idx_l1; \ + OMX_BOOL restricted_b_frames; \ + OMX_VIDEO_PARAM_BITRATETYPE bitrate; \ + OMX_VIDEO_PARAM_QUANTIZATIONTYPE quant; \ + OMX_VIDEO_PARAM_PROFILELEVELTYPE profile_level; \ + OMX_CONFIG_INTRAREFRESHVOPTYPE force_pic_type; \ + struct vl_compositor compositor; \ + struct vl_compositor_state cstate; \ + struct pipe_video_buffer *scale_buffer[OMX_VID_ENC_NUM_SCALING_BUFFERS]; \ + OMX_CONFIG_SCALEFACTORTYPE scale; \ + OMX_U32 current_scale_buffer; \ + OMX_U32 stacked_frames_num; +ENDCLASS(vid_enc_PrivateType) + +OMX_ERRORTYPE vid_enc_LoaderComponent(stLoaderComponentType *comp); + +#endif diff --git a/src/gallium/state_trackers/omx/meson.build b/src/gallium/state_trackers/omx/meson.build new file mode 100644 index 00000000000..d17332553ff --- /dev/null +++ b/src/gallium/state_trackers/omx/meson.build @@ -0,0 +1,38 @@ +# Copyright © 2017 Intel Corporation + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +if gallium_omx == 'bellagio' +files_omx = files( + 'bellagio/entrypoint.c', + 'bellagio/vid_dec.c', + 'bellagio/vid_dec_mpeg12.c', + 'bellagio/vid_dec_h264.c', + 'bellagio/vid_dec_h265.c', + 'bellagio/vid_enc.c' +) +endif + +libomx_st = static_library( + 'omx_st', + files_omx, + c_args : [c_vis_args], + include_directories : [inc_common], + dependencies : [dep_omx, dep_x11_xcb, dep_xcb, dep_xcb_dri2, dep_xcb_dri3], +) |