Home | History | Annotate | Download | only in omx
      1 /**************************************************************************
      2  *
      3  * Copyright 2013 Advanced Micro Devices, Inc.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 
     28 /*
     29  * Authors:
     30  *      Christian Knig <christian.koenig (at) amd.com>
     31  *
     32  */
     33 
     34 
     35 #include <assert.h>
     36 
     37 #include <OMX_Video.h>
     38 
     39 /* bellagio defines a DEBUG macro that we don't want */
     40 #ifndef DEBUG
     41 #include <bellagio/omxcore.h>
     42 #undef DEBUG
     43 #else
     44 #include <bellagio/omxcore.h>
     45 #endif
     46 
     47 #include <bellagio/omx_base_video_port.h>
     48 
     49 #include "pipe/p_screen.h"
     50 #include "pipe/p_video_codec.h"
     51 #include "state_tracker/drm_driver.h"
     52 #include "util/u_memory.h"
     53 #include "vl/vl_video_buffer.h"
     54 
     55 #include "entrypoint.h"
     56 #include "vid_enc.h"
     57 
     58 struct encode_task {
     59    struct list_head list;
     60 
     61    struct pipe_video_buffer *buf;
     62    unsigned pic_order_cnt;
     63    struct pipe_resource *bitstream;
     64    void *feedback;
     65 };
     66 
     67 struct input_buf_private {
     68    struct list_head tasks;
     69 
     70    struct pipe_resource *resource;
     71    struct pipe_transfer *transfer;
     72 };
     73 
     74 struct output_buf_private {
     75    struct pipe_resource *bitstream;
     76    struct pipe_transfer *transfer;
     77 };
     78 
     79 static OMX_ERRORTYPE vid_enc_Constructor(OMX_COMPONENTTYPE *comp, OMX_STRING name);
     80 static OMX_ERRORTYPE vid_enc_Destructor(OMX_COMPONENTTYPE *comp);
     81 static OMX_ERRORTYPE vid_enc_SetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param);
     82 static OMX_ERRORTYPE vid_enc_GetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param);
     83 static OMX_ERRORTYPE vid_enc_SetConfig(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR config);
     84 static OMX_ERRORTYPE vid_enc_GetConfig(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR config);
     85 static OMX_ERRORTYPE vid_enc_MessageHandler(OMX_COMPONENTTYPE *comp, internalRequestMessageType *msg);
     86 static OMX_ERRORTYPE vid_enc_AllocateInBuffer(omx_base_PortType *port, OMX_INOUT OMX_BUFFERHEADERTYPE **buf,
     87                                               OMX_IN OMX_U32 idx, OMX_IN OMX_PTR private, OMX_IN OMX_U32 size);
     88 static OMX_ERRORTYPE vid_enc_UseInBuffer(omx_base_PortType *port, OMX_BUFFERHEADERTYPE **buf, OMX_U32 idx,
     89                                          OMX_PTR private, OMX_U32 size, OMX_U8 *mem);
     90 static OMX_ERRORTYPE vid_enc_FreeInBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf);
     91 static OMX_ERRORTYPE vid_enc_EncodeFrame(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf);
     92 static OMX_ERRORTYPE vid_enc_AllocateOutBuffer(omx_base_PortType *comp, OMX_INOUT OMX_BUFFERHEADERTYPE **buf,
     93                                                OMX_IN OMX_U32 idx, OMX_IN OMX_PTR private, OMX_IN OMX_U32 size);
     94 static OMX_ERRORTYPE vid_enc_FreeOutBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf);
     95 static void vid_enc_BufferEncoded(OMX_COMPONENTTYPE *comp, OMX_BUFFERHEADERTYPE* input, OMX_BUFFERHEADERTYPE* output);
     96 
     97 static void enc_ReleaseTasks(struct list_head *head);
     98 
     99 OMX_ERRORTYPE vid_enc_LoaderComponent(stLoaderComponentType *comp)
    100 {
    101    comp->componentVersion.s.nVersionMajor = 0;
    102    comp->componentVersion.s.nVersionMinor = 0;
    103    comp->componentVersion.s.nRevision = 0;
    104    comp->componentVersion.s.nStep = 1;
    105    comp->name_specific_length = 1;
    106    comp->constructor = vid_enc_Constructor;
    107 
    108    comp->name = CALLOC(1, OMX_MAX_STRINGNAME_SIZE);
    109    if (!comp->name)
    110       return OMX_ErrorInsufficientResources;
    111 
    112    comp->name_specific = CALLOC(1, sizeof(char *));
    113    if (!comp->name_specific)
    114       goto error_arrays;
    115 
    116    comp->role_specific = CALLOC(1, sizeof(char *));
    117    if (!comp->role_specific)
    118       goto error_arrays;
    119 
    120    comp->name_specific[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE);
    121    if (comp->name_specific[0] == NULL)
    122       goto error_specific;
    123 
    124    comp->role_specific[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE);
    125    if (comp->role_specific[0] == NULL)
    126       goto error_specific;
    127 
    128    strcpy(comp->name, OMX_VID_ENC_BASE_NAME);
    129    strcpy(comp->name_specific[0], OMX_VID_ENC_AVC_NAME);
    130    strcpy(comp->role_specific[0], OMX_VID_ENC_AVC_ROLE);
    131 
    132    return OMX_ErrorNone;
    133 
    134 error_specific:
    135    FREE(comp->role_specific[0]);
    136    FREE(comp->name_specific[0]);
    137 
    138 error_arrays:
    139    FREE(comp->role_specific);
    140    FREE(comp->name_specific);
    141 
    142    FREE(comp->name);
    143 
    144    return OMX_ErrorInsufficientResources;
    145 }
    146 
    147 static OMX_ERRORTYPE vid_enc_Constructor(OMX_COMPONENTTYPE *comp, OMX_STRING name)
    148 {
    149    vid_enc_PrivateType *priv;
    150    omx_base_video_PortType *port;
    151    struct pipe_screen *screen;
    152    OMX_ERRORTYPE r;
    153    int i;
    154 
    155    assert(!comp->pComponentPrivate);
    156 
    157    priv = comp->pComponentPrivate = CALLOC(1, sizeof(vid_enc_PrivateType));
    158    if (!priv)
    159       return OMX_ErrorInsufficientResources;
    160 
    161    r = omx_base_filter_Constructor(comp, name);
    162    if (r)
    163 	return r;
    164 
    165    priv->BufferMgmtCallback = vid_enc_BufferEncoded;
    166    priv->messageHandler = vid_enc_MessageHandler;
    167    priv->destructor = vid_enc_Destructor;
    168 
    169    comp->SetParameter = vid_enc_SetParameter;
    170    comp->GetParameter = vid_enc_GetParameter;
    171    comp->GetConfig = vid_enc_GetConfig;
    172    comp->SetConfig = vid_enc_SetConfig;
    173 
    174    priv->screen = omx_get_screen();
    175    if (!priv->screen)
    176       return OMX_ErrorInsufficientResources;
    177 
    178    screen = priv->screen->pscreen;
    179    if (!screen->get_video_param(screen, PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH,
    180                                 PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_SUPPORTED))
    181       return OMX_ErrorBadParameter;
    182 
    183    priv->s_pipe = screen->context_create(screen, priv->screen, 0);
    184    if (!priv->s_pipe)
    185       return OMX_ErrorInsufficientResources;
    186 
    187    if (!vl_compositor_init(&priv->compositor, priv->s_pipe)) {
    188       priv->s_pipe->destroy(priv->s_pipe);
    189       priv->s_pipe = NULL;
    190       return OMX_ErrorInsufficientResources;
    191    }
    192 
    193    if (!vl_compositor_init_state(&priv->cstate, priv->s_pipe)) {
    194       vl_compositor_cleanup(&priv->compositor);
    195       priv->s_pipe->destroy(priv->s_pipe);
    196       priv->s_pipe = NULL;
    197       return OMX_ErrorInsufficientResources;
    198    }
    199 
    200    priv->t_pipe = screen->context_create(screen, priv->screen, 0);
    201    if (!priv->t_pipe)
    202       return OMX_ErrorInsufficientResources;
    203 
    204    priv->sPortTypesParam[OMX_PortDomainVideo].nStartPortNumber = 0;
    205    priv->sPortTypesParam[OMX_PortDomainVideo].nPorts = 2;
    206    priv->ports = CALLOC(2, sizeof(omx_base_PortType *));
    207    if (!priv->ports)
    208       return OMX_ErrorInsufficientResources;
    209 
    210    for (i = 0; i < 2; ++i) {
    211       priv->ports[i] = CALLOC(1, sizeof(omx_base_video_PortType));
    212       if (!priv->ports[i])
    213          return OMX_ErrorInsufficientResources;
    214 
    215       base_video_port_Constructor(comp, &priv->ports[i], i, i == 0);
    216    }
    217 
    218    port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX];
    219    port->sPortParam.format.video.nFrameWidth = 176;
    220    port->sPortParam.format.video.nFrameHeight = 144;
    221    port->sPortParam.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
    222    port->sVideoParam.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
    223    port->sPortParam.nBufferCountActual = 8;
    224    port->sPortParam.nBufferCountMin = 4;
    225 
    226    port->Port_SendBufferFunction = vid_enc_EncodeFrame;
    227    port->Port_AllocateBuffer = vid_enc_AllocateInBuffer;
    228    port->Port_UseBuffer = vid_enc_UseInBuffer;
    229    port->Port_FreeBuffer = vid_enc_FreeInBuffer;
    230 
    231    port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX];
    232    strcpy(port->sPortParam.format.video.cMIMEType,"video/H264");
    233    port->sPortParam.format.video.nFrameWidth = 176;
    234    port->sPortParam.format.video.nFrameHeight = 144;
    235    port->sPortParam.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
    236    port->sVideoParam.eCompressionFormat = OMX_VIDEO_CodingAVC;
    237 
    238    port->Port_AllocateBuffer = vid_enc_AllocateOutBuffer;
    239    port->Port_FreeBuffer = vid_enc_FreeOutBuffer;
    240 
    241    priv->bitrate.eControlRate = OMX_Video_ControlRateDisable;
    242    priv->bitrate.nTargetBitrate = 0;
    243 
    244    priv->quant.nQpI = OMX_VID_ENC_QUANT_I_FRAMES_DEFAULT;
    245    priv->quant.nQpP = OMX_VID_ENC_QUANT_P_FRAMES_DEFAULT;
    246    priv->quant.nQpB = OMX_VID_ENC_QUANT_B_FRAMES_DEFAULT;
    247 
    248    priv->profile_level.eProfile = OMX_VIDEO_AVCProfileBaseline;
    249    priv->profile_level.eLevel = OMX_VIDEO_AVCLevel51;
    250 
    251    priv->force_pic_type.IntraRefreshVOP = OMX_FALSE;
    252    priv->frame_num = 0;
    253    priv->pic_order_cnt = 0;
    254    priv->restricted_b_frames = debug_get_bool_option("OMX_USE_RESTRICTED_B_FRAMES", FALSE);
    255 
    256    priv->scale.xWidth = OMX_VID_ENC_SCALING_WIDTH_DEFAULT;
    257    priv->scale.xHeight = OMX_VID_ENC_SCALING_WIDTH_DEFAULT;
    258 
    259    LIST_INITHEAD(&priv->free_tasks);
    260    LIST_INITHEAD(&priv->used_tasks);
    261    LIST_INITHEAD(&priv->b_frames);
    262    LIST_INITHEAD(&priv->stacked_tasks);
    263 
    264    return OMX_ErrorNone;
    265 }
    266 
    267 static OMX_ERRORTYPE vid_enc_Destructor(OMX_COMPONENTTYPE *comp)
    268 {
    269    vid_enc_PrivateType* priv = comp->pComponentPrivate;
    270    int i;
    271 
    272    enc_ReleaseTasks(&priv->free_tasks);
    273    enc_ReleaseTasks(&priv->used_tasks);
    274    enc_ReleaseTasks(&priv->b_frames);
    275    enc_ReleaseTasks(&priv->stacked_tasks);
    276 
    277    if (priv->ports) {
    278       for (i = 0; i < priv->sPortTypesParam[OMX_PortDomainVideo].nPorts; ++i) {
    279          if(priv->ports[i])
    280             priv->ports[i]->PortDestructor(priv->ports[i]);
    281       }
    282       FREE(priv->ports);
    283       priv->ports=NULL;
    284    }
    285 
    286    for (i = 0; i < OMX_VID_ENC_NUM_SCALING_BUFFERS; ++i)
    287       if (priv->scale_buffer[i])
    288          priv->scale_buffer[i]->destroy(priv->scale_buffer[i]);
    289 
    290    if (priv->s_pipe) {
    291       vl_compositor_cleanup_state(&priv->cstate);
    292       vl_compositor_cleanup(&priv->compositor);
    293       priv->s_pipe->destroy(priv->s_pipe);
    294    }
    295 
    296    if (priv->t_pipe)
    297       priv->t_pipe->destroy(priv->t_pipe);
    298 
    299    if (priv->screen)
    300       omx_put_screen();
    301 
    302    return omx_workaround_Destructor(comp);
    303 }
    304 
    305 static OMX_ERRORTYPE enc_AllocateBackTexture(omx_base_PortType *port,
    306                                              struct pipe_resource **resource,
    307                                              struct pipe_transfer **transfer,
    308                                              OMX_U8 **map)
    309 {
    310    OMX_COMPONENTTYPE* comp = port->standCompContainer;
    311    vid_enc_PrivateType *priv = comp->pComponentPrivate;
    312    struct pipe_resource buf_templ;
    313    struct pipe_box box = {};
    314    OMX_U8 *ptr;
    315 
    316    memset(&buf_templ, 0, sizeof buf_templ);
    317    buf_templ.target = PIPE_TEXTURE_2D;
    318    buf_templ.format = PIPE_FORMAT_I8_UNORM;
    319    buf_templ.bind = PIPE_BIND_LINEAR;
    320    buf_templ.usage = PIPE_USAGE_STAGING;
    321    buf_templ.flags = 0;
    322    buf_templ.width0 = port->sPortParam.format.video.nFrameWidth;
    323    buf_templ.height0 = port->sPortParam.format.video.nFrameHeight * 3 / 2;
    324    buf_templ.depth0 = 1;
    325    buf_templ.array_size = 1;
    326 
    327    *resource = priv->s_pipe->screen->resource_create(priv->s_pipe->screen, &buf_templ);
    328    if (!*resource)
    329       return OMX_ErrorInsufficientResources;
    330 
    331    box.width = (*resource)->width0;
    332    box.height = (*resource)->height0;
    333    box.depth = (*resource)->depth0;
    334    ptr = priv->s_pipe->transfer_map(priv->s_pipe, *resource, 0, PIPE_TRANSFER_WRITE, &box, transfer);
    335    if (map)
    336       *map = ptr;
    337 
    338    return OMX_ErrorNone;
    339 }
    340 
    341 static OMX_ERRORTYPE vid_enc_SetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param)
    342 {
    343    OMX_COMPONENTTYPE *comp = handle;
    344    vid_enc_PrivateType *priv = comp->pComponentPrivate;
    345    OMX_ERRORTYPE r;
    346 
    347    if (!param)
    348       return OMX_ErrorBadParameter;
    349 
    350    switch(idx) {
    351    case OMX_IndexParamPortDefinition: {
    352       OMX_PARAM_PORTDEFINITIONTYPE *def = param;
    353 
    354       r = omx_base_component_SetParameter(handle, idx, param);
    355       if (r)
    356          return r;
    357 
    358       if (def->nPortIndex == OMX_BASE_FILTER_INPUTPORT_INDEX) {
    359          omx_base_video_PortType *port;
    360          unsigned framesize;
    361          struct pipe_resource *resource;
    362          struct pipe_transfer *transfer;
    363 
    364          port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX];
    365          enc_AllocateBackTexture(priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX],
    366                                  &resource, &transfer, NULL);
    367          port->sPortParam.format.video.nStride = transfer->stride;
    368          pipe_transfer_unmap(priv->s_pipe, transfer);
    369          pipe_resource_reference(&resource, NULL);
    370 
    371          framesize = port->sPortParam.format.video.nStride *
    372                      port->sPortParam.format.video.nFrameHeight;
    373          port->sPortParam.format.video.nSliceHeight = port->sPortParam.format.video.nFrameHeight;
    374          port->sPortParam.nBufferSize = framesize * 3 / 2;
    375 
    376          port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX];
    377          port->sPortParam.nBufferSize = framesize * 512 / (16*16);
    378 
    379          priv->frame_rate = def->format.video.xFramerate;
    380 
    381          priv->callbacks->EventHandler(comp, priv->callbackData, OMX_EventPortSettingsChanged,
    382                                        OMX_BASE_FILTER_OUTPUTPORT_INDEX, 0, NULL);
    383       }
    384       break;
    385    }
    386    case OMX_IndexParamStandardComponentRole: {
    387       OMX_PARAM_COMPONENTROLETYPE *role = param;
    388 
    389       r = checkHeader(param, sizeof(OMX_PARAM_COMPONENTROLETYPE));
    390       if (r)
    391          return r;
    392 
    393       if (strcmp((char *)role->cRole, OMX_VID_ENC_AVC_ROLE)) {
    394          return OMX_ErrorBadParameter;
    395       }
    396 
    397       break;
    398    }
    399    case OMX_IndexParamVideoBitrate: {
    400       OMX_VIDEO_PARAM_BITRATETYPE *bitrate = param;
    401 
    402       r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_BITRATETYPE));
    403       if (r)
    404          return r;
    405 
    406       priv->bitrate = *bitrate;
    407 
    408       break;
    409    }
    410    case OMX_IndexParamVideoQuantization: {
    411       OMX_VIDEO_PARAM_QUANTIZATIONTYPE *quant = param;
    412 
    413       r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_QUANTIZATIONTYPE));
    414       if (r)
    415          return r;
    416 
    417       priv->quant = *quant;
    418 
    419       break;
    420    }
    421    case OMX_IndexParamVideoProfileLevelCurrent: {
    422       OMX_VIDEO_PARAM_PROFILELEVELTYPE *profile_level = param;
    423 
    424       r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_PROFILELEVELTYPE));
    425       if (r)
    426          return r;
    427 
    428       priv->profile_level = *profile_level;
    429 
    430       break;
    431    }
    432    default:
    433       return omx_base_component_SetParameter(handle, idx, param);
    434    }
    435    return OMX_ErrorNone;
    436 }
    437 
    438 static OMX_ERRORTYPE vid_enc_GetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param)
    439 {
    440    OMX_COMPONENTTYPE *comp = handle;
    441    vid_enc_PrivateType *priv = comp->pComponentPrivate;
    442    OMX_ERRORTYPE r;
    443 
    444    if (!param)
    445       return OMX_ErrorBadParameter;
    446 
    447    switch(idx) {
    448    case OMX_IndexParamStandardComponentRole: {
    449       OMX_PARAM_COMPONENTROLETYPE *role = param;
    450 
    451       r = checkHeader(param, sizeof(OMX_PARAM_COMPONENTROLETYPE));
    452       if (r)
    453          return r;
    454 
    455       strcpy((char *)role->cRole, OMX_VID_ENC_AVC_ROLE);
    456       break;
    457    }
    458    case OMX_IndexParamVideoInit:
    459       r = checkHeader(param, sizeof(OMX_PORT_PARAM_TYPE));
    460       if (r)
    461          return r;
    462 
    463       memcpy(param, &priv->sPortTypesParam[OMX_PortDomainVideo], sizeof(OMX_PORT_PARAM_TYPE));
    464       break;
    465 
    466    case OMX_IndexParamVideoPortFormat: {
    467       OMX_VIDEO_PARAM_PORTFORMATTYPE *format = param;
    468       omx_base_video_PortType *port;
    469 
    470       r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));
    471       if (r)
    472          return r;
    473 
    474       if (format->nPortIndex > 1)
    475          return OMX_ErrorBadPortIndex;
    476 
    477       port = (omx_base_video_PortType *)priv->ports[format->nPortIndex];
    478       memcpy(format, &port->sVideoParam, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));
    479       break;
    480    }
    481    case OMX_IndexParamVideoBitrate: {
    482       OMX_VIDEO_PARAM_BITRATETYPE *bitrate = param;
    483 
    484       r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_BITRATETYPE));
    485       if (r)
    486          return r;
    487 
    488       bitrate->eControlRate = priv->bitrate.eControlRate;
    489       bitrate->nTargetBitrate = priv->bitrate.nTargetBitrate;
    490 
    491       break;
    492    }
    493    case OMX_IndexParamVideoQuantization: {
    494       OMX_VIDEO_PARAM_QUANTIZATIONTYPE *quant = param;
    495 
    496       r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_QUANTIZATIONTYPE));
    497       if (r)
    498          return r;
    499 
    500       quant->nQpI = priv->quant.nQpI;
    501       quant->nQpP = priv->quant.nQpP;
    502       quant->nQpB = priv->quant.nQpB;
    503 
    504       break;
    505    }
    506    case OMX_IndexParamVideoProfileLevelCurrent: {
    507       OMX_VIDEO_PARAM_PROFILELEVELTYPE *profile_level = param;
    508 
    509       r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_PROFILELEVELTYPE));
    510       if (r)
    511          return r;
    512 
    513       profile_level->eProfile = priv->profile_level.eProfile;
    514       profile_level->eLevel = priv->profile_level.eLevel;
    515 
    516       break;
    517    }
    518    default:
    519       return omx_base_component_GetParameter(handle, idx, param);
    520    }
    521    return OMX_ErrorNone;
    522 }
    523 
    524 static OMX_ERRORTYPE vid_enc_SetConfig(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR config)
    525 {
    526    OMX_COMPONENTTYPE *comp = handle;
    527    vid_enc_PrivateType *priv = comp->pComponentPrivate;
    528    OMX_ERRORTYPE r;
    529    int i;
    530 
    531    if (!config)
    532       return OMX_ErrorBadParameter;
    533 
    534    switch(idx) {
    535    case OMX_IndexConfigVideoIntraVOPRefresh: {
    536       OMX_CONFIG_INTRAREFRESHVOPTYPE *type = config;
    537 
    538       r = checkHeader(config, sizeof(OMX_CONFIG_INTRAREFRESHVOPTYPE));
    539       if (r)
    540          return r;
    541 
    542       priv->force_pic_type = *type;
    543 
    544       break;
    545    }
    546    case OMX_IndexConfigCommonScale: {
    547       OMX_CONFIG_SCALEFACTORTYPE *scale = config;
    548 
    549       r = checkHeader(config, sizeof(OMX_CONFIG_SCALEFACTORTYPE));
    550       if (r)
    551          return r;
    552 
    553       if (scale->xWidth < 176 || scale->xHeight < 144)
    554          return OMX_ErrorBadParameter;
    555 
    556       for (i = 0; i < OMX_VID_ENC_NUM_SCALING_BUFFERS; ++i) {
    557          if (priv->scale_buffer[i]) {
    558             priv->scale_buffer[i]->destroy(priv->scale_buffer[i]);
    559             priv->scale_buffer[i] = NULL;
    560          }
    561       }
    562 
    563       priv->scale = *scale;
    564       if (priv->scale.xWidth != 0xffffffff && priv->scale.xHeight != 0xffffffff) {
    565          struct pipe_video_buffer templat = {};
    566 
    567          templat.buffer_format = PIPE_FORMAT_NV12;
    568          templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
    569          templat.width = priv->scale.xWidth;
    570          templat.height = priv->scale.xHeight;
    571          templat.interlaced = false;
    572          for (i = 0; i < OMX_VID_ENC_NUM_SCALING_BUFFERS; ++i) {
    573             priv->scale_buffer[i] = priv->s_pipe->create_video_buffer(priv->s_pipe, &templat);
    574             if (!priv->scale_buffer[i])
    575                return OMX_ErrorInsufficientResources;
    576          }
    577       }
    578 
    579       break;
    580    }
    581    default:
    582       return omx_base_component_SetConfig(handle, idx, config);
    583    }
    584 
    585    return OMX_ErrorNone;
    586 }
    587 
    588 static OMX_ERRORTYPE vid_enc_GetConfig(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR config)
    589 {
    590    OMX_COMPONENTTYPE *comp = handle;
    591    vid_enc_PrivateType *priv = comp->pComponentPrivate;
    592    OMX_ERRORTYPE r;
    593 
    594    if (!config)
    595       return OMX_ErrorBadParameter;
    596 
    597    switch(idx) {
    598    case OMX_IndexConfigCommonScale: {
    599       OMX_CONFIG_SCALEFACTORTYPE *scale = config;
    600 
    601       r = checkHeader(config, sizeof(OMX_CONFIG_SCALEFACTORTYPE));
    602       if (r)
    603          return r;
    604 
    605       scale->xWidth = priv->scale.xWidth;
    606       scale->xHeight = priv->scale.xHeight;
    607 
    608       break;
    609    }
    610    default:
    611       return omx_base_component_GetConfig(handle, idx, config);
    612    }
    613 
    614    return OMX_ErrorNone;
    615 }
    616 
    617 static enum pipe_video_profile enc_TranslateOMXProfileToPipe(unsigned omx_profile)
    618 {
    619    switch (omx_profile) {
    620    case OMX_VIDEO_AVCProfileBaseline:
    621       return PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE;
    622    case OMX_VIDEO_AVCProfileMain:
    623       return PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN;
    624    case OMX_VIDEO_AVCProfileExtended:
    625       return PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED;
    626    case OMX_VIDEO_AVCProfileHigh:
    627       return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH;
    628    case OMX_VIDEO_AVCProfileHigh10:
    629       return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10;
    630    case OMX_VIDEO_AVCProfileHigh422:
    631       return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH422;
    632    case OMX_VIDEO_AVCProfileHigh444:
    633       return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH444;
    634    default:
    635       return PIPE_VIDEO_PROFILE_UNKNOWN;
    636    }
    637 }
    638 
    639 static unsigned enc_TranslateOMXLevelToPipe(unsigned omx_level)
    640 {
    641    switch (omx_level) {
    642    case OMX_VIDEO_AVCLevel1:
    643    case OMX_VIDEO_AVCLevel1b:
    644       return 10;
    645    case OMX_VIDEO_AVCLevel11:
    646       return 11;
    647    case OMX_VIDEO_AVCLevel12:
    648       return 12;
    649    case OMX_VIDEO_AVCLevel13:
    650       return 13;
    651    case OMX_VIDEO_AVCLevel2:
    652       return 20;
    653    case OMX_VIDEO_AVCLevel21:
    654       return 21;
    655    case OMX_VIDEO_AVCLevel22:
    656       return 22;
    657    case OMX_VIDEO_AVCLevel3:
    658       return 30;
    659    case OMX_VIDEO_AVCLevel31:
    660       return 31;
    661    case OMX_VIDEO_AVCLevel32:
    662       return 32;
    663    case OMX_VIDEO_AVCLevel4:
    664       return 40;
    665    case OMX_VIDEO_AVCLevel41:
    666       return 41;
    667    default:
    668    case OMX_VIDEO_AVCLevel42:
    669       return 42;
    670    case OMX_VIDEO_AVCLevel5:
    671       return 50;
    672    case OMX_VIDEO_AVCLevel51:
    673       return 51;
    674    }
    675 }
    676 
    677 static OMX_ERRORTYPE vid_enc_MessageHandler(OMX_COMPONENTTYPE* comp, internalRequestMessageType *msg)
    678 {
    679    vid_enc_PrivateType* priv = comp->pComponentPrivate;
    680 
    681    if (msg->messageType == OMX_CommandStateSet) {
    682       if ((msg->messageParam == OMX_StateIdle ) && (priv->state == OMX_StateLoaded)) {
    683 
    684          struct pipe_video_codec templat = {};
    685          omx_base_video_PortType *port;
    686 
    687          port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX];
    688 
    689          templat.profile = enc_TranslateOMXProfileToPipe(priv->profile_level.eProfile);
    690          templat.level = enc_TranslateOMXLevelToPipe(priv->profile_level.eLevel);
    691          templat.entrypoint = PIPE_VIDEO_ENTRYPOINT_ENCODE;
    692          templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
    693          templat.width = priv->scale_buffer[priv->current_scale_buffer] ?
    694                             priv->scale.xWidth : port->sPortParam.format.video.nFrameWidth;
    695          templat.height = priv->scale_buffer[priv->current_scale_buffer] ?
    696                             priv->scale.xHeight : port->sPortParam.format.video.nFrameHeight;
    697 
    698          if (templat.profile == PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE) {
    699             struct pipe_screen *screen = priv->screen->pscreen;
    700             templat.max_references = 1;
    701             priv->stacked_frames_num =
    702                screen->get_video_param(screen,
    703                                        PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH,
    704                                        PIPE_VIDEO_ENTRYPOINT_ENCODE,
    705                                        PIPE_VIDEO_CAP_STACKED_FRAMES);
    706          } else {
    707             templat.max_references = OMX_VID_ENC_P_PERIOD_DEFAULT;
    708             priv->stacked_frames_num = 1;
    709          }
    710          priv->codec = priv->s_pipe->create_video_codec(priv->s_pipe, &templat);
    711 
    712       } else if ((msg->messageParam == OMX_StateLoaded) && (priv->state == OMX_StateIdle)) {
    713          if (priv->codec) {
    714             priv->codec->destroy(priv->codec);
    715             priv->codec = NULL;
    716          }
    717       }
    718    }
    719 
    720    return omx_base_component_MessageHandler(comp, msg);
    721 }
    722 
    723 static OMX_ERRORTYPE vid_enc_AllocateInBuffer(omx_base_PortType *port, OMX_INOUT OMX_BUFFERHEADERTYPE **buf,
    724                                               OMX_IN OMX_U32 idx, OMX_IN OMX_PTR private, OMX_IN OMX_U32 size)
    725 {
    726    struct input_buf_private *inp;
    727    OMX_ERRORTYPE r;
    728 
    729    r = base_port_AllocateBuffer(port, buf, idx, private, size);
    730    if (r)
    731       return r;
    732 
    733    inp = (*buf)->pInputPortPrivate = CALLOC_STRUCT(input_buf_private);
    734    if (!inp) {
    735       base_port_FreeBuffer(port, idx, *buf);
    736       return OMX_ErrorInsufficientResources;
    737    }
    738 
    739    LIST_INITHEAD(&inp->tasks);
    740 
    741    FREE((*buf)->pBuffer);
    742    r = enc_AllocateBackTexture(port, &inp->resource, &inp->transfer, &(*buf)->pBuffer);
    743    if (r) {
    744       FREE(inp);
    745       base_port_FreeBuffer(port, idx, *buf);
    746       return r;
    747    }
    748 
    749    return OMX_ErrorNone;
    750 }
    751 
    752 static OMX_ERRORTYPE vid_enc_UseInBuffer(omx_base_PortType *port, OMX_BUFFERHEADERTYPE **buf, OMX_U32 idx,
    753                                          OMX_PTR private, OMX_U32 size, OMX_U8 *mem)
    754 {
    755    struct input_buf_private *inp;
    756    OMX_ERRORTYPE r;
    757 
    758    r = base_port_UseBuffer(port, buf, idx, private, size, mem);
    759    if (r)
    760       return r;
    761 
    762    inp = (*buf)->pInputPortPrivate = CALLOC_STRUCT(input_buf_private);
    763    if (!inp) {
    764       base_port_FreeBuffer(port, idx, *buf);
    765       return OMX_ErrorInsufficientResources;
    766    }
    767 
    768    LIST_INITHEAD(&inp->tasks);
    769 
    770    return OMX_ErrorNone;
    771 }
    772 
    773 static OMX_ERRORTYPE vid_enc_FreeInBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf)
    774 {
    775    OMX_COMPONENTTYPE* comp = port->standCompContainer;
    776    vid_enc_PrivateType *priv = comp->pComponentPrivate;
    777    struct input_buf_private *inp = buf->pInputPortPrivate;
    778 
    779    if (inp) {
    780       enc_ReleaseTasks(&inp->tasks);
    781       if (inp->transfer)
    782          pipe_transfer_unmap(priv->s_pipe, inp->transfer);
    783       pipe_resource_reference(&inp->resource, NULL);
    784       FREE(inp);
    785    }
    786    buf->pBuffer = NULL;
    787 
    788    return base_port_FreeBuffer(port, idx, buf);
    789 }
    790 
    791 static OMX_ERRORTYPE vid_enc_AllocateOutBuffer(omx_base_PortType *port, OMX_INOUT OMX_BUFFERHEADERTYPE **buf,
    792                                                OMX_IN OMX_U32 idx, OMX_IN OMX_PTR private, OMX_IN OMX_U32 size)
    793 {
    794    OMX_ERRORTYPE r;
    795 
    796    r = base_port_AllocateBuffer(port, buf, idx, private, size);
    797    if (r)
    798       return r;
    799 
    800    FREE((*buf)->pBuffer);
    801    (*buf)->pBuffer = NULL;
    802    (*buf)->pOutputPortPrivate = CALLOC(1, sizeof(struct output_buf_private));
    803    if (!(*buf)->pOutputPortPrivate) {
    804       base_port_FreeBuffer(port, idx, *buf);
    805       return OMX_ErrorInsufficientResources;
    806    }
    807 
    808    return OMX_ErrorNone;
    809 }
    810 
    811 static OMX_ERRORTYPE vid_enc_FreeOutBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf)
    812 {
    813    OMX_COMPONENTTYPE* comp = port->standCompContainer;
    814    vid_enc_PrivateType *priv = comp->pComponentPrivate;
    815 
    816    if (buf->pOutputPortPrivate) {
    817       struct output_buf_private *outp = buf->pOutputPortPrivate;
    818       if (outp->transfer)
    819          pipe_transfer_unmap(priv->t_pipe, outp->transfer);
    820       pipe_resource_reference(&outp->bitstream, NULL);
    821       FREE(outp);
    822       buf->pOutputPortPrivate = NULL;
    823    }
    824    buf->pBuffer = NULL;
    825 
    826    return base_port_FreeBuffer(port, idx, buf);
    827 }
    828 
    829 static struct encode_task *enc_NeedTask(omx_base_PortType *port)
    830 {
    831    OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video;
    832    OMX_COMPONENTTYPE* comp = port->standCompContainer;
    833    vid_enc_PrivateType *priv = comp->pComponentPrivate;
    834 
    835    struct pipe_video_buffer templat = {};
    836    struct encode_task *task;
    837 
    838    if (!LIST_IS_EMPTY(&priv->free_tasks)) {
    839       task = LIST_ENTRY(struct encode_task, priv->free_tasks.next, list);
    840       LIST_DEL(&task->list);
    841       return task;
    842    }
    843 
    844    /* allocate a new one */
    845    task = CALLOC_STRUCT(encode_task);
    846    if (!task)
    847       return NULL;
    848 
    849    templat.buffer_format = PIPE_FORMAT_NV12;
    850    templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
    851    templat.width = def->nFrameWidth;
    852    templat.height = def->nFrameHeight;
    853    templat.interlaced = false;
    854 
    855    task->buf = priv->s_pipe->create_video_buffer(priv->s_pipe, &templat);
    856    if (!task->buf) {
    857       FREE(task);
    858       return NULL;
    859    }
    860 
    861    return task;
    862 }
    863 
    864 static void enc_MoveTasks(struct list_head *from, struct list_head *to)
    865 {
    866    to->prev->next = from->next;
    867    from->next->prev = to->prev;
    868    from->prev->next = to;
    869    to->prev = from->prev;
    870    LIST_INITHEAD(from);
    871 }
    872 
    873 static void enc_ReleaseTasks(struct list_head *head)
    874 {
    875    struct encode_task *i, *next;
    876 
    877    if (!head || !head->next)
    878       return;
    879 
    880    LIST_FOR_EACH_ENTRY_SAFE(i, next, head, list) {
    881       pipe_resource_reference(&i->bitstream, NULL);
    882       i->buf->destroy(i->buf);
    883       FREE(i);
    884    }
    885 }
    886 
    887 static OMX_ERRORTYPE enc_LoadImage(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf,
    888                                    struct pipe_video_buffer *vbuf)
    889 {
    890    OMX_COMPONENTTYPE* comp = port->standCompContainer;
    891    vid_enc_PrivateType *priv = comp->pComponentPrivate;
    892    OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video;
    893    struct pipe_box box = {};
    894    struct input_buf_private *inp = buf->pInputPortPrivate;
    895 
    896    if (!inp->resource) {
    897       struct pipe_sampler_view **views;
    898       void *ptr;
    899 
    900       views = vbuf->get_sampler_view_planes(vbuf);
    901       if (!views)
    902          return OMX_ErrorInsufficientResources;
    903 
    904       ptr = buf->pBuffer;
    905       box.width = def->nFrameWidth;
    906       box.height = def->nFrameHeight;
    907       box.depth = 1;
    908       priv->s_pipe->texture_subdata(priv->s_pipe, views[0]->texture, 0,
    909                                     PIPE_TRANSFER_WRITE, &box,
    910                                     ptr, def->nStride, 0);
    911       ptr = ((uint8_t*)buf->pBuffer) + (def->nStride * box.height);
    912       box.width = def->nFrameWidth / 2;
    913       box.height = def->nFrameHeight / 2;
    914       box.depth = 1;
    915       priv->s_pipe->texture_subdata(priv->s_pipe, views[1]->texture, 0,
    916                                     PIPE_TRANSFER_WRITE, &box,
    917                                     ptr, def->nStride, 0);
    918    } else {
    919       struct pipe_blit_info blit;
    920       struct vl_video_buffer *dst_buf = (struct vl_video_buffer *)vbuf;
    921 
    922       pipe_transfer_unmap(priv->s_pipe, inp->transfer);
    923 
    924       box.width = def->nFrameWidth;
    925       box.height = def->nFrameHeight;
    926       box.depth = 1;
    927 
    928       priv->s_pipe->resource_copy_region(priv->s_pipe,
    929                                          dst_buf->resources[0],
    930                                          0, 0, 0, 0, inp->resource, 0, &box);
    931 
    932       memset(&blit, 0, sizeof(blit));
    933       blit.src.resource = inp->resource;
    934       blit.src.format = inp->resource->format;
    935 
    936       blit.src.box.x = 0;
    937       blit.src.box.y = def->nFrameHeight;
    938       blit.src.box.width = def->nFrameWidth;
    939       blit.src.box.height = def->nFrameHeight / 2 ;
    940       blit.src.box.depth = 1;
    941 
    942       blit.dst.resource = dst_buf->resources[1];
    943       blit.dst.format = blit.dst.resource->format;
    944 
    945       blit.dst.box.width = def->nFrameWidth / 2;
    946       blit.dst.box.height = def->nFrameHeight / 2;
    947       blit.dst.box.depth = 1;
    948       blit.filter = PIPE_TEX_FILTER_NEAREST;
    949 
    950       blit.mask = PIPE_MASK_G;
    951       priv->s_pipe->blit(priv->s_pipe, &blit);
    952 
    953       blit.src.box.x = 1;
    954       blit.mask = PIPE_MASK_R;
    955       priv->s_pipe->blit(priv->s_pipe, &blit);
    956       priv->s_pipe->flush(priv->s_pipe, NULL, 0);
    957 
    958       box.width = inp->resource->width0;
    959       box.height = inp->resource->height0;
    960       box.depth = inp->resource->depth0;
    961       buf->pBuffer = priv->s_pipe->transfer_map(priv->s_pipe, inp->resource, 0,
    962                                                 PIPE_TRANSFER_WRITE, &box,
    963                                                 &inp->transfer);
    964    }
    965 
    966    return OMX_ErrorNone;
    967 }
    968 
    969 static void enc_ScaleInput(omx_base_PortType *port, struct pipe_video_buffer **vbuf, unsigned *size)
    970 {
    971    OMX_COMPONENTTYPE* comp = port->standCompContainer;
    972    vid_enc_PrivateType *priv = comp->pComponentPrivate;
    973    OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video;
    974    struct pipe_video_buffer *src_buf = *vbuf;
    975    struct vl_compositor *compositor = &priv->compositor;
    976    struct vl_compositor_state *s = &priv->cstate;
    977    struct pipe_sampler_view **views;
    978    struct pipe_surface **dst_surface;
    979    unsigned i;
    980 
    981    if (!priv->scale_buffer[priv->current_scale_buffer])
    982       return;
    983 
    984    views = src_buf->get_sampler_view_planes(src_buf);
    985    dst_surface = priv->scale_buffer[priv->current_scale_buffer]->get_surfaces
    986                  (priv->scale_buffer[priv->current_scale_buffer]);
    987    vl_compositor_clear_layers(s);
    988 
    989    for (i = 0; i < VL_MAX_SURFACES; ++i) {
    990       struct u_rect src_rect;
    991       if (!views[i] || !dst_surface[i])
    992          continue;
    993       src_rect.x0 = 0;
    994       src_rect.y0 = 0;
    995       src_rect.x1 = def->nFrameWidth;
    996       src_rect.y1 = def->nFrameHeight;
    997       if (i > 0) {
    998          src_rect.x1 /= 2;
    999          src_rect.y1 /= 2;
   1000       }
   1001       vl_compositor_set_rgba_layer(s, compositor, 0, views[i], &src_rect, NULL, NULL);
   1002       vl_compositor_render(s, compositor, dst_surface[i], NULL, false);
   1003    }
   1004    *size  = priv->scale.xWidth * priv->scale.xHeight * 2;
   1005    *vbuf = priv->scale_buffer[priv->current_scale_buffer++];
   1006    priv->current_scale_buffer %= OMX_VID_ENC_NUM_SCALING_BUFFERS;
   1007 }
   1008 
   1009 static void enc_GetPictureParamPreset(struct pipe_h264_enc_picture_desc *picture)
   1010 {
   1011    picture->motion_est.enc_disable_sub_mode = 0x000000fe;
   1012    picture->motion_est.enc_ime2_search_range_x = 0x00000001;
   1013    picture->motion_est.enc_ime2_search_range_y = 0x00000001;
   1014    picture->pic_ctrl.enc_constraint_set_flags = 0x00000040;
   1015 }
   1016 
   1017 static void enc_ControlPicture(omx_base_PortType *port, struct pipe_h264_enc_picture_desc *picture)
   1018 {
   1019    OMX_COMPONENTTYPE* comp = port->standCompContainer;
   1020    vid_enc_PrivateType *priv = comp->pComponentPrivate;
   1021    struct pipe_h264_enc_rate_control *rate_ctrl = &picture->rate_ctrl;
   1022 
   1023    switch (priv->bitrate.eControlRate) {
   1024    case OMX_Video_ControlRateVariable:
   1025       rate_ctrl->rate_ctrl_method = PIPE_H264_ENC_RATE_CONTROL_METHOD_VARIABLE;
   1026       break;
   1027    case OMX_Video_ControlRateConstant:
   1028       rate_ctrl->rate_ctrl_method = PIPE_H264_ENC_RATE_CONTROL_METHOD_CONSTANT;
   1029       break;
   1030    case OMX_Video_ControlRateVariableSkipFrames:
   1031       rate_ctrl->rate_ctrl_method = PIPE_H264_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP;
   1032       break;
   1033    case OMX_Video_ControlRateConstantSkipFrames:
   1034       rate_ctrl->rate_ctrl_method = PIPE_H264_ENC_RATE_CONTROL_METHOD_CONSTANT_SKIP;
   1035       break;
   1036    default:
   1037       rate_ctrl->rate_ctrl_method = PIPE_H264_ENC_RATE_CONTROL_METHOD_DISABLE;
   1038       break;
   1039    }
   1040 
   1041    rate_ctrl->frame_rate_den = OMX_VID_ENC_CONTROL_FRAME_RATE_DEN_DEFAULT;
   1042    rate_ctrl->frame_rate_num = ((priv->frame_rate) >> 16) * rate_ctrl->frame_rate_den;
   1043 
   1044    if (rate_ctrl->rate_ctrl_method != PIPE_H264_ENC_RATE_CONTROL_METHOD_DISABLE) {
   1045       if (priv->bitrate.nTargetBitrate < OMX_VID_ENC_BITRATE_MIN)
   1046          rate_ctrl->target_bitrate = OMX_VID_ENC_BITRATE_MIN;
   1047       else if (priv->bitrate.nTargetBitrate < OMX_VID_ENC_BITRATE_MAX)
   1048          rate_ctrl->target_bitrate = priv->bitrate.nTargetBitrate;
   1049       else
   1050          rate_ctrl->target_bitrate = OMX_VID_ENC_BITRATE_MAX;
   1051       rate_ctrl->peak_bitrate = rate_ctrl->target_bitrate;
   1052       if (rate_ctrl->target_bitrate < OMX_VID_ENC_BITRATE_MEDIAN)
   1053          rate_ctrl->vbv_buffer_size = MIN2((rate_ctrl->target_bitrate * 2.75), OMX_VID_ENC_BITRATE_MEDIAN);
   1054       else
   1055          rate_ctrl->vbv_buffer_size = rate_ctrl->target_bitrate;
   1056 
   1057       if (rate_ctrl->frame_rate_num) {
   1058          unsigned long long t = rate_ctrl->target_bitrate;
   1059          t *= rate_ctrl->frame_rate_den;
   1060          rate_ctrl->target_bits_picture = t / rate_ctrl->frame_rate_num;
   1061       } else {
   1062          rate_ctrl->target_bits_picture = rate_ctrl->target_bitrate;
   1063       }
   1064       rate_ctrl->peak_bits_picture_integer = rate_ctrl->target_bits_picture;
   1065       rate_ctrl->peak_bits_picture_fraction = 0;
   1066    }
   1067 
   1068    picture->quant_i_frames = priv->quant.nQpI;
   1069    picture->quant_p_frames = priv->quant.nQpP;
   1070    picture->quant_b_frames = priv->quant.nQpB;
   1071 
   1072    picture->frame_num = priv->frame_num;
   1073    picture->ref_idx_l0 = priv->ref_idx_l0;
   1074    picture->ref_idx_l1 = priv->ref_idx_l1;
   1075    picture->enable_vui = (picture->rate_ctrl.frame_rate_num != 0);
   1076    enc_GetPictureParamPreset(picture);
   1077 }
   1078 
   1079 static void enc_HandleTask(omx_base_PortType *port, struct encode_task *task,
   1080                            enum pipe_h264_enc_picture_type picture_type)
   1081 {
   1082    OMX_COMPONENTTYPE* comp = port->standCompContainer;
   1083    vid_enc_PrivateType *priv = comp->pComponentPrivate;
   1084    unsigned size = priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX]->sPortParam.nBufferSize;
   1085    struct pipe_video_buffer *vbuf = task->buf;
   1086    struct pipe_h264_enc_picture_desc picture = {};
   1087 
   1088    /* -------------- scale input image --------- */
   1089    enc_ScaleInput(port, &vbuf, &size);
   1090    priv->s_pipe->flush(priv->s_pipe, NULL, 0);
   1091 
   1092    /* -------------- allocate output buffer --------- */
   1093    task->bitstream = pipe_buffer_create(priv->s_pipe->screen, PIPE_BIND_VERTEX_BUFFER,
   1094                                         PIPE_USAGE_STREAM, size);
   1095 
   1096    picture.picture_type = picture_type;
   1097    picture.pic_order_cnt = task->pic_order_cnt;
   1098    if (priv->restricted_b_frames && picture_type == PIPE_H264_ENC_PICTURE_TYPE_B)
   1099       picture.not_referenced = true;
   1100    enc_ControlPicture(port, &picture);
   1101 
   1102    /* -------------- encode frame --------- */
   1103    priv->codec->begin_frame(priv->codec, vbuf, &picture.base);
   1104    priv->codec->encode_bitstream(priv->codec, vbuf, task->bitstream, &task->feedback);
   1105    priv->codec->end_frame(priv->codec, vbuf, &picture.base);
   1106 }
   1107 
   1108 static void enc_ClearBframes(omx_base_PortType *port, struct input_buf_private *inp)
   1109 {
   1110    OMX_COMPONENTTYPE* comp = port->standCompContainer;
   1111    vid_enc_PrivateType *priv = comp->pComponentPrivate;
   1112    struct encode_task *task;
   1113 
   1114    if (LIST_IS_EMPTY(&priv->b_frames))
   1115       return;
   1116 
   1117    task = LIST_ENTRY(struct encode_task, priv->b_frames.prev, list);
   1118    LIST_DEL(&task->list);
   1119 
   1120    /* promote last from to P frame */
   1121    priv->ref_idx_l0 = priv->ref_idx_l1;
   1122    enc_HandleTask(port, task, PIPE_H264_ENC_PICTURE_TYPE_P);
   1123    LIST_ADDTAIL(&task->list, &inp->tasks);
   1124    priv->ref_idx_l1 = priv->frame_num++;
   1125 
   1126    /* handle B frames */
   1127    LIST_FOR_EACH_ENTRY(task, &priv->b_frames, list) {
   1128       enc_HandleTask(port, task, PIPE_H264_ENC_PICTURE_TYPE_B);
   1129       if (!priv->restricted_b_frames)
   1130          priv->ref_idx_l0 = priv->frame_num;
   1131       priv->frame_num++;
   1132    }
   1133 
   1134    enc_MoveTasks(&priv->b_frames, &inp->tasks);
   1135 }
   1136 
   1137 static OMX_ERRORTYPE vid_enc_EncodeFrame(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf)
   1138 {
   1139    OMX_COMPONENTTYPE* comp = port->standCompContainer;
   1140    vid_enc_PrivateType *priv = comp->pComponentPrivate;
   1141    struct input_buf_private *inp = buf->pInputPortPrivate;
   1142    enum pipe_h264_enc_picture_type picture_type;
   1143    struct encode_task *task;
   1144    unsigned stacked_num = 0;
   1145    OMX_ERRORTYPE err;
   1146 
   1147    enc_MoveTasks(&inp->tasks, &priv->free_tasks);
   1148    task = enc_NeedTask(port);
   1149    if (!task)
   1150       return OMX_ErrorInsufficientResources;
   1151 
   1152    if (buf->nFilledLen == 0) {
   1153       if (buf->nFlags & OMX_BUFFERFLAG_EOS) {
   1154          buf->nFilledLen = buf->nAllocLen;
   1155          enc_ClearBframes(port, inp);
   1156          enc_MoveTasks(&priv->stacked_tasks, &inp->tasks);
   1157          priv->codec->flush(priv->codec);
   1158       }
   1159       return base_port_SendBufferFunction(port, buf);
   1160    }
   1161 
   1162    if (buf->pOutputPortPrivate) {
   1163       struct pipe_video_buffer *vbuf = buf->pOutputPortPrivate;
   1164       buf->pOutputPortPrivate = task->buf;
   1165       task->buf = vbuf;
   1166    } else {
   1167       /* ------- load input image into video buffer ---- */
   1168       err = enc_LoadImage(port, buf, task->buf);
   1169       if (err != OMX_ErrorNone) {
   1170          FREE(task);
   1171          return err;
   1172       }
   1173    }
   1174 
   1175    /* -------------- determine picture type --------- */
   1176    if (!(priv->pic_order_cnt % OMX_VID_ENC_IDR_PERIOD_DEFAULT) ||
   1177        priv->force_pic_type.IntraRefreshVOP) {
   1178       enc_ClearBframes(port, inp);
   1179       picture_type = PIPE_H264_ENC_PICTURE_TYPE_IDR;
   1180       priv->force_pic_type.IntraRefreshVOP = OMX_FALSE;
   1181       priv->frame_num = 0;
   1182    } else if (priv->codec->profile == PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE ||
   1183               !(priv->pic_order_cnt % OMX_VID_ENC_P_PERIOD_DEFAULT) ||
   1184               (buf->nFlags & OMX_BUFFERFLAG_EOS)) {
   1185       picture_type = PIPE_H264_ENC_PICTURE_TYPE_P;
   1186    } else {
   1187       picture_type = PIPE_H264_ENC_PICTURE_TYPE_B;
   1188    }
   1189 
   1190    task->pic_order_cnt = priv->pic_order_cnt++;
   1191 
   1192    if (picture_type == PIPE_H264_ENC_PICTURE_TYPE_B) {
   1193       /* put frame at the tail of the queue */
   1194       LIST_ADDTAIL(&task->list, &priv->b_frames);
   1195    } else {
   1196       /* handle I or P frame */
   1197       priv->ref_idx_l0 = priv->ref_idx_l1;
   1198       enc_HandleTask(port, task, picture_type);
   1199       LIST_ADDTAIL(&task->list, &priv->stacked_tasks);
   1200       LIST_FOR_EACH_ENTRY(task, &priv->stacked_tasks, list) {
   1201          ++stacked_num;
   1202       }
   1203       if (stacked_num == priv->stacked_frames_num) {
   1204          struct encode_task *t;
   1205          t = LIST_ENTRY(struct encode_task, priv->stacked_tasks.next, list);
   1206          LIST_DEL(&t->list);
   1207          LIST_ADDTAIL(&t->list, &inp->tasks);
   1208       }
   1209       priv->ref_idx_l1 = priv->frame_num++;
   1210 
   1211       /* handle B frames */
   1212       LIST_FOR_EACH_ENTRY(task, &priv->b_frames, list) {
   1213          enc_HandleTask(port, task, PIPE_H264_ENC_PICTURE_TYPE_B);
   1214          if (!priv->restricted_b_frames)
   1215             priv->ref_idx_l0 = priv->frame_num;
   1216          priv->frame_num++;
   1217       }
   1218 
   1219       enc_MoveTasks(&priv->b_frames, &inp->tasks);
   1220    }
   1221 
   1222    if (LIST_IS_EMPTY(&inp->tasks))
   1223       return port->ReturnBufferFunction(port, buf);
   1224    else
   1225       return base_port_SendBufferFunction(port, buf);
   1226 }
   1227 
   1228 static void vid_enc_BufferEncoded(OMX_COMPONENTTYPE *comp, OMX_BUFFERHEADERTYPE* input, OMX_BUFFERHEADERTYPE* output)
   1229 {
   1230    vid_enc_PrivateType *priv = comp->pComponentPrivate;
   1231    struct output_buf_private *outp = output->pOutputPortPrivate;
   1232    struct input_buf_private *inp = input->pInputPortPrivate;
   1233    struct encode_task *task;
   1234    struct pipe_box box = {};
   1235    unsigned size;
   1236 
   1237    if (!inp || LIST_IS_EMPTY(&inp->tasks)) {
   1238       input->nFilledLen = 0; /* mark buffer as empty */
   1239       enc_MoveTasks(&priv->used_tasks, &inp->tasks);
   1240       return;
   1241    }
   1242 
   1243    task = LIST_ENTRY(struct encode_task, inp->tasks.next, list);
   1244    LIST_DEL(&task->list);
   1245    LIST_ADDTAIL(&task->list, &priv->used_tasks);
   1246 
   1247    if (!task->bitstream)
   1248       return;
   1249 
   1250    /* ------------- map result buffer ----------------- */
   1251 
   1252    if (outp->transfer)
   1253       pipe_transfer_unmap(priv->t_pipe, outp->transfer);
   1254 
   1255    pipe_resource_reference(&outp->bitstream, task->bitstream);
   1256    pipe_resource_reference(&task->bitstream, NULL);
   1257 
   1258    box.width = outp->bitstream->width0;
   1259    box.height = outp->bitstream->height0;
   1260    box.depth = outp->bitstream->depth0;
   1261 
   1262    output->pBuffer = priv->t_pipe->transfer_map(priv->t_pipe, outp->bitstream, 0,
   1263                                                 PIPE_TRANSFER_READ_WRITE,
   1264                                                 &box, &outp->transfer);
   1265 
   1266    /* ------------- get size of result ----------------- */
   1267 
   1268    priv->codec->get_feedback(priv->codec, task->feedback, &size);
   1269 
   1270    output->nOffset = 0;
   1271    output->nFilledLen = size; /* mark buffer as full */
   1272 }
   1273