从AVPacket填充CMediaType和IMediaSample以获取h264视频 [英] Filling CMediaType and IMediaSample from AVPacket for h264 video
问题描述
我搜索后几乎没有发现任何东西,所以我非常感谢我的问题。
我正在编写一个使用libav读取的DirectShow源过滤器并从youtube的FLV文件发送下游h264数据包。但是我找不到合适的libav结构的字段来正确实现过滤器的GetMediType()和FillBuffer()。一些libav字段为空。结果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]->编解码器-> sample_rate; // sample_rate为0
pvi-> dwBitRate = m_pFormatContext-> bit_rate;
pvi-> rcSource = videoRect;
pvi-> rcTarget = videoRect;
//位图
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]->编解码器-> bits_per_raw_sample; //或此处应该是bits_per_coded_sample
pvi-> bmiHeader.biCompression = FOURCC_H264;
pvi-> bmiHeader.biSizeImage = GetBitmapSize(& pvi-> bmiHeader);
FillBuffer()的一部分:
//获取缓冲区指针
BYTE * pBuffer = NULL;
if(pSamp-> GetPointer(& pBuffer)< 0)
返回S_FALSE;
//获取下一个数据包
AVPacket * pPacket = m_mediaFile.getNextPacket();
if(pPacket-> data == NULL)
返回S_FALSE;
//如果(pSamp-> GetSize()< pPacket-> size)
返回S_FALSE ;,则检查数据包和缓冲区大小
;
//从数据包复制到样本缓冲区
memcpy(pBuffer,pPacket-> data,pPacket-> size);
//设置媒体采样时间
REFERENCE_TIME start = m_mediaFile.timeStampToReferenceTime(pPacket-> pts);
REFERENCE_TIME持续时间= m_mediaFile.timeStampToReferenceTime(pPacket-> duration);
REFERENCE_TIME结束=开始+持续时间;
pSamp-> SetTime(& start,& end);
pSamp-> SetMediaTime(& start,& end);
P.S。我已经使用hax264解码器调试了过滤器,并且在调用libav弃用的函数img_convert()时崩溃。
AM_MEDIA_TYPE
应该包含适用于h264的正确MEDIASUBTYPE。
这些都是错误的:
pvi-> bmiHeader.biWidth = videoRect.right;
pvi-> bmiHeader.biHeight = videoRect.bottom;
由于以下原因,您应使用独立于rcSource / rcTarget的宽度/高度
pvi-> bmiHeader可能是零。
pvi-> bmiHeader .biBitCount = m_pFormatContext-> streams [m_streamNo]-> codec-> bits_per_raw_sample; //或此处应为bits_per_coded_sample
仅当
biWidth * biHeight * biBitCount / 8
是样本的真实大小。我不这么认为...
pvi-> bmiHeader.biCompression = FOURCC_H264;
这也必须在子类型参数的AM_MEDIA_TYPE中传递。
pvi-> bmiHeader.biSizeImage = GetBitmapSize(& pvi-> bmiHeader);
这失败了,因为该函数不知道fourcc,并且由于不是全帧,因此该示例的位计数显然是错误的。
您必须看看如何数据流由下游的h264过滤器处理。这似乎是有缺陷的。
I have searched and have found almost nothing, so I would really appreciate some help with my question.
I am writting a DirectShow source filter which uses libav to read and send downstream h264 packets from youtube's FLV file. But I can't find appropriate libav structure's fields to implement correctly filter's GetMediType() and FillBuffer(). Some libav fields is null. In consequence h264 decoder crashes in attempt to process received data.
Where am I wrong? In working with libav or with DirectShow interfaces? Maybe h264 requires additional processing when working with libav or I fill reference time incorrectly? Does someone have any links useful for writing DirectShow h264 source filter with libav?
Part of 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);
Part of 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. I've debugged my filter with hax264 decoder and it crashes on call to libav deprecated function img_convert().
解决方案You have to fill the right fields with the right values.
The
AM_MEDIA_TYPE
should contain the right MEDIASUBTYPE for h264.And these are plain wrong :
pvi->bmiHeader.biWidth = videoRect.right;
pvi->bmiHeader.biHeight = videoRect.bottom;
You should use a width/height which is independent of the rcSource/rcTarget, due to the them being indicators, and maybe completely zero if you take them from some other filter.
pvi->bmiHeader.biBitCount = m_pFormatContext->streams[m_streamNo]->codec->bits_per_raw_sample;//or should here be bits_per_coded_sample
This only makes sense if
biWidth*biHeight*biBitCount/8
are the true size of the sample. I do not think so ...pvi->bmiHeader.biCompression = FOURCC_H264;
This must also be passed in the AM_MEDIA_TYPE in the subtype parameter.
pvi->bmiHeader.biSizeImage = GetBitmapSize(&pvi->bmiHeader);
This fails, because the fourcc is unknown to the function and the bitcount is plain wrong for this sample, due to not being a full frame.
You have to take a look at how the data stream is handled by the downstream h264 filter. This seems to be flawed.
这篇关于从AVPacket填充CMediaType和IMediaSample以获取h264视频的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!