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 * Zeng Li <zeng.li@intel.com>
27 * Shengquan Yuan <shengquan.yuan@intel.com>
28 * Binglin Chen <binglin.chen@intel.com>
29 *
30 */
31
32
33
34 #include "psb_drv_video.h"
35
36 #include "lnc_hostcode.h"
37 #include "hwdefs/topaz_defs.h"
38 #include "psb_def.h"
39 #include "psb_cmdbuf.h"
40 #include <stdio.h>
41 #include "psb_output.h"
42 #include <wsbm/wsbm_manager.h>
43 #include "lnc_hostheader.h"
44 #include "psb_drv_debug.h"
45
46 #define ALIGN_TO(value, align) ((value + align - 1) & ~(align - 1))
47 #define PAGE_ALIGN(value) ALIGN_TO(value, 4096)
48
lnc__alloc_context_buffer(context_ENC_p ctx)49 static VAStatus lnc__alloc_context_buffer(context_ENC_p ctx)
50 {
51 int width, height;
52 VAStatus vaStatus = VA_STATUS_SUCCESS;
53
54 /* width and height should be source surface's w and h or ?? */
55 width = ctx->obj_context->picture_width;
56 height = ctx->obj_context->picture_height;
57
58 ctx->pic_params_size = 256;
59
60 ctx->header_buffer_size = 4 * HEADER_SIZE + MAX_SLICES_PER_PICTURE * HEADER_SIZE;
61
62 ctx->seq_header_ofs = 0;
63 ctx->pic_header_ofs = HEADER_SIZE;
64 ctx->eoseq_header_ofs = 2 * HEADER_SIZE;
65 ctx->eostream_header_ofs = 3 * HEADER_SIZE;
66 ctx->slice_header_ofs = 4 * HEADER_SIZE;
67
68 ctx->sliceparam_buffer_size = ((sizeof(SLICE_PARAMS) + 15) & 0xfff0) * MAX_SLICES_PER_PICTURE;
69
70 /* All frame share same MTX_CURRENT_IN_PARAMS and above/bellow param
71 * create MTX_CURRENT_IN_PARAMS buffer seperately
72 * every MB has one MTX_CURRENT_IN_PARAMS structure, and the (N+1) frame can
73 * reuse (N) frame's structure
74 */
75 ctx->in_params_size = (10 + width * height / (16 * 16)) * sizeof(MTX_CURRENT_IN_PARAMS);
76 ctx->bellow_params_size = BELOW_PARAMS_SIZE * width * height / (16 * 16) * 16;
77 ctx->above_params_size = (width * height / 16) * 128 + 15;
78
79 ctx->topaz_buffer_size = ctx->in_params_size + /* MTX_CURRENT_IN_PARAMS size */
80 ctx->bellow_params_size + /* above_params */
81 ctx->above_params_size; /* above_params */
82
83 vaStatus = psb_buffer_create(ctx->obj_context->driver_data, ctx->in_params_size, psb_bt_cpu_vpu, &ctx->topaz_in_params_I);
84 vaStatus |= psb_buffer_create(ctx->obj_context->driver_data, ctx->in_params_size, psb_bt_cpu_vpu, &ctx->topaz_in_params_P);
85 vaStatus |= psb_buffer_create(ctx->obj_context->driver_data, ctx->above_params_size + ctx->bellow_params_size, psb_bt_cpu_vpu, &ctx->topaz_above_bellow_params);
86
87 ctx->in_params_ofs = 0;
88 ctx->bellow_params_ofs = 0;
89 ctx->above_params_ofs = ctx->bellow_params_ofs + ctx->bellow_params_size;
90
91 return vaStatus;
92 }
93
lnc__get_ipe_control(enum drm_lnc_topaz_codec eEncodingFormat)94 unsigned int lnc__get_ipe_control(enum drm_lnc_topaz_codec eEncodingFormat)
95 {
96 unsigned int RegVal = 0;
97
98 RegVal = F_ENCODE(2, MVEA_CR_IPE_GRID_FINE_SEARCH) |
99 F_ENCODE(0, MVEA_CR_IPE_GRID_SEARCH_SIZE) |
100 F_ENCODE(1, MVEA_CR_IPE_Y_FINE_SEARCH);
101
102 switch (eEncodingFormat) {
103 case IMG_CODEC_H263_NO_RC:
104 case IMG_CODEC_H263_VBR:
105 case IMG_CODEC_H263_CBR:
106 RegVal |= F_ENCODE(0, MVEA_CR_IPE_BLOCKSIZE) | F_ENCODE(0, MVEA_CR_IPE_ENCODING_FORMAT);
107 break;
108 case IMG_CODEC_MPEG4_NO_RC:
109 case IMG_CODEC_MPEG4_VBR:
110 case IMG_CODEC_MPEG4_CBR:
111 RegVal |= F_ENCODE(1, MVEA_CR_IPE_BLOCKSIZE) | F_ENCODE(1, MVEA_CR_IPE_ENCODING_FORMAT);
112 default:
113 break;
114 case IMG_CODEC_H264_NO_RC:
115 case IMG_CODEC_H264_VBR:
116 case IMG_CODEC_H264_CBR:
117 case IMG_CODEC_H264_VCM:
118 RegVal |= F_ENCODE(2, MVEA_CR_IPE_BLOCKSIZE) | F_ENCODE(2, MVEA_CR_IPE_ENCODING_FORMAT);
119 break;
120 }
121 RegVal |= F_ENCODE(6, MVEA_CR_IPE_Y_CANDIDATE_NUM);
122 return RegVal;
123 }
124
125
lnc_DestroyContext(object_context_p obj_context)126 void lnc_DestroyContext(object_context_p obj_context)
127 {
128 context_ENC_p ctx;
129 ctx = (context_ENC_p)obj_context->format_data;
130 if (NULL != ctx->slice_param_cache)
131 free(ctx->slice_param_cache);
132 if (NULL == ctx->save_seq_header_p)
133 free(ctx->save_seq_header_p);
134 free(obj_context->format_data);
135 obj_context->format_data = NULL;
136 }
137
lnc_CreateContext(object_context_p obj_context,object_config_p obj_config)138 VAStatus lnc_CreateContext(
139 object_context_p obj_context,
140 object_config_p obj_config)
141 {
142 int width, height;
143 context_ENC_p ctx;
144 VAStatus vaStatus;
145
146 width = obj_context->picture_width;
147 height = obj_context->picture_height;
148 ctx = (context_ENC_p) calloc(1, sizeof(struct context_ENC_s));
149 if (NULL == ctx) {
150 vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
151 DEBUG_FAILURE;
152 return vaStatus;
153 }
154
155 obj_context->format_data = (void*) ctx;
156 ctx->obj_context = obj_context;
157
158 ctx->RawWidth = (unsigned short) width;
159 ctx->RawHeight = (unsigned short) height;
160
161 ctx->Width = (unsigned short)(~0xf & (width + 0xf));
162 ctx->Height = (unsigned short)(~0xf & (height + 0xf));
163
164 ctx->HeightMinus16MinusLRBTopOffset = ctx->Height - (MVEA_LRB_TOP_OFFSET + 16);
165 ctx->HeightMinus32MinusLRBTopOffset = ctx->Height - (MVEA_LRB_TOP_OFFSET + 32);
166 ctx->HeightMinusLRB_TopAndBottom_OffsetsPlus16 = ctx->Height - (MVEA_LRB_TOP_OFFSET + MVEA_LRB_TOP_OFFSET + 16);
167 ctx->HeightMinusLRBSearchHeight = ctx->Height - MVEA_LRB_SEARCH_HEIGHT;
168
169 ctx->FCode = 0;
170
171 ctx->sRCParams.VCMBitrateMargin = 0;
172 ctx->sRCParams.BufferSize = 0;
173 ctx->sRCParams.InitialQp = 0;
174 ctx->sRCParams.MinQP = 0;
175
176 vaStatus = lnc__alloc_context_buffer(ctx);
177
178 return vaStatus;
179 }
180
181
lnc_BeginPicture(context_ENC_p ctx)182 VAStatus lnc_BeginPicture(context_ENC_p ctx)
183 {
184 VAStatus vaStatus = VA_STATUS_SUCCESS;
185 lnc_cmdbuf_p cmdbuf;
186 int ret;
187
188 ctx->src_surface = ctx->obj_context->current_render_target;
189
190 /* clear frameskip flag to 0 */
191 CLEAR_SURFACE_INFO_skipped_flag(ctx->src_surface->psb_surface);
192
193 /* Initialise the command buffer */
194 ret = lnc_context_get_next_cmdbuf(ctx->obj_context);
195 if (ret) {
196 drv_debug_msg(VIDEO_DEBUG_GENERAL, "get next cmdbuf fail\n");
197 vaStatus = VA_STATUS_ERROR_UNKNOWN;
198 return vaStatus;
199 }
200 cmdbuf = ctx->obj_context->lnc_cmdbuf;
201
202 /* map start_pic param */
203 vaStatus = psb_buffer_map(&cmdbuf->pic_params, &cmdbuf->pic_params_p);
204 if (vaStatus) {
205 return vaStatus;
206 }
207 vaStatus = psb_buffer_map(&cmdbuf->header_mem, &cmdbuf->header_mem_p);
208 if (vaStatus) {
209 psb_buffer_unmap(&cmdbuf->pic_params);
210 return vaStatus;
211 }
212
213 vaStatus = psb_buffer_map(&cmdbuf->slice_params, &cmdbuf->slice_params_p);
214 if (vaStatus) {
215 psb_buffer_unmap(&cmdbuf->pic_params);
216 psb_buffer_unmap(&cmdbuf->header_mem);
217 return vaStatus;
218 }
219
220 /* only map topaz param when necessary */
221 cmdbuf->topaz_in_params_I_p = NULL;
222 cmdbuf->topaz_in_params_P_p = NULL;
223 cmdbuf->topaz_above_bellow_params_p = NULL;
224
225 if (ctx->obj_context->frame_count == 0) { /* first picture */
226 psb_driver_data_p driver_data = ctx->obj_context->driver_data;
227
228 lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_SW_NEW_CODEC, 3, driver_data->drm_context);
229 lnc_cmdbuf_insert_command_param(cmdbuf, ctx->eCodec);
230 lnc_cmdbuf_insert_command_param(cmdbuf, (ctx->Width << 16) | ctx->Height);
231 }
232
233 /* insert START_PIC command */
234 lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_START_PIC, 3, ctx->obj_context->frame_count);
235 /* write the address of structure PIC_PARAMS following command MTX_CMDID_START_PIC
236 * the content of PIC_PARAMS is filled when RenderPicture(...,VAEncPictureParameterBufferXXX)
237 */
238 RELOC_CMDBUF(cmdbuf->cmd_idx, 0, &cmdbuf->pic_params);
239 cmdbuf->cmd_idx++;
240 ctx->initial_qp_in_cmdbuf = cmdbuf->cmd_idx; /* remember the place */
241 cmdbuf->cmd_idx++;
242
243 ctx->obj_context->slice_count = 0;
244
245 /* no RC paramter provided in vaBeginPicture
246 * so delay RC param setup into vaRenderPicture(SequenceHeader...)
247 */
248 return vaStatus;
249 }
250
251
lnc_RenderPictureParameter(context_ENC_p ctx)252 VAStatus lnc_RenderPictureParameter(context_ENC_p ctx)
253 {
254 PIC_PARAMS *psPicParams; /* PIC_PARAMS has been put in lnc_hostcode.h */
255 object_surface_p src_surface;
256 unsigned int srf_buf_offset;
257 object_surface_p rec_surface;
258 object_surface_p ref_surface;
259 lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
260 VAStatus vaStatus = VA_STATUS_ERROR_UNKNOWN;
261
262 psPicParams = (PIC_PARAMS *)cmdbuf->pic_params_p;
263
264 /* second frame will reuse some rate control parameters (IN_PARAMS_MP4)
265 * so only memset picture parames except IN_PARAMS
266 * BUT now IN_RC_PARAMS was reload from the cache, so it now can
267 * memset entirE PIC_PARAMS
268 */
269 memset(psPicParams, 0, (int)((unsigned char *)&psPicParams->sInParams - (unsigned char *)psPicParams));
270
271 src_surface = ctx->src_surface;
272 if (NULL == src_surface) {
273 vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
274 DEBUG_FAILURE;
275 return vaStatus;
276 }
277
278 rec_surface = ctx->dest_surface;
279 if (NULL == rec_surface) {
280 vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
281 DEBUG_FAILURE;
282 return vaStatus;
283 }
284
285 /*The fisrt frame always is I frame and the content of reference frame wouldn't be used.
286 * But the heights of ref and dest frame should be the same.
287 * That allows Topaz to keep its motion vectors up to date, which helps maintain performance */
288 if (ctx->obj_context->frame_count == 0)
289 ctx->ref_surface = ctx->dest_surface;
290
291 ref_surface = ctx->ref_surface;
292 if (NULL == ref_surface) {
293 vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
294 DEBUG_FAILURE;
295 return vaStatus;
296 }
297
298 /* clear frameskip flag */
299 CLEAR_SURFACE_INFO_skipped_flag(rec_surface->psb_surface);
300 CLEAR_SURFACE_INFO_skipped_flag(ref_surface->psb_surface);
301
302 /* Write video data byte offset into Coded buffer
303 * If it is here, it will be a SYNC point, which have performance impact
304 * Move to psb__CreateBuffer
305 vaStatus = psb_buffer_map(ctx->coded_buf->psb_buffer, &pBuffer);
306 if(vaStatus) {
307 DEBUG_FAILURE;
308 return vaStatus;
309 }
310 *(IMG_UINT32 *)(pBuffer+8) = 16;
311 psb_buffer_unmap(ctx->coded_buf->psb_buffer);
312 */
313
314 psPicParams->SrcYStride = src_surface->psb_surface->stride;
315 switch (ctx->eFormat) {
316 case IMG_CODEC_IYUV: /* IYUV */
317 case IMG_CODEC_PL8:
318 psPicParams->SrcUVStride = src_surface->psb_surface->stride / 2;
319 psPicParams->SrcUVRowStride = src_surface->psb_surface->stride * 16 / 2;
320 break;
321 case IMG_CODEC_IMC2: /* IMC2 */
322 case IMG_CODEC_PL12:
323 psPicParams->SrcUVStride = src_surface->psb_surface->stride;
324 psPicParams->SrcUVRowStride = src_surface->psb_surface->stride * 16;
325 break;
326 default:
327 break;
328 }
329 psPicParams->SrcYRowStride = src_surface->psb_surface->stride * 16;
330 /* psPicParams->SrcUVRowStride = src_surface->psb_surface->stride * 16 / 2; */
331
332 /* Dest(rec) stride
333 * The are now literally Dst stride (not equivalent to 'offset to next row')
334 */
335 #ifdef VA_EMULATOR
336 /* only for simulator, va-emulator needs the actually stride for
337 * reconstructed frame transfer (va-emulator->driver)
338 */
339 psPicParams->DstYStride = rec_surface->psb_surface->stride;
340 psPicParams->DstUVStride = rec_surface->psb_surface->stride;
341 psPicParams->DstYRowStride = rec_surface->psb_surface->stride * 16;
342 psPicParams->DstUVRowStride = rec_surface->psb_surface->stride * 16 / 2;
343 #else
344 psPicParams->DstYStride = rec_surface->height * 16;
345 psPicParams->DstUVStride = rec_surface->height * 16 / 2;
346 psPicParams->DstYRowStride = psPicParams->DstYStride;
347 psPicParams->DstUVRowStride = psPicParams->DstUVStride;
348 #endif
349
350 psPicParams->InParamsRowStride = (ctx->obj_context->picture_width / 16) * 256;
351 psPicParams->BelowParamRowStride = (ctx->obj_context->picture_width / 16) * 32;
352
353 psPicParams->Width = ctx->Width;
354 psPicParams->Height = ctx->Height;
355
356 /* not sure why we are setting this up here... */
357 psPicParams->Flags = 0;
358 switch (ctx->eCodec) {
359 case IMG_CODEC_H264_NO_RC:
360 case IMG_CODEC_H264_VBR:
361 case IMG_CODEC_H264_CBR:
362 case IMG_CODEC_H264_VCM:
363 psPicParams->Flags |= ISH264_FLAGS;
364 break;
365 case IMG_CODEC_H263_VBR:
366 case IMG_CODEC_H263_CBR:
367 case IMG_CODEC_H263_NO_RC:
368 psPicParams->Flags |= ISH263_FLAGS;
369 break;
370 case IMG_CODEC_MPEG4_NO_RC:
371 case IMG_CODEC_MPEG4_VBR:
372 case IMG_CODEC_MPEG4_CBR:
373 psPicParams->Flags |= ISMPEG4_FLAGS;
374 break;
375 default:
376 return VA_STATUS_ERROR_UNKNOWN;
377 }
378
379 switch (ctx->eCodec) {
380 case IMG_CODEC_H264_VBR:
381 case IMG_CODEC_MPEG4_VBR:
382 case IMG_CODEC_H263_VBR:
383 psPicParams->Flags |= ISVBR_FLAGS;
384 break;
385 case IMG_CODEC_H264_VCM:
386 psPicParams->Flags |= ISVCM_FLAGS;
387 /* drop through to CBR case */
388 case IMG_CODEC_H263_CBR:
389 case IMG_CODEC_H264_CBR:
390 case IMG_CODEC_MPEG4_CBR:
391 psPicParams->Flags |= ISCBR_FLAGS;
392 break;
393 case IMG_CODEC_MPEG4_NO_RC:
394 case IMG_CODEC_H263_NO_RC:
395 case IMG_CODEC_H264_NO_RC:
396 break;
397 default:
398 return VA_STATUS_ERROR_UNKNOWN;
399 }
400
401
402 if (ctx->sRCParams.RCEnable) {
403 /* for the first frame, will setup RC params in EndPicture */
404 if (ctx->obj_context->frame_count > 0) { /* reuse in_params parameter */
405 /* reload IN_RC_PARAMS from cache */
406 memcpy(&psPicParams->sInParams, &ctx->in_params_cache, sizeof(IN_RC_PARAMS));
407
408 /* delay these into END_PICTURE timeframe */
409 /*
410 psPicParams->sInParams.BitsTransmitted = ctx->sRCParams.BitsTransmitted;
411 */
412 }
413 } else
414 psPicParams->sInParams.SeInitQP = ctx->sRCParams.InitialQp;
415
416 /* some relocations have to been done here */
417 srf_buf_offset = src_surface->psb_surface->buf.buffer_ofs;
418 if (src_surface->psb_surface->buf.type == psb_bt_camera)
419 drv_debug_msg(VIDEO_DEBUG_GENERAL, "src surface GPU offset 0x%08x, luma offset 0x%08x\n",
420 wsbmBOOffsetHint(src_surface->psb_surface->buf.drm_buf), srf_buf_offset);
421
422 RELOC_PIC_PARAMS(&psPicParams->SrcYBase, srf_buf_offset, &src_surface->psb_surface->buf);
423 switch (ctx->eFormat) {
424 case IMG_CODEC_IYUV:
425 case IMG_CODEC_PL8:
426 case IMG_CODEC_PL12:
427 RELOC_PIC_PARAMS(&psPicParams->SrcUBase,
428 srf_buf_offset + src_surface->psb_surface->chroma_offset,
429 &src_surface->psb_surface->buf);
430
431 RELOC_PIC_PARAMS(&psPicParams->SrcVBase,
432 srf_buf_offset + src_surface->psb_surface->chroma_offset,
433 &src_surface->psb_surface->buf);
434
435 break;
436 case IMG_CODEC_IMC2:
437 case IMG_CODEC_NV12:
438 break;
439 }
440
441 /*
442 * Do not forget this!
443 * MTXWriteMem(MTXData.ui32CCBCtrlAddr + MTX_CCBCTRL_QP, sRCParams.ui32InitialQp);
444 */
445 /* following START_PIC, insert initial QP */
446 *ctx->initial_qp_in_cmdbuf = ctx->sRCParams.InitialQp;
447
448
449 RELOC_PIC_PARAMS(&psPicParams->DstYBase, 0, &rec_surface->psb_surface->buf);
450
451 RELOC_PIC_PARAMS(&psPicParams->DstUVBase,
452 rec_surface->psb_surface->stride * rec_surface->height,
453 &rec_surface->psb_surface->buf);
454
455 RELOC_PIC_PARAMS(&psPicParams->CodedBase, 0, ctx->coded_buf->psb_buffer);
456
457 /* MTX_CURRENT_IN_PARAMS buffer is seperate buffer now */
458 /*The type of frame will decide psPicParams->InParamsBase should
459 * use cmdbuf->topaz_in_params_P or cmdbuf->topaz_in_params_I*/
460 /*RELOC_PIC_PARAMS(&psPicParams->InParamsBase, ctx->in_params_ofs, cmdbuf->topaz_in_params_P);*/
461 RELOC_PIC_PARAMS(&psPicParams->BelowParamsBase, ctx->bellow_params_ofs, cmdbuf->topaz_above_bellow_params);
462 RELOC_PIC_PARAMS(&psPicParams->AboveParamsBase, ctx->above_params_ofs, cmdbuf->topaz_above_bellow_params);
463
464 return VA_STATUS_SUCCESS;
465 }
466
lnc__PatchBitsConsumedInRCParam(context_ENC_p ctx)467 static VAStatus lnc__PatchBitsConsumedInRCParam(context_ENC_p ctx)
468 {
469 lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
470 /* PIC_PARAMS *psPicParams = cmdbuf->pic_params_p; */
471 VAStatus vaStatus;
472
473 (void)cmdbuf;
474 /* it will wait until last encode session is done */
475 /* now it just wait the last session is done and the frame skip
476 * is */
477 drv_debug_msg(VIDEO_DEBUG_GENERAL, "will patch bits consumed for rc\n");
478 if (ctx->pprevious_coded_buf) {
479 vaStatus = psb_buffer_sync(ctx->pprevious_coded_buf->psb_buffer);
480 if (vaStatus)
481 return vaStatus;
482 }
483
484 return VA_STATUS_SUCCESS;
485 }
486
lnc_RedoRenderPictureSkippedFrame(context_ENC_p ctx)487 static VAStatus lnc_RedoRenderPictureSkippedFrame(context_ENC_p ctx)
488 {
489 lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
490 VAStatus vaStatus = VA_STATUS_SUCCESS;
491 int i = 0;
492
493 /* reset cmdbuf to skip existing picture/slice DO_HEAD commands */
494 cmdbuf->cmd_idx = cmdbuf->cmd_idx_saved_frameskip;
495
496 switch (ctx->eCodec) {
497 case IMG_CODEC_H263_CBR: /* H263 don't need picture header/slice header, only reset command buf */
498 case IMG_CODEC_H263_VBR:
499 break;
500 case IMG_CODEC_H264_VBR:
501 case IMG_CODEC_H264_CBR: /* slice header needs redo */
502 case IMG_CODEC_H264_VCM: {
503 /* only need one slice header here */
504 VAEncSliceParameterBuffer *pBuffer = &ctx->slice_param_cache[i];
505 unsigned int MBSkipRun, FirstMBAddress;
506 int deblock_on;
507
508 if ((pBuffer->slice_flags.bits.disable_deblocking_filter_idc == 0)
509 || (pBuffer->slice_flags.bits.disable_deblocking_filter_idc == 2))
510 deblock_on = IMG_TRUE;
511 else
512 deblock_on = IMG_FALSE;
513
514 if (1 /* ctx->sRCParams.RCEnable && ctx->sRCParams.FrameSkip */) /* we know it is true */
515 MBSkipRun = (ctx->Width * ctx->Height) / 256;
516 else
517 MBSkipRun = 0;
518
519 FirstMBAddress = (pBuffer->start_row_number * ctx->Width) / 16;
520 /* Insert Do Header command, relocation is needed */
521
522 lnc__H264_prepare_slice_header((IMG_UINT32 *)(cmdbuf->header_mem_p + ctx->slice_header_ofs + i * HEADER_SIZE),
523 0, /*pBuffer->slice_flags.bits.is_intra*/
524 pBuffer->slice_flags.bits.disable_deblocking_filter_idc,
525 ctx->obj_context->frame_count,
526 FirstMBAddress,
527 MBSkipRun,
528 (ctx->obj_context->frame_count == 0),
529 pBuffer->slice_flags.bits.uses_long_term_ref,
530 pBuffer->slice_flags.bits.is_long_term_ref,
531 ctx->idr_pic_id);
532
533
534 lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_DO_HEADER, 2, (i << 2) | 2);
535 RELOC_CMDBUF(cmdbuf->cmd_idx++,
536 ctx->slice_header_ofs + i * HEADER_SIZE,
537 &cmdbuf->header_mem);
538 }
539
540 break;
541 case IMG_CODEC_MPEG4_VBR:
542 case IMG_CODEC_MPEG4_CBR: /* only picture header need redo */
543 lnc__MPEG4_prepare_vop_header((IMG_UINT32 *)(cmdbuf->header_mem_p + ctx->pic_header_ofs),
544 IMG_FALSE /* bIsVOPCoded is false now */,
545 ctx->MPEG4_vop_time_increment_frameskip, /* In testbench, this should be FrameNum */
546 4,/* default value is 4,search range */
547 ctx->MPEG4_picture_type_frameskip,
548 ctx->MPEG4_vop_time_increment_resolution/* defaule value */);
549
550 lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_DO_HEADER, 2, 1);
551 RELOC_CMDBUF(cmdbuf->cmd_idx++, ctx->pic_header_ofs, &cmdbuf->header_mem);
552 vaStatus = lnc_RenderPictureParameter(ctx);
553 break;
554 default:
555 drv_debug_msg(VIDEO_DEBUG_ERROR, "Non-RC mode should be here for FrameSkip handling\n");
556 ASSERT(0);
557 }
558
559 return vaStatus;
560 }
561
lnc_SetupRCParam(context_ENC_p ctx)562 static VAStatus lnc_SetupRCParam(context_ENC_p ctx)
563 {
564 lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
565 PIC_PARAMS *psPicParams = (PIC_PARAMS *)cmdbuf->pic_params_p;
566 int origin_qp;/* in DDK setup_rc will change qp strangly,
567 * just for keep same with DDK
568 */
569
570 origin_qp = ctx->sRCParams.InitialQp;
571
572 drv_debug_msg(VIDEO_DEBUG_GENERAL, "will setup rc data\n");
573
574 psPicParams->Flags |= ISRC_FLAGS;
575 lnc__setup_rcdata(ctx, psPicParams, &ctx->sRCParams);
576
577 /* restore it, just keep same with DDK */
578 ctx->sRCParams.InitialQp = origin_qp;
579
580 /* save IN_RC_PARAMS into the cache */
581 memcpy(&ctx->in_params_cache, (unsigned char *)&psPicParams->sInParams, sizeof(IN_RC_PARAMS));
582
583 return VA_STATUS_SUCCESS;
584 }
585
lnc_UpdateRCParam(context_ENC_p ctx)586 static VAStatus lnc_UpdateRCParam(context_ENC_p ctx)
587 {
588 int origin_qp;
589 lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
590 PIC_PARAMS *psPicParams = (PIC_PARAMS *)cmdbuf->pic_params_p;
591
592 origin_qp = ctx->sRCParams.InitialQp;
593
594 drv_debug_msg(VIDEO_DEBUG_GENERAL, "will update rc data\n");
595 lnc__update_rcdata(ctx, psPicParams, &ctx->sRCParams);
596
597 /* set minQP if hosts set minQP */
598 if (ctx->sRCParams.MinQP)
599 psPicParams->sInParams.MinQPVal = ctx->sRCParams.MinQP;
600
601 /* if seinitqp is set, restore the value hosts want */
602 if (origin_qp) {
603 psPicParams->sInParams.SeInitQP = origin_qp;
604 psPicParams->sInParams.MyInitQP = origin_qp;
605 ctx->sRCParams.InitialQp = origin_qp;
606 }
607
608 /* save IN_RC_PARAMS into the cache */
609 memcpy(&ctx->in_params_cache, (unsigned char *)&psPicParams->sInParams, sizeof(IN_RC_PARAMS));
610
611 return VA_STATUS_SUCCESS;
612 }
613
lnc_PatchRCMode(context_ENC_p ctx)614 static VAStatus lnc_PatchRCMode(context_ENC_p ctx)
615 {
616 int frame_skip = 0;
617
618 drv_debug_msg(VIDEO_DEBUG_GENERAL, "will patch rc data\n");
619 /* it will ensure previous encode finished */
620 lnc__PatchBitsConsumedInRCParam(ctx);
621
622 /* get frameskip flag */
623 lnc_surface_get_frameskip(ctx->obj_context->driver_data, ctx->src_surface->psb_surface, &frame_skip);
624 /* current frame is skipped
625 * redo RenderPicture with FrameSkip set
626 */
627 if (frame_skip == 1)
628 lnc_RedoRenderPictureSkippedFrame(ctx);
629
630 return VA_STATUS_SUCCESS;
631 }
632
lnc_EndPicture(context_ENC_p ctx)633 VAStatus lnc_EndPicture(context_ENC_p ctx)
634 {
635 VAStatus vaStatus = VA_STATUS_SUCCESS;
636 lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
637
638 if (ctx->sRCParams.RCEnable == IMG_TRUE) {
639 if (ctx->obj_context->frame_count == 0)
640 lnc_SetupRCParam(ctx);
641 else if (ctx->update_rc_control)
642 lnc_UpdateRCParam(ctx);
643 else
644 lnc_PatchRCMode(ctx);
645 }
646 ctx->update_rc_control = 0;
647
648 /* save current settings */
649 ctx->previous_src_surface = ctx->src_surface;
650 ctx->previous_ref_surface = ctx->ref_surface;
651 ctx->previous_dest_surface = ctx->dest_surface; /* reconstructed surface */
652 ctx->pprevious_coded_buf = ctx->previous_coded_buf;
653 ctx->previous_coded_buf = ctx->coded_buf;
654
655 lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_END_PIC, 3, 0);
656 lnc_cmdbuf_insert_command_param(cmdbuf, 0);/* two meaningless parameters */
657 lnc_cmdbuf_insert_command_param(cmdbuf, 0);
658 psb_buffer_unmap(&cmdbuf->pic_params);
659 psb_buffer_unmap(&cmdbuf->header_mem);
660 psb_buffer_unmap(&cmdbuf->slice_params);
661
662 /* unmap MTX_CURRENT_IN_PARAMS buffer only when it is mapped */
663 if (cmdbuf->topaz_in_params_I_p != NULL) {
664 psb_buffer_unmap(cmdbuf->topaz_in_params_I);
665 cmdbuf->topaz_in_params_I_p = NULL;
666 }
667
668 if (cmdbuf->topaz_in_params_P_p != NULL) {
669 psb_buffer_unmap(cmdbuf->topaz_in_params_P);
670 cmdbuf->topaz_in_params_P_p = NULL;
671 }
672
673 if (cmdbuf->topaz_above_bellow_params_p != NULL) {
674 psb_buffer_unmap(cmdbuf->topaz_above_bellow_params);
675 cmdbuf->topaz_above_bellow_params_p = NULL;
676 }
677
678 if (lnc_context_flush_cmdbuf(ctx->obj_context)) {
679 vaStatus = VA_STATUS_ERROR_UNKNOWN;
680 }
681
682 return vaStatus;
683 }
684
lnc__setup_busize(context_ENC_p ctx)685 static void lnc__setup_busize(context_ENC_p ctx)
686 {
687 unsigned int old_busize = ctx->sRCParams.BUSize;
688
689 /* it is called at EndPicture, we should now the Slice number */
690 ctx->Slices = ctx->obj_context->slice_count;
691
692 /* if no BU size is given then pick one ourselves */
693 if (ctx->sRCParams.BUSize != 0) { /* application provided BUSize */
694 IMG_UINT32 MBs, MBsperSlice, MBsLastSlice;
695 IMG_UINT32 BUs;
696 IMG_INT32 SliceHeight;
697
698 MBs = ctx->Height * ctx->Width / (16 * 16);
699
700 SliceHeight = ctx->Height / ctx->Slices;
701 /* SliceHeight += 15; */
702 SliceHeight &= ~15;
703
704 MBsperSlice = (SliceHeight * ctx->Width) / (16 * 16);
705 MBsLastSlice = MBs - (MBsperSlice * (ctx->Slices - 1));
706
707 /* they have given us a basic unit so validate it */
708 if (ctx->sRCParams.BUSize < 6) {
709 drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size too small, must be greater than 6\n");
710 ctx->sRCParams.BUSize = 0; /* need repatch */;
711 }
712 if (ctx->sRCParams.BUSize > MBsperSlice) {
713 drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size too large, must be less than the number of macroblocks in a slice\n");
714 ctx->sRCParams.BUSize = 0; /* need repatch */;
715 }
716 if (ctx->sRCParams.BUSize > MBsLastSlice) {
717 drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size too large, must be less than number of macroblocks in the last slice\n");
718 ctx->sRCParams.BUSize = 0; /* need repatch */;
719 }
720 BUs = MBsperSlice / ctx->sRCParams.BUSize;
721 if ((BUs * ctx->sRCParams.BUSize) != MBsperSlice) {
722 drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size not an integer divisor of MB's in a slice");
723 ctx->sRCParams.BUSize = 0; /* need repatch */;
724 }
725 if (BUs > 200) {
726 drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size too small. There must be less than 200 basic units per slice");
727 ctx->sRCParams.BUSize = 0; /* need repatch */;
728 }
729 BUs = MBsLastSlice / ctx->sRCParams.BUSize;
730 if (BUs > 200) {
731 drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Basic unit size too small. There must be less than 200 basic units per slice");
732 ctx->sRCParams.BUSize = 0; /* need repatch */;
733 }
734 }
735
736 if (ctx->sRCParams.BUSize == 0) {
737 IMG_UINT32 MBs, MBsperSlice, MBsLastSlice;
738 IMG_UINT32 BUs, BUsperSlice, BUsLastSlice;
739 IMG_INT32 SliceHeight;
740
741 MBs = ctx->Height * ctx->Width / (16 * 16);
742
743 SliceHeight = ctx->Height / ctx->Slices;
744 /* SliceHeight += 15; */
745 SliceHeight &= ~15;
746
747 MBsperSlice = (SliceHeight * ctx->Width) / (16 * 16);
748 MBsLastSlice = MBs - (MBsperSlice * (ctx->Slices - 1));
749
750 /* we have to verify that MBs is divisiable by BU AND that BU is > pipeline length */
751 if (ctx->sRCParams.BUSize < 6) {
752 ctx->sRCParams.BUSize = 6;
753 }
754
755 BUs = MBs / ctx->sRCParams.BUSize;
756 while (BUs*ctx->sRCParams.BUSize != MBs) {
757 ctx->sRCParams.BUSize++;
758 BUs = MBs / ctx->sRCParams.BUSize;
759 }
760
761 /* Check number of BUs in the pipe is less than maximum number allowed 200 */
762 BUsperSlice = MBsperSlice / ctx->sRCParams.BUSize;
763 BUsLastSlice = MBsLastSlice / ctx->sRCParams.BUSize;
764 while ((BUsperSlice *(ctx->Slices - 1) + BUsLastSlice) > 200) {
765 ctx->sRCParams.BUSize++;
766 BUsperSlice = MBsperSlice / ctx->sRCParams.BUSize;
767 BUsLastSlice = MBsLastSlice / ctx->sRCParams.BUSize;
768 }
769
770 /* Check whether there are integer number of BUs in the slices */
771 BUsperSlice = MBsperSlice / ctx->sRCParams.BUSize;
772 BUsLastSlice = MBsLastSlice / ctx->sRCParams.BUSize;
773 while ((BUsperSlice*ctx->sRCParams.BUSize != MBsperSlice) ||
774 (BUsLastSlice*ctx->sRCParams.BUSize != MBsLastSlice)) {
775 ctx->sRCParams.BUSize++;
776 BUsperSlice = MBsperSlice / ctx->sRCParams.BUSize;
777 BUsLastSlice = MBsLastSlice / ctx->sRCParams.BUSize;
778 }
779
780 if (ctx->sRCParams.BUSize != old_busize)
781 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Patched Basic unit to %d (original=%d)\n", ctx->sRCParams.BUSize, old_busize);
782 }
783 }
784
785
786 /***********************************************************************************
787 * Function Name : SetupRCData
788 * Inputs :
789 * Outputs :
790 * Returns :
791 * Description : Sets up RC Data
792 ************************************************************************************/
lnc__setup_rcdata(context_ENC_p psContext,PIC_PARAMS * psPicParams,IMG_RC_PARAMS * psRCParams)793 void lnc__setup_rcdata(
794 context_ENC_p psContext,
795 PIC_PARAMS *psPicParams,
796 IMG_RC_PARAMS *psRCParams)
797 {
798 IMG_UINT32 max_bitrate = psContext->Width * psContext->Height * 1.5 * 8 * 60;
799 IMG_UINT8 InitialSeInitQP = 0;
800
801 /* frameskip is always cleared, specially handled at vaEndPicture */
802 psRCParams->FrameSkip = 0;
803
804 if (!psRCParams->BitsPerSecond)
805 psRCParams->BitsPerSecond = 64000;
806 if (psRCParams->BitsPerSecond > max_bitrate)
807 psRCParams->BitsPerSecond = max_bitrate;
808
809 if (!psRCParams->FrameRate)
810 psRCParams->FrameRate = 30;
811
812 if (psRCParams->BufferSize == 0) {
813 if (psRCParams->BitsPerSecond < 256000)
814 psRCParams->BufferSize = (9 * psRCParams->BitsPerSecond) >> 1;
815 else
816 psRCParams->BufferSize = (5 * psRCParams->BitsPerSecond) >> 1;
817 }
818 psRCParams->InitialLevel = (3 * psRCParams->BufferSize) >> 4;
819 psRCParams->InitialDelay = (13 * psRCParams->BufferSize) >> 4;
820
821 lnc__setup_busize(psContext); /* calculate BasicUnitSize */
822
823 psPicParams->sInParams.SeInitQP = psRCParams->InitialQp;
824
825 psPicParams->sInParams.MBPerRow = (psContext->Width >> 4);
826 psPicParams->sInParams.MBPerBU = psRCParams->BUSize;
827 psPicParams->sInParams.MBPerFrm = (psContext->Width >> 4) * (psContext->Height >> 4);
828 psPicParams->sInParams.BUPerFrm = (psPicParams->sInParams.MBPerFrm) / psRCParams->BUSize;
829
830 InitialSeInitQP = psPicParams->sInParams.SeInitQP;
831
832 lnc__update_rcdata(psContext, psPicParams, psRCParams);
833 /* set minQP if hosts set minQP */
834 if (psRCParams->MinQP)
835 psPicParams->sInParams.MinQPVal = psRCParams->MinQP;
836
837 /* if seinitqp is set, restore the value hosts want */
838 if (InitialSeInitQP) {
839 psPicParams->sInParams.SeInitQP = InitialSeInitQP;
840 psPicParams->sInParams.MyInitQP = InitialSeInitQP;
841 psRCParams->InitialQp = InitialSeInitQP;
842 }
843 }
844
lnc__update_rcdata(context_ENC_p psContext,PIC_PARAMS * psPicParams,IMG_RC_PARAMS * psRCParams)845 void lnc__update_rcdata(context_ENC_p psContext,
846 PIC_PARAMS *psPicParams,
847 IMG_RC_PARAMS *psRCParams)
848 {
849 double L1, L2, L3, L4, L5, flBpp;
850 INT16 i16TempQP;
851 IMG_INT32 i32BufferSizeInFrames;
852
853 flBpp = 1.0 * psRCParams->BitsPerSecond / (psRCParams->FrameRate * psContext->Width * psContext->Height);
854
855 /* recalculate for small frames */
856 if (psContext->Width <= 176)
857 flBpp = flBpp / 2.0;
858
859 psPicParams->sInParams.IntraPeriod = psRCParams->IntraFreq;
860 psPicParams->sInParams.BitRate = psRCParams->BitsPerSecond;
861 psPicParams->sInParams.IntraPeriod = psRCParams->IntraFreq;
862
863 psPicParams->sInParams.BitsPerFrm = psRCParams->BitsPerSecond / psRCParams->FrameRate;
864 psPicParams->sInParams.BitsPerGOP = psPicParams->sInParams.BitsPerFrm * psRCParams->IntraFreq;
865 psPicParams->sInParams.BitsPerBU = psPicParams->sInParams.BitsPerFrm / (4 * psPicParams->sInParams.BUPerFrm);
866 psPicParams->sInParams.BitsPerMB = psPicParams->sInParams.BitsPerBU / psRCParams->BUSize;
867
868 i32BufferSizeInFrames = psRCParams->BufferSize / psPicParams->sInParams.BitsPerFrm;
869
870 // select thresholds and initial Qps etc that are codec dependent
871 switch (psContext->eCodec) {
872 case IMG_CODEC_H264_CBR:
873 case IMG_CODEC_H264_VCM:
874 case IMG_CODEC_H264_VBR:
875 L1 = 0.1;
876 L2 = 0.15;
877 L3 = 0.2;
878 psPicParams->sInParams.MaxQPVal = 51;
879
880 // Set THSkip Values
881 if (flBpp <= 0.07)
882 psPicParams->THSkip = TH_SKIP_24;
883 else if (flBpp <= 0.14)
884 psPicParams->THSkip = TH_SKIP_12;
885 else
886 psPicParams->THSkip = TH_SKIP_0;
887
888 if (flBpp <= 0.3)
889 psPicParams->Flags |= ISRC_I16BIAS;
890
891 // Setup MAX and MIN Quant Values
892 if (flBpp >= 0.50)
893 i16TempQP = 4;
894 else if (flBpp > 0.133)
895 i16TempQP = (unsigned int)(24 - (40 * flBpp));
896 else
897 i16TempQP = (unsigned int)(32 - (100 * flBpp));
898
899 psPicParams->sInParams.MinQPVal = (max(min(psPicParams->sInParams.MaxQPVal, i16TempQP), 0));
900 // Calculate Initial QP if it has not been specified
901
902 L1 = 0.050568;
903 L2 = 0.202272;
904 L3 = 0.40454321;
905 L4 = 0.80908642;
906 L5 = 1.011358025;
907 if (flBpp < L1)
908 i16TempQP = (IMG_INT16)(47 - 78.10 * flBpp);
909
910 else if (flBpp >= L1 && flBpp < L2)
911 i16TempQP = (IMG_INT16)(46 - 72.51 * flBpp);
912
913 else if (flBpp >= L2 && flBpp < L3)
914 i16TempQP = (IMG_INT16)(36 - 24.72 * flBpp);
915
916 else if (flBpp >= L3 && flBpp < L4)
917 i16TempQP = (IMG_INT16)(34 - 19.78 * flBpp);
918
919 else if (flBpp >= L4 && flBpp < L5)
920 i16TempQP = (IMG_INT16)(27 - 9.89 * flBpp);
921
922 else if (flBpp >= L5)
923 i16TempQP = (IMG_INT16)(20 - 4.95 * flBpp);
924
925 psPicParams->sInParams.SeInitQP = (IMG_UINT8)(max(min(psPicParams->sInParams.MaxQPVal, i16TempQP), 0));
926 break;
927
928 case IMG_CODEC_MPEG4_CBR:
929 case IMG_CODEC_MPEG4_VBR:
930 psPicParams->sInParams.MaxQPVal = 31;
931
932 if (psContext->Width == 176) {
933 L1 = 0.1;
934 L2 = 0.3;
935 L3 = 0.6;
936 } else if (psContext->Width == 352) {
937 L1 = 0.2;
938 L2 = 0.6;
939 L3 = 1.2;
940 } else {
941 L1 = 0.25;
942 L2 = 1.4;
943 L3 = 2.4;
944 }
945
946 // Calculate Initial QP if it has not been specified
947 if (flBpp <= L1)
948 psPicParams->sInParams.SeInitQP = 31;
949 else {
950 if (flBpp <= L2)
951 psPicParams->sInParams.SeInitQP = 25;
952 else
953 psPicParams->sInParams.SeInitQP = (flBpp <= L3) ? 20 : 10;
954 }
955
956 if (flBpp >= 0.25) {
957 psPicParams->sInParams.MinQPVal = 1;
958 } else {
959 psPicParams->sInParams.MinQPVal = 2;
960 }
961 break;
962
963 case IMG_CODEC_H263_CBR:
964 case IMG_CODEC_H263_VBR:
965 psPicParams->sInParams.MaxQPVal = 31;
966
967 if (psContext->Width == 176) {
968 L1 = 0.1;
969 L2 = 0.3;
970 L3 = 0.6;
971 } else if (psContext->Width == 352) {
972 L1 = 0.2;
973 L2 = 0.6;
974 L3 = 1.2;
975 } else {
976 L1 = 0.25;
977 L2 = 1.4;
978 L3 = 2.4;
979 }
980
981 // Calculate Initial QP if it has not been specified
982 if (flBpp <= L1)
983 psPicParams->sInParams.SeInitQP = 31;
984 else {
985 if (flBpp <= L2)
986 psPicParams->sInParams.SeInitQP = 25;
987 else
988 psPicParams->sInParams.SeInitQP = (flBpp <= L3) ? 20 : 10;
989 }
990
991 psPicParams->sInParams.MinQPVal = 3;
992
993 break;
994
995 default:
996 /* the NO RC cases will fall here */
997 break;
998 }
999
1000 // Set up Input Parameters that are mode dependent
1001 switch (psContext->eCodec) {
1002 case IMG_CODEC_H264_NO_RC:
1003 case IMG_CODEC_H263_NO_RC:
1004 case IMG_CODEC_MPEG4_NO_RC:
1005 return;
1006
1007 case IMG_CODEC_H264_VCM:
1008 psPicParams->Flags |= ISVCM_FLAGS | ISCBR_FLAGS;
1009 /* drop through to CBR case */
1010 /* for SD and above we can target 95% (122/128) of maximum bitrate */
1011 if (psRCParams->VCMBitrateMargin) {
1012 psPicParams->sInParams.VCMBitrateMargin = psRCParams->VCMBitrateMargin;
1013 } else {
1014 if (psContext->Height >= 480)
1015 psPicParams->sInParams.VCMBitrateMargin = 122;
1016 else
1017 psPicParams->sInParams.VCMBitrateMargin = 115; /* for less and SD we target 90% (115/128) of maximum bitrate */
1018 if (i32BufferSizeInFrames < 15)
1019 psPicParams->sInParams.VCMBitrateMargin -= 5;/* when we have a very small window size we reduce the target further to avoid too much skipping */
1020 }
1021 psPicParams->sInParams.ForceSkipMargin = 500;/* start skipping MBs when within 500 bits of slice or frame limit */
1022
1023 // Set a scale factor to avoid overflows in maths
1024 if (psRCParams->BitsPerSecond < 1000000) { // 1 Mbits/s
1025 psPicParams->sInParams.ScaleFactor = 0;
1026 } else if (psRCParams->BitsPerSecond < 2000000) { // 2 Mbits/s
1027 psPicParams->sInParams.ScaleFactor = 1;
1028 } else if (psRCParams->BitsPerSecond < 4000000) { // 4 Mbits/s
1029 psPicParams->sInParams.ScaleFactor = 2;
1030 } else if (psRCParams->BitsPerSecond < 8000000) { // 8 Mbits/s
1031 psPicParams->sInParams.ScaleFactor = 3;
1032 } else {
1033 psPicParams->sInParams.ScaleFactor = 4;
1034 }
1035
1036 psPicParams->sInParams.BufferSize = i32BufferSizeInFrames;
1037 break;
1038
1039 case IMG_CODEC_H264_CBR:
1040 psPicParams->Flags |= ISCBR_FLAGS;
1041 // ------------------- H264 CBR RC ------------------- //
1042 // Initialize the parameters of fluid flow traffic model.
1043 psPicParams->sInParams.BufferSize = psRCParams->BufferSize;
1044
1045 // HRD consideration - These values are used by H.264 reference code.
1046 if (psRCParams->BitsPerSecond < 1000000) { // 1 Mbits/s
1047 psPicParams->sInParams.ScaleFactor = 0;
1048 } else if (psRCParams->BitsPerSecond < 2000000) { // 2 Mbits/s
1049 psPicParams->sInParams.ScaleFactor = 1;
1050 } else if (psRCParams->BitsPerSecond < 4000000) { // 4 Mbits/s
1051 psPicParams->sInParams.ScaleFactor = 2;
1052 } else if (psRCParams->BitsPerSecond < 8000000) { // 8 Mbits/s
1053 psPicParams->sInParams.ScaleFactor = 3;
1054 } else {
1055 psPicParams->sInParams.ScaleFactor = 4;
1056 }
1057 break;
1058
1059 case IMG_CODEC_MPEG4_CBR:
1060 case IMG_CODEC_H263_CBR:
1061 psPicParams->Flags |= ISCBR_FLAGS;
1062
1063 flBpp = 256 * (psRCParams->BitsPerSecond / psContext->Width);
1064 flBpp /= (psContext->Height * psRCParams->FrameRate);
1065
1066 if ((psPicParams->sInParams.MBPerFrm > 1024 && flBpp < 16) || (psPicParams->sInParams.MBPerFrm <= 1024 && flBpp < 24))
1067 psPicParams->sInParams.HalfFrameRate = 1;
1068 else
1069 psPicParams->sInParams.HalfFrameRate = 0;
1070
1071 if (psPicParams->sInParams.HalfFrameRate >= 1) {
1072 psPicParams->sInParams.SeInitQP = 31;
1073 psPicParams->sInParams.AvQPVal = 31;
1074 psPicParams->sInParams.MyInitQP = 31;
1075 }
1076
1077 if (psRCParams->BitsPerSecond <= 384000)
1078 psPicParams->sInParams.BufferSize = ((psRCParams->BitsPerSecond * 5) >> 1);
1079 else
1080 psPicParams->sInParams.BufferSize = psRCParams->BitsPerSecond * 4;
1081 break;
1082
1083 case IMG_CODEC_MPEG4_VBR:
1084 case IMG_CODEC_H263_VBR:
1085 case IMG_CODEC_H264_VBR:
1086 psPicParams->Flags |= ISVBR_FLAGS;
1087
1088 psPicParams->sInParams.MBPerBU = psPicParams->sInParams.MBPerFrm;
1089 psPicParams->sInParams.BUPerFrm = 1;
1090
1091 // Initialize the parameters of fluid flow traffic model.
1092 psPicParams->sInParams.BufferSize = ((5 * psRCParams->BitsPerSecond) >> 1);
1093
1094 // These scale factor are used only for rate control to avoid overflow
1095 // in fixed-point calculation these scale factors are decided by bit rate
1096 if (psRCParams->BitsPerSecond < 640000) {
1097 psPicParams->sInParams.ScaleFactor = 2; // related to complexity
1098 } else if (psRCParams->BitsPerSecond < 2000000) {
1099 psPicParams->sInParams.ScaleFactor = 4;
1100 } else {
1101 psPicParams->sInParams.ScaleFactor = 6;
1102 }
1103 break;
1104 default:
1105 break;
1106 }
1107
1108 psPicParams->sInParams.MyInitQP = psPicParams->sInParams.SeInitQP;
1109 psPicParams->sInParams.InitialDelay = psRCParams->InitialDelay;
1110 psPicParams->sInParams.InitialLevel = psRCParams->InitialLevel;
1111 psRCParams->InitialQp = psPicParams->sInParams.SeInitQP;
1112 }
1113
1114
1115
lnc__setup_qpvalue_h264(MTX_CURRENT_IN_PARAMS * psCurrent,IMG_BYTE bySliceQP)1116 static void lnc__setup_qpvalue_h264(
1117 MTX_CURRENT_IN_PARAMS * psCurrent,
1118 IMG_BYTE bySliceQP)
1119 {
1120 /* H.264 QP scaling tables */
1121 IMG_BYTE HOST_PVR_QP_SCALE_CR[52] = {
1122 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
1123 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
1124 28, 29, 29, 30, 31, 32, 32, 33, 34, 34, 35, 35, 36, 36, 37, 37,
1125 37, 38, 38, 38, 39, 39, 39, 39
1126 };
1127
1128 psCurrent->bySliceQP = bySliceQP;
1129 psCurrent->bySliceQPC = HOST_PVR_QP_SCALE_CR[psCurrent->bySliceQP];
1130 }
1131
1132
lnc__setup_qpvalues_mpeg4(MTX_CURRENT_IN_PARAMS * psCurrent,IMG_BYTE bySliceQP)1133 static void lnc__setup_qpvalues_mpeg4(
1134 MTX_CURRENT_IN_PARAMS * psCurrent,
1135 IMG_BYTE bySliceQP)
1136 {
1137 psCurrent->bySliceQP = bySliceQP;
1138 }
1139
1140
lnc__setup_slice_row_params(context_ENC_p ctx,IMG_BOOL IsIntra,IMG_UINT16 CurrentRowY,IMG_INT16 SliceStartRowY,IMG_INT16 SliceHeight,IMG_BOOL VectorsValid,int bySliceQP)1141 static void lnc__setup_slice_row_params(
1142 context_ENC_p ctx,
1143 IMG_BOOL IsIntra,
1144 IMG_UINT16 CurrentRowY,
1145 IMG_INT16 SliceStartRowY,
1146 IMG_INT16 SliceHeight,
1147 IMG_BOOL VectorsValid,
1148 int bySliceQP)
1149 {
1150 /* Note: CurrentRowY and SliceStartRowY are now in pixels (not MacroBlocks)
1151 * - saves needless multiplications and divisions
1152 */
1153 IMG_INT16 Pos, YPos, srcY;
1154 MTX_CURRENT_IN_PARAMS *psCurrent;
1155 lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
1156 IMG_UINT16 tmp;
1157
1158 if (IsIntra && cmdbuf->topaz_in_params_I_p == NULL) {
1159 VAStatus vaStatus = psb_buffer_map(cmdbuf->topaz_in_params_I, &cmdbuf->topaz_in_params_I_p);
1160 if (vaStatus != VA_STATUS_SUCCESS) {
1161 drv_debug_msg(VIDEO_DEBUG_ERROR, "map topaz MTX_CURRENT_IN_PARAMS failed\n");
1162 return;
1163 }
1164 }
1165
1166 if ((!IsIntra) && cmdbuf->topaz_in_params_P_p == NULL) {
1167 VAStatus vaStatus = psb_buffer_map(cmdbuf->topaz_in_params_P, &cmdbuf->topaz_in_params_P_p);
1168 if (vaStatus != VA_STATUS_SUCCESS) {
1169 drv_debug_msg(VIDEO_DEBUG_ERROR, "map topaz MTX_CURRENT_IN_PARAMS failed\n");
1170 return;
1171 }
1172 }
1173 if (IsIntra)
1174 psCurrent = (MTX_CURRENT_IN_PARAMS*)(cmdbuf->topaz_in_params_I_p + ctx->in_params_ofs);
1175 else
1176 psCurrent = (MTX_CURRENT_IN_PARAMS*)(cmdbuf->topaz_in_params_P_p + ctx->in_params_ofs);
1177
1178 psCurrent += (CurrentRowY * (ctx->Width) / 256);
1179
1180 if ((YPos = srcY = CurrentRowY - MVEA_LRB_TOP_OFFSET) < 0)
1181 srcY = 0;
1182 else if (YPos > ctx->HeightMinusLRB_TopAndBottom_OffsetsPlus16)
1183 srcY = ctx->HeightMinusLRBSearchHeight;
1184
1185 tmp = (CurrentRowY != SliceStartRowY);
1186
1187 for (Pos = 0; Pos < (int)ctx->Width; Pos += 16, psCurrent++) {
1188 memset(psCurrent, 0, sizeof(MTX_CURRENT_IN_PARAMS));
1189 psCurrent->MVValid = 0;
1190 psCurrent->ParamsValid = 0;
1191
1192 /* Setup the parameters and motion vectors */
1193 if (tmp) {
1194 psCurrent->MVValid = 66;
1195 psCurrent->ParamsValid |= PARAMS_ABOVE_VALID;
1196
1197 if (Pos + 16 < (int)ctx->Width) {
1198 psCurrent->ParamsValid |= PARAMS_ABOVER_VALID;
1199 psCurrent->MVValid |= 4; /* (1<<2) */
1200 }
1201
1202 if (Pos > 0 && (Pos < (int)ctx->Width)) {
1203 psCurrent->ParamsValid |= PARAMS_ABOVEL_VALID;
1204 psCurrent->MVValid |= 1; /* (1<<0) */
1205 }
1206 }
1207 if ((Pos == 0) && (CurrentRowY == SliceStartRowY)) {
1208 psCurrent->ParamsValid |= MB_START_OF_SLICE;/* OPTI? */
1209 }
1210 /* Have to fill in the right hand row of 4x4 vectors into the the left block */
1211 if (Pos) {
1212 psCurrent->MVValid |= 72; /* (1<<3)+(1<<6) */
1213 psCurrent->ParamsValid |= 8; /* (1<<3) */
1214 }
1215 if (Pos == (int)(ctx->Width - 16)) {
1216 /* indicate the last MB in a row */
1217 psCurrent->ParamsValid |= MB_END_OF_ROW;
1218 /* are we the last mb in the slice? */
1219 if (YPos == (SliceStartRowY + SliceHeight - (MVEA_LRB_TOP_OFFSET + 16))) {
1220 psCurrent->ParamsValid |= MB_END_OF_SLICE;
1221 if (YPos == ctx->HeightMinus16MinusLRBTopOffset) {
1222 psCurrent->ParamsValid |= MB_END_OF_PICTURE;
1223 }
1224 }
1225 }
1226 /* And now the below block
1227 * should do some kind of check to see if we are the first inter block,
1228 * as otherwise the vectors will be invalid!
1229 */
1230 if (VectorsValid) {
1231 if (YPos < ctx->HeightMinus16MinusLRBTopOffset) {
1232 psCurrent->MVValid |= 16; /* (1<<4) */
1233
1234 if (YPos < ctx->HeightMinus32MinusLRBTopOffset) {
1235 psCurrent->MVValid |= 32; /* (1<<5) */
1236 }
1237 }
1238 }
1239
1240 /* Set up IPEMin and Max for coordinate X in the search reference region */
1241 /* And set up flags in SPEMax when needed */
1242 if (Pos <= 48) {
1243 psCurrent->IPEMin[0] = 48 - Pos;
1244 psCurrent->RealEdge |= SPE_EDGE_LEFT;
1245 } else {
1246 psCurrent->IPEMin[0] = 3;
1247 }
1248
1249 if ((Pos + 48 + 16) > (int)ctx->Width) {
1250 psCurrent->IPEMax[0] = (47 + ctx->Width) - Pos; /* (112 - 1) - ((Pos + 48+16) - ctx->Width); */
1251 psCurrent->RealEdge |= SPE_EDGE_RIGHT;
1252 } else {
1253 psCurrent->IPEMax[0] = 108; /* (112 - 1) - 3; */
1254 }
1255
1256 /* Set up IPEMin and Max for Y coordinate in the search reference region */
1257 /* And set up flags in SPEMax when needed */
1258 if (YPos <= 0) {
1259 psCurrent->IPEMin[1] = 0;
1260 psCurrent->RealEdge |= SPE_EDGE_TOP;
1261 } else {
1262 psCurrent->IPEMin[1] = 3;
1263 }
1264
1265 /* Max Y */
1266 if (YPos > ctx->HeightMinusLRB_TopAndBottom_OffsetsPlus16) {
1267 psCurrent->IPEMax[1] = MVEA_LRB_SEARCH_HEIGHT - 1;
1268 psCurrent->RealEdge |= SPE_EDGE_BOTTOM;
1269 } else {
1270 psCurrent->IPEMax[1] = MVEA_LRB_SEARCH_HEIGHT - 4;
1271 }
1272
1273 psCurrent->CurBlockAddr = ((IMG_UINT8)(((YPos + MVEA_LRB_TOP_OFFSET) - srcY) / 16) << 4) | 0x3;
1274
1275 /* Setup the control register values These will get setup and transferred to a different location within
1276 * the macroblock parameter structure. They are then read out of the esb by the mtx and used to control
1277 * the hardware units
1278 */
1279 psCurrent->IPEControl = ctx->IPEControl;
1280
1281 switch (ctx->eCodec) {
1282 case IMG_CODEC_H263_NO_RC:
1283 case IMG_CODEC_H263_VBR:
1284 case IMG_CODEC_H263_CBR:
1285 lnc__setup_qpvalues_mpeg4(psCurrent, bySliceQP);
1286 psCurrent->JMCompControl = F_ENCODE(2, MVEA_CR_JMCOMP_MODE);
1287 psCurrent->VLCControl = F_ENCODE(3, TOPAZ_VLC_CR_CODEC) |
1288 F_ENCODE(IsIntra ? 0 : 1, TOPAZ_VLC_CR_SLICE_CODING_TYPE);
1289 break;
1290 case IMG_CODEC_MPEG4_NO_RC:
1291 case IMG_CODEC_MPEG4_VBR:
1292 case IMG_CODEC_MPEG4_CBR:
1293 lnc__setup_qpvalues_mpeg4(psCurrent, bySliceQP);
1294 psCurrent->JMCompControl = F_ENCODE(1, MVEA_CR_JMCOMP_MODE) |
1295 F_ENCODE(1, MVEA_CR_JMCOMP_AC_ENABLE);
1296 psCurrent->VLCControl = F_ENCODE(2, TOPAZ_VLC_CR_CODEC) |
1297 F_ENCODE(IsIntra ? 0 : 1, TOPAZ_VLC_CR_SLICE_CODING_TYPE);
1298 break;
1299 default:
1300 case IMG_CODEC_H264_NO_RC:
1301 case IMG_CODEC_H264_VBR:
1302 case IMG_CODEC_H264_CBR:
1303 case IMG_CODEC_H264_VCM:
1304 lnc__setup_qpvalue_h264(psCurrent, bySliceQP);
1305 psCurrent->JMCompControl = F_ENCODE(0, MVEA_CR_JMCOMP_MODE);
1306 psCurrent->VLCControl = F_ENCODE(1, TOPAZ_VLC_CR_CODEC) |
1307 F_ENCODE(IsIntra ? 0 : 1, TOPAZ_VLC_CR_SLICE_CODING_TYPE);
1308 break;
1309 }
1310 }
1311
1312 psCurrent->RealEdge = 0;
1313
1314 }
1315
lnc_setup_slice_params(context_ENC_p ctx,IMG_UINT16 YSliceStartPos,IMG_UINT16 SliceHeight,IMG_BOOL IsIntra,IMG_BOOL VectorsValid,int bySliceQP)1316 void lnc_setup_slice_params(
1317 context_ENC_p ctx,
1318 IMG_UINT16 YSliceStartPos,
1319 IMG_UINT16 SliceHeight,
1320 IMG_BOOL IsIntra,
1321 IMG_BOOL VectorsValid,
1322 int bySliceQP)
1323 {
1324 IMG_UINT16 Rows, CurrentRowY;
1325
1326 Rows = SliceHeight / 16;
1327 CurrentRowY = YSliceStartPos;
1328
1329 while (Rows) {
1330 lnc__setup_slice_row_params(
1331 ctx,
1332 IsIntra,
1333 CurrentRowY,
1334 YSliceStartPos,
1335 SliceHeight,
1336 VectorsValid, bySliceQP);
1337
1338 CurrentRowY += 16;
1339 Rows--;
1340 }
1341
1342 }
1343
1344
1345
lnc__send_encode_slice_params(context_ENC_p ctx,IMG_BOOL IsIntra,IMG_UINT16 CurrentRow,IMG_BOOL DeblockSlice,IMG_UINT32 FrameNum,IMG_UINT16 SliceHeight,IMG_UINT16 CurrentSlice,IMG_UINT32 MaxSliceSize)1346 IMG_UINT32 lnc__send_encode_slice_params(
1347 context_ENC_p ctx,
1348 IMG_BOOL IsIntra,
1349 IMG_UINT16 CurrentRow,
1350 IMG_BOOL DeblockSlice,
1351 IMG_UINT32 FrameNum,
1352 IMG_UINT16 SliceHeight,
1353 IMG_UINT16 CurrentSlice,
1354 IMG_UINT32 MaxSliceSize)
1355 {
1356 SLICE_PARAMS *psSliceParams;
1357 IMG_UINT16 RowOffset;
1358
1359 psb_buffer_p psCoded;
1360 object_surface_p ref_surface;
1361 psb_buffer_p psRef;
1362 lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
1363
1364
1365 ref_surface = ctx->ref_surface;
1366 psRef = &ctx->ref_surface->psb_surface->buf;
1367 psCoded = ctx->coded_buf->psb_buffer;
1368
1369 psSliceParams = (SLICE_PARAMS *)(cmdbuf->slice_params_p +
1370 CurrentSlice * ((sizeof(SLICE_PARAMS) + 15) & 0xfff0));
1371
1372 psSliceParams->SliceHeight = SliceHeight;
1373 psSliceParams->SliceStartRowNum = CurrentRow / 16;
1374
1375 /* We want multiple ones of these so we can submit multiple slices without having to wait for the next */
1376 psSliceParams->CodedDataPos = 0;
1377 psSliceParams->TotalCoded = 0;
1378 psSliceParams->Flags = 0;
1379
1380 #ifdef VA_EMULATOR
1381 psSliceParams->RefYStride = ref_surface->psb_surface->stride;
1382 psSliceParams->RefUVStride = ref_surface->psb_surface->stride;
1383 psSliceParams->RefYRowStride = ref_surface->psb_surface->stride * 16;
1384 psSliceParams->RefUVRowStride = ref_surface->psb_surface->stride * 16 / 2;
1385 #else
1386 psSliceParams->RefYStride = ref_surface->height * 16;
1387 psSliceParams->RefUVStride = ref_surface->height * 8;
1388 psSliceParams->RefYRowStride = psSliceParams->RefYStride;
1389 psSliceParams->RefUVRowStride = psSliceParams->RefUVStride;
1390 #endif
1391
1392 psSliceParams->FCode = ctx->FCode;/* Not clear yet, This field is not appare in firmware doc */
1393 RowOffset = CurrentRow - 32;
1394 if (RowOffset <= 0)
1395 RowOffset = 0;
1396 if (RowOffset > (ctx->Height - 80))
1397 RowOffset = (ctx->Height - 80);
1398
1399 psSliceParams->MaxSliceSize = MaxSliceSize;
1400 psSliceParams->NumAirMBs = ctx->num_air_mbs;
1401 /* DDKv145: 3 lsb of threshold used as spacing between AIR MBs */
1402 psSliceParams->AirThreshold = ctx->air_threshold + (FrameNum & 3) + 2;
1403
1404 if (ctx->autotune_air_flag)
1405 psSliceParams->Flags |= AUTOTUNE_AIR;
1406
1407 if (!IsIntra) {
1408 psSliceParams->Flags |= ISINTER_FLAGS;
1409 }
1410 if (DeblockSlice) {
1411 psSliceParams->Flags |= DEBLOCK_FRAME;
1412 }
1413 switch (ctx->eCodec) {
1414 case IMG_CODEC_H263_NO_RC:
1415 case IMG_CODEC_H263_VBR:
1416 case IMG_CODEC_H263_CBR:
1417 psSliceParams->Flags |= ISH263_FLAGS;
1418 break;
1419 case IMG_CODEC_MPEG4_NO_RC:
1420 case IMG_CODEC_MPEG4_VBR:
1421 case IMG_CODEC_MPEG4_CBR:
1422 psSliceParams->Flags |= ISMPEG4_FLAGS;
1423 break;
1424 case IMG_CODEC_H264_NO_RC:
1425 case IMG_CODEC_H264_VBR:
1426 case IMG_CODEC_H264_CBR:
1427 case IMG_CODEC_H264_VCM:
1428 psSliceParams->Flags |= ISH264_FLAGS;
1429 break;
1430 default:
1431 psSliceParams->Flags |= ISH264_FLAGS;
1432 drv_debug_msg(VIDEO_DEBUG_ERROR, "No format specified defaulting to h.264\n");
1433 break;
1434 }
1435 /* we should also setup the interleaving requirements based on the source format */
1436 if (ctx->eFormat != IMG_CODEC_PL12)
1437 psSliceParams->Flags |= INTERLEAVE_TARGET;
1438
1439 cmdbuf = ctx->obj_context->lnc_cmdbuf;
1440
1441 RELOC_SLICE_PARAMS(&(psSliceParams->RefYBase), 16 * RowOffset, psRef);
1442 RELOC_SLICE_PARAMS(&(psSliceParams->RefUVBase),
1443 ref_surface->psb_surface->stride * ref_surface->height + (RowOffset * 16 / 2),
1444 psRef);
1445 RELOC_SLICE_PARAMS(&(psSliceParams->CodedData), 0, psCoded);
1446
1447 lnc_cmdbuf_insert_command(cmdbuf, MTX_CMDID_ENCODE_SLICE, 2, (CurrentSlice << 2) | (IsIntra & 0x3));
1448 RELOC_CMDBUF(cmdbuf->cmd_idx++,
1449 CurrentSlice *((sizeof(SLICE_PARAMS) + 15) & 0xfff0),
1450 &cmdbuf->slice_params);
1451
1452 return 0;
1453 }
1454
1455
1456
1457 /*
1458 * Function Name : Reset_EncoderParams
1459 * Description : Reset Above & Below Params at the Start of Intra frame
1460 */
lnc_reset_encoder_params(context_ENC_p ctx)1461 void lnc_reset_encoder_params(context_ENC_p ctx)
1462 {
1463 unsigned char *Add_Below, *Add_Above;
1464 lnc_cmdbuf_p cmdbuf = ctx->obj_context->lnc_cmdbuf;
1465
1466 /* all frames share the same Topaz param, in_param/aboveparam/bellow
1467 * map it only when necessary
1468 */
1469 if (cmdbuf->topaz_above_bellow_params_p == NULL) {
1470 VAStatus vaStatus = psb_buffer_map(cmdbuf->topaz_above_bellow_params, &cmdbuf->topaz_above_bellow_params_p);
1471 if (vaStatus != VA_STATUS_SUCCESS) {
1472 drv_debug_msg(VIDEO_DEBUG_ERROR, "map topaz MTX_CURRENT_IN_PARAMS failed\n");
1473 return;
1474 }
1475 }
1476
1477 Add_Below = cmdbuf->topaz_above_bellow_params_p + ctx->bellow_params_ofs;
1478 memset(Add_Below, 0, ctx->bellow_params_size);
1479
1480 Add_Above = cmdbuf->topaz_above_bellow_params_p + ctx->above_params_ofs;
1481 memset(Add_Above, 0, ctx->above_params_size);
1482 }
1483