tng_MPEG4ES.c revision 35b15a0a6456d1ca2b2c1ccae60e548743175526
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 *    Edward Lin <edward.lin@intel.com>
29 *    Zhaohan Ren <zhaohan.ren@intel.com>
30 *
31 */
32
33
34#include <errno.h>
35#include <stdlib.h>
36#include <unistd.h>
37#include <stdint.h>
38#include <string.h>
39
40#include "psb_def.h"
41#include "psb_surface.h"
42#include "tng_cmdbuf.h"
43#include "tng_hostcode.h"
44#include "tng_hostheader.h"
45#include "tng_MPEG4ES.h"
46#include "psb_drv_debug.h"
47
48#include "hwdefs/coreflags.h"
49#include "hwdefs/topaz_vlc_regs.h"
50#include "hwdefs/topaz_db_regs.h"
51#include "hwdefs/topazhp_default_params.h"
52
53#define TOPAZ_MPEG4_MAX_BITRATE 16000000
54
55#define INIT_CONTEXT_MPEG4ES    context_ENC_p ctx = (context_ENC_p) obj_context->format_data
56#define SURFACE(id)    ((object_surface_p) object_heap_lookup( &ctx->obj_context->driver_data->surface_heap, id ))
57#define BUFFER(id)  ((object_buffer_p) object_heap_lookup( &ctx->obj_context->driver_data->buffer_heap, id ))
58
59static void tng_MPEG4ES_QueryConfigAttributes(
60    VAProfile profile,
61    VAEntrypoint entrypoint,
62    VAConfigAttrib *attrib_list,
63    int num_attribs)
64{
65    int i;
66
67    drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s\n", __FUNCTION__);
68
69    /* RateControl attributes */
70    for (i = 0; i < num_attribs; i++) {
71        switch (attrib_list[i].type) {
72        case VAConfigAttribRTFormat:
73            break;
74
75        case VAConfigAttribEncAutoReference:
76            attrib_list[i].value = 1;
77            break;
78
79        case VAConfigAttribEncMaxRefFrames:
80            attrib_list[i].value = 2;
81            break;
82
83        case VAConfigAttribRateControl:
84            attrib_list[i].value = VA_RC_NONE | VA_RC_CBR | VA_RC_VBR | VA_RC_VCM;
85            break;
86
87        default:
88            attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED;
89            break;
90        }
91    }
92}
93
94
95static VAStatus tng_MPEG4ES_ValidateConfig(
96    object_config_p obj_config)
97{
98    int i;
99    drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s\n", __FUNCTION__);
100    /* Check all attributes */
101    for (i = 0; i < obj_config->attrib_count; i++) {
102        switch (obj_config->attrib_list[i].type) {
103        case VAConfigAttribRTFormat:
104            /* Ignore */
105            break;
106        case VAConfigAttribRateControl:
107            break;
108        case VAConfigAttribEncAutoReference:
109            break;
110        case VAConfigAttribEncMaxRefFrames:
111            break;
112        default:
113            return VA_STATUS_ERROR_ATTR_NOT_SUPPORTED;
114        }
115    }
116
117    return VA_STATUS_SUCCESS;
118}
119
120static VAStatus tng_MPEG4ES_CreateContext(
121    object_context_p obj_context,
122    object_config_p obj_config)
123{
124    VAStatus vaStatus = VA_STATUS_SUCCESS;
125    context_ENC_p ctx;
126    unsigned int eRCMode;
127
128    drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s\n", __FUNCTION__);
129
130    vaStatus = tng_CreateContext(obj_context, obj_config, 0);
131
132    if (VA_STATUS_SUCCESS != vaStatus)
133        return VA_STATUS_ERROR_ALLOCATION_FAILED;
134
135    ctx = (context_ENC_p) obj_context->format_data;
136    ctx->eStandard = IMG_STANDARD_MPEG4;
137    ctx->eFormat = IMG_CODEC_PL12;                          // use default
138
139    switch(ctx->sRCParams.eRCMode) {
140	case IMG_RCMODE_NONE:
141	    ctx->eCodec = IMG_CODEC_MPEG4_NO_RC;
142	    break;
143	case IMG_RCMODE_VBR:
144	    ctx->eCodec = IMG_CODEC_MPEG4_VBR;
145	    break;
146	case IMG_RCMODE_CBR:
147	    ctx->eCodec = IMG_CODEC_MPEG4_CBR;
148	    break;
149	default:
150	    drv_debug_msg(VIDEO_DEBUG_ERROR, "Unknown RCMode %08x\n", ctx->sRCParams.eRCMode);
151	    break;
152    }
153
154    ctx->bIsInterlaced = IMG_FALSE;
155    ctx->bIsInterleaved = IMG_FALSE;
156    ctx->ui16PictureHeight = ctx->ui16FrameHeight;
157
158    ctx->bVPAdaptiveRoundingDisable = IMG_TRUE;
159
160    /* TopazHP only support Simple Profile */
161    switch (obj_config->profile) {
162        case VAProfileMPEG4Simple:
163            ctx->ui8ProfileIdc = SP;
164            break;
165        default:
166            ctx->ui8ProfileIdc = SP;
167        break;
168    }
169
170    //This parameter need not be exposed
171    ctx->ui8InterIntraIndex = 3;
172    ctx->ui8CodedSkippedIndex = 3;
173    ctx->bEnableHostQP = IMG_FALSE;
174    ctx->uMaxChunks = 0xA0;
175    ctx->uChunksPerMb = 0x40;
176    ctx->uPriorityChunks = (0xA0 - 0x60);
177    ctx->ui32FCode = 4;
178    ctx->iFineYSearchSize = 2;
179
180    //This parameter need not be exposed
181    //host to control the encoding process
182    ctx->bEnableInpCtrl = IMG_FALSE;
183    ctx->bEnableHostBias = IMG_FALSE;
184    //By default false Newly Added
185    ctx->bEnableCumulativeBiases = IMG_FALSE;
186
187    //Weighted Prediction is not supported in TopazHP Version 3.0
188    ctx->bWeightedPrediction = IMG_FALSE;
189    ctx->ui8VPWeightedImplicitBiPred = 0;
190    ctx->bInsertHRDParams = 0;
191
192
193    ctx->bArbitrarySO = IMG_FALSE;
194    ctx->ui32BasicUnit = 0;
195
196    return vaStatus;
197}
198
199static void tng_MPEG4ES_DestroyContext(
200    object_context_p obj_context)
201{
202    drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s\n", __FUNCTION__);
203    tng_DestroyContext(obj_context, 0);
204}
205
206static VAStatus tng_MPEG4ES_BeginPicture(
207    object_context_p obj_context)
208{
209    INIT_CONTEXT_MPEG4ES;
210    tng_cmdbuf_p cmdbuf = ctx->obj_context->tng_cmdbuf;
211    context_ENC_mem *ps_mem = &(ctx->ctx_mem[ctx->ui32StreamID]);
212    VAStatus vaStatus = VA_STATUS_SUCCESS;
213    drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s start\n", __FUNCTION__);
214    vaStatus = tng_BeginPicture(ctx);
215
216    drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s end\n", __FUNCTION__);
217    return vaStatus;
218}
219
220static VAStatus tng__MPEG4ES_process_sequence_param(context_ENC_p ctx, object_buffer_p obj_buffer)
221{
222    context_ENC_mem *ps_mem = &(ctx->ctx_mem[ctx->ui32StreamID]);
223    VAEncSequenceParameterBufferMPEG4 *psSeqParams;
224    tng_cmdbuf_p cmdbuf = ctx->obj_context->tng_cmdbuf;
225    IMG_RC_PARAMS *psRCParams = &(ctx->sRCParams);
226
227    ASSERT(obj_buffer->type == VAEncSequenceParameterBufferType);
228    ASSERT(obj_buffer->size == sizeof(VAEncSequenceParameterBufferMPEG4));
229
230    if (obj_buffer->size != sizeof(VAEncSequenceParameterBufferMPEG4)) {
231        return VA_STATUS_ERROR_UNKNOWN;
232    }
233
234    ctx->obj_context->frame_count = 0;
235    psSeqParams = (VAEncSequenceParameterBufferMPEG4 *) obj_buffer->buffer_data;
236    obj_buffer->buffer_data = NULL;
237    obj_buffer->size = 0;
238
239    ctx->ui32IdrPeriod = psSeqParams->intra_period;
240    ctx->ui32IntraCnt = psSeqParams->intra_period;
241
242    if (ctx->ui32IntraCnt == 0) {
243        ctx->ui32IntraCnt = INT_MAX;
244        ctx->ui32IdrPeriod = 1;
245        drv_debug_msg(VIDEO_DEBUG_GENERAL,
246           "%s: only ONE I frame in the sequence, %d\n",
247           __FUNCTION__, ctx->ui32IdrPeriod);
248    }
249
250    ctx->bCustomScaling = IMG_FALSE;
251    ctx->bUseDefaultScalingList = IMG_FALSE;
252
253    //set MV limit infor
254    ctx->ui32VertMVLimit = 255 ;//(63.75 in qpel increments)
255    ctx->bLimitNumVectors = IMG_TRUE;
256
257    ctx->ui8LevelIdc = psSeqParams->profile_and_level_indication;
258
259    /**************set rc params ****************/
260    if (psSeqParams->bits_per_second > TOPAZ_MPEG4_MAX_BITRATE) {
261        ctx->sRCParams.ui32BitsPerSecond = TOPAZ_MPEG4_MAX_BITRATE;
262        drv_debug_msg(VIDEO_DEBUG_GENERAL, " bits_per_second(%d) exceeds \
263		the maximum bitrate, set it with %d\n",
264                                 psSeqParams->bits_per_second,
265                                 TOPAZ_MPEG4_MAX_BITRATE);
266    } else
267        ctx->sRCParams.ui32BitsPerSecond = psSeqParams->bits_per_second;
268
269    //FIXME: Zhaohan, this should be figured out in testsuite?
270    if (!ctx->uiCbrBufferTenths)
271	ctx->uiCbrBufferTenths = TOPAZHP_DEFAULT_uiCbrBufferTenths;
272
273    if (ctx->uiCbrBufferTenths) {
274        psRCParams->ui32BufferSize      = (IMG_UINT32)(psRCParams->ui32BitsPerSecond * ctx->uiCbrBufferTenths / 10.0);
275    } else {
276        if (psRCParams->ui32BitsPerSecond < 256000)
277            psRCParams->ui32BufferSize = ((9 * psRCParams->ui32BitsPerSecond) >> 1);
278        else
279            psRCParams->ui32BufferSize = ((5 * psRCParams->ui32BitsPerSecond) >> 1);
280    }
281
282    psRCParams->i32InitialDelay = (13 * psRCParams->ui32BufferSize) >> 4;
283    psRCParams->i32InitialLevel = (3 * psRCParams->ui32BufferSize) >> 4;
284    psRCParams->ui32IntraFreq = psSeqParams->intra_period;
285
286    psRCParams->ui32InitialQp = psSeqParams->initial_qp;
287    psRCParams->iMinQP = psSeqParams->min_qp;
288    ctx->ui32BasicUnit = psSeqParams->min_qp;
289    //psRCParams->ui32BUSize = psSeqParams->basic_unit_size;
290    //ctx->ui32KickSize = psRCParams->ui32BUSize;
291    psRCParams->ui32FrameRate = psSeqParams->frame_rate;
292
293    //B-frames are not supported for non-H.264 streams
294    ctx->sRCParams.ui16BFrames = 0;
295    ctx->ui8SlotsInUse = psRCParams->ui16BFrames + 2;
296
297#if HEADERS_VERBOSE_OUTPUT
298    drv_debug_msg(VIDEO_DEBUG_GENERAL, "\n\n**********************************************************************\n");
299    drv_debug_msg(VIDEO_DEBUG_GENERAL, "******** HOST FIRMWARE ROUTINES TO PASS HEADERS AND TOKENS TO MTX******\n");
300    drv_debug_msg(VIDEO_DEBUG_GENERAL, "**********************************************************************\n\n");
301#endif
302
303    free(psSeqParams);
304
305    return VA_STATUS_SUCCESS;
306}
307
308static VAStatus tng__MPEG4ES_process_picture_param(context_ENC_p ctx, object_buffer_p obj_buffer)
309{
310    VAStatus vaStatus = VA_STATUS_SUCCESS;
311    context_ENC_mem *ps_mem = &(ctx->ctx_mem[ctx->ui32StreamID]);
312    context_ENC_frame_buf *ps_buf = &(ctx->ctx_frame_buf);
313    VAEncPictureParameterBufferMPEG4 *psPicParams;
314    IMG_BOOL bDepViewPPS = IMG_FALSE;
315    void* pTmpBuf = NULL;
316
317    drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: start\n",__FUNCTION__);
318    ASSERT(obj_buffer->type == VAEncPictureParameterBufferType);
319    if (obj_buffer->size != sizeof(VAEncPictureParameterBufferMPEG4)) {
320        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s L%d Invalid coded buffer handle\n", __FUNCTION__, __LINE__);
321        return VA_STATUS_ERROR_UNKNOWN;
322    }
323
324    /* Transfer ownership of VAEncPictureParameterBufferMPEG4 data */
325    psPicParams = (VAEncPictureParameterBufferMPEG4 *) obj_buffer->buffer_data;
326    obj_buffer->buffer_data = NULL;
327    obj_buffer->size = 0;
328
329    ASSERT(ctx->ui16Width == psPicParams->picture_width);
330    ASSERT(ctx->ui16PictureHeight == psPicParams->picture_height);
331#ifndef _TNG_FRAMES_
332    ps_buf->ref_surface[0] = ps_buf->ref_surface[2] = SURFACE(psPicParams->reference_picture);
333    ps_buf->ref_surface[1] = ps_buf->ref_surface[3] = SURFACE(psPicParams->reconstructed_picture);
334#else
335    ps_buf->ref_surface = SURFACE(psPicParams->reference_picture);
336    ps_buf->rec_surface = SURFACE(psPicParams->reconstructed_picture);
337#endif
338    ps_buf->coded_buf = BUFFER(psPicParams->coded_buf);
339
340    if (NULL == ps_buf->coded_buf) {
341        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s L%d Invalid coded buffer handle\n", __FUNCTION__, __LINE__);
342        free(psPicParams);
343        return VA_STATUS_ERROR_INVALID_BUFFER;
344    }
345
346    free(psPicParams);
347    drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: end\n",__FUNCTION__);
348
349    return vaStatus;
350}
351
352static VAStatus tng__MPEG4ES_process_slice_param(context_ENC_p ctx, object_buffer_p obj_buffer)
353{
354    VAStatus vaStatus = VA_STATUS_SUCCESS;
355    VAEncSliceParameterBuffer *psSliceParams;
356
357    ASSERT(obj_buffer->type == VAEncSliceParameterBufferType);
358    /* Prepare InParams for macros of current slice, insert slice header, insert do slice command */
359
360    /* Transfer ownership of VAEncPictureParameterBufferMPEG4 data */
361    psSliceParams = (VAEncSliceParameterBuffer*) obj_buffer->buffer_data;
362    obj_buffer->size = 0;
363
364    //deblocking behaviour
365    ctx->bArbitrarySO = IMG_FALSE;
366    ctx->ui8DeblockIDC = psSliceParams->slice_flags.bits.disable_deblocking_filter_idc;
367    ++ctx->ui8SlicesPerPicture;
368    return vaStatus;
369}
370
371static VAStatus tng__MPEG4ES_process_misc_param(context_ENC_p ctx, object_buffer_p obj_buffer)
372{
373    VAStatus vaStatus = VA_STATUS_SUCCESS;
374    VAEncMiscParameterBuffer *pBuffer;
375    VAEncMiscParameterFrameRate *frame_rate_param;
376    VAEncMiscParameterRateControl *rate_control_param;
377    IMG_RC_PARAMS   *psRCParams = &(ctx->sRCParams);
378
379    ASSERT(obj_buffer->type == VAEncMiscParameterBufferType);
380
381    /* Transfer ownership of VAEncMiscParameterBuffer data */
382    pBuffer = (VAEncMiscParameterBuffer *) obj_buffer->buffer_data;
383    obj_buffer->size = 0;
384
385    switch (pBuffer->type) {
386    case VAEncMiscParameterTypeFrameRate:
387        frame_rate_param = (VAEncMiscParameterFrameRate *)pBuffer->data;
388        psRCParams->ui32FrameRate = frame_rate_param->framerate;
389        if (psRCParams->ui32FrameRate == 0)
390            psRCParams->ui32FrameRate = 30;
391    case VAEncMiscParameterTypeRateControl:
392        rate_control_param = (VAEncMiscParameterRateControl *)pBuffer->data;
393
394        if (rate_control_param->initial_qp > 51 || rate_control_param->min_qp > 51) {
395            drv_debug_msg(VIDEO_DEBUG_ERROR, "Initial_qp(%d) and min_qpinitial_qp(%d) "
396                               "are invalid.\nQP shouldn't be larger than 51 for MPEG4\n",
397                               rate_control_param->initial_qp, rate_control_param->min_qp);
398            vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
399            break;
400        }
401
402        drv_debug_msg(VIDEO_DEBUG_GENERAL, "rate control changed from %d to %d\n",
403                                 psRCParams->ui32BitsPerSecond,
404                                 rate_control_param->bits_per_second);
405
406        if ((rate_control_param->bits_per_second == psRCParams->ui32BitsPerSecond) &&
407            (psRCParams->ui32BufferSize == psRCParams->ui32BitsPerSecond / 1000 * rate_control_param->window_size) &&
408            (psRCParams->iMinQP == rate_control_param->min_qp) &&
409            (psRCParams->ui32InitialQp == rate_control_param->initial_qp))
410            break;
411
412        if (rate_control_param->bits_per_second > TOPAZ_MPEG4_MAX_BITRATE) {
413            psRCParams->ui32BitsPerSecond = TOPAZ_MPEG4_MAX_BITRATE;
414            drv_debug_msg(VIDEO_DEBUG_GENERAL, " bits_per_second(%d) exceeds \
415				the maximum bitrate, set it with %d\n",
416                                     rate_control_param->bits_per_second,
417                                     TOPAZ_MPEG4_MAX_BITRATE);
418        } else
419            psRCParams->ui32BitsPerSecond = rate_control_param->bits_per_second;
420
421        if (rate_control_param->window_size != 0)
422            psRCParams->ui32BufferSize = psRCParams->ui32BitsPerSecond * rate_control_param->window_size / 1000;
423        if (rate_control_param->initial_qp != 0)
424            psRCParams->ui32InitialQp = rate_control_param->initial_qp;
425        if (rate_control_param->min_qp != 0)
426            psRCParams->iMinQP = rate_control_param->min_qp;
427        break;
428    default:
429        break;
430    }
431
432    return vaStatus;
433}
434
435static VAStatus tng_MPEG4ES_RenderPicture(
436    object_context_p obj_context,
437    object_buffer_p *buffers,
438    int num_buffers)
439{
440    INIT_CONTEXT_MPEG4ES;
441    VAStatus vaStatus = VA_STATUS_SUCCESS;
442    int i;
443
444    drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: start\n", __FUNCTION__);
445    for (i = 0; i < num_buffers; i++) {
446        object_buffer_p obj_buffer = buffers[i];
447        drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: type = %d, num = %d\n", __FUNCTION__, obj_buffer->type, num_buffers);
448
449        switch (obj_buffer->type) {
450        case VAEncSequenceParameterBufferType:
451            drv_debug_msg(VIDEO_DEBUG_GENERAL, "tng_MPEG4_RenderPicture got VAEncSequenceParameterBufferType\n");
452            vaStatus = tng__MPEG4ES_process_sequence_param(ctx, obj_buffer);
453            DEBUG_FAILURE;
454            break;
455        case VAEncPictureParameterBufferType:
456            drv_debug_msg(VIDEO_DEBUG_GENERAL, "tng_MPEG4_RenderPicture got VAEncPictureParameterBuffer\n");
457            vaStatus = tng__MPEG4ES_process_picture_param(ctx, obj_buffer);
458            DEBUG_FAILURE;
459            break;
460
461        case VAEncSliceParameterBufferType:
462            drv_debug_msg(VIDEO_DEBUG_GENERAL, "tng_MPEG4_RenderPicture got VAEncSliceParameterBufferType\n");
463            vaStatus = tng__MPEG4ES_process_slice_param(ctx, obj_buffer);
464            DEBUG_FAILURE;
465            break;
466
467        case VAEncMiscParameterBufferType:
468            drv_debug_msg(VIDEO_DEBUG_GENERAL, "tng_MPEG4_RenderPicture got VAEncMiscParameterBufferType\n");
469            vaStatus = tng__MPEG4ES_process_misc_param(ctx, obj_buffer);
470            DEBUG_FAILURE;
471            break;
472        default:
473            vaStatus = VA_STATUS_ERROR_UNKNOWN;
474            DEBUG_FAILURE;
475        }
476        if (vaStatus != VA_STATUS_SUCCESS) {
477            break;
478        }
479    }
480    drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: end\n", __FUNCTION__);
481
482    return vaStatus;
483}
484
485static VAStatus tng_MPEG4ES_EndPicture(
486    object_context_p obj_context)
487{
488    INIT_CONTEXT_MPEG4ES;
489    VAStatus vaStatus = VA_STATUS_SUCCESS;
490    drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s start\n", __FUNCTION__);
491    vaStatus = tng_EndPicture(ctx);
492    drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s end\n", __FUNCTION__);
493
494    return vaStatus;
495}
496
497struct format_vtable_s tng_MPEG4ES_vtable = {
498queryConfigAttributes:
499    tng_MPEG4ES_QueryConfigAttributes,
500validateConfig:
501    tng_MPEG4ES_ValidateConfig,
502createContext:
503    tng_MPEG4ES_CreateContext,
504destroyContext:
505    tng_MPEG4ES_DestroyContext,
506beginPicture:
507    tng_MPEG4ES_BeginPicture,
508renderPicture:
509    tng_MPEG4ES_RenderPicture,
510endPicture:
511    tng_MPEG4ES_EndPicture
512};
513
514/*EOF*/
515