Virtual Developer Workshop: Containerized Development with Docker
This project is built to be used as a library to perform image processing on AVI files through exclusive use of Microsoft AVIFile API. The main task this library is built for is defined below:
- Open AVI file on a disk
- Read AVI video stream, frame by frame, as raw RGB data
- Perform some processing on raw image data
- Save the resulting video, frame by frame, into another AVI file
The library consists of a single implementation file "RawAVIStream.cpp" and a single header file "RawAVIStream.h". In advance to the core files there is a sample code that uses this library in "test.cpp".
The code is built with "Microsoft Visual Studio 2008, 9.0.30729.1 SP" and "Microsoft Platform SDK for Windows XP SP2". All the relevant files are included, except codecs, MSVCRT redistributable, etc.
Following is an explanation on how the API is used.
Reading from an AVI FileHere is the minimal code needed to open an AVI file and initiate reading raw data:
// Error handling is intentionally leaved out for clarity PAVISTREAM ppavi; AVIFileInit(); AVIStreamOpenFromFile(&ppavi, filename, streamtypeVIDEO, 0, OF_READ, NULL); BITMAPINFOHEADER bi; long format_length = sizeof(bi); AVIStreamReadFormat(ppavi, 0, &bi, &format_length); bi.biBitCount = 24; bi.biCompression = BI_RGB; bi.biSizeImage = 0; PGETFRAME getframe = AVIStreamGetFrameOpen(ppavi, avi->bi); AVIStreamRelease(ppavi);
The main function in this code block is AVIStreamGetFrameOpen. In case this function runs successfully, we have a pointer that allows us to read video data, frame by frame, like this:
void *buffer = AVIStreamGetFrame(avi->getframe, index); CopyMemory(target, (BYTE*)buffer + ((BITMAPINFOHEADER*)buffer)->biSize, ((BITMAPINFOHEADER*)buffer)->biSizeImage);
The auxiliary function used is AVIStreamReadFormat. Obviously, we can fill-in BITMAPINFOHEADER without this function. However, we have to determine the frame size somehow. In this code we use AVIStreamOpenFromFile because we are only interested in video processing. The alternative to this call is AVIFileOpen/AVIFileGetStream.
Writing into an AVI File
Creating an uncompressed AVI file from a set of raw data frames is performed using the same API:
// Error handling is intentionally leaved out for clarity BITMAPINFOHEADER bi; PAVIFILE pavifile; AVISTREAMINFO info; PAVISTREAM ppavi; AVIFileInit(); // Create empty AVI file AVIFileOpen(&pavifile, filename, OF_WRITE | OF_CREATE, NULL); // Create a video stream with minimum data needed. ZeroMemory(&info, sizeof(info)); info.fccType = streamtypeVIDEO; info.dwScale = 1; info.dwRate = 25; // This is rather arbitrary, although inspired by PAL TV standard AVIFileCreateStream(pavifile, &ppavi, &info); AVIFileRelease(pavifile); // Set data format to raw RGB, compatible to the format specified in RawAVIReader above. // Unfortunately, we can't specify MPEG compression, although MPEG schema is designed // for streaming. If we do specify compression, it must be done outside somehow. // We specify only minimal data needed to render a valid AVI video. ZeroMemory(&bi, sizeof(bi)); bi.biSize = sizeof(bi); bi.biWidth = width; bi.biHeight = height; bi.biPlanes = 1; bi.biBitCount = 24; bi.biCompression = BI_RGB; bi.biXPelsPerMeter = 1000; bi.biYPelsPerMeter = 1000; AVIStreamSetFormat(ppavi, 0, &bi, sizeof(bi));
After this code is performed, we have a variable 'ppavi' pointing into a valid AVI stream handler. Having this handler, we do:
BYTE *frameRGB = new BYTE[3 * width * height]; ... fillInTheFrame(frameRGB, width, height); // What-ever does it mean AVIStreamWrite(ppavi, index, 1, frameRGB, 3 * width * height, 0, NULL, NULL);
In advance of the core task of encoding/decoding raw AVI data, this library implements a stand-alone function that compresses one file into another using the Microsoft implemented MPEG codec. The choice
options.fccHandler = mmioFOURCC('M','S','V','C');
is taken from MSDN and is thought to be found on most Windows machines. The simplest use of this codec is:
AVICOMPRESSOPTIONS options; PAVISTREAM ppavi; AVIStreamOpenFromFile(&ppavi, source, streamtypeVIDEO, 0, OF_READ, NULL); memset(&options, 0, sizeof(options)); options.fccType = streamtypeVIDEO; options.fccHandler = mmioFOURCC('M','S','V','C'); options.dwKeyFrameEvery = 2; options.dwQuality = 1; options.dwFlags = AVICOMPRESSF_KEYFRAMES; AVISave(target, NULL, NULL, 1, ppavi, &options);