从AVPacket填充CMediaType和IMediaSample以获取h264视频 [英] Filling CMediaType and IMediaSample from AVPacket for h264 video

查看:111
本文介绍了从AVPacket填充CMediaType和IMediaSample以获取h264视频的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我搜索后几乎没有发现任何东西,所以我非常感谢我的问题。



我正在编写一个使用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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆