LINUX.ORG.RU

ffmpeg trouble


0

0

Стоит задача:
Нужно нарезать скриншотов с видеофайла, отступив от начала некоторый процент файла и от конца.
Проблема заключается в том, что при обработке 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);
    }




 

Ответ на: комментарий от dont

> Ну извените, я не силен в этом.

Громатека, громатека... ИзвИните.

Читай и выбрасывай фреймы, пока frame->key_frame в 1 не установится. И flag &= ~AVSEEK_FLAG_ANY делай

mv ★★★★★
()
Ответ на: комментарий от mv

Прошу прощения, но русский для меня не родной. Все работает, спасибо.

А не могли бы Вы посоветовать где можно почитать про форматы видео, разные там типы фреймов и т.д. Так же интересно было почитать про устройство ffmpeg, я вот до сих пор не понял, что конкретно собой представляет AVPacket и AVFrame. Какие есть альтернативы ffmpeg'у, врапер может какой-нить на С++ или конкурент\аналог?

dont
() автор топика
Ответ на: комментарий от dont

> А не могли бы Вы посоветовать где можно почитать про форматы видео, разные там типы фреймов и т.д.

wiki, doom9.net

> Так же интересно было почитать про устройство ffmpeg,

Самое больное место в ffmpeg - отсутствие документации.

> я вот до сих пор не понял, что конкретно собой представляет AVPacket и AVFrame

AVFrame - это структура для описания кадра (формат, размеры). AVPacket - структура для описания одного чанка (порции данных) в AVI-контейнере. В пакеты упаковывается пожатые энкодером видео и звук. Читать в цикле пакеты нужно для того, что пожатые картинки могут превышать размер пакета.

> Какие есть альтернативы ffmpeg'у, врапер может какой-нить на С++ или конкурент\аналог?

Для декодирования можно использовать xinelib. Для работы а-ля m$ DirectShow можно использовать GStreamer - вещь хорошая, но по состоянию на год назад была для меня сильно глюкавой. С глюкавого ffmpeg, у которого между релизами плавает api, смысла уходить не было, т.к. требовалась некоторая гибкость, которую gstreamer обеспечить не мог из-за глюков :) Врапперов плюсатых не встречал. Для gstreamer'а они заброшены и не доделаны, но недавно в рассылке читал, что кто-то начал опять плюсатый враппер делать. Без враппера же прямая работа с GObject на Си, особенно исследовательского характера, когда архитектура постоянно меняется, может повредить мозг ;) В любом случае, можно подписаться на мейллист gstreamer-devel и просить помощи там.

mv ★★★★★
()
Ответ на: комментарий от mv

Спасибо большое. Будем разбираться.

dont
() автор топика
Ответ на: комментарий от INFOMAN

Код с примера, тестовый, не мой) Хотя я сам в разумном использовании гоуту ничего страшного не вижу.

dont
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.