Receive video frames in a loop

This commit is contained in:
Chris Robinson 2019-07-16 20:20:25 -07:00
parent 101e641288
commit 2b21a08f89

View File

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