Receive video frames in a loop
This commit is contained in:
parent
101e641288
commit
2b21a08f89
@ -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};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user