/* * Copyright (c) 2011 Intel Corporation. All Rights Reserved. * Copyright (c) Imagination Technologies Limited, UK * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Authors: * Elaine Wang <elaine.wang@intel.com> * */ #include <stdlib.h> #include <stdint.h> #include <string.h> #include "psb_def.h" #include "psb_drv_debug.h" #include "psb_surface.h" #include "psb_cmdbuf.h" #include "tng_hostcode.h" #include "tng_hostheader.h" #include "tng_jpegES.h" #ifdef _TOPAZHP_PDUMP_ #include "tng_trace.h" #endif static void tng__trace_cmdbuf(tng_cmdbuf_p cmdbuf) { int i; IMG_UINT32 ui32CmdTmp[4]; IMG_UINT32 *ptmp = (IMG_UINT32 *)(cmdbuf->cmd_start); drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: start\n", __FUNCTION__); //skip the newcodec if (*ptmp != MTX_CMDID_SW_NEW_CODEC) { drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: error new coded\n", __FUNCTION__); return ; } ptmp += 6; if ((*ptmp & 0xf) != MTX_CMDID_SETUP_INTERFACE) { drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: error setup interface\n", __FUNCTION__); return ; } ui32CmdTmp[0] = *ptmp++; ui32CmdTmp[1] = *ptmp++; ui32CmdTmp[2] = *ptmp++; ui32CmdTmp[3] = 0; #ifdef _TOPAZHP_PDUMP_ topazhp_dump_command((unsigned int*)ui32CmdTmp); #endif for (i = 0; i < 3; i++) { ui32CmdTmp[0] = *ptmp++; ui32CmdTmp[1] = *ptmp++; ui32CmdTmp[2] = 0; ui32CmdTmp[3] = 0; #ifdef _TOPAZHP_PDUMP_ topazhp_dump_command((unsigned int*)ui32CmdTmp); #endif } drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: end\n", __FUNCTION__); return; } #define SURFACE(id) ((object_surface_p) object_heap_lookup( &ctx->obj_context->driver_data->surface_heap, id )) #define BUFFER(id) ((object_buffer_p) object_heap_lookup( &ctx->obj_context->driver_data->buffer_heap, id )) #define PTG_JPEG_MAX_MCU_PER_SCAN (0x4000) #define PTG_JPEG_HEADER_MAX_SIZE (1024) #define C_INTERLEAVE 1 #define LC_YUYVINTERLEAVE 2 #define LC_YVYUINTERLEAVE 3 #define LC_UYVYINTERLEAVE 4 #define LC_VYUYINTERLEAVE 5 #define ISCHROMAINTERLEAVED(eSurfaceFormat) ((IMG_UINT)(eSurfaceFormat==IMG_CODEC_PL12) * C_INTERLEAVE) /****************************************************************************** General definitions ******************************************************************************/ #define BYTE 8 #define BYTES_IN_INT 4 #define BITS_IN_INT 32 #define BLOCK_SIZE 8 #define PELS_IN_BLOCK 64 /****************************************************************************** JPEG marker definitions ******************************************************************************/ #define START_OF_IMAGE 0xFFD8 #define SOF_BASELINE_DCT 0xFFC0 #define END_OF_IMAGE 0xFFD9 #define START_OF_SCAN 0xFFDA /* Definitions for the huffman table specification in the Marker segment */ #define DHT_MARKER 0xFFC4 #define LH_DC 0x001F #define LH_AC 0x00B5 #define LEVEL_SHIFT 128 /* Definitions for the quantization table specification in the Marker segment */ #define DQT_MARKER 0xFFDB #define ACMAX 0x03FF #define DCMAX 0x07FF /* Length and precision of the quantization table parameters */ #define LQPQ 0x00430 #define QMAX 255 #define CLIP(Number,Max,Min) if((Number) > (Max)) (Number) = (Max); \ else if((Number) < (Min)) (Number) = (Min) ///////////////////////////////////////////////////////////////////////////////////// // BMP Reading Header Stuff ///////////////////////////////////////////////////////////////////////////////////// static const IMG_UINT8 gQuantLuma[QUANT_TABLE_SIZE_BYTES] = { 16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 55, 14, 13, 16, 24, 40, 57, 69, 56, 14, 17, 22, 29, 51, 87, 80, 62, 18, 22, 37, 56, 68, 109, 103, 77, 24, 35, 55, 64, 81, 104, 113, 92, 49, 64, 78, 87, 103, 121, 120, 101, 72, 92, 95, 98, 112, 100, 103, 99 }; /*****************************************************************************/ /* \brief gQuantChroma */ /* */ /* Contains the data that needs to be sent in the marker segment of an */ /* interchange format JPEG stream or an abbreviated format table */ /* specification data stream. */ /* Quantizer table for the chrominance component */ /*****************************************************************************/ static const IMG_UINT8 gQuantChroma[QUANT_TABLE_SIZE_BYTES] = { 17, 18, 24, 47, 99, 99, 99, 99, 18, 21, 26, 66, 99, 99, 99, 99, 24, 26, 56, 99, 99, 99, 99, 99, 47, 66, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99 }; /*****************************************************************************/ /* \brief gZigZag */ /* */ /* Zigzag scan pattern */ /*****************************************************************************/ static const IMG_UINT8 gZigZag[] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 }; /*****************************************************************************/ /* \brief gMarkerDataLumaDc */ /* */ /* Contains the data that needs to be sent in the marker segment of an */ /* interchange format JPEG stream or an abbreviated format table */ /* specification data stream. */ /* Specifies the huffman table used for encoding the luminance DC */ /* coefficient differences. The table represents Table K.3 of */ /* IS0/IEC 10918-1:1994(E) */ /*****************************************************************************/ static const IMG_UINT8 gMarkerDataLumaDc[] = { //TcTh Li 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Vi 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B }; /*****************************************************************************/ /* \brief gMarkerDataLumaAc */ /* */ /* Contains the data that needs to be sent in the marker segment of an */ /* interchange format JPEG stream or an abbreviated format table */ /* specification data stream. */ /* Specifies the huffman table used for encoding the luminance AC */ /* coefficients. The table represents Table K.5 of IS0/IEC 10918-1:1994(E) */ /*****************************************************************************/ static const IMG_UINT8 gMarkerDataLumaAc[] = { // TcTh Li 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, // Vi 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA }; /*****************************************************************************/ /* \brief gMarkerDataChromaDc */ /* */ /* Contains the data that needs to be sent in the marker segment of an */ /* interchange format JPEG stream or an abbreviated format table */ /* specification data stream. */ /* Specifies the huffman table used for encoding the chrominance DC */ /* coefficient differences. The table represents Table K.4 of */ /* IS0/IEC 10918-1:1994(E) */ /*****************************************************************************/ static const IMG_UINT8 gMarkerDataChromaDc[] = { // TcTh Li 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // Vi 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B }; /*****************************************************************************/ /* \brief gMarkerDataChromaAc */ /* */ /* Contains the data that needs to be sent in the marker segment of an */ /* interchange format JPEG stream or an abbreviated format table */ /* specification data stream. */ /* Specifies the huffman table used for encoding the chrominance AC */ /* coefficients. The table represents Table K.6 of IS0/IEC 10918-1:1994(E) */ /*****************************************************************************/ static const IMG_UINT8 gMarkerDataChromaAc[] = { // TcTh 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, // Vi 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA }; static int CustomizeQuantizationTables(unsigned char *luma_matrix, unsigned char *chroma_matrix, unsigned int ui32Quality) { unsigned int uc_qVal; unsigned int uc_j; if((NULL == luma_matrix) || (NULL == chroma_matrix) || (ui32Quality < 1) || (ui32Quality > 100)) return 1; /* Compute luma quantization table */ ui32Quality = (ui32Quality<50) ? (5000/ui32Quality) : (200-ui32Quality*2); for(uc_j=0; uc_j<QUANT_TABLE_SIZE_BYTES; ++uc_j) { uc_qVal = (gQuantLuma[uc_j] * ui32Quality + 50) / 100; uc_qVal = (uc_qVal>0xFF)? 0xFF:uc_qVal; uc_qVal = (uc_qVal<1)? 1:uc_qVal; luma_matrix[uc_j] = (unsigned char)uc_qVal; } /* Compute chroma quantization table */ for(uc_j=0; uc_j<QUANT_TABLE_SIZE_BYTES; ++uc_j) { uc_qVal = (gQuantChroma[uc_j] * ui32Quality + 50) / 100; uc_qVal = (uc_qVal>0xFF)? 0xFF:uc_qVal; uc_qVal = (uc_qVal<1)? 1:uc_qVal; chroma_matrix[uc_j] = (unsigned char)uc_qVal; } return 0; } static void SetDefaultQmatix(void *pMemInfoTableBlock) { JPEG_MTX_QUANT_TABLE *pQTable = pMemInfoTableBlock; memcpy(pQTable->aui8LumaQuantParams, gQuantLuma, QUANT_TABLE_SIZE_BYTES); memcpy(pQTable->aui8ChromaQuantParams, gQuantChroma, QUANT_TABLE_SIZE_BYTES); return; } static void IssueQmatix(TOPAZHP_JPEG_ENCODER_CONTEXT *pJPEGContext) { int i; context_ENC_p ctx = (context_ENC_p)pJPEGContext->ctx; /* Dump MTX setup data for debug */ ASSERT(NULL != pJPEGContext->pMemInfoTableBlock); drv_debug_msg(VIDEO_DEBUG_GENERAL, "Issue Quantization Table data\n"); for (i=0; i<128; i+=8) { if (0 == i) { drv_debug_msg(VIDEO_DEBUG_GENERAL, "Table 0:\n"); } else if (64 == i) { drv_debug_msg(VIDEO_DEBUG_GENERAL, "Table 1:\n"); } drv_debug_msg(VIDEO_DEBUG_GENERAL, "%d %d %d %d %d %d %d %d\n", *((unsigned char *)ctx->obj_context->tng_cmdbuf->jpeg_pic_params_p+i), *((unsigned char *)ctx->obj_context->tng_cmdbuf->jpeg_pic_params_p+i+1), *((unsigned char *)ctx->obj_context->tng_cmdbuf->jpeg_pic_params_p+i+2), *((unsigned char *)ctx->obj_context->tng_cmdbuf->jpeg_pic_params_p+i+3), *((unsigned char *)ctx->obj_context->tng_cmdbuf->jpeg_pic_params_p+i+4), *((unsigned char *)ctx->obj_context->tng_cmdbuf->jpeg_pic_params_p+i+5), *((unsigned char *)ctx->obj_context->tng_cmdbuf->jpeg_pic_params_p+i+6), *((unsigned char *)ctx->obj_context->tng_cmdbuf->jpeg_pic_params_p+i+7)); } tng_cmdbuf_insert_command(ctx->obj_context, 0, MTX_CMDID_SETQUANT, 0, &(ctx->obj_context->tng_cmdbuf->jpeg_pic_params), 0); } static void InitializeJpegEncode(TOPAZHP_JPEG_ENCODER_CONTEXT *pJPEGContext) { context_ENC_p ctx = (context_ENC_p)pJPEGContext->ctx; IMG_UINT16 ui16_width; IMG_UINT16 ui16_height; IMG_UINT32 ui32UpperLimit; /*********************************************************************/ /* Determine the horizonal and the vertical sampling frequency of */ /* each of components in the image */ /*********************************************************************/ ui16_width = ctx->ui16Width; ui16_height = ctx->ui16FrameHeight; //pTFrame->height isn't the real height of image, because vaCreateSurface has made it aligned with 32 switch (pJPEGContext->eFormat) { case IMG_CODEC_PL12: default: pJPEGContext->MCUComponent[0].ui32WidthBlocks = 16; pJPEGContext->MCUComponent[0].ui32HeightBlocks = 16; pJPEGContext->MCUComponent[0].ui32XLimit = ui16_width; pJPEGContext->MCUComponent[0].ui32YLimit = ui16_height; pJPEGContext->MCUComponent[1].ui32WidthBlocks = 8; pJPEGContext->MCUComponent[1].ui32HeightBlocks = 8; pJPEGContext->MCUComponent[1].ui32XLimit = ui16_width >> 1; pJPEGContext->MCUComponent[1].ui32YLimit = ui16_height >> 1; pJPEGContext->MCUComponent[2].ui32WidthBlocks = 8; pJPEGContext->MCUComponent[2].ui32HeightBlocks = 8; pJPEGContext->MCUComponent[2].ui32XLimit = ui16_width >> 1; pJPEGContext->MCUComponent[2].ui32YLimit = ui16_height >> 1; break; } switch (ISCHROMAINTERLEAVED(pJPEGContext->eFormat)) { case C_INTERLEAVE: default: // Chroma format is byte interleaved, as the engine runs using planar colour surfaces we need // to fool the engine into offsetting by 16 instead of 8 pJPEGContext->MCUComponent[1].ui32WidthBlocks += pJPEGContext->MCUComponent[2].ui32WidthBlocks; pJPEGContext->MCUComponent[1].ui32XLimit += pJPEGContext->MCUComponent[2].ui32XLimit; pJPEGContext->MCUComponent[2].ui32XLimit = pJPEGContext->MCUComponent[2].ui32YLimit = pJPEGContext->MCUComponent[2].ui32WidthBlocks = pJPEGContext->MCUComponent[2].ui32HeightBlocks = 0; break; } pJPEGContext->sScan_Encode_Info.ui32NumberMCUsX = (pJPEGContext->MCUComponent[0].ui32XLimit + (pJPEGContext->MCUComponent[0].ui32WidthBlocks - 1)) / pJPEGContext->MCUComponent[0].ui32WidthBlocks; pJPEGContext->sScan_Encode_Info.ui32NumberMCUsY = (pJPEGContext->MCUComponent[0].ui32YLimit + (pJPEGContext->MCUComponent[0].ui32HeightBlocks - 1)) / pJPEGContext->MCUComponent[0].ui32HeightBlocks; pJPEGContext->sScan_Encode_Info.ui32NumberMCUsToEncode = pJPEGContext->sScan_Encode_Info.ui32NumberMCUsX * pJPEGContext->sScan_Encode_Info.ui32NumberMCUsY; drv_debug_msg(VIDEO_DEBUG_GENERAL, "Number of X MCUs: %d\n", pJPEGContext->sScan_Encode_Info.ui32NumberMCUsX); drv_debug_msg(VIDEO_DEBUG_GENERAL, "Number of Y MCUs: %d\n", pJPEGContext->sScan_Encode_Info.ui32NumberMCUsY); drv_debug_msg(VIDEO_DEBUG_GENERAL, "Number of total MCUs: %d\n", pJPEGContext->sScan_Encode_Info.ui32NumberMCUsToEncode); // Number of MCUs sent for a scan _must_ lie at the beginning of a line so that the chroma component can't violate the 16 byte DMA start alignment constraint // (Actual memory alignment for final DMA will have width aligned to 64, so start of line will automatically meet the 16 byte alignment required by the DMA engine) pJPEGContext->sScan_Encode_Info.ui32NumberMCUsToEncodePerScan = (pJPEGContext->sScan_Encode_Info.ui32NumberMCUsY + (pJPEGContext->NumCores - 1)) / pJPEGContext->NumCores; pJPEGContext->sScan_Encode_Info.ui32NumberMCUsToEncodePerScan *= pJPEGContext->sScan_Encode_Info.ui32NumberMCUsX; drv_debug_msg(VIDEO_DEBUG_GENERAL, "Number of MCUs per core: %d\n", pJPEGContext->sScan_Encode_Info.ui32NumberMCUsToEncodePerScan); // Limit the scan size to maximum useable (due to it being used as the 16 bit field for Restart Intervals) = 0xFFFF MCUs // In reality, worst case allocatable bytes is less than this, something around 0x159739C == 0x4b96 MCUs = 139 x 139 MCUS = 2224 * 2224 pixels, approx. // We'll give this upper limit some margin for error, and limit our MCUsPerScan to 2000 * 2000 pixels = 125 * 125 MCUS = 0x3D09 MCUS = 0x116F322 bytes (1170 worst case per MCU) // If more MCUs are required, then the image will be automatically encoded with multiple scans on the same pipes ui32UpperLimit = PTG_JPEG_MAX_MCU_PER_SCAN / pJPEGContext->sScan_Encode_Info.ui32NumberMCUsX; ui32UpperLimit *= pJPEGContext->sScan_Encode_Info.ui32NumberMCUsX; if (pJPEGContext->sScan_Encode_Info.ui32NumberMCUsToEncodePerScan > ui32UpperLimit) { // Set MCUs to encode per scan to equal maximum limit and then truncate to ensure it lies at the first MCU of a line (to satisfy the 64 byte requirement) pJPEGContext->sScan_Encode_Info.ui32NumberMCUsToEncodePerScan = ui32UpperLimit; } drv_debug_msg(VIDEO_DEBUG_GENERAL, "Number of MCUs per scan: %d\n", pJPEGContext->sScan_Encode_Info.ui32NumberMCUsToEncodePerScan); //Need to set up CB Output slicenumber to equal number of slices required to encode image // Set current CB scan to maximum scan number (will count down as scans are output) pJPEGContext->sScan_Encode_Info.ui16ScansInImage = (pJPEGContext->sScan_Encode_Info.ui32NumberMCUsToEncode + (pJPEGContext->sScan_Encode_Info.ui32NumberMCUsToEncodePerScan - 1)) / pJPEGContext->sScan_Encode_Info.ui32NumberMCUsToEncodePerScan; pJPEGContext->sScan_Encode_Info.ui8NumberOfCodedBuffers = pJPEGContext->sScan_Encode_Info.ui16ScansInImage; drv_debug_msg(VIDEO_DEBUG_GENERAL, "Scans in image: %d\n", pJPEGContext->sScan_Encode_Info.ui16ScansInImage); drv_debug_msg(VIDEO_DEBUG_GENERAL, "Number of coded buffers: %d\n", pJPEGContext->sScan_Encode_Info.ui8NumberOfCodedBuffers); return; } static void AssignCodedDataBuffers(TOPAZHP_JPEG_ENCODER_CONTEXT *pJPEGContext) { IMG_UINT8 ui8Loop; pJPEGContext->ui32SizePerCodedBuffer = (pJPEGContext->jpeg_coded_buf.ui32Size - PTG_JPEG_HEADER_MAX_SIZE) / pJPEGContext->sScan_Encode_Info.ui8NumberOfCodedBuffers; pJPEGContext->ui32SizePerCodedBuffer &= ~0xf; memset((void *)pJPEGContext->sScan_Encode_Info.aBufferTable, 0x0, sizeof(TOPAZHP_JPEG_BUFFER_INFO)*pJPEGContext->sScan_Encode_Info.ui8NumberOfCodedBuffers); drv_debug_msg(VIDEO_DEBUG_GENERAL, "jpeg_coded_buf.pMemInfo: 0x%x\n", (unsigned int)(pJPEGContext->jpeg_coded_buf.pMemInfo)); for (ui8Loop = 0 ; ui8Loop < pJPEGContext->sScan_Encode_Info.ui8NumberOfCodedBuffers; ui8Loop++) { //pJPEGContext->sScan_Encode_Info.aBufferTable[ui8Loop].ui32DataBufferSizeBytes = DATA_BUFFER_SIZE(pJPEGContext->sScan_Encode_Info.ui32NumberMCUsToEncodePerScan); //pJPEGContext->sScan_Encode_Info.aBufferTable[ui8Loop].ui32DataBufferSizeBytes = (pJPEGContext->sScan_Encode_Info.aBufferTable[ui8Loop].ui32DataBufferSizeBytes+sizeof(BUFFER_HEADER)) + 3 & ~3; pJPEGContext->sScan_Encode_Info.aBufferTable[ui8Loop].ui32DataBufferUsedBytes = 0; pJPEGContext->sScan_Encode_Info.aBufferTable[ui8Loop].i8PipeNumber = 0; // Indicates buffer is idle pJPEGContext->sScan_Encode_Info.aBufferTable[ui8Loop].ui16ScanNumber = 0; // Indicates buffer is idle pJPEGContext->sScan_Encode_Info.aBufferTable[ui8Loop].pMemInfo = (void *) ((IMG_UINT32)pJPEGContext->jpeg_coded_buf.pMemInfo + PTG_JPEG_HEADER_MAX_SIZE + ui8Loop * pJPEGContext->ui32SizePerCodedBuffer); drv_debug_msg(VIDEO_DEBUG_GENERAL, "aBufferTable[%d].pMemInfo: 0x%x\n", ui8Loop, (unsigned int)(pJPEGContext->sScan_Encode_Info.aBufferTable[ui8Loop].pMemInfo)); } return; } static void SetSetupInterface(TOPAZHP_JPEG_ENCODER_CONTEXT *pJPEGContext) { context_ENC_p ctx = (context_ENC_p)pJPEGContext->ctx; context_ENC_mem *ps_mem = &(ctx->ctx_mem[ctx->ui32StreamID]); context_ENC_mem_size *ps_mem_size = &(ctx->ctx_mem_size); tng_cmdbuf_set_phys(pJPEGContext->pMTXWritebackMemory->apWritebackRegions, WB_FIFO_SIZE, &(ctx->bufs_writeback), 0, ps_mem_size->writeback); } static void IssueSetupInterface(TOPAZHP_JPEG_ENCODER_CONTEXT *pJPEGContext) { int i; context_ENC_p ctx = (context_ENC_p)pJPEGContext->ctx; ASSERT(NULL != pJPEGContext->pMTXSetup); drv_debug_msg(VIDEO_DEBUG_GENERAL, "Issue SetupInterface\n"); for (i = 0; i < WB_FIFO_SIZE; i++) { drv_debug_msg(VIDEO_DEBUG_GENERAL, "apWritebackRegions[%d]: 0x%x\n", i, pJPEGContext->pMTXWritebackMemory->apWritebackRegions[i]); } tng_cmdbuf_insert_command(ctx->obj_context, 0, MTX_CMDID_SETUP_INTERFACE, 0, &(ctx->obj_context->tng_cmdbuf->jpeg_header_interface_mem), 0); } static IMG_ERRORCODE SetMTXSetup( TOPAZHP_JPEG_ENCODER_CONTEXT *pJPEGContext, object_surface_p pTFrame) { IMG_UINT32 srf_buf_offset; context_ENC_p ctx = (context_ENC_p)pJPEGContext->ctx; tng_cmdbuf_p cmdbuf = ctx->obj_context->tng_cmdbuf; context_ENC_mem *ps_mem = &(ctx->ctx_mem[ctx->ui32StreamID]); context_ENC_mem_size *ps_mem_size = &(ctx->ctx_mem_size); pJPEGContext->pMTXSetup->ui32ComponentsInScan = MTX_MAX_COMPONENTS; switch (pJPEGContext->eFormat) { case IMG_CODEC_PL12: if (pTFrame->psb_surface->stride % 64) { drv_debug_msg(VIDEO_DEBUG_ERROR, "Surface stride isn't aligned to 64 bytes as HW requires: %u!\n", pTFrame->psb_surface->stride); return IMG_ERR_INVALID_CONTEXT; } pJPEGContext->pMTXSetup->ComponentPlane[0].ui32Stride = pTFrame->psb_surface->stride; pJPEGContext->pMTXSetup->ComponentPlane[1].ui32Stride = pTFrame->psb_surface->stride; pJPEGContext->pMTXSetup->ComponentPlane[2].ui32Stride = pTFrame->psb_surface->stride; pJPEGContext->pMTXSetup->ComponentPlane[0].ui32Height = pJPEGContext->MCUComponent[0].ui32YLimit; pJPEGContext->pMTXSetup->ComponentPlane[1].ui32Height = pJPEGContext->MCUComponent[0].ui32YLimit / 2; pJPEGContext->pMTXSetup->ComponentPlane[2].ui32Height = pJPEGContext->MCUComponent[0].ui32YLimit / 2; break; default: drv_debug_msg(VIDEO_DEBUG_ERROR, "Not supported FOURCC: %x!\n", pJPEGContext->eFormat); return IMG_ERR_INVALID_CONTEXT; } srf_buf_offset = pTFrame->psb_surface->buf.buffer_ofs; RELOC_JPEG_PIC_PARAMS_PTG(&pJPEGContext->pMTXSetup->ComponentPlane[0].ui32PhysAddr, srf_buf_offset, &pTFrame->psb_surface->buf); switch (pJPEGContext->eFormat) { case IMG_CODEC_PL12: RELOC_JPEG_PIC_PARAMS_PTG(&pJPEGContext->pMTXSetup->ComponentPlane[1].ui32PhysAddr, srf_buf_offset + pTFrame->psb_surface->stride * pTFrame->height, &pTFrame->psb_surface->buf); //Byte interleaved surface, so need to force chroma to use single surface by fooling it into //thinking it's dealing with standard 8x8 planaerblocks RELOC_JPEG_PIC_PARAMS_PTG(&pJPEGContext->pMTXSetup->ComponentPlane[2].ui32PhysAddr, srf_buf_offset + pTFrame->psb_surface->stride * pTFrame->height + 8, &pTFrame->psb_surface->buf); break; default: drv_debug_msg(VIDEO_DEBUG_ERROR, "Not supported FOURCC: %x!\n", pJPEGContext->eFormat); return IMG_ERR_INVALID_CONTEXT; } memcpy((void *)pJPEGContext->pMTXSetup->MCUComponent, (void *)pJPEGContext->MCUComponent, sizeof(pJPEGContext->MCUComponent)); pJPEGContext->pMTXSetup->ui32TableA = 0; pJPEGContext->pMTXSetup->ui16DataInterleaveStatus = ISCHROMAINTERLEAVED(pJPEGContext->eFormat); pJPEGContext->pMTXSetup->ui16MaxPipes = (IMG_UINT16)pJPEGContext->NumCores; return IMG_ERR_OK; } static void IssueMTXSetup(TOPAZHP_JPEG_ENCODER_CONTEXT *pJPEGContext) { uint32_t i; context_ENC_p ctx = (context_ENC_p)pJPEGContext->ctx; /* Dump MTX setup data for debug */ ASSERT(NULL != pJPEGContext->pMTXSetup); drv_debug_msg(VIDEO_DEBUG_GENERAL, "Issue MTX setup data\n"); for (i = 0; i < pJPEGContext->pMTXSetup->ui32ComponentsInScan; i++) { drv_debug_msg(VIDEO_DEBUG_GENERAL, "ComponentPlane[%d]: 0x%x, %d, %d\n", i, pJPEGContext->pMTXSetup->ComponentPlane[i].ui32PhysAddr, pJPEGContext->pMTXSetup->ComponentPlane[i].ui32Stride, pJPEGContext->pMTXSetup->ComponentPlane[i].ui32Height); drv_debug_msg(VIDEO_DEBUG_GENERAL, "MCUComponent[%d]: %d, %d, %d, %d\n", i, pJPEGContext->pMTXSetup->MCUComponent[i].ui32WidthBlocks, pJPEGContext->pMTXSetup->MCUComponent[i].ui32HeightBlocks, pJPEGContext->pMTXSetup->MCUComponent[i].ui32XLimit, pJPEGContext->pMTXSetup->MCUComponent[i].ui32YLimit); } drv_debug_msg(VIDEO_DEBUG_GENERAL, "ui32ComponentsInScan: %d\n", pJPEGContext->pMTXSetup->ui32ComponentsInScan); drv_debug_msg(VIDEO_DEBUG_GENERAL, "ui32TableA: %d\n", pJPEGContext->pMTXSetup->ui32TableA); drv_debug_msg(VIDEO_DEBUG_GENERAL, "ui16DataInterleaveStatus: %d\n", pJPEGContext->pMTXSetup->ui16DataInterleaveStatus); drv_debug_msg(VIDEO_DEBUG_GENERAL, "ui16MaxPipes: %d\n", pJPEGContext->pMTXSetup->ui16MaxPipes); tng_cmdbuf_insert_command(ctx->obj_context, 0, MTX_CMDID_SETUP, 0, &(ctx->obj_context->tng_cmdbuf->jpeg_header_mem), 0); return; } static void fPutBitsToBuffer(STREAMTYPEW *BitStream, IMG_UINT8 NoOfBytes, IMG_UINT32 ActualBits) { IMG_UINT8 ui8Lp; IMG_UINT8 *pui8S; pui8S = (IMG_UINT8 *)BitStream->Buffer; pui8S += BitStream->Offset; for (ui8Lp = NoOfBytes; ui8Lp > 0; ui8Lp--) *(pui8S++) = ((IMG_UINT8 *) &ActualBits)[ui8Lp-1]; BitStream->Offset += NoOfBytes; } static IMG_UINT32 EncodeMarkerSegment(TOPAZHP_JPEG_ENCODER_CONTEXT *pJPEGContext, IMG_UINT8 *puc_stream_buff, IMG_BOOL bIncludeHuffmanTables) { STREAMTYPEW s_streamW; IMG_UINT8 uc_i; s_streamW.Offset = 0; s_streamW.Buffer = puc_stream_buff; /* Writing the start of image marker */ fPutBitsToBuffer(&s_streamW, 2, START_OF_IMAGE); /* Writing the quantization table for luminance into the stream */ fPutBitsToBuffer(&s_streamW, 2, DQT_MARKER); fPutBitsToBuffer(&s_streamW, 3, LQPQ << 4); // 20 bits = LQPQ, 4 bits = 0 (Destination identifier for the luminance quantizer tables) IMG_ASSERT(PELS_IN_BLOCK <= QUANT_TABLE_SIZE_BYTES); for (uc_i = 0; uc_i < PELS_IN_BLOCK; uc_i++) { // Write zigzag ordered luma quantization values to our JPEG header fPutBitsToBuffer(&s_streamW, 1, pJPEGContext->psTablesBlock->aui8LumaQuantParams[gZigZag[uc_i]]); } /* Writing the quantization table for chrominance into the stream */ fPutBitsToBuffer(&s_streamW, 2, DQT_MARKER); fPutBitsToBuffer(&s_streamW, 3, (LQPQ << 4) | 1); // 20 bits = LQPQ, 4 bits = 1 (Destination identifier for the chrominance quantizer tables) for (uc_i = 0; uc_i < PELS_IN_BLOCK; uc_i++) { // Write zigzag ordered chroma quantization values to our JPEG header fPutBitsToBuffer(&s_streamW, 1, pJPEGContext->psTablesBlock->aui8ChromaQuantParams[gZigZag[uc_i]]); } if (bIncludeHuffmanTables) { /* Writing the huffman tables for luminance dc coeffs */ /* Write the DHT Marker */ fPutBitsToBuffer(&s_streamW, 2, DHT_MARKER); fPutBitsToBuffer(&s_streamW, 2, LH_DC); for (uc_i = 0; uc_i < LH_DC - 2; uc_i++) { fPutBitsToBuffer(&s_streamW, 1, gMarkerDataLumaDc[uc_i]); } /* Writing the huffman tables for luminance ac coeffs */ /* Write the DHT Marker */ fPutBitsToBuffer(&s_streamW, 2, DHT_MARKER); fPutBitsToBuffer(&s_streamW, 2, LH_AC); for (uc_i = 0; uc_i < LH_AC - 2; uc_i++) { fPutBitsToBuffer(&s_streamW, 1, gMarkerDataLumaAc[uc_i]); } /* Writing the huffman tables for chrominance dc coeffs */ fPutBitsToBuffer(&s_streamW, 2, DHT_MARKER); fPutBitsToBuffer(&s_streamW, 2, LH_DC); for (uc_i = 0; uc_i < LH_DC - 2; uc_i++) { fPutBitsToBuffer(&s_streamW, 1, gMarkerDataChromaDc[uc_i]); } /* Writing the huffman tables for luminance ac coeffs */ /* Write the DHT Marker */ fPutBitsToBuffer(&s_streamW, 2, DHT_MARKER); fPutBitsToBuffer(&s_streamW, 2, LH_AC); for (uc_i = 0; uc_i < LH_AC - 2; uc_i++) { fPutBitsToBuffer(&s_streamW, 1, gMarkerDataChromaAc[uc_i]); } } // Activate Restart markers if (pJPEGContext->sScan_Encode_Info.ui16CScan > 1) { // Only use restart intervals if we need them (ie. multiple Scan encode and/or parallel CB encode) fPutBitsToBuffer(&s_streamW, 2, 0xFFDD); //Marker header fPutBitsToBuffer(&s_streamW, 2, 4); // Byte size of marker (header not included) fPutBitsToBuffer(&s_streamW, 2, pJPEGContext->sScan_Encode_Info.ui32NumberMCUsToEncodePerScan); // Restart Interval (same as MCUs per buffer) } return s_streamW.Offset; } static IMG_UINT32 EncodeFrameHeader(TOPAZHP_JPEG_ENCODER_CONTEXT *pJPEGContext, IMG_UINT8 *puc_stream_buff) { STREAMTYPEW ps_streamW; IMG_UINT8 uc_num_comp_in_img; uc_num_comp_in_img = pJPEGContext->pMTXSetup->ui32ComponentsInScan; ps_streamW.Offset = 0; ps_streamW.Buffer = puc_stream_buff; //if(ps_jpeg_params->uc_isAbbreviated != 0) // fPutBitsToBuffer(&ps_streamW, 2, START_OF_IMAGE); /* Writing the frame header */ fPutBitsToBuffer(&ps_streamW, 2, SOF_BASELINE_DCT); /* Frame header length */ fPutBitsToBuffer(&ps_streamW, 2, 8 + 3 * uc_num_comp_in_img); /* Precision */ fPutBitsToBuffer(&ps_streamW, 1, 8); /* Height : sample lines */ fPutBitsToBuffer(&ps_streamW, 2, pJPEGContext->ui32OutputHeight); /* Width : samples per line */ fPutBitsToBuffer(&ps_streamW, 2, pJPEGContext->ui32OutputWidth); /* Number of image components */ fPutBitsToBuffer(&ps_streamW, 1, uc_num_comp_in_img); //Chroma Details if (pJPEGContext->pMTXSetup->ui16DataInterleaveStatus < C_INTERLEAVE) { //Luma Details /* Component identifier */ fPutBitsToBuffer(&ps_streamW, 1, 1); //CompId 0 = 1, 1 = 2, 2 = 3 fPutBitsToBuffer(&ps_streamW, 1, ((pJPEGContext->pMTXSetup->MCUComponent[0].ui32WidthBlocks >> 3) << 4) | (pJPEGContext->pMTXSetup->MCUComponent[0].ui32HeightBlocks >> 3)); fPutBitsToBuffer(&ps_streamW, 1, 0); // 0 = Luma(0), 1,2 = Chroma(1) //Chroma planar fPutBitsToBuffer(&ps_streamW, 1, 2); //CompId 0 = 1, 1 = 2, 2 = 3 /* 4 bit Horizontal and 4 bit vertical sampling factors */ fPutBitsToBuffer(&ps_streamW, 1, ((pJPEGContext->pMTXSetup->MCUComponent[1].ui32WidthBlocks >> 3) << 4) | (pJPEGContext->pMTXSetup->MCUComponent[1].ui32HeightBlocks >> 3)); fPutBitsToBuffer(&ps_streamW, 1, 1); // 0 = Luma(0), 1,2 = Chroma(1) fPutBitsToBuffer(&ps_streamW, 1, 3); //CompId 0 = 1, 1 = 2, 2 = 3 /* 4 bit Horizontal and 4 bit vertical sampling factors */ fPutBitsToBuffer(&ps_streamW, 1, ((pJPEGContext->pMTXSetup->MCUComponent[2].ui32WidthBlocks >> 3) << 4) | (pJPEGContext->pMTXSetup->MCUComponent[2].ui32HeightBlocks >> 3)); fPutBitsToBuffer(&ps_streamW, 1, 1); // 0 = Luma(0), 1,2 = Chroma(1) } else if (pJPEGContext->pMTXSetup->ui16DataInterleaveStatus == C_INTERLEAVE) { //Luma Details /* Component identifier */ fPutBitsToBuffer(&ps_streamW, 1, 1); //CompId 0 = 1, 1 = 2, 2 = 3 fPutBitsToBuffer(&ps_streamW, 1, ((pJPEGContext->pMTXSetup->MCUComponent[0].ui32WidthBlocks >> 3) << 4) | (pJPEGContext->pMTXSetup->MCUComponent[0].ui32HeightBlocks >> 3)); fPutBitsToBuffer(&ps_streamW, 1, 0); // 0 = Luma(0), 1,2 = Chroma(1) // Chroma Interleaved fPutBitsToBuffer(&ps_streamW, 1, 2); //CompId 0 = 1, 1 = 2, 2 = 3 /* 4 bit Horizontal and 4 bit vertical sampling factors */ fPutBitsToBuffer(&ps_streamW, 1, ((pJPEGContext->pMTXSetup->MCUComponent[1].ui32WidthBlocks >> 4) << 4) | (pJPEGContext->pMTXSetup->MCUComponent[1].ui32HeightBlocks >> 3)); fPutBitsToBuffer(&ps_streamW, 1, 1); // 0 = Luma(0), 1,2 = Chroma(1) fPutBitsToBuffer(&ps_streamW, 1, 3); //CompId 0 = 1, 1 = 2, 2 = 3 /* 4 bit Horizontal and 4 bit vertical sampling factors */ fPutBitsToBuffer(&ps_streamW, 1, ((pJPEGContext->pMTXSetup->MCUComponent[1].ui32WidthBlocks >> 4) << 4) | (pJPEGContext->pMTXSetup->MCUComponent[1].ui32HeightBlocks >> 3)); fPutBitsToBuffer(&ps_streamW, 1, 1); // 0 = Luma(0), 1,2 = Chroma(1) } else { //Luma Details /* Component identifier */ fPutBitsToBuffer(&ps_streamW, 1, 1); //CompId 0 = 1, 1 = 2, 2 = 3 fPutBitsToBuffer(&ps_streamW, 1, ((pJPEGContext->pMTXSetup->MCUComponent[0].ui32WidthBlocks >> 4) << 4) | (pJPEGContext->pMTXSetup->MCUComponent[0].ui32HeightBlocks >> 3)); fPutBitsToBuffer(&ps_streamW, 1, 0); // 0 = Luma(0), 1,2 = Chroma(1) //Chroma YUYV - Special case fPutBitsToBuffer(&ps_streamW, 1, 2); //CompId 0 = 1, 1 = 2, 2 = 3 /* 4 bit Horizontal and 4 bit vertical sampling factors */ fPutBitsToBuffer(&ps_streamW, 1, ((pJPEGContext->pMTXSetup->MCUComponent[0].ui32WidthBlocks >> 5) << 4) | (pJPEGContext->pMTXSetup->MCUComponent[0].ui32HeightBlocks >> 3)); fPutBitsToBuffer(&ps_streamW, 1, 1); // 0 = Luma(0), 1,2 = Chroma(1) fPutBitsToBuffer(&ps_streamW, 1, 3); //CompId 0 = 1, 1 = 2, 2 = 3 /* 4 bit Horizontal and 4 bit vertical sampling factors */ fPutBitsToBuffer(&ps_streamW, 1, ((pJPEGContext->pMTXSetup->MCUComponent[0].ui32WidthBlocks >> 5) << 4) | (pJPEGContext->pMTXSetup->MCUComponent[0].ui32HeightBlocks >> 3)); fPutBitsToBuffer(&ps_streamW, 1, 1); // 0 = Luma(0), 1,2 = Chroma(1) } //Use if you want start of scan (image data) to align to 32 //fPutBitsToBuffer(&ps_streamW, 1, 0xFF); return ps_streamW.Offset; } static IMG_UINT32 JPGEncodeMarker(TOPAZHP_JPEG_ENCODER_CONTEXT *pJPEGContext , IMG_UINT8* pui8BitStreamBuffer , IMG_UINT32 *pui32BytesWritten, IMG_BOOL bIncludeHuffmanTables) { #ifdef JPEG_VERBOSE drv_debug_msg(VIDEO_DEBUG_GENERAL, "PVRJPGEncodeMarker"); #endif *pui32BytesWritten += EncodeMarkerSegment(pJPEGContext, pui8BitStreamBuffer + *pui32BytesWritten, bIncludeHuffmanTables); return 0; } static IMG_UINT32 JPGEncodeHeader(TOPAZHP_JPEG_ENCODER_CONTEXT *pJPEGContext, IMG_UINT8* pui8BitStreamBuffer , IMG_UINT32* pui32BytesWritten) { #ifdef JPEG_VERBOSE drv_debug_msg(VIDEO_DEBUG_GENERAL, "JPGEncodeHeader"); #endif *pui32BytesWritten += EncodeFrameHeader(pJPEGContext, pui8BitStreamBuffer + *pui32BytesWritten); return 0; } static IMG_UINT32 JPGEncodeSOSHeader(TOPAZHP_JPEG_ENCODER_CONTEXT *pJPEGContext, IMG_UINT8* pui8BitStreamBuffer , IMG_UINT32* pui32BytesWritten) { IMG_UINT8 uc_comp_id, ui8Comp; STREAMTYPEW s_streamW; s_streamW.Offset = 0; s_streamW.Buffer = pui8BitStreamBuffer + *pui32BytesWritten; /* Start of scan */ fPutBitsToBuffer(&s_streamW, 2, START_OF_SCAN); /* Scan header length */ fPutBitsToBuffer(&s_streamW, 2, 6 + (pJPEGContext->pMTXSetup->ui32ComponentsInScan << 1)); /* Number of image components in scan */ fPutBitsToBuffer(&s_streamW, 1, pJPEGContext->pMTXSetup->ui32ComponentsInScan); for (ui8Comp = 0; ui8Comp < pJPEGContext->pMTXSetup->ui32ComponentsInScan; ui8Comp++) { uc_comp_id = ui8Comp + 1; /* Scan component selector */ fPutBitsToBuffer(&s_streamW, 1, uc_comp_id); /*4 Bits Dc entropy coding table destination selector */ /*4 Bits Ac entropy coding table destination selector */ fPutBitsToBuffer(&s_streamW, 1, ((ui8Comp != 0 ? 1 : 0) << 4) | (ui8Comp != 0 ? 1 : 0)); // Huffman table refs = 0 Luma 1 Chroma } /* Start of spectral or predictor selection */ fPutBitsToBuffer(&s_streamW, 1, 0); /* End of spectral selection */ fPutBitsToBuffer(&s_streamW, 1, 63); /*4 Bits Successive approximation bit position high (0)*/ /*4 Bits Successive approximation bit position low or point transform (0)*/ fPutBitsToBuffer(&s_streamW, 1, 0); *pui32BytesWritten += s_streamW.Offset; return 0; } static void InitializeScanCounter(TOPAZHP_JPEG_ENCODER_CONTEXT *pJPEGContext) { pJPEGContext->sScan_Encode_Info.ui16SScan = pJPEGContext->sScan_Encode_Info.ui16CScan = pJPEGContext->sScan_Encode_Info.ui16ScansInImage; } static IMG_ERRORCODE PrepareHeader(TOPAZHP_JPEG_ENCODER_CONTEXT * pJPEGContext, IMG_CODED_BUFFER *pCBuffer, IMG_UINT32 ui32StartOffset, IMG_BOOL bIncludeHuffmanTables) { IMG_ERRORCODE rc; IMG_UINT8 *ui8OutputBuffer; //Locate our JPEG Coded buffer ui8OutputBuffer = (IMG_UINT8 *)pCBuffer->pMemInfo; pCBuffer->ui32BytesWritten = ui32StartOffset; *((IMG_UINT32*)ui8OutputBuffer + pCBuffer->ui32BytesWritten) = 0; drv_debug_msg(VIDEO_DEBUG_GENERAL, "Before writing headers, ui32BytesWritten: %d\n", pCBuffer->ui32BytesWritten); // JPGEncodeMarker - Currently misses out the APP0 header rc = JPGEncodeMarker(pJPEGContext, (IMG_UINT8 *) ui8OutputBuffer, &pCBuffer->ui32BytesWritten, bIncludeHuffmanTables); if (rc) return rc; drv_debug_msg(VIDEO_DEBUG_GENERAL, "After JPGEncodeMarker, ui32BytesWritten: %d\n", pCBuffer->ui32BytesWritten); rc = JPGEncodeHeader(pJPEGContext , (IMG_UINT8 *) ui8OutputBuffer , &pCBuffer->ui32BytesWritten); if (rc) return rc; drv_debug_msg(VIDEO_DEBUG_GENERAL, "After JPGEncodeHeader, ui32BytesWritten: %d\n", pCBuffer->ui32BytesWritten); rc = JPGEncodeSOSHeader(pJPEGContext, (IMG_UINT8 *) ui8OutputBuffer, &pCBuffer->ui32BytesWritten); if (rc) return rc; drv_debug_msg(VIDEO_DEBUG_GENERAL, "After JPGEncodeSOSHeader, ui32BytesWritten: %d\n", pCBuffer->ui32BytesWritten); return IMG_ERR_OK; } static IMG_ERRORCODE IssueBufferToHW( TOPAZHP_JPEG_ENCODER_CONTEXT *pJPEGContext, IMG_UINT16 ui16BCnt, IMG_INT8 i8PipeNumber, IMG_UINT32 ui32NoMCUsToEncode) { MTX_ISSUE_BUFFERS *psBufferCmd; context_ENC_p ctx = (context_ENC_p)(pJPEGContext->ctx); context_ENC_frame_buf *ps_buf = &(ctx->ctx_frame_buf); pJPEGContext->sScan_Encode_Info.aBufferTable[ui16BCnt].ui32DataBufferUsedBytes = ((BUFFER_HEADER*)(pJPEGContext->sScan_Encode_Info.aBufferTable[ui16BCnt].pMemInfo))->ui32BytesUsed = -1; // Won't be necessary with SC Peek commands enabled drv_debug_msg(VIDEO_DEBUG_GENERAL, "Submit Scan %d which contains %d MCU in Buffer %d to MTX %d\n", pJPEGContext->sScan_Encode_Info.aBufferTable[ui16BCnt].ui16ScanNumber, ui32NoMCUsToEncode, ui16BCnt, i8PipeNumber); // Issue to MTX //////////////////////////// psBufferCmd = (MTX_ISSUE_BUFFERS *)(pJPEGContext->sScan_Encode_Info.aBufferTable[ui16BCnt].pMemInfo); ASSERT(psBufferCmd); drv_debug_msg(VIDEO_DEBUG_GENERAL, "ui16ScansInImage: %d\n", pJPEGContext->sScan_Encode_Info.ui16ScansInImage); drv_debug_msg(VIDEO_DEBUG_GENERAL, "ui16ScanNumber: %d\n", pJPEGContext->sScan_Encode_Info.aBufferTable[ui16BCnt].ui16ScanNumber); drv_debug_msg(VIDEO_DEBUG_GENERAL, "ui32NumberMCUsToEncodePerScan: %d\n", pJPEGContext->sScan_Encode_Info.ui32NumberMCUsToEncodePerScan); psBufferCmd->ui32MCUCntAndResetFlag = (ui32NoMCUsToEncode << 1) | 0x1; psBufferCmd->ui32MCUPositionOfScanAndPipeNo = (((pJPEGContext->sScan_Encode_Info.ui16ScansInImage - pJPEGContext->sScan_Encode_Info.aBufferTable[ui16BCnt].ui16ScanNumber) * pJPEGContext->sScan_Encode_Info.ui32NumberMCUsToEncodePerScan)<<2)&(~2); ASSERT(0 == i8PipeNumber); if (i8PipeNumber <= 3) psBufferCmd->ui32MCUPositionOfScanAndPipeNo |= i8PipeNumber; drv_debug_msg(VIDEO_DEBUG_GENERAL, "ui32MCUPositionOfScanAndPipeNo: 0x%x\n", psBufferCmd->ui32MCUPositionOfScanAndPipeNo); drv_debug_msg(VIDEO_DEBUG_GENERAL, "ui32MCUCntAndResetFlag: 0x%x\n", psBufferCmd->ui32MCUCntAndResetFlag); drv_debug_msg(VIDEO_DEBUG_GENERAL, "psBufferCmd: 0x%x\n", (unsigned int)(psBufferCmd)); drv_debug_msg(VIDEO_DEBUG_GENERAL, "Command Data: 0x%x\n", (unsigned int)(PTG_JPEG_HEADER_MAX_SIZE + ui16BCnt * pJPEGContext->ui32SizePerCodedBuffer)); // Issue buffers tng_cmdbuf_insert_command(ctx->obj_context, 0, MTX_CMDID_ISSUEBUFF, 0, ps_buf->coded_buf->psb_buffer, PTG_JPEG_HEADER_MAX_SIZE + ui16BCnt * pJPEGContext->ui32SizePerCodedBuffer); return IMG_ERR_OK; } static void tng_jpeg_QueryConfigAttributes( VAProfile __maybe_unused profile, VAEntrypoint __maybe_unused entrypoint, VAConfigAttrib *attrib_list, int num_attribs) { int i; drv_debug_msg(VIDEO_DEBUG_GENERAL, "tng_jpeg_QueryConfigAttributes\n"); /* Return supported attributes */ for (i = 0; i < num_attribs; i++) { switch (attrib_list[i].type) { case VAConfigAttribRTFormat: /* Already handled in psb_GetConfigAttributes */ break; case VAConfigAttribEncJPEG: /* The below JPEG ENC capabilities are fixed by TopazHP and not changable. */ { VAConfigAttribValEncJPEG* ptr = (VAConfigAttribValEncJPEG *)&(attrib_list[i].value); (ptr->bits).arithmatic_coding_mode = 0; /* Unsupported */ (ptr->bits).progressive_dct_mode = 0; /* Unsupported */ (ptr->bits).non_interleaved_mode = 1; /* Supported */ (ptr->bits).differential_mode = 0; /* Unsupported */ (ptr->bits).max_num_components = MTX_MAX_COMPONENTS; /* Only 3 is supported */ (ptr->bits).max_num_scans = PTG_JPEG_MAX_SCAN_NUM; (ptr->bits).max_num_huffman_tables = 4; /* Only 4 is supported */ (ptr->bits).max_num_huffman_tables = 2; /* Only 2 is supported */ } break; case VAConfigAttribMaxPictureWidth: case VAConfigAttribMaxPictureHeight: /* No pure limitation on an image's width or height seperately, as long as the image's MCUs need less than max_num_scans rounds of encoding and a surface of that source size is allocatable. */ attrib_list[i].value = 0; /* No pure limitation */ break; default: attrib_list[i].value = VA_ATTRIB_NOT_SUPPORTED; break; } } return; } static VAStatus tng_jpeg_ValidateConfig( object_config_p obj_config) { drv_debug_msg(VIDEO_DEBUG_GENERAL, "tng_jpeg_ValidateConfig\n"); int i; /* Check all attributes */ for (i = 0; i < obj_config->attrib_count; i++) { switch (obj_config->attrib_list[i].type) { case VAConfigAttribRTFormat: /* Ignore */ break; case VAConfigAttribRateControl: break; default: return VA_STATUS_ERROR_ATTR_NOT_SUPPORTED; } } return VA_STATUS_SUCCESS; } static VAStatus tng_jpeg_CreateContext( object_context_p obj_context, object_config_p obj_config) { int i; VAStatus vaStatus = VA_STATUS_SUCCESS; context_ENC_p ctx; TOPAZHP_JPEG_ENCODER_CONTEXT *jpeg_ctx_p; drv_debug_msg(VIDEO_DEBUG_GENERAL, "tng_jpeg_CreateContext\n"); vaStatus = tng_CreateContext(obj_context, obj_config, 1); if (VA_STATUS_SUCCESS != vaStatus) return VA_STATUS_ERROR_ALLOCATION_FAILED; ctx = (context_ENC_p) obj_context->format_data; ctx->eCodec = IMG_CODEC_JPEG; ASSERT(0 == (ctx->ui16Width % 2)); ASSERT(0 == (ctx->ui16FrameHeight % 2)); for (i = 0; i < obj_config->attrib_count; i++) { if (VAConfigAttribRTFormat == obj_config->attrib_list[i].type) { switch (obj_config->attrib_list[i].value) { case VA_RT_FORMAT_YUV420: ctx->eFormat = IMG_CODEC_PL12; drv_debug_msg(VIDEO_DEBUG_GENERAL, "JPEG encoding: NV12 format chose.\n"); break; default: drv_debug_msg(VIDEO_DEBUG_ERROR, "JPEG encoding: unsupported YUV format and force it to be NV12!\n"); ctx->eFormat = IMG_CODEC_PL12; break; } break; } } ctx->jpeg_ctx = (TOPAZHP_JPEG_ENCODER_CONTEXT *)calloc(1, sizeof(TOPAZHP_JPEG_ENCODER_CONTEXT)); if (NULL == ctx->jpeg_ctx) return VA_STATUS_ERROR_ALLOCATION_FAILED; jpeg_ctx_p = ctx->jpeg_ctx; jpeg_ctx_p->ctx = ctx; memset((void *)jpeg_ctx_p, 0x0, sizeof(jpeg_ctx_p)); jpeg_ctx_p->NumCores = TOPAZHP_PIPE_NUM; jpeg_ctx_p->eFormat = ctx->eFormat; jpeg_ctx_p->ui32OutputWidth = ctx->ui16Width; jpeg_ctx_p->ui32OutputHeight = ctx->ui16FrameHeight; InitializeJpegEncode(jpeg_ctx_p); if ((jpeg_ctx_p->sScan_Encode_Info.ui16ScansInImage < 1) || (jpeg_ctx_p->sScan_Encode_Info.ui16ScansInImage > PTG_JPEG_MAX_SCAN_NUM)) { drv_debug_msg(VIDEO_DEBUG_ERROR, "JPEG MCU scanning number(%d) is wrong!\n", jpeg_ctx_p->sScan_Encode_Info.ui16ScansInImage); free(ctx->jpeg_ctx); ctx->jpeg_ctx = NULL; return VA_STATUS_ERROR_UNKNOWN; } /*Allocate coded buffers' descripters */ jpeg_ctx_p->sScan_Encode_Info.aBufferTable = (TOPAZHP_JPEG_BUFFER_INFO *)calloc(1, (jpeg_ctx_p->sScan_Encode_Info.ui8NumberOfCodedBuffers) * (sizeof(TOPAZHP_JPEG_BUFFER_INFO))); if (NULL == jpeg_ctx_p->sScan_Encode_Info.aBufferTable) return VA_STATUS_ERROR_ALLOCATION_FAILED; return vaStatus; } static void tng_jpeg_DestroyContext( object_context_p obj_context) { context_ENC_p ctx; drv_debug_msg(VIDEO_DEBUG_GENERAL, "tng_jpeg_DestroyPicture\n"); ctx = (context_ENC_p)(obj_context->format_data); if (ctx->jpeg_ctx) { if (ctx->jpeg_ctx->sScan_Encode_Info.aBufferTable) { free(ctx->jpeg_ctx->sScan_Encode_Info.aBufferTable); ctx->jpeg_ctx->sScan_Encode_Info.aBufferTable = NULL; } free(ctx->jpeg_ctx); } tng_DestroyContext(obj_context, 1); } static VAStatus tng__cmdbuf_lowpower(context_ENC_p ctx) { VAStatus vaStatus = VA_STATUS_SUCCESS; tng_cmdbuf_p cmdbuf = ctx->obj_context->tng_cmdbuf; psb_driver_data_p driver_data = ctx->obj_context->driver_data; *cmdbuf->cmd_idx++ = ((MTX_CMDID_SW_LEAVE_LOWPOWER & MTX_CMDWORD_ID_MASK) << MTX_CMDWORD_ID_SHIFT) | ((ctx->ui32RawFrameCount & MTX_CMDWORD_CORE_MASK) << MTX_CMDWORD_CORE_SHIFT) | (((driver_data->context_id & MTX_CMDWORD_COUNT_MASK) << MTX_CMDWORD_COUNT_SHIFT)); tng_cmdbuf_insert_command_param(ctx->eCodec); return vaStatus; } static VAStatus tng_jpeg_BeginPicture( object_context_p obj_context) { VAStatus vaStatus = VA_STATUS_SUCCESS; int ret; tng_cmdbuf_p cmdbuf; context_ENC_p ctx = (context_ENC_p) obj_context->format_data; TOPAZHP_JPEG_ENCODER_CONTEXT *jpeg_ctx_p = ctx->jpeg_ctx; context_ENC_frame_buf *ps_buf = &(ctx->ctx_frame_buf); psb_driver_data_p driver_data = ctx->obj_context->driver_data; drv_debug_msg(VIDEO_DEBUG_GENERAL, "tng_jpeg_BeginPicture: Frame %d\n", ctx->obj_context->frame_count); /* Get the current surface */ ps_buf->src_surface = ctx->obj_context->current_render_target; /* Initialize the command buffer */ ret = tng_context_get_next_cmdbuf(ctx->obj_context); if (ret) { drv_debug_msg(VIDEO_DEBUG_ERROR, "get next cmdbuf fail\n"); vaStatus = VA_STATUS_ERROR_UNKNOWN; return vaStatus; } cmdbuf = ctx->obj_context->tng_cmdbuf; //For the first picture of a set to be encoded, need to ask kernel to perpare JPEG encoding if (ctx->obj_context->frame_count == 0) { /* first picture */ *cmdbuf->cmd_idx++ = ((MTX_CMDID_SW_NEW_CODEC & MTX_CMDWORD_ID_MASK) << MTX_CMDWORD_ID_SHIFT) | ((ctx->eCodec) << MTX_CMDWORD_CORE_SHIFT) | (((driver_data->drm_context & MTX_CMDWORD_COUNT_MASK) << MTX_CMDWORD_COUNT_SHIFT)); tng_cmdbuf_insert_command_param((ctx->ui16Width << 16) | ctx->ui16FrameHeight); } /* Map MTX setup buffer */ vaStatus = psb_buffer_map(&cmdbuf->jpeg_header_mem, (unsigned char **)&cmdbuf->jpeg_header_mem_p); if (vaStatus) { drv_debug_msg(VIDEO_DEBUG_ERROR, "Fail to map MTX setup buffer\n"); return vaStatus; } jpeg_ctx_p->pMemInfoMTXSetup = cmdbuf->jpeg_header_mem_p; jpeg_ctx_p->pMTXSetup = (JPEG_MTX_DMA_SETUP*)jpeg_ctx_p->pMemInfoMTXSetup; memset(jpeg_ctx_p->pMemInfoMTXSetup, 0x0, ctx->jpeg_header_mem_size); /* Map MTX setup interface buffer */ vaStatus = psb_buffer_map(&cmdbuf->jpeg_header_interface_mem, (unsigned char **)&cmdbuf->jpeg_header_interface_mem_p); if (vaStatus) { drv_debug_msg(VIDEO_DEBUG_ERROR, "Fail to map MTX setup interface buffer\n"); psb_buffer_unmap(&cmdbuf->jpeg_header_mem); return vaStatus; } jpeg_ctx_p->pMemInfoWritebackMemory = cmdbuf->jpeg_header_interface_mem_p; jpeg_ctx_p->pMTXWritebackMemory = (JPEG_MTX_WRITEBACK_MEMORY*)jpeg_ctx_p->pMemInfoWritebackMemory; memset(jpeg_ctx_p->pMemInfoWritebackMemory, 0x0, ctx->jpeg_header_interface_mem_size); /* Map quantization table buffer */ vaStatus = psb_buffer_map(&cmdbuf->jpeg_pic_params, (unsigned char **)&cmdbuf->jpeg_pic_params_p); if (vaStatus) { drv_debug_msg(VIDEO_DEBUG_ERROR, "Fail to map quantization table buffer\n"); psb_buffer_unmap(&cmdbuf->jpeg_header_mem); psb_buffer_unmap(&cmdbuf->jpeg_header_interface_mem); return vaStatus; } jpeg_ctx_p->pMemInfoTableBlock = cmdbuf->jpeg_pic_params_p; jpeg_ctx_p->psTablesBlock = (JPEG_MTX_QUANT_TABLE *)jpeg_ctx_p->pMemInfoTableBlock; memset(jpeg_ctx_p->pMemInfoTableBlock, 0x0, ctx->jpeg_pic_params_size); vaStatus = tng__cmdbuf_lowpower(ctx); if (vaStatus != VA_STATUS_SUCCESS) { drv_debug_msg(VIDEO_DEBUG_ERROR, "cmdbuf lowpower\n"); } /* Set SetupInterface*/ SetSetupInterface(jpeg_ctx_p); IssueSetupInterface(jpeg_ctx_p); /* Set MTX setup struture */ ret = SetMTXSetup(jpeg_ctx_p, ps_buf->src_surface); if (ret != IMG_ERR_OK) return ret; IssueMTXSetup(jpeg_ctx_p); /* Initialize the default quantization tables */ SetDefaultQmatix(jpeg_ctx_p->pMemInfoTableBlock); /* Initialize scan counters */ InitializeScanCounter(jpeg_ctx_p); tng_cmdbuf_buffer_ref(cmdbuf, &(ctx->obj_context->current_render_target->psb_surface->buf)); return vaStatus; } static VAStatus ProcessQmatrixParam(context_ENC_p ctx, object_buffer_p obj_buffer) { VAStatus vaStatus = VA_STATUS_SUCCESS; VAQMatrixBufferJPEG *pBuffer; JPEG_MTX_QUANT_TABLE* pQMatrix = (JPEG_MTX_QUANT_TABLE *)(ctx->jpeg_ctx->psTablesBlock); ASSERT(obj_buffer->type == VAQMatrixBufferType); pBuffer = (VAQMatrixBufferJPEG *)obj_buffer->buffer_data; if (0 != pBuffer->load_lum_quantiser_matrix) { memcpy(pQMatrix->aui8LumaQuantParams, pBuffer->lum_quantiser_matrix, QUANT_TABLE_SIZE_BYTES); } if (0 != pBuffer->load_chroma_quantiser_matrix) { memcpy(pQMatrix->aui8ChromaQuantParams, pBuffer->chroma_quantiser_matrix, QUANT_TABLE_SIZE_BYTES); } free(obj_buffer->buffer_data); obj_buffer->buffer_data = NULL; return vaStatus; } static VAStatus ProcessPictureParam(context_ENC_p ctx, object_buffer_p obj_buffer) { VAStatus vaStatus = VA_STATUS_SUCCESS; VAEncPictureParameterBufferJPEG *pBuffer = NULL; BUFFER_HEADER *pBufHeader = NULL; TOPAZHP_JPEG_ENCODER_CONTEXT *jpeg_ctx = ctx->jpeg_ctx; JPEG_MTX_QUANT_TABLE* pQMatrix = (JPEG_MTX_QUANT_TABLE *) (ctx->jpeg_ctx->pMemInfoTableBlock); context_ENC_frame_buf *ps_buf = &(ctx->ctx_frame_buf); IMG_ERRORCODE rc; /* Check the input buffer */ ASSERT(obj_buffer->type == VAEncPictureParameterBufferType); if ((obj_buffer->num_elements != 1) || (obj_buffer->size != sizeof(VAEncPictureParameterBufferJPEG))) { return VA_STATUS_ERROR_UNKNOWN; } /* Lookup and get coded buffer */ pBuffer = (VAEncPictureParameterBufferJPEG *)obj_buffer->buffer_data; /* Parameters checking */ if (((pBuffer->pic_flags).bits.profile != 0) || /* Only "0 - Baseline" is supported */ ((pBuffer->pic_flags).bits.progressive != 0) || /* Only "0 - sequential" is supported */ ((pBuffer->pic_flags).bits.huffman != 1) || /* Only "1 - huffman" is supported */ ((pBuffer->pic_flags).bits.interleaved != 0) || /* Only "0 - non interleaved" is supported */ ((pBuffer->pic_flags).bits.differential != 0)) /* Only "0 - non differential" is supported */ return VA_STATUS_ERROR_INVALID_PARAMETER; if ((pBuffer->sample_bit_depth != 8) || /* Only 8-bits sample depth is supported */ (pBuffer->num_components != MTX_MAX_COMPONENTS) || /* Only 3 components setting is supported */ (pBuffer->quality > 100)) return VA_STATUS_ERROR_INVALID_PARAMETER; /* Set quality */ if (pBuffer->quality != 0) { /* Quality value is set */ CustomizeQuantizationTables(pQMatrix->aui8LumaQuantParams, pQMatrix->aui8ChromaQuantParams, pBuffer->quality); } ASSERT(ctx->ui16Width == pBuffer->picture_width); ASSERT(ctx->ui16FrameHeight == pBuffer->picture_height); ps_buf->coded_buf = BUFFER(pBuffer->coded_buf); free(pBuffer); obj_buffer->buffer_data = NULL; obj_buffer->size = 0; if (NULL == ps_buf->coded_buf) { drv_debug_msg(VIDEO_DEBUG_ERROR, "%s L%d Invalid coded buffer handle\n", __FUNCTION__, __LINE__); return VA_STATUS_ERROR_INVALID_BUFFER; } /* Map coded buffer */ vaStatus = psb_buffer_map(ps_buf->coded_buf->psb_buffer, (unsigned char **)&jpeg_ctx->jpeg_coded_buf.pMemInfo); if (vaStatus) { drv_debug_msg(VIDEO_DEBUG_ERROR, "ERROR: Map coded_buf failed!"); return vaStatus; } jpeg_ctx->jpeg_coded_buf.ui32Size = ps_buf->coded_buf->size; jpeg_ctx->jpeg_coded_buf.sLock = BUFFER_FREE; jpeg_ctx->jpeg_coded_buf.ui32BytesWritten = 0; if ((jpeg_ctx->jpeg_coded_buf.ui32Size) < (9 + 6 + (4 * 3))) { return VA_STATUS_ERROR_INVALID_BUFFER; } /* Assign coded buffer to each scan */ drv_debug_msg(VIDEO_DEBUG_GENERAL, "Assign coded buffer to each scan\n"); AssignCodedDataBuffers(jpeg_ctx); drv_debug_msg(VIDEO_DEBUG_GENERAL, "Coded buffer total size is %d," "coded segment size per scan is %d\n", jpeg_ctx->jpeg_coded_buf.ui32Size, jpeg_ctx->ui32SizePerCodedBuffer); /* Write JPEG headers to coded buffer */ drv_debug_msg(VIDEO_DEBUG_GENERAL, "Write JPEG Headers to coded buf\n"); pBufHeader = (BUFFER_HEADER *)jpeg_ctx->jpeg_coded_buf.pMemInfo; pBufHeader->ui32BytesUsed = 0; /* Not include BUFFER_HEADER*/ rc = PrepareHeader(jpeg_ctx, &jpeg_ctx->jpeg_coded_buf, sizeof(BUFFER_HEADER), IMG_TRUE); if (rc != IMG_ERR_OK) return VA_STATUS_ERROR_UNKNOWN; pBufHeader->ui32Reserved3 = PTG_JPEG_HEADER_MAX_SIZE;//Next coded buffer offset pBufHeader->ui32BytesUsed = jpeg_ctx->jpeg_coded_buf.ui32BytesWritten - sizeof(BUFFER_HEADER); drv_debug_msg(VIDEO_DEBUG_GENERAL, "sizeof(BUFFER_HEADER): %d, ui32BytesUsed :%d, ui32Reserved3: %d, ui32BytesWritten: %d\n", sizeof(BUFFER_HEADER), pBufHeader->ui32BytesUsed, pBufHeader->ui32Reserved3, jpeg_ctx->jpeg_coded_buf.ui32BytesWritten); return vaStatus; } static VAStatus tng_jpeg_RenderPicture( object_context_p obj_context, object_buffer_p *buffers, int num_buffers) { context_ENC_p ctx = (context_ENC_p) obj_context->format_data; VAStatus vaStatus = VA_STATUS_SUCCESS; int i; drv_debug_msg(VIDEO_DEBUG_GENERAL, "tng_jpeg_RenderPicture\n"); for (i = 0; i < num_buffers; i++) { object_buffer_p obj_buffer = buffers[i]; switch (obj_buffer->type) { case VAQMatrixBufferType: drv_debug_msg(VIDEO_DEBUG_GENERAL, "tng_jpeg_RenderPicture got VAEncSliceParameterBufferType\n"); vaStatus = ProcessQmatrixParam(ctx, obj_buffer); DEBUG_FAILURE; break; case VAEncPictureParameterBufferType: drv_debug_msg(VIDEO_DEBUG_GENERAL, "tng_jpeg_RenderPicture got VAEncPictureParameterBufferType\n"); vaStatus = ProcessPictureParam(ctx, obj_buffer); DEBUG_FAILURE; break; case VAEncSliceParameterBufferType: drv_debug_msg(VIDEO_DEBUG_GENERAL, "tng_jpeg_RenderPicture got VAEncSliceParameterBufferType\n"); drv_debug_msg(VIDEO_DEBUG_WARNING, "VAEncSliceParameterBufferType is ignored on TopazHP\n"); vaStatus = VA_STATUS_SUCCESS; DEBUG_FAILURE; break; default: vaStatus = VA_STATUS_ERROR_UNKNOWN; DEBUG_FAILURE; } } return vaStatus; } static VAStatus tng_jpeg_EndPicture( object_context_p obj_context) { IMG_UINT16 ui16BCnt; IMG_UINT32 rc = 0; VAStatus vaStatus = VA_STATUS_SUCCESS; IMG_UINT32 ui32NoMCUsToEncode = 0; IMG_UINT32 ui32RemainMCUs = 0; context_ENC_p ctx = (context_ENC_p) obj_context->format_data; TOPAZHP_JPEG_ENCODER_CONTEXT *jpeg_ctx_p = ctx->jpeg_ctx; tng_cmdbuf_p cmdbuf = (tng_cmdbuf_p)ctx->obj_context->tng_cmdbuf; context_ENC_mem *ps_mem = &(ctx->ctx_mem[ctx->ui32StreamID]); context_ENC_frame_buf *ps_buf = &(ctx->ctx_frame_buf); drv_debug_msg(VIDEO_DEBUG_GENERAL, "tng_jpeg_EndPicture\n"); IssueQmatix(jpeg_ctx_p); /* Compute the next scan to be sent */ ui32RemainMCUs = jpeg_ctx_p->sScan_Encode_Info.ui32NumberMCUsToEncode; drv_debug_msg(VIDEO_DEBUG_GENERAL, "ui32RemainMCUs: %d\n", ui32RemainMCUs); for (ui16BCnt = 0; (ui16BCnt < jpeg_ctx_p->sScan_Encode_Info.ui8NumberOfCodedBuffers) && (jpeg_ctx_p->sScan_Encode_Info.ui16SScan > 0); ui16BCnt++) { jpeg_ctx_p->sScan_Encode_Info.aBufferTable[ui16BCnt].ui16ScanNumber = jpeg_ctx_p->sScan_Encode_Info.ui16SScan--; jpeg_ctx_p->sScan_Encode_Info.aBufferTable[ui16BCnt].i8PipeNumber = (1 == jpeg_ctx_p->NumCores) ? 0 : ((ui16BCnt+1) % jpeg_ctx_p->NumCores); if (jpeg_ctx_p->sScan_Encode_Info.ui16SScan > 0) { ui32NoMCUsToEncode = jpeg_ctx_p->sScan_Encode_Info.ui32NumberMCUsToEncodePerScan; } else { // Final scan, may need fewer MCUs than buffer size, calculate the remainder ui32NoMCUsToEncode = ui32RemainMCUs; jpeg_ctx_p->sScan_Encode_Info.aBufferTable[ui16BCnt].i8PipeNumber = 0; } drv_debug_msg(VIDEO_DEBUG_GENERAL, "ui32NoMCUsToEncode: %d\n", ui32NoMCUsToEncode); //Send scan to MTX rc = IssueBufferToHW(jpeg_ctx_p, ui16BCnt, jpeg_ctx_p->sScan_Encode_Info.aBufferTable[ui16BCnt].i8PipeNumber, ui32NoMCUsToEncode); if (rc != IMG_ERR_OK) { vaStatus = VA_STATUS_ERROR_UNKNOWN; DEBUG_FAILURE; return vaStatus; } ui32RemainMCUs -= ui32NoMCUsToEncode; } psb_buffer_unmap(&cmdbuf->jpeg_pic_params); cmdbuf->jpeg_pic_params_p = NULL; psb_buffer_unmap(&cmdbuf->jpeg_header_mem); cmdbuf->jpeg_header_mem_p = NULL; psb_buffer_unmap(ps_buf->coded_buf->psb_buffer); jpeg_ctx_p->jpeg_coded_buf.pMemInfo = NULL; psb_buffer_unmap(&(ctx->bufs_writeback)); //tng__trace_cmdbuf(cmdbuf); if (tng_context_flush_cmdbuf(ctx->obj_context)) { vaStatus = VA_STATUS_ERROR_UNKNOWN; return vaStatus; } ctx->obj_context->frame_count++; return VA_STATUS_SUCCESS; } /* Add Restart interval termination (RSTm)to coded buf 1 ~ NumCores-1*/ static inline VAStatus tng_OutputResetIntervalToCB(IMG_UINT8 *pui8Buf, IMG_UINT8 ui8_marker) { if (NULL == pui8Buf) return VA_STATUS_ERROR_UNKNOWN; /*Refer to CCITT Rec. T.81 (1992 E), B.2.1*/ /*RSTm: Restart marker conditional marker which is placed between * entropy-coded segments only if restartis enabled. There are 8 unique * restart markers (m = 0 - 7) which repeat in sequence from 0 to 7, starting with * zero for each scan, to provide a modulo 8 restart interval count*/ *pui8Buf++ = 0xff; *pui8Buf = (ui8_marker & 0x7) | 0xD0; return 0; } VAStatus tng_jpeg_AppendMarkers(object_context_p obj_context, void *raw_coded_buf) { context_ENC_p ctx = (context_ENC_p) obj_context->format_data; TOPAZHP_JPEG_ENCODER_CONTEXT *jpeg_ctx_p = ctx->jpeg_ctx; IMG_UINT16 ui16BCnt; BUFFER_HEADER* pBufHeader; STREAMTYPEW s_streamW; void *pSegStart = raw_coded_buf; if (pSegStart == NULL) { return VA_STATUS_ERROR_UNKNOWN; } pBufHeader = (BUFFER_HEADER *)pSegStart; drv_debug_msg(VIDEO_DEBUG_GENERAL, "Number of Coded buffers %d, Per Coded Buffer size : %d\n", jpeg_ctx_p->sScan_Encode_Info.ui8NumberOfCodedBuffers, jpeg_ctx_p->ui32SizePerCodedBuffer); /*The first part of coded buffer contains JPEG headers*/ pBufHeader->ui32Reserved3 = PTG_JPEG_HEADER_MAX_SIZE; jpeg_ctx_p->jpeg_coded_buf.ui32BytesWritten = 0; for (ui16BCnt = 0; ui16BCnt < jpeg_ctx_p->sScan_Encode_Info.ui8NumberOfCodedBuffers; ui16BCnt++) { pBufHeader = (BUFFER_HEADER *)pSegStart; pBufHeader->ui32Reserved3 = PTG_JPEG_HEADER_MAX_SIZE + jpeg_ctx_p->ui32SizePerCodedBuffer * ui16BCnt ; drv_debug_msg(VIDEO_DEBUG_GENERAL, "Coded Buffer Part %d, size %d, next part offset: %d\n", ui16BCnt, pBufHeader->ui32BytesUsed, pBufHeader->ui32Reserved3); if (ui16BCnt > 0) { drv_debug_msg(VIDEO_DEBUG_GENERAL, "Append 2 bytes Reset Interval %d " "to Coded Buffer Part %d\n", ui16BCnt - 1, ui16BCnt); // OUTPUT RESTART INTERVAL TO CODED BUFFER tng_OutputResetIntervalToCB( (IMG_UINT8 *)((IMG_UINT32)pSegStart + sizeof(BUFFER_HEADER) + pBufHeader->ui32BytesUsed), ui16BCnt - 1); pBufHeader->ui32BytesUsed += 2; } jpeg_ctx_p->jpeg_coded_buf.ui32BytesWritten += pBufHeader->ui32BytesUsed; pSegStart = (void *)((IMG_UINT32)raw_coded_buf + pBufHeader->ui32Reserved3); } pBufHeader = (BUFFER_HEADER *)pSegStart; pBufHeader->ui32Reserved3 = 0; /*Last Part of Coded Buffer*/ jpeg_ctx_p->jpeg_coded_buf.ui32BytesWritten += pBufHeader->ui32BytesUsed; drv_debug_msg(VIDEO_DEBUG_GENERAL, "Coded Buffer Part %d, size %d, next part offset: %d\n", ui16BCnt, pBufHeader->ui32BytesUsed, pBufHeader->ui32Reserved3); s_streamW.Buffer = pSegStart; s_streamW.Offset = (sizeof(BUFFER_HEADER) + pBufHeader->ui32BytesUsed); fPutBitsToBuffer(&s_streamW, 2, END_OF_IMAGE); pBufHeader->ui32BytesUsed += 2; jpeg_ctx_p->jpeg_coded_buf.ui32BytesWritten += 2; drv_debug_msg(VIDEO_DEBUG_GENERAL, "Add two bytes to last part of coded buffer," " total: %d\n", jpeg_ctx_p->jpeg_coded_buf.ui32BytesWritten); return VA_STATUS_SUCCESS; } struct format_vtable_s tng_JPEGES_vtable = { queryConfigAttributes: tng_jpeg_QueryConfigAttributes, validateConfig: tng_jpeg_ValidateConfig, createContext: tng_jpeg_CreateContext, destroyContext: tng_jpeg_DestroyContext, beginPicture: tng_jpeg_BeginPicture, renderPicture: tng_jpeg_RenderPicture, endPicture: tng_jpeg_EndPicture };