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