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 *
28 */
29
30
31#include <stdlib.h>
32#include <stdint.h>
33#include <string.h>
34
35#include "psb_def.h"
36#include "psb_drv_debug.h"
37#include "psb_surface.h"
38#include "psb_cmdbuf.h"
39#include "pnw_jpeg.h"
40#include "pnw_hostcode.h"
41#include "pnw_hostheader.h"
42#include "pnw_hostjpeg.h"
43
44#define INIT_CONTEXT_JPEG       context_ENC_p ctx = (context_ENC_p) obj_context->format_data
45#define SURFACE(id)    ((object_surface_p) object_heap_lookup( &ctx->obj_context->driver_data->surface_heap, id ))
46#define BUFFER(id)  ((object_buffer_p) object_heap_lookup( &ctx->obj_context->driver_data->buffer_heap, id ))
47
48/*
49  Balancing the workloads of executing MTX_CMDID_ISSUEBUFF commands to 2-cores:
50  1 commands: 0 (0b/0x0)
51  2 commands: 1-0 (01b/0x1)
52  3 commands: 1-0-0 (001b/0x1)
53  4 commands: 1-0-1-0 (0101b/0x5)
54  5 commands: 1-0-1-0-0 (00101b/0x5)
55  6 commands: 1-0-1-0-1-0 (010101b/0x15)
56  7 commands: 1-0-1-0-1-0-0 (0010101b/0x15)
57*/
58static const uint32_t aui32_jpg_mtx_num[PNW_JPEG_MAX_SCAN_NUM] = {0x0, 0x1, 0x1, 0x5, 0x5, 0x15, 0x15};
59
60static void pnw_jpeg_QueryConfigAttributes(
61    VAProfile __maybe_unused profile,
62    VAEntrypoint __maybe_unused entrypoint,
63    VAConfigAttrib *attrib_list,
64    int num_attribs)
65{
66    int i;
67
68    drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_jpeg_QueryConfigAttributes\n");
69
70    /* RateControl attributes */
71    for (i = 0; i < num_attribs; i++) {
72        switch (attrib_list[i].type) {
73        case VAConfigAttribRTFormat:
74            /* Already handled in psb_GetConfigAttributes */
75            break;
76        case VAConfigAttribEncJPEG:
77            /* The below JPEG ENC capabilities are fixed by TopazSC and not changable. */
78            {
79                VAConfigAttribValEncJPEG* ptr = (VAConfigAttribValEncJPEG *)&(attrib_list[i].value);
80                (ptr->bits).arithmatic_coding_mode = 0; /* Unsupported */
81                (ptr->bits).progressive_dct_mode = 0; /* Unsupported */
82                (ptr->bits).non_interleaved_mode = 1; /* Supported */
83                (ptr->bits).differential_mode = 0; /* Unsupported */
84                (ptr->bits).max_num_components = PNW_JPEG_COMPONENTS_NUM; /* Only 3 is supported */
85                (ptr->bits).max_num_scans = PNW_JPEG_MAX_SCAN_NUM;
86                (ptr->bits).max_num_huffman_tables = 4; /* Only 4 is supported */
87                (ptr->bits).max_num_huffman_tables = 2; /* Only 2 is supported */
88            }
89            break;
90        case VAConfigAttribMaxPictureWidth:
91        case VAConfigAttribMaxPictureHeight:
92            /* No pure limitation on an image's width or height seperately,
93               as long as the image's MCUs need less than max_num_scans rounds of encoding
94               and a surface of that source size is allocatable. */
95            attrib_list[i].value = 0; /* No pure limitation */
96            break;
97        default:
98            attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED;
99            break;
100        }
101    }
102
103    return;
104}
105
106
107static VAStatus pnw_jpeg_ValidateConfig(
108    object_config_p obj_config)
109{
110    int i;
111    /* Check all attributes */
112    for (i = 0; i < obj_config->attrib_count; i++) {
113        switch (obj_config->attrib_list[i].type) {
114        case VAConfigAttribRTFormat:
115            /* Ignore */
116            break;
117        case VAConfigAttribRateControl:
118            break;
119        default:
120            return VA_STATUS_ERROR_ATTR_NOT_SUPPORTED;
121        }
122    }
123
124    return VA_STATUS_SUCCESS;
125
126}
127
128/*Init JPEG context. Ported from IMG_JPEG_EncoderInitialise*/
129static VAStatus pnw_jpeg_CreateContext(
130    object_context_p obj_context,
131    object_config_p obj_config)
132{
133    VAStatus vaStatus = VA_STATUS_SUCCESS;
134    context_ENC_p ctx;
135    TOPAZSC_JPEG_ENCODER_CONTEXT *jpeg_ctx_p;
136    int i;
137
138    drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_jpeg_CreateContext\n");
139
140    vaStatus = pnw_CreateContext(obj_context, obj_config, 1);
141    if (VA_STATUS_SUCCESS != vaStatus)
142        return VA_STATUS_ERROR_ALLOCATION_FAILED;
143
144    ctx = (context_ENC_p) obj_context->format_data;
145
146    ctx->eCodec = IMG_CODEC_JPEG;
147
148    for (i = 0; i < obj_config->attrib_count; i++) {
149        if (VAConfigAttribRTFormat ==  obj_config->attrib_list[i].type) {
150            switch (obj_config->attrib_list[i].value) {
151            case VA_RT_FORMAT_YUV420:
152                if (obj_context->render_targets != NULL) {
153                    object_surface_p surface_p = SURFACE(obj_context->render_targets[0]);
154                    if (NULL == surface_p) {
155                        ctx->eFormat = IMG_CODEC_PL12;
156                        drv_debug_msg(VIDEO_DEBUG_ERROR, "JPEG encoding: Unsupported format and set to NV12\n");
157                        break;
158                    }
159
160                    if ((surface_p->psb_surface)->extra_info[4] == VA_FOURCC_NV12) {
161                        ctx->eFormat = IMG_CODEC_PL12;
162                        drv_debug_msg(VIDEO_DEBUG_GENERAL, "JPEG encoding: Choose NV12 format\n");
163                    }
164                    else if ((surface_p->psb_surface)->extra_info[4] == VA_FOURCC_IYUV) {
165                        ctx->eFormat = IMG_CODEC_IYUV;
166                        drv_debug_msg(VIDEO_DEBUG_GENERAL, "JPEG encoding: Choose IYUV format\n");
167                    }
168                    else {
169                        ctx->eFormat = IMG_CODEC_PL12;
170                        drv_debug_msg(VIDEO_DEBUG_ERROR, "JPEG encoding: Unsupported format and set to NV12\n");
171                    }
172                }
173                else {
174                    ctx->eFormat = IMG_CODEC_PL12;
175                    drv_debug_msg(VIDEO_DEBUG_ERROR, "JPEG encoding: Unsupported format and set to NV12\n");
176                }
177                break;
178            case VA_RT_FORMAT_YUV422:
179                ctx->eFormat = IMG_CODEC_YV16;
180                drv_debug_msg(VIDEO_DEBUG_GENERAL, "JPEG encoding: Choose YUV422 format\n");
181                break;
182            default:
183                ctx->eFormat = IMG_CODEC_PL12;
184                drv_debug_msg(VIDEO_DEBUG_ERROR, "JPEG encoding: Unsupported format and set to NV12\n");
185                break;
186            }
187            break;
188        }
189    }
190
191    ctx->Slices = 2;
192    ctx->ParallelCores = 2;
193    ctx->NumCores = 2;
194    ctx->jpeg_ctx = (TOPAZSC_JPEG_ENCODER_CONTEXT *)calloc(1, sizeof(TOPAZSC_JPEG_ENCODER_CONTEXT));
195    CHECK_ALLOCATION(ctx->jpeg_ctx);
196
197    jpeg_ctx_p = ctx->jpeg_ctx;
198    jpeg_ctx_p->eFormat = ctx->eFormat;
199
200    /*Chroma sampling step x_step X y_step*/
201    jpeg_ctx_p->ui8ScanNum = JPEG_SCANNING_COUNT(ctx->Width, ctx->Height, ctx->NumCores, jpeg_ctx_p->eFormat);
202
203    if (jpeg_ctx_p->ui8ScanNum < 2 || jpeg_ctx_p->ui8ScanNum > PNW_JPEG_MAX_SCAN_NUM) {
204        drv_debug_msg(VIDEO_DEBUG_ERROR, "JPEG MCU scanning number(%d) is wrong!\n", jpeg_ctx_p->ui8ScanNum);
205        free(ctx->jpeg_ctx);
206        ctx->jpeg_ctx = NULL;
207        return VA_STATUS_ERROR_UNKNOWN;
208    }
209
210    jpeg_ctx_p->sScan_Encode_Info.ui8NumberOfCodedBuffers = jpeg_ctx_p->ui8ScanNum;
211
212    drv_debug_msg(VIDEO_DEBUG_GENERAL, " JPEG Scanning Number %d\n", jpeg_ctx_p->ui8ScanNum);
213    jpeg_ctx_p->sScan_Encode_Info.aBufferTable =
214        (TOPAZSC_JPEG_BUFFER_INFO *)calloc(1, sizeof(TOPAZSC_JPEG_BUFFER_INFO)
215                                           * jpeg_ctx_p->sScan_Encode_Info.ui8NumberOfCodedBuffers);
216
217    if (NULL == jpeg_ctx_p->sScan_Encode_Info.aBufferTable)
218        return VA_STATUS_ERROR_ALLOCATION_FAILED;
219
220    /*It will be figured out when known the size of whole coded buffer.*/
221    jpeg_ctx_p->ui32SizePerCodedBuffer = 0;
222
223    jpeg_ctx_p->ctx = (unsigned char *)ctx;
224    /*Reuse header_mem(76*4 bytes) and pic_params_size(256 bytes)
225     *  as pMemInfoMTXSetup(JPEG_MTX_DMA_SETUP 24x4 bytes) and
226     *  pMemInfoTableBlock JPEG_MTX_QUANT_TABLE(128byes)*/
227    return vaStatus;
228}
229
230
231static void pnw_jpeg_DestroyContext(
232    object_context_p obj_context)
233{
234    context_ENC_p ctx;
235
236    drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_jpeg_DestroyPicture\n");
237
238    ctx = (context_ENC_p)(obj_context->format_data);
239
240    if (ctx->jpeg_ctx) {
241        if (ctx->jpeg_ctx->sScan_Encode_Info.aBufferTable) {
242            free(ctx->jpeg_ctx->sScan_Encode_Info.aBufferTable);
243            ctx->jpeg_ctx->sScan_Encode_Info.aBufferTable = NULL;
244        }
245
246        free(ctx->jpeg_ctx);
247    }
248    pnw_DestroyContext(obj_context);
249
250}
251
252static VAStatus pnw_jpeg_BeginPicture(
253    object_context_p obj_context)
254{
255    INIT_CONTEXT_JPEG;
256    VAStatus vaStatus = VA_STATUS_SUCCESS;
257    int ret;
258    pnw_cmdbuf_p cmdbuf;
259
260    drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_jpeg_BeginPicture: Frame %d\n", ctx->obj_context->frame_count);
261
262    ctx->src_surface = ctx->obj_context->current_render_target;
263
264    /* Initialise the command buffer */
265    ret = pnw_context_get_next_cmdbuf(ctx->obj_context);
266    if (ret) {
267        drv_debug_msg(VIDEO_DEBUG_GENERAL, "get next cmdbuf fail\n");
268        vaStatus = VA_STATUS_ERROR_UNKNOWN;
269        return vaStatus;
270    }
271    cmdbuf = ctx->obj_context->pnw_cmdbuf;
272
273    /* map start_pic param */
274    vaStatus = psb_buffer_map(&cmdbuf->pic_params, &cmdbuf->pic_params_p);
275    if (vaStatus) {
276        return vaStatus;
277    }
278    vaStatus = psb_buffer_map(&cmdbuf->header_mem, &cmdbuf->header_mem_p);
279    if (vaStatus) {
280        psb_buffer_unmap(&cmdbuf->pic_params);
281        return vaStatus;
282    }
283
284    memset(ctx->jpeg_ctx->sScan_Encode_Info.aBufferTable, 0,
285           sizeof(TOPAZSC_JPEG_BUFFER_INFO) * ctx->jpeg_ctx->sScan_Encode_Info.ui8NumberOfCodedBuffers);
286
287    /*Store the QMatrix data*/
288    ctx->jpeg_ctx->pMemInfoTableBlock = cmdbuf->pic_params_p;
289    ctx->jpeg_ctx->psTablesBlock = (JPEG_MTX_QUANT_TABLE *)ctx->jpeg_ctx->pMemInfoTableBlock;
290
291    /*Store MTX_SETUP data*/
292    ctx->jpeg_ctx->pMemInfoMTXSetup = cmdbuf->header_mem_p;
293    ctx->jpeg_ctx->pMTXSetup = (JPEG_MTX_DMA_SETUP*)ctx->jpeg_ctx->pMemInfoMTXSetup;
294
295    ctx->jpeg_ctx->pMTXSetup->ui32ComponentsInScan = PNW_JPEG_COMPONENTS_NUM;
296
297    if (ctx->obj_context->frame_count == 0) { /* first picture */
298
299        psb_driver_data_p driver_data = ctx->obj_context->driver_data;
300
301        *cmdbuf->cmd_idx++ = ((MTX_CMDID_SW_NEW_CODEC & MTX_CMDWORD_ID_MASK) << MTX_CMDWORD_ID_SHIFT) |
302                             (((driver_data->drm_context & MTX_CMDWORD_COUNT_MASK) << MTX_CMDWORD_COUNT_SHIFT));
303        pnw_cmdbuf_insert_command_param(ctx->eCodec);
304        pnw_cmdbuf_insert_command_param((ctx->Width << 16) | ctx->Height);
305    }
306
307    pnw_jpeg_set_default_qmatix(ctx->jpeg_ctx->pMemInfoTableBlock);
308
309    return vaStatus;
310}
311
312static VAStatus pnw__jpeg_process_picture_param(context_ENC_p ctx, object_buffer_p obj_buffer)
313{
314    VAStatus vaStatus = VA_STATUS_SUCCESS;
315    VAEncPictureParameterBufferJPEG *pBuffer;
316    pnw_cmdbuf_p cmdbuf = ctx->obj_context->pnw_cmdbuf;
317    BUFFER_HEADER *pBufHeader;
318    //unsigned long *pPictureHeaderMem;
319    //MTX_HEADER_PARAMS *psPicHeader;
320    int i;
321    TOPAZSC_JPEG_ENCODER_CONTEXT *jpeg_ctx = ctx->jpeg_ctx;
322    JPEG_MTX_QUANT_TABLE* pQMatrix = (JPEG_MTX_QUANT_TABLE *)
323                                     (ctx->jpeg_ctx->pMemInfoTableBlock);
324    IMG_ERRORCODE rc;
325
326    ASSERT(obj_buffer->type == VAEncPictureParameterBufferType);
327
328    if ((obj_buffer->num_elements != 1) ||
329        (obj_buffer->size != sizeof(VAEncPictureParameterBufferJPEG))) {
330        return VA_STATUS_ERROR_UNKNOWN;
331    }
332
333    /* Transfer ownership of VAEncPictureParameterBufferMPEG4 data */
334    pBuffer = (VAEncPictureParameterBufferJPEG *) obj_buffer->buffer_data;
335    obj_buffer->buffer_data = NULL;
336    obj_buffer->size = 0;
337
338    /* Parameters checking */
339    if (((pBuffer->pic_flags).bits.profile != 0) || /* Only "0 - Baseline" is supported */
340       ((pBuffer->pic_flags).bits.progressive != 0) || /* Only "0 - sequential" is supported */
341       ((pBuffer->pic_flags).bits.huffman != 1) || /* Only "1 - huffman" is supported */
342       ((pBuffer->pic_flags).bits.interleaved != 0) || /* Only "0 - non interleaved" is supported */
343       ((pBuffer->pic_flags).bits.differential != 0)) /* Only "0 - non differential" is supported */
344        return VA_STATUS_ERROR_INVALID_PARAMETER;
345
346    if ((pBuffer->sample_bit_depth != 8) || /* Only 8-bits sample depth is supported */
347       (pBuffer->num_components != PNW_JPEG_COMPONENTS_NUM) || /* Only 3 components setting is supported */
348       (pBuffer->quality > 100))
349        return VA_STATUS_ERROR_INVALID_PARAMETER;
350
351    /* Set quality */
352    if (pBuffer->quality != 0) { /* Quality value is set */
353        customize_quantization_tables(pQMatrix->aui8LumaQuantParams,
354                                      pQMatrix->aui8ChromaQuantParams,
355                                      pBuffer->quality);
356    }
357
358    /* Get the width and height of encode destination */
359    jpeg_ctx->ui32OutputWidth = (unsigned short)(~0x1 & (pBuffer->picture_width + 0x1));
360    jpeg_ctx->ui32OutputHeight = (unsigned short)(~0x1 & (pBuffer->picture_height + 0x1));
361
362    ASSERT(ctx->Width >= jpeg_ctx->ui32OutputWidth);
363    ASSERT(ctx->Height >= jpeg_ctx->ui32OutputHeight);
364
365    /*Overwrite the scan info if destination's sizes are different from source's */
366    if ((ctx->Width!=jpeg_ctx->ui32OutputWidth) || (ctx->Height!=jpeg_ctx->ui32OutputHeight)) {
367        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Overwriting the scan info...\n");
368
369        jpeg_ctx->ui8ScanNum = JPEG_SCANNING_COUNT(jpeg_ctx->ui32OutputWidth, jpeg_ctx->ui32OutputHeight, ctx->NumCores, jpeg_ctx->eFormat);
370
371        if (jpeg_ctx->ui8ScanNum < 2 || jpeg_ctx->ui8ScanNum > PNW_JPEG_MAX_SCAN_NUM) {
372            drv_debug_msg(VIDEO_DEBUG_ERROR, "JPEG MCU scanning number(%d) is wrong!\n", jpeg_ctx->ui8ScanNum);
373            free(ctx->jpeg_ctx);
374            ctx->jpeg_ctx = NULL;
375            return VA_STATUS_ERROR_UNKNOWN;
376    	}
377
378        drv_debug_msg(VIDEO_DEBUG_GENERAL, "JPEG Scanning Number %d\n", jpeg_ctx->ui8ScanNum);
379        jpeg_ctx->sScan_Encode_Info.ui8NumberOfCodedBuffers = jpeg_ctx->ui8ScanNum;
380    }
381
382    ctx->coded_buf = BUFFER(pBuffer->coded_buf);
383    free(pBuffer);
384
385    if (NULL == ctx->coded_buf) {
386        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s L%d Invalid coded buffer handle\n", __FUNCTION__, __LINE__);
387        return VA_STATUS_ERROR_INVALID_BUFFER;
388    }
389
390    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Set Quant Tables\n");
391    /*Set Quant Tables*/
392    for (i = ctx->NumCores - 1; i >= 0; i--)
393        pnw_cmdbuf_insert_command_package(ctx->obj_context,
394                                          i,
395                                          MTX_CMDID_SETQUANT,
396                                          &cmdbuf->pic_params,
397                                          0);
398
399    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Quant Table \n");
400
401    for (i=0; i<128; i+=8) {
402        if (0 == i) {
403            drv_debug_msg(VIDEO_DEBUG_GENERAL, "Table 0:\n");
404        }
405        else if (64 == i) {
406            drv_debug_msg(VIDEO_DEBUG_GENERAL, "Table 1:\n");
407        }
408        drv_debug_msg(VIDEO_DEBUG_GENERAL, "%d %d %d %d %d %d %d %d\n",
409                      *((unsigned char *)cmdbuf->pic_params_p+i),
410                      *((unsigned char *)cmdbuf->pic_params_p+i+1),
411                      *((unsigned char *)cmdbuf->pic_params_p+i+2),
412                      *((unsigned char *)cmdbuf->pic_params_p+i+3),
413                      *((unsigned char *)cmdbuf->pic_params_p+i+4),
414                      *((unsigned char *)cmdbuf->pic_params_p+i+5),
415                      *((unsigned char *)cmdbuf->pic_params_p+i+6),
416                      *((unsigned char *)cmdbuf->pic_params_p+i+7));
417    }
418
419    jpeg_ctx->ui32SizePerCodedBuffer =
420        JPEG_CODED_BUF_SEGMENT_SIZE(ctx->coded_buf->size,
421                                    jpeg_ctx->ui32OutputWidth, jpeg_ctx->ui32OutputHeight,
422                                    ctx->NumCores, jpeg_ctx->eFormat);
423    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Coded buffer total size is %d,"
424                             "coded segment size per scan is %d\n",
425                             ctx->coded_buf->size, jpeg_ctx->ui32SizePerCodedBuffer);
426
427    vaStatus = psb_buffer_map(ctx->coded_buf->psb_buffer, (unsigned char **)&jpeg_ctx->jpeg_coded_buf.pMemInfo);
428    if (vaStatus) {
429        drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Map coded_buf failed!");
430        return vaStatus;
431    }
432    jpeg_ctx->jpeg_coded_buf.ui32Size = ctx->coded_buf->size;
433    jpeg_ctx->jpeg_coded_buf.sLock = BUFFER_FREE;
434    jpeg_ctx->jpeg_coded_buf.ui32BytesWritten = 0;
435
436    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Setup JPEG Tables\n");
437    rc = SetupJPEGTables(ctx->jpeg_ctx, &jpeg_ctx->jpeg_coded_buf,  ctx->src_surface);
438
439    if (rc != IMG_ERR_OK)
440        return VA_STATUS_ERROR_UNKNOWN;
441
442    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Write JPEG Headers to coded buf\n");
443
444    pBufHeader = (BUFFER_HEADER *)jpeg_ctx->jpeg_coded_buf.pMemInfo;
445    pBufHeader->ui32BytesUsed = 0; /* Not include BUFFER_HEADER*/
446    rc = PrepareHeader(jpeg_ctx, &jpeg_ctx->jpeg_coded_buf, sizeof(BUFFER_HEADER), IMG_TRUE);
447    if (rc != IMG_ERR_OK)
448        return VA_STATUS_ERROR_UNKNOWN;
449
450    pBufHeader->ui32Reserved3 = PNW_JPEG_HEADER_MAX_SIZE;//Next coded buffer offset
451    pBufHeader->ui32BytesUsed = jpeg_ctx->jpeg_coded_buf.ui32BytesWritten - sizeof(BUFFER_HEADER);
452
453    drv_debug_msg(VIDEO_DEBUG_GENERAL, "JPEG Buffer Header size: %d, File Header size :%d, next codef buffer offset: %d\n",
454                             sizeof(BUFFER_HEADER), pBufHeader->ui32BytesUsed, pBufHeader->ui32Reserved3);
455    return vaStatus;
456}
457
458static VAStatus pnw__jpeg_process_qmatrix_param(context_ENC_p ctx, object_buffer_p obj_buffer)
459{
460    VAStatus vaStatus = VA_STATUS_SUCCESS;
461    VAQMatrixBufferJPEG *pBuffer;
462    JPEG_MTX_QUANT_TABLE* pQMatrix = (JPEG_MTX_QUANT_TABLE *)
463                                     (ctx->jpeg_ctx->pMemInfoTableBlock);
464    int i;
465
466    ASSERT(obj_buffer->type == VAQMatrixBufferType);
467
468    pBuffer = (VAQMatrixBufferJPEG *) obj_buffer->buffer_data;
469
470    /* Zero value isn't allowed. It will cause JPEG firmware time out */
471    if (0 != pBuffer->load_lum_quantiser_matrix) {
472        for (i=0; i<QUANT_TABLE_SIZE_BYTES; ++i)
473            if (pBuffer->lum_quantiser_matrix[i] != 0)
474                pQMatrix->aui8LumaQuantParams[i] =
475                    pBuffer->lum_quantiser_matrix[i];
476    }
477
478    if (0 != pBuffer->load_chroma_quantiser_matrix) {
479        for (i=0; i<QUANT_TABLE_SIZE_BYTES; ++i)
480            if (pBuffer->chroma_quantiser_matrix[i] != 0)
481                pQMatrix->aui8ChromaQuantParams[i] =
482                    pBuffer->chroma_quantiser_matrix[i];
483    }
484
485    free(obj_buffer->buffer_data);
486    obj_buffer->buffer_data = NULL;
487
488    return vaStatus;
489}
490
491
492static VAStatus pnw_jpeg_RenderPicture(
493    object_context_p obj_context,
494    object_buffer_p *buffers,
495    int num_buffers)
496{
497    INIT_CONTEXT_JPEG;
498    VAStatus vaStatus = VA_STATUS_SUCCESS;
499    int i;
500
501    drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_jpeg_RenderPicture\n");
502
503    for (i = 0; i < num_buffers; i++) {
504        object_buffer_p obj_buffer = buffers[i];
505
506        switch (obj_buffer->type) {
507        case VAQMatrixBufferType:
508            drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_jpeg_RenderPicture got VAQMatrixBufferType\n");
509            vaStatus = pnw__jpeg_process_qmatrix_param(ctx, obj_buffer);
510            DEBUG_FAILURE;
511            break;
512        case VAEncPictureParameterBufferType:
513            drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_jpeg_RenderPicture got VAEncPictureParameterBufferType\n");
514            vaStatus = pnw__jpeg_process_picture_param(ctx, obj_buffer);
515            DEBUG_FAILURE;
516            break;
517        case VAEncSliceParameterBufferType:
518            drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_jpeg_RenderPicture got VAEncSliceParameterBufferJPEG\n");
519            drv_debug_msg(VIDEO_DEBUG_WARNING, "VAEncSliceParameterBufferJPEG is ignored on TopazSC\n");
520            vaStatus = VA_STATUS_SUCCESS;
521            DEBUG_FAILURE;
522            break;
523        default:
524            vaStatus = VA_STATUS_ERROR_UNKNOWN;
525            DEBUG_FAILURE;
526        }
527    }
528
529    return vaStatus;
530}
531
532/* Add Restart interval termination (RSTm)to coded buf 1 ~ NumCores-1*/
533static inline VAStatus pnw_OutputResetIntervalToCB(IMG_UINT8 *pui8Buf, IMG_UINT8 ui8_marker)
534{
535    if (NULL == pui8Buf)
536        return VA_STATUS_ERROR_UNKNOWN;
537    /*Refer to CCITT Rec. T.81 (1992 E), B.2.1*/
538    /*RSTm: Restart marker conditional marker which is placed between
539     * entropy-coded segments only if restartis enabled. There are 8 unique
540     * restart markers (m = 0 - 7) which repeat in sequence from 0 to 7, starting with
541     * zero for each scan, to provide a modulo 8 restart interval count*/
542    *pui8Buf++ = 0xff;
543    *pui8Buf = (ui8_marker | 0xd0);
544    return 0;
545}
546
547
548static VAStatus pnw_jpeg_EndPicture(
549    object_context_p obj_context)
550{
551    INIT_CONTEXT_JPEG;
552    IMG_UINT16 ui16BCnt;
553    TOPAZSC_JPEG_ENCODER_CONTEXT *pContext = ctx->jpeg_ctx;
554    IMG_UINT32 rc = 0;
555    pnw_cmdbuf_p cmdbuf = (pnw_cmdbuf_p)ctx->obj_context->pnw_cmdbuf;
556    VAStatus vaStatus = VA_STATUS_SUCCESS;
557    IMG_UINT32 ui32NoMCUsToEncode;
558    IMG_UINT32 ui32RemainMCUs;
559
560    drv_debug_msg(VIDEO_DEBUG_GENERAL, "pnw_jpeg_EndPicture\n");
561
562    ui32RemainMCUs = pContext->sScan_Encode_Info.ui32NumberMCUsToEncode;
563
564    for (ui16BCnt = 0; ui16BCnt < pContext->sScan_Encode_Info.ui8NumberOfCodedBuffers
565         && pContext->sScan_Encode_Info.ui16SScan > 0; ui16BCnt++) {
566        pContext->sScan_Encode_Info.aBufferTable[ui16BCnt].ui16ScanNumber =
567            pContext->sScan_Encode_Info.ui16SScan--;
568	if (pContext->sScan_Encode_Info.ui8NumberOfCodedBuffers < 2 ||
569		pContext->sScan_Encode_Info.ui8NumberOfCodedBuffers > PNW_JPEG_MAX_SCAN_NUM) {
570	    vaStatus = VA_STATUS_ERROR_UNKNOWN;
571            DEBUG_FAILURE;
572            return vaStatus;
573	}
574        /*i8MTXNumber is the core number.*/
575        pContext->sScan_Encode_Info.aBufferTable[ui16BCnt].i8MTXNumber =
576            (aui32_jpg_mtx_num[pContext->sScan_Encode_Info.ui8NumberOfCodedBuffers - 1]
577             >> ui16BCnt) & 0x1;
578
579        if (pContext->sScan_Encode_Info.ui16SScan == 0) {
580            ui32NoMCUsToEncode = ui32RemainMCUs;
581            // Final scan, may need fewer MCUs than buffer size, calculate the remainder
582        } else
583            ui32NoMCUsToEncode = pContext->sScan_Encode_Info.ui32NumberMCUsToEncodePerScan;
584
585        pContext->sScan_Encode_Info.ui32CurMCUsOffset =
586            pContext->sScan_Encode_Info.ui32NumberMCUsToEncode - ui32RemainMCUs;
587
588        rc = SubmitScanToMTX(pContext, ui16BCnt,
589                             pContext->sScan_Encode_Info.aBufferTable[ui16BCnt].i8MTXNumber, ui32NoMCUsToEncode);
590        if (rc != IMG_ERR_OK) {
591            vaStatus = VA_STATUS_ERROR_UNKNOWN;
592            DEBUG_FAILURE;
593            return vaStatus;
594        }
595
596        ui32RemainMCUs -= ui32NoMCUsToEncode;
597    }
598    pnw_cmdbuf_insert_command_package(ctx->obj_context,
599                                      1 ,
600                                      MTX_CMDID_NULL,
601                                      NULL,
602                                      0);
603
604
605    psb_buffer_unmap(&cmdbuf->pic_params);
606    cmdbuf->pic_params_p = NULL;
607    psb_buffer_unmap(&cmdbuf->header_mem);
608    cmdbuf->header_mem_p = NULL;
609    /*psb_buffer_unmap(&cmdbuf->slice_params);
610    cmdbuf->slice_params_p = NULL;*/
611    psb_buffer_unmap(ctx->coded_buf->psb_buffer);
612    pContext->jpeg_coded_buf.pMemInfo = NULL;
613    if (pnw_context_flush_cmdbuf(ctx->obj_context)) {
614        vaStatus = VA_STATUS_ERROR_UNKNOWN;
615        return vaStatus;
616    }
617
618    ctx->obj_context->frame_count++;
619    return VA_STATUS_SUCCESS;
620}
621
622VAStatus pnw_jpeg_AppendMarkers(object_context_p obj_context, unsigned char *raw_coded_buf)
623{
624    INIT_CONTEXT_JPEG;
625    IMG_UINT16 ui16BCnt;
626    TOPAZSC_JPEG_ENCODER_CONTEXT *pContext = ctx->jpeg_ctx;
627    BUFFER_HEADER* pBufHeader;
628    STREAMTYPEW s_streamW;
629    unsigned char *pSegStart = raw_coded_buf;
630
631    if (pSegStart == NULL) {
632        return VA_STATUS_ERROR_UNKNOWN;
633    }
634
635    pBufHeader = (BUFFER_HEADER *)pSegStart;
636
637    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Number of Coded buffers %d, Per Coded Buffer size : %d\n",
638                             pContext->sScan_Encode_Info.ui8NumberOfCodedBuffers, pContext->ui32SizePerCodedBuffer);
639
640    /*The first part of coded buffer contains JPEG headers*/
641    pBufHeader->ui32Reserved3 = PNW_JPEG_HEADER_MAX_SIZE;
642
643    pContext->jpeg_coded_buf.ui32BytesWritten = 0;
644
645    for (ui16BCnt = 0;
646         ui16BCnt < pContext->sScan_Encode_Info.ui8NumberOfCodedBuffers;
647         ui16BCnt++) {
648        pBufHeader = (BUFFER_HEADER *)pSegStart;
649        pBufHeader->ui32Reserved3 =
650            PNW_JPEG_HEADER_MAX_SIZE + pContext->ui32SizePerCodedBuffer * ui16BCnt ;
651
652        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Coded Buffer Part %d, size %d, next part offset: %d\n",
653                                 ui16BCnt, pBufHeader->ui32BytesUsed, pBufHeader->ui32Reserved3);
654
655        if (ui16BCnt > 0 && pContext->sScan_Encode_Info.ui8NumberOfCodedBuffers > 1) {
656            drv_debug_msg(VIDEO_DEBUG_GENERAL, "Append 2 bytes Reset Interval %d "
657                                     "to Coded Buffer Part %d\n", ui16BCnt - 1, ui16BCnt);
658
659            while(*(pSegStart +sizeof(BUFFER_HEADER) + pBufHeader->ui32BytesUsed - 1) == 0xff)
660                pBufHeader->ui32BytesUsed--;
661
662            pnw_OutputResetIntervalToCB(
663                (IMG_UINT8 *)(pSegStart +
664                              sizeof(BUFFER_HEADER) + pBufHeader->ui32BytesUsed),
665                ui16BCnt - 1);
666
667            pBufHeader->ui32BytesUsed += 2;
668        }
669
670        pContext->jpeg_coded_buf.ui32BytesWritten += pBufHeader->ui32BytesUsed;
671        pSegStart = raw_coded_buf + pBufHeader->ui32Reserved3;
672    }
673    pBufHeader = (BUFFER_HEADER *)pSegStart;
674    pBufHeader->ui32Reserved3 = 0; /*Last Part of Coded Buffer*/
675    pContext->jpeg_coded_buf.ui32BytesWritten += pBufHeader->ui32BytesUsed;
676
677    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Coded Buffer Part %d, size %d, next part offset: %d\n",
678                             ui16BCnt, pBufHeader->ui32BytesUsed, pBufHeader->ui32Reserved3);
679
680    while(*(pSegStart +sizeof(BUFFER_HEADER) + pBufHeader->ui32BytesUsed - 1) == 0xff)
681        pBufHeader->ui32BytesUsed--;
682
683    s_streamW.Buffer = pSegStart;
684    s_streamW.Offset = (sizeof(BUFFER_HEADER) + pBufHeader->ui32BytesUsed);
685
686    fPutBitsToBuffer(&s_streamW, 2, END_OF_IMAGE);
687
688    pBufHeader->ui32BytesUsed += 2;
689    pContext->jpeg_coded_buf.ui32BytesWritten += 2;
690
691    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Add two bytes to last part of coded buffer,"
692                             " total: %d\n", pContext->jpeg_coded_buf.ui32BytesWritten);
693    return VA_STATUS_SUCCESS;
694}
695
696struct format_vtable_s pnw_JPEG_vtable = {
697queryConfigAttributes:
698    pnw_jpeg_QueryConfigAttributes,
699validateConfig:
700    pnw_jpeg_ValidateConfig,
701createContext:
702    pnw_jpeg_CreateContext,
703destroyContext:
704    pnw_jpeg_DestroyContext,
705beginPicture:
706    pnw_jpeg_BeginPicture,
707renderPicture:
708    pnw_jpeg_RenderPicture,
709endPicture:
710    pnw_jpeg_EndPicture
711};
712