Стоит задача:
Нужно нарезать скриншотов с видеофайла, отступив от начала некоторый процент файла и от конца.
Проблема заключается в том, что при обработке mpeg файлов ф-я avcodec_decode_video выдает предупреждения
[mpeg1video @ 0x2afbbda34e90]current_picture not initialized
[mpeg1video @ 0x2afbbda34e90]warning: first frame is no keyframe
и скрин получается заквадраченым.
Для avi-видео - все в порядке, никаких предупреждений.
Размыто только себе представляю, что есть разные типы фреймов, и если находимся не на ключевом фрейме, будут такие проблемы. Но как это решить, ума не приложу.
Вот мой код, который по теме:
int startPercent = one->getVideoIndenBegin();
int endPercent = one->getVideoIndenEnd();
int screensNumber = one->getScreenShotCount();
int64_t start_pos = m_pFormatCtx->start_time +((int)( m_pFormatCtx->duration * startPercent * 0.01) );
int64_t end_pos = m_pFormatCtx->start_time + (m_pFormatCtx->duration - (int)( m_pFormatCtx->duration*endPercent*0.01) );
int64_t step = (end_pos - start_pos) / (screensNumber );
int64_t target_frame = start_pos;
l1:
if(0 > av_seek_frame(m_pFormatCtx, -1, target_frame, AVSEEK_FLAG_BACKWARD))
one->log().error("1:Can't seek to %d frame",target_frame);
target_frame+= step;
avcodec_flush_buffers(m_pCodecCtx);
while(av_read_frame(m_pFormatCtx, &m_packet) >= 0)
{
// Is this a packet from the video stream?
if(m_packet.stream_index==m_videoStreamNum)
{
// Decode video frame
avcodec_decode_video(m_pCodecCtx,m_pFrame,&m_frameFinished,
m_packet.data, m_packet.size);
// Did we get a video frame?
if(m_frameFinished)
{
m_pFrameCodecCtx->qmin = m_pFrameCodecCtx->qmax = 3;
m_pFrameCodecCtx->mb_lmin = m_pFrameCodecCtx->lmin = m_pFrameCodecCtx->qmin * FF_QP2LAMBDA;
m_pFrameCodecCtx->mb_lmax = m_pFrameCodecCtx->lmax = m_pFrameCodecCtx->qmax * FF_QP2LAMBDA;
m_pFrameCodecCtx->flags |= CODEC_FLAG_QSCALE;
m_pFrame->quality = 4;
m_pFrame->pts = i;
int szBufferActual = avcodec_encode_video(m_pFrameCodecCtx, m_pBuf, numBytes, m_pFrame);
if(szBufferActual < 0)
{
one->log().error("avcodec_encode_video error. return value = %d",szBufferActual);
return -1;
}
if(++i <= screensNumber)
{
/* Write JPEG to file */
if(!saveFrame(frameName,m_pBuf,szBufferActual,i))
return false;
else
{
minute++;
av_free_packet(&m_packet);
goto l1;
}
}
else
break;
}
}
av_free_packet(&m_packet);
}
Прошу прощения, но русский для меня не родной.
Все работает, спасибо.
А не могли бы Вы посоветовать где можно почитать про форматы видео, разные там типы фреймов и т.д.
Так же интересно было почитать про устройство ffmpeg, я вот до сих пор не понял, что конкретно собой представляет AVPacket и AVFrame.
Какие есть альтернативы ffmpeg'у, врапер может какой-нить на С++ или конкурент\аналог?
> А не могли бы Вы посоветовать где можно почитать про форматы видео, разные там типы фреймов и т.д.
wiki, doom9.net
> Так же интересно было почитать про устройство ffmpeg,
Самое больное место в ffmpeg - отсутствие документации.
> я вот до сих пор не понял, что конкретно собой представляет AVPacket и AVFrame
AVFrame - это структура для описания кадра (формат, размеры). AVPacket - структура для описания одного чанка (порции данных) в AVI-контейнере. В пакеты упаковывается пожатые энкодером видео и звук. Читать в цикле пакеты нужно для того, что пожатые картинки могут превышать размер пакета.
> Какие есть альтернативы ffmpeg'у, врапер может какой-нить на С++ или конкурент\аналог?
Для декодирования можно использовать xinelib. Для работы а-ля m$ DirectShow можно использовать GStreamer - вещь хорошая, но по состоянию на год назад была для меня сильно глюкавой. С глюкавого ffmpeg, у которого между релизами плавает api, смысла уходить не было, т.к. требовалась некоторая гибкость, которую gstreamer обеспечить не мог из-за глюков :) Врапперов плюсатых не встречал. Для gstreamer'а они заброшены и не доделаны, но недавно в рассылке читал, что кто-то начал опять плюсатый враппер делать. Без враппера же прямая работа с GObject на Си, особенно исследовательского характера, когда архитектура постоянно меняется, может повредить мозг ;) В любом случае, можно подписаться на мейллист gstreamer-devel и просить помощи там.