#define AL_LOG_SECTION "ff_scaler" #include #include #include #include "scaler.h" static AVFrame *alloc_picture(enum AVPixelFormat pix_fmt, s32 width, s32 height) { AVFrame *frame = av_frame_alloc(); if (!frame) return NULL; s32 ret = av_image_alloc(frame->data, frame->linesize, width, height, pix_fmt, 32); if (ret < 0) { log_error("Failed to allocate picture buffer (%s).", av_err2str(ret)); return NULL; } /* s32 size = av_image_get_buffer_size(pix_fmt, width, height, 1); u8 *buffer = (u8 *)av_malloc(size); if (!buffer) { av_free(frame); return NULL; } s32 ret = av_image_fill_arrays(frame->data, frame->linesize, buffer, pix_fmt, width, height, 1); if (ret < 0) { log_error("Failed to allocate picture buffer (%s).", av_err2str(ret)); av_free(frame); return NULL; } */ frame->width = width; frame->height = height; frame->format = pix_fmt; return frame; } static bool ff_scaler_init(struct camu_scaler *scale, struct camu_scaler_format *fmt) { struct camu_ff_scaler *av = (struct camu_ff_scaler *)scale; al_assert(fmt->scaler_needed); av->fmt = *fmt; av->scaler_context = sws_getContext( fmt->in.width, fmt->in.height, (enum AVPixelFormat)fmt->in.format, fmt->req.width, fmt->req.height, (enum AVPixelFormat)fmt->req.format, SWS_BITEXACT, NULL, NULL, NULL); if (!av->scaler_context) { log_error("Failed to create scaler context."); return false; } struct camu_codec_frame *frame = &av->frame; frame->av.frame = alloc_picture((enum AVPixelFormat)fmt->req.format, fmt->req.width, fmt->req.height); if (!frame->av.frame) { log_error("Failed to allocate frame."); return false; } return true; } static bool ff_scaler_scale(struct camu_scaler *scale, const u8 **in_slice, s32 *in_strides) { struct camu_ff_scaler *av = (struct camu_ff_scaler *)scale; AVFrame *frame = av->frame.av.frame; struct camu_scaler_format *fmt = &av->fmt; s32 slice_height = (s32)fmt->in.height; s32 ret = sws_scale(av->scaler_context, in_slice, in_strides, 0, slice_height, frame->data, frame->linesize); if (ret != (s32)fmt->req.height) { log_error("Failed to scale frame (%s).", av_err2str(ret)); return false; } return true; } static struct camu_codec_frame *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; struct camu_codec_frame *frame = &av->frame; if (frame->av.frame) { av_freep(&frame->av.frame->data[0]); av_frame_free(&frame->av.frame); } if (av->scaler_context) { sws_freeContext(av->scaler_context); av->scaler_context = NULL; } al_free(av); *scale = NULL; } struct camu_scaler *camu_ff_scaler_create(void) { 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; }