There is a lot of support in C# for image conversion and compression, but I have never found a good tool to convert images into the MPEG format. I wish someone had done it for me, but since they didn't I wrote a class called
MPEGFunctions that provides the functions you need to convert a bitmap image to an MPEG1 I Frame. The code is functional but definitely not optimized or efficient. I think the
MPEGFunctions class and the provided sample application are a pretty good learning tool if you want to learn more about MPEG image compression.
There are a couple reasons why I needed a program like this. The first is that I have some MPEG animations on my web site, and I wanted to put up a short title screen at the beginning of the video clips. I can create a title screen using something like Microsoft Paint, convert it to an MPEG sequence of 2 second duration, and then play it with Windows Media Player (Media Player won't display JPEGs but will display my MPEG sequences). Another reason is I work with digital set top boxes, and I needed a way to create MPEG still frames that the boxes could display. Set top boxes are good at rendering MPEG but usually can't display JPEGs.
The MPEG1 standard (ISO/IEC 11172 Part 2) describes the process used to encode and compress an image into the MPEG1 format. A good tutorial link I found on the web that helped me a lot can be found here:
or do a Google search on: jpeg dct cmpt365.
The source code for the
MPEGFunctions class is in the file named Class1.cs. The source code for the
ImageFunctions class is in the ImageFunctions.cs file.
The simplest MPEG frame type is the I Frame. To convert an image to an MPEG I Frame you need to start with an RGB bitmap and go through the following steps:
- Pad the bitmap in both the height and width dimensions so that the bitmap dimensions are even multiples of 16. You need to do this because the basic building block of an MPEG image is a 16x16 pixel macro block. Use the
- Break the image into 16x16 pixel macro blocks.
- For each macroblock create 4 8x8 pixel Y blocks, and sub sample the macro block to create 1 8x8 pixel CR block and 1 8x8 pixel
CBblock. Convert the RGB values for the pixels into Y, CR, and CB color components. Use the
- Calculate the Discrete Cosine Transform (DCT) for each block. Use the
- Quantize the DCT coefficients. Use the
- Rearrange the DCT coefficients for each block using a zigzag scan. Use the
- Calculate the Huffman Code sequences for the DC DCT coefficients. Use the
- Calculate the Huffman Code sequences for the AC DCT coefficients. Use the
- Repeat steps 3 through 8 for each macro block in the image.
- Write the MPEG headers, Huffman Codes, and MPEG trailers to a memory stream, file, or other output format.
Using the code
The sample application shows how to use the
- Use File->Open to select any C# supported image format (GIF, JPEG, BMP, etc.). The image will be placed into pictureBox1. If the image is smaller than 352x352 pixels it will be displayed at its normal size. If it is bigger, it will be stretched/squeezed to fit in the 352x352 picture box. The image will be padded if necessary to make the dimensions evenly divisible by 16.
- If you select WriteToFile->MPEG IFrame the image will be converted to an MPEG1 IFrame and written to the selected output file. You can open the output file with Windows Media Player and it will display.
- If you select WriteToFile->MPEG Sequence the image will be converted to an IFrame. The converted image will be repeated for the number of frames selected in the dialog box. The entire sequence will be written to the selected output file. You can open the output file with Windows Media Player and it will play at a rate of 30 frames per second.
- If you click on a location in pictureBox1 the associated 16x16 pixel macroblock will be displayed in pictureBox2. The macroblock is stretched to fit the pictureBox2 dimensions.
- If you select the "Block Details" button you will be taken to a new dialog box where you can see the R, G, and B pixel values for the macroblock.
- If you select the "Convert To YPrPb" button you will be taken to a new dialog box where you can see the Y, Pr, and Pb values for the macroblock.
- If you select the "Calculate DCT" button you will be taken to a new dialog box where the DCT transformed values for the selected block will be displayed.
- If you select the "Quantize" button you can see the results of the quantization step.
- If you select the "ZigZag Order" button you can see the results of reordering the DCT coefficients.
- If you select "DC Encode" you can see the binary string produced by Huffman encoding the DC value.
- If you select "AC Encode" you can see the binary string produced by Huffman encoding the AC values.
Points of Interest
MPEG I Frames are very similar to JPEG images, in fact the process to create a JPEG is virtually identical to MPEG. The syntax of the final bitstream is different, but with some simple changes you could turn the
MPEGFunctions class into a
JPEGFunctions class. However, in C# it is so simple to save images as JPEGs that it really isn't necessary. You can see how simple it is to convert a bitmap to JPEG in my sample application in the
MPEG is not really designed to be a format for single image compression. It is actually supposed to be used for video compression, and a lot of its usefulness comes from using previous and future video frames to make predictions for what any single video frame will look like. These are called P and B frames and allow video to be compressed even more efficiently than if only I Frames are used.
So far I can only do MPEG I frames, but I hope to keep going with this project and add the functions needed to create MPEG P and B frames. I will also create a
JPEGFunctions class someday that is similar to the
MPEGFunctions class. Hopefully in 3 months or so there will be an update to this project.