Move decoder frame to decoder
The video buffer held 3 frames: - the producer frame (for decoding) - the pending frame (to exchange between the producer and consumer) - the consumer frame (for rendering) It worked well, but it prevented video buffers to be chained, because the consumer frame of the first video buffer must be the same as the producer frame of the second video buffer. To solve this problem, make the decoder handle its decoding frame, and keep only the pending and consumer frames in the video_buffer. decoder -> pending -> consumer -> pending -> consumer |---------------------||---------------------| video_buffer 1 video_buffer 2 This paves the way to support asynchronous swscale.
This commit is contained in:
parent
9e737a1bef
commit
5cfa159e16
@ -14,7 +14,7 @@
|
||||
// set the decoded frame as ready for rendering, and notify
|
||||
static void
|
||||
push_frame(struct decoder *decoder) {
|
||||
video_buffer_producer_offer_frame(decoder->video_buffer);
|
||||
video_buffer_producer_offer_frame(decoder->video_buffer, &decoder->frame);
|
||||
}
|
||||
|
||||
void
|
||||
@ -36,11 +36,19 @@ decoder_open(struct decoder *decoder, const AVCodec *codec) {
|
||||
return false;
|
||||
}
|
||||
|
||||
decoder->frame = av_frame_alloc();
|
||||
if (!decoder->frame) {
|
||||
avcodec_close(decoder->codec_ctx);
|
||||
avcodec_free_context(&decoder->codec_ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
decoder_close(struct decoder *decoder) {
|
||||
av_frame_free(&decoder->frame);
|
||||
avcodec_close(decoder->codec_ctx);
|
||||
avcodec_free_context(&decoder->codec_ctx);
|
||||
}
|
||||
@ -55,8 +63,7 @@ decoder_push(struct decoder *decoder, const AVPacket *packet) {
|
||||
LOGE("Could not send video packet: %d", ret);
|
||||
return false;
|
||||
}
|
||||
ret = avcodec_receive_frame(decoder->codec_ctx,
|
||||
decoder->video_buffer->producer_frame);
|
||||
ret = avcodec_receive_frame(decoder->codec_ctx, decoder->frame);
|
||||
if (!ret) {
|
||||
// a frame was received
|
||||
push_frame(decoder);
|
||||
@ -67,7 +74,7 @@ decoder_push(struct decoder *decoder, const AVPacket *packet) {
|
||||
#else
|
||||
int got_picture;
|
||||
int len = avcodec_decode_video2(decoder->codec_ctx,
|
||||
decoder->video_buffer->decoding_frame,
|
||||
decoder->frame,
|
||||
&got_picture,
|
||||
packet);
|
||||
if (len < 0) {
|
||||
|
@ -11,6 +11,7 @@ struct video_buffer;
|
||||
struct decoder {
|
||||
struct video_buffer *video_buffer;
|
||||
AVCodecContext *codec_ctx;
|
||||
AVFrame *frame;
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -10,24 +10,19 @@ bool
|
||||
video_buffer_init(struct video_buffer *vb, bool wait_consumer,
|
||||
const struct video_buffer_callbacks *cbs,
|
||||
void *cbs_userdata) {
|
||||
vb->producer_frame = av_frame_alloc();
|
||||
if (!vb->producer_frame) {
|
||||
goto error_0;
|
||||
}
|
||||
|
||||
vb->pending_frame = av_frame_alloc();
|
||||
if (!vb->pending_frame) {
|
||||
goto error_1;
|
||||
goto error_0;
|
||||
}
|
||||
|
||||
vb->consumer_frame = av_frame_alloc();
|
||||
if (!vb->consumer_frame) {
|
||||
goto error_2;
|
||||
goto error_1;
|
||||
}
|
||||
|
||||
bool ok = sc_mutex_init(&vb->mutex);
|
||||
if (!ok) {
|
||||
goto error_3;
|
||||
goto error_2;
|
||||
}
|
||||
|
||||
vb->wait_consumer = wait_consumer;
|
||||
@ -54,12 +49,10 @@ video_buffer_init(struct video_buffer *vb, bool wait_consumer,
|
||||
|
||||
return true;
|
||||
|
||||
error_3:
|
||||
av_frame_free(&vb->consumer_frame);
|
||||
error_2:
|
||||
av_frame_free(&vb->pending_frame);
|
||||
av_frame_free(&vb->consumer_frame);
|
||||
error_1:
|
||||
av_frame_free(&vb->producer_frame);
|
||||
av_frame_free(&vb->pending_frame);
|
||||
error_0:
|
||||
return false;
|
||||
}
|
||||
@ -72,7 +65,6 @@ video_buffer_destroy(struct video_buffer *vb) {
|
||||
sc_mutex_destroy(&vb->mutex);
|
||||
av_frame_free(&vb->consumer_frame);
|
||||
av_frame_free(&vb->pending_frame);
|
||||
av_frame_free(&vb->producer_frame);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -83,7 +75,7 @@ swap_frames(AVFrame **lhs, AVFrame **rhs) {
|
||||
}
|
||||
|
||||
void
|
||||
video_buffer_producer_offer_frame(struct video_buffer *vb) {
|
||||
video_buffer_producer_offer_frame(struct video_buffer *vb, AVFrame **pframe) {
|
||||
sc_mutex_lock(&vb->mutex);
|
||||
if (vb->wait_consumer) {
|
||||
// wait for the current (expired) frame to be consumed
|
||||
@ -93,7 +85,7 @@ video_buffer_producer_offer_frame(struct video_buffer *vb) {
|
||||
}
|
||||
|
||||
av_frame_unref(vb->pending_frame);
|
||||
swap_frames(&vb->producer_frame, &vb->pending_frame);
|
||||
swap_frames(pframe, &vb->pending_frame);
|
||||
|
||||
bool skipped = !vb->pending_frame_consumed;
|
||||
if (skipped) {
|
||||
|
@ -29,7 +29,6 @@ typedef struct AVFrame AVFrame;
|
||||
*/
|
||||
|
||||
struct video_buffer {
|
||||
AVFrame *producer_frame;
|
||||
AVFrame *pending_frame;
|
||||
AVFrame *consumer_frame;
|
||||
|
||||
@ -60,8 +59,9 @@ void
|
||||
video_buffer_destroy(struct video_buffer *vb);
|
||||
|
||||
// set the producer frame as ready for consuming
|
||||
// the produced frame is exchanged with an unused allocated frame
|
||||
void
|
||||
video_buffer_producer_offer_frame(struct video_buffer *vb);
|
||||
video_buffer_producer_offer_frame(struct video_buffer *vb, AVFrame **pframe);
|
||||
|
||||
// mark the consumer frame as consumed and return it
|
||||
// the frame is valid until the next call to this function
|
||||
|
Loading…
x
Reference in New Issue
Block a user