Click here to Skip to main content
11,930,788 members (53,623 online)
Click here to Skip to main content
Add your own
alternative version


116 bookmarked

Steganography IV - Reading and Writing AVI files

, 19 May 2004 CPOL
Rate this:
Please Sign up or sign in to vote.
An article about hiding bytes in the bitmap frames of uncompressed AVI files.


The video stream in an AVI file is nothing more than a sequence of bitmaps. This article is about extracting these bitmaps and re-building the stream, in order to hide a message in the video.


Before reading this article, you should have read at least part one, Steganography - Hiding messages in the Noise of a Picture. This one uses the application described in parts 1-3, but you don’t need the extended features to understand it.

Reading the Video Stream

The Windows AVI library is a set of functions in avifil32.dll. Before it is ready to use, it has to be initialized with AVIFileInit. AVIFileOpen opens the file, AVIFileGetStream finds the video stream. Each of these functions allocates memory which has to be released.

//Initialize the AVI library
public static extern void AVIFileInit();

//Open an AVI file
[DllImport("avifil32.dll", PreserveSig=true)]
public static extern int AVIFileOpen(
    ref int ppfile,
    String szFile,
    int uMode,
    int pclsidHandler);

//Get a stream from an open AVI file
public static extern int AVIFileGetStream(
    int pfile,
    out IntPtr ppavi,  
    int fccType,       
    int lParam);

//Release an open AVI stream
public static extern int AVIStreamRelease(IntPtr aviStream);

//Release an ope AVI file
public static extern int AVIFileRelease(int pfile);

//Close the AVI library
public static extern void AVIFileExit();

Now we are able to open an AVI file and get the video stream. AVI files can contain many streams of four different types (Video, Audio, Midi and Text). Usually there is only one stream of each type, and we are only interested in the video stream.

private int aviFile = 0;
private IntPtr aviStream;

public void Open(string fileName) {
    AVIFileInit(); //Intitialize AVI library
    //Open the file
    int result = AVIFileOpen(
        ref aviFile,
        OF_SHARE_DENY_WRITE, 0);
    //Get the video stream
    result = AVIFileGetStream(
        out aviStream,
        streamtypeVIDEO, 0);

Before we start reading the frames, we must know what exactly we want to read:

  • Where does the first frame begin?
  • How many frames are available?
  • What is the height/width of the images?

The AVI library contains a function for every question.

//Get the start position of a stream
[DllImport("avifil32.dll", PreserveSig=true)]
public static extern int AVIStreamStart(int pavi);

//Get the length of a stream in frames
[DllImport("avifil32.dll", PreserveSig=true)]
public static extern int AVIStreamLength(int pavi);

//Get header information about an open stream
public static extern int AVIStreamInfo(
    int pAVIStream,
    ref AVISTREAMINFO psi,
    int lSize);

With these functions we can fill a BITMAPINFOHEADER structure. To extract the images, we need three more functions.

//Get a pointer to a GETFRAME object (returns 0 on error)
public static extern int AVIStreamGetFrameOpen(
    IntPtr pAVIStream,

//Get a pointer to a packed DIB (returns 0 on error)
public static extern int AVIStreamGetFrame(
    int pGetFrameObj,
    int lPos);

//Release the GETFRAME object
public static extern int AVIStreamGetFrameClose(int pGetFrameObj);

Finally we are ready to decompress the frames...

//get start position and count of frames
int firstFrame = AVIStreamStart(aviStream.ToInt32());
int countFrames = AVIStreamLength(aviStream.ToInt32());

//get header information            
result = AVIStreamInfo(aviStream.ToInt32(), ref streamInfo,

//construct the expected bitmap header
bih.biBitCount = 24;
bih.biCompression = 0; //BI_RGB;
bih.biHeight = (Int32)streamInfo.rcFrame.bottom;
bih.biWidth = (Int32)streamInfo.rcFrame.right;
bih.biPlanes = 1;
bih.biSize = (UInt32)Marshal.SizeOf(bih);

//prepare to decompress DIBs (device independend bitmaps)
int getFrameObject = AVIStreamGetFrameOpen(aviStream, ref bih);


//Export the frame at the specified position
public void ExportBitmap(int position, String dstFileName){
    //Decompress the frame and return a pointer to the DIB
    int pDib = Avi.AVIStreamGetFrame(getFrameObject, firstFrame + position);

    //Copy the bitmap header into a managed struct
    bih = (BITMAPINFOHEADER)Marshal.PtrToStructure(new IntPtr(pDib),
    //Copy the image
    byte[] bitmapData = new byte[bih.biSizeImage];
    int address = pDib + Marshal.SizeOf(bih);
    for(int offset=0; offset<bitmapData.Length; offset++){
        bitmapData[offset] = Marshal.ReadByte(new IntPtr(address));

    //Copy bitmap info
    byte[] bitmapInfo = new byte[Marshal.SizeOf(bih)];
    IntPtr ptr;
    ptr = Marshal.AllocHGlobal(bitmapInfo.Length);
    Marshal.StructureToPtr(bih, ptr, false);
    address = ptr.ToInt32();
    for(int offset=0; offset<bitmapInfo.Length; offset++){
        bitmapInfo[offset] = Marshal.ReadByte(new IntPtr(address));

...and store them in bitmap files.

    //Create file header
    bfh.bfType = Avi.BMP_MAGIC_COOKIE;
    //size of file as written to disk

    bfh.bfSize = (Int32)(55 + bih.biSizeImage);
    bfh.bfOffBits = Marshal.SizeOf(bih) + Marshal.SizeOf(bfh);

    //Create or overwrite the destination file
    FileStream fs = new FileStream(dstFileName, System.IO.FileMode.Create);
    BinaryWriter bw = new BinaryWriter(fs);

    //Write header
    //Write bitmap info
    //Write bitmap data
} //end of ExportBitmap

The application can use the extracted bitmaps just like any other image file. If one carrier file is an AVI video, it extracts the first frame to a temporary file, opens it and hides a part of the message. Then it writes the resulting bitmap to a new video stream, and continues with the next frame. After the last frame the application closes both video files, deletes the temporary bitmap file, and continues with the next carrier file.

Writing to a Video Stream

When the application opens an AVI carrier file, it creates another AVI file for the resulting bitmaps. The new video stream must have the same size and frame rate as the original stream, so we cannot create it in the Open() method. When the first bitmap arrives, we know the frame size and are able to create a video stream. The functions to create streams and write frames are AVIFileCreateStream, AVIStreamSetFormat and AVIStreamWrite:

//Create a new stream in an open AVI file
public static extern int AVIFileCreateStream(
    int pfile,
    out IntPtr ppavi, 
    ref AVISTREAMINFO ptr_streaminfo);

//Set the format for a new stream
public static extern int AVIStreamSetFormat(
    IntPtr aviStream, Int32 lPos, 
    ref BITMAPINFOHEADER lpFormat, Int32 cbFormat);

//Write a sample to a stream
public static extern int AVIStreamWrite(
    IntPtr aviStream, Int32 lStart, Int32 lSamples, 
    IntPtr lpBuffer, Int32 cbBuffer, Int32 dwFlags, 
    Int32 dummy1, Int32 dummy2);

Now we can create a stream...

//Create a new video stream
private void CreateStream() {
    //describe the stream to create
    strhdr.fccType = this.fccType; //mmioStringToFOURCC("vids", 0)
    strhdr.fccHandler = this.fccHandler; //"Microsoft Video 1"
    strhdr.dwScale = 1;
    strhdr.dwRate = frameRate;
    strhdr.dwSuggestedBufferSize = (UInt32)(height * stride);
    //use highest quality! Compression destroys the hidden message.
    strhdr.dwQuality = 10000;
    strhdr.rcFrame.bottom = (UInt32)height;
    strhdr.rcFrame.right = (UInt32)width;
    strhdr.szName = new UInt16[64];
    //create the stream
    int result = AVIFileCreateStream(aviFile, out aviStream, ref strhdr);

    //define the image format
    bi.biSize      = (UInt32)Marshal.SizeOf(bi);
    bi.biWidth     = (Int32)width;
    bi.biHeight    = (Int32)height;
    bi.biPlanes    = 1;
    bi.biBitCount  = 24;
    bi.biSizeImage = (UInt32)(this.stride * this.height);

    //format the stream
    result = Avi.AVIStreamSetFormat(aviStream, 0, ref bi, Marshal.SizeOf(bi));

...and write video frames.

//Create an empty AVI file
public void Open(string fileName, UInt32 frameRate) {
    this.frameRate = frameRate;

    int hr = Avi.AVIFileOpen(
        ref aviFile, fileName, 
        OF_WRITE | OF_CREATE, 0);

//Add a sample to the stream - for first sample: create the stream 
public void AddFrame(Bitmap bmp) {
    BitmapData bmpDat = bmp.LockBits(
        new Rectangle(0, 0, bmp.Width, bmp.Height),

    //this is the first frame - get size and create a new stream
    if (this.countFrames == 0) {
        this.stride = (UInt32)bmpDat.Stride;
        this.width = bmp.Width;
        this.height = bmp.Height;
        CreateStream(); //a method to create a new video stream

    //add the bitmap to the stream
    int result = AVIStreamWrite(aviStream,
        countFrames, 1, 
        bmpDat.Scan0, //pointer to the beginning of the image data
        (Int32) (stride  * height), 
        0, 0, 0); 

    this.countFrames ++;

That's all we need to read and write video streams. Non-video streams and compression are not interesting at the moment, because compression destroys the hidden message by changing colours, and sound would make the files even larger - uncompressed AVI files are big enough! Wink | ;-)

Changes in CryptUtility

The HideOrExtract() method used to load all carrier images at once. This was no good from the beginning, and now it became impossible. From now on HideOrExtract() loads only one bitmap, and disposes it before loading the next one. The currently used carrier image - simple bitmap or extracted AVI frame - is stored in a BitmapInfo structure, which is passed around by ref.
public struct BitmapInfo{
    //uncompressed image
    public Bitmap bitmap;
    //position of the frame in the AVI stream, -1 for non-avi bitmaps
    public int aviPosition;
    //count of frames in the AVI stream, or 0 for non-avi bitmaps
    public int aviCountFrames;
    //path and name of the bitmap file
    //this file will be deleted later, if aviPosition is 0 or greater
    public String sourceFileName;
    //how many bytes will be hidden in this image
    public long messageBytesToHide;

    public void LoadBitmap(String fileName){
        bitmap = new Bitmap(fileName);
        sourceFileName = fileName;

Whenever MovePixelPosition moves the position into the next carrier bitmap, it checks the field aviPosition. If aviPosition is < 0, it saves and disposes the bitmap. If aviPosition is 0 or greater, it is a frame in an AVI stream. It is not saved to a file, but added to the open AVI stream. If the bitmap was a simple image or the last frame of an AVI stream, the method opens the next carrier file. If there are more frames in the AVI stream, is exports and loads the next bitmap.

Using the code

There are three new classes in the project:

  • AviReader opens existing AVI files and copies frames to bitmap files.
  • AviWriter creates new AVI files and combines bitmaps to a video stream.
  • Avi contains the function declarations and structure definitions.


Thanks to Shrinkwrap Visual Basic, for the "Visual Basic AVIFile Tutorial". The examples could not be easily converted to VB.NET or C#, but they gave me important hints on how to copy DIBs.

Thanks to Rene N., who posted an AviWriter class in microsoft.public.dotnet.languages.csharp.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Corinna John
Software Developer
Germany Germany
Corinna lives in Hannover/Germany (CeBIT City) and works as a Delphi developer, though her favorite language is C#.

You may also be interested in...

Comments and Discussions

GeneralRe: could you please this code ??? Pin
quang moi 124-Jun-10 2:39
memberquang moi 124-Jun-10 2:39 
GeneralRe: could you please explain for this code ??? Pin
quang moi 124-Jun-10 3:44
memberquang moi 124-Jun-10 3:44 
QuestionHow I could compress the Bitmaps that I put in the AVI file Pin
molinarius7-May-10 5:44
membermolinarius7-May-10 5:44 
AnswerRe: How I could compress the Bitmaps that I put in the AVI file Pin
Corinna John24-Jun-10 0:03
memberCorinna John24-Jun-10 0:03 
Generalmany frames are ignored Pin
CryproKit29-Apr-10 23:58
memberCryproKit29-Apr-10 23:58 
GeneralRe: many frames are ignored Pin
Corinna John30-Apr-10 11:57
memberCorinna John30-Apr-10 11:57 
GeneralRe: many frames are ignored Pin
CryproKit2-May-10 6:17
memberCryproKit2-May-10 6:17 
GeneralRe: many frames are ignored Pin
CryproKit1-Jun-10 4:57
memberCryproKit1-Jun-10 4:57 
GeneralRe: many frames are ignored Pin
Corinna John1-Jun-10 5:17
memberCorinna John1-Jun-10 5:17 
GeneralRe: many frames are ignored Pin
CryproKit5-Jun-10 17:18
memberCryproKit5-Jun-10 17:18 
GeneralError:The instruction at "0x10001862" referenced memory at "0x00000004". The memory could not be read Pin
samwitwicky13-Apr-10 22:06
membersamwitwicky13-Apr-10 22:06 
Questiongetting Exception on running the code Pin
samwitwicky15-Mar-10 19:39
membersamwitwicky15-Mar-10 19:39 
AnswerRe: getting Exception on running the code Pin
Corinna John15-Mar-10 23:18
memberCorinna John15-Mar-10 23:18 
GeneralRe: getting Exception on running the code Pin
samwitwicky17-Mar-10 5:07
membersamwitwicky17-Mar-10 5:07 
GeneralThe AVI seems to work but it's black Pin
dereklac20-Dec-09 19:04
memberdereklac20-Dec-09 19:04 
Generalvideo steganography Pin
lakshman5079-Dec-09 23:16
memberlakshman5079-Dec-09 23:16 
QuestionSample examples for hiding a text in to mp3 file Pin
Ganesht_200030-Nov-09 1:50
memberGanesht_200030-Nov-09 1:50 
GeneralUpside down Pin
peterfortuin10-Sep-09 2:54
memberpeterfortuin10-Sep-09 2:54 
QuestionVideo compression [modified] Pin
DanInManchester21-Jun-09 1:23
memberDanInManchester21-Jun-09 1:23 
AnswerRe: Video compression Pin
Corinna John21-Jun-09 1:34
memberCorinna John21-Jun-09 1:34 
GeneralRe: Video compression Pin
DanInManchester30-Jun-09 6:41
memberDanInManchester30-Jun-09 6:41 
GeneralTransitions Pin
danstoke29-May-09 20:08
memberdanstoke29-May-09 20:08 
GeneralRe: Transitions Pin
Corinna John30-May-09 12:58
memberCorinna John30-May-09 12:58 
QuestionCan't load some AVIs [modified] Pin
Member 424905518-Apr-09 13:40
memberMember 424905518-Apr-09 13:40 
QuestionChanging the AVI size ? Pin
Mohammad Dayyan1-Apr-09 10:49
memberMohammad Dayyan1-Apr-09 10:49 
GeneralExcellent Pin
Mohammad Dayyan27-Mar-09 6:15
memberMohammad Dayyan27-Mar-09 6:15 
QuestionI've a few questions Pin
UnknownIsMyName22-Jan-09 12:12
memberUnknownIsMyName22-Jan-09 12:12 
AnswerRe: I've a few questions Pin
Corinna John23-Jan-09 9:11
memberCorinna John23-Jan-09 9:11 
GeneralRe: I've a few questions Pin
UnknownIsMyName24-Jan-09 7:11
memberUnknownIsMyName24-Jan-09 7:11 
Generalvideo streaming Pin
sdeniz26-Sep-08 4:49
membersdeniz26-Sep-08 4:49 
GeneralAvi to BMp Pin
#Jet1-Apr-08 3:25
member#Jet1-Apr-08 3:25 
QuestionBMP files Pin
Derek Loftis17-Nov-07 16:12
memberDerek Loftis17-Nov-07 16:12 
AnswerRe: BMP files Pin
Corinna John18-Nov-07 7:43
memberCorinna John18-Nov-07 7:43 
GeneralRe: BMP files [modified] Pin
Derek Loftis18-Nov-07 15:20
memberDerek Loftis18-Nov-07 15:20 
Generalplease reply Pin
suvarna_bvb13-May-07 23:01
membersuvarna_bvb13-May-07 23:01 
Generalplzzz reply... Pin
suvarna_bvb10-May-07 19:54
membersuvarna_bvb10-May-07 19:54 
GeneralRe: plzzz reply... Pin
Corinna John11-May-07 5:32
memberCorinna John11-May-07 5:32 
GeneralNeed the help.. Pin
atans8-May-07 17:32
memberatans8-May-07 17:32 
GeneralRe: Need the help.. Pin
Corinna John9-May-07 3:05
memberCorinna John9-May-07 3:05 
Generalneed urgent help... [modified] Pin
suvarna_bvb26-Apr-07 19:50
membersuvarna_bvb26-Apr-07 19:50 
GeneralRe: need urgent help... Pin
Corinna John11-May-07 5:29
memberCorinna John11-May-07 5:29 
QuestionAVI steganography Pin
Musharaf Zaheer Qureshi30-Jan-07 20:53
memberMusharaf Zaheer Qureshi30-Jan-07 20:53 
AnswerRe: AVI steganography Pin
Corinna John31-Jan-07 8:06
memberCorinna John31-Jan-07 8:06 
GeneralRe: AVI steganography Pin
lonelywind198229-Aug-07 18:32
memberlonelywind198229-Aug-07 18:32 
GeneralRe: AVI steganography Pin
Corinna John29-Aug-07 21:09
memberCorinna John29-Aug-07 21:09 
GeneralAVI files Pin
caohieu13-Dec-06 0:13
membercaohieu13-Dec-06 0:13 
GeneralRe: AVI files Pin
Corinna John13-Dec-06 6:11
memberCorinna John13-Dec-06 6:11 
GeneralRe: AVI files Pin
caohieu9-Jan-07 18:13
membercaohieu9-Jan-07 18:13 
GeneralDon't work with avi file Pin
ductri22-Oct-06 1:39
memberductri22-Oct-06 1:39 
QuestionPlease help me Pin
ana_cool28-Aug-06 15:50
memberana_cool28-Aug-06 15:50 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.151126.1 | Last Updated 20 May 2004
Article Copyright 2003 by Corinna John
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid