2017-08-05 1 views
0

Ich verwende die verschiedenen APIs von ffmpeg, um Videos in meiner Anwendung zu zeichnen. Bis jetzt funktioniert das sehr gut. Da ich auch Gifs habe, möchte ich Schleifen machen, ohne die Datei immer wieder neu laden zu müssen.Repeating ffmpeg stream (libavcodec/libavformat)

In meinem Code sucht der Decoder-Schleife wie folgt aus:

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); 
} 

ein Video zu Ende Lesen funktioniert sehr gut, und wenn ich gesetzt Dont mRepeat auf true es richtig EOFs und stoppt das Parsen. Jedoch, wenn ich den folgenden Anwendungs ​​Looping geschieht:

  • das Video endet
  • AVERROR_EOF geschieht bei av_read_frame
  • EOF-repeat gedruckt wird
  • Ein zufälliger Rahmen wird aus dem Strom zu lesen (und gerendert)
  • AVERROR_EOF passiert bei av_read_frame
  • EOF-repeat wird
  • gedruckt
  • Ein zufälliger Rahmen aus dem Stream gelesen wird (und gerendert)
  • ...

Sie können es sich vorstellen, wie ich ein gif einer drehenden Globus haben und nach einer vollen Umdrehung es um zufällig gerade beginnt Springen, manchmal für einen Bruchteil einer Sekunde richtig, manchmal rückwärts und manchmal nur zufällig überall.

Ich habe auch mehrere Versionen mit avformat_seek_file ausprobiert, wie anders wäre es, alles auf den Anfang zurückzusetzen und wieder von vorne anzufangen?

Antwort

1

Ich fand heraus, dass ich auch meine IO Kontext zum Anfang zurück:

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; 
} 

Jetzt das Video richtig Schleifen für immer :)