#define AL_LOG_SECTION "stb_image" #include #include "common.h" #define STBI_MALLOC camu_page_alloc #define STBI_FREE al_free #define STBI_REALLOC camu_page_realloc #define STBI_ASSERT al_assert #define STBI_NO_STDIO #define STBI_NO_FAILURE_STRINGS #define STB_IMAGE_IMPLEMENTATION #ifdef CAMU_LOCAL_STB #include #else #include #endif #include "stb_image.h" #define FORCE_RGBA #ifdef LIANA_SERVER #include "../cache/entry.h" static bool stbi_demuxer_init(struct camu_demuxer *demux, struct cch_handle *handle) { struct camu_stbi_demuxer *stb = (struct camu_stbi_demuxer *)demux; stb->handle = handle; nn_buffer_init(&stb->buffer); stb->eof = false; cch_handle_seek(stb->handle, 0, SEEK_SET); struct cch_backing *backing = stb->handle->entry->backing; off_t size = backing->get_size_if_known(backing); nn_buffer_ensure_space(&stb->buffer, size); cch_handle_read(stb->handle, nn_buffer_get_ptr(&stb->buffer, 0), size); stb->buffer.size = size; s32 w, h, channels; u8 *data = nn_buffer_get_ptr(&stb->buffer, 0); if (!stbi_info_from_memory(data, stb->buffer.size, &w, &h, &channels)) { log_error("stbi_info_from_memory() failed."); return false; } struct camu_codec_stream stream = { 0 }; stream.mode = CAMU_NORMAL; stream.type = CAMU_STREAM_VIDEO; struct camu_video_format *fmt = &stream.video.fmt; fmt->width = (u32)w; fmt->height = (u32)h; #ifdef FORCE_RGBA fmt->format = camu_pixel_format_from_channels(4); #else fmt->format = camu_pixel_format_from_channels(channels); #endif al_array_push(stb->demux.streams, stream); return true; } static s32 stbi_demuxer_get_packet(struct camu_demuxer *demux, struct camu_codec_packet *packet) { struct camu_stbi_demuxer *stb = (struct camu_stbi_demuxer *)demux; if (!stb->eof) { packet->mode = CAMU_NORMAL; packet->buffer = &stb->buffer; stb->eof = true; return CAMU_OK; } return CAMU_ERR_EOF; } static u64 stbi_demuxer_get_duration(struct camu_demuxer *demux) { (void)demux; return 0; } static bool stbi_demuxer_seek(struct camu_demuxer *demux, u64 pos, bool bytes) { (void)demux; (void)pos; (void)bytes; return true; } static void stbi_demuxer_free(struct camu_demuxer **demux) { struct camu_stbi_demuxer *stb = (struct camu_stbi_demuxer *)*demux; nn_buffer_free(&stb->buffer); al_array_free(stb->demux.streams); al_free(stb); *demux = NULL; } struct camu_demuxer *camu_stbi_demuxer_create(void) { struct camu_stbi_demuxer *stb = al_alloc_object(struct camu_stbi_demuxer); stb->demux.mode = CAMU_NORMAL; al_array_init(stb->demux.streams); stb->demux.init = stbi_demuxer_init; stb->demux.get_packet = stbi_demuxer_get_packet; stb->demux.get_duration = stbi_demuxer_get_duration; stb->demux.seek = stbi_demuxer_seek; stb->demux.free = stbi_demuxer_free; return (struct camu_demuxer *)stb; } #endif #ifdef LIANA_CLIENT static bool stbi_decoder_init(struct camu_decoder *dec, struct camu_renderer *renderer, struct camu_codec_stream *stream, void (*callback)(void *, struct camu_codec_frame *), void *userdata) { struct camu_stbi_decoder *stb = (struct camu_stbi_decoder *)dec; (void)renderer; stb->stream = stream; stb->callback = callback; stb->userdata = userdata; return true; } static s32 stbi_decoder_push(struct camu_decoder *dec, struct camu_codec_packet *packet) { struct camu_stbi_decoder *stb = (struct camu_stbi_decoder *)dec; if (!packet) return CAMU_OK; s32 w, h, channels; u8 *data = nn_buffer_get_ptr(packet->buffer, 0); #ifdef FORCE_RGBA u8 *pixels = stbi_load_from_memory(data, packet->buffer->size, &w, &h, &channels, 4); #else u8 *pixels = stbi_load_from_memory(data, packet->buffer->size, &w, &h, &channels, 0); #endif if (!pixels) { log_error("stbi_load_from_memory() failed."); return CAMU_ERR_ERROR; } struct camu_video_format *fmt = &stb->stream->video.fmt; al_assert(w > 0 && h > 0 && (u32)w == fmt->width && (u32)h == fmt->height); struct camu_codec_frame *frame = al_alloc_object(struct camu_codec_frame); frame->mode = CAMU_NORMAL; frame->flags = 0; frame->data = pixels; frame->video.width = (u32)w; frame->video.height = (u32)h; #ifdef FORCE_RGBA frame->format = camu_pixel_format_from_channels(4); #else frame->format = camu_pixel_format_from_channels(channels); al_assert(frame->format == fmt->format); #endif frame->pts = 0.0; stb->callback(stb->userdata, frame); return CAMU_OK; } static void stbi_decoder_flush(struct camu_decoder *dec) { (void)dec; } static s32 stbi_decoder_process(struct camu_decoder *dec) { (void)dec; return CAMU_ERR_EOF; } static void stbi_decoder_free(struct camu_decoder **dec) { struct camu_stbi_decoder *stb = (struct camu_stbi_decoder *)*dec; al_free(stb); *dec = NULL; } struct camu_decoder *camu_stbi_decoder_create(void) { struct camu_stbi_decoder *stb = al_alloc_object(struct camu_stbi_decoder); stb->dec.mode = CAMU_NORMAL; stb->dec.init = stbi_decoder_init; stb->dec.push = stbi_decoder_push; stb->dec.process = stbi_decoder_process; stb->dec.flush = stbi_decoder_flush; stb->dec.free = stbi_decoder_free; return (struct camu_decoder *)stb; } #endif