diff options
author | Chris Robinson <[email protected]> | 2019-07-19 22:55:20 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2019-07-19 22:55:20 -0700 |
commit | 9959d661a02b8d140dfc43b2aa1c6bfa40a5af18 (patch) | |
tree | ffdb43da4c024bd9c1df895cf278137b79f58a5f /examples/alffplay.cpp | |
parent | 29cf87f34d67cf73307d0ec5d61c14b520fcdc1c (diff) |
Restructure codec send/receive calls
In particular, after an initial fill of the codec's internal buffer, each
receive_frame call is followed by one or more send_packet calls. For
asynchronous codecs, this has the effect of letting the codec work while the
handler thread is waiting for an AVFrame structure to become available or
waiting for more decoded data to be needed. For synchronous codecs, this
makes the send_packet calls use up time that would be spent waiting.
Diffstat (limited to 'examples/alffplay.cpp')
-rw-r--r-- | examples/alffplay.cpp | 139 |
1 files changed, 64 insertions, 75 deletions
diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp index 466c4576..1f2c7d6c 100644 --- a/examples/alffplay.cpp +++ b/examples/alffplay.cpp @@ -188,6 +188,21 @@ class PacketQueue { size_t mTotalSize{0}; bool mFinished{false}; + AVPacket *getPacket(std::unique_lock<std::mutex> &lock) + { + while(mPackets.empty() && !mFinished) + mCondVar.wait(lock); + return mPackets.empty() ? nullptr : &mPackets.front(); + } + + void pop() + { + AVPacket *pkt = &mPackets.front(); + mTotalSize -= pkt->size; + av_packet_unref(pkt); + mPackets.pop_front(); + } + public: ~PacketQueue() { @@ -197,6 +212,22 @@ public: mTotalSize = 0; } + void sendTo(AVCodecContext *codecctx) + { + std::unique_lock<std::mutex> lock{mMutex}; + AVPacket *lastpkt{}; + while((lastpkt=getPacket(lock)) != nullptr) + { + const int ret{avcodec_send_packet(codecctx, lastpkt)}; + if(ret == AVERROR(EAGAIN)) return; + if(ret < 0) + std::cerr<< "Failed to send packet: "<<ret <<std::endl; + pop(); + } + if(!lastpkt) + avcodec_send_packet(codecctx, nullptr); + } + void setFinished() { { @@ -206,13 +237,6 @@ public: mCondVar.notify_one(); } - AVPacket *getPacket(std::unique_lock<std::mutex> &lock) - { - while(mPackets.empty() && !mFinished) - mCondVar.wait(lock); - return mPackets.empty() ? nullptr : &mPackets.front(); - } - bool put(const AVPacket *pkt) { { @@ -232,16 +256,6 @@ public: mCondVar.notify_one(); return true; } - - void pop() - { - AVPacket *pkt = &mPackets.front(); - mTotalSize -= pkt->size; - av_packet_unref(pkt); - mPackets.pop_front(); - } - - std::mutex &getMutex() noexcept { return mMutex; } }; @@ -547,33 +561,21 @@ int AudioState::decodeFrame() { while(!mMovie.mQuit.load(std::memory_order_relaxed)) { - { - std::unique_lock<std::mutex> lock{mPackets.getMutex()}; - AVPacket *lastpkt{}; - while((lastpkt=mPackets.getPacket(lock)) != nullptr) - { - 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); - } const int ret{avcodec_receive_frame(mCodecCtx.get(), mDecodedFrame.get())}; - if(ret == AVERROR_EOF) break; if(ret < 0) { - std::cerr<< "Failed to receive frame: "<<ret <<std::endl; - break; + if(ret == AVERROR_EOF) break; + if(ret != AVERROR(EAGAIN)) + { + std::cerr<< "Failed to receive frame: "<<ret <<std::endl; + break; + } } + mPackets.sendTo(mCodecCtx.get()); + if(mDecodedFrame->nb_samples <= 0) - { - av_frame_unref(mDecodedFrame.get()); continue; - } /* If provided, update w/ pts */ if(mDecodedFrame->best_effort_timestamp != AV_NOPTS_VALUE) @@ -1006,6 +1008,9 @@ int AudioState::handler() #endif samples = av_malloc(buffer_len); + /* Prefill the codec buffer. */ + mPackets.sendTo(mCodecCtx.get()); + srclock.lock(); while(alGetError() == AL_NO_ERROR && !mMovie.mQuit.load(std::memory_order_relaxed) && mConnected.test_and_set(std::memory_order_relaxed)) @@ -1305,39 +1310,20 @@ int VideoState::handler() [](Picture &pict) -> void { pict.mFrame = AVFramePtr{av_frame_alloc()}; }); + /* Prefill the codec buffer. */ + mPackets.sendTo(mCodecCtx.get()); + while(!mMovie.mQuit.load(std::memory_order_relaxed)) { - { - std::unique_lock<std::mutex> lock{mPackets.getMutex()}; - AVPacket *lastpkt{}; - while((lastpkt=mPackets.getPacket(lock)) != nullptr) - { - 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); - } + size_t write_idx{mPictQWrite.load(std::memory_order_relaxed)}; + Picture *vp{&mPictQ[write_idx]}; - while(!mMovie.mQuit.load(std::memory_order_relaxed)) + /* Decode video frame. */ + AVFrame *decoded_frame{vp->mFrame.get()}; + const int ret{avcodec_receive_frame(mCodecCtx.get(), decoded_frame)}; + if(ret == AVERROR_EOF) break; + if(ret == 0) { - 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>( @@ -1354,18 +1340,21 @@ int VideoState::handler() */ write_idx = (write_idx+1)%mPictQ.size(); mPictQWrite.store(write_idx, std::memory_order_release); + } + else if(ret != AVERROR(EAGAIN)) + std::cerr<< "Failed to receive frame: "<<ret <<std::endl; - 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); - } + mPackets.sendTo(mCodecCtx.get()); + + 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}; |