C# Topics
Using the erdmpg-6.dll file with C#
The Standard Mpeg Encoder offers the erdmpg-6.dll file as an alternative to the DirectShow filter. This dll file allows you to encode RGB24 video data and PCM audio data directly from memory into MPEG files (as well as all formats supported by the encoder.
There are two samples in the encoder package that show the usage of this dll:
- DirectAccessSample: This is a C++ console application that demonstrates how to load a bitmap file from disk into memory and create an MPEG file from this bitmap file. Additionally, a sound sample is generated in memory and saved in the same file
- CSharpDirectAccess: This is a C# sample that shows how to write encode all jpeg files in a particular directory into an MPEG file. The files are loaded into System.Drawing.Bitmap, and then the bit buffer is sent to the Dll to be encoded to an MPEG file.
Tutorial: Encode Bitmap into an MPEG file using C#
On a high level...
All you have to do is instanciate the MpegManager class, and pass in a System.Drawing.Bitmap image.
// Create a new MPEG File. Second parameter is the output format, 3rd and 4th
// parameters are the width and height
MpegManager mpegManager
= new MpegManager
("c:\\out.mpg",
1,
320,
240);
// Load the image into a bitmap
System.Drawing.
Bitmap image
= new System.Drawing.
Bitmap("c:\\test.jpg");
// Write it as a frame
mpegManager.
AddFrame(image
);
// close the file
mpegManager.
CloseFile();
Somewhat more detailed...
The MpegManager is a C# class that interfaces with the erdmpg-6.dll file. It does so over the the proxy StandardMpegEncoderDll.cs, which allows C# code interface with an unmanaged dll. This file should be included as a reference in your project, and contains the following functions:
int MediaFileSetBufferCallback(IntPtr pUserData, BufferCallback callbackFunc);
int MediaFileInitialize();
int MediaFileCreate();
int MediaFileClose();
int MediaFileWriteVideoRGB24(IntPtr imgDataP, int len, Int64 llStartTime, Int64 llEndTime);
int MediaFileWriteAudio(IntPtr audDataP, int len, Int64 llStartTime, Int64 llEndTime);
int MediaFileSetFormat(String pstrPresetName);
int MediaFileSetParameter(String pstrParameterName, String pstrParameterValue);
The functions above are the entire public interface for the dll. Those few functions allow you take full control over all aspects of your encoded file.
The general usage of the dll functions in this manner:
- You call the MediaFileInitialize function to get all the internal objects created
- You call the MediaFileSetFormat with a string preset like "mpeg-2" to have the parameters set to default values
- You use the function MediaFileSetParameter to tweak the parameters to fit your needs
- You call the function MediaFileSetBufferCallback to set the callback function that will receive the mpeg data as a binary stream. This function can write the file to disk or send the file over a network
- You call the function MediaFileCreate. This will create the Mpeg File header data using the loaded formats. After calling this function, your callback function will be called a few times with the data you need to write to create the header file
- You now retrieve your MPEG data, and write it using: MediaFileWriteVideoRGB24
- When you are done, call MediaFileClose
Simple Mpeg Encoding in C# - The MpegManager class
class MpegManager
{
FileStream _fileStream;
BinaryWriter _binaryWriter;
int _expectedWidth;
int _expectedHeight;
const int ONE_SECOND
= 10000000;
long _curPicStart
= 0;
long _forcedPicDuration
= 0;
// 3 * ONE_SECOND; // change this to 0 to encode each frame normally
public MpegManager
(String fileName,
int format,
int sourceWidth,
int sourceHeight
) {
// Reset the start position
_curPicStart
= 0;
// sourceWidth and sourceHeight is the expected size of the bitmaps
// If they do not match, they will be resized to that size
_expectedWidth
= sourceWidth;
_expectedHeight
= sourceHeight;
// Open the output mpeg file. The data is sent in the callback at the
// end of this file
_fileStream
= File.
Create(fileName
);
_binaryWriter
= new BinaryWriter
(_fileStream
);
// Initialize the encoder
StandardMpegEncoderDll.
MediaFileInitialize();
// Select the format (mpeg-1, etc)
SelectFormat
(format
);
// Set the source width and height
StandardMpegEncoderDll.
MediaFileSetParameter("nInputX", sourceWidth.
ToString());
StandardMpegEncoderDll.
MediaFileSetParameter("nInputY", sourceHeight.
ToString());
// switch off audio
StandardMpegEncoderDll.
MediaFileSetParameter("bWriteAudioStream",
"0");
// Set the MPEG data callback function. If you wish, pass your
// user specific data as the first parameter
IntPtr myData
= (IntPtr
)0;
BufferCallback cb
= new BufferCallback
(MpegBufferCallback
);
StandardMpegEncoderDll.
MediaFileSetBufferCallback(myData, cb
);
// Create the file
StandardMpegEncoderDll.
MediaFileCreate();
}
public Bitmap ResizeBitmap
(Bitmap b,
int nWidth,
int nHeight
)
{
if (b.
Width == nWidth
&& b.
Height == nHeight
)
return b;
Bitmap result
= new Bitmap
(nWidth, nHeight
);
using (Graphics g
= Graphics.
FromImage((Image
)result
))
g.
DrawImage(b, 0, 0, nWidth, nHeight
);
return result;
}
public bool AddFrame
(System.Drawing.
Bitmap bmp
) {
bmp
= ResizeBitmap
(bmp, _expectedWidth, _expectedHeight
);
Rectangle rc
= new Rectangle
(0, 0, bmp.
Width, bmp.
Height);
// lock bitmap data
BitmapData bmData
= bmp.
LockBits(rc, ImageLockMode.
ReadWrite,
PixelFormat.
Format24bppRgb);
// Get the address of the first line.
IntPtr ptr
= bmData.
Scan0;
int lenBitmap
= bmp.
Width * bmp.
Height * 3;
// Write to the mpeg file.
if (_forcedPicDuration
> 0
) {
StandardMpegEncoderDll.
MediaFileWriteVideoRGB24(ptr, lenBitmap, _curPicStart, _curPicStart
+ _forcedPicDuration
);
_curPicStart
+= _forcedPicDuration;
}
else
StandardMpegEncoderDll.
MediaFileWriteVideoRGB24(ptr, lenBitmap,
-1,
-1);
// unlock bitmap data
bmp.
UnlockBits(bmData
);
return true;
}
public void SelectFormat
(int iFormatIndex
) {
// Presets are listed in VBGui
switch (iFormatIndex
)
{
case 0
:
StandardMpegEncoderDll.
MediaFileSetFormat("mpeg-1");
break;
case 1:
StandardMpegEncoderDll.
MediaFileSetFormat("mpeg-2");
break;
}
}
public void CloseFile
() {
// Close the file
StandardMpegEncoderDll.
MediaFileClose();
}
Int64 MpegBufferCallback
(IntPtr pUserData, IntPtr pDataBuffer,
int bufferLen,
int flags, Int64 seekPos,
int nID
)
{
// This is the function that receives the MPEG data. Write it to a file
// or stream it. Be careful to seek to where the seekPos tells you to seek
// to.
switch (flags
)
{
case 0
: // open file
// file is already opened in constructor
break;
case 1: // write file
byte[] managedBuffer
= new byte[bufferLen
];
Marshal.
Copy(pDataBuffer, managedBuffer, 0, managedBuffer.
Length);
_binaryWriter.
Write(managedBuffer, 0, bufferLen
);
break;
case 2: // close
_binaryWriter.
Close();
_fileStream.
Close();
_binaryWriter
= null;
_fileStream
= null;
break;
case 3: // seek
_binaryWriter.
Seek((int)seekPos, SeekOrigin.
Begin);
break;
}
return 0;
}
}