RFX_MESSAGE* rfx_split_message(RFX_CONTEXT* context, RFX_MESSAGE* message, int* numMessages, int maxDataSize) { int i, j; UINT32 tileDataSize; RFX_MESSAGE* messages; maxDataSize -= 1024; /* reserve enough space for headers */ *numMessages = ((message->tilesDataSize + maxDataSize) / maxDataSize) * 4; messages = (RFX_MESSAGE*) calloc((*numMessages), sizeof(RFX_MESSAGE)); if (!messages) return NULL; j = 0; for (i = 0; i < message->numTiles; i++) { tileDataSize = rfx_tile_length(message->tiles[i]); if ((messages[j].tilesDataSize + tileDataSize) > ((UINT32) maxDataSize)) j++; if (!messages[j].numTiles) { messages[j].frameIdx = message->frameIdx + j; messages[j].numQuant = message->numQuant; messages[j].quantVals = message->quantVals; messages[j].numRects = message->numRects; messages[j].rects = message->rects; messages[j].tiles = (RFX_TILE**) malloc(sizeof(RFX_TILE*) * message->numTiles); messages[j].freeRects = FALSE; messages[j].freeArray = TRUE; } messages[j].tilesDataSize += tileDataSize; messages[j].tiles[messages[j].numTiles++] = message->tiles[i]; message->tiles[i] = NULL; } *numMessages = j + 1; context->frameIdx += j; message->numTiles = 0; for (i = 0; i < *numMessages; i++) { for (j = 0; j < messages[i].numTiles; j++) { } } return messages; }
static void rfx_write_tile(RFX_CONTEXT* context, wStream* s, RFX_TILE* tile) { UINT32 blockLen; blockLen = rfx_tile_length(tile); Stream_EnsureRemainingCapacity(s, blockLen); Stream_Write_UINT16(s, CBT_TILE); /* BlockT.blockType (2 bytes) */ Stream_Write_UINT32(s, blockLen); /* BlockT.blockLen (4 bytes) */ Stream_Write_UINT8(s, tile->quantIdxY); /* quantIdxY (1 byte) */ Stream_Write_UINT8(s, tile->quantIdxCb); /* quantIdxCb (1 byte) */ Stream_Write_UINT8(s, tile->quantIdxCr); /* quantIdxCr (1 byte) */ Stream_Write_UINT16(s, tile->xIdx); /* xIdx (2 bytes) */ Stream_Write_UINT16(s, tile->yIdx); /* yIdx (2 bytes) */ Stream_Write_UINT16(s, tile->YLen); /* YLen (2 bytes) */ Stream_Write_UINT16(s, tile->CbLen); /* CbLen (2 bytes) */ Stream_Write_UINT16(s, tile->CrLen); /* CrLen (2 bytes) */ Stream_Write(s, tile->YData, tile->YLen); /* YData */ Stream_Write(s, tile->CbData, tile->CbLen); /* CbData */ Stream_Write(s, tile->CrData, tile->CrLen); /* CrData */ }
RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects, int numRects, BYTE* data, int width, int height, int scanline) { int i, maxNbTiles, maxTilesX, maxTilesY; int xIdx, yIdx, regionNbRects; int gridRelX, gridRelY, ax, ay, bytesPerPixel; RFX_TILE* tile; RFX_RECT* rfxRect; RFX_MESSAGE* message = NULL; PTP_WORK* workObject = NULL; RFX_TILE_COMPOSE_WORK_PARAM *workParam = NULL; BOOL success = FALSE; REGION16 rectsRegion, tilesRegion; RECTANGLE_16 currentTileRect; const RECTANGLE_16 *regionRect; const RECTANGLE_16 *extents; assert(data); assert(rects); assert(numRects > 0); assert(width > 0); assert(height > 0); assert(scanline > 0); if (!(message = (RFX_MESSAGE*)calloc(1, sizeof(RFX_MESSAGE)))) return NULL; region16_init(&tilesRegion); region16_init(&rectsRegion); if (context->state == RFX_STATE_SEND_HEADERS) rfx_update_context_properties(context); message->frameIdx = context->frameIdx++; if (!context->numQuant) { if (!(context->quants = (UINT32*) malloc(sizeof(rfx_default_quantization_values)))) goto skip_encoding_loop; CopyMemory(context->quants, &rfx_default_quantization_values, sizeof(rfx_default_quantization_values)); context->numQuant = 1; context->quantIdxY = 0; context->quantIdxCb = 0; context->quantIdxCr = 0; } message->numQuant = context->numQuant; message->quantVals = context->quants; bytesPerPixel = (context->bits_per_pixel / 8); if (!computeRegion(rects, numRects, &rectsRegion, width, height)) goto skip_encoding_loop; extents = region16_extents(&rectsRegion); assert(extents->right - extents->left > 0); assert(extents->bottom - extents->top > 0); maxTilesX = 1 + TILE_NO(extents->right - 1) - TILE_NO(extents->left); maxTilesY = 1 + TILE_NO(extents->bottom - 1) - TILE_NO(extents->top); maxNbTiles = maxTilesX * maxTilesY; if (!(message->tiles = calloc(maxNbTiles, sizeof(RFX_TILE*)))) goto skip_encoding_loop; if (!setupWorkers(context, maxNbTiles)) goto skip_encoding_loop; if (context->priv->UseThreads) { workObject = context->priv->workObjects; workParam = context->priv->tileWorkParams; } regionRect = region16_rects(&rectsRegion, ®ionNbRects); if (!(message->rects = calloc(regionNbRects, sizeof(RFX_RECT)))) goto skip_encoding_loop; message->numRects = regionNbRects; for (i = 0, rfxRect = message->rects; i < regionNbRects; i++, regionRect++, rfxRect++) { int startTileX = regionRect->left / 64; int endTileX = (regionRect->right - 1) / 64; int startTileY = regionRect->top / 64; int endTileY = (regionRect->bottom - 1) / 64; rfxRect->x = regionRect->left; rfxRect->y = regionRect->top; rfxRect->width = (regionRect->right - regionRect->left); rfxRect->height = (regionRect->bottom - regionRect->top); for (yIdx = startTileY, gridRelY = startTileY * 64; yIdx <= endTileY; yIdx++, gridRelY += 64 ) { int tileHeight = 64; if ((yIdx == endTileY) && (gridRelY + 64 > height)) tileHeight = height - gridRelY; currentTileRect.top = gridRelY; currentTileRect.bottom = gridRelY + tileHeight; for (xIdx = startTileX, gridRelX = startTileX * 64; xIdx <= endTileX; xIdx++, gridRelX += 64) { int tileWidth = 64; if ((xIdx == endTileX) && (gridRelX + 64 > width)) tileWidth = width - gridRelX; currentTileRect.left = gridRelX; currentTileRect.right = gridRelX + tileWidth; /* checks if this tile is already treated */ if (region16_intersects_rect(&tilesRegion, ¤tTileRect)) continue; if (!(tile = (RFX_TILE*) ObjectPool_Take(context->priv->TilePool))) goto skip_encoding_loop; tile->xIdx = xIdx; tile->yIdx = yIdx; tile->x = gridRelX; tile->y = gridRelY; tile->scanline = scanline; tile->width = tileWidth; tile->height = tileHeight; ax = gridRelX; ay = gridRelY; if (tile->data && tile->allocated) { free(tile->data); tile->allocated = FALSE; } tile->data = &data[(ay * scanline) + (ax * bytesPerPixel)]; tile->quantIdxY = context->quantIdxY; tile->quantIdxCb = context->quantIdxCb; tile->quantIdxCr = context->quantIdxCr; tile->YLen = tile->CbLen = tile->CrLen = 0; if (!(tile->YCbCrData = (BYTE *)BufferPool_Take(context->priv->BufferPool, -1))) goto skip_encoding_loop; tile->YData = (BYTE*) &(tile->YCbCrData[((8192 + 32) * 0) + 16]); tile->CbData = (BYTE*) &(tile->YCbCrData[((8192 + 32) * 1) + 16]); tile->CrData = (BYTE*) &(tile->YCbCrData[((8192 + 32) * 2) + 16]); message->tiles[message->numTiles] = tile; message->numTiles++; if (context->priv->UseThreads) { workParam->context = context; workParam->tile = tile; if (!(*workObject = CreateThreadpoolWork( (PTP_WORK_CALLBACK)rfx_compose_message_tile_work_callback, (void*) workParam, &context->priv->ThreadPoolEnv))) { goto skip_encoding_loop; } SubmitThreadpoolWork(*workObject); workObject++; workParam++; } else { rfx_encode_rgb(context, tile); } if (!region16_union_rect(&tilesRegion, &tilesRegion, ¤tTileRect)) goto skip_encoding_loop; } /* xIdx */ } /* yIdx */ } /* rects */ success = TRUE; skip_encoding_loop: if (success && message->numTiles != maxNbTiles) { void* pmem = realloc((void*) message->tiles, sizeof(RFX_TILE*) * message->numTiles); if (pmem) message->tiles = (RFX_TILE**) pmem; else success = FALSE; } /* when using threads ensure all computations are done */ message->tilesDataSize = 0; workObject = context->priv->workObjects; for (i = 0; i < message->numTiles; i++) { tile = message->tiles[i]; if (context->priv->UseThreads) { if (*workObject) { WaitForThreadpoolWorkCallbacks(*workObject, FALSE); CloseThreadpoolWork(*workObject); } workObject++; } message->tilesDataSize += rfx_tile_length(tile); } region16_uninit(&tilesRegion); region16_uninit(&rectsRegion); if (success) return message; WLog_ERR(TAG, "%s: failed", __FUNCTION__); message->freeRects = TRUE; rfx_message_free(context, message); return NULL; }