简体   繁体   中英

Repeating ffmpeg stream (libavcodec/libavformat)

I am using the various APIs from ffmpeg to draw videos in my application. So far this works very well. Since I also have gifs I want to do looping without having to load the file over and over again.

In my code the decoder loop looks like this:

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

Reading a video to the end works perfectly well and if I dont set mRepeat to true it properly EOFs and stops parsing. However when I use looping the following happens:

  • The video ends
  • AVERROR_EOF happens at av_read_frame
  • EOF-repeat is printed
  • A random frame is read from the stream (and rendered)
  • AVERROR_EOF happens at av_read_frame
  • EOF-repeat is printed
  • A random frame is read from the stream (and rendered)
  • ...

You can imagine it like I have a gif of a spinning globe and after one full turn it just starts randomly jumping around, sometimes for a fraction of a second correctly, sometimes backwards and sometimes just randomly everywhere.

I have also tried several versions with avformat_seek_file what other way would there be to reset everything to the beginning and start from scratch again?

I figured out that I also need to reset my IO context to the beginning:

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

Now the video properly loops forever :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM