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 #include "psb_def.h"
32 #include "psb_surface.h"
33 #include "psb_cmdbuf.h"
34 #include "pnw_H263ES.h"
35 #include "pnw_hostcode.h"
36 #include "pnw_hostheader.h"
37 #include "psb_drv_debug.h"
38
39 #include <stdlib.h>
40 #include <stdint.h>
41 #include <string.h>
42
43
44 #define TOPAZ_H263_MAX_BITRATE 16000000
45
46 #define INIT_CONTEXT_H263ES context_ENC_p ctx = (context_ENC_p) (obj_context->format_data)
47 #define SURFACE(id) ((object_surface_p) object_heap_lookup( &ctx->obj_context->driver_data->surface_heap, id ))
48 #define BUFFER(id) ((object_buffer_p) object_heap_lookup( &ctx->obj_context->driver_data->buffer_heap, id ))
49
50
pnw_H263ES_QueryConfigAttributes(VAProfile __maybe_unused profile,VAEntrypoint __maybe_unused entrypoint,VAConfigAttrib * attrib_list,int num_attribs)51 static void pnw_H263ES_QueryConfigAttributes(
52 VAProfile __maybe_unused profile,
53 VAEntrypoint __maybe_unused entrypoint,
54 VAConfigAttrib *attrib_list,
55 int num_attribs)
56 {
57 int i;
58 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H263ES_QueryConfigAttributes\n");
59
60 /* RateControl attributes */
61 for (i = 0; i < num_attribs; i++) {
62 switch (attrib_list[i].type) {
63 case VAConfigAttribRTFormat:
64 break;
65
66 case VAConfigAttribRateControl:
67 attrib_list[i].value = VA_RC_NONE | VA_RC_CBR | VA_RC_VBR;
68 break;
69
70 default:
71 attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED;
72 break;
73 }
74 }
75
76 }
77
78
pnw_H263ES_ValidateConfig(object_config_p obj_config)79 static VAStatus pnw_H263ES_ValidateConfig(
80 object_config_p obj_config)
81 {
82 int i;
83 /* Check all attributes */
84 for (i = 0; i < obj_config->attrib_count; i++) {
85 switch (obj_config->attrib_list[i].type) {
86 case VAConfigAttribRTFormat:
87 /* Ignore */
88 break;
89 case VAConfigAttribRateControl:
90 break;
91 default:
92 return VA_STATUS_ERROR_ATTR_NOT_SUPPORTED;
93 }
94 }
95
96 return VA_STATUS_SUCCESS;
97 }
98
99
pnw_H263ES_CreateContext(object_context_p obj_context,object_config_p obj_config)100 static VAStatus pnw_H263ES_CreateContext(
101 object_context_p obj_context,
102 object_config_p obj_config)
103 {
104 VAStatus vaStatus = VA_STATUS_SUCCESS;
105 unsigned int eRCmode;
106 context_ENC_p ctx;
107 int i;
108
109 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H263ES_CreateContext\n");
110
111 vaStatus = pnw_CreateContext(obj_context, obj_config, 0);/* alloc context_ENC_s and BO */
112
113 if (VA_STATUS_SUCCESS != vaStatus)
114 return VA_STATUS_ERROR_ALLOCATION_FAILED;
115
116 ctx = (context_ENC_p) obj_context->format_data;
117
118 for (i = 0; i < obj_config->attrib_count; i++) {
119 if (obj_config->attrib_list[i].type == VAConfigAttribRateControl)
120 break;
121 }
122
123 if (i >= obj_config->attrib_count)
124 eRCmode = VA_RC_NONE;
125 else
126 eRCmode = obj_config->attrib_list[i].value;
127
128
129 if (eRCmode == VA_RC_VBR) {
130 ctx->eCodec = IMG_CODEC_H263_VBR;
131 ctx->sRCParams.RCEnable = IMG_TRUE;
132 } else if (eRCmode == VA_RC_CBR) {
133 ctx->eCodec = IMG_CODEC_H263_CBR;
134 ctx->sRCParams.RCEnable = IMG_TRUE;
135 } else if (eRCmode == VA_RC_NONE) {
136 ctx->eCodec = IMG_CODEC_H263_NO_RC;
137 ctx->sRCParams.RCEnable = IMG_FALSE;
138 } else
139 return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
140 ctx->eFormat = IMG_CODEC_PL12;
141
142 ctx->Slices = ctx->Height / 16;
143 ctx->ParallelCores = 1; /* H263 encode use only one core from DDKv186 */
144
145 ctx->IPEControl = pnw__get_ipe_control(ctx->eCodec);
146
147 return vaStatus;
148
149
150 }
151
152
pnw_H263ES_DestroyContext(object_context_p obj_context)153 static void pnw_H263ES_DestroyContext(
154 object_context_p obj_context)
155 {
156
157 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H263ES_DestroyContext\n");
158
159 pnw_DestroyContext(obj_context);
160 }
161
pnw_H263ES_BeginPicture(object_context_p obj_context)162 static VAStatus pnw_H263ES_BeginPicture(
163 object_context_p obj_context)
164 {
165 VAStatus vaStatus = VA_STATUS_SUCCESS;
166
167 INIT_CONTEXT_H263ES;
168
169 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H263ES_BeginPicture\n");
170
171 vaStatus = pnw_BeginPicture(ctx);
172
173 return vaStatus;
174 }
175
176
pnw__H263ES_process_sequence_param(context_ENC_p ctx,object_buffer_p obj_buffer)177 static VAStatus pnw__H263ES_process_sequence_param(context_ENC_p ctx, object_buffer_p obj_buffer)
178 {
179 /*
180 * process rate control parameters
181 */
182 VAEncSequenceParameterBufferH263 *pSequenceParams;
183 int i;
184 unsigned int frame_size;
185
186 ASSERT(obj_buffer->type == VAEncSequenceParameterBufferType);
187 ASSERT(obj_buffer->num_elements == 1);
188 ASSERT(obj_buffer->size == sizeof(VAEncSequenceParameterBufferH263));
189 //initialize the frame_rate and qp
190 ctx->sRCParams.InitialQp = 15;
191 ctx->sRCParams.MinQP = 1;
192 ctx->sRCParams.FrameRate = 30;
193
194 if ((obj_buffer->num_elements != 1) ||
195 (obj_buffer->size != sizeof(VAEncSequenceParameterBufferH263))) {
196 return VA_STATUS_ERROR_UNKNOWN;
197 }
198
199 pSequenceParams = (VAEncSequenceParameterBufferH263 *) obj_buffer->buffer_data;
200 obj_buffer->buffer_data = NULL;
201 obj_buffer->size = 0;
202
203 if (pSequenceParams->bits_per_second > TOPAZ_H263_MAX_BITRATE) {
204 ctx->sRCParams.BitsPerSecond = TOPAZ_H263_MAX_BITRATE;
205 drv_debug_msg(VIDEO_DEBUG_GENERAL, " bits_per_second(%d) exceeds \
206 the maximum bitrate, set it with %d\n",
207 pSequenceParams->bits_per_second,
208 TOPAZ_H263_MAX_BITRATE);
209 } else
210 ctx->sRCParams.BitsPerSecond = pSequenceParams->bits_per_second;
211
212 ctx->sRCParams.FrameRate = (pSequenceParams->frame_rate < 1) ? 1 :
213 ((65535 < pSequenceParams->frame_rate) ? 65535 : pSequenceParams->frame_rate);
214 ctx->sRCParams.InitialQp = pSequenceParams->initial_qp;
215 ctx->sRCParams.MinQP = pSequenceParams->min_qp;
216 ctx->sRCParams.BUSize = 0; /* default 0, and will be set in pnw__setup_busize */
217
218 ctx->sRCParams.BufferSize = ctx->sRCParams.BitsPerSecond;
219 frame_size = ctx->sRCParams.BitsPerSecond / ctx->sRCParams.FrameRate;
220 /*
221 IMG_UINT16 MBRows = 0;
222 if(ctx->Height <= 400)
223 MBRows = 1;
224 else if (ctx->Height < 800)
225 MBRows = 2;
226 */
227 ctx->sRCParams.Slices = ctx->Slices;
228 ctx->sRCParams.QCPOffset = 0;/* FIXME */
229 if (ctx->sRCParams.IntraFreq != pSequenceParams->intra_period
230 && ctx->raw_frame_count != 0
231 && ctx->sRCParams.IntraFreq != 0
232 && ((ctx->obj_context->frame_count + 1) % ctx->sRCParams.IntraFreq) != 0
233 && (!ctx->sRCParams.bDisableFrameSkipping)) {
234 drv_debug_msg(VIDEO_DEBUG_ERROR,
235 "Changing intra period value in the middle of a GOP is\n"
236 "not allowed if frame skip isn't disabled.\n"
237 "it can cause I frame been skipped\n");
238 return VA_STATUS_ERROR_INVALID_PARAMETER;
239 }
240 else
241 ctx->sRCParams.IntraFreq = pSequenceParams->intra_period;
242
243 ctx->sRCParams.InitialLevel = (3 * ctx->sRCParams.BufferSize) >> 4;
244 /* Aligned with target frame size */
245 ctx->sRCParams.InitialLevel += (frame_size / 2);
246 ctx->sRCParams.InitialLevel /= frame_size;
247 ctx->sRCParams.InitialLevel *= frame_size;
248 ctx->sRCParams.InitialDelay = ctx->sRCParams.BufferSize - ctx->sRCParams.InitialLevel;
249 ctx->buffer_size = ctx->sRCParams.BufferSize;
250
251 /*if (ctx->sRCParams.BitsPerSecond < 256000)
252 ctx->sRCParams.BufferSize = (9 * ctx->sRCParams.BitsPerSecond) >> 1;
253 else
254 ctx->sRCParams.BufferSize = (5 * ctx->sRCParams.BitsPerSecond) >> 1;*/
255
256 if (ctx->raw_frame_count == 0) { /* Add Register IO behind begin Picture */
257 for (i = (ctx->ParallelCores - 1); i >= 0; i--)
258 pnw_set_bias(ctx, i);
259 }
260
261 free(pSequenceParams);
262 return VA_STATUS_SUCCESS;
263 }
264
265
266 /* Work done by the followinig funcs in testbench should be done here.
267 * IMG_C_StartPicture()
268 * IMG_C_InsertSync()
269 * APP_H263_SendPictureHeader()
270 * Frame skip must be taken into consideration
271 * */
pnw__H263ES_process_picture_param(context_ENC_p ctx,object_buffer_p obj_buffer)272 static VAStatus pnw__H263ES_process_picture_param(context_ENC_p ctx, object_buffer_p obj_buffer)
273 {
274 VAStatus vaStatus = VA_STATUS_SUCCESS;
275 VAEncPictureParameterBufferH263 *pBuffer;
276 pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf;
277 H263_SOURCE_FORMAT_TYPE SourceFormatType;
278 int i;
279
280 ASSERT(obj_buffer->type == VAEncPictureParameterBufferType);
281
282 if ((obj_buffer->num_elements != 1) ||
283 (obj_buffer->size != sizeof(VAEncPictureParameterBufferH263))) {
284 return VA_STATUS_ERROR_UNKNOWN;
285 }
286
287 /* Transfer ownership of VAEncPictureParameterBufferH263 data */
288 pBuffer = (VAEncPictureParameterBufferH263 *) obj_buffer->buffer_data;
289 obj_buffer->buffer_data = NULL;
290 obj_buffer->size = 0;
291
292 ctx->ref_surface = SURFACE(pBuffer->reference_picture);
293 ctx->dest_surface = SURFACE(pBuffer->reconstructed_picture);
294 ctx->coded_buf = BUFFER(pBuffer->coded_buf);
295
296 ctx->RawWidth = pBuffer->picture_width;
297 ctx->RawHeight = pBuffer->picture_height;
298
299 /* Insert do_header command here */
300
301 if ((ctx->Width == 128) && (ctx->Height == 96))
302 SourceFormatType = _128x96_SubQCIF;
303 else if ((ctx->Width == 176) && (ctx->Height == 144))
304 SourceFormatType = _176x144_QCIF;
305 else if ((ctx->Width == 352) && (ctx->Height == 288))
306 SourceFormatType = _352x288_CIF;
307 else if ((ctx->Width == 704) && (ctx->Height == 576))
308 SourceFormatType = _704x576_4CIF;
309 else if ((ctx->Width <= 720) && (ctx->Height <= 576))
310 SourceFormatType = 7;
311 else {
312 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Unsupported resolution!\n");
313 return VA_STATUS_ERROR_RESOLUTION_NOT_SUPPORTED;
314 }
315
316 memset(cmdbuf->header_mem_p + ctx->pic_header_ofs,
317 0,
318 HEADER_SIZE);
319 pnw__H263_prepare_picture_header(cmdbuf->header_mem_p + ctx->pic_header_ofs,
320 ctx->obj_context->frame_count,
321 pBuffer->picture_type,
322 SourceFormatType,
323 ctx->sRCParams.FrameRate,
324 ctx->RawWidth,
325 ctx->RawHeight);
326
327 pnw_cmdbuf_insert_command_package(ctx->obj_context,
328 ctx->ParallelCores - 1, /* Send to the last core as this will complete first */
329 MTX_CMDID_DO_HEADER,
330 &cmdbuf->header_mem,
331 ctx->pic_header_ofs);
332
333
334 /* Prepare START_PICTURE params */
335 /* Actually H263 only use 1 core from DDKv186 */
336 for (i = (ctx->ParallelCores - 1); i >= 0; i--)
337 vaStatus = pnw_RenderPictureParameter(ctx, i);
338
339 free(pBuffer);
340 return vaStatus;
341 }
342
343
pnw__H263ES_process_slice_param(context_ENC_p ctx,object_buffer_p obj_buffer)344 static VAStatus pnw__H263ES_process_slice_param(context_ENC_p ctx, object_buffer_p obj_buffer)
345 {
346 /* Prepare InParams for macros of current slice, insert slice header, insert do slice command */
347 VAEncSliceParameterBuffer *pBuffer;
348 pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf;
349 PIC_PARAMS *psPicParams = (PIC_PARAMS *)(cmdbuf->pic_params_p);
350 unsigned int i;
351 int slice_param_idx;
352
353 ASSERT(obj_buffer->type == VAEncSliceParameterBufferType);
354
355 /* Transfer ownership of VAEncPictureParameterBufferH263 data */
356 pBuffer = (VAEncSliceParameterBuffer *) obj_buffer->buffer_data;
357 obj_buffer->size = 0;
358
359 /*In case the slice number changes*/
360 if ((ctx->slice_param_cache != NULL) && (obj_buffer->num_elements != ctx->slice_param_num)) {
361 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Slice number changes. Previous value is %d. Now it's %d\n",
362 ctx->slice_param_num, obj_buffer->num_elements);
363 free(ctx->slice_param_cache);
364 ctx->slice_param_cache = NULL;
365 ctx->slice_param_num = 0;
366 }
367
368 if (NULL == ctx->slice_param_cache) {
369 ctx->slice_param_num = obj_buffer->num_elements;
370 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Allocate %d VAEncSliceParameterBuffer cache buffers\n", 2 * ctx->slice_param_num);
371 ctx->slice_param_cache = calloc(2 * ctx->slice_param_num, sizeof(VAEncSliceParameterBuffer));
372 if (NULL == ctx->slice_param_cache) {
373 drv_debug_msg(VIDEO_DEBUG_ERROR, "Run out of memory!\n");
374 free(obj_buffer->buffer_data);
375 return VA_STATUS_ERROR_ALLOCATION_FAILED;
376 }
377 }
378
379 for (i = 0; i < obj_buffer->num_elements; i++) {
380 /*Todo list:
381 *1.Insert Do header command
382 *2.setup InRowParams
383 *3.setup Slice params
384 *4.Insert Do slice command
385 * */
386 unsigned char deblock_idc;
387
388 deblock_idc = pBuffer->slice_flags.bits.disable_deblocking_filter_idc;
389
390 /* Insert Do Header command, relocation is needed */
391 if (ctx->obj_context->slice_count) { /*First slice of a frame need not slice header*/
392 memset(cmdbuf->header_mem_p + ctx->slice_header_ofs
393 + ctx->obj_context->slice_count * HEADER_SIZE,
394 0,
395 HEADER_SIZE);
396
397 pnw__H263_prepare_GOBslice_header(
398 cmdbuf->header_mem_p + ctx->slice_header_ofs + ctx->obj_context->slice_count * HEADER_SIZE,
399 ctx->obj_context->slice_count,
400 ctx->obj_context->frame_count);
401
402 ctx->LastSliceNum[ctx->SliceToCore] = ctx->obj_context->slice_count;
403
404 pnw_cmdbuf_insert_command_package(ctx->obj_context,
405 ctx->SliceToCore,
406 MTX_CMDID_DO_HEADER,
407 &cmdbuf->header_mem,
408 ctx->slice_header_ofs + ctx->obj_context->slice_count * HEADER_SIZE);
409
410 if (0 == ctx->SliceToCore) {
411 ctx->SliceToCore = ctx->ParallelCores;
412 }
413 ctx->SliceToCore--;
414
415 }
416
417 if ((pBuffer->start_row_number == 0) && pBuffer->slice_flags.bits.is_intra) {
418 pnw_reset_encoder_params(ctx); /* originally do in BeginPicture, but beginpicture has no intra info */
419 ctx->BelowParamsBufIdx = (ctx->BelowParamsBufIdx + 1) & 0x1;
420 }
421
422 slice_param_idx = (pBuffer->slice_flags.bits.is_intra ? 0 : 1) * ctx->slice_param_num + i;
423 if (VAEncSliceParameter_Equal(&ctx->slice_param_cache[slice_param_idx], pBuffer) == 0) {
424 /* cache current param parameters */
425 memcpy(&ctx->slice_param_cache[slice_param_idx],
426 pBuffer, sizeof(VAEncSliceParameterBuffer));
427
428 /* Setup InParams value*/
429 pnw_setup_slice_params(ctx,
430 pBuffer->start_row_number * 16,
431 pBuffer->slice_height * 16,
432 pBuffer->slice_flags.bits.is_intra,
433 ctx->obj_context->frame_count > 0,
434 psPicParams->sInParams.SeInitQP);
435 }
436
437 /* Insert do slice command and setup related buffer value */
438 pnw__send_encode_slice_params(ctx,
439 pBuffer->slice_flags.bits.is_intra,
440 pBuffer->start_row_number * 16,
441 deblock_idc,
442 ctx->obj_context->frame_count,
443 pBuffer->slice_height * 16,
444 ctx->obj_context->slice_count);
445
446 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Now frame_count/slice_count is %d/%d\n",
447 ctx->obj_context->frame_count, ctx->obj_context->slice_count);
448
449 ctx->obj_context->slice_count++;
450 pBuffer++; /*Move to the next buffer*/
451
452 ASSERT(ctx->obj_context->slice_count < MAX_SLICES_PER_PICTURE);
453 }
454
455 free(obj_buffer->buffer_data);
456 obj_buffer->buffer_data = NULL;
457 return VA_STATUS_SUCCESS;
458 }
459
460
461
pnw_H263ES_RenderPicture(object_context_p obj_context,object_buffer_p * buffers,int num_buffers)462 static VAStatus pnw_H263ES_RenderPicture(
463 object_context_p obj_context,
464 object_buffer_p *buffers,
465 int num_buffers)
466 {
467 int i;
468 INIT_CONTEXT_H263ES;
469 VAStatus vaStatus = VA_STATUS_SUCCESS;
470
471 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H263ES_RenderPicture\n");
472
473 for (i = 0; i < num_buffers; i++) {
474 object_buffer_p obj_buffer = buffers[i];
475
476 switch (obj_buffer->type) {
477 case VAEncSequenceParameterBufferType:
478 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H263_RenderPicture got VAEncSequenceParameterBufferType\n");
479 vaStatus = pnw__H263ES_process_sequence_param(ctx, obj_buffer);
480 DEBUG_FAILURE;
481 break;
482
483 case VAEncPictureParameterBufferType:
484 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H263_RenderPicture got VAEncPictureParameterBuffer\n");
485 vaStatus = pnw__H263ES_process_picture_param(ctx, obj_buffer);
486 DEBUG_FAILURE;
487 break;
488
489 case VAEncSliceParameterBufferType:
490 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H263_RenderPicture got VAEncSliceParameterBufferType\n");
491 vaStatus = pnw__H263ES_process_slice_param(ctx, obj_buffer);
492 DEBUG_FAILURE;
493 break;
494
495 default:
496 vaStatus = VA_STATUS_ERROR_UNKNOWN;
497 DEBUG_FAILURE;
498 }
499 if (vaStatus != VA_STATUS_SUCCESS) {
500 break;
501 }
502 }
503
504
505 return vaStatus;
506 }
507
pnw_H263ES_EndPicture(object_context_p obj_context)508 static VAStatus pnw_H263ES_EndPicture(
509 object_context_p obj_context)
510 {
511 VAStatus vaStatus = VA_STATUS_SUCCESS;
512 INIT_CONTEXT_H263ES;
513
514 drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_H263ES_EndPicture\n");
515
516 vaStatus = pnw_EndPicture(ctx);
517
518 return vaStatus;
519 }
520
521
522 struct format_vtable_s pnw_H263ES_vtable = {
523 queryConfigAttributes:
524 pnw_H263ES_QueryConfigAttributes,
525 validateConfig:
526 pnw_H263ES_ValidateConfig,
527 createContext:
528 pnw_H263ES_CreateContext,
529 destroyContext:
530 pnw_H263ES_DestroyContext,
531 beginPicture:
532 pnw_H263ES_BeginPicture,
533 renderPicture:
534 pnw_H263ES_RenderPicture,
535 endPicture:
536 pnw_H263ES_EndPicture
537 };
538