summaryrefslogtreecommitdiff
path: root/src/codec
diff options
context:
space:
mode:
Diffstat (limited to 'src/codec')
-rw-r--r--src/codec/codec.h52
-rw-r--r--src/codec/codecs.c96
-rw-r--r--src/codec/codecs.h15
-rw-r--r--src/codec/ffmpeg/decoder.c10
-rw-r--r--src/codec/meson.build2
-rw-r--r--src/codec/spng/meson.build7
-rw-r--r--src/codec/spng/server.c7
-rw-r--r--src/codec/stb_image/meson.build7
-rw-r--r--src/codec/wuffs/client.c100
-rw-r--r--src/codec/wuffs/impl.c204
-rw-r--r--src/codec/wuffs/inc.h12
-rw-r--r--src/codec/wuffs/meson.build7
-rw-r--r--src/codec/wuffs/server.c102
13 files changed, 401 insertions, 220 deletions
diff --git a/src/codec/codec.h b/src/codec/codec.h
index 25ec73e..701ef16 100644
--- a/src/codec/codec.h
+++ b/src/codec/codec.h
@@ -1,6 +1,7 @@
#pragma once
#include <al/array.h>
+#include <al/str.h>
#include <nnwt/common.h>
#ifdef CAMU_HAVE_FFMPEG
#include <libavutil/pixdesc.h>
@@ -9,6 +10,8 @@
#include "../cache/handle.h"
+#include "codecs.h"
+
enum {
CAMU_LANG_UNKNOWN = 0,
CAMU_LANG_ENGLISH,
@@ -59,7 +62,6 @@ enum {
enum {
CAMU_PIXEL_FORMAT_RGBA = AV_PIX_FMT_RGBA,
- CAMU_PIXEL_FORMAT_RGB8 = AV_PIX_FMT_RGB8,
CAMU_PIXEL_FORMAT_RGB24 = AV_PIX_FMT_RGB24,
CAMU_PIXEL_FORMAT_RGB32 = AV_PIX_FMT_RGB32,
CAMU_PIXEL_FORMAT_GREYA = AV_PIX_FMT_GRAY8A,
@@ -67,6 +69,13 @@ enum {
CAMU_PIXEL_FORMAT_PAL8 = AV_PIX_FMT_PAL8
};
+enum {
+ CAMU_CODEC_FALLBACK = -1,
+ CAMU_CODEC_NONE = AV_CODEC_ID_NONE,
+ CAMU_CODEC_PNG = AV_CODEC_ID_PNG,
+ CAMU_CODEC_JPEG = AV_CODEC_ID_MJPEG
+};
+
#define CAMU_PLANAR_DATA_POINTERS AV_NUM_DATA_POINTERS
#else
enum {
@@ -107,9 +116,18 @@ enum {
enum {
CAMU_PIXEL_FORMAT_RGBA = 0,
- CAMU_PIXEL_FORMAT_RGB,
+ CAMU_PIXEL_FORMAT_RGB24,
+ CAMU_PIXEL_FORMAT_RGB32,
CAMU_PIXEL_FORMAT_GREYA,
- CAMU_PIXEL_FORMAT_GREY
+ CAMU_PIXEL_FORMAT_GREY,
+ CAMU_PIXEL_FORMAT_PAL8
+};
+
+enum {
+ CAMU_CODEC_FALLBACK = -1,
+ CAMU_CODEC_NONE,
+ CAMU_CODEC_PNG,
+ CAMU_CODEC_JPEG
};
#define CAMU_PLANAR_DATA_POINTERS 8
@@ -150,6 +168,7 @@ struct camu_codec_stream {
u8 type;
s32 index;
u64 duration;
+ struct camu_codec_info *codec_info;
struct {
struct camu_video_format fmt;
} video;
@@ -256,6 +275,7 @@ static inline bool camu_resampler_format_matches(struct camu_resampler_format *f
&& fmt->in.channel_count == fmt->req.channel_count;
}
+#ifdef CAMU_HAVE_FFMPEG
#ifndef CAMU_OLD_FFMPEG
#define AV_CODECPAR_CHANNEL_LAYOUT(codecpar) ((codecpar)->ch_layout)
#define AV_CODECPAR_CHANNELS(codecpar) ((codecpar)->ch_layout.nb_channels)
@@ -279,6 +299,7 @@ static inline void camu_copy_channel_layout(u64 *dest, u64 *src)
*dest = *src;
}
#endif
+#endif
static inline void camu_audio_format_copy(struct camu_audio_format *dest, struct camu_audio_format *src)
{
@@ -408,3 +429,28 @@ static inline void camu_codec_frame_discard(struct camu_codec_frame *frame)
if (frame->mode == CAMU_NORMAL && frame->data) al_free(frame->data);
al_free(frame);
}
+
+static inline s32 camu_guess_format(str *short_name, str *ext, str *mime_type)
+{
+ if (al_str_eq(ext, &al_str_c(".png"))) {
+ return CAMU_CODEC_PNG;
+ } else if (al_str_eq(ext, &al_str_c(".jpeg")) || al_str_eq(ext, &al_str_c(".jpg"))) {
+ return CAMU_CODEC_JPEG;
+ }
+#ifdef CAMU_HAVE_FFMPEG
+ char *c_short_name = short_name ? al_str_to_c_str(short_name) : NULL;
+ char *c_ext = ext ? al_str_to_c_str(ext) : NULL;
+ char *c_mime_type = mime_type ? al_str_to_c_str(mime_type) : NULL;
+ // Empty short_name to attempt avoiding image2 probing.
+ const AVOutputFormat *fmt = av_guess_format(c_short_name ? c_short_name : "", c_ext, c_mime_type);
+ if (c_short_name) al_free(c_short_name);
+ if (c_ext) al_free(c_ext);
+ if (c_mime_type) al_free(c_mime_type);
+ // In FFmpeg AV_CODEC_ID_MJPEG also means "image2".
+ if (fmt) return (fmt->audio_codec != AV_CODEC_ID_NONE) ? fmt->audio_codec : fmt->video_codec;
+#else
+ (void)short_name;
+ (void)mime_type;
+#endif
+ return -1;
+}
diff --git a/src/codec/codecs.c b/src/codec/codecs.c
new file mode 100644
index 0000000..7374517
--- /dev/null
+++ b/src/codec/codecs.c
@@ -0,0 +1,96 @@
+#include "codecs.h"
+#include "codec.h"
+
+#ifdef LIANA_SERVER
+#include "../../codec/wuffs/demuxer.h"
+#include "../../codec/stb_image/demuxer.h"
+#include "../../codec/spng/demuxer.h"
+#ifdef CAMU_HAVE_FFMPEG
+#include "../../codec/ffmpeg/demuxer.h"
+#endif
+#endif
+
+#ifdef LIANA_CLIENT
+#include "../../codec/wuffs/decoder.h"
+#include "../../codec/stb_image/decoder.h"
+#include "../../codec/spng/decoder.h"
+#ifdef CAMU_HAVE_FFMPEG
+#include "../../codec/ffmpeg/decoder.h"
+#endif
+#endif
+
+struct camu_codec_info codec_information[] = {
+#ifdef CAMU_HAVE_WUFFS
+ {
+ .name = al_str_c("wuffs"),
+ .supported = (s32[]){ CAMU_CODEC_PNG, CAMU_CODEC_NONE },
+#ifdef LIANA_SERVER
+ .create_demuxer = camu_wuffs_demuxer_create,
+#endif
+#ifdef LIANA_CLIENT
+ .create_decoder = camu_wuffs_decoder_create
+#endif
+ },
+#endif
+#ifdef CAMU_HAVE_STB_IMAGE
+ {
+ .name = al_str_c("stb_image"),
+ .supported = (s32[]){ CAMU_CODEC_PNG, CAMU_CODEC_JPEG, CAMU_CODEC_NONE },
+#ifdef LIANA_SERVER
+ .create_demuxer = camu_stbi_demuxer_create,
+#endif
+#ifdef LIANA_CLIENT
+ .create_decoder = camu_stbi_decoder_create
+#endif
+ },
+#endif
+#ifdef CAMU_HAVE_SPNG
+ {
+ .name = al_str_c("spng"),
+ .supported = (s32[]){ CAMU_CODEC_PNG, CAMU_CODEC_NONE },
+#ifdef LIANA_SERVER
+ .create_demuxer = camu_spng_demuxer_create,
+#endif
+#ifdef LIANA_CLIENT
+ .create_decoder = camu_spng_decoder_create
+#endif
+ },
+#endif
+#ifdef CAMU_HAVE_FFMPEG
+ {
+ .name = al_str_c("FFmpeg"),
+ .supported = (s32[]){ CAMU_CODEC_FALLBACK },
+#ifdef LIANA_SERVER
+ .create_demuxer = camu_ff_demuxer_create,
+#endif
+#ifdef LIANA_CLIENT
+ .create_decoder = camu_ff_decoder_create
+#endif
+ },
+#endif
+};
+
+struct camu_codec_info *camu_codec_info_by_type(s32 type)
+{
+ for (u32 i = 0; i < ARRAY_SIZE(codec_information); i++) {
+ struct camu_codec_info *info = &codec_information[i];
+ s32 *supported = info->supported;
+ while (*supported != CAMU_CODEC_NONE) {
+ if (type == (*supported) || (*supported) == CAMU_CODEC_FALLBACK) {
+ return info;
+ }
+ supported++;
+ }
+ }
+ return NULL;
+}
+
+struct camu_codec_info *camu_codec_info_by_name(str *name)
+{
+ for (u32 i = 0; i < ARRAY_SIZE(codec_information); i++) {
+ if (al_str_eq(&codec_information[i].name, name)) {
+ return &codec_information[i];
+ }
+ }
+ return NULL;
+}
diff --git a/src/codec/codecs.h b/src/codec/codecs.h
new file mode 100644
index 0000000..d383eec
--- /dev/null
+++ b/src/codec/codecs.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <al/str.h>
+
+struct camu_codec_info {
+ str name;
+ s32 *supported;
+ struct camu_demuxer *(*create_demuxer)(void);
+ struct camu_decoder *(*create_decoder)(void);
+};
+
+extern struct camu_codec_info codec_information[];
+
+struct camu_codec_info *camu_codec_info_by_type(s32 type);
+struct camu_codec_info *camu_codec_info_by_name(str *name);
diff --git a/src/codec/ffmpeg/decoder.c b/src/codec/ffmpeg/decoder.c
index cfa1dc2..7be21a2 100644
--- a/src/codec/ffmpeg/decoder.c
+++ b/src/codec/ffmpeg/decoder.c
@@ -151,11 +151,11 @@ static bool hw_device_supported_by_type(struct camu_ff_decoder *av, enum AVHWDev
}
*/
-static enum AVHWDeviceType hw_device_supported_by_name(struct camu_ff_decoder *av, const char *name)
+static enum AVHWDeviceType hw_device_supported_by_name(struct camu_ff_decoder *av, const char *name, size_t length)
{
enum AVHWDeviceType supported_type;
al_array_foreach(av->supported_hw_devices, i, supported_type) {
- if (strcmp(av_hwdevice_get_type_name(supported_type), name) == 0) {
+ if (al_strncmp(av_hwdevice_get_type_name(supported_type), name, length) == 0) {
return supported_type;
}
}
@@ -236,7 +236,8 @@ static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *rend
av->hw_device_type = AV_HWDEVICE_TYPE_NONE;
av->hw_pix_fmt = AV_PIX_FMT_NONE;
for (u32 i = 0; i < ARRAY_SIZE(hwdevces); i++) {
- av->hw_device_type = hw_device_supported_by_name(av, hwdevces[i]);
+ size_t length = sizeof(hwdevces[i]) - 1;
+ av->hw_device_type = hw_device_supported_by_name(av, hwdevces[i], length);
if (!get_hwdevice_config(av, codec, av->hw_device_type)) {
av->hw_device_type = AV_HWDEVICE_TYPE_NONE;
} else {
@@ -247,7 +248,8 @@ static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *rend
const AVCodec *hw_codec;
al_array_foreach(av->supported_hw_codecs, i, hw_codec) {
if (hw_codec->id == codecpar->codec_id) {
- av->hw_device_type = hw_device_supported_by_name(av, hw_codec->wrapper_name);
+ size_t length = al_strlen(hw_codec->wrapper_name);
+ av->hw_device_type = hw_device_supported_by_name(av, hw_codec->wrapper_name, length);
if (get_hwdevice_config(av, hw_codec, av->hw_device_type)) {
codec = hw_codec;
break;
diff --git a/src/codec/meson.build b/src/codec/meson.build
index 9401b0b..851a72a 100644
--- a/src/codec/meson.build
+++ b/src/codec/meson.build
@@ -1,4 +1,4 @@
-codec_src = ['packet_ext.c']
+codec_src = ['packet_ext.c', 'codecs.c']
codec_server_deps = []
codec_client_deps = []
diff --git a/src/codec/spng/meson.build b/src/codec/spng/meson.build
index d8af781..f99a885 100644
--- a/src/codec/spng/meson.build
+++ b/src/codec/spng/meson.build
@@ -1,3 +1,6 @@
spng = dependency('spng')
-codec_server_deps += [declare_dependency(sources: ['server.c'], dependencies: spng)]
-codec_client_deps += [declare_dependency(sources: ['client.c'], dependencies: spng)]
+spng_args = ['-DCAMU_HAVE_SPNG']
+codec_server_deps += declare_dependency(sources: ['server.c'],
+ dependencies: spng, compile_args: spng_args)
+codec_client_deps += declare_dependency(sources: ['client.c'],
+ dependencies: spng, compile_args: spng_args)
diff --git a/src/codec/spng/server.c b/src/codec/spng/server.c
index 8eb941b..1bb2ca8 100644
--- a/src/codec/spng/server.c
+++ b/src/codec/spng/server.c
@@ -13,7 +13,8 @@ static bool spng_demuxer_init(struct camu_demuxer *demux, struct cch_handle *han
spng->eof = false;
cch_handle_seek(spng->handle, 0, SEEK_SET);
- off_t size = cch_entry_get_size(spng->handle->entry);
+ struct cch_backing *backing = spng->handle->entry->backing;
+ off_t size = backing->get_size_if_known(backing);
nn_buffer_ensure_space(&spng->buffer, size);
cch_handle_read(spng->handle, nn_buffer_get_ptr(&spng->buffer, 0), size);
spng->buffer.size = size;
@@ -59,10 +60,11 @@ static u64 spng_demuxer_get_duration(struct camu_demuxer *demux)
return 0;
}
-static bool spng_demuxer_seek(struct camu_demuxer *demux, u64 pos)
+static bool spng_demuxer_seek(struct camu_demuxer *demux, u64 pos, bool bytes)
{
(void)demux;
(void)pos;
+ (void)bytes;
return true;
}
@@ -75,7 +77,6 @@ static void spng_demuxer_free(struct camu_demuxer **demux)
*demux = NULL;
}
-
struct camu_demuxer *camu_spng_demuxer_create(void)
{
struct camu_spng_demuxer *spng = al_alloc_object(struct camu_spng_demuxer);
diff --git a/src/codec/stb_image/meson.build b/src/codec/stb_image/meson.build
index fea86ff..e6faa21 100644
--- a/src/codec/stb_image/meson.build
+++ b/src/codec/stb_image/meson.build
@@ -1,3 +1,6 @@
stb = subproject('stb').get_variable('stb')
-codec_server_deps += declare_dependency(sources: ['server.c', 'impl.c'], dependencies: stb)
-codec_client_deps += declare_dependency(sources: ['client.c', 'impl.c'], dependencies: stb)
+stb_args = ['-DCAMU_HAVE_STB_IMAGE']
+codec_server_deps += declare_dependency(sources: ['server.c', 'impl.c'],
+ dependencies: stb, compile_args: stb_args)
+codec_client_deps += declare_dependency(sources: ['client.c', 'impl.c'],
+ dependencies: stb, compile_args: stb_args)
diff --git a/src/codec/wuffs/client.c b/src/codec/wuffs/client.c
new file mode 100644
index 0000000..c57e506
--- /dev/null
+++ b/src/codec/wuffs/client.c
@@ -0,0 +1,100 @@
+#include "decoder.h"
+#include "inc.h"
+
+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;
+}
diff --git a/src/codec/wuffs/impl.c b/src/codec/wuffs/impl.c
index 2c8f162..ab291cb 100644
--- a/src/codec/wuffs/impl.c
+++ b/src/codec/wuffs/impl.c
@@ -1,204 +1,2 @@
-#include <nnwt/common.h>
#define WUFFS_IMPLEMENTATION
-#define WUFFS_CONFIG__STATIC_FUNCTIONS
-#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
-#include <wuffs-unsupported-snapshot.c>
-
-#include "../../cache/entry.h"
-
-#include "demuxer.h"
-#include "decoder.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);
- off_t size = cch_entry_get_size(wfs->handle->entry);
- 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 = { 0 };
- wuffs_base__status status = wuffs_png__decoder__initialize(&wf_dec, sizeof(wf_dec), WUFFS_VERSION, 0);
- if (!wuffs_base__status__is_ok(&status)) 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 = wfs->buffer.size;
- src.meta.wi = wfs->buffer.size;
- src.meta.closed = true;
-
- wuffs_base__image_config ic = { 0 };
- 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;
- stream.mode = CAMU_NORMAL;
- stream.type = CAMU_STREAM_VIDEO;
- stream.video.width = wuffs_base__pixel_config__width(&ic.pixcfg);
- stream.video.height = wuffs_base__pixel_config__height(&ic.pixcfg);
- stream.video.format = CAMU_PIXEL_FORMAT_RGBA;
-
- al_array_push(wfs->demux.streams, stream);
-
- return true;
-err:
- 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)
-{
- (void)demux;
- (void)pos;
- 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;
-}
-
-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->data = NULL;
- frame->flags = 0;
- frame->width = wfs->stream->video.width;
- frame->height = wfs->stream->video.height;
- frame->format = CAMU_PIXEL_FMT_RGBA;
-
- wuffs_png__decoder wf_dec = { 0 };
- wuffs_base__status status = wuffs_png__decoder__initialize(&wf_dec, sizeof(wf_dec), WUFFS_VERSION, 0);
- if (!wuffs_base__status__is_ok(&status)) 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 };
- 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, frame->width, frame->height);
-
- wuffs_base__pixel_buffer pb = { 0 };
- size_t dst_size = frame->width * frame->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);
-
- return CAMU_OK;
-err:
- 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_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;
-}
-
-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;
-}
+#include "inc.h"
diff --git a/src/codec/wuffs/inc.h b/src/codec/wuffs/inc.h
new file mode 100644
index 0000000..51e3743
--- /dev/null
+++ b/src/codec/wuffs/inc.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#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
+#include <wuffs-unsupported-snapshot.c>
diff --git a/src/codec/wuffs/meson.build b/src/codec/wuffs/meson.build
index bb5007a..5e5c398 100644
--- a/src/codec/wuffs/meson.build
+++ b/src/codec/wuffs/meson.build
@@ -1,3 +1,6 @@
wuffs = subproject('wuffs').get_variable('wuffs')
-#codec_server_deps += declare_dependency(sources: ['server.c'], dependencies: wuffs)
-#codec_client_deps += declare_dependency(sources: ['client.c'], dependencies: wuffs)
+wuffs_args = ['-DCAMU_HAVE_WUFFS']
+codec_server_deps += declare_dependency(sources: ['server.c', 'impl.c'],
+ dependencies: wuffs, compile_args: wuffs_args)
+codec_client_deps += declare_dependency(sources: ['client.c', 'impl.c'],
+ dependencies: wuffs, compile_args: wuffs_args)
diff --git a/src/codec/wuffs/server.c b/src/codec/wuffs/server.c
new file mode 100644
index 0000000..5e7e885
--- /dev/null
+++ b/src/codec/wuffs/server.c
@@ -0,0 +1,102 @@
+#include "../../cache/entry.h"
+
+#include "demuxer.h"
+#include "inc.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;
+}