diff options
| author | 2023-11-06 11:54:08 -0500 | |
|---|---|---|
| committer | 2023-11-06 11:54:08 -0500 | |
| commit | a48a68cfb04b2020737c0adfb0e7667451a22b5c (patch) | |
| tree | a92121897f84298c3798a4f2ba56de45cd100eab /src/bimu/handlers | |
| download | camu-a48a68cfb04b2020737c0adfb0e7667451a22b5c.tar.gz camu-a48a68cfb04b2020737c0adfb0e7667451a22b5c.tar.bz2 camu-a48a68cfb04b2020737c0adfb0e7667451a22b5c.zip | |
Add camu
- Subprojects temporarily omitted
Signed-off-by: Andrew Opalach <andrew@akon.city>
Diffstat (limited to 'src/bimu/handlers')
| -rw-r--r-- | src/bimu/handlers/codec.h | 20 | ||||
| -rw-r--r-- | src/bimu/handlers/codec_client.c | 109 | ||||
| -rw-r--r-- | src/bimu/handlers/codec_server.c | 159 |
3 files changed, 288 insertions, 0 deletions
diff --git a/src/bimu/handlers/codec.h b/src/bimu/handlers/codec.h new file mode 100644 index 0000000..a8031b1 --- /dev/null +++ b/src/bimu/handlers/codec.h @@ -0,0 +1,20 @@ +#pragma once + +#include "../handler.h" + +#include "../../codec/codec.h" + +struct bmu_codec_server { + struct bmu_server_handler handler; + struct camu_demuxer *demux; + struct camu_packet packet; + struct aki_packet_pool *pool; +}; + +struct bmu_codec_client { + struct bmu_client_handler handler; + struct camu_decoder *dec; +}; + +struct bmu_server_handler *bmu_codec_server_create(void); +struct bmu_client_handler *bmu_codec_client_create(void); diff --git a/src/bimu/handlers/codec_client.c b/src/bimu/handlers/codec_client.c new file mode 100644 index 0000000..ffe8c16 --- /dev/null +++ b/src/bimu/handlers/codec_client.c @@ -0,0 +1,109 @@ +#include "../../codec/libav/decoder.h" +#include "../../codec/libav/packet_ext.h" +#include "../../codec/stb_image/decoder.h" +#include "../../codec/wuffs/decoder.h" +#include "../../codec/spng/decoder.h" + +#include "../../bimu/local.h" + +#include "codec.h" + +static void data_callback(void *userdata, struct camu_frame *frame) +{ + struct bmu_codec_client *codec = (struct bmu_codec_client *)userdata; + codec->handler.callback(codec->handler.userdata, BIMU_CLIENT_DATA, codec->handler.stream, frame); +} + +static bool codec_client_init(struct bmu_client_handler *handler, struct camu_renderer *renderer, + struct bmu_client_stream *stream) +{ + struct bmu_codec_client *codec = (struct bmu_codec_client *)handler; + codec->dec = camu_lav_decoder_create(); + //codec->dec = camu_spng_decoder_create(); + //codec->dec = camu_stbi_decoder_create(); + //codec->dec = camu_wuffs_decoder_create(); + codec->handler.stream = stream; + if (!codec->dec->init(codec->dec, renderer, &stream->stream)) { + return false; + } + codec->dec->stream = &stream->stream; + codec->handler.callback(codec->handler.userdata, BIMU_CLIENT_CONFIGURE, codec->handler.stream, NULL); + codec->dec->set_callback(codec->dec, data_callback, codec); + return true; +} + +#ifdef HAVE_FFMPEG +static void push_av_packet(struct bmu_codec_client *codec, AVPacket *pkt) +{ + struct camu_packet packet; + packet.av.pkt = pkt; + s32 ret = codec->dec->push(codec->dec, &packet); + av_packet_unref(pkt); + av_packet_free(&pkt); + al_assert(ret == CAMU_OK); +} +#endif + +static void push_packet(struct bmu_codec_client *codec, struct aki_buffer *buffer) +{ + struct camu_packet packet; + packet.buffer = buffer; + s32 ret = codec->dec->push(codec->dec, &packet); + al_assert(ret == CAMU_OK); +} + +static void codec_client_handle_data_packet(struct bmu_client_handler *handler, struct aki_packet *packet) +{ + struct bmu_codec_client *codec = (struct bmu_codec_client *)handler; + switch (aki_packet_read_u8(packet)) { + case CAMU_NORMAL: { + struct aki_buffer buffer; + aki_packet_read_buffer(packet, &buffer); + push_packet(codec, &buffer); + break; + } +#ifdef HAVE_FFMPEG + case CAMU_FFMPEG_COMPAT: { + push_av_packet(codec, aki_packet_read_av_packet(packet)); + break; + } +#endif + } + s32 ret = codec->dec->process(codec->dec); + al_assert(ret == CAMU_ERR_AGAIN || ret == CAMU_ERR_EOF); +} + +static void codec_client_handle_eof(struct bmu_client_handler *handler) +{ + struct bmu_codec_client *codec = (struct bmu_codec_client *)handler; + s32 ret = codec->dec->push(codec->dec, NULL); + // Flush returns success. + ret = codec->dec->process(codec->dec); + al_assert(ret == CAMU_ERR_EOF); + codec->handler.callback(codec->handler.userdata, BIMU_CLIENT_EOF, codec->handler.stream, NULL); +} + +static void codec_client_flush(struct bmu_client_handler *handler) +{ + struct bmu_codec_client *codec = (struct bmu_codec_client *)handler; + codec->dec->flush(codec->dec); +} + +static void codec_client_free(struct bmu_client_handler **handler) +{ + struct bmu_codec_client *codec = (struct bmu_codec_client *)*handler; + codec->dec->free(&codec->dec); + al_free(codec); + *handler = NULL; +} + +struct bmu_client_handler *bmu_codec_client_create(void) +{ + struct bmu_codec_client *codec = al_alloc_object(struct bmu_codec_client); + codec->handler.init = codec_client_init; + codec->handler.handle_data_packet = codec_client_handle_data_packet; + codec->handler.handle_eof = codec_client_handle_eof; + codec->handler.flush = codec_client_flush; + codec->handler.free = codec_client_free; + return (struct bmu_client_handler *)codec; +} diff --git a/src/bimu/handlers/codec_server.c b/src/bimu/handlers/codec_server.c new file mode 100644 index 0000000..b555370 --- /dev/null +++ b/src/bimu/handlers/codec_server.c @@ -0,0 +1,159 @@ +#include "../../codec/codec.h" +#include "../../codec/libav/demuxer.h" +#include "../../codec/libav/packet_ext.h" +#include "../../codec/stb_image/demuxer.h" +#include "../../codec/wuffs/demuxer.h" +#include "../../codec/spng/demuxer.h" + +#include "../handler.h" + +#include "codec.h" + +static bool codec_server_init(struct bmu_server_handler *handler, struct cch_handle *handle, struct aki_packet_pool *pool) +{ + struct bmu_codec_server *codec = (struct bmu_codec_server *)handler; + codec->demux = camu_lav_demuxer_create(); + //codec->demux = camu_spng_demuxer_create(); + //codec->demux = camu_stbi_demuxer_create(); + //codec->demux = camu_wuffs_demuxer_create(); + if (!codec->demux->init(codec->demux, handle)) { + return false; + } + switch (codec->demux->type) { + case CAMU_NORMAL: + break; +#ifdef HAVE_FFMPEG + case CAMU_FFMPEG_COMPAT: + codec->packet.av.pkt = av_packet_alloc(); + break; +#endif + } + codec->pool = pool; + return true; +} + +static void codec_server_write_info(struct bmu_server_handler *handler, struct aki_packet *packet) +{ + struct bmu_codec_server *codec = (struct bmu_codec_server *)handler; + aki_packet_write_u32(packet, codec->demux->streams.size); + struct camu_stream *stream; + al_array_foreach_ptr(codec->demux->streams, i, stream) { + aki_packet_write_u8(packet, stream->type); + switch (stream->type) { + case CAMU_NORMAL: + aki_packet_write_s32(packet, stream->video.width); + aki_packet_write_s32(packet, stream->video.height); + break; +#ifdef HAVE_FFMPEG + case CAMU_FFMPEG_COMPAT: + aki_packet_write_av_codec_id(packet, stream->av.stream->codecpar->codec_id); + aki_packet_write_av_stream(packet, stream->av.stream); + break; +#endif + } + } +} + +static s64 codec_server_get_duration(struct bmu_server_handler *handler) +{ + struct bmu_codec_server *codec = (struct bmu_codec_server *)handler; + return codec->demux->get_duration(codec->demux); +} + +static bool codec_server_seek(struct bmu_server_handler *handler, s64 pos) +{ + struct bmu_codec_server *codec = (struct bmu_codec_server *)handler; + return codec->demux->seek(codec->demux, pos); +} + +static bool codec_server_step(struct bmu_server_handler *handler) +{ + struct bmu_codec_server *codec = (struct bmu_codec_server *)handler; + struct aki_packet *packet = aki_packet_pool_get(codec->pool); + if (!packet) return false; + aki_packet_write_u8(packet, 0); + s32 ret = codec->demux->get_packet(codec->demux, &codec->packet); + do { + if (ret == CAMU_OK) { + switch (codec->packet.type) { + case CAMU_NORMAL: { + aki_packet_write_s32(packet, 0); + aki_packet_write_u8(packet, 0); + aki_packet_write_u8(packet, codec->packet.type); + aki_packet_write_buffer(packet, codec->packet.buffer); + break; + } +#ifdef HAVE_FFMPEG + case CAMU_FFMPEG_COMPAT: { + AVPacket *pkt = codec->packet.av.pkt; + aki_packet_write_s32(packet, pkt->stream_index); + aki_packet_write_u8(packet, 0); + aki_packet_write_u8(packet, codec->packet.type); + aki_packet_write_av_packet(packet, pkt); + av_packet_unref(pkt); + break; + } +#endif + } + aki_packet_pool_submit(codec->pool, packet); + } else if (ret == CAMU_ERR_EOF) { + struct camu_stream *stream; + al_array_foreach_ptr(codec->demux->streams, i, stream) { + if (i != 0) { // HACK + packet = aki_packet_pool_get(codec->pool); + if (!packet) return false; + aki_packet_write_u8(packet, 0); + } + switch (stream->type) { + case CAMU_NORMAL: + aki_packet_write_s32(packet, 0); + break; +#ifdef HAVE_FFMPEG + case CAMU_FFMPEG_COMPAT: + aki_packet_write_s32(packet, stream->av.stream->index); + break; +#endif + } + aki_packet_write_u8(packet, 1); + aki_packet_pool_submit(codec->pool, packet); + } + return false; + } else { + aki_packet_write_s32(packet, -2); + aki_packet_write_u8(packet, 2); + aki_packet_pool_submit(codec->pool, packet); + return false; + } + break; + } while (1); + return true; +} + +static void codec_server_free(struct bmu_server_handler **handler) +{ + struct bmu_codec_server *codec = (struct bmu_codec_server *)*handler; + switch (codec->demux->type) { + case CAMU_NORMAL: + break; +#ifdef HAVE_FFMPEG + case CAMU_FFMPEG_COMPAT: + av_packet_free(&codec->packet.av.pkt); + break; +#endif + } + codec->demux->free(&codec->demux); + al_free(codec); + *handler = NULL; +} + +struct bmu_server_handler *bmu_codec_server_create(void) +{ + struct bmu_codec_server *codec = al_alloc_object(struct bmu_codec_server); + codec->handler.init = codec_server_init; + codec->handler.write_info = codec_server_write_info; + codec->handler.get_duration = codec_server_get_duration; + codec->handler.seek = codec_server_seek; + codec->handler.step = codec_server_step; + codec->handler.free = codec_server_free; + return (struct bmu_server_handler *)codec; +} |