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@intel.com>
27  *    Zeng Li <zeng.li@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 ))
pnw_H264ES_QueryConfigAttributes(VAProfile __maybe_unused profile,VAEntrypoint __maybe_unused entrypoint,VAConfigAttrib * attrib_list,int num_attribs)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 
pnw_H264ES_ValidateConfig(object_config_p obj_config)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 
pnw_H264ES_CreateContext(object_context_p obj_context,object_config_p obj_config)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 
pnw_H264ES_DestroyContext(object_context_p obj_context)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 
pnw_H264ES_BeginPicture(object_context_p obj_context)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 
pnw__H264ES_process_sequence_param(context_ENC_p ctx,object_buffer_p obj_buffer)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 
pnw__H264ES_insert_SEI_buffer_period(context_ENC_p ctx)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 
pnw__H264ES_insert_SEI_pic_timing(context_ENC_p ctx)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
pnw__H264ES_insert_SEI_FPA_param(context_ENC_p ctx,object_buffer_p obj_buffer)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 
pnw__H264ES_insert_SEI_FPA_data(context_ENC_p ctx,object_buffer_p obj_buffer)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 
pnw__H264ES_process_picture_param(context_ENC_p ctx,object_buffer_p obj_buffer)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 
pnw__H264ES_encode_one_slice(context_ENC_p ctx,VAEncSliceParameterBuffer * pBuffer)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 */
pnw__convert_sliceparameter_buffer(VAEncSliceParameterBufferH264 * pBufferH264,VAEncSliceParameterBuffer * pBuffer,int picture_width_in_mbs,unsigned int num_elemenent)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 
pnw__H264ES_process_slice_param(context_ENC_p ctx,object_buffer_p obj_buffer)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 = NULL, *pBuffer = NULL;
849     pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf;
850     PIC_PARAMS *psPicParams = (PIC_PARAMS *)(cmdbuf->pic_params_p);
851     bool pBufferAlloced = false;
852     unsigned int i, j, slice_per_core;
853     VAStatus vaStatus = VA_STATUS_SUCCESS;
854 
855     ASSERT(obj_buffer->type == VAEncSliceParameterBufferType);
856 
857     if (obj_buffer->num_elements > (ctx->Height / 16)) {
858         vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
859         goto out2;
860     }
861     cmdbuf = ctx->obj_context->pnw_cmdbuf;
862     psPicParams = (PIC_PARAMS *)cmdbuf->pic_params_p;
863 
864     /* Transfer ownership of VAEncPictureParameterBuffer data */
865     if (obj_buffer->size == sizeof(VAEncSliceParameterBufferH264)) {
866         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Receive VAEncSliceParameterBufferH264 buffer");
867         pBuffer = calloc(obj_buffer->num_elements, sizeof(VAEncSliceParameterBuffer));
868 
869         if (pBuffer == NULL) {
870             drv_debug_msg(VIDEO_DEBUG_ERROR, "Run out of memory!\n");
871             vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
872             goto out2;
873         }
874 
875         pBufferAlloced = true;
876 
877         pnw__convert_sliceparameter_buffer((VAEncSliceParameterBufferH264 *)obj_buffer->buffer_data,
878                                            pBuffer,
879                                            ctx->Width / 16,
880                                            obj_buffer->num_elements);
881     } else if (obj_buffer->size == sizeof(VAEncSliceParameterBuffer)) {
882         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Receive VAEncSliceParameterBuffer buffer");
883         pBuffer = (VAEncSliceParameterBuffer *) obj_buffer->buffer_data;
884     } else {
885         drv_debug_msg(VIDEO_DEBUG_ERROR, "Buffer size(%d) is wrong. It should be %d or %d\n",
886                 obj_buffer->size, sizeof(VAEncSliceParameterBuffer),
887                 sizeof(VAEncSliceParameterBufferH264));
888         vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
889         goto out2;
890     }
891 
892     obj_buffer->size = 0;
893 
894     /*In case the slice number changes*/
895     if ((ctx->slice_param_cache != NULL) && (obj_buffer->num_elements != ctx->slice_param_num)) {
896         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Slice number changes. Previous value is %d. Now it's %d\n",
897                 ctx->slice_param_num, obj_buffer->num_elements);
898         free(ctx->slice_param_cache);
899         ctx->slice_param_cache = NULL;
900         ctx->slice_param_num = 0;
901     }
902 
903     if (NULL == ctx->slice_param_cache) {
904         ctx->slice_param_num = obj_buffer->num_elements;
905         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Allocate %d VAEncSliceParameterBuffer cache buffers\n", 2 * ctx->slice_param_num);
906         ctx->slice_param_cache = calloc(2 * ctx->slice_param_num, sizeof(VAEncSliceParameterBuffer));
907         if (NULL == ctx->slice_param_cache) {
908             drv_debug_msg(VIDEO_DEBUG_ERROR, "Run out of memory!\n");
909 
910             /* free the converted VAEncSliceParameterBuffer */
911             if (pBufferAlloced)
912                 free(pBuffer);
913             free(obj_buffer->buffer_data);
914             return VA_STATUS_ERROR_ALLOCATION_FAILED;
915         }
916     }
917 
918     ctx->sRCParams.Slices = obj_buffer->num_elements;
919     if (getenv("PSB_VIDEO_SIG_CORE") == NULL) {
920         if ((ctx->ParallelCores == 2) && (obj_buffer->num_elements == 1)) {
921             /*Need to replace unneccesary MTX_CMDID_STARTPICs with MTX_CMDID_PAD*/
922             for (i = 0; i < (ctx->ParallelCores - 1); i++) {
923                 *(cmdbuf->cmd_idx_saved[PNW_CMDBUF_START_PIC_IDX] + i * 4) &= (~MTX_CMDWORD_ID_MASK);
924                 *(cmdbuf->cmd_idx_saved[PNW_CMDBUF_START_PIC_IDX] + i * 4) |= MTX_CMDID_PAD;
925             }
926             drv_debug_msg(VIDEO_DEBUG_GENERAL, " Remove unneccesary %d MTX_CMDID_STARTPIC commands from cmdbuf\n",
927                     ctx->ParallelCores - obj_buffer->num_elements);
928             ctx->ParallelCores = obj_buffer->num_elements;
929 
930             /* All header generation commands should be send to core 0*/
931             for (i = PNW_CMDBUF_SEQ_HEADER_IDX; i < PNW_CMDBUF_SAVING_MAX; i++) {
932                 if (cmdbuf->cmd_idx_saved[i] != 0)
933                     *(cmdbuf->cmd_idx_saved[i]) &=
934                         ~(MTX_CMDWORD_CORE_MASK << MTX_CMDWORD_CORE_SHIFT);
935             }
936 
937             ctx->SliceToCore = ctx->ParallelCores - 1;
938         }
939     }
940 
941     slice_per_core = obj_buffer->num_elements / ctx->ParallelCores;
942     pBuf_per_core = pBuffer;
943     for (i = 0; i < slice_per_core; i++) {
944         pBuffer = pBuf_per_core;
945         for (j = 0; j < ctx->ParallelCores; j++) {
946             vaStatus = pnw__H264ES_encode_one_slice(ctx, pBuffer);
947             if (vaStatus != VA_STATUS_SUCCESS)
948                 goto out1;
949             if (0 == ctx->SliceToCore) {
950                 ctx->SliceToCore = ctx->ParallelCores;
951             }
952             ctx->SliceToCore--;
953 
954             ASSERT(ctx->obj_context->slice_count < MAX_SLICES_PER_PICTURE);
955             /*Move to the next buffer which will be sent to core j*/
956             pBuffer += slice_per_core;
957         }
958         pBuf_per_core++; /* Move to the next buffer */
959     }
960 
961     /*Cope with last slice when slice number is odd and parallelCores is even*/
962     if (obj_buffer->num_elements > (slice_per_core * ctx->ParallelCores)) {
963         ctx->SliceToCore = 0;
964         pBuffer -= slice_per_core;
965         pBuffer ++;
966         vaStatus = pnw__H264ES_encode_one_slice(ctx, pBuffer);
967     }
968 out1:
969     /* free the converted VAEncSliceParameterBuffer */
970     if (pBufferAlloced)
971         free(pBuffer);
972 
973 out2:
974     free(obj_buffer->buffer_data);
975     obj_buffer->buffer_data = NULL;
976 
977     return vaStatus;
978 }
979 
pnw__H264ES_process_misc_param(context_ENC_p ctx,object_buffer_p obj_buffer)980 static VAStatus pnw__H264ES_process_misc_param(context_ENC_p ctx, object_buffer_p obj_buffer)
981 {
982     /* Prepare InParams for macros of current slice, insert slice header, insert do slice command */
983     VAEncMiscParameterBuffer *pBuffer;
984     VAEncMiscParameterRateControl *rate_control_param;
985     VAEncMiscParameterAIR *air_param;
986     VAEncMiscParameterMaxSliceSize *max_slice_size_param;
987     VAEncMiscParameterFrameRate *frame_rate_param;
988     VAEncMiscParameterHRD *hrd_param;
989     VAStatus vaStatus = VA_STATUS_SUCCESS;
990     unsigned int max_bps;
991     unsigned int frame_size;
992 
993     ASSERT(obj_buffer->type == VAEncMiscParameterBufferType);
994 
995 
996     /* Transfer ownership of VAEncMiscParameterBuffer data */
997     pBuffer = (VAEncMiscParameterBuffer *) obj_buffer->buffer_data;
998     obj_buffer->size = 0;
999 
1000     if (ctx->eCodec != IMG_CODEC_H264_VCM
1001             && (pBuffer->type != VAEncMiscParameterTypeHRD
1002                 && pBuffer->type != VAEncMiscParameterTypeRateControl
1003                 && pBuffer->type != VAEncMiscParameterTypeFrameRate)) {
1004         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Buffer type %d isn't supported in none VCM mode.\n",
1005                 pBuffer->type);
1006         free(obj_buffer->buffer_data);
1007         obj_buffer->buffer_data = NULL;
1008         return VA_STATUS_SUCCESS;
1009     }
1010 
1011     switch (pBuffer->type) {
1012         case VAEncMiscParameterTypeFrameRate:
1013             frame_rate_param = (VAEncMiscParameterFrameRate *)pBuffer->data;
1014 
1015             if (frame_rate_param->framerate < 1 || frame_rate_param->framerate > 65535) {
1016                 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
1017                 break;
1018             }
1019 
1020             if (ctx->sRCParams.FrameRate == frame_rate_param->framerate)
1021                 break;
1022 
1023             drv_debug_msg(VIDEO_DEBUG_GENERAL, "frame rate changed from %d to %d\n",
1024                     ctx->sRCParams.FrameRate,
1025                     frame_rate_param->framerate);
1026             ctx->sRCParams.FrameRate = frame_rate_param->framerate;
1027             ctx->sRCParams.bBitrateChanged = IMG_TRUE;
1028 
1029             ctx->sRCParams.FrameRate = (frame_rate_param->framerate < 1) ? 1 :
1030                 ((65535 < frame_rate_param->framerate) ? 65535 : frame_rate_param->framerate);
1031             break;
1032 
1033         case VAEncMiscParameterTypeRateControl:
1034             rate_control_param = (VAEncMiscParameterRateControl *)pBuffer->data;
1035 
1036             /* Currently, none VCM mode only supports frame skip and bit stuffing
1037              * disable flag and doesn't accept other parameters in
1038              * buffer of VAEncMiscParameterTypeRateControl type */
1039             if (rate_control_param->rc_flags.value != 0 || ctx->raw_frame_count == 0) {
1040                 if (rate_control_param->rc_flags.bits.disable_frame_skip)
1041                     ctx->sRCParams.bDisableFrameSkipping = IMG_TRUE;
1042                 if (rate_control_param->rc_flags.bits.disable_bit_stuffing)
1043                     ctx->sRCParams.bDisableBitStuffing = IMG_TRUE;
1044                 drv_debug_msg(VIDEO_DEBUG_GENERAL,
1045                         "bDisableFrameSkipping is %d and bDisableBitStuffing is %d\n",
1046                         ctx->sRCParams.bDisableFrameSkipping, ctx->sRCParams.bDisableBitStuffing);
1047             }
1048 
1049             if (rate_control_param->initial_qp > 51 ||
1050                     rate_control_param->min_qp > 51) {
1051                 drv_debug_msg(VIDEO_DEBUG_ERROR, "Initial_qp(%d) and min_qpinitial_qp(%d) "
1052                         "are invalid.\nQP shouldn't be larger than 51 for H264\n",
1053                         rate_control_param->initial_qp, rate_control_param->min_qp);
1054                 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
1055                 break;
1056             }
1057 
1058             if (rate_control_param->window_size > 2000) {
1059                 drv_debug_msg(VIDEO_DEBUG_ERROR, "window_size is too much!\n");
1060                 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
1061                 break;
1062             }
1063 
1064             /* Check if any none-zero RC parameter is changed*/
1065             if ((rate_control_param->bits_per_second == 0 ||
1066                         rate_control_param->bits_per_second == ctx->sRCParams.BitsPerSecond) &&
1067                     (rate_control_param->window_size == 0 ||
1068                     ctx->sRCParams.BufferSize == ctx->sRCParams.BitsPerSecond / 1000 * rate_control_param->window_size) &&
1069                     (ctx->sRCParams.MinQP == rate_control_param->min_qp) &&
1070                     (ctx->sRCParams.InitialQp == rate_control_param->initial_qp) &&
1071                     (rate_control_param->basic_unit_size == 0 ||
1072                      ctx->sRCParams.BUSize == rate_control_param->basic_unit_size)) {
1073 		     drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s No RC parameter is changed\n",
1074 				     __FUNCTION__);
1075                 break;
1076 	    }
1077             else if (ctx->raw_frame_count != 0 || ctx->eCodec == IMG_CODEC_H264_VCM)
1078                 ctx->sRCParams.bBitrateChanged = IMG_TRUE;
1079 
1080             /* The initial target bitrate is set by Sequence parameter buffer.
1081                Here is for changed bitrate only */
1082             if (rate_control_param->bits_per_second > TOPAZ_H264_MAX_BITRATE) {
1083                 drv_debug_msg(VIDEO_DEBUG_ERROR, " bits_per_second(%d) exceeds \
1084                         the maximum bitrate, set it with %d\n",
1085                         rate_control_param->bits_per_second,
1086                         TOPAZ_H264_MAX_BITRATE);
1087                 break;
1088             }
1089             /* The initial target bitrate is set by Sequence parameter buffer.
1090                Here is for changed bitrate only */
1091             if (rate_control_param->bits_per_second != 0 &&
1092                     ctx->raw_frame_count != 0) {
1093                 drv_debug_msg(VIDEO_DEBUG_GENERAL,
1094                         "bitrate is changed from %d to %d on frame %d\n",
1095                         ctx->sRCParams.BitsPerSecond,
1096                         rate_control_param->bits_per_second,
1097                         ctx->raw_frame_count);
1098                 max_bps =  (ctx->Width * ctx->Height * 3 / 2 ) * 8 * ctx->sRCParams.FrameRate;
1099                 if (ctx->Width > 720)
1100                     max_bps /= 4;
1101                 else
1102                     max_bps /= 2;
1103 
1104                 drv_debug_msg(VIDEO_DEBUG_GENERAL, " width %d height %d, frame rate %d\n",
1105                         ctx->Width, ctx->Height, ctx->sRCParams.FrameRate);
1106                 if (rate_control_param->bits_per_second > max_bps) {
1107                     drv_debug_msg(VIDEO_DEBUG_ERROR,
1108                             "Invalid bitrate %d, violate ITU-T Rec. H.264 (03/2005) A.3.1"
1109                             "\n clip to %d bps\n", rate_control_param->bits_per_second, max_bps);
1110                     ctx->sRCParams.BitsPerSecond = max_bps;
1111                 } else {
1112                     /* See 110% target bitrate for VCM. Otherwise, the resulted bitrate is much lower
1113                        than target bitrate */
1114                     if (ctx->eCodec == IMG_CODEC_H264_VCM)
1115                         rate_control_param->bits_per_second =
1116                             rate_control_param->bits_per_second / 100 * 110;
1117                     drv_debug_msg(VIDEO_DEBUG_GENERAL, "Bitrate is set to %d\n",
1118                             rate_control_param->bits_per_second);
1119                     ctx->sRCParams.BitsPerSecond = rate_control_param->bits_per_second;
1120                 }
1121             }
1122 
1123             if (rate_control_param->min_qp != 0)
1124                 ctx->sRCParams.MinQP = rate_control_param->min_qp;
1125             if (rate_control_param->window_size != 0) {
1126                 ctx->sRCParams.BufferSize =
1127                     ctx->sRCParams.BitsPerSecond / 1000 * rate_control_param->window_size;
1128 		if (ctx->sRCParams.FrameRate == 0) {
1129                     drv_debug_msg(VIDEO_DEBUG_ERROR, "frame rate can't be zero. Set it to 30");
1130                     ctx->sRCParams.FrameRate = 30;
1131                 }
1132 
1133                 frame_size = ctx->sRCParams.BitsPerSecond / ctx->sRCParams.FrameRate;
1134                 if (frame_size == 0) {
1135                     drv_debug_msg(VIDEO_DEBUG_ERROR, "Bitrate is too low %d\n",
1136                             ctx->sRCParams.BitsPerSecond);
1137                     break;
1138                 }
1139                 ctx->sRCParams.InitialLevel = (3 * ctx->sRCParams.BufferSize) >> 4;
1140                 ctx->sRCParams.InitialLevel += (frame_size / 2);
1141                 ctx->sRCParams.InitialLevel /= frame_size;
1142                 ctx->sRCParams.InitialLevel *= frame_size;
1143                 ctx->sRCParams.InitialDelay =
1144                     ctx->sRCParams.BufferSize - ctx->sRCParams.InitialLevel;
1145             }
1146 
1147             if (rate_control_param->initial_qp != 0)
1148                 ctx->sRCParams.InitialQp = rate_control_param->initial_qp;
1149             if (rate_control_param->basic_unit_size != 0)
1150                 ctx->sRCParams.BUSize = rate_control_param->basic_unit_size;
1151 
1152             drv_debug_msg(VIDEO_DEBUG_GENERAL,
1153                     "Set Misc parameters(frame %d): window_size %d, initial qp %d\n" \
1154                     "\tmin qp %d, bunit size %d\n",
1155                     ctx->raw_frame_count,
1156                     rate_control_param->window_size,
1157                     rate_control_param->initial_qp,
1158                     rate_control_param->min_qp,
1159                     rate_control_param->basic_unit_size);
1160             break;
1161 
1162         case VAEncMiscParameterTypeMaxSliceSize:
1163             max_slice_size_param = (VAEncMiscParameterMaxSliceSize *)pBuffer->data;
1164 
1165             /*The max slice size should not be bigger than 1920x1080x1.5x8 */
1166             if (max_slice_size_param->max_slice_size > 24883200) {
1167                 drv_debug_msg(VIDEO_DEBUG_ERROR,"Invalid max_slice_size. It should be 1~ 24883200.\n");
1168                 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
1169                 break;
1170             }
1171 
1172             if (ctx->max_slice_size == max_slice_size_param->max_slice_size)
1173                 break;
1174 
1175             drv_debug_msg(VIDEO_DEBUG_GENERAL, "max slice size changed to %d\n",
1176                     max_slice_size_param->max_slice_size);
1177 
1178             ctx->max_slice_size = max_slice_size_param->max_slice_size;
1179 
1180             break;
1181 
1182         case VAEncMiscParameterTypeAIR:
1183             air_param = (VAEncMiscParameterAIR *)pBuffer->data;
1184 
1185             if (air_param->air_num_mbs > 65535 ||
1186                     air_param->air_threshold > 65535) {
1187                 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
1188                 break;
1189             }
1190 
1191             drv_debug_msg(VIDEO_DEBUG_GENERAL,"air slice size changed to num_air_mbs %d "
1192                     "air_threshold %d, air_auto %d\n",
1193                     air_param->air_num_mbs, air_param->air_threshold,
1194                     air_param->air_auto);
1195 
1196             if (((ctx->Height * ctx->Width) >> 8) < (int)air_param->air_num_mbs)
1197                 air_param->air_num_mbs = ((ctx->Height * ctx->Width) >> 8);
1198             if (air_param->air_threshold == 0)
1199                 drv_debug_msg(VIDEO_DEBUG_GENERAL,"%s: air threshold is set to zero\n",
1200                         __func__);
1201             ctx->num_air_mbs = air_param->air_num_mbs;
1202             ctx->air_threshold = air_param->air_threshold;
1203             //ctx->autotune_air_flag = air_param->air_auto;
1204 
1205             break;
1206 
1207         case VAEncMiscParameterTypeHRD:
1208             hrd_param = (VAEncMiscParameterHRD *)pBuffer->data;
1209 
1210             if (hrd_param->buffer_size == 0
1211                     || hrd_param->initial_buffer_fullness == 0)
1212                 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Find zero value for buffer_size "
1213                         "and initial_buffer_fullness.\n"
1214                         "Will assign default value to them later \n");
1215 
1216             if (ctx->initial_buffer_fullness > ctx->buffer_size) {
1217                 drv_debug_msg(VIDEO_DEBUG_ERROR, "initial_buffer_fullnessi(%d) shouldn't be"
1218                         " larger that buffer_size(%d)!\n",
1219                         hrd_param->initial_buffer_fullness,
1220                         hrd_param->buffer_size);
1221                 vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
1222                 break;
1223             }
1224 
1225             if (!ctx->sRCParams.RCEnable) {
1226                 drv_debug_msg(VIDEO_DEBUG_ERROR, "Only when rate control is enabled,"
1227                         " VAEncMiscParameterTypeHRD will take effect.\n");
1228                 break;
1229             }
1230 
1231             ctx->buffer_size = hrd_param->buffer_size;
1232             ctx->initial_buffer_fullness = hrd_param->initial_buffer_fullness;
1233             ctx->bInserHRDParams = IMG_TRUE;
1234             drv_debug_msg(VIDEO_DEBUG_GENERAL, "hrd param buffer_size set to %d "
1235                     "initial buffer fullness set to %d\n",
1236                     ctx->buffer_size, ctx->initial_buffer_fullness);
1237 
1238             break;
1239 
1240         default:
1241             vaStatus = VA_STATUS_ERROR_UNKNOWN;
1242             DEBUG_FAILURE;
1243             break;
1244     }
1245 
1246     free(obj_buffer->buffer_data);
1247     obj_buffer->buffer_data = NULL;
1248 
1249     return vaStatus;
1250 }
1251 
1252 
1253 
pnw_H264ES_RenderPicture(object_context_p obj_context,object_buffer_p * buffers,int num_buffers)1254 static VAStatus pnw_H264ES_RenderPicture(
1255         object_context_p obj_context,
1256         object_buffer_p *buffers,
1257         int num_buffers)
1258 {
1259     INIT_CONTEXT_H264ES;
1260     VAStatus vaStatus = VA_STATUS_SUCCESS;
1261     int i;
1262 
1263     drv_debug_msg(VIDEO_DEBUG_GENERAL,"pnw_H264ES_RenderPicture\n");
1264 
1265     for (i = 0; i < num_buffers; i++) {
1266         object_buffer_p obj_buffer = buffers[i];
1267 
1268         switch (obj_buffer->type) {
1269             case VAEncSequenceParameterBufferType:
1270                 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncSequenceParameterBufferType\n");
1271                 vaStatus = pnw__H264ES_process_sequence_param(ctx, obj_buffer);
1272                 DEBUG_FAILURE;
1273                 break;
1274 
1275             case VAEncPictureParameterBufferType:
1276                 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncPictureParameterBuffer\n");
1277                 vaStatus = pnw__H264ES_process_picture_param(ctx, obj_buffer);
1278                 DEBUG_FAILURE;
1279                 break;
1280 
1281             case VAEncSliceParameterBufferType:
1282                 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncSliceParameterBufferType\n");
1283                 vaStatus = pnw__H264ES_process_slice_param(ctx, obj_buffer);
1284                 DEBUG_FAILURE;
1285                 break;
1286 
1287             case VAEncMiscParameterBufferType:
1288                 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncMiscParameterBufferType\n");
1289                 vaStatus = pnw__H264ES_process_misc_param(ctx, obj_buffer);
1290                 DEBUG_FAILURE;
1291                 break;
1292 #if PSB_MFLD_DUMMY_CODE
1293             case VAEncPackedHeaderParameterBufferType:
1294                 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncPackedHeaderParameterBufferType\n");
1295                 vaStatus = pnw__H264ES_insert_SEI_FPA_param(ctx, obj_buffer);
1296                 DEBUG_FAILURE;
1297                 break;
1298             case VAEncPackedHeaderDataBufferType:
1299                 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264_RenderPicture got VAEncPackedHeaderDataBufferType\n");
1300                 vaStatus = pnw__H264ES_insert_SEI_FPA_data(ctx, obj_buffer);
1301                 DEBUG_FAILURE;
1302                 break;
1303 #endif
1304 
1305             default:
1306                 vaStatus = VA_STATUS_ERROR_UNKNOWN;
1307                 DEBUG_FAILURE;
1308         }
1309         if (vaStatus != VA_STATUS_SUCCESS) {
1310             break;
1311         }
1312     }
1313 
1314     return vaStatus;
1315 }
1316 
pnw_H264ES_EndPicture(object_context_p obj_context)1317 static VAStatus pnw_H264ES_EndPicture(
1318         object_context_p obj_context)
1319 {
1320     INIT_CONTEXT_H264ES;
1321     pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf;
1322     PIC_PARAMS *psPicParams = (PIC_PARAMS *)cmdbuf->pic_params_p;
1323     VAStatus vaStatus = VA_STATUS_SUCCESS;
1324     unsigned char core = 0;
1325 
1326     drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H264ES_EndPicture\n");
1327 
1328     /* Unlike MPEG4 and H263, slices number is defined by user */
1329     for (core = 0; core < ctx->ParallelCores; core++) {
1330         psPicParams = (PIC_PARAMS *)
1331             (cmdbuf->pic_params_p +  ctx->pic_params_size * core);
1332         psPicParams->NumSlices =  ctx->sRCParams.Slices;
1333     }
1334 
1335     vaStatus = pnw_EndPicture(ctx);
1336 
1337     return vaStatus;
1338 }
1339 
1340 
1341 struct format_vtable_s pnw_H264ES_vtable = {
1342 queryConfigAttributes:
1343     pnw_H264ES_QueryConfigAttributes,
1344     validateConfig:
1345         pnw_H264ES_ValidateConfig,
1346     createContext:
1347         pnw_H264ES_CreateContext,
1348     destroyContext:
1349         pnw_H264ES_DestroyContext,
1350     beginPicture:
1351         pnw_H264ES_BeginPicture,
1352     renderPicture:
1353         pnw_H264ES_RenderPicture,
1354     endPicture:
1355         pnw_H264ES_EndPicture
1356 };
1357 
pnw_set_frame_skip_flag(object_context_p obj_context)1358 VAStatus pnw_set_frame_skip_flag(
1359         object_context_p obj_context)
1360 {
1361     INIT_CONTEXT_H264ES;
1362     VAStatus vaStatus = VA_STATUS_SUCCESS;
1363 
1364 
1365     if (ctx && ctx->previous_src_surface) {
1366         SET_SURFACE_INFO_skipped_flag(ctx->previous_src_surface->psb_surface, 1);
1367         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Detected a skipped frame for surface 0x%08x.\n",
1368             ctx->previous_src_surface->psb_surface);
1369     }
1370 
1371     return vaStatus;
1372 }
1373 
1374 
1375