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