Add intermediate frame in video buffer

There were only two frames simultaneously:
 - one used by the decoder;
 - one used by the renderer.

When the decoder finished decoding a frame, it swapped it with the
rendering frame.

Adding a third frame provides several benefits:
 - the decoder do not have to wait for the renderer to release the
   mutex;
 - it simplifies the video_buffer API;
 - it makes the rendering frame valid until the next call to
   video_buffer_take_rendering_frame(), which will be useful for
   swscaling on window resize.
This commit is contained in:
Romain Vimont
2021-02-01 09:38:11 +01:00
parent c53bd4d8b6
commit c0c4ba7009
3 changed files with 70 additions and 32 deletions

View File

@@ -11,14 +11,35 @@
// forward declarations
typedef struct AVFrame AVFrame;
/**
* There are 3 frames in memory:
* - one frame is held by the decoder (decoding_frame)
* - one frame is held by the renderer (rendering_frame)
* - one frame is shared between the decoder and the renderer (pending_frame)
*
* The decoder decodes a packet into the decoding_frame (it may takes time).
*
* Once the frame is decoded, it calls video_buffer_offer_decoded_frame(),
* which swaps the decoding and pending frames.
*
* When the renderer is notified that a new frame is available, it calls
* video_buffer_take_rendering_frame() to retrieve it, which swaps the pending
* and rendering frames. The frame is valid until the next call, without
* blocking the decoder.
*/
struct video_buffer {
AVFrame *decoding_frame;
AVFrame *pending_frame;
AVFrame *rendering_frame;
sc_mutex mutex;
bool render_expired_frames;
bool interrupted;
sc_cond rendering_frame_consumed_cond;
bool rendering_frame_consumed;
sc_cond pending_frame_consumed_cond;
bool pending_frame_consumed;
struct fps_counter *fps_counter;
};
@@ -30,18 +51,15 @@ void
video_buffer_destroy(struct video_buffer *vb);
// set the decoded frame as ready for rendering
// this function locks vb->mutex during its execution
// the output flag is set to report whether the previous frame has been skipped
void
video_buffer_offer_decoded_frame(struct video_buffer *vb,
bool *previous_frame_skipped);
// mark the rendering frame as consumed and return it
// MUST be called with vb->mutex locked!!!
// the caller is expected to render the returned frame to some texture before
// unlocking vb->mutex
// the frame is valid until the next call to this function
const AVFrame *
video_buffer_consume_rendered_frame(struct video_buffer *vb);
video_buffer_take_rendering_frame(struct video_buffer *vb);
// wake up and avoid any blocking call
void