#define WUFFS_CONFIG__MODULES #define WUFFS_CONFIG__MODULE__BASE #define WUFFS_CONFIG__MODULE__ADLER32 #define WUFFS_CONFIG__MODULE__DEFLATE #define WUFFS_CONFIG__MODULE__ZLIB #define WUFFS_CONFIG__MODULE__CRC32 #define WUFFS_CONFIG__MODULE__PNG #define WUFFS_CONFIG__MODULE__JPEG #define WUFFS_CONFIG__MODULE__IMAGE #define WUFFS_IMPLEMENTATION #ifdef CAMU_LOCAL_WUFFS #include #else #include #endif #include "wuffs.h" #include "common.h" #ifdef LIANA_SERVER #include "../cache/entry.h" static bool wuffs_demuxer_init(struct camu_demuxer *demux, struct cch_handle *handle) { struct camu_wuffs_demuxer *wfs = (struct camu_wuffs_demuxer *)demux; wfs->handle = handle; nn_buffer_init(&wfs->buffer); wfs->eof = false; cch_handle_seek(wfs->handle, 0, SEEK_SET); struct cch_backing *backing = wfs->handle->entry->backing; off_t size = backing->get_size_if_known(backing); nn_buffer_ensure_space(&wfs->buffer, size); cch_handle_read(wfs->handle, nn_buffer_get_ptr(&wfs->buffer, 0), size); wfs->buffer.size = size; wuffs_png__decoder *wf_dec = wuffs_png__decoder__alloc(); if (!wf_dec) goto err; wuffs_png__decoder__set_quirk(wf_dec, WUFFS_BASE__QUIRK_IGNORE_CHECKSUM, true); wuffs_base__io_buffer src = { 0 }; src.data.ptr = nn_buffer_get_ptr(&wfs->buffer, 0); src.data.len = size; src.meta.wi = size; src.meta.closed = true; wuffs_base__image_config ic = { 0 }; wuffs_base__status status = wuffs_png__decoder__decode_image_config(wf_dec, &ic, &src); if (!wuffs_base__status__is_ok(&status)) goto err; if (!wuffs_base__image_config__is_valid(&ic)) goto err; 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 = wuffs_base__pixel_config__width(&ic.pixcfg); fmt->height = wuffs_base__pixel_config__height(&ic.pixcfg); fmt->format = CAMU_PIXEL_FORMAT_RGBA; al_array_push(wfs->demux.streams, stream); free(wf_dec); return true; err: if (wf_dec) free(wf_dec); return false; } static s32 wuffs_demuxer_get_packet(struct camu_demuxer *demux, struct camu_codec_packet *packet) { struct camu_wuffs_demuxer *wfs = (struct camu_wuffs_demuxer *)demux; if (!wfs->eof) { packet->mode = CAMU_NORMAL; packet->buffer = &wfs->buffer; wfs->eof = true; return CAMU_OK; } return CAMU_ERR_EOF; } static u64 wuffs_demuxer_get_duration(struct camu_demuxer *demux) { (void)demux; return 0; } static bool wuffs_demuxer_seek(struct camu_demuxer *demux, u64 pos, bool bytes) { (void)demux; (void)pos; (void)bytes; return true; } static void wuffs_demuxer_free(struct camu_demuxer **demux) { struct camu_wuffs_demuxer *wfs = (struct camu_wuffs_demuxer *)*demux; nn_buffer_free(&wfs->buffer); al_array_free(wfs->demux.streams); al_free(wfs); *demux = NULL; } struct camu_demuxer *camu_wuffs_demuxer_create(void) { struct camu_wuffs_demuxer *wfs = al_alloc_object(struct camu_wuffs_demuxer); wfs->demux.mode = CAMU_NORMAL; al_array_init(wfs->demux.streams); wfs->demux.init = wuffs_demuxer_init; wfs->demux.get_packet = wuffs_demuxer_get_packet; wfs->demux.get_duration = wuffs_demuxer_get_duration; wfs->demux.seek = wuffs_demuxer_seek; wfs->demux.free = wuffs_demuxer_free; return (struct camu_demuxer *)wfs; } #endif #ifdef LIANA_CLIENT static bool wuffs_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_wuffs_decoder *wfs = (struct camu_wuffs_decoder *)dec; (void)renderer; wfs->stream = stream; wfs->callback = callback; wfs->userdata = userdata; return true; } static s32 wuffs_decoder_push(struct camu_decoder *dec, struct camu_codec_packet *packet) { struct camu_wuffs_decoder *wfs = (struct camu_wuffs_decoder *)dec; if (!packet) return CAMU_OK; struct camu_codec_frame *frame = al_alloc_object(struct camu_codec_frame); frame->mode = CAMU_NORMAL; frame->flags = 0; frame->data = NULL; struct camu_video_format *fmt = &wfs->stream->video.fmt; frame->video.width = fmt->width; frame->video.height = fmt->height; frame->format = CAMU_PIXEL_FORMAT_RGBA; wuffs_png__decoder *wf_dec = wuffs_png__decoder__alloc(); if (!wf_dec) goto err; wuffs_png__decoder__set_quirk(wf_dec, WUFFS_BASE__QUIRK_IGNORE_CHECKSUM, true); wuffs_base__io_buffer src = { 0 }; src.data.ptr = nn_buffer_get_ptr(packet->buffer, 0); src.data.len = packet->buffer->size; src.meta.wi = packet->buffer->size; src.meta.closed = true; wuffs_base__image_config ic = { 0 }; wuffs_base__status status = wuffs_png__decoder__decode_image_config(wf_dec, &ic, &src); if (!wuffs_base__status__is_ok(&status)) goto err; if (!wuffs_base__image_config__is_valid(&ic)) goto err; u32 pixsub = WUFFS_BASE__PIXEL_SUBSAMPLING__NONE; u32 pixfmt = WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL; wuffs_base__pixel_config__set(&ic.pixcfg, pixfmt, pixsub, fmt->width, fmt->height); wuffs_base__pixel_buffer pb = { 0 }; size_t dst_size = fmt->width * fmt->height * 4; size_t wrk_size = wuffs_png__decoder__workbuf_len(wf_dec).max_incl; frame->data = camu_page_alloc(dst_size + wrk_size); status = wuffs_base__pixel_buffer__set_from_slice(&pb, &ic.pixcfg, wuffs_base__make_slice_u8(frame->data, dst_size)); if (!wuffs_base__status__is_ok(&status)) goto err; wuffs_base__slice_u8 wrk = wuffs_base__make_slice_u8(frame->data + dst_size, wrk_size); status = wuffs_png__decoder__decode_frame(wf_dec, &pb, &src, 0, wrk, NULL); if (!wuffs_base__status__is_ok(&status)) goto err; wfs->callback(wfs->userdata, frame); free(wf_dec); return CAMU_OK; err: if (wf_dec) free(wf_dec); camu_codec_frame_discard(frame); return CAMU_ERR_ERROR; } static void wuffs_decoder_flush(struct camu_decoder *dec) { (void)dec; } static s32 wuffs_decoder_process(struct camu_decoder *dec) { (void)dec; return CAMU_ERR_EOF; } static void wuffs_decoder_free(struct camu_decoder **dec) { struct camu_wuffs_decoder *wfs = (struct camu_wuffs_decoder *)*dec; al_free(wfs); *dec = NULL; } struct camu_decoder *camu_wuffs_decoder_create(void) { struct camu_wuffs_decoder *wfs = al_alloc_object(struct camu_wuffs_decoder); wfs->dec.mode = CAMU_NORMAL; wfs->dec.init = wuffs_decoder_init; wfs->dec.push = wuffs_decoder_push; wfs->dec.process = wuffs_decoder_process; wfs->dec.flush = wuffs_decoder_flush; wfs->dec.free = wuffs_decoder_free; return (struct camu_decoder *)wfs; } #endif