从AVPacket为h264视频填充CMediaType和IMediaSample

时间:2011-08-15 15:19:17

标签: c++ directshow h.264 libav

我已经搜索过并且几乎找不到任何内容,所以我非常感谢我的一些帮助。

我正在写一个DirectShow源过滤器,它使用libav从youtube的FLV文件中读取和发送下游h264数据包。但我找不到合适的libav结构字段来正确实现过滤器的GetMediType()和FillBuffer()。一些libav字段为null。结果,h264解码器崩溃,试图处理接收的数据。

我哪里错了?在使用libav或DirectShow接口?使用libav或者我错误地填充参考时间时,h264可能需要额外的处理吗?有人有任何链接用于编写带有libav的DirectShow h264源过滤器吗?

GetMediaType()的一部分:

VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER*) toMediaType->AllocFormatBuffer(sizeof(VIDEOINFOHEADER));
pvi->AvgTimePerFrame = UNITS_PER_SECOND / m_pFormatContext->streams[m_streamNo]->codec->sample_rate; //sample_rate is 0
pvi->dwBitRate       = m_pFormatContext->bit_rate;
pvi->rcSource        = videoRect;
pvi->rcTarget        = videoRect;

//Bitmap
pvi->bmiHeader.biSize     = sizeof(BITMAPINFOHEADER);
pvi->bmiHeader.biWidth    = videoRect.right;
pvi->bmiHeader.biHeight   = videoRect.bottom;
pvi->bmiHeader.biPlanes   = 1;
pvi->bmiHeader.biBitCount = m_pFormatContext->streams[m_streamNo]->codec->bits_per_raw_sample;//or should here be bits_per_coded_sample
pvi->bmiHeader.biCompression = FOURCC_H264;
pvi->bmiHeader.biSizeImage = GetBitmapSize(&pvi->bmiHeader);

FillBuffer()的一部分:

//Get buffer pointer
BYTE* pBuffer = NULL;
if (pSamp->GetPointer(&pBuffer) < 0)
   return S_FALSE;

//Get next packet
AVPacket* pPacket = m_mediaFile.getNextPacket();
if (pPacket->data == NULL)
   return S_FALSE;

//Check packet and buffer size
if (pSamp->GetSize() < pPacket->size)
   return S_FALSE;

//Copy from packet to sample buffer
memcpy(pBuffer, pPacket->data, pPacket->size);

//Set media sample time
REFERENCE_TIME start    = m_mediaFile.timeStampToReferenceTime(pPacket->pts);
REFERENCE_TIME duration = m_mediaFile.timeStampToReferenceTime(pPacket->duration);
REFERENCE_TIME end      = start + duration;
pSamp->SetTime(&start, &end);
pSamp->SetMediaTime(&start, &end);

P.S。我用hax264解码器调试了我的过滤器,并在调用libav弃用函数img_convert()时崩溃。

2 个答案:

答案 0 :(得分:2)

以下是构建正确的H.264媒体类型所需的MSDN链接:H.264 Video Types

答案 1 :(得分:1)

您必须使用正确的值填充正确的字段。

AM_MEDIA_TYPE应该包含正确的h264 MEDIASUBTYPE。

这些都是完全错误的:

  

pvi-&gt; bmiHeader.biWidth = videoRect.right;

     

pvi-&gt; bmiHeader.biHeight = videoRect.bottom;

你应该使用一个独立于rcSource / rcTarget的宽度/高度,因为它们是指标,如果你从其他过滤器中取出它们,它可能完全为零。

pvi->bmiHeader.biBitCount = m_pFormatContext->streams[m_streamNo]->codec->bits_per_raw_sample;//or should here be bits_per_coded_sample

只有biWidth*biHeight*biBitCount/8是样本的真实大小才有意义。我不这么认为......

pvi->bmiHeader.biCompression = FOURCC_H264;

这也必须在子类型参数中的AM_MEDIA_TYPE中传递。

  

pvi-&gt; bmiHeader.biSizeImage = GetBitmapSize(&amp; pvi-&gt; bmiHeader);

这失败了,因为函数不知道fourcc,并且bitcount对于这个样本来说是完全错误的,因为它不是一个完整的框架。

您必须查看下游h264过滤器如何处理数据流。这似乎有缺陷。