windows media format sdk中使用precompressed stream的问题,高手请进
我要在windows media format sdk中使用一个自己开发的video for windows codec作编码,文档中称这种使用第三方codec为precompressed stream, 应用开发者必须自己完成数据的压缩,并将压缩后的数据传递给writer object。
writer object必须使用一个自定义的profile来说明这个precompressed stream, 下面是我按照文档中的说法完成的代码:
// 媒体类型的GUID
// {31444956-EB3F-4D0D-90FA-E807FCBAA116}
DEFINE_GUID(TTLH264_Video,
0x31444956, 0xeb3f, 0x4d0d, 0x90, 0xfa, 0xe8, 0x7, 0xfc, 0xba, 0xa1, 0x16);
// 媒体类型的压缩类型
const DWORD FOURCC_VID1 = MAKEFOURCC('V','I','D','1');
// 826558806 // 0x31444956
// 文档中讲媒体类型的GUID必须和压缩类型匹配, 象这样
// DWORD FOURCC_VID1 = MAKEFOURCC('V','I','D','1') = 0x31444956
// 则GUID必须以0x31444956, 开头
// 问题是我们怎么去控制GUID的生成值呢,目前我是生成后直接将其修改成符合标
// 准的形式,不知可不可以
const WORD VIDEO_STREAM_NUMBER = 1;
WCHAR *VIDEO_STREAM_NAME = L"TTL H.264 Video Stream";
WCHAR *VIDEO_STREAM_CONNECTION_NAME = L"TTL Video Connection";
// 初始化代码
// Image Info (Vid1 format)
ZeroMemory(&m_bmpInfoHdr, sizeof(BITMAPINFOHEADER));
m_bmpInfoHdr.biSize = sizeof(BITMAPINFOHEADER);
m_bmpInfoHdr.biWidth = m_nWidth;
m_bmpInfoHdr.biHeight = m_nHeight;
m_bmpInfoHdr.biPlanes = 1;
m_bmpInfoHdr.biBitCount = 24;
m_bmpInfoHdr.biCompression = FOURCC_VID1; // 自定义的
// Compression type
// Video Format Struct
RECT rect;
SetRect(&rect, 0, 0, m_nWidth, m_nHeight);
ZeroMemory(&m_VideoInfoHdr, sizeof(WMVIDEOINFOHEADER));
m_VideoInfoHdr.rcSource = rect;
m_VideoInfoHdr.rcTarget = rect;
m_VideoInfoHdr.dwBitRate = 190773; // 码率
m_VideoInfoHdr.dwBitErrorRate = 0; // 这个好像是错
// 误的码
// 率,不止怎么填
m_VideoInfoHdr.AvgTimePerFrame = 40 * 10000; // 每祯图象显示时
// 间
// (100ns 为单位)
m_VideoInfoHdr.bmiHeader = m_bmpInfoHdr;
// Video Media Type
ZeroMemory(&m_MediaSubType, sizeof(WM_MEDIA_TYPE));
m_MediaSubType.majortype = WMMEDIATYPE_Video;
m_MediaSubType.subtype = TTLH264_Video; // 自定义
// Compress type
// 的GUID
m_MediaSubType.bFixedSizeSamples = FALSE; // 每祯图象是否大
// 小相同
m_MediaSubType.bTemporalCompression = TRUE; // 图象是否已经
// 压缩过
m_MediaSubType.lSampleSize = 0;
m_MediaSubType.formattype = WMFORMAT_VideoInfo;
m_MediaSubType.pUnk = NULL;
m_MediaSubType.cbFormat = sizeof(WMVIDEOINFOHEADER);
m_MediaSubType.pbFormat = (BYTE*)&m_VideoInfoHdr;
// Init Com Library
CoInitialize(NULL);
// Create an Empty Profile
HRESULT hr = WMCreateProfileManager(&m_pProfileMgr);
hr = m_pProfileMgr->CreateEmptyProfile(WMT_VER_9_0,
&m_pProfile);
// create a new stream, config the stream
hr = m_pProfile->CreateNewStream(WMMEDIATYPE_Video,
&m_pStreamCfg);
hr = m_pStreamCfg->SetStreamNumber(1);
hr = m_pStreamCfg->SetStreamName(L"TTL Video Stream");
hr = m_pStreamCfg->SetConnectionName(L"Video");
hr = m_pStreamCfg->SetBufferWindow(3000); // 缓冲时间
hr = m_pStreamCfg->SetBitrate(190773); // 码率
hr = m_pStreamCfg->QueryInterface(IID_IWMMediaProps, (void**)
&m_pMediaProp);
hr = m_pMediaProp->SetMediaType(&m_MediaSubType); // 设置sub
// type
if (FAILED(hr))
{
// 在这里失败, 返回值表示m_MediaSubType的设置不正确
if (hr == NS_E_INVALID_STREAM)
int y = 100;
}
// add the stream to the profile
hr = m_pProfile->AddStream(m_pStreamCfg);
if (FAILED(hr))
{
if (hr == NS_E_INVALID_STREAM)
int x = 100;
}
// Create WM Writer Object, Set the Profile
hr = WMCreateWriter(NULL, &m_pWriter);
hr = m_pWriter->SetProfile(m_pProfile);
// Config all Input
DWORD dwInputCount = 0;
hr = m_pWriter->GetInputCount(&dwInputCount);
for (int i = 0; i < dwInputCount; i++)
hr = m_pWriter->SetInputProps(i, NULL);
// Init Writer
hr = WMCreateWriterFileSink(&m_pFileSink);
hr = m_pFileSink->QueryInterface(IID_IWMWriterFileSink3,
(void**)&m_pFileSink3);
hr = m_pWriter->QueryInterface(IID_IWMWriterAdvanced, (void**)
m_pWriterAdvanced);
hr = m_pWriterAdvanced->AddSink(m_pFileSink3);
// 启动写入线程
unsigned ThreadID;
m_hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadProc, this,
0, &ThreadID);
// 初始化结束
// 这里是写入数据的线程代码
int CTTLASFWriter::Run()
{
m_bRunning = true;
// 打开输出文件, 开始写入
HRESULT hr = m_pFileSink3->Open(L"d:\\test.asf");
hr = m_pWriter->BeginWriting();
QWORD qwSampleTime = 0; // sample time
while (true)
{
if (m_bExit)
break;
// 获取数据
int res = m_pSource->ReadVideo(&m_pInBuffer,
&m_InSize);
if (m_InSize <= 0 || res == -1)
break;
INSSBuffer *pNSSBuffer;
hr = m_pWriter->AllocateSample(m_InSize, &pNSSBuffer);
BYTE *pOutBuf = NULL;
hr = pNSSBuffer->GetBuffer(&pOutBuf);
memcpy(pOutBuf, m_pInBuffer, m_InSize);
hr = pNSSBuffer->SetLength(m_InSize);
qwSampleTime = timeGetTime() * 10000; // 单位100ns
m_pWriterAdvanced->WriteStreamSample
(VIDEO_STREAM_NUMBER, qwSampleTime, 0, 0, 0,
pNSSBuffer);
pNSSBuffer->Release();
m_pInBuffer = NULL;
m_InSize = 0;
}
hr = m_pFileSink3->Close();
hr = m_pWriter->EndWriting();
m_bRunning = false;
return 0;
}
请教为什么我设置sub media type会失败, 另外在写入sample时,每个sample都需要有一个sample time, 文档中也没有介绍这个冬冬怎么写, 它是相对第一祯的时间还是绝对的时间值呢? 请高手帮忙。