Path: blob/21.2-virgl/src/gallium/frontends/omx/bellagio/vid_enc.c
4565 views
/**************************************************************************1*2* Copyright 2013 Advanced Micro Devices, Inc.3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the7* "Software"), to deal in the Software without restriction, including8* without limitation the rights to use, copy, modify, merge, publish,9* distribute, sub license, and/or sell copies of the Software, and to10* permit persons to whom the Software is furnished to do so, subject to11* the following conditions:12*13* The above copyright notice and this permission notice (including the14* next paragraph) shall be included in all copies or substantial portions15* of the Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS18* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.20* IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR21* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,22* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE23* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.24*25**************************************************************************/2627/*28* Authors:29* Christian König <[email protected]>30*31*/323334#include <assert.h>3536#include <OMX_Video.h>3738/* bellagio defines a DEBUG macro that we don't want */39#ifndef DEBUG40#include <bellagio/omxcore.h>41#undef DEBUG42#else43#include <bellagio/omxcore.h>44#endif4546#include <bellagio/omx_base_video_port.h>4748#include "pipe/p_screen.h"49#include "pipe/p_video_codec.h"50#include "util/u_memory.h"5152#include "entrypoint.h"53#include "vid_enc.h"54#include "vid_omx_common.h"55#include "vid_enc_common.h"5657static OMX_ERRORTYPE vid_enc_Constructor(OMX_COMPONENTTYPE *comp, OMX_STRING name);58static OMX_ERRORTYPE vid_enc_Destructor(OMX_COMPONENTTYPE *comp);59static OMX_ERRORTYPE vid_enc_SetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param);60static OMX_ERRORTYPE vid_enc_GetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param);61static OMX_ERRORTYPE vid_enc_SetConfig(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR config);62static OMX_ERRORTYPE vid_enc_GetConfig(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR config);63static OMX_ERRORTYPE vid_enc_MessageHandler(OMX_COMPONENTTYPE *comp, internalRequestMessageType *msg);64static OMX_ERRORTYPE vid_enc_AllocateInBuffer(omx_base_PortType *port, OMX_INOUT OMX_BUFFERHEADERTYPE **buf,65OMX_IN OMX_U32 idx, OMX_IN OMX_PTR private, OMX_IN OMX_U32 size);66static OMX_ERRORTYPE vid_enc_UseInBuffer(omx_base_PortType *port, OMX_BUFFERHEADERTYPE **buf, OMX_U32 idx,67OMX_PTR private, OMX_U32 size, OMX_U8 *mem);68static OMX_ERRORTYPE vid_enc_FreeInBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf);69static OMX_ERRORTYPE vid_enc_EncodeFrame(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf);70static OMX_ERRORTYPE vid_enc_AllocateOutBuffer(omx_base_PortType *comp, OMX_INOUT OMX_BUFFERHEADERTYPE **buf,71OMX_IN OMX_U32 idx, OMX_IN OMX_PTR private, OMX_IN OMX_U32 size);72static OMX_ERRORTYPE vid_enc_FreeOutBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf);73static void vid_enc_BufferEncoded(OMX_COMPONENTTYPE *comp, OMX_BUFFERHEADERTYPE* input, OMX_BUFFERHEADERTYPE* output);7475OMX_ERRORTYPE vid_enc_LoaderComponent(stLoaderComponentType *comp)76{77comp->componentVersion.s.nVersionMajor = 0;78comp->componentVersion.s.nVersionMinor = 0;79comp->componentVersion.s.nRevision = 0;80comp->componentVersion.s.nStep = 1;81comp->name_specific_length = 1;82comp->constructor = vid_enc_Constructor;8384comp->name = CALLOC(1, OMX_MAX_STRINGNAME_SIZE);85if (!comp->name)86return OMX_ErrorInsufficientResources;8788comp->name_specific = CALLOC(1, sizeof(char *));89if (!comp->name_specific)90goto error_arrays;9192comp->role_specific = CALLOC(1, sizeof(char *));93if (!comp->role_specific)94goto error_arrays;9596comp->name_specific[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE);97if (comp->name_specific[0] == NULL)98goto error_specific;99100comp->role_specific[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE);101if (comp->role_specific[0] == NULL)102goto error_specific;103104strcpy(comp->name, OMX_VID_ENC_BASE_NAME);105strcpy(comp->name_specific[0], OMX_VID_ENC_AVC_NAME);106strcpy(comp->role_specific[0], OMX_VID_ENC_AVC_ROLE);107108return OMX_ErrorNone;109110error_specific:111FREE(comp->role_specific[0]);112FREE(comp->name_specific[0]);113114error_arrays:115FREE(comp->role_specific);116FREE(comp->name_specific);117118FREE(comp->name);119120return OMX_ErrorInsufficientResources;121}122123static OMX_ERRORTYPE vid_enc_Constructor(OMX_COMPONENTTYPE *comp, OMX_STRING name)124{125vid_enc_PrivateType *priv;126omx_base_video_PortType *port;127struct pipe_screen *screen;128OMX_ERRORTYPE r;129int i;130131assert(!comp->pComponentPrivate);132133priv = comp->pComponentPrivate = CALLOC(1, sizeof(vid_enc_PrivateType));134if (!priv)135return OMX_ErrorInsufficientResources;136137r = omx_base_filter_Constructor(comp, name);138if (r)139return r;140141priv->BufferMgmtCallback = vid_enc_BufferEncoded;142priv->messageHandler = vid_enc_MessageHandler;143priv->destructor = vid_enc_Destructor;144145comp->SetParameter = vid_enc_SetParameter;146comp->GetParameter = vid_enc_GetParameter;147comp->GetConfig = vid_enc_GetConfig;148comp->SetConfig = vid_enc_SetConfig;149150priv->screen = omx_get_screen();151if (!priv->screen)152return OMX_ErrorInsufficientResources;153154screen = priv->screen->pscreen;155if (!screen->get_video_param(screen, PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH,156PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_SUPPORTED))157return OMX_ErrorBadParameter;158159priv->s_pipe = pipe_create_multimedia_context(screen);160if (!priv->s_pipe)161return OMX_ErrorInsufficientResources;162163enc_InitCompute_common(priv);164165if (!vl_compositor_init(&priv->compositor, priv->s_pipe)) {166priv->s_pipe->destroy(priv->s_pipe);167priv->s_pipe = NULL;168return OMX_ErrorInsufficientResources;169}170171if (!vl_compositor_init_state(&priv->cstate, priv->s_pipe)) {172vl_compositor_cleanup(&priv->compositor);173priv->s_pipe->destroy(priv->s_pipe);174priv->s_pipe = NULL;175return OMX_ErrorInsufficientResources;176}177178priv->t_pipe = pipe_create_multimedia_context(screen);179if (!priv->t_pipe)180return OMX_ErrorInsufficientResources;181182priv->sPortTypesParam[OMX_PortDomainVideo].nStartPortNumber = 0;183priv->sPortTypesParam[OMX_PortDomainVideo].nPorts = 2;184priv->ports = CALLOC(2, sizeof(omx_base_PortType *));185if (!priv->ports)186return OMX_ErrorInsufficientResources;187188for (i = 0; i < 2; ++i) {189priv->ports[i] = CALLOC(1, sizeof(omx_base_video_PortType));190if (!priv->ports[i])191return OMX_ErrorInsufficientResources;192193base_video_port_Constructor(comp, &priv->ports[i], i, i == 0);194}195196port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX];197port->sPortParam.format.video.nFrameWidth = 176;198port->sPortParam.format.video.nFrameHeight = 144;199port->sPortParam.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;200port->sVideoParam.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;201port->sPortParam.nBufferCountActual = 8;202port->sPortParam.nBufferCountMin = 4;203204port->Port_SendBufferFunction = vid_enc_EncodeFrame;205port->Port_AllocateBuffer = vid_enc_AllocateInBuffer;206port->Port_UseBuffer = vid_enc_UseInBuffer;207port->Port_FreeBuffer = vid_enc_FreeInBuffer;208209port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX];210strcpy(port->sPortParam.format.video.cMIMEType,"video/H264");211port->sPortParam.format.video.nFrameWidth = 176;212port->sPortParam.format.video.nFrameHeight = 144;213port->sPortParam.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;214port->sVideoParam.eCompressionFormat = OMX_VIDEO_CodingAVC;215216port->Port_AllocateBuffer = vid_enc_AllocateOutBuffer;217port->Port_FreeBuffer = vid_enc_FreeOutBuffer;218219priv->bitrate.eControlRate = OMX_Video_ControlRateDisable;220priv->bitrate.nTargetBitrate = 0;221222priv->quant.nQpI = OMX_VID_ENC_QUANT_I_FRAMES_DEFAULT;223priv->quant.nQpP = OMX_VID_ENC_QUANT_P_FRAMES_DEFAULT;224priv->quant.nQpB = OMX_VID_ENC_QUANT_B_FRAMES_DEFAULT;225226priv->profile_level.eProfile = OMX_VIDEO_AVCProfileBaseline;227priv->profile_level.eLevel = OMX_VIDEO_AVCLevel51;228229priv->force_pic_type.IntraRefreshVOP = OMX_FALSE;230priv->frame_num = 0;231priv->pic_order_cnt = 0;232priv->restricted_b_frames = debug_get_bool_option("OMX_USE_RESTRICTED_B_FRAMES", FALSE);233234priv->scale.xWidth = OMX_VID_ENC_SCALING_WIDTH_DEFAULT;235priv->scale.xHeight = OMX_VID_ENC_SCALING_WIDTH_DEFAULT;236237list_inithead(&priv->free_tasks);238list_inithead(&priv->used_tasks);239list_inithead(&priv->b_frames);240list_inithead(&priv->stacked_tasks);241242return OMX_ErrorNone;243}244245static OMX_ERRORTYPE vid_enc_Destructor(OMX_COMPONENTTYPE *comp)246{247vid_enc_PrivateType* priv = comp->pComponentPrivate;248int i;249250enc_ReleaseTasks(&priv->free_tasks);251enc_ReleaseTasks(&priv->used_tasks);252enc_ReleaseTasks(&priv->b_frames);253enc_ReleaseTasks(&priv->stacked_tasks);254255if (priv->ports) {256for (i = 0; i < priv->sPortTypesParam[OMX_PortDomainVideo].nPorts; ++i) {257if(priv->ports[i])258priv->ports[i]->PortDestructor(priv->ports[i]);259}260FREE(priv->ports);261priv->ports=NULL;262}263264for (i = 0; i < OMX_VID_ENC_NUM_SCALING_BUFFERS; ++i)265if (priv->scale_buffer[i])266priv->scale_buffer[i]->destroy(priv->scale_buffer[i]);267268if (priv->s_pipe) {269vl_compositor_cleanup_state(&priv->cstate);270vl_compositor_cleanup(&priv->compositor);271enc_ReleaseCompute_common(priv);272priv->s_pipe->destroy(priv->s_pipe);273}274275if (priv->t_pipe)276priv->t_pipe->destroy(priv->t_pipe);277278if (priv->screen)279omx_put_screen();280281return omx_workaround_Destructor(comp);282}283284static OMX_ERRORTYPE enc_AllocateBackTexture(omx_base_PortType *port,285struct pipe_resource **resource,286struct pipe_transfer **transfer,287OMX_U8 **map)288{289OMX_COMPONENTTYPE* comp = port->standCompContainer;290vid_enc_PrivateType *priv = comp->pComponentPrivate;291struct pipe_resource buf_templ;292struct pipe_box box = {};293OMX_U8 *ptr;294295memset(&buf_templ, 0, sizeof buf_templ);296buf_templ.target = PIPE_TEXTURE_2D;297buf_templ.format = PIPE_FORMAT_I8_UNORM;298buf_templ.bind = PIPE_BIND_LINEAR;299buf_templ.usage = PIPE_USAGE_STAGING;300buf_templ.flags = 0;301buf_templ.width0 = port->sPortParam.format.video.nFrameWidth;302buf_templ.height0 = port->sPortParam.format.video.nFrameHeight * 3 / 2;303buf_templ.depth0 = 1;304buf_templ.array_size = 1;305306*resource = priv->s_pipe->screen->resource_create(priv->s_pipe->screen, &buf_templ);307if (!*resource)308return OMX_ErrorInsufficientResources;309310box.width = (*resource)->width0;311box.height = (*resource)->height0;312box.depth = (*resource)->depth0;313ptr = priv->s_pipe->texture_map(priv->s_pipe, *resource, 0, PIPE_MAP_WRITE, &box, transfer);314if (map)315*map = ptr;316317return OMX_ErrorNone;318}319320static OMX_ERRORTYPE vid_enc_SetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param)321{322OMX_COMPONENTTYPE *comp = handle;323vid_enc_PrivateType *priv = comp->pComponentPrivate;324OMX_ERRORTYPE r;325326if (!param)327return OMX_ErrorBadParameter;328329switch(idx) {330case OMX_IndexParamPortDefinition: {331OMX_PARAM_PORTDEFINITIONTYPE *def = param;332333r = omx_base_component_SetParameter(handle, idx, param);334if (r)335return r;336337if (def->nPortIndex == OMX_BASE_FILTER_INPUTPORT_INDEX) {338omx_base_video_PortType *port;339unsigned framesize;340struct pipe_resource *resource;341struct pipe_transfer *transfer;342343port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX];344enc_AllocateBackTexture(priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX],345&resource, &transfer, NULL);346port->sPortParam.format.video.nStride = transfer->stride;347pipe_texture_unmap(priv->s_pipe, transfer);348pipe_resource_reference(&resource, NULL);349350framesize = port->sPortParam.format.video.nStride *351port->sPortParam.format.video.nFrameHeight;352port->sPortParam.format.video.nSliceHeight = port->sPortParam.format.video.nFrameHeight;353port->sPortParam.nBufferSize = framesize * 3 / 2;354355port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX];356port->sPortParam.nBufferSize = framesize * 512 / (16*16);357358priv->frame_rate = def->format.video.xFramerate;359360priv->callbacks->EventHandler(comp, priv->callbackData, OMX_EventPortSettingsChanged,361OMX_BASE_FILTER_OUTPUTPORT_INDEX, 0, NULL);362}363break;364}365case OMX_IndexParamStandardComponentRole: {366OMX_PARAM_COMPONENTROLETYPE *role = param;367368r = checkHeader(param, sizeof(OMX_PARAM_COMPONENTROLETYPE));369if (r)370return r;371372if (strcmp((char *)role->cRole, OMX_VID_ENC_AVC_ROLE)) {373return OMX_ErrorBadParameter;374}375376break;377}378case OMX_IndexParamVideoBitrate: {379OMX_VIDEO_PARAM_BITRATETYPE *bitrate = param;380381r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_BITRATETYPE));382if (r)383return r;384385priv->bitrate = *bitrate;386387break;388}389case OMX_IndexParamVideoQuantization: {390OMX_VIDEO_PARAM_QUANTIZATIONTYPE *quant = param;391392r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_QUANTIZATIONTYPE));393if (r)394return r;395396priv->quant = *quant;397398break;399}400case OMX_IndexParamVideoProfileLevelCurrent: {401OMX_VIDEO_PARAM_PROFILELEVELTYPE *profile_level = param;402403r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_PROFILELEVELTYPE));404if (r)405return r;406407priv->profile_level = *profile_level;408409break;410}411default:412return omx_base_component_SetParameter(handle, idx, param);413}414return OMX_ErrorNone;415}416417static OMX_ERRORTYPE vid_enc_GetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param)418{419OMX_COMPONENTTYPE *comp = handle;420vid_enc_PrivateType *priv = comp->pComponentPrivate;421OMX_ERRORTYPE r;422423if (!param)424return OMX_ErrorBadParameter;425426switch(idx) {427case OMX_IndexParamStandardComponentRole: {428OMX_PARAM_COMPONENTROLETYPE *role = param;429430r = checkHeader(param, sizeof(OMX_PARAM_COMPONENTROLETYPE));431if (r)432return r;433434strcpy((char *)role->cRole, OMX_VID_ENC_AVC_ROLE);435break;436}437case OMX_IndexParamVideoInit:438r = checkHeader(param, sizeof(OMX_PORT_PARAM_TYPE));439if (r)440return r;441442memcpy(param, &priv->sPortTypesParam[OMX_PortDomainVideo], sizeof(OMX_PORT_PARAM_TYPE));443break;444445case OMX_IndexParamVideoPortFormat: {446OMX_VIDEO_PARAM_PORTFORMATTYPE *format = param;447omx_base_video_PortType *port;448449r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));450if (r)451return r;452453if (format->nPortIndex > 1)454return OMX_ErrorBadPortIndex;455if (format->nIndex >= 1)456return OMX_ErrorNoMore;457458port = (omx_base_video_PortType *)priv->ports[format->nPortIndex];459memcpy(format, &port->sVideoParam, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));460break;461}462case OMX_IndexParamVideoBitrate: {463OMX_VIDEO_PARAM_BITRATETYPE *bitrate = param;464465r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_BITRATETYPE));466if (r)467return r;468469bitrate->eControlRate = priv->bitrate.eControlRate;470bitrate->nTargetBitrate = priv->bitrate.nTargetBitrate;471472break;473}474case OMX_IndexParamVideoQuantization: {475OMX_VIDEO_PARAM_QUANTIZATIONTYPE *quant = param;476477r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_QUANTIZATIONTYPE));478if (r)479return r;480481quant->nQpI = priv->quant.nQpI;482quant->nQpP = priv->quant.nQpP;483quant->nQpB = priv->quant.nQpB;484485break;486}487case OMX_IndexParamVideoProfileLevelCurrent: {488OMX_VIDEO_PARAM_PROFILELEVELTYPE *profile_level = param;489490r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_PROFILELEVELTYPE));491if (r)492return r;493494profile_level->eProfile = priv->profile_level.eProfile;495profile_level->eLevel = priv->profile_level.eLevel;496497break;498}499default:500return omx_base_component_GetParameter(handle, idx, param);501}502return OMX_ErrorNone;503}504505static OMX_ERRORTYPE vid_enc_SetConfig(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR config)506{507OMX_COMPONENTTYPE *comp = handle;508vid_enc_PrivateType *priv = comp->pComponentPrivate;509OMX_ERRORTYPE r;510int i;511512if (!config)513return OMX_ErrorBadParameter;514515switch(idx) {516case OMX_IndexConfigVideoIntraVOPRefresh: {517OMX_CONFIG_INTRAREFRESHVOPTYPE *type = config;518519r = checkHeader(config, sizeof(OMX_CONFIG_INTRAREFRESHVOPTYPE));520if (r)521return r;522523priv->force_pic_type = *type;524525break;526}527case OMX_IndexConfigCommonScale: {528OMX_CONFIG_SCALEFACTORTYPE *scale = config;529530r = checkHeader(config, sizeof(OMX_CONFIG_SCALEFACTORTYPE));531if (r)532return r;533534if (scale->xWidth < 176 || scale->xHeight < 144)535return OMX_ErrorBadParameter;536537for (i = 0; i < OMX_VID_ENC_NUM_SCALING_BUFFERS; ++i) {538if (priv->scale_buffer[i]) {539priv->scale_buffer[i]->destroy(priv->scale_buffer[i]);540priv->scale_buffer[i] = NULL;541}542}543544priv->scale = *scale;545if (priv->scale.xWidth != 0xffffffff && priv->scale.xHeight != 0xffffffff) {546struct pipe_video_buffer templat = {};547548templat.buffer_format = PIPE_FORMAT_NV12;549templat.width = priv->scale.xWidth;550templat.height = priv->scale.xHeight;551templat.interlaced = false;552for (i = 0; i < OMX_VID_ENC_NUM_SCALING_BUFFERS; ++i) {553priv->scale_buffer[i] = priv->s_pipe->create_video_buffer(priv->s_pipe, &templat);554if (!priv->scale_buffer[i])555return OMX_ErrorInsufficientResources;556}557}558559break;560}561default:562return omx_base_component_SetConfig(handle, idx, config);563}564565return OMX_ErrorNone;566}567568static OMX_ERRORTYPE vid_enc_GetConfig(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR config)569{570OMX_COMPONENTTYPE *comp = handle;571vid_enc_PrivateType *priv = comp->pComponentPrivate;572OMX_ERRORTYPE r;573574if (!config)575return OMX_ErrorBadParameter;576577switch(idx) {578case OMX_IndexConfigCommonScale: {579OMX_CONFIG_SCALEFACTORTYPE *scale = config;580581r = checkHeader(config, sizeof(OMX_CONFIG_SCALEFACTORTYPE));582if (r)583return r;584585scale->xWidth = priv->scale.xWidth;586scale->xHeight = priv->scale.xHeight;587588break;589}590default:591return omx_base_component_GetConfig(handle, idx, config);592}593594return OMX_ErrorNone;595}596597static OMX_ERRORTYPE vid_enc_MessageHandler(OMX_COMPONENTTYPE* comp, internalRequestMessageType *msg)598{599vid_enc_PrivateType* priv = comp->pComponentPrivate;600601if (msg->messageType == OMX_CommandStateSet) {602if ((msg->messageParam == OMX_StateIdle ) && (priv->state == OMX_StateLoaded)) {603604struct pipe_video_codec templat = {};605omx_base_video_PortType *port;606607port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX];608609templat.profile = enc_TranslateOMXProfileToPipe(priv->profile_level.eProfile);610templat.level = enc_TranslateOMXLevelToPipe(priv->profile_level.eLevel);611templat.entrypoint = PIPE_VIDEO_ENTRYPOINT_ENCODE;612templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;613templat.width = priv->scale_buffer[priv->current_scale_buffer] ?614priv->scale.xWidth : port->sPortParam.format.video.nFrameWidth;615templat.height = priv->scale_buffer[priv->current_scale_buffer] ?616priv->scale.xHeight : port->sPortParam.format.video.nFrameHeight;617618if (templat.profile == PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE) {619struct pipe_screen *screen = priv->screen->pscreen;620templat.max_references = 1;621priv->stacked_frames_num =622screen->get_video_param(screen,623PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH,624PIPE_VIDEO_ENTRYPOINT_ENCODE,625PIPE_VIDEO_CAP_STACKED_FRAMES);626} else {627templat.max_references = OMX_VID_ENC_P_PERIOD_DEFAULT;628priv->stacked_frames_num = 1;629}630priv->codec = priv->s_pipe->create_video_codec(priv->s_pipe, &templat);631632} else if ((msg->messageParam == OMX_StateLoaded) && (priv->state == OMX_StateIdle)) {633if (priv->codec) {634priv->codec->destroy(priv->codec);635priv->codec = NULL;636}637}638}639640return omx_base_component_MessageHandler(comp, msg);641}642643static OMX_ERRORTYPE vid_enc_AllocateInBuffer(omx_base_PortType *port, OMX_INOUT OMX_BUFFERHEADERTYPE **buf,644OMX_IN OMX_U32 idx, OMX_IN OMX_PTR private, OMX_IN OMX_U32 size)645{646struct input_buf_private *inp;647OMX_ERRORTYPE r;648649r = base_port_AllocateBuffer(port, buf, idx, private, size);650if (r)651return r;652653inp = (*buf)->pInputPortPrivate = CALLOC_STRUCT(input_buf_private);654if (!inp) {655base_port_FreeBuffer(port, idx, *buf);656return OMX_ErrorInsufficientResources;657}658659list_inithead(&inp->tasks);660661FREE((*buf)->pBuffer);662r = enc_AllocateBackTexture(port, &inp->resource, &inp->transfer, &(*buf)->pBuffer);663if (r) {664FREE(inp);665base_port_FreeBuffer(port, idx, *buf);666return r;667}668669return OMX_ErrorNone;670}671672static OMX_ERRORTYPE vid_enc_UseInBuffer(omx_base_PortType *port, OMX_BUFFERHEADERTYPE **buf, OMX_U32 idx,673OMX_PTR private, OMX_U32 size, OMX_U8 *mem)674{675struct input_buf_private *inp;676OMX_ERRORTYPE r;677678r = base_port_UseBuffer(port, buf, idx, private, size, mem);679if (r)680return r;681682inp = (*buf)->pInputPortPrivate = CALLOC_STRUCT(input_buf_private);683if (!inp) {684base_port_FreeBuffer(port, idx, *buf);685return OMX_ErrorInsufficientResources;686}687688list_inithead(&inp->tasks);689690return OMX_ErrorNone;691}692693static OMX_ERRORTYPE vid_enc_FreeInBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf)694{695OMX_COMPONENTTYPE* comp = port->standCompContainer;696vid_enc_PrivateType *priv = comp->pComponentPrivate;697struct input_buf_private *inp = buf->pInputPortPrivate;698699if (inp) {700enc_ReleaseTasks(&inp->tasks);701if (inp->transfer)702pipe_texture_unmap(priv->s_pipe, inp->transfer);703pipe_resource_reference(&inp->resource, NULL);704FREE(inp);705}706buf->pBuffer = NULL;707708return base_port_FreeBuffer(port, idx, buf);709}710711static OMX_ERRORTYPE vid_enc_AllocateOutBuffer(omx_base_PortType *port, OMX_INOUT OMX_BUFFERHEADERTYPE **buf,712OMX_IN OMX_U32 idx, OMX_IN OMX_PTR private, OMX_IN OMX_U32 size)713{714OMX_ERRORTYPE r;715716r = base_port_AllocateBuffer(port, buf, idx, private, size);717if (r)718return r;719720FREE((*buf)->pBuffer);721(*buf)->pBuffer = NULL;722(*buf)->pOutputPortPrivate = CALLOC(1, sizeof(struct output_buf_private));723if (!(*buf)->pOutputPortPrivate) {724base_port_FreeBuffer(port, idx, *buf);725return OMX_ErrorInsufficientResources;726}727728return OMX_ErrorNone;729}730731static OMX_ERRORTYPE vid_enc_FreeOutBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf)732{733OMX_COMPONENTTYPE* comp = port->standCompContainer;734vid_enc_PrivateType *priv = comp->pComponentPrivate;735736if (buf->pOutputPortPrivate) {737struct output_buf_private *outp = buf->pOutputPortPrivate;738if (outp->transfer)739pipe_buffer_unmap(priv->t_pipe, outp->transfer);740pipe_resource_reference(&outp->bitstream, NULL);741FREE(outp);742buf->pOutputPortPrivate = NULL;743}744buf->pBuffer = NULL;745746return base_port_FreeBuffer(port, idx, buf);747}748749static struct encode_task *enc_NeedTask(omx_base_PortType *port)750{751OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video;752OMX_COMPONENTTYPE* comp = port->standCompContainer;753vid_enc_PrivateType *priv = comp->pComponentPrivate;754755return enc_NeedTask_common(priv, def);756}757758static OMX_ERRORTYPE enc_LoadImage(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf,759struct pipe_video_buffer *vbuf)760{761OMX_COMPONENTTYPE* comp = port->standCompContainer;762vid_enc_PrivateType *priv = comp->pComponentPrivate;763OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video;764return enc_LoadImage_common(priv, def, buf, vbuf);765}766767static void enc_ScaleInput(omx_base_PortType *port, struct pipe_video_buffer **vbuf, unsigned *size)768{769OMX_COMPONENTTYPE* comp = port->standCompContainer;770vid_enc_PrivateType *priv = comp->pComponentPrivate;771OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video;772enc_ScaleInput_common(priv, def, vbuf, size);773}774775static void enc_ControlPicture(omx_base_PortType *port, struct pipe_h264_enc_picture_desc *picture)776{777OMX_COMPONENTTYPE* comp = port->standCompContainer;778vid_enc_PrivateType *priv = comp->pComponentPrivate;779enc_ControlPicture_common(priv, picture);780}781782static void enc_HandleTask(omx_base_PortType *port, struct encode_task *task,783enum pipe_h2645_enc_picture_type picture_type)784{785OMX_COMPONENTTYPE* comp = port->standCompContainer;786vid_enc_PrivateType *priv = comp->pComponentPrivate;787unsigned size = priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX]->sPortParam.nBufferSize;788struct pipe_video_buffer *vbuf = task->buf;789struct pipe_h264_enc_picture_desc picture = {};790791/* -------------- scale input image --------- */792enc_ScaleInput(port, &vbuf, &size);793priv->s_pipe->flush(priv->s_pipe, NULL, 0);794795/* -------------- allocate output buffer --------- */796task->bitstream = pipe_buffer_create(priv->s_pipe->screen,797PIPE_BIND_VERTEX_BUFFER,798PIPE_USAGE_STAGING, /* map for read */799size);800801picture.picture_type = picture_type;802picture.pic_order_cnt = task->pic_order_cnt;803picture.base.profile = enc_TranslateOMXProfileToPipe(priv->profile_level.eProfile);804picture.base.entry_point = PIPE_VIDEO_ENTRYPOINT_ENCODE;805if (priv->restricted_b_frames && picture_type == PIPE_H2645_ENC_PICTURE_TYPE_B)806picture.not_referenced = true;807enc_ControlPicture(port, &picture);808809/* -------------- encode frame --------- */810priv->codec->begin_frame(priv->codec, vbuf, &picture.base);811priv->codec->encode_bitstream(priv->codec, vbuf, task->bitstream, &task->feedback);812priv->codec->end_frame(priv->codec, vbuf, &picture.base);813}814815static void enc_ClearBframes(omx_base_PortType *port, struct input_buf_private *inp)816{817OMX_COMPONENTTYPE* comp = port->standCompContainer;818vid_enc_PrivateType *priv = comp->pComponentPrivate;819struct encode_task *task;820821if (list_is_empty(&priv->b_frames))822return;823824task = LIST_ENTRY(struct encode_task, priv->b_frames.prev, list);825list_del(&task->list);826827/* promote last from to P frame */828priv->ref_idx_l0 = priv->ref_idx_l1;829enc_HandleTask(port, task, PIPE_H2645_ENC_PICTURE_TYPE_P);830list_addtail(&task->list, &inp->tasks);831priv->ref_idx_l1 = priv->frame_num++;832833/* handle B frames */834LIST_FOR_EACH_ENTRY(task, &priv->b_frames, list) {835enc_HandleTask(port, task, PIPE_H2645_ENC_PICTURE_TYPE_B);836if (!priv->restricted_b_frames)837priv->ref_idx_l0 = priv->frame_num;838priv->frame_num++;839}840841enc_MoveTasks(&priv->b_frames, &inp->tasks);842}843844static OMX_ERRORTYPE vid_enc_EncodeFrame(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf)845{846OMX_COMPONENTTYPE* comp = port->standCompContainer;847vid_enc_PrivateType *priv = comp->pComponentPrivate;848struct input_buf_private *inp = buf->pInputPortPrivate;849enum pipe_h2645_enc_picture_type picture_type;850struct encode_task *task;851unsigned stacked_num = 0;852OMX_ERRORTYPE err;853854enc_MoveTasks(&inp->tasks, &priv->free_tasks);855task = enc_NeedTask(port);856if (!task)857return OMX_ErrorInsufficientResources;858859if (buf->nFilledLen == 0) {860if (buf->nFlags & OMX_BUFFERFLAG_EOS) {861buf->nFilledLen = buf->nAllocLen;862enc_ClearBframes(port, inp);863enc_MoveTasks(&priv->stacked_tasks, &inp->tasks);864priv->codec->flush(priv->codec);865}866return base_port_SendBufferFunction(port, buf);867}868869if (buf->pOutputPortPrivate) {870struct pipe_video_buffer *vbuf = buf->pOutputPortPrivate;871buf->pOutputPortPrivate = task->buf;872task->buf = vbuf;873} else {874/* ------- load input image into video buffer ---- */875err = enc_LoadImage(port, buf, task->buf);876if (err != OMX_ErrorNone) {877FREE(task);878return err;879}880}881882/* -------------- determine picture type --------- */883if (!(priv->pic_order_cnt % OMX_VID_ENC_IDR_PERIOD_DEFAULT) ||884priv->force_pic_type.IntraRefreshVOP) {885enc_ClearBframes(port, inp);886picture_type = PIPE_H2645_ENC_PICTURE_TYPE_IDR;887priv->force_pic_type.IntraRefreshVOP = OMX_FALSE;888priv->frame_num = 0;889priv->pic_order_cnt = 0;890} else if (priv->codec->profile == PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE ||891!(priv->pic_order_cnt % OMX_VID_ENC_P_PERIOD_DEFAULT) ||892(buf->nFlags & OMX_BUFFERFLAG_EOS)) {893picture_type = PIPE_H2645_ENC_PICTURE_TYPE_P;894} else {895picture_type = PIPE_H2645_ENC_PICTURE_TYPE_B;896}897898task->pic_order_cnt = priv->pic_order_cnt++;899900if (picture_type == PIPE_H2645_ENC_PICTURE_TYPE_B) {901/* put frame at the tail of the queue */902list_addtail(&task->list, &priv->b_frames);903} else {904/* handle I or P frame */905priv->ref_idx_l0 = priv->ref_idx_l1;906enc_HandleTask(port, task, picture_type);907list_addtail(&task->list, &priv->stacked_tasks);908LIST_FOR_EACH_ENTRY(task, &priv->stacked_tasks, list) {909++stacked_num;910}911if (stacked_num == priv->stacked_frames_num) {912struct encode_task *t;913t = LIST_ENTRY(struct encode_task, priv->stacked_tasks.next, list);914list_del(&t->list);915list_addtail(&t->list, &inp->tasks);916}917priv->ref_idx_l1 = priv->frame_num++;918919/* handle B frames */920LIST_FOR_EACH_ENTRY(task, &priv->b_frames, list) {921enc_HandleTask(port, task, PIPE_H2645_ENC_PICTURE_TYPE_B);922if (!priv->restricted_b_frames)923priv->ref_idx_l0 = priv->frame_num;924priv->frame_num++;925}926927enc_MoveTasks(&priv->b_frames, &inp->tasks);928}929930if (list_is_empty(&inp->tasks))931return port->ReturnBufferFunction(port, buf);932else933return base_port_SendBufferFunction(port, buf);934}935936static void vid_enc_BufferEncoded(OMX_COMPONENTTYPE *comp, OMX_BUFFERHEADERTYPE* input, OMX_BUFFERHEADERTYPE* output)937{938vid_enc_PrivateType *priv = comp->pComponentPrivate;939vid_enc_BufferEncoded_common(priv, input, output);940}941942943