2017-08-05 4 views
0

J'utilise les différentes API de ffmpeg pour dessiner des vidéos dans mon application. Jusqu'à présent, cela fonctionne très bien. Comme j'ai aussi des gifs, je veux faire une boucle sans avoir à charger le fichier encore et encore.Répétition du flux ffmpeg (libavcodec/libavformat)

Dans mon code de la boucle de décodeur ressemble à ceci:

AVPacket packet = {}; 
av_init_packet(&packet); 
while (mIsRunning) { 
    int error = av_read_frame(mContext, &packet); 
    if (error == AVERROR_EOF) { 
     if(mRepeat) { 
      logger.info("EOF-repeat"); 
      auto stream = mContext->streams[mVideoStream]; 
      av_seek_frame(mContext, mVideoStream, 0, 0); 
      continue; 
     } 
     if (mReadVideo) { 
      avcodec_send_packet(mVideoCodec, nullptr); 
     } 
     if (mReadAudio) { 
      avcodec_send_packet(mAudioCodec, nullptr); 
     } 
     break; 
    } 

    if (error < 0) { 
     char err[AV_ERROR_MAX_STRING_SIZE]; 
     av_make_error_string(err, AV_ERROR_MAX_STRING_SIZE, error); 
     logger.error("Failed to read next frame from stream: ", err); 
     throw std::runtime_error("Stream reading failed"); 
    } 

    if (packet.stream_index == mVideoStream && mReadVideo) { 
     int32 err; 
     { 
      std::lock_guard<std::mutex> l(mVideoLock); 
      err = avcodec_send_packet(mVideoCodec, &packet); 
     } 
     mImageEvent.notify_all(); 
     while (err == AVERROR(EAGAIN) && mIsRunning) { 
      { 
       std::unique_lock<std::mutex> l(mReaderLock); 
       mReaderEvent.wait(l); 
      } 
      { 
       std::lock_guard<std::mutex> l(mVideoLock); 
       err = avcodec_send_packet(mVideoCodec, &packet); 
      } 
     } 
    } 

    av_packet_unref(&packet); 
} 

La lecture d'une vidéo à la fin fonctionne parfaitement bien et si je ne mets mRepeat à true correctement EOF et arrête l'analyse syntaxique. Cependant quand on utilise une boucle qui suit se produit:

  • La vidéo se termine
  • AVERROR_EOF arrive à av_read_frame
  • EOF-repeat est imprimé
  • Une trame aléatoire est lue à partir du courant (et rendu)
  • AVERROR_EOF arrive à av_read_frame
  • EOF-repeat est imprimé
  • Une trame aléatoire est lue à partir du flux (et rendu)
  • ...

Vous pouvez l'imaginer comme je l'ai un gif d'un globe en rotation et après un tour complet, il commence juste sauter au hasard autour, parfois pour une fraction de seconde correctement, parfois en arrière et parfois juste au hasard partout.

J'ai également essayé plusieurs versions avec avformat_seek_file quelle autre façon de tout réinitialiser au début et recommencer à zéro?

Répondre

1

Je compris que je dois aussi réinitialiser mon contexte IO au début:

if(mRepeat) { 
    auto stream = mContext->streams[mVideoStream]; 
    avio_seek(mContext->pb, 0, SEEK_SET); 
    avformat_seek_file(mContext, mVideoStream, 0, 0, stream->duration, 0); 
    continue; 
} 

Maintenant, la vidéo boucles correctement pour toujours :)