Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (c) 2011 Intel Corporation. All Rights Reserved.
      3  * Copyright (c) Imagination Technologies Limited, UK
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the
      7  * "Software"), to deal in the Software without restriction, including
      8  * without limitation the rights to use, copy, modify, merge, publish,
      9  * distribute, sub license, and/or sell copies of the Software, and to
     10  * permit persons to whom the Software is furnished to do so, subject to
     11  * the following conditions:
     12  *
     13  * The above copyright notice and this permission notice (including the
     14  * next paragraph) shall be included in all copies or substantial portions
     15  * of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     20  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
     21  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     23  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     24  *
     25  * Authors:
     26  *    Elaine Wang <elaine.wang (at) intel.com>
     27  *    Zeng Li <zeng.li (at) intel.com>
     28  *
     29  */
     30 
     31 
     32 #include <errno.h>
     33 #include <stdlib.h>
     34 #include <unistd.h>
     35 #include <stdint.h>
     36 #include <string.h>
     37 
     38 #include "psb_def.h"
     39 #include "psb_drv_debug.h"
     40 #include "psb_surface.h"
     41 #include "psb_cmdbuf.h"
     42 #include "pnw_hostcode.h"
     43 #include "pnw_H264ES.h"
     44 #include "pnw_hostheader.h"
     45 #include "va/va_enc_h264.h"
     46 #define TOPAZ_H264_MAX_BITRATE 50000000
     47 
     48 #define INIT_CONTEXT_H264ES     context_ENC_p ctx = (context_ENC_p) obj_context->format_data
     49 #define SURFACE(id)    ((object_surface_p) object_heap_lookup( &ctx->obj_context->driver_data->surface_heap, id ))
     50 #define BUFFER(id)  ((object_buffer_p) object_heap_lookup( &ctx->obj_context->driver_data->buffer_heap, id ))
     51 static void pnw_H264ES_QueryConfigAttributes(
     52         VAProfile __maybe_unused profile,
     53         VAEntrypoint __maybe_unused entrypoint,
     54         VAConfigAttrib *attrib_list,
     55         int num_attribs)
     56 {
     57     int i;
     58 
     59     drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264ES_QueryConfigAttributes\n");
     60 
     61     /* RateControl attributes */
     62     for (i = 0; i < num_attribs; i++) {
     63         switch (attrib_list[i].type) {
     64             case VAConfigAttribRTFormat:
     65                 break;
     66 
     67             case VAConfigAttribRateControl:
     68                 attrib_list[i].value = VA_RC_NONE | VA_RC_CBR | VA_RC_VBR | VA_RC_VCM;
     69 	        break;
     70 
     71             case VAConfigAttribEncMaxRefFrames:
     72                 attrib_list[i].value = 1;
     73                 break;
     74 
     75 	    default:
     76 		attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED;
     77 		break;
     78 	}
     79     }
     80 }
     81 
     82 
     83 static VAStatus pnw_H264ES_ValidateConfig(
     84         object_config_p obj_config)
     85 {
     86     int i;
     87     /* Check all attributes */
     88     for (i = 0; i < obj_config->attrib_count; i++) {
     89         switch (obj_config->attrib_list[i].type) {
     90             case VAConfigAttribRTFormat:
     91                 /* Ignore */
     92                 break;
     93             case VAConfigAttribRateControl:
     94                 break;
     95             default:
     96                 return VA_STATUS_ERROR_ATTR_NOT_SUPPORTED;
     97         }
     98     }
     99 
    100     return VA_STATUS_SUCCESS;
    101 }
    102 
    103 
    104 static VAStatus pnw_H264ES_CreateContext(
    105         object_context_p obj_context,
    106         object_config_p obj_config)
    107 {
    108     VAStatus vaStatus = VA_STATUS_SUCCESS;
    109     context_ENC_p ctx;
    110     int i;
    111     unsigned int eRCmode;
    112 
    113     drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264ES_CreateContext\n");
    114 
    115     vaStatus = pnw_CreateContext(obj_context, obj_config, 0);
    116 
    117     if (VA_STATUS_SUCCESS != vaStatus)
    118         return VA_STATUS_ERROR_ALLOCATION_FAILED;
    119 
    120     ctx = (context_ENC_p) obj_context->format_data;
    121 
    122     for (i = 0; i < obj_config->attrib_count; i++) {
    123         if (obj_config->attrib_list[i].type == VAConfigAttribRateControl)
    124             break;
    125     }
    126 
    127     if (i >= obj_config->attrib_count)
    128         eRCmode = VA_RC_NONE;
    129     else
    130         eRCmode = obj_config->attrib_list[i].value;
    131 
    132 
    133     if (eRCmode == VA_RC_VBR) {
    134         ctx->eCodec = IMG_CODEC_H264_VBR;
    135         ctx->sRCParams.RCEnable = IMG_TRUE;
    136         ctx->sRCParams.bDisableBitStuffing = IMG_FALSE;
    137     } else if (eRCmode == VA_RC_CBR) {
    138         ctx->eCodec = IMG_CODEC_H264_CBR;
    139         ctx->sRCParams.RCEnable = IMG_TRUE;
    140         ctx->sRCParams.bDisableBitStuffing = IMG_TRUE;
    141     } else if (eRCmode == VA_RC_NONE) {
    142         ctx->eCodec = IMG_CODEC_H264_NO_RC;
    143         ctx->sRCParams.RCEnable = IMG_FALSE;
    144         ctx->sRCParams.bDisableBitStuffing = IMG_FALSE;
    145     } else if (eRCmode == VA_RC_VCM) {
    146         ctx->eCodec = IMG_CODEC_H264_VCM;
    147         ctx->sRCParams.RCEnable = IMG_TRUE;
    148         ctx->sRCParams.bDisableBitStuffing = IMG_FALSE;
    149     } else
    150         return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
    151 
    152     drv_debug_msg(VIDEO_DEBUG_GENERAL, "eCodec is %d\n", ctx->eCodec);
    153     ctx->eFormat = IMG_CODEC_PL12;      /* use default */
    154 
    155     ctx->Slices = 1;
    156     ctx->idr_pic_id = 1;
    157     ctx->buffer_size = 0;
    158     ctx->initial_buffer_fullness = 0;
    159     //initialize the frame_rate and qp
    160     ctx->sRCParams.FrameRate = 30;
    161 
    162     if (getenv("PSB_VIDEO_SIG_CORE") == NULL) {
    163         ctx->Slices = 2;
    164         ctx->NumCores = 2;
    165     }
    166 
    167     ctx->ParallelCores = min(ctx->NumCores, ctx->Slices);
    168 
    169     ctx->IPEControl = pnw__get_ipe_control(ctx->eCodec);
    170 
    171     switch (obj_config->profile) {
    172         case VAProfileH264Baseline:
    173             ctx->profile_idc = 5;
    174             break;
    175         case VAProfileH264Main:
    176             ctx->profile_idc = 6;
    177             break;
    178         default:
    179             ctx->profile_idc = 6;
    180             break;
    181     }
    182 
    183     return vaStatus;
    184 }
    185 
    186 static void pnw_H264ES_DestroyContext(
    187         object_context_p obj_context)
    188 {
    189     drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264ES_DestroyPicture\n");
    190 
    191     pnw_DestroyContext(obj_context);
    192 }
    193 
    194 static VAStatus pnw_H264ES_BeginPicture(
    195         object_context_p obj_context)
    196 {
    197     INIT_CONTEXT_H264ES;
    198     VAStatus vaStatus = VA_STATUS_SUCCESS;
    199 
    200     drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264ES_BeginPicture\n");
    201 
    202     vaStatus = pnw_BeginPicture(ctx);
    203 
    204     return vaStatus;
    205 }
    206 
    207 static VAStatus pnw__H264ES_process_sequence_param(context_ENC_p ctx, object_buffer_p obj_buffer)
    208 {
    209     VAEncSequenceParameterBufferH264 *pSequenceParams;
    210     pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf;
    211     H264_VUI_PARAMS *pVUI_Params = &(ctx->VUI_Params);
    212     H264_CROP_PARAMS sCrop;
    213     int i;
    214     unsigned int frame_size;
    215     unsigned int max_bps;
    216 
    217     ASSERT(obj_buffer->type == VAEncSequenceParameterBufferType);
    218     ASSERT(obj_buffer->num_elements == 1);
    219     ASSERT(obj_buffer->size == sizeof(VAEncSequenceParameterBufferH264));
    220 
    221     if ((obj_buffer->num_elements != 1) ||
    222             (obj_buffer->size != sizeof(VAEncSequenceParameterBufferH264))) {
    223         return VA_STATUS_ERROR_UNKNOWN;
    224     }
    225 
    226     if(ctx->sRCParams.FrameRate == 0)
    227         ctx->sRCParams.FrameRate = 30;
    228     ctx->obj_context->frame_count = 0;
    229 
    230     pSequenceParams = (VAEncSequenceParameterBufferH264 *) obj_buffer->buffer_data;
    231     obj_buffer->buffer_data = NULL;
    232     obj_buffer->size = 0;
    233 
    234     if (!pSequenceParams->bits_per_second) {
    235         pSequenceParams->bits_per_second = ctx->Height * ctx->Width * 30 * 12;
    236         drv_debug_msg(VIDEO_DEBUG_GENERAL, "bits_per_second is 0, set to %d\n",
    237                 pSequenceParams->bits_per_second);
    238     }
    239     ctx->sRCParams.bBitrateChanged =
    240         (pSequenceParams->bits_per_second == ctx->sRCParams.BitsPerSecond ?
    241          IMG_FALSE : IMG_TRUE);
    242 
    243     if (pSequenceParams->bits_per_second > TOPAZ_H264_MAX_BITRATE) {
    244         ctx->sRCParams.BitsPerSecond = TOPAZ_H264_MAX_BITRATE;
    245         drv_debug_msg(VIDEO_DEBUG_GENERAL, " bits_per_second(%d) exceeds \
    246                 the maximum bitrate, set it with %d\n",
    247                 pSequenceParams->bits_per_second,
    248                 TOPAZ_H264_MAX_BITRATE);
    249     }
    250 
    251     /* According to Table A-1 Level limits, if resolution is bigger than 625SD,
    252        min compression ratio is 4, otherwise min compression ratio is 2 */
    253     max_bps =  (ctx->Width * ctx->Height * 3 / 2 ) * 8 * ctx->sRCParams.FrameRate;
    254     if (ctx->Width > 720)
    255         max_bps /= 4;
    256     else
    257         max_bps /= 2;
    258 
    259     drv_debug_msg(VIDEO_DEBUG_GENERAL, " width %d height %d, frame rate %d\n",
    260             ctx->Width, ctx->Height, ctx->sRCParams.FrameRate);
    261     if (pSequenceParams->bits_per_second > max_bps) {
    262         drv_debug_msg(VIDEO_DEBUG_ERROR,
    263                 "Invalid bitrate %d, violate ITU-T Rec. H.264 (03/2005) A.3.1"
    264                 "\n clip to %d bps\n", pSequenceParams->bits_per_second, max_bps);
    265         ctx->sRCParams.BitsPerSecond = max_bps;
    266     } else {
    267         /* See 110% target bitrate for VCM. Otherwise, the resulted bitrate is much lower
    268            than target bitrate */
    269         if (ctx->eCodec == IMG_CODEC_H264_VCM)
    270             pSequenceParams->bits_per_second =
    271                 pSequenceParams->bits_per_second / 100 * 110;
    272 
    273         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Bitrate is set to %d\n",
    274                 pSequenceParams->bits_per_second);
    275         ctx->sRCParams.BitsPerSecond = pSequenceParams->bits_per_second;
    276     }
    277 
    278     /*if (ctx->sRCParams.IntraFreq != pSequenceParams->intra_period)
    279       ctx->sRCParams.bBitrateChanged = IMG_TRUE;*/
    280     ctx->sRCParams.IDRFreq = pSequenceParams->intra_idr_period;
    281 
    282     ctx->sRCParams.Slices = ctx->Slices;
    283     ctx->sRCParams.QCPOffset = 0;
    284 
    285     if (ctx->sRCParams.IntraFreq != pSequenceParams->intra_period
    286             && ctx->raw_frame_count != 0
    287             && ctx->sRCParams.IntraFreq != 0
    288             && ((ctx->obj_context->frame_count + 1) % ctx->sRCParams.IntraFreq) != 0
    289             && (!ctx->sRCParams.bDisableFrameSkipping)) {
    290         drv_debug_msg(VIDEO_DEBUG_ERROR,
    291                 "Changing intra period value in the middle of a GOP is\n"
    292                 "not allowed if frame skip isn't disabled.\n"
    293                 "it can cause I frame been skipped\n");
    294         free(pSequenceParams);
    295         return VA_STATUS_ERROR_INVALID_PARAMETER;
    296     }
    297     else
    298         ctx->sRCParams.IntraFreq = pSequenceParams->intra_period;
    299 
    300     frame_size = ctx->sRCParams.BitsPerSecond / ctx->sRCParams.FrameRate;
    301 
    302     if (ctx->bInserHRDParams &&
    303             ctx->buffer_size != 0 && ctx->initial_buffer_fullness != 0) {
    304         ctx->sRCParams.BufferSize = ctx->buffer_size;
    305         ctx->sRCParams.InitialLevel = ctx->buffer_size - ctx->initial_buffer_fullness;
    306         ctx->sRCParams.InitialDelay = ctx->initial_buffer_fullness;
    307     }
    308     else {
    309         ctx->buffer_size = ctx->sRCParams.BitsPerSecond;
    310         ctx->initial_buffer_fullness = ctx->sRCParams.BitsPerSecond;
    311         ctx->sRCParams.BufferSize = ctx->buffer_size;
    312         ctx->sRCParams.InitialLevel = (3 * ctx->sRCParams.BufferSize) >> 4;
    313         /* Aligned with target frame size */
    314         ctx->sRCParams.InitialLevel += (frame_size / 2);
    315         ctx->sRCParams.InitialLevel /= frame_size;
    316         ctx->sRCParams.InitialLevel *= frame_size;
    317         ctx->sRCParams.InitialDelay = ctx->buffer_size - ctx->sRCParams.InitialLevel;
    318     }
    319 
    320     if (ctx->raw_frame_count == 0) {
    321         for (i = (ctx->ParallelCores - 1); i >= 0; i--)
    322             pnw_set_bias(ctx, i);
    323     }
    324 
    325     pVUI_Params->bit_rate_value_minus1 = ctx->sRCParams.BitsPerSecond / 64 - 1;
    326     pVUI_Params->cbp_size_value_minus1 = ctx->sRCParams.BufferSize / 64 - 1;
    327     if (IMG_CODEC_H264_CBR != ctx->eCodec ||
    328             ctx->sRCParams.bDisableBitStuffing ||
    329             ctx->sRCParams.bDisableFrameSkipping)
    330         pVUI_Params->CBR = 0;
    331     else
    332         pVUI_Params->CBR = 1;
    333 
    334     pVUI_Params->initial_cpb_removal_delay_length_minus1 = BPH_SEI_NAL_INITIAL_CPB_REMOVAL_DELAY_SIZE - 1;
    335     pVUI_Params->cpb_removal_delay_length_minus1 = PTH_SEI_NAL_CPB_REMOVAL_DELAY_SIZE - 1;
    336     pVUI_Params->dpb_output_delay_length_minus1 = PTH_SEI_NAL_DPB_OUTPUT_DELAY_SIZE - 1;
    337     pVUI_Params->time_offset_length = 24;
    338     ctx->bInsertVUI = pSequenceParams->vui_parameters_present_flag ? IMG_TRUE: IMG_FALSE;
    339     if (ctx->bInsertVUI) {
    340         if (pSequenceParams->num_units_in_tick !=0 && pSequenceParams->time_scale !=0
    341                 && (pSequenceParams->time_scale > pSequenceParams->num_units_in_tick) ) {
    342             pVUI_Params->Time_Scale = pSequenceParams->time_scale;
    343             pVUI_Params->num_units_in_tick = pSequenceParams->num_units_in_tick;
    344         }
    345         else {
    346             pVUI_Params->num_units_in_tick = 1;
    347             pVUI_Params->Time_Scale = ctx->sRCParams.FrameRate * 2;
    348         }
    349     }
    350 
    351     if (ctx->bInsertVUI && pSequenceParams->vui_fields.bits.aspect_ratio_info_present_flag &&
    352             (pSequenceParams->aspect_ratio_idc == 0xff /* Extended_SAR */)) {
    353         pVUI_Params->aspect_ratio_info_present_flag = IMG_TRUE;
    354         pVUI_Params->aspect_ratio_idc = 0xff;
    355         pVUI_Params->sar_width = pSequenceParams->sar_width;
    356         pVUI_Params->sar_height = pSequenceParams->sar_height;
    357     }
    358 
    359     sCrop.bClip = pSequenceParams->frame_cropping_flag;
    360     sCrop.LeftCropOffset = 0;
    361     sCrop.RightCropOffset = 0;
    362     sCrop.TopCropOffset = 0;
    363     sCrop.BottomCropOffset = 0;
    364 
    365     if (!sCrop.bClip) {
    366         if (ctx->RawHeight & 0xf) {
    367             sCrop.bClip = IMG_TRUE;
    368             sCrop.BottomCropOffset = (((ctx->RawHeight + 0xf) & (~0xf)) - ctx->RawHeight) / 2;
    369         }
    370         if (ctx->RawWidth & 0xf) {
    371             sCrop.bClip = IMG_TRUE;
    372             sCrop.RightCropOffset = (((ctx->RawWidth + 0xf) & (~0xf)) - ctx->RawWidth) / 2;
    373         }
    374     } else {
    375         sCrop.LeftCropOffset = pSequenceParams->frame_crop_left_offset;
    376         sCrop.RightCropOffset = pSequenceParams->frame_crop_right_offset;
    377         sCrop.TopCropOffset = pSequenceParams->frame_crop_top_offset;
    378         sCrop.BottomCropOffset = pSequenceParams->frame_crop_bottom_offset;
    379     }
    380     /* sequence header is always inserted */
    381 
    382     memset(cmdbuf->header_mem_p + ctx->seq_header_ofs,
    383             0,
    384             HEADER_SIZE);
    385 
    386     /*
    387        if (ctx->bInserHRDParams) {
    388        memset(cmdbuf->header_mem_p + ctx->aud_header_ofs,
    389        0,
    390        HEADER_SIZE);
    391 
    392        pnw__H264_prepare_AUD_header(cmdbuf->header_mem_p + ctx->aud_header_ofs);
    393        pnw_cmdbuf_insert_command_package(ctx->obj_context,
    394        ctx->ParallelCores - 1,
    395        MTX_CMDID_DO_HEADER,
    396        &cmdbuf->header_mem,
    397        ctx->aud_header_ofs);
    398        }
    399      */
    400     if (ctx->eCodec == IMG_CODEC_H264_NO_RC)
    401         pnw__H264_prepare_sequence_header(cmdbuf->header_mem_p + ctx->seq_header_ofs,
    402                 pSequenceParams->picture_width_in_mbs,
    403                 pSequenceParams->picture_height_in_mbs,
    404                 pSequenceParams->vui_parameters_present_flag,
    405                 pSequenceParams->vui_parameters_present_flag ? (pVUI_Params) : NULL,
    406                 &sCrop,
    407                 pSequenceParams->level_idc, ctx->profile_idc);
    408     else
    409         pnw__H264_prepare_sequence_header(cmdbuf->header_mem_p + ctx->seq_header_ofs,
    410                 pSequenceParams->picture_width_in_mbs,
    411                 pSequenceParams->picture_height_in_mbs,
    412                 pSequenceParams->vui_parameters_present_flag,
    413                 pSequenceParams->vui_parameters_present_flag ? (pVUI_Params) : NULL,
    414                 &sCrop,
    415                 pSequenceParams->level_idc, ctx->profile_idc);
    416 
    417     /*Periodic IDR need SPS. We save the sequence header here*/
    418     if (ctx->sRCParams.IDRFreq != 0) {
    419         if (NULL == ctx->save_seq_header_p) {
    420             ctx->save_seq_header_p = malloc(HEADER_SIZE);
    421             if (NULL == ctx->save_seq_header_p) {
    422                 drv_debug_msg(VIDEO_DEBUG_ERROR, "Ran out of memory!\n");
    423                 free(pSequenceParams);
    424                 return VA_STATUS_ERROR_ALLOCATION_FAILED;
    425             }
    426             memcpy((unsigned char *)ctx->save_seq_header_p,
    427                     (unsigned char *)(cmdbuf->header_mem_p + ctx->seq_header_ofs),
    428                     HEADER_SIZE);
    429         }
    430     }
    431     ctx->none_vcl_nal++;
    432     cmdbuf->cmd_idx_saved[PNW_CMDBUF_SEQ_HEADER_IDX] = cmdbuf->cmd_idx;
    433     /* Send to the last core as this will complete first */
    434     pnw_cmdbuf_insert_command_package(ctx->obj_context,
    435             ctx->ParallelCores - 1,
    436             MTX_CMDID_DO_HEADER,
    437             &cmdbuf->header_mem,
    438             ctx->seq_header_ofs);
    439     free(pSequenceParams);
    440 
    441     return VA_STATUS_SUCCESS;
    442 }
    443 
    444 
    445 static VAStatus pnw__H264ES_insert_SEI_buffer_period(context_ENC_p ctx)
    446 {
    447     unsigned int ui32nal_initial_cpb_removal_delay;
    448     unsigned int ui32nal_initial_cpb_removal_delay_offset;
    449     pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf;
    450 
    451     ui32nal_initial_cpb_removal_delay =
    452         90000 * (1.0 * ctx->sRCParams.InitialDelay / ctx->sRCParams.BitsPerSecond);
    453     ui32nal_initial_cpb_removal_delay_offset =
    454         90000 * (1.0 * ctx->buffer_size / ctx->sRCParams.BitsPerSecond)
    455         - ui32nal_initial_cpb_removal_delay;
    456 
    457     drv_debug_msg(VIDEO_DEBUG_GENERAL, "Insert SEI buffer period message with "
    458             "ui32nal_initial_cpb_removal_delay(%d) and "
    459             "ui32nal_initial_cpb_removal_delay_offset(%d)\n",
    460             ui32nal_initial_cpb_removal_delay,
    461             ui32nal_initial_cpb_removal_delay_offset);
    462 
    463     memset(cmdbuf->header_mem_p + ctx->sei_buf_prd_ofs,
    464             0,
    465             HEADER_SIZE);
    466 
    467     pnw__H264_prepare_SEI_buffering_period_header(
    468             (MTX_HEADER_PARAMS *)(cmdbuf->header_mem_p + ctx->sei_buf_prd_ofs),
    469             1, //ui8NalHrdBpPresentFlag,
    470             0, //ui8nal_cpb_cnt_minus1,
    471             1 + ctx->VUI_Params.initial_cpb_removal_delay_length_minus1, //ui8nal_initial_cpb_removal_delay_length,
    472             ui32nal_initial_cpb_removal_delay, //ui32nal_initial_cpb_removal_delay,
    473             ui32nal_initial_cpb_removal_delay_offset, //ui32nal_initial_cpb_removal_delay_offset,
    474             0, //ui8VclHrdBpPresentFlag,
    475             NOT_USED_BY_TOPAZ, //ui8vcl_cpb_cnt_minus1,
    476             0, //ui32vcl_initial_cpb_removal_delay,
    477             0 //ui32vcl_initial_cpb_removal_delay_offset
    478             );
    479     cmdbuf->cmd_idx_saved[PNW_CMDBUF_SEI_BUF_PERIOD_IDX] = cmdbuf->cmd_idx;
    480     pnw_cmdbuf_insert_command_package(ctx->obj_context,
    481             ctx->ParallelCores - 1,
    482             MTX_CMDID_DO_HEADER,
    483             &cmdbuf->header_mem,
    484             ctx->sei_buf_prd_ofs);
    485 
    486     ctx->none_vcl_nal++;
    487     return VA_STATUS_SUCCESS;
    488 }
    489 
    490 
    491 static VAStatus pnw__H264ES_insert_SEI_pic_timing(context_ENC_p ctx)
    492 {
    493     pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf;
    494     uint32_t ui32cpb_removal_delay;
    495 
    496     drv_debug_msg(VIDEO_DEBUG_GENERAL, "Insert SEI picture timing message. \n");
    497 
    498     memset(cmdbuf->header_mem_p + ctx->sei_pic_tm_ofs,
    499             0,
    500             HEADER_SIZE);
    501 
    502     /* ui32cpb_removal_delay is zero for 1st frame and will be reset
    503      * after a IDR frame */
    504     if (ctx->obj_context->frame_count == 0) {
    505         if (ctx->raw_frame_count == 0)
    506             ui32cpb_removal_delay = 0;
    507         else
    508             ui32cpb_removal_delay =
    509                 ctx->sRCParams.IDRFreq * ctx->sRCParams.IntraFreq * 2;
    510     } else
    511         ui32cpb_removal_delay = 2 * ctx->obj_context->frame_count;
    512 
    513     pnw__H264_prepare_SEI_picture_timing_header(
    514             (MTX_HEADER_PARAMS *)(cmdbuf->header_mem_p + ctx->sei_pic_tm_ofs),
    515             1,
    516             ctx->VUI_Params.cpb_removal_delay_length_minus1,
    517             ctx->VUI_Params.dpb_output_delay_length_minus1,
    518             ui32cpb_removal_delay, //ui32cpb_removal_delay,
    519             2, //ui32dpb_output_delay,
    520             0, //ui8pic_struct_present_flag,
    521             0, //ui8pic_struct,
    522             0, //ui8NumClockTS,
    523             0, //*aui8clock_timestamp_flag,
    524             0, //ui8full_timestamp_flag,
    525             0, //ui8seconds_flag,
    526             0, //ui8minutes_flag,
    527             0, //ui8hours_flag,
    528             0, //ui8seconds_value,
    529             0, //ui8minutes_value,
    530             0, //ui8hours_value,
    531             0, //ui8ct_type,
    532             0, //ui8nuit_field_based_flag,
    533             0, //ui8counting_type,
    534             0, //ui8discontinuity_flag,
    535             0, //ui8cnt_dropped_flag,
    536             0, //ui8n_frames,
    537             0, //ui8time_offset_length,
    538             0 //i32time_offset)
    539                 );
    540 
    541     cmdbuf->cmd_idx_saved[PNW_CMDBUF_SEI_PIC_TIMING_IDX] = cmdbuf->cmd_idx;
    542     pnw_cmdbuf_insert_command_package(ctx->obj_context,
    543             ctx->ParallelCores - 1,
    544             MTX_CMDID_DO_HEADER,
    545             &cmdbuf->header_mem,
    546             ctx->sei_pic_tm_ofs);
    547 
    548     ctx->none_vcl_nal++;
    549     return VA_STATUS_SUCCESS;
    550 }
    551 
    552 #if PSB_MFLD_DUMMY_CODE
    553 static VAStatus pnw__H264ES_insert_SEI_FPA_param(context_ENC_p ctx, object_buffer_p obj_buffer)
    554 {
    555     VAStatus vaStatus = VA_STATUS_SUCCESS;
    556     pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf;
    557     VAEncPackedHeaderParameterBuffer *sei_param_buf = (VAEncPackedHeaderParameterBuffer *)obj_buffer->buffer_data;
    558 
    559     drv_debug_msg(VIDEO_DEBUG_GENERAL, "Insert SEI frame packing arrangement message. \n");
    560     ctx->sei_pic_data_size = sei_param_buf->bit_length/8;
    561 
    562     return VA_STATUS_SUCCESS;
    563 }
    564 
    565 static VAStatus pnw__H264ES_insert_SEI_FPA_data(context_ENC_p ctx, object_buffer_p obj_buffer)
    566 {
    567     VAStatus vaStatus = VA_STATUS_SUCCESS;
    568     pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf;
    569     char *sei_data_buf;
    570 
    571     drv_debug_msg(VIDEO_DEBUG_GENERAL, "Insert SEI frame packing arrangement message. \n");
    572 
    573     memset(cmdbuf->header_mem_p + ctx->sei_pic_fpa_ofs,
    574             0,
    575             HEADER_SIZE);
    576     sei_data_buf = (char *)obj_buffer->buffer_data;
    577 
    578     pnw__H264_prepare_SEI_FPA_header((MTX_HEADER_PARAMS *)(cmdbuf->header_mem_p + ctx->sei_pic_fpa_ofs), sei_data_buf, ctx->sei_pic_data_size);
    579     pnw_cmdbuf_insert_command_package(ctx->obj_context,
    580             ctx->ParallelCores - 1,
    581             MTX_CMDID_DO_HEADER,
    582             &cmdbuf->header_mem,
    583             ctx->sei_pic_fpa_ofs);
    584 
    585     return VA_STATUS_SUCCESS;
    586 }
    587 #endif
    588 
    589 static VAStatus pnw__H264ES_process_picture_param(context_ENC_p ctx, object_buffer_p obj_buffer)
    590 {
    591     VAStatus vaStatus = VA_STATUS_SUCCESS;
    592     int i;
    593     VAEncPictureParameterBufferH264 *pBuffer;
    594     int need_sps = 0;
    595     pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf;
    596 
    597     ASSERT(obj_buffer->type == VAEncPictureParameterBufferType);
    598 
    599     if ((obj_buffer->num_elements != 1) ||
    600             (obj_buffer->size != sizeof(VAEncPictureParameterBufferH264))) {
    601         return VA_STATUS_ERROR_UNKNOWN;
    602     }
    603 
    604     /* Transfer ownership of VAEncPictureParameterBufferH264 data */
    605     pBuffer = (VAEncPictureParameterBufferH264 *) obj_buffer->buffer_data;
    606     obj_buffer->buffer_data = NULL;
    607     obj_buffer->size = 0;
    608 
    609     ctx->ref_surface = SURFACE(pBuffer->ReferenceFrames[0].picture_id);
    610     ctx->dest_surface = SURFACE(pBuffer->CurrPic.picture_id);
    611     ctx->coded_buf = BUFFER(pBuffer->coded_buf);
    612 
    613     //ASSERT(ctx->Width == pBuffer->picture_width);
    614     //ASSERT(ctx->Height == pBuffer->picture_height);
    615 
    616     if (NULL == ctx->coded_buf) {
    617         drv_debug_msg(VIDEO_DEBUG_ERROR, "%s L%d Invalid coded buffer handle\n", __FUNCTION__, __LINE__);
    618         free(pBuffer);
    619         return VA_STATUS_ERROR_INVALID_BUFFER;
    620     }
    621     if ((ctx->sRCParams.IntraFreq != 0) && (ctx->sRCParams.IDRFreq != 0)) { /* period IDR is desired */
    622         unsigned int is_intra = 0;
    623         unsigned int intra_cnt = 0;
    624 
    625         ctx->force_idr_h264 = 0;
    626 
    627         if ((ctx->obj_context->frame_count % ctx->sRCParams.IntraFreq) == 0) {
    628             is_intra = 1; /* suppose current frame is I frame */
    629             intra_cnt = ctx->obj_context->frame_count / ctx->sRCParams.IntraFreq;
    630         }
    631 
    632         /* current frame is I frame (suppose), and an IDR frame is desired*/
    633         if ((is_intra) && ((intra_cnt % ctx->sRCParams.IDRFreq) == 0)) {
    634             ctx->force_idr_h264 = 1;
    635             /*When two consecutive access units in decoding order are both IDR access
    636              * units, the value of idr_pic_id in the slices of the first such IDR
    637              * access unit shall differ from the idr_pic_id in the second such IDR
    638              * access unit. We set it with 1 or 0 alternately.*/
    639             ctx->idr_pic_id = 1 - ctx->idr_pic_id;
    640 
    641             /* it is periodic IDR in the middle of one sequence encoding, need SPS */
    642             if (ctx->obj_context->frame_count > 0)
    643                 need_sps = 1;
    644 
    645             ctx->obj_context->frame_count = 0;
    646         }
    647     }
    648 
    649     /* If VUI header isn't enabled, we'll igore the request for HRD header insertion */
    650     if (ctx->bInserHRDParams)
    651         ctx->bInserHRDParams = ctx->bInsertVUI;
    652 
    653     /* For H264, PicHeader only needed in the first picture*/
    654     if (!(ctx->obj_context->frame_count)) {
    655         cmdbuf = ctx->obj_context->pnw_cmdbuf;
    656 
    657         if (need_sps) {
    658             drv_debug_msg(VIDEO_DEBUG_GENERAL, "TOPAZ: insert a SPS before IDR frame\n");
    659             /* reuse the previous SPS */
    660             memcpy((unsigned char *)(cmdbuf->header_mem_p + ctx->seq_header_ofs),
    661                     (unsigned char *)ctx->save_seq_header_p,
    662                     HEADER_SIZE);
    663 
    664             cmdbuf->cmd_idx_saved[PNW_CMDBUF_SEQ_HEADER_IDX] = cmdbuf->cmd_idx;
    665             /* Send to the last core as this will complete first */
    666             pnw_cmdbuf_insert_command_package(ctx->obj_context,
    667                     ctx->ParallelCores - 1,
    668                     MTX_CMDID_DO_HEADER,
    669                     &cmdbuf->header_mem,
    670                     ctx->seq_header_ofs);
    671             ctx->none_vcl_nal++;
    672         }
    673 
    674         if (ctx->bInserHRDParams) {
    675             pnw__H264ES_insert_SEI_buffer_period(ctx);
    676             pnw__H264ES_insert_SEI_pic_timing(ctx);
    677         }
    678 
    679         pnw__H264_prepare_picture_header(cmdbuf->header_mem_p + ctx->pic_header_ofs, IMG_FALSE, ctx->sRCParams.QCPOffset);
    680 
    681         cmdbuf->cmd_idx_saved[PNW_CMDBUF_PIC_HEADER_IDX] = cmdbuf->cmd_idx;
    682         /* Send to the last core as this will complete first */
    683         pnw_cmdbuf_insert_command_package(ctx->obj_context,
    684                 ctx->ParallelCores - 1,
    685                 MTX_CMDID_DO_HEADER,
    686                 &cmdbuf->header_mem,
    687                 ctx->pic_header_ofs);
    688         ctx->none_vcl_nal++;
    689     }
    690     else if (ctx->bInserHRDParams)
    691         pnw__H264ES_insert_SEI_pic_timing(ctx);
    692 
    693     if (ctx->ParallelCores == 1) {
    694         ctx->coded_buf_per_slice = 0;
    695         drv_debug_msg(VIDEO_DEBUG_GENERAL, "TOPAZ: won't splite coded buffer(%d) since only one slice being encoded\n",
    696                 ctx->coded_buf->size);
    697     } else {
    698         /*Make sure DMA start is 128bits alignment*/
    699         ctx->coded_buf_per_slice = (ctx->coded_buf->size / ctx->ParallelCores) & (~0xf) ;
    700         drv_debug_msg(VIDEO_DEBUG_GENERAL, "TOPAZ: the size of coded_buf per slice %d( Total %d) \n", ctx->coded_buf_per_slice,
    701                 ctx->coded_buf->size);
    702     }
    703 
    704     /* Prepare START_PICTURE params */
    705     /* FIXME is really need multiple picParams? Need multiple calculate for each? */
    706     for (i = (ctx->ParallelCores - 1); i >= 0; i--)
    707         vaStatus = pnw_RenderPictureParameter(ctx, i);
    708 
    709     free(pBuffer);
    710     return vaStatus;
    711 }
    712 
    713 static VAStatus pnw__H264ES_encode_one_slice(context_ENC_p ctx,
    714         VAEncSliceParameterBuffer *pBuffer)
    715 {
    716     pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf;
    717     unsigned int MBSkipRun, FirstMBAddress;
    718     unsigned char deblock_idc;
    719     unsigned char is_intra = 0;
    720     int slice_param_idx;
    721     PIC_PARAMS *psPicParams = (PIC_PARAMS *)(cmdbuf->pic_params_p);
    722     VAStatus vaStatus = VA_STATUS_SUCCESS;
    723 
    724     /*Slice encoding Order:
    725      *1.Insert Do header command
    726      *2.setup InRowParams
    727      *3.setup Slice params
    728      *4.Insert Do slice command
    729      * */
    730 
    731     if (pBuffer->slice_height > (ctx->Height / 16) ||
    732            pBuffer->start_row_number > (ctx->Height / 16) ||
    733            (pBuffer->slice_height + pBuffer->start_row_number) > (ctx->Height / 16)) {
    734         drv_debug_msg(VIDEO_DEBUG_ERROR, "slice height %d or start row number %d is too large",
    735                 pBuffer->slice_height,  pBuffer->start_row_number);
    736         return VA_STATUS_ERROR_INVALID_PARAMETER;
    737     }
    738     MBSkipRun = (pBuffer->slice_height * ctx->Width) / 16;
    739     deblock_idc = pBuffer->slice_flags.bits.disable_deblocking_filter_idc;
    740 
    741     /*If the frame is skipped, it shouldn't be a I frame*/
    742     if (ctx->force_idr_h264 || (ctx->obj_context->frame_count == 0)) {
    743         is_intra = 1;
    744     } else
    745         is_intra = (ctx->sRCParams.RCEnable && ctx->sRCParams.FrameSkip) ? 0 : pBuffer->slice_flags.bits.is_intra;
    746 
    747     FirstMBAddress = (pBuffer->start_row_number * ctx->Width) / 16;
    748 
    749     memset(cmdbuf->header_mem_p + ctx->slice_header_ofs
    750             + ctx->obj_context->slice_count * HEADER_SIZE,
    751             0,
    752             HEADER_SIZE);
    753 
    754     /* Insert Do Header command, relocation is needed */
    755     pnw__H264_prepare_slice_header(cmdbuf->header_mem_p + ctx->slice_header_ofs
    756             + ctx->obj_context->slice_count * HEADER_SIZE,
    757             is_intra,
    758             pBuffer->slice_flags.bits.disable_deblocking_filter_idc,
    759             ctx->obj_context->frame_count,
    760             FirstMBAddress,
    761             MBSkipRun,
    762             0,
    763             ctx->force_idr_h264,
    764             IMG_FALSE,
    765             IMG_FALSE,
    766             ctx->idr_pic_id);
    767 
    768     /* ensure that this slice is consequtive to that last processed by the target core */
    769     /*
    770        ASSERT( -1 == ctx->LastSliceNum[ctx->SliceToCore]
    771        || ctx->obj_context->slice_count == 1 + ctx->LastSliceNum[ctx->SliceToCore] );
    772      */
    773     /* note the slice number the target core is now processing */
    774     ctx->LastSliceNum[ctx->SliceToCore] = ctx->obj_context->slice_count;
    775 
    776     pnw_cmdbuf_insert_command_package(ctx->obj_context,
    777             ctx->SliceToCore,
    778             MTX_CMDID_DO_HEADER,
    779             &cmdbuf->header_mem,
    780             ctx->slice_header_ofs + ctx->obj_context->slice_count * HEADER_SIZE);
    781     if (!(ctx->sRCParams.RCEnable && ctx->sRCParams.FrameSkip)) {
    782         /*Only reset on the first frame. It's more effective than DDK. Have confirmed with IMG*/
    783         if (ctx->obj_context->frame_count == 0)
    784             pnw_reset_encoder_params(ctx);
    785         if ((pBuffer->start_row_number == 0) && pBuffer->slice_flags.bits.is_intra) {
    786             ctx->BelowParamsBufIdx = (ctx->BelowParamsBufIdx + 1) & 0x1;
    787         }
    788 
    789         slice_param_idx = (pBuffer->slice_flags.bits.is_intra ? 0 : 1) * ctx->slice_param_num
    790             + ctx->obj_context->slice_count;
    791         if (VAEncSliceParameter_Equal(&ctx->slice_param_cache[slice_param_idx], pBuffer) == 0) {
    792             /* cache current param parameters */
    793             memcpy(&ctx->slice_param_cache[slice_param_idx],
    794                     pBuffer, sizeof(VAEncSliceParameterBuffer));
    795 
    796             /* Setup InParams value*/
    797             pnw_setup_slice_params(ctx,
    798                     pBuffer->start_row_number * 16,
    799                     pBuffer->slice_height * 16,
    800                     pBuffer->slice_flags.bits.is_intra,
    801                     ctx->obj_context->frame_count > 0,
    802                     psPicParams->sInParams.SeInitQP);
    803         }
    804 
    805         /* Insert do slice command and setup related buffer value */
    806         pnw__send_encode_slice_params(ctx,
    807                 pBuffer->slice_flags.bits.is_intra,
    808                 pBuffer->start_row_number * 16,
    809                 deblock_idc,
    810                 ctx->obj_context->frame_count,
    811                 pBuffer->slice_height * 16,
    812                 ctx->obj_context->slice_count);
    813 
    814         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Now frame_count/slice_count is %d/%d\n",
    815                 ctx->obj_context->frame_count, ctx->obj_context->slice_count);
    816     }
    817     ctx->obj_context->slice_count++;
    818 
    819     return vaStatus;
    820 }
    821 
    822 /* convert from VAEncSliceParameterBufferH264  to VAEncSliceParameterBuffer */
    823 static VAStatus pnw__convert_sliceparameter_buffer(VAEncSliceParameterBufferH264 *pBufferH264,
    824                                                    VAEncSliceParameterBuffer *pBuffer,
    825                                                    int picture_width_in_mbs,
    826                                                    unsigned int num_elemenent)
    827 {
    828     unsigned int i;
    829 
    830     for (i = 0; i < num_elemenent; i++) {
    831         pBuffer->start_row_number = pBufferH264->macroblock_address / picture_width_in_mbs;
    832         pBuffer->slice_height =  pBufferH264->num_macroblocks / picture_width_in_mbs;
    833         pBuffer->slice_flags.bits.is_intra =
    834             (((pBufferH264->slice_type == 2) || (pBufferH264->slice_type == 7)) ? 1 : 0);
    835         pBuffer->slice_flags.bits.disable_deblocking_filter_idc =  pBufferH264->disable_deblocking_filter_idc;
    836 
    837         /* next conversion */
    838         pBuffer++;
    839         pBufferH264++;
    840     }
    841 
    842     return 0;
    843 }
    844 
    845 static VAStatus pnw__H264ES_process_slice_param(context_ENC_p ctx, object_buffer_p obj_buffer)
    846 {
    847     /* Prepare InParams for macros of current slice, insert slice header, insert do slice command */
    848     VAEncSliceParameterBuffer *pBuf_per_core, *pBuffer;
    849     pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf;
    850     PIC_PARAMS *psPicParams = (PIC_PARAMS *)(cmdbuf->pic_params_p);
    851     unsigned int i, j, slice_per_core;
    852     VAStatus vaStatus = VA_STATUS_SUCCESS;
    853 
    854     ASSERT(obj_buffer->type == VAEncSliceParameterBufferType);
    855 
    856     if (obj_buffer->num_elements > (ctx->Height / 16)) {
    857         vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
    858         goto out2;
    859     }
    860     cmdbuf = ctx->obj_context->pnw_cmdbuf;
    861     psPicParams = (PIC_PARAMS *)cmdbuf->pic_params_p;
    862 
    863     /* Transfer ownership of VAEncPictureParameterBuffer data */
    864     if (obj_buffer->size == sizeof(VAEncSliceParameterBufferH264)) {
    865         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Receive VAEncSliceParameterBufferH264 buffer");
    866         pBuffer = calloc(obj_buffer->num_elements, sizeof(VAEncSliceParameterBuffer));
    867 
    868         if (pBuffer == NULL) {
    869             drv_debug_msg(VIDEO_DEBUG_ERROR, "Run out of memory!\n");
    870             vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
    871             goto out2;
    872         }
    873 
    874         pnw__convert_sliceparameter_buffer((VAEncSliceParameterBufferH264 *)obj_buffer->buffer_data,
    875                                            pBuffer,
    876                                            ctx->Width / 16,
    877                                            obj_buffer->num_elements);
    878     } else if (obj_buffer->size == sizeof(VAEncSliceParameterBuffer)) {
    879         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Receive VAEncSliceParameterBuffer buffer");
    880         pBuffer = (VAEncSliceParameterBuffer *) obj_buffer->buffer_data;
    881     } else {
    882         drv_debug_msg(VIDEO_DEBUG_ERROR, "Buffer size(%d) is wrong. It should be %d or %d\n",
    883                 obj_buffer->size, sizeof(VAEncSliceParameterBuffer),
    884                 sizeof(VAEncSliceParameterBufferH264));
    885         vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
    886         goto out2;
    887     }
    888 
    889     obj_buffer->size = 0;
    890 
    891     /*In case the slice number changes*/
    892     if ((ctx->slice_param_cache != NULL) && (obj_buffer->num_elements != ctx->slice_param_num)) {
    893         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Slice number changes. Previous value is %d. Now it's %d\n",
    894                 ctx->slice_param_num, obj_buffer->num_elements);
    895         free(ctx->slice_param_cache);
    896         ctx->slice_param_cache = NULL;
    897         ctx->slice_param_num = 0;
    898     }
    899 
    900     if (NULL == ctx->slice_param_cache) {
    901         ctx->slice_param_num = obj_buffer->num_elements;
    902         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Allocate %d VAEncSliceParameterBuffer cache buffers\n", 2 * ctx->slice_param_num);
    903         ctx->slice_param_cache = calloc(2 * ctx->slice_param_num, sizeof(VAEncSliceParameterBuffer));
    904         if (NULL == ctx->slice_param_cache) {
    905             drv_debug_msg(VIDEO_DEBUG_ERROR, "Run out of memory!\n");
    906 
    907             /* free the converted VAEncSliceParameterBuffer */
    908             if (obj_buffer->size == sizeof(VAEncSliceParameterBufferH264))
    909                 free(pBuffer);
    910             free(obj_buffer->buffer_data);
    911             return VA_STATUS_ERROR_ALLOCATION_FAILED;
    912         }
    913     }
    914 
    915     ctx->sRCParams.Slices = obj_buffer->num_elements;
    916     if (getenv("PSB_VIDEO_SIG_CORE") == NULL) {
    917         if ((ctx->ParallelCores == 2) && (obj_buffer->num_elements == 1)) {
    918             /*Need to replace unneccesary MTX_CMDID_STARTPICs with MTX_CMDID_PAD*/
    919             for (i = 0; i < (ctx->ParallelCores - 1); i++) {
    920                 *(cmdbuf->cmd_idx_saved[PNW_CMDBUF_START_PIC_IDX] + i * 4) &= (~MTX_CMDWORD_ID_MASK);
    921                 *(cmdbuf->cmd_idx_saved[PNW_CMDBUF_START_PIC_IDX] + i * 4) |= MTX_CMDID_PAD;
    922             }
    923             drv_debug_msg(VIDEO_DEBUG_GENERAL, " Remove unneccesary %d MTX_CMDID_STARTPIC commands from cmdbuf\n",
    924                     ctx->ParallelCores - obj_buffer->num_elements);
    925             ctx->ParallelCores = obj_buffer->num_elements;
    926 
    927             /* All header generation commands should be send to core 0*/
    928             for (i = PNW_CMDBUF_SEQ_HEADER_IDX; i < PNW_CMDBUF_SAVING_MAX; i++) {
    929                 if (cmdbuf->cmd_idx_saved[i] != 0)
    930                     *(cmdbuf->cmd_idx_saved[i]) &=
    931                         ~(MTX_CMDWORD_CORE_MASK << MTX_CMDWORD_CORE_SHIFT);
    932             }
    933 
    934             ctx->SliceToCore = ctx->ParallelCores - 1;
    935         }
    936     }
    937 
    938     slice_per_core = obj_buffer->num_elements / ctx->ParallelCores;
    939     pBuf_per_core = pBuffer;
    940     for (i = 0; i < slice_per_core; i++) {
    941         pBuffer = pBuf_per_core;
    942         for (j = 0; j < ctx->ParallelCores; j++) {
    943             vaStatus = pnw__H264ES_encode_one_slice(ctx, pBuffer);
    944             if (vaStatus != VA_STATUS_SUCCESS)
    945                 goto out1;
    946             if (0 == ctx->SliceToCore) {
    947                 ctx->SliceToCore = ctx->ParallelCores;
    948             }
    949             ctx->SliceToCore--;
    950 
    951             ASSERT(ctx->obj_context->slice_count < MAX_SLICES_PER_PICTURE);
    952             /*Move to the next buffer which will be sent to core j*/
    953             pBuffer += slice_per_core;
    954         }
    955         pBuf_per_core++; /* Move to the next buffer */
    956     }
    957 
    958     /*Cope with last slice when slice number is odd and parallelCores is even*/
    959     if (obj_buffer->num_elements > (slice_per_core * ctx->ParallelCores)) {
    960         ctx->SliceToCore = 0;
    961         pBuffer -= slice_per_core;
    962         pBuffer ++;
    963         vaStatus = pnw__H264ES_encode_one_slice(ctx, pBuffer);
    964     }
    965 out1:
    966     /* free the converted VAEncSliceParameterBuffer */
    967     if (obj_buffer->size == sizeof(VAEncSliceParameterBufferH264))
    968         free(pBuffer);
    969 
    970 out2:
    971     free(obj_buffer->buffer_data);
    972     obj_buffer->buffer_data = NULL;
    973 
    974     return vaStatus;
    975 }
    976 
    977 static VAStatus pnw__H264ES_process_misc_param(context_ENC_p ctx, object_buffer_p obj_buffer)
    978 {
    979     /* Prepare InParams for macros of current slice, insert slice header, insert do slice command */
    980     VAEncMiscParameterBuffer *pBuffer;
    981     VAEncMiscParameterRateControl *rate_control_param;
    982     VAEncMiscParameterAIR *air_param;
    983     VAEncMiscParameterMaxSliceSize *max_slice_size_param;
    984     VAEncMiscParameterFrameRate *frame_rate_param;
    985     VAEncMiscParameterHRD *hrd_param;
    986     VAStatus vaStatus = VA_STATUS_SUCCESS;
    987     unsigned int max_bps;
    988     unsigned int frame_size;
    989 
    990     ASSERT(obj_buffer->type == VAEncMiscParameterBufferType);
    991 
    992 
    993     /* Transfer ownership of VAEncMiscParameterBuffer data */
    994     pBuffer = (VAEncMiscParameterBuffer *) obj_buffer->buffer_data;
    995     obj_buffer->size = 0;
    996 
    997     if (ctx->eCodec != IMG_CODEC_H264_VCM
    998             && (pBuffer->type != VAEncMiscParameterTypeHRD
    999                 && pBuffer->type != VAEncMiscParameterTypeRateControl
   1000                 && pBuffer->type != VAEncMiscParameterTypeFrameRate)) {
   1001         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Buffer type %d isn't supported in none VCM mode.\n",
   1002                 pBuffer->type);
   1003         free(obj_buffer->buffer_data);
   1004         obj_buffer->buffer_data = NULL;
   1005         return VA_STATUS_SUCCESS;
   1006     }
   1007 
   1008     switch (pBuffer->type) {
   1009         case VAEncMiscParameterTypeFrameRate:
   1010             frame_rate_param = (VAEncMiscParameterFrameRate *)pBuffer->data;
   1011 
   1012             if (frame_rate_param->framerate < 1 || frame_rate_param->framerate > 65535) {
   1013                 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
   1014                 break;
   1015             }
   1016 
   1017             if (ctx->sRCParams.FrameRate == frame_rate_param->framerate)
   1018                 break;
   1019 
   1020             drv_debug_msg(VIDEO_DEBUG_GENERAL, "frame rate changed from %d to %d\n",
   1021                     ctx->sRCParams.FrameRate,
   1022                     frame_rate_param->framerate);
   1023             ctx->sRCParams.FrameRate = frame_rate_param->framerate;
   1024             ctx->sRCParams.bBitrateChanged = IMG_TRUE;
   1025 
   1026             ctx->sRCParams.FrameRate = (frame_rate_param->framerate < 1) ? 1 :
   1027                 ((65535 < frame_rate_param->framerate) ? 65535 : frame_rate_param->framerate);
   1028             break;
   1029 
   1030         case VAEncMiscParameterTypeRateControl:
   1031             rate_control_param = (VAEncMiscParameterRateControl *)pBuffer->data;
   1032 
   1033             /* Currently, none VCM mode only supports frame skip and bit stuffing
   1034              * disable flag and doesn't accept other parameters in
   1035              * buffer of VAEncMiscParameterTypeRateControl type */
   1036             if (rate_control_param->rc_flags.value != 0 || ctx->raw_frame_count == 0) {
   1037                 if (rate_control_param->rc_flags.bits.disable_frame_skip)
   1038                     ctx->sRCParams.bDisableFrameSkipping = IMG_TRUE;
   1039                 if (rate_control_param->rc_flags.bits.disable_bit_stuffing)
   1040                     ctx->sRCParams.bDisableBitStuffing = IMG_TRUE;
   1041                 drv_debug_msg(VIDEO_DEBUG_GENERAL,
   1042                         "bDisableFrameSkipping is %d and bDisableBitStuffing is %d\n",
   1043                         ctx->sRCParams.bDisableFrameSkipping, ctx->sRCParams.bDisableBitStuffing);
   1044             }
   1045 
   1046             if (rate_control_param->initial_qp > 51 ||
   1047                     rate_control_param->min_qp > 51) {
   1048                 drv_debug_msg(VIDEO_DEBUG_ERROR, "Initial_qp(%d) and min_qpinitial_qp(%d) "
   1049                         "are invalid.\nQP shouldn't be larger than 51 for H264\n",
   1050                         rate_control_param->initial_qp, rate_control_param->min_qp);
   1051                 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
   1052                 break;
   1053             }
   1054 
   1055             if (rate_control_param->window_size > 2000) {
   1056                 drv_debug_msg(VIDEO_DEBUG_ERROR, "window_size is too much!\n");
   1057                 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
   1058                 break;
   1059             }
   1060 
   1061             /* Check if any none-zero RC parameter is changed*/
   1062             if ((rate_control_param->bits_per_second == 0 ||
   1063                         rate_control_param->bits_per_second == ctx->sRCParams.BitsPerSecond) &&
   1064                     (rate_control_param->window_size == 0 ||
   1065                     ctx->sRCParams.BufferSize == ctx->sRCParams.BitsPerSecond / 1000 * rate_control_param->window_size) &&
   1066                     (ctx->sRCParams.MinQP == rate_control_param->min_qp) &&
   1067                     (ctx->sRCParams.InitialQp == rate_control_param->initial_qp) &&
   1068                     (rate_control_param->basic_unit_size == 0 ||
   1069                      ctx->sRCParams.BUSize == rate_control_param->basic_unit_size)) {
   1070 		     drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s No RC parameter is changed\n",
   1071 				     __FUNCTION__);
   1072                 break;
   1073 	    }
   1074             else if (ctx->raw_frame_count != 0 || ctx->eCodec == IMG_CODEC_H264_VCM)
   1075                 ctx->sRCParams.bBitrateChanged = IMG_TRUE;
   1076 
   1077             /* The initial target bitrate is set by Sequence parameter buffer.
   1078                Here is for changed bitrate only */
   1079             if (rate_control_param->bits_per_second > TOPAZ_H264_MAX_BITRATE) {
   1080                 drv_debug_msg(VIDEO_DEBUG_ERROR, " bits_per_second(%d) exceeds \
   1081                         the maximum bitrate, set it with %d\n",
   1082                         rate_control_param->bits_per_second,
   1083                         TOPAZ_H264_MAX_BITRATE);
   1084                 break;
   1085             }
   1086             /* The initial target bitrate is set by Sequence parameter buffer.
   1087                Here is for changed bitrate only */
   1088             if (rate_control_param->bits_per_second != 0 &&
   1089                     ctx->raw_frame_count != 0) {
   1090                 drv_debug_msg(VIDEO_DEBUG_GENERAL,
   1091                         "bitrate is changed from %d to %d on frame %d\n",
   1092                         ctx->sRCParams.BitsPerSecond,
   1093                         rate_control_param->bits_per_second,
   1094                         ctx->raw_frame_count);
   1095                 max_bps =  (ctx->Width * ctx->Height * 3 / 2 ) * 8 * ctx->sRCParams.FrameRate;
   1096                 if (ctx->Width > 720)
   1097                     max_bps /= 4;
   1098                 else
   1099                     max_bps /= 2;
   1100 
   1101                 drv_debug_msg(VIDEO_DEBUG_GENERAL, " width %d height %d, frame rate %d\n",
   1102                         ctx->Width, ctx->Height, ctx->sRCParams.FrameRate);
   1103                 if (rate_control_param->bits_per_second > max_bps) {
   1104                     drv_debug_msg(VIDEO_DEBUG_ERROR,
   1105                             "Invalid bitrate %d, violate ITU-T Rec. H.264 (03/2005) A.3.1"
   1106                             "\n clip to %d bps\n", rate_control_param->bits_per_second, max_bps);
   1107                     ctx->sRCParams.BitsPerSecond = max_bps;
   1108                 } else {
   1109                     /* See 110% target bitrate for VCM. Otherwise, the resulted bitrate is much lower
   1110                        than target bitrate */
   1111                     if (ctx->eCodec == IMG_CODEC_H264_VCM)
   1112                         rate_control_param->bits_per_second =
   1113                             rate_control_param->bits_per_second / 100 * 110;
   1114                     drv_debug_msg(VIDEO_DEBUG_GENERAL, "Bitrate is set to %d\n",
   1115                             rate_control_param->bits_per_second);
   1116                     ctx->sRCParams.BitsPerSecond = rate_control_param->bits_per_second;
   1117                 }
   1118             }
   1119 
   1120             if (rate_control_param->min_qp != 0)
   1121                 ctx->sRCParams.MinQP = rate_control_param->min_qp;
   1122             if (rate_control_param->window_size != 0) {
   1123                 ctx->sRCParams.BufferSize =
   1124                     ctx->sRCParams.BitsPerSecond / 1000 * rate_control_param->window_size;
   1125 		if (ctx->sRCParams.FrameRate == 0) {
   1126                     drv_debug_msg(VIDEO_DEBUG_ERROR, "frame rate can't be zero. Set it to 30");
   1127                     ctx->sRCParams.FrameRate = 30;
   1128                 }
   1129 
   1130                 frame_size = ctx->sRCParams.BitsPerSecond / ctx->sRCParams.FrameRate;
   1131                 if (frame_size == 0) {
   1132                     drv_debug_msg(VIDEO_DEBUG_ERROR, "Bitrate is too low %d\n",
   1133                             ctx->sRCParams.BitsPerSecond);
   1134                     break;
   1135                 }
   1136                 ctx->sRCParams.InitialLevel = (3 * ctx->sRCParams.BufferSize) >> 4;
   1137                 ctx->sRCParams.InitialLevel += (frame_size / 2);
   1138                 ctx->sRCParams.InitialLevel /= frame_size;
   1139                 ctx->sRCParams.InitialLevel *= frame_size;
   1140                 ctx->sRCParams.InitialDelay =
   1141                     ctx->sRCParams.BufferSize - ctx->sRCParams.InitialLevel;
   1142             }
   1143 
   1144             if (rate_control_param->initial_qp != 0)
   1145                 ctx->sRCParams.InitialQp = rate_control_param->initial_qp;
   1146             if (rate_control_param->basic_unit_size != 0)
   1147                 ctx->sRCParams.BUSize = rate_control_param->basic_unit_size;
   1148 
   1149             drv_debug_msg(VIDEO_DEBUG_GENERAL,
   1150                     "Set Misc parameters(frame %d): window_size %d, initial qp %d\n" \
   1151                     "\tmin qp %d, bunit size %d\n",
   1152                     ctx->raw_frame_count,
   1153                     rate_control_param->window_size,
   1154                     rate_control_param->initial_qp,
   1155                     rate_control_param->min_qp,
   1156                     rate_control_param->basic_unit_size);
   1157             break;
   1158 
   1159         case VAEncMiscParameterTypeMaxSliceSize:
   1160             max_slice_size_param = (VAEncMiscParameterMaxSliceSize *)pBuffer->data;
   1161 
   1162             /*The max slice size should not be bigger than 1920x1080x1.5x8 */
   1163             if (max_slice_size_param->max_slice_size > 24883200) {
   1164                 drv_debug_msg(VIDEO_DEBUG_ERROR,"Invalid max_slice_size. It should be 1~ 24883200.\n");
   1165                 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
   1166                 break;
   1167             }
   1168 
   1169             if (ctx->max_slice_size == max_slice_size_param->max_slice_size)
   1170                 break;
   1171 
   1172             drv_debug_msg(VIDEO_DEBUG_GENERAL, "max slice size changed to %d\n",
   1173                     max_slice_size_param->max_slice_size);
   1174 
   1175             ctx->max_slice_size = max_slice_size_param->max_slice_size;
   1176 
   1177             break;
   1178 
   1179         case VAEncMiscParameterTypeAIR:
   1180             air_param = (VAEncMiscParameterAIR *)pBuffer->data;
   1181 
   1182             if (air_param->air_num_mbs > 65535 ||
   1183                     air_param->air_threshold > 65535) {
   1184                 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
   1185                 break;
   1186             }
   1187 
   1188             drv_debug_msg(VIDEO_DEBUG_GENERAL,"air slice size changed to num_air_mbs %d "
   1189                     "air_threshold %d, air_auto %d\n",
   1190                     air_param->air_num_mbs, air_param->air_threshold,
   1191                     air_param->air_auto);
   1192 
   1193             if (((ctx->Height * ctx->Width) >> 8) < (int)air_param->air_num_mbs)
   1194                 air_param->air_num_mbs = ((ctx->Height * ctx->Width) >> 8);
   1195             if (air_param->air_threshold == 0)
   1196                 drv_debug_msg(VIDEO_DEBUG_GENERAL,"%s: air threshold is set to zero\n",
   1197                         __func__);
   1198             ctx->num_air_mbs = air_param->air_num_mbs;
   1199             ctx->air_threshold = air_param->air_threshold;
   1200             //ctx->autotune_air_flag = air_param->air_auto;
   1201 
   1202             break;
   1203 
   1204         case VAEncMiscParameterTypeHRD:
   1205             hrd_param = (VAEncMiscParameterHRD *)pBuffer->data;
   1206 
   1207             if (hrd_param->buffer_size == 0
   1208                     || hrd_param->initial_buffer_fullness == 0)
   1209                 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Find zero value for buffer_size "
   1210                         "and initial_buffer_fullness.\n"
   1211                         "Will assign default value to them later \n");
   1212 
   1213             if (ctx->initial_buffer_fullness > ctx->buffer_size) {
   1214                 drv_debug_msg(VIDEO_DEBUG_ERROR, "initial_buffer_fullnessi(%d) shouldn't be"
   1215                         " larger that buffer_size(%d)!\n",
   1216                         hrd_param->initial_buffer_fullness,
   1217                         hrd_param->buffer_size);
   1218                 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
   1219                 break;
   1220             }
   1221 
   1222             if (!ctx->sRCParams.RCEnable) {
   1223                 drv_debug_msg(VIDEO_DEBUG_ERROR, "Only when rate control is enabled,"
   1224                         " VAEncMiscParameterTypeHRD will take effect.\n");
   1225                 break;
   1226             }
   1227 
   1228             ctx->buffer_size = hrd_param->buffer_size;
   1229             ctx->initial_buffer_fullness = hrd_param->initial_buffer_fullness;
   1230             ctx->bInserHRDParams = IMG_TRUE;
   1231             drv_debug_msg(VIDEO_DEBUG_GENERAL, "hrd param buffer_size set to %d "
   1232                     "initial buffer fullness set to %d\n",
   1233                     ctx->buffer_size, ctx->initial_buffer_fullness);
   1234 
   1235             break;
   1236 
   1237         default:
   1238             vaStatus = VA_STATUS_ERROR_UNKNOWN;
   1239             DEBUG_FAILURE;
   1240             break;
   1241     }
   1242 
   1243     free(obj_buffer->buffer_data);
   1244     obj_buffer->buffer_data = NULL;
   1245 
   1246     return vaStatus;
   1247 }
   1248 
   1249 
   1250 
   1251 static VAStatus pnw_H264ES_RenderPicture(
   1252         object_context_p obj_context,
   1253         object_buffer_p *buffers,
   1254         int num_buffers)
   1255 {
   1256     INIT_CONTEXT_H264ES;
   1257     VAStatus vaStatus = VA_STATUS_SUCCESS;
   1258     int i;
   1259 
   1260     drv_debug_msg(VIDEO_DEBUG_GENERAL,"pnw_H264ES_RenderPicture\n");
   1261 
   1262     for (i = 0; i < num_buffers; i++) {
   1263         object_buffer_p obj_buffer = buffers[i];
   1264 
   1265         switch (obj_buffer->type) {
   1266             case VAEncSequenceParameterBufferType:
   1267                 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncSequenceParameterBufferType\n");
   1268                 vaStatus = pnw__H264ES_process_sequence_param(ctx, obj_buffer);
   1269                 DEBUG_FAILURE;
   1270                 break;
   1271 
   1272             case VAEncPictureParameterBufferType:
   1273                 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncPictureParameterBuffer\n");
   1274                 vaStatus = pnw__H264ES_process_picture_param(ctx, obj_buffer);
   1275                 DEBUG_FAILURE;
   1276                 break;
   1277 
   1278             case VAEncSliceParameterBufferType:
   1279                 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncSliceParameterBufferType\n");
   1280                 vaStatus = pnw__H264ES_process_slice_param(ctx, obj_buffer);
   1281                 DEBUG_FAILURE;
   1282                 break;
   1283 
   1284             case VAEncMiscParameterBufferType:
   1285                 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncMiscParameterBufferType\n");
   1286                 vaStatus = pnw__H264ES_process_misc_param(ctx, obj_buffer);
   1287                 DEBUG_FAILURE;
   1288                 break;
   1289 #if PSB_MFLD_DUMMY_CODE
   1290             case VAEncPackedHeaderParameterBufferType:
   1291                 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncPackedHeaderParameterBufferType\n");
   1292                 vaStatus = pnw__H264ES_insert_SEI_FPA_param(ctx, obj_buffer);
   1293                 DEBUG_FAILURE;
   1294                 break;
   1295             case VAEncPackedHeaderDataBufferType:
   1296                 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncPackedHeaderDataBufferType\n");
   1297                 vaStatus = pnw__H264ES_insert_SEI_FPA_data(ctx, obj_buffer);
   1298                 DEBUG_FAILURE;
   1299                 break;
   1300 #endif
   1301 
   1302             default:
   1303                 vaStatus = VA_STATUS_ERROR_UNKNOWN;
   1304                 DEBUG_FAILURE;
   1305         }
   1306         if (vaStatus != VA_STATUS_SUCCESS) {
   1307             break;
   1308         }
   1309     }
   1310 
   1311     return vaStatus;
   1312 }
   1313 
   1314 static VAStatus pnw_H264ES_EndPicture(
   1315         object_context_p obj_context)
   1316 {
   1317     INIT_CONTEXT_H264ES;
   1318     pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf;
   1319     PIC_PARAMS *psPicParams = (PIC_PARAMS *)cmdbuf->pic_params_p;
   1320     VAStatus vaStatus = VA_STATUS_SUCCESS;
   1321     unsigned char core = 0;
   1322 
   1323     drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264ES_EndPicture\n");
   1324 
   1325     /* Unlike MPEG4 and H263, slices number is defined by user */
   1326     for (core = 0; core < ctx->ParallelCores; core++) {
   1327         psPicParams = (PIC_PARAMS *)
   1328             (cmdbuf->pic_params_p +  ctx->pic_params_size * core);
   1329         psPicParams->NumSlices =  ctx->sRCParams.Slices;
   1330     }
   1331 
   1332     vaStatus = pnw_EndPicture(ctx);
   1333 
   1334     return vaStatus;
   1335 }
   1336 
   1337 
   1338 struct format_vtable_s pnw_H264ES_vtable = {
   1339 queryConfigAttributes:
   1340     pnw_H264ES_QueryConfigAttributes,
   1341     validateConfig:
   1342         pnw_H264ES_ValidateConfig,
   1343     createContext:
   1344         pnw_H264ES_CreateContext,
   1345     destroyContext:
   1346         pnw_H264ES_DestroyContext,
   1347     beginPicture:
   1348         pnw_H264ES_BeginPicture,
   1349     renderPicture:
   1350         pnw_H264ES_RenderPicture,
   1351     endPicture:
   1352         pnw_H264ES_EndPicture
   1353 };
   1354 
   1355 VAStatus pnw_set_frame_skip_flag(
   1356         object_context_p obj_context)
   1357 {
   1358     INIT_CONTEXT_H264ES;
   1359     VAStatus vaStatus = VA_STATUS_SUCCESS;
   1360 
   1361 
   1362     if (ctx && ctx->previous_src_surface) {
   1363         SET_SURFACE_INFO_skipped_flag(ctx->previous_src_surface->psb_surface, 1);
   1364         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Detected a skipped frame for surface 0x%08x.\n",
   1365             ctx->previous_src_surface->psb_surface);
   1366     }
   1367 
   1368     return vaStatus;
   1369 }
   1370 
   1371 
   1372