Implementing a Custom CODEC for the WindowsCodecs Extensibility System

As the name implies, a CODEC is a enCOder and DECoder. In the case of WindowsCodecs, Microsoft provides a set of APIs that allow our customers to implement their own CODEC for their custom image file format. Like this anyone who utilizes the WindowsCodecs APIs will be able to take advantage of all of the built-in CODECs as well as any custom CODECs installed on the machine. The WinFX Beta 1 SDK (with some minor modifications) provides the necessary headers and libs for taking the first steps in building your own CODEC.

Implementing a Decoder
There are 2 interfaces that you must implement:

  • IWICBitmapFrameDecode
  • IWICBitmapDecoder

Implementation is found in AitDecoder.h|cpp

Implementing an Encoder
There are 2 interfaces that you must implement:

  • IWICBitmapFrameEncode
  • IWICBitmapEncoder

Implementation is found in AitEncoder.h|cpp

Miscellaneous Glue
In addition to implementing the 4 interfaces, you must setup the registry in order for WindowsCodecs to know about the custom CODEC. Ideally, these can be added as part of your CODEC's MSI package or as part of the DllRegisterServer() so that when you register the DLL on the machine these registry entries get set.

Implementation is found in Main.cpp as well as some helpers in ClassFactory.h, RegistryValueManager.h, UnknownImpl.h

About the sample "AIT" CODEC
When my team and I were designing the "AIT" (Avalon Imaging Test) CODEC, we wanted to keep it as simple as possible. It doesn't utilize any compression methods. It's pretty much a straight "dump" of the pixel data to a persistent format. Also, we wanted to represent data as if this were a "production" CODEC, so concepts such as image blocks are similar to other formats, such as PNG. Within the AIT CODEC, a block takes the form of:

struct AIT_BLOCK
{
uint8_t name[4]; // used to distinguish the type of block
// (first 3 bytes are ASCII, last byte must be 0)
uint32_t frame_number; // specifies which frame in the
// image this data should be applied to
uint32_t size; // gives the number of bytes in
// the data section of the block
uint8_t data[size]; // gives the raw data of the block
// (must be interprested based upon
// the name of the block)
};

There are 6 types of blocks that the AIT CODEC support -- AIT, COL, FRA, PAL, PRE, THU

AIT Block
This block must be the first block in the file and must be specified only once. It may be regarded as the header of AIT files.
The data section of this block takes the form:

struct AIT_BLOCK_DATA
{
Uint32_t num_frames; // number of frames in the images (permitted to be 0)
};

COL Block
This block specifies a color context to be applied either globally to the image (when AIT_BLOCK.frame_number == 0xFFFFFFFF) or to a frame (when AIT_BLOCK.frame_number != 0xFFFFFFFF).
The field AIT_BLOCK.size specifies the size in bytes of the ICM profile to be used in this color context.
The data section is the value of those bytes.

FRA Block
This block specifies the bitmap data of a frame. The AIT_BLOCK.frame_number must be a value in the range [0, N) where N is the number of frames in the image (as specified in the AIT block).
The data section of this block takes the form:

struct FRA_BLOCK_DATA
{
BITMAP_SOURCE_DATA bitmap_source;
};

where BITMAP_SOURCE_DATA takes the form:

struct BITMAP_SOURCE_DATA
{
uint32_t width; // width dimension of the image
uint32_t height; // height dimension of the image
double dpi_x; // resolution (pixels/inch) of image in X direction
double dpi_y; // resolution (pixels/inch) of image in Y direction
uint32_t stride; // the number of bytes needed to
// encode one scanline of the bitmap
GUID pixel_format; // the GUID of the pixel format of this bitmap
// valid values include those recognized
// in wincodec.h (GUID_WICPixelFormat*)
uint8_t bitmap_data[stride * height]; // all data values one scanline at a time beginning
// at the top-most scanline and continuing
// to the bottom-most scanline
};

(Here, a double is an IEEE 64-bit floating-point number and GUID is 16 bytes used to uniquely identify an object.)
A FRA block, therefore, is simply the BITMAP_SOURCE_DATA needed to represent that frame.
BITMAP_SOURCE_DATA contains a variety of fields.

PAL Block
This block specifies a palette to be either applied to the image as a whole or to an individual frame (using the same logic as outlined in the COL block).
The data section of this block takes the form:

struct PAL_BLOCK_DATA
{
uint32_t num_colors; // number of colors in this palette (must be > 0)
WICColor colors[num_colors]; // gives those colors as WICColors (defined in wincodec.h)
};

PRE Block
This block specifies a preview bitmap that may be applied to the image as a whole (AIT_BLOCK.frame_number must equal 0xFFFFFFFF).
Its data section is simply a BITMAP_SOURCE_DATA (similar to a FRA block).

THU Block
This block specifies a thumbnail bitmap the may be applied to the entire image or a single frame (as specified in the save rules as COL’s).
Its data section is simply a BITMAP_SOURCE_DATA (similar to a FRA block).

Acknowledgements
This CODEC was originally written by one of the testers on my team, Frank Krueger (but has since left Microsoft). Also, the code was reviewed by our development leads, Rajat Goel and Thomas Olsen. Many thanks to all of them for their help and effort in getting this sample posted.

 

CODE (Beta 1): AitCodec.zip

BETA 1 SDK work around: UpdatedInclude.zip