Заполнение CMediaType и IMediaSample из AVPacket для видео h264 - PullRequest
3 голосов
/ 15 августа 2011

Я искал и почти ничего не нашел, поэтому буду очень признателен за помощь в моем вопросе.

Я пишу исходный фильтр DirectShow, который использует libav для чтения и отправки нисходящих пакетов h264 из FLV-файла youtube. Но я не могу найти соответствующие поля структуры libav для правильной реализации фильтров GetMediType () и FillBuffer (). Некоторые поля libav имеют значение null. В результате происходит сбой декодера h264 при попытке обработать полученные данные.

Где я не прав? В работе с libav или с интерфейсами DirectShow? Может быть, h264 требует дополнительной обработки при работе с libav или я неправильно заполняю эталонное время? Есть ли у кого-нибудь ссылки, полезные для написания фильтра исходного кода DirectShow h264 с помощью libav?

Часть 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 ]

2 голосов
/ 07 сентября 2011

Вот ссылка MSDN, необходимая для создания правильного типа носителя H.264: Типы видео H.264

1 голос
/ 15 августа 2011

Вы должны заполнить правильные поля правильными значениями.

AM_MEDIA_TYPE должен содержать правильный MEDIASUBTYPE для h264.

И это совершенно неправильно:

pvi-> bmiHeader.biWidth = videoRect.right;

pvi-> 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-> bmiHeader.biSizeImage = GetBitmapSize (& pvi-> bmiHeader);

Это терпит неудачу, потому что fourcc неизвестен функции, а число битов в этом примере просто неверно из-за того, что оно не является полным кадром.

Вы должны взглянуть на то, как поток данных обрабатывается нижестоящим фильтром h264. Это кажется ошибочным.

...