From 846e17728f2ed2af3672987ef61853f0bc96c224 Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Mon, 28 Oct 2024 13:08:13 -0400 Subject: Refactor video buffer and scaler, better A/V sync Signed-off-by: Andrew Opalach --- src/codec/codec.h | 30 ++++++++++++++++++++--- src/codec/ffmpeg/scaler.c | 61 ++++++++++++++++++++++++++++------------------ src/codec/ffmpeg/scaler.h | 19 ++++----------- src/codec/stb_image/impl.c | 12 +++++---- 4 files changed, 76 insertions(+), 46 deletions(-) (limited to 'src/codec') diff --git a/src/codec/codec.h b/src/codec/codec.h index 9528522..68f45f6 100644 --- a/src/codec/codec.h +++ b/src/codec/codec.h @@ -112,14 +112,18 @@ struct camu_audio_format { s32 channel_count; }; +struct camu_video_format { + s32 width; + s32 height; + s32 format; +}; + struct camu_codec_stream { u8 mode; u8 type; u64 duration; struct { - s32 width; - s32 height; - s32 format; + struct camu_video_format fmt; } video; struct { struct camu_audio_format fmt; @@ -192,6 +196,19 @@ struct camu_resampler { void (*free)(struct camu_resampler **); }; +struct camu_scaler_format { + bool scaler_needed; + struct camu_video_format in; + struct camu_video_format req; +}; + +struct camu_scaler { + bool (*init)(struct camu_scaler *, struct camu_scaler_format *); + bool (*scale)(struct camu_scaler *, const u8 **in_slice, s32 *in_strides); + AVFrame *(*get_frame)(struct camu_scaler *); + void (*free)(struct camu_scaler **); +}; + AL_UNUSED_FUNCTION_PUSH static inline bool camu_resampler_format_matches(struct camu_resampler_format *fmt) @@ -279,6 +296,13 @@ static inline f64 camu_audio_format_bytes_to_sec(struct camu_audio_format *fmt, return samples / (f64)fmt->sample_rate; } +static inline void camu_video_format_copy(struct camu_video_format *dest, struct camu_video_format *src) +{ + dest->width = src->width; + dest->height = src->height; + dest->format = src->format; +} + static const char *camu_pixel_format_name(s32 format) { switch (format) { diff --git a/src/codec/ffmpeg/scaler.c b/src/codec/ffmpeg/scaler.c index 9b5c5e0..d233268 100644 --- a/src/codec/ffmpeg/scaler.c +++ b/src/codec/ffmpeg/scaler.c @@ -34,51 +34,64 @@ static AVFrame *alloc_picture(enum AVPixelFormat pix_fmt, s32 width, s32 height) return frame; } -bool camu_ff_scaler_init(struct camu_ff_scaler *scale, struct camu_ff_scale_fmt *fmt) +static bool ff_scaler_init(struct camu_scaler *scale, struct camu_scaler_format *fmt) { - al_memset(scale, 0, sizeof(struct camu_ff_scaler)); + struct camu_ff_scaler *av = (struct camu_ff_scaler *)scale; + al_assert(fmt->scaler_needed); - if (fmt->in_width == fmt->req_width && fmt->in_height == fmt->req_height && - fmt->in_format == fmt->req_format) { - fmt->scaler_needed = false; - return true; - } + av->fmt = *fmt; s32 flags = SWS_BITEXACT; - scale->scaler_context = sws_getContext(fmt->in_width, fmt->in_height, fmt->in_format, - fmt->req_width, fmt->req_height, fmt->req_format, flags, NULL, NULL, NULL); - if (!scale->scaler_context) { + av->scaler_context = sws_getContext(fmt->in.width, fmt->in.height, fmt->in.format, + fmt->req.width, fmt->req.height, fmt->req.format, flags, NULL, NULL, NULL); + if (!av->scaler_context) { al_log_error("ff_scaler", "Failed to create scaler context."); return false; } - scale->frame = alloc_picture(fmt->req_format, fmt->req_width, fmt->req_height); - if (!scale->frame) { + av->frame = alloc_picture(fmt->req.format, fmt->req.width, fmt->req.height); + if (!av->frame) { al_log_error("ff_scaler", "Failed to allocate frame."); return false; } - fmt->scaler_needed = true; - - scale->fmt = *fmt; - return true; } -bool camu_ff_scaler_scale(struct camu_ff_scaler *scale, const u8 **in_slice, s32 *in_strides) +static bool ff_scaler_scale(struct camu_scaler *scale, const u8 **in_slice, s32 *in_strides) { - s32 ret = sws_scale(scale->scaler_context, in_slice, in_strides, 0, scale->fmt.in_height, - scale->frame->data, scale->frame->linesize); - if (ret != scale->fmt.req_height) { + struct camu_ff_scaler *av = (struct camu_ff_scaler *)scale; + s32 ret = sws_scale(av->scaler_context, in_slice, in_strides, 0, av->fmt.in.height, + av->frame->data, av->frame->linesize); + if (ret != av->fmt.req.height) { al_log_error("ff_scaler", "Failed to scale frame (%s).", av_err2str(ret)); return false; } return true; } -void camu_ff_scaler_close(struct camu_ff_scaler *scale) +static AVFrame *ff_scaler_get_frame(struct camu_scaler *scale) +{ + struct camu_ff_scaler *av = (struct camu_ff_scaler *)scale; + return av->frame; +} + +static void ff_scaler_free(struct camu_scaler **scale) +{ + struct camu_ff_scaler *av = (struct camu_ff_scaler *)*scale; + av_freep(&av->frame->data[0]); + av_frame_free(&av->frame); + sws_freeContext(av->scaler_context); + al_free(av); + *scale = NULL; +} + +struct camu_scaler *camu_ff_scaler_create(void) { - av_freep(&scale->frame->data[0]); - av_frame_free(&scale->frame); - sws_freeContext(scale->scaler_context); + struct camu_ff_scaler *av = al_alloc_object(struct camu_ff_scaler); + av->scale.init = ff_scaler_init; + av->scale.scale = ff_scaler_scale; + av->scale.get_frame = ff_scaler_get_frame; + av->scale.free = ff_scaler_free; + return (struct camu_scaler *)av; } diff --git a/src/codec/ffmpeg/scaler.h b/src/codec/ffmpeg/scaler.h index 3e53fbb..a4effb3 100644 --- a/src/codec/ffmpeg/scaler.h +++ b/src/codec/ffmpeg/scaler.h @@ -1,24 +1,15 @@ #pragma once -#include #include +#include -struct camu_ff_scale_fmt { - s32 in_width; - s32 in_height; - enum AVPixelFormat in_format; - s32 req_width; - s32 req_height; - enum AVPixelFormat req_format; - bool scaler_needed; -}; +#include "../codec.h" struct camu_ff_scaler { + struct camu_scaler scale; struct SwsContext *scaler_context; - struct camu_ff_scale_fmt fmt; + struct camu_scaler_format fmt; AVFrame *frame; }; -bool camu_ff_scaler_init(struct camu_ff_scaler *scale, struct camu_ff_scale_fmt *fmt); -bool camu_ff_scaler_scale(struct camu_ff_scaler *scale, const u8 **in_slice, s32 *in_strides); -void camu_ff_scaler_close(struct camu_ff_scaler *scale); +struct camu_scaler *camu_ff_scaler_create(void); diff --git a/src/codec/stb_image/impl.c b/src/codec/stb_image/impl.c index 98d9e2c..ac1cbc5 100644 --- a/src/codec/stb_image/impl.c +++ b/src/codec/stb_image/impl.c @@ -40,9 +40,10 @@ static bool stbi_demuxer_init(struct camu_demuxer *demux, struct cch_handle *han struct camu_codec_stream stream = { 0 }; stream.mode = CAMU_NORMAL; stream.type = CAMU_STREAM_VIDEO; - stream.video.width = w; - stream.video.height = h; - stream.video.format = camu_pixel_format_from_channels(channels); + struct camu_video_format *fmt = &stream.video.fmt; + fmt->width = w; + fmt->height = h; + fmt->format = camu_pixel_format_from_channels(channels); al_array_push(stb->demux.streams, stream); @@ -106,7 +107,8 @@ static s32 stbi_decoder_push(struct camu_decoder *dec, struct camu_codec_packet u8 *data = aki_buffer_get_ptr(packet->buffer, 0); u8 *pixels = stbi_load_from_memory(data, packet->buffer->size, &w, &h, &channels, 0); if (!pixels) return CAMU_ERR_ERROR; - al_assert(w == stb->stream->video.width && h == stb->stream->video.height); + struct camu_video_format *fmt = &stb->stream->video.fmt; + al_assert(w == fmt->width && h == fmt->height); struct camu_codec_frame *frame = al_alloc_object(struct camu_codec_frame); frame->mode = CAMU_NORMAL; @@ -115,7 +117,7 @@ static s32 stbi_decoder_push(struct camu_decoder *dec, struct camu_codec_packet frame->video.width = w; frame->video.height = h; frame->format = camu_pixel_format_from_channels(channels); - al_assert(frame->format == stb->stream->video.format); + al_assert(frame->format == fmt->format); frame->pts = 0.0; stb->callback(stb->userdata, frame); -- cgit v1.2.3-101-g0448