This document gives you more information about the stream encoding and stream decoding method.
This tutorial explains how to encode and decode an image by passing pixel data block by block.
Required Background
The image is decoded / encoded
using imageconversion.dll and currently only
JPEG codec is supported for the streaming block method, so jpegcodec.dll is used from the Imaging Plugins component.
Introduction
An image is compressed into an image frame. This is decoded / encoded in one go which consumes more memory usage.
The Symbian JPEG codec now supports
enhanced functionality during the encode / decode operation using
Stream Encoding and Stream Decoding methods. In these methods an image
frame which is part of a compressed image can be divided into sub
blocks and these are encoded / decoded block by block of YUV pixel
data.
For decoder MImageConvStreamedDecode and TImageConvStreamedDecode are used to adapt
the streaming functionality. And for encoder MImageConvStreamedEncode and TImageConvStreamedEncode are used to adapt
the streaming functionality.
Note:- Only the Symbian JPEG codec supports decoding / encoding of an image using Stream Encoding and Stream Decoding methods which consumes less memory usage. No other Symbian codecs are modified to provide this support.
The Stream Encoding And Stream Decoding methods also supports cropping or scaling an image in sequence order or random order.
Setup and Configuration Requirements
For the encoder / the decoder to perform streaming you need to set up the navigation mode by using the streaming capabilities.
The streaming capabilites
for decoding are supported by TDecodeStreamCaps. For example you can obtain the optimum number of blocks through
streaming in a single request to get maximum performance by using
the parameter aOptimalBlocksPerRequest.
The streaming
capabilities for encoding are supported by the Image Processor Adaptation
Plug-in encoder. For example you can obtain the maximum number
of blocks through streaming by using the parameter aMaxBlocksPerRequest.
During the decode operation, the blocks or sub-frames can be navigated in the following order :
The sub-frames or blocks can be passed sequentially from top left of the image, left to right and top to bottom.
The blocks can be passed in random order to access each block.
During the encode operation,the blocks or sub-frames can be navigated :
The Following tasks are covered in this tutorial:
Basic Procedure For Stream Encoding And Stream Decoding
The high level steps to perform streaming block during encode and decode operation are as follows:
To create the
encoder call CImageEncoder::FileNewL() or CImageEncoder::DataNewL() and to create the decoder call CImageDecoder::FileNewL() or CImageDecoder::DataNewL().
For the encoder
streaming, requests a streaming interface through CImageEncoder::BlockStreamerL() and for the decoder streaming, request an interface through CImageDecoder::BlockStreamerL().
After requesting
the streaming interface, if the streaming extension is supported then
a T class pointer is returned which gives access to the JPEG codec
extension. TImageConvStreamedDecode gives the extension
functionality for stream decoding and TImageConvStreamedEncode gives the extension functionality for stream encoding.
To set the navigation mode for the encode streaming call TEncodeStreamCaps::TNavigation() and for the decode streaming
call TDecodeStreamCaps::TNavigation().
For decode streaming, the navigation possibilities are :
The blocks are returned from first to last.
The blocks are returned from last to first.
The blocks are returned randomly e.g. 18, 5, 20.
The blocks are returned in a random order but moving only from first to last e.g. 1, 5, 18.
The blocks are returned in a random order but moving only from last to first e.g. 18, 5, 1.
The navigation are shown below:
enum TNavigation
{
ENavigationSequentialForward = 0x01, // Sequential order from first to last
ENavigationSequentialBackwards = 0x10, // Sequential order from last to first
ENavigationRandom = 0x08, // random order
ENavigationRandomForward = 0x02, // random order frist to last
ENavigationRandomBackwards = 0x04, // random order last to first
}
For encode streaming, the navigation possibilities are:
The blocks are returned from first to last.
The blocks are returned in a random order but moving only from first to last e.g. 1, 5, 18.
The blocks are returned in a random order but moving only from last to first e.g. 1, 5, 18.
enum TNavigation
{
ENavigationSequentialForward = 0x01, // sequential order from first to last
ENavigationRandomForward = 0x02, // random order from first to last
EnavigationRandomBackwards = 0x04, // random order from last to first
};
To initialize
the stream decoder use TImageConvStreamedDecode::InitFrameL() and use its parameter.
To initialize
the encode streaming use TImageConvStreamedEncode::InitFrameL() and use its parameter.
During decode
function, the memory for storing CImageFrame must
be large enough to contain the decoded frame. To obtain the buffer
size for a particular decode function call TImageConvStreamedDecode::GetBufferSize().
The GetBufferSize() function returns:
To store the
image data in any format or layout which is described by a format
code UID, create an empty image frame using CImageFrame.
To set the image
frame size in pixels call CImageFrame::SetFrameSizeInPixels(). The parameter aFrameSize is used to returned aBlockSizeInPixels from GetBufferSize.
In decode streaming,
in order to start asynchronous call to return blocks use MImageConvStreamedDecode::GetNextBlocks().
In encode streaming,
in order to start asynchronous call to append blocks use MImageConvStreamedEncode::AppendBlocks().
Note: The memory optimization is mainly achieved
by GetNextBlocks and AppendBlocks applying effect to the image frame block. And the streaming is only
supported by the images which are multiples of Minimum Coded Unit
(MCU).
Example
The example below shows how to use stream encoding and stream decoding methods:
void CIclExample::StreamDecodeAndEncodeYuvFrameL(const TDesC& aSrcFileName, const TDesC& aDestFileName)
{
const TInt KFrameNumber = 0; // first frame
const TUid KFormat = KUidFormatYUV422Interleaved; // 422 sampling scheme
const TInt KNumBlocksToGet = 1;
RChunk chunk;
TSize streamBlockSizeInPixels;
TEncodeStreamCaps caps;
TInt numBlocksRead = 0;
TBool haveMoreBlocks = ETrue;
// Create the decoder, passing the filename. The image is recognised by the
// Image Conversion Library, an appropriate codec plugin loaded and the image headers parsed.
// If the image is not recognised or valid then the call will leave with an error
CImageDecoder* jpegImageDecoder = static_cast<CJPEGImageFrameDecoder*>( CImageDecoder::FileNewL(iFs, aSrcFileName));
CleanupStack::PushL(jpegImageDecoder);
// Create the encoder, passing the filename. The image is recognised by the
// Image Conversion Library, an appropriate codec plugin loaded and the image headers parsed.
// If the image is not recognised or valid then the call will leave with an error
CImageEncoder* jpegImageEncoder = static_cast<CJPEGImageFrameEncoder*>( CImageEncoder::FileNewL(iFs, aDestFileName, CImageEncoder::EOptionNone, KImageTypeJPGUid));
CleanupStack::PushL(jpegImageEncoder);
// Create encode & decode Block Streamer
TImageConvStreamedDecode* streamDecode = jpegImageDecoder->BlockStreamerL();
TImageConvStreamedEncode* streamEncode = jpegImageEncoder->BlockStreamerL();
TFrameInfo frameInfo = jpegImageDecoder->FrameInfo();
TSize frameSizeInPixels(frameInfo.iOverallSizeInPixels); //NOTE: The image used for decoding should be multiple of MCU(Minimum coded unit)
//set the navigation mode initialize decoder frame
TDecodeStreamCaps::TNavigation decodeNavigation = TDecodeStreamCaps::ENavigationSequentialForward;
streamDecode->InitFrameL(KFormat, KFrameNumber, decodeNavigation);
streamEncode->GetCapabilities(KFormat,caps);
TSize blockSizeInPixels = TSize(caps.MinBlockSizeInPixels());
//initialize encoder frame
TEncodeStreamCaps::TNavigation encodeNavigation = TEncodeStreamCaps::ENavigationSequentialForward;
streamEncode->InitFrameL(KFormat, KFrameNumber, frameSizeInPixels, blockSizeInPixels, encodeNavigation, NULL);
//When decoding, the buffer wrapped by the destination CImageFrame must be large enough to contain the decoded frame.
//GetBufferSize() should be used to obtain the buffer size required for a particular decode
TInt imageSizeInBytes = streamDecode->GetBufferSize(KFormat, streamBlockSizeInPixels, KNumBlocksToGet);
User::LeaveIfError(chunk.CreateGlobal(KRChunk, imageSizeInBytes, imageSizeInBytes, EOwnerProcess));
CleanupClosePushL(chunk);
// Create an empty imageframe
CImageFrame* imageFrame = CImageFrame::NewL(&chunk, imageSizeInBytes, 0);
CleanupStack::PushL(imageFrame);
imageFrame->SetFrameSizeInPixels(streamBlockSizeInPixels);
while(haveMoreBlocks)
{
// See Note 1
CActiveListener* activeListener = CreateAndInitializeActiveListenerLC();
//decoder get blocks
streamDecode->GetNextBlocks(activeListener->iStatus, *imageFrame, KNumBlocksToGet, numBlocksRead, haveMoreBlocks);
// See Note 2
CActiveScheduler::Start();
User::LeaveIfError(activeListener->iStatus.Int()); // decode complete.
//NOTE: Apply effects like adjust brightness etc in low memory conditions by use of streaming to the image frame block
// See Note 1
activeListener->InitializeActiveListener();
//encoder append blocks
streamEncode->AppendBlocks(activeListener->iStatus, *imageFrame, numBlocksRead);
// See Note 2
CActiveScheduler::Start();
User::LeaveIfError(activeListener->iStatus.Int()); // encode complete.
CleanupStack::PopAndDestroy(activeListener); // encodeActiveListener
}
CleanupStack::PopAndDestroy(4); // imageFrame, chunk, jpegImageEncoder and jpegImageDecoder
}