From 2b21a08f89bbf5ccff935ada6b5bbe42501f18c4 Mon Sep 17 00:00:00 2001
From: Chris Robinson <chris.kcat@gmail.com>
Date: Tue, 16 Jul 2019 20:20:25 -0700
Subject: Receive video frames in a loop

---
 examples/alffplay.cpp | 90 ++++++++++++++++++++++++++++-----------------------
 1 file changed, 50 insertions(+), 40 deletions(-)

(limited to 'examples/alffplay.cpp')

diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp
index ccdfd51f..466c4576 100644
--- a/examples/alffplay.cpp
+++ b/examples/alffplay.cpp
@@ -552,19 +552,21 @@ int AudioState::decodeFrame()
             AVPacket *lastpkt{};
             while((lastpkt=mPackets.getPacket(lock)) != nullptr)
             {
-                int ret{avcodec_send_packet(mCodecCtx.get(), lastpkt)};
+                const int ret{avcodec_send_packet(mCodecCtx.get(), lastpkt)};
                 if(ret == AVERROR(EAGAIN)) break;
+                if(ret < 0)
+                    std::cerr<< "Failed to send packet: "<<ret <<std::endl;
                 mPackets.pop();
             }
             if(!lastpkt)
                 avcodec_send_packet(mCodecCtx.get(), nullptr);
         }
-        int ret{avcodec_receive_frame(mCodecCtx.get(), mDecodedFrame.get())};
+        const int ret{avcodec_receive_frame(mCodecCtx.get(), mDecodedFrame.get())};
         if(ret == AVERROR_EOF) break;
         if(ret < 0)
         {
-            std::cerr<< "Failed to decode frame: "<<ret <<std::endl;
-            return 0;
+            std::cerr<< "Failed to receive frame: "<<ret <<std::endl;
+            break;
         }
 
         if(mDecodedFrame->nb_samples <= 0)
@@ -1179,7 +1181,7 @@ void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer)
             mFinalUpdate = true;
         mPictQRead.store(read_idx, std::memory_order_release);
         std::unique_lock<std::mutex>{mPictQMutex}.unlock();
-        mPictQCond.notify_all();
+        mPictQCond.notify_one();
         return;
     }
 
@@ -1187,7 +1189,7 @@ void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer)
     {
         mPictQRead.store(read_idx, std::memory_order_release);
         std::unique_lock<std::mutex>{mPictQMutex}.unlock();
-        mPictQCond.notify_all();
+        mPictQCond.notify_one();
 
         /* allocate or resize the buffer! */
         bool fmt_updated{false};
@@ -1287,7 +1289,7 @@ void VideoState::updateVideo(SDL_Window *screen, SDL_Renderer *renderer)
         {
             mFinalUpdate = true;
             std::unique_lock<std::mutex>{mPictQMutex}.unlock();
-            mPictQCond.notify_all();
+            mPictQCond.notify_one();
         }
     }
 }
@@ -1305,57 +1307,65 @@ int VideoState::handler()
 
     while(!mMovie.mQuit.load(std::memory_order_relaxed))
     {
-        size_t write_idx{mPictQWrite.load(std::memory_order_relaxed)};
-        Picture *vp{&mPictQ[write_idx]};
-
         {
             std::unique_lock<std::mutex> lock{mPackets.getMutex()};
             AVPacket *lastpkt{};
             while((lastpkt=mPackets.getPacket(lock)) != nullptr)
             {
-                int ret{avcodec_send_packet(mCodecCtx.get(), lastpkt)};
+                const int ret{avcodec_send_packet(mCodecCtx.get(), lastpkt)};
                 if(ret == AVERROR(EAGAIN)) break;
+                if(ret < 0)
+                    std::cerr<< "Failed to send packet: "<<ret <<std::endl;
                 mPackets.pop();
             }
             if(!lastpkt)
                 avcodec_send_packet(mCodecCtx.get(), nullptr);
         }
-        /* Decode video frame */
-        AVFrame *decoded_frame{vp->mFrame.get()};
-        int ret{avcodec_receive_frame(mCodecCtx.get(), decoded_frame)};
-        if(ret == AVERROR_EOF) break;
-        if(ret < 0)
+
+        while(!mMovie.mQuit.load(std::memory_order_relaxed))
         {
-            std::cerr<< "Failed to decode frame: "<<ret <<std::endl;
-            continue;
-        }
+            size_t write_idx{mPictQWrite.load(std::memory_order_relaxed)};
+            Picture *vp{&mPictQ[write_idx]};
+
+            /* Decode video frame. */
+            AVFrame *decoded_frame{vp->mFrame.get()};
+            const int ret{avcodec_receive_frame(mCodecCtx.get(), decoded_frame)};
+            if(ret == AVERROR_EOF) goto finished;
+            if(ret == AVERROR(EAGAIN)) break;
+            if(ret < 0)
+            {
+                std::cerr<< "Failed to receive frame: "<<ret <<std::endl;
+                break;
+            }
 
-        /* Get the PTS for this frame. */
-        if(decoded_frame->best_effort_timestamp != AV_NOPTS_VALUE)
-            mCurrentPts = std::chrono::duration_cast<nanoseconds>(
-                seconds_d64{av_q2d(mStream->time_base)*decoded_frame->best_effort_timestamp});
-        vp->mPts = mCurrentPts;
+            /* Get the PTS for this frame. */
+            if(decoded_frame->best_effort_timestamp != AV_NOPTS_VALUE)
+                mCurrentPts = std::chrono::duration_cast<nanoseconds>(
+                    seconds_d64{av_q2d(mStream->time_base)*decoded_frame->best_effort_timestamp});
+            vp->mPts = mCurrentPts;
 
-        /* Update the video clock to the next expected PTS. */
-        auto frame_delay = av_q2d(mCodecCtx->time_base);
-        frame_delay += decoded_frame->repeat_pict * (frame_delay * 0.5);
-        mCurrentPts += std::chrono::duration_cast<nanoseconds>(seconds_d64{frame_delay});
+            /* Update the video clock to the next expected PTS. */
+            auto frame_delay = av_q2d(mCodecCtx->time_base);
+            frame_delay += decoded_frame->repeat_pict * (frame_delay * 0.5);
+            mCurrentPts += std::chrono::duration_cast<nanoseconds>(seconds_d64{frame_delay});
 
-        /* Put the frame in the queue to be loaded into a texture and displayed
-         * by the rendering thread.
-         */
-        write_idx = (write_idx+1)%mPictQ.size();
-        mPictQWrite.store(write_idx, std::memory_order_release);
+            /* Put the frame in the queue to be loaded into a texture and
+             * displayed by the rendering thread.
+             */
+            write_idx = (write_idx+1)%mPictQ.size();
+            mPictQWrite.store(write_idx, std::memory_order_release);
 
-        if(write_idx == mPictQRead.load(std::memory_order_acquire))
-        {
-            /* Wait until we have space for a new pic */
-            std::unique_lock<std::mutex> lock{mPictQMutex};
-            while(write_idx == mPictQRead.load(std::memory_order_acquire) &&
-                !mMovie.mQuit.load(std::memory_order_relaxed))
-                mPictQCond.wait(lock);
+            if(write_idx == mPictQRead.load(std::memory_order_acquire))
+            {
+                /* Wait until we have space for a new pic */
+                std::unique_lock<std::mutex> lock{mPictQMutex};
+                while(write_idx == mPictQRead.load(std::memory_order_acquire) &&
+                    !mMovie.mQuit.load(std::memory_order_relaxed))
+                    mPictQCond.wait(lock);
+            }
         }
     }
+finished:
     mEOS = true;
 
     std::unique_lock<std::mutex> lock{mPictQMutex};
-- 
cgit v1.2.3