AVI英文全称为Audio Video Interleaved,即音频视频交错格式。它是一种将语音和影像同步组合在一起的文件格式。AVI支持256色和RLE压缩,主要应用在多媒体光盘上,主要用来保存电视、电影等各种影像信息。
在Windows系统中,借助于API之利,我们能够轻易的实现AVI文件的分解与重组。下面,我给出一个C#版本的AVI分解示例。
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.IO;
namespace org.loon.util
{
/// <summary>
/// org.loon.util.AVIUtil 用于AVI文件处理
/// </summary>
public class AVIUtil
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct BITMAPFILEHEADER
{
public ushort bfType;
public uint bfSize;
public ushort bfReserved1;
public ushort bfReserved2;
public uint bfOffBits;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct BITMAPINFOHEADER
{
public uint biSize;
public int biWidth;
public int biHeight;
public ushort biPlanes;
public ushort biBitCount;
public uint biCompression;
public uint biSizeImage;
public int biXPelsPerMeter;
public int biYPelsPerMeter;
public uint biClrUsed;
public uint biClrImportant;
public const int BI_RGB = 0;
}
const uint DIB_RGB_COLORS = 0;
const uint DIB_PAL_COLORS = 1;
/// <summary>
/// 对象转换
/// </summary>
/// <param name="pBITMAPINFOHEADER"></param>
/// <returns></returns>
public static Bitmap ToBitmap(IntPtr pBITMAPINFOHEADER)
{
unsafe
{
BITMAPINFOHEADER* pbmi = (BITMAPINFOHEADER*)pBITMAPINFOHEADER;
BITMAPFILEHEADER pbmfi;
pbmfi.bfType = (int)‘M‘ << 8 | (int)‘B‘;
pbmfi.bfOffBits = (uint)(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));
pbmfi.bfSize = pbmfi.bfOffBits + pbmi->biSizeImage;
MemoryStream stream = new MemoryStream();
BinaryWriter bw = new BinaryWriter(stream);
byte[] data = new byte[sizeof(BITMAPFILEHEADER)];
Marshal.Copy((IntPtr)(&pbmfi), data, 0, data.Length);
bw.Write(data);
data = new byte[sizeof(BITMAPINFOHEADER)];
Marshal.Copy(pBITMAPINFOHEADER, data, 0, data.Length);
bw.Write(data);
data = new byte[pbmi->biSizeImage];
++pbmi;
Marshal.Copy((IntPtr)pbmi, data, 0, data.Length);
bw.Write(data);
bw.Flush();
bw.BaseStream.Position = 0;
return new Bitmap(bw.BaseStream);
}
}
}
/// <summary>
/// AviFile,用于AVI文件处理
/// </summary>
public class AviFile : IDisposable
{
const string AVIFILE32 = "AVIFIL32";
const int AVIGETFRAMEF_BESTDISPLAYFMT = 1;
internal enum OpenFileFlags : uint
{
OF_READ = 0x00000000,
OF_WRITE = 0x00000001,
OF_READWRITE = 0x00000002,
OF_SHARE_COMPAT = 0x00000000,
OF_SHARE_EXCLUSIVE = 0x00000010,
OF_SHARE_DENY_WRITE = 0x00000020,
OF_SHARE_DENY_READ = 0x00000030,
OF_SHARE_DENY_NONE = 0x00000040,
OF_PARSE = 0x00000100,
OF_DELETE = 0x00000200,
OF_VERIFY = 0x00000400,
OF_CANCEL = 0x00000800,
OF_CREATE = 0x00001000,
OF_PROMPT = 0x00002000,
OF_EXIST = 0x00004000,
OF_REOPEN = 0x00008000,
}
[DllImport(AVIFILE32)]
extern internal static void AVIFileInit();
[DllImport(AVIFILE32)]
extern internal static void AVIFileExit();
[DllImport(AVIFILE32)]
extern internal static uint AVIFileOpen(out IntPtr ppfile, string szFile, OpenFileFlags mode, IntPtr pclsidHandler);
[DllImport(AVIFILE32)]
extern internal static int AVIFileRelease(IntPtr pfile);
[DllImport(AVIFILE32)]
extern internal static uint AVIFileGetStream(IntPtr pfile, out IntPtr ppavi, uint fccType, int lParam);
[DllImport(AVIFILE32)]
extern internal static int AVIStreamRelease(IntPtr pavi);
[DllImport(AVIFILE32)]
extern internal static IntPtr AVIStreamGetFrameOpen(IntPtr pavi, int lpbiWanted);
[DllImport(AVIFILE32)]
extern internal static IntPtr AVIStreamGetFrame(IntPtr pgf, int lPos);
[DllImport(AVIFILE32)]
extern internal static int AVIStreamLength(IntPtr pavi);
[DllImport(AVIFILE32)]
extern internal static uint AVIStreamGetFrameClose(IntPtr pget);
static uint mmioFOURCC(char c0, char c1, char c2, char c3)
{
return (uint)c3 << 24 | (uint)c2 << 16 | (uint)c1 << 8 | (uint)c0;
}
static readonly uint streamtypeVIDEO = mmioFOURCC(‘v‘, ‘i‘, ‘d‘, ‘s‘);
static readonly uint streamtypeAUDIO = mmioFOURCC(‘a‘, ‘u‘, ‘d‘, ‘s‘);
static readonly uint streamtypeMIDI = mmioFOURCC(‘m‘, ‘i‘, ‘d‘, ‘s‘);
static readonly uint streamtypeTEXT = mmioFOURCC(‘t‘, ‘x‘, ‘t‘, ‘s‘);
IntPtr aviFile = IntPtr.Zero;
IntPtr aviStream = IntPtr.Zero;
bool disposed = false;
public static void Initialize()
{
AVIFileInit();
}
public static void Terminate()
{
AVIFileExit();
}
public AviFile(string filename)
{
uint result;
result = AVIFileOpen(out aviFile, filename, OpenFileFlags.OF_READ, IntPtr.Zero);
if (result != 0)
{
Release();
throw new Exception("AVIFileOpen failure.");
}
result = AVIFileGetStream(aviFile, out aviStream, streamtypeVIDEO, 0);
if (result != 0)
{
Release();
throw new Exception("AVIFileGetStream failure.");
}
}
~AviFile()
{
Dispose(false);
}
void Release()
{
if (aviStream != IntPtr.Zero)
{
AVIStreamRelease(aviStream);
aviStream = IntPtr.Zero;
}
if (aviFile != IntPtr.Zero)
{
AVIFileRelease(aviFile);
aviFile = IntPtr.Zero;
}
}
public int GetMaxFrameCount()
{
if (aviStream == IntPtr.Zero)
throw new InvalidOperationException();
return AVIStreamLength(aviStream);
}
public Bitmap GetFrame(int no)
{
if (aviStream == IntPtr.Zero)
throw new InvalidOperationException();
IntPtr frame = IntPtr.Zero;
try
{
frame = AVIStreamGetFrameOpen(aviStream, AVIGETFRAMEF_BESTDISPLAYFMT);
IntPtr pbmi = AVIStreamGetFrame(frame, no);
return org.loon.util.AVIUtil.ToBitmap(pbmi);
}
finally
{
if (frame != IntPtr.Zero)
AVIStreamGetFrameClose(frame);
}
}
protected void Dispose(bool disposing)
{
if (disposed)
return;
disposed = true;
Release();
}
public void Dispose()
{
//不让垃圾回收器终止指定对象(即不将指定对象调入终止序列中)
GC.SuppressFinalize(this);
Dispose(true);
}
}
}
分解AVI:
string filename = "d:\test.avi";
//初始化
org.loon.util.AviFile.Initialize();
using (org.loon.util.AviFile avi = new org.loon.util.AviFile(filename))
{
int max = avi.GetMaxFrameCount();
for (int i = 0; i < max; ++i)
{
Bitmap bmp = avi.GetFrame(i);
bmp.Save("d:\test\"+i + ".bmp");
bmp.Dispose();
}
}
//完成
org.loon.util.AviFile.Terminate();