#define AL_LOG_SECTION "codec_server" #include #include "../../server/common.h" #include "../../codec/codec.h" #include "../../codec/codecs.h" #ifdef CAMU_HAVE_FFMPEG #include "../../codec/ffmpeg/packet_ext.h" #endif #include "codec.h" static bool codec_server_init(struct lia_server_handler *handler, struct cch_handle *handle) { struct lia_codec_server *codec = (struct lia_codec_server *)handler; codec->demux = NULL; codec->codec_info = camu_codec_info_by_type(cch_entry_guess_format(handle->entry)); if (!codec->codec_info) { return false; } log_info("Selected demuxer: %.*s.", al_str_x(&codec->codec_info->name)); codec->demux = codec->codec_info->create_demuxer(); if (!codec->demux->init(codec->demux, handle)) { return false; } #ifdef LIANA_SERVER_LOOP codec->pts_offset = 0; #endif switch (codec->demux->mode) { case CAMU_NORMAL: break; #ifdef CAMU_HAVE_FFMPEG case CAMU_FFMPEG_COMPAT: #ifndef CAMU_DIRECT_MODE codec->packet.av.pkt = av_packet_alloc(); #endif break; #endif } return true; } static void codec_server_write_info(struct lia_server_handler *handler, struct nn_packet *packet) { struct lia_codec_server *codec = (struct lia_codec_server *)handler; u64 duration = codec->demux->get_duration(codec->demux); nn_packet_write_u64(packet, duration); nn_packet_write_u32(packet, codec->demux->streams.count); struct camu_codec_stream *stream; al_array_foreach_ptr(codec->demux->streams, i, stream) { nn_packet_write_str(packet, &codec->codec_info->name); nn_packet_write_u8(packet, stream->mode); nn_packet_write_u8(packet, stream->type); nn_packet_write_u64(packet, stream->duration); // stream->index = i is currently expected but shouldn't be (and isn't) relied upon anywhere. al_assert(stream->index == (s32)i); nn_packet_write_s32(packet, stream->index); switch (stream->mode) { case CAMU_NORMAL: { struct camu_video_format *fmt = &stream->video.fmt; nn_packet_write_u32(packet, fmt->width); nn_packet_write_u32(packet, fmt->height); nn_packet_write_s32(packet, fmt->format); break; } #ifdef CAMU_HAVE_FFMPEG case CAMU_FFMPEG_COMPAT: nn_packet_write_av_codec_id(packet, stream->av.stream->codecpar->codec_id); nn_packet_write_av_stream(packet, stream->av.stream); break; #endif } } } static void codec_server_subscribe(struct lia_server_handler *handler, u32 mask) { struct lia_codec_server *codec = (struct lia_codec_server *)handler; codec->demux->subscribed = mask; } static u64 codec_server_get_duration(struct lia_server_handler *handler) { struct lia_codec_server *codec = (struct lia_codec_server *)handler; return codec->demux->get_duration(codec->demux); } static bool codec_server_seek(struct lia_server_handler *handler, u64 pos) { struct lia_codec_server *codec = (struct lia_codec_server *)handler; #ifdef LIANA_SERVER_LOOP codec->pts_offset = 0; #endif return codec->demux->seek(codec->demux, pos, false); } static void codec_server_step(struct lia_server_handler *handler) { struct lia_codec_server *codec = (struct lia_codec_server *)handler; #ifdef CAMU_HAVE_FFMPEG #ifdef CAMU_DIRECT_MODE codec->packet.av.pkt = av_packet_alloc(); #endif #endif codec->handler.status = codec->demux->get_packet(codec->demux, &codec->packet); } static void codec_server_write_packet(struct lia_server_handler *handler, struct nn_packet *packet) { struct lia_codec_server *codec = (struct lia_codec_server *)handler; if (codec->handler.status == CAMU_OK) { nn_packet_write_u8(packet, LIANA_PACKET_DATA); switch (codec->packet.mode) { case CAMU_NORMAL: { nn_packet_write_s32(packet, 0); nn_packet_write_u8(packet, codec->packet.mode); #ifdef CAMU_DIRECT_MODE packet->opaque = codec->packet.buffer; #else nn_packet_write_buffer(packet, codec->packet.buffer); #endif break; } #ifdef CAMU_HAVE_FFMPEG case CAMU_FFMPEG_COMPAT: { AVPacket *pkt = codec->packet.av.pkt; #ifdef LIANA_SERVER_LOOP struct camu_codec_stream *stream = &al_array_at(codec->demux->streams, pkt->stream_index); AVRational time_base = stream->av.stream->time_base; pkt->pts += av_rescale_q(codec->pts_offset, AV_TIME_BASE_Q, time_base); #endif nn_packet_write_s32(packet, pkt->stream_index); nn_packet_write_u8(packet, codec->packet.mode); #ifdef CAMU_DIRECT_MODE packet->opaque = pkt; #else nn_packet_write_av_packet(packet, pkt); av_packet_unref(pkt); #endif break; } #endif } } else if (codec->handler.status == CAMU_ERR_EOF) { nn_packet_write_u8(packet, LIANA_PACKET_EOF); #ifdef LIANA_SERVER_LOOP codec->pts_offset += codec->demux->get_duration(codec->demux); codec->demux->seek(codec->demux, 0, false); #endif } else { nn_packet_write_u8(packet, LIANA_PACKET_ERROR); } } static void codec_server_free(struct lia_server_handler **handler) { struct lia_codec_server *codec = (struct lia_codec_server *)*handler; if (codec->demux) { switch (codec->demux->mode) { case CAMU_NORMAL: break; #ifdef CAMU_HAVE_FFMPEG case CAMU_FFMPEG_COMPAT: #ifndef CAMU_DIRECT_MODE av_packet_free(&codec->packet.av.pkt); #endif break; #endif } codec->demux->free(&codec->demux); } al_free(codec); *handler = NULL; } struct lia_server_handler *lia_codec_server_create(void) { struct lia_codec_server *codec = al_alloc_object(struct lia_codec_server); codec->handler.init = codec_server_init; codec->handler.write_info = codec_server_write_info; codec->handler.subscribe = codec_server_subscribe; codec->handler.get_duration = codec_server_get_duration; codec->handler.seek = codec_server_seek; codec->handler.step = codec_server_step; codec->handler.write_packet = codec_server_write_packet; codec->handler.free = codec_server_free; return (struct lia_server_handler *)codec; }