diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 668268c..19bae14 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -18,6 +18,7 @@ set(HEADER_FILES
include/chiaki/gkcrypt.h
include/chiaki/audio.h
include/chiaki/audioreceiver.h
+ include/chiaki/video.h
include/chiaki/videoreceiver.h)
set(SOURCE_FILES
diff --git a/lib/include/chiaki/video.h b/lib/include/chiaki/video.h
new file mode 100644
index 0000000..76a4f61
--- /dev/null
+++ b/lib/include/chiaki/video.h
@@ -0,0 +1,40 @@
+/*
+ * This file is part of Chiaki.
+ *
+ * Chiaki is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chiaki is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chiaki. If not, see .
+ */
+
+#ifndef CHIAKI_VIDEO_H
+#define CHIAKI_VIDEO_H
+
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct chiaki_video_profile_t
+{
+ unsigned int width;
+ unsigned int height;
+ size_t header_sz;
+ uint8_t *header;
+} ChiakiVideoProfile;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CHIAKI_VIDEO_H
diff --git a/lib/include/chiaki/videoreceiver.h b/lib/include/chiaki/videoreceiver.h
index 3b2c23a..1d94ffa 100644
--- a/lib/include/chiaki/videoreceiver.h
+++ b/lib/include/chiaki/videoreceiver.h
@@ -20,21 +20,34 @@
#include "common.h"
#include "log.h"
+#include "video.h"
#ifdef __cplusplus
extern "C" {
#endif
+#define CHIAKI_VIDEO_PROFILES_MAX 8
+
typedef struct chiaki_video_receiver_t
{
struct chiaki_session_t *session;
ChiakiLog *log;
-
+ ChiakiVideoProfile profiles[CHIAKI_VIDEO_PROFILES_MAX];
+ size_t profiles_count;
} ChiakiVideoReceiver;
CHIAKI_EXPORT void chiaki_video_receiver_init(ChiakiVideoReceiver *video_receiver, struct chiaki_session_t *session);
CHIAKI_EXPORT void chiaki_video_receiver_fini(ChiakiVideoReceiver *video_receiver);
+/**
+ * Called after receiving the Stream Info Packet.
+ *
+ * @param video_receiver
+ * @param profiles Array of profiles. Ownership of the contained header buffers will be transferred to the ChiakiVideoReceiver!
+ * @param profiles_count must be <= CHIAKI_VIDEO_PROFILES_MAX
+ */
+CHIAKI_EXPORT void chiaki_video_receiver_stream_info(ChiakiVideoReceiver *video_receiver, ChiakiVideoProfile *profiles, size_t profiles_count);
+
static inline ChiakiVideoReceiver *chiaki_video_receiver_new(struct chiaki_session_t *session)
{
ChiakiVideoReceiver *video_receiver = CHIAKI_NEW(ChiakiVideoReceiver);
diff --git a/lib/src/nagare.c b/lib/src/nagare.c
index 479213d..64b6eb9 100644
--- a/lib/src/nagare.c
+++ b/lib/src/nagare.c
@@ -21,6 +21,7 @@
#include
#include
#include
+#include
#include
#include
@@ -305,6 +306,44 @@ error:
chiaki_mirai_signal(&nagare->mirai, NAGARE_MIRAI_RESPONSE_FAIL);
}
+typedef struct decode_resolutions_context_t
+{
+ ChiakiNagare *nagare;
+ ChiakiVideoProfile video_profiles[CHIAKI_VIDEO_PROFILES_MAX];
+ size_t video_profiles_count;
+} DecodeResolutionsContext;
+
+static bool pb_decode_resolution(pb_istream_t *stream, const pb_field_t *field, void **arg)
+{
+ DecodeResolutionsContext *ctx = *arg;
+
+ tkproto_ResolutionPayload resolution = { 0 };
+ ChiakiPBDecodeBufAlloc header_buf = { 0 };
+ resolution.video_header.arg = &header_buf;
+ resolution.video_header.funcs.decode = chiaki_pb_decode_buf_alloc;
+ if(!pb_decode(stream, tkproto_ResolutionPayload_fields, &resolution))
+ return false;
+
+ if(!header_buf.buf)
+ {
+ CHIAKI_LOGE(&ctx->nagare->session->log, "Failed to decode video header\n");
+ return true;
+ }
+
+ if(ctx->video_profiles_count >= CHIAKI_VIDEO_PROFILES_MAX)
+ {
+ CHIAKI_LOGE(&ctx->nagare->session->log, "Received more resolutions than the maximum\n");
+ return true;
+ }
+
+ ChiakiVideoProfile *profile = &ctx->video_profiles[ctx->video_profiles_count++];
+ profile->width = resolution.width;
+ profile->height = resolution.height;
+ profile->header_sz = header_buf.size;
+ profile->header = header_buf.buf;
+ return true;
+}
+
static void nagare_takion_data_expect_streaminfo(ChiakiNagare *nagare, uint8_t *buf, size_t buf_size)
{
@@ -316,7 +355,12 @@ static void nagare_takion_data_expect_streaminfo(ChiakiNagare *nagare, uint8_t *
msg.stream_info_payload.audio_header.arg = &audio_header_buf;
msg.stream_info_payload.audio_header.funcs.decode = chiaki_pb_decode_buf;
- // TODO: msg.stream_info_payload.resolution
+ DecodeResolutionsContext decode_resolutions_context;
+ decode_resolutions_context.nagare = nagare;
+ memset(decode_resolutions_context.video_profiles, 0, sizeof(decode_resolutions_context.video_profiles));
+ decode_resolutions_context.video_profiles_count = 0;
+ msg.stream_info_payload.resolution.arg = &decode_resolutions_context;
+ msg.stream_info_payload.resolution.funcs.decode = pb_decode_resolution;
pb_istream_t stream = pb_istream_from_buffer(buf, buf_size);
bool r = pb_decode(&stream, tkproto_TakionMessage_fields, &msg);
@@ -342,6 +386,10 @@ static void nagare_takion_data_expect_streaminfo(ChiakiNagare *nagare, uint8_t *
chiaki_audio_header_load(&audio_header_s, audio_header);
chiaki_audio_receiver_stream_info(nagare->session->audio_receiver, &audio_header_s);
+ chiaki_video_receiver_stream_info(nagare->session->video_receiver,
+ decode_resolutions_context.video_profiles,
+ decode_resolutions_context.video_profiles_count);
+
// TODO: do some checks?
nagare_send_streaminfo_ack(nagare);
diff --git a/lib/src/pb_utils.h b/lib/src/pb_utils.h
index db9bf8c..4183945 100644
--- a/lib/src/pb_utils.h
+++ b/lib/src/pb_utils.h
@@ -72,4 +72,23 @@ static bool chiaki_pb_decode_buf(pb_istream_t *stream, const pb_field_t *field,
}
+typedef struct chiaki_pb_decode_buf_alloc_t
+{
+ size_t size;
+ uint8_t *buf;
+} ChiakiPBDecodeBufAlloc;
+
+static bool chiaki_pb_decode_buf_alloc(pb_istream_t *stream, const pb_field_t *field, void **arg)
+{
+ ChiakiPBDecodeBufAlloc *buf = *arg;
+ buf->size = stream->bytes_left;
+ buf->buf = malloc(buf->size);
+ if(!buf->buf)
+ return false;
+ bool r = pb_read(stream, buf->buf, buf->size);
+ if(!r)
+ buf->size = 0;
+ return r;
+}
+
#endif // CHIAKI_PB_UTILS_H
diff --git a/lib/src/videoreceiver.c b/lib/src/videoreceiver.c
index eb2f4af..0e675b8 100644
--- a/lib/src/videoreceiver.c
+++ b/lib/src/videoreceiver.c
@@ -18,13 +18,38 @@
#include
#include
+#include
CHIAKI_EXPORT void chiaki_video_receiver_init(ChiakiVideoReceiver *video_receiver, struct chiaki_session_t *session)
{
video_receiver->session = session;
video_receiver->log = &session->log;
+ memset(video_receiver->profiles, 0, sizeof(video_receiver->profiles));
+ video_receiver->profiles_count = 0;
}
CHIAKI_EXPORT void chiaki_video_receiver_fini(ChiakiVideoReceiver *video_receiver)
{
+ for(size_t i=0; iprofiles_count; i++)
+ free(video_receiver->profiles[i].header);
+}
+
+CHIAKI_EXPORT void chiaki_video_receiver_stream_info(ChiakiVideoReceiver *video_receiver, ChiakiVideoProfile *profiles, size_t profiles_count)
+{
+ if(video_receiver->profiles_count > 0)
+ {
+ CHIAKI_LOGE(video_receiver->log, "Video Receiver profiles already set\n");
+ return;
+ }
+
+ memcpy(video_receiver->profiles, profiles, profiles_count * sizeof(ChiakiVideoProfile));
+ video_receiver->profiles_count = profiles_count;
+
+ CHIAKI_LOGI(video_receiver->log, "Video Profiles:\n");
+ for(size_t i=0; iprofiles_count; i++)
+ {
+ ChiakiVideoProfile *profile = &video_receiver->profiles[i];
+ CHIAKI_LOGI(video_receiver->log, " %zu: %ux%u\n", i, profile->width, profile->height);
+ chiaki_log_hexdump(video_receiver->log, CHIAKI_LOG_DEBUG, profile->header, profile->header_sz);
+ }
}
\ No newline at end of file