windows media format sdk中使用precompressed stream的问题,高手请进

captainwh 2003-11-04 11:24:39
我要在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, 文档中也没有介绍这个冬冬怎么写, 它是相对第一祯的时间还是绝对的时间值呢? 请高手帮忙。
...全文
210 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
captainwh 2003-11-10
  • 打赏
  • 举报
回复
我试过去掉写sample的代码,象下面这样:
HRESULT hr = m_pFileSink3->Open(L"d:\\test1.asf");
hr = m_pWriter->BeginWriting();
hr = m_pFileSink3->Close();
hr = m_pWriter->EndWriting();

和有写sample的情况,象下面这样:

QWORD qwSampleTime = 0;
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);

if (m_ImageCount == 0)
{
m_StartTime = timeGetTime();
qwSampleTime = m_StartTime * 10000;
}
else
{
qwSampleTime = (timeGetTime() - m_StartTime) * 10000;
}

DWORD dwFlags;
if (m_InSize > 10 * 1024)
dwFlags = WM_SF_CLEANPOINT;
else
dwFlags = 0;

hr = m_pWriterAdvanced->WriteStreamSample(VIDEO_STREAM_NUMBER,
qwSampleTime, 0, 0, dwFlags, pNSSBuffer);
//hr = m_pWriter->WriteSample(0, qwSampleTime, 0, pNSSBuffer);
if (hr != S_OK)
{
break;
}
pNSSBuffer->Release();

m_ImageCount++;
printf("%d %d\n", m_ImageCount, m_InSize);

m_pInBuffer = NULL;
m_InSize = 0;
}

hr = m_pFileSink3->Close();
hr = m_pWriter->EndWriting();

程序运行结束后文件都是2.28k, 也就是说数据根本没有写入文件,请问这又是怎么回事呢
captainwh 2003-11-10
  • 打赏
  • 举报
回复
我每一祯图象数据都用WriteStreamSample写入成功了,为什么最后得到的asf文件只有2.5k呢?我写入的数据总量大概在2.5m左右。
captainwh 2003-11-10
  • 打赏
  • 举报
回复
太感谢了,问题解决了
蒋晟 2003-11-10
  • 打赏
  • 举报
回复
当不是实时录制的时候,sample time就是播放时的媒体时间
蒋晟 2003-11-09
  • 打赏
  • 举报
回复
Converting FOURCC Codes to Subtype GUIDs

A range of 2*32 GUIDs is reserved for representing FOURCCs. These GUIDs are all of the form XXXXXXXX-0000-0010-8000-00AA00389B71 where XXXXXXXX is the FOURCC code. Thus, the subtype GUID for YUY2 is 32595559-0000-0010-8000-00AA00389B71.

Many of these GUIDs are defined already in the header file Uuids.h. For example, the YUY2 subtype is defined as MEDIASUBTYPE_YUY2. The DirectShow base class library also provides a helper class, FOURCCMap, which can be used to convert FOURCC codes into GUID values. The FOURCCMap constructor takes a FOURCC code as an input parameter. You can then cast the FOURCCMap object to the corresponding GUID:

FOURCCMap fccMap(FCC('YUY2'));
GUID g1 = (GUID)fccMap;

// Equivalent:
GUID g2 = (GUID)FOURCCMap(FCC('YUY2'));



FOURCC Registration Page
FOURCC Registration. To register a new FOURCC, complete the attached document and mail it to Microsoft at mmreg@microsoft.com. This system is fine in principle but there is currently no way of getting that information back out of the folks at Microsoft once the format is registered. ...

http://www.microsoft.com/whdc/hwdev/archive/devdes/fourcc.mspx
蒋晟 2003-11-06
  • 打赏
  • 举报
回复
对了,你知道为什么用Windows Media Audio 9压缩声音会变调么?不压缩没有问题
蒋晟 2003-11-06
  • 打赏
  • 举报
回复
声音变得很低
似乎是CPU过忙,采样不足造成的
captainwh 2003-11-06
  • 打赏
  • 举报
回复
不知啊,变成什么了
captainwh 2003-11-05
  • 打赏
  • 举报
回复
由于是压缩数据,biSizeImage大小不是固定的,我试了给它一个最大值,没有效果
captainwh 2003-11-05
  • 打赏
  • 举报
回复
谢谢各位支持,大家再帮我顶啊
蒋晟 2003-11-05
  • 打赏
  • 举报
回复
Sample time还是有问题,应该减去开始的时间m_tStart=timeGetTime();

m_tCur =timeGetTime()-m_tStart;
QWORD cnsSampleTime=(QWORD)(m_tCur)*10000;
不推荐用时间戳,因为会增加带宽。如果确实要加,可以参考UncompAVIToWMV示例中的函数
HRESULT CUncompAVIToWMV::AddSMPTETimeCode( INSSBuffer * pSample,
QWORD qwPresTime )

hahu 2003-11-05
  • 打赏
  • 举报
回复
biCompression =BI_RGB
的时候可以不用biSizeImage
其他情况可以不写吗?

也没有看过biCompression 不用sdk提供的值
captainwh 2003-11-05
  • 打赏
  • 举报
回复
media sub type是支持的,做法应该就是这样,但我的参数哪里错误了呢,请有经验的帮我看看我设置的BITMAPINFOHEADER, WMVIDEOINFOHEADER, WM_MEDIA_TYPE这三个结构体中哪里数据是非法的呢?
蒋晟 2003-11-04
  • 打赏
  • 举报
回复
Sample Time是从写入开始计算的采样的绝对时间,单位是100纳秒(1/10000毫秒)
我是用timeGetTime然后乘10000的
某些类型的流的Sample Time不能是0,例如script流
自定义的子类型没用过,可能不被支持吧
captainwh 2003-11-04
  • 打赏
  • 举报
回复
:( ,哪位知道啊
dzqsuper 2003-11-04
  • 打赏
  • 举报
回复
这么高的高手
你应该当版主来
Ah 2003-11-04
  • 打赏
  • 举报
回复
关注

16,550

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • AIGC Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧