生成视频文件的方式很多,你可以使用libx264这个开源的264编解码库来编码视频,生成视频文件;但是这样很麻烦,还需要另外找一个包装器(比如mp4)来包装这个视频流,否则播放器一般无法识别和播放。
想生成视频文件?何必舍近求远,windows系统本身就内置了一套视频生成框架——VFW,它提供了一组API,可以直接将RGB数据写入到视频文件中,大部分播放器都能够识别并播放这种视频文件。下面我将发布一个我修改过的AVI视频录制类,使用者可以直接使用此类来录制视频。
//
// avifile.h
//
#include <windows.h>
#include <vfw.h>
class CAviFile
{
public:
CAviFile();
~CAviFile(void);
/// <Summary>
/// 初始化AVI对象
/// </Summary>
HRESULT Open(LPCSTR lpszFileName, DWORD dwCodec, DWORD dwFPS, INT nWidth, INT nHeight, INT nQuality, INT nKeyFrame);
/// <Summary>
/// 销毁AVI对象
/// </Summary>
HRESULT Close(void);
/// </Summary>
/// Inserts the given bitmap bits into the movie as a new Frame at the end.
/// The width, height and nBitsPerPixel are the width, height and bits per pixel
/// of the bitmap pointed to by the input pBits.
/// </Summary>
HRESULT AppendNewFrame(int nWidth, int nHeight, LPVOID pBits, int nBitsPerPixel);
private:
HRESULT AppendFrame(int, int, LPVOID, int);
private:
// Keeps track of the current Frame Index
LONG m_lSample;
PAVIFILE m_pAviFile;
PAVISTREAM m_pAviStream;
PAVISTREAM m_pAviCompressedStream;
// RGB缓冲区
BOOL m_bStatus;
};
//
// avifile.cpp
//
#include "StdAfx.h"
#include "avifile.h"
#pragma comment( lib, "vfw32.lib" )
CAviFile:: CAviFile()
{
m_bStatus = FALSE;
m_lSample = 0;
m_pAviFile = NULL;
m_pAviStream = NULL;
}
CAviFile::~CAviFile(void)
{
Close();
}
HRESULT CAviFile::Open(LPCSTR lpszFileName, DWORD dwCodec, DWORD dwFPS, INT nWidth, INT nHeight, INT nQuality, INT nKeyFrame)
{
if (m_bStatus)
{
return S_OK;
}
AVIFileInit();
if(FAILED(AVIFileOpen(&m_pAviFile, lpszFileName, OF_CREATE | OF_WRITE, NULL)))
{
return E_FAIL;
}
// 默认质量
AVISTREAMINFO AviStreamInfo;
ZeroMemory(&AviStreamInfo, sizeof(AVISTREAMINFO));
AviStreamInfo.fccType = streamtypeVIDEO;
AviStreamInfo.fccHandler = dwCodec;
AviStreamInfo.dwScale = 1;
AviStreamInfo.dwRate = dwFPS;
//AviStreamInfo.dwQuality = m_nQuality;
AviStreamInfo.dwSuggestedBufferSize = nWidth * nHeight * 3;
SetRect(&AviStreamInfo.rcFrame, 0, 0, nWidth, nHeight);
lstrcpy(AviStreamInfo.szName, "VideoStream");
if(FAILED(AVIFileCreateStream(m_pAviFile, &m_pAviStream, &AviStreamInfo)))
{
return E_FAIL;
}
AVICOMPRESSOPTIONS AviCompressOptions;
ZeroMemory(&AviCompressOptions, sizeof(AVICOMPRESSOPTIONS));
AviCompressOptions.fccType = streamtypeVIDEO;
AviCompressOptions.fccHandler = AviStreamInfo.fccHandler;
AviCompressOptions.dwFlags = AVICOMPRESSF_KEYFRAMES | AVICOMPRESSF_VALID;//|AVICOMPRESSF_DATARATE;
AviCompressOptions.dwKeyFrameEvery = nKeyFrame;
//AviCompressOptions.dwBytesPerSecond = 0;
AviCompressOptions.dwQuality = nQuality;
if(FAILED(AVIMakeCompressedStream(&m_pAviCompressedStream, m_pAviStream, &AviCompressOptions, NULL)))
{
// One reason this error might occur is if you are using a Codec that is not
// available on your system. Check the mmioFOURCC() code you are using and make
// sure you have that codec installed properly on your machine.
return E_FAIL;
}
BITMAPINFO bmpInfo;
ZeroMemory(&bmpInfo, sizeof(BITMAPINFO));
bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biWidth = nWidth;
bmpInfo.bmiHeader.biHeight = nHeight;
bmpInfo.bmiHeader.biCompression = BI_RGB;
bmpInfo.bmiHeader.biBitCount = 24;
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfo.bmiHeader.biSizeImage = bmpInfo.bmiHeader.biWidth * bmpInfo.bmiHeader.biHeight * bmpInfo.bmiHeader.biBitCount / 8;
if(FAILED(AVIStreamSetFormat(m_pAviCompressedStream, 0, (LPVOID)&bmpInfo, bmpInfo.bmiHeader.biSize)))
{
// One reason this error might occur is if your bitmap does not meet the Codec requirements.
// For example,
// your bitmap is 32bpp while the Codec supports only 16 or 24 bpp; Or
// your bitmap is 274 * 258 size, while the Codec supports only sizes that are powers of 2; etc...
// Possible solution to avoid this is: make your bitmap suit the codec requirements,
// or Choose a codec that is suitable for your bitmap.
return E_FAIL;
}
m_bStatus = TRUE;
return S_OK;
}
HRESULT CAviFile::Close(void)
{
if (!m_bStatus)
{
return S_OK;
}
m_bStatus = FALSE;
m_lSample = 0;
if(m_pAviCompressedStream)
{
AVIStreamRelease(m_pAviCompressedStream);
m_pAviCompressedStream = NULL;
}
if(m_pAviStream)
{
AVIStreamRelease(m_pAviStream);
m_pAviStream = NULL;
}
if(m_pAviFile)
{
AVIFileRelease(m_pAviFile);
m_pAviFile = NULL;
}
AVIFileExit();
return S_OK;
}
HRESULT CAviFile::AppendNewFrame(int nWidth, int nHeight, LPVOID pBits,int nBitsPerPixel)
{
return AppendFrame(nWidth, nHeight, pBits, nBitsPerPixel);
}
HRESULT CAviFile::AppendFrame(int nWidth, int nHeight, LPVOID pBits,int nBitsPerPixel)
{
if (!m_bStatus)
{
return E_FAIL;
}
return AVIStreamWrite(m_pAviCompressedStream, m_lSample++, 1, pBits, (nWidth * nHeight * nBitsPerPixel), 0, NULL, NULL);
}
调用用如下方法:
CAviFile m_videoRecord; //定义对象
// 创建avi文件
CString strFile = _T("C:\\1.avi");
if (FAILED(m_videoRecord.Open(strFile, /*mmioFOURCC('I', '4', '2', '0')*/mmioFOURCC('X', '2', '6', '4'), 5, m_rectWnd.Width(), m_rectWnd.Height(), 100 * 100, 30)))
{
return FALSE;
}
// 写入视频帧
m_videoRecord.AppendNewFrame(nWidth, nHeight, pBit, 3);
写到这里也就完成了99%了,如果你就这样拿去调试的话,
m_videoRecord.Open
会返回失败,因为找不到响应的编码器,你需要下载x264vfw编码器库,
点这里下载
然后安装,完了在调试就没问题了。
这里只是生成了视频文件,如果还需要音频文件的话,那就相对比较麻烦了,
需要单独在录制一个wav的音频文件,然后在使用AVISaveVW这个API想音视频流合并起来才可以。
各种麻烦就不说了,而且音视频还不同步;如果需要录制带音频的视频文件,就推荐用这种方法了,
建议直接用x264编码视频,用libfaac编码音频,然后用libmp4来包装即可。