From 49e7143de9775fc913c5689796aea8cda5e6b6dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sat, 29 Jun 2019 17:29:18 +0200 Subject: [PATCH] Move Chiaki Session to StreamSession --- gui/include/streamsession.h | 28 ++++++++- gui/include/streamwindow.h | 12 +++- gui/src/main.cpp | 117 +----------------------------------- gui/src/streamsession.cpp | 97 +++++++++++++++++++++++++++++- gui/src/streamwindow.cpp | 26 +++++++- 5 files changed, 157 insertions(+), 123 deletions(-) diff --git a/gui/include/streamsession.h b/gui/include/streamsession.h index 844fb7f..63e7286 100644 --- a/gui/include/streamsession.h +++ b/gui/include/streamsession.h @@ -18,21 +18,45 @@ #ifndef CHIAKI_STREAMSESSION_H #define CHIAKI_STREAMSESSION_H +#include "videodecoder.h" + #include -#include +#include + +#include + +class QGamepad; +class QAudioOutput; +class QIODevice; class StreamSession : public QObject { + friend class StreamSessionPrivate; + Q_OBJECT private: + ChiakiSession session; + QGamepad *gamepad; + VideoDecoder video_decoder; + + QAudioOutput *audio_output; + QIODevice *audio_io; + + void PushAudioFrame(int16_t *buf, size_t samples_count); + void PushVideoSample(uint8_t *buf, size_t buf_size); + public: - explicit StreamSession(QObject *parent = nullptr); + explicit StreamSession(const QString &host, const QString ®istkey, const QString &ostype, const QString &auth, const QString &morning, const QString &did, QObject *parent = nullptr); ~StreamSession(); QGamepad *GetGamepad() { return gamepad; } + VideoDecoder *GetVideoDecoder() { return &video_decoder; } + + signals: + void CurrentImageUpdated(); private slots: void UpdateGamepads(); diff --git a/gui/include/streamwindow.h b/gui/include/streamwindow.h index f7122f8..f842a25 100644 --- a/gui/include/streamwindow.h +++ b/gui/include/streamwindow.h @@ -21,19 +21,25 @@ #include class QLabel; +class StreamSession; class StreamWindow: public QMainWindow { Q_OBJECT public: - explicit StreamWindow(QWidget *parent = nullptr); + explicit StreamWindow(StreamSession *session, QWidget *parent = nullptr); ~StreamWindow(); + private: + StreamSession *session; + + QLabel *imageLabel; + void SetImage(const QImage &image); - private: - QLabel *imageLabel; + private slots: + void FramesAvailable(); }; #endif // CHIAKI_GUI_STREAMWINDOW_H diff --git a/gui/src/main.cpp b/gui/src/main.cpp index c352f6e..86a64c6 100644 --- a/gui/src/main.cpp +++ b/gui/src/main.cpp @@ -86,127 +86,16 @@ int RunMain(QApplication &app) return app.exec(); } -QAudioOutput *audio_out; -QIODevice *audio_io; -VideoDecoder video_decoder; - - -void audio_frame_cb(int16_t *buf, size_t samples_count, void *user) -{ - audio_io->write((const char *)buf, static_cast(samples_count * 2 * 2)); -} - -void video_sample_cb(uint8_t *buf, size_t buf_size, void *user) -{ - video_decoder.PutFrame(buf, buf_size); - /*if(!video_out_file) - return; - printf("writing %#zx to file, start: %#zx\n", buf_size, file_size); - chiaki_log_hexdump(nullptr, CHIAKI_LOG_DEBUG, buf, buf_size); - file_size += buf_size; - video_out_file->write((const char *)buf, buf_size);*/ - //StreamRelayIODevice *io_device = reinterpret_cast(user); - //io_device->PushSample(buf, buf_size); -} int RunStream(QApplication &app, const QString &host, const QString ®istkey, const QString &ostype, const QString &auth, const QString &morning, const QString &did) { - StreamSession stream_session; + StreamSession stream_session(host, registkey, ostype, auth, morning, did); - QByteArray host_str = host.toUtf8(); - QByteArray registkey_str = registkey.toUtf8(); - QByteArray ostype_str = ostype.toUtf8(); - - ChiakiConnectInfo connect_info; - connect_info.host = host_str.constData(); - connect_info.regist_key = registkey_str.constData(); - connect_info.ostype = ostype_str.constData(); - - QByteArray auth_str = auth.toUtf8(); - size_t auth_len = auth_str.length(); - if(auth_len > sizeof(connect_info.auth)) - auth_len = sizeof(connect_info.auth); - memcpy(connect_info.auth, auth_str.constData(), auth_len); - if(auth_len < sizeof(connect_info.auth)) - memset(connect_info.auth + auth_len, 0, sizeof(connect_info.auth) - auth_len); - - size_t morning_size = sizeof(connect_info.morning); - QByteArray morning_str = morning.toUtf8(); - ChiakiErrorCode err = chiaki_base64_decode(morning_str.constData(), morning_str.length(), connect_info.morning, &morning_size); - if(err != CHIAKI_ERR_SUCCESS || morning_size != sizeof(connect_info.morning)) - { - printf("morning invalid.\n"); - return 1; - } - - size_t did_size = sizeof(connect_info.did); - QByteArray did_str = did.toUtf8(); - err = chiaki_base64_decode(did_str.constData(), did_str.length(), connect_info.did, &did_size); - if(err != CHIAKI_ERR_SUCCESS || did_size != sizeof(connect_info.did)) - { - printf("did invalid.\n"); - return 1; - } - - StreamWindow window; + StreamWindow window(&stream_session); window.resize(640, 360); window.show(); - - QAudioFormat audio_format; - audio_format.setSampleRate(48000); - audio_format.setChannelCount(2); - audio_format.setSampleSize(16); - audio_format.setCodec("audio/pcm"); - audio_format.setSampleType(QAudioFormat::SignedInt); - - QAudioDeviceInfo audio_device_info(QAudioDeviceInfo::defaultOutputDevice()); - if(!audio_device_info.isFormatSupported(audio_format)) - { - printf("audio output format not supported\n"); - } - - audio_out = new QAudioOutput(audio_format); - audio_io = audio_out->start(); - - - //video_out_file = nullptr; - //video_out_file->open(QFile::ReadWrite); - - QObject::connect(&video_decoder, &VideoDecoder::FramesAvailable, &window, [&window]() { - QImage prev; - QImage image; - do - { - prev = image; - image = video_decoder.PullFrame(); - } while(!image.isNull()); - - if(!prev.isNull()) - { - window.SetImage(prev); - } - }); - - ChiakiSession session; - chiaki_session_init(&session, &connect_info); - chiaki_session_set_audio_frame_cb(&session, audio_frame_cb, nullptr); - chiaki_session_set_video_sample_cb(&session, video_sample_cb, nullptr); - chiaki_session_start(&session); - app.setQuitOnLastWindowClosed(true); - - int ret = app.exec(); - - //video_out_file->close(); - - //printf("CLOSED!!! filesize: %zu\n", file_size); - - chiaki_session_join(&session); - chiaki_session_fini(&session); - - delete audio_out; - - return 0; + return app.exec(); } diff --git a/gui/src/streamsession.cpp b/gui/src/streamsession.cpp index 010fb7c..0778b7d 100644 --- a/gui/src/streamsession.cpp +++ b/gui/src/streamsession.cpp @@ -17,19 +17,85 @@ #include +#include + #include +#include +#include #include -StreamSession::StreamSession(QObject *parent) + +static void AudioFrameCb(int16_t *buf, size_t samples_count, void *user); +static void VideoSampleCb(uint8_t *buf, size_t buf_size, void *user); + +StreamSession::StreamSession(const QString &host, const QString ®istkey, const QString &ostype, const QString &auth, const QString &morning, const QString &did, QObject *parent) : QObject(parent), gamepad(nullptr) { + QByteArray host_str = host.toUtf8(); + QByteArray registkey_str = registkey.toUtf8(); + QByteArray ostype_str = ostype.toUtf8(); + + ChiakiConnectInfo connect_info; + connect_info.host = host_str.constData(); + connect_info.regist_key = registkey_str.constData(); + connect_info.ostype = ostype_str.constData(); + + QByteArray auth_str = auth.toUtf8(); + size_t auth_len = auth_str.length(); + if(auth_len > sizeof(connect_info.auth)) + auth_len = sizeof(connect_info.auth); + memcpy(connect_info.auth, auth_str.constData(), auth_len); + if(auth_len < sizeof(connect_info.auth)) + memset(connect_info.auth + auth_len, 0, sizeof(connect_info.auth) - auth_len); + + size_t morning_size = sizeof(connect_info.morning); + QByteArray morning_str = morning.toUtf8(); + ChiakiErrorCode err = chiaki_base64_decode(morning_str.constData(), morning_str.length(), connect_info.morning, &morning_size); + if(err != CHIAKI_ERR_SUCCESS || morning_size != sizeof(connect_info.morning)) + { + printf("morning invalid.\n"); + throw std::exception(); // TODO: proper exception + } + + size_t did_size = sizeof(connect_info.did); + QByteArray did_str = did.toUtf8(); + err = chiaki_base64_decode(did_str.constData(), did_str.length(), connect_info.did, &did_size); + if(err != CHIAKI_ERR_SUCCESS || did_size != sizeof(connect_info.did)) + { + printf("did invalid.\n"); + throw std::exception(); // TODO: proper exception + } + + QAudioFormat audio_format; + audio_format.setSampleRate(48000); + audio_format.setChannelCount(2); + audio_format.setSampleSize(16); + audio_format.setCodec("audio/pcm"); + audio_format.setSampleType(QAudioFormat::SignedInt); + + QAudioDeviceInfo audio_device_info(QAudioDeviceInfo::defaultOutputDevice()); + if(!audio_device_info.isFormatSupported(audio_format)) + { + printf("audio output format not supported\n"); + } + + audio_output = new QAudioOutput(audio_format, this); + audio_io = audio_output->start(); + + chiaki_session_init(&session, &connect_info); + chiaki_session_set_audio_frame_cb(&session, AudioFrameCb, this); + chiaki_session_set_video_sample_cb(&session, VideoSampleCb, this); + chiaki_session_start(&session); + connect(QGamepadManager::instance(), &QGamepadManager::connectedGamepadsChanged, this, &StreamSession::UpdateGamepads); UpdateGamepads(); } StreamSession::~StreamSession() { + chiaki_session_join(&session); + chiaki_session_fini(&session); } void StreamSession::UpdateGamepads() @@ -49,4 +115,33 @@ void StreamSession::UpdateGamepads() qDebug() << "gamepad" << connected_pads[0] << "connected: " << gamepad->name(); } } +} + +void StreamSession::PushAudioFrame(int16_t *buf, size_t samples_count) +{ + audio_io->write((const char *)buf, static_cast(samples_count * 2 * 2)); +} + +void StreamSession::PushVideoSample(uint8_t *buf, size_t buf_size) +{ + video_decoder.PutFrame(buf, buf_size); +} + +class StreamSessionPrivate +{ + public: + static void PushAudioFrame(StreamSession *session, int16_t *buf, size_t samples_count) { session->PushAudioFrame(buf, samples_count); } + static void PushVideoSample(StreamSession *session, uint8_t *buf, size_t buf_size) { session->PushVideoSample(buf, buf_size); } +}; + +static void AudioFrameCb(int16_t *buf, size_t samples_count, void *user) +{ + auto session = reinterpret_cast(user); + StreamSessionPrivate::PushAudioFrame(session, buf, samples_count); +} + +static void VideoSampleCb(uint8_t *buf, size_t buf_size, void *user) +{ + auto session = reinterpret_cast(user); + StreamSessionPrivate::PushVideoSample(session, buf, buf_size); } \ No newline at end of file diff --git a/gui/src/streamwindow.cpp b/gui/src/streamwindow.cpp index 984ca98..27af570 100644 --- a/gui/src/streamwindow.cpp +++ b/gui/src/streamwindow.cpp @@ -16,11 +16,13 @@ */ #include +#include #include -StreamWindow::StreamWindow(QWidget *parent) - : QMainWindow(parent) +StreamWindow::StreamWindow(StreamSession *session, QWidget *parent) + : QMainWindow(parent), + session(session) { imageLabel = new QLabel(this); setCentralWidget(imageLabel); @@ -29,6 +31,8 @@ StreamWindow::StreamWindow(QWidget *parent) imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); imageLabel->setScaledContents(true); + connect(session->GetVideoDecoder(), &VideoDecoder::FramesAvailable, this, &StreamWindow::FramesAvailable); + FramesAvailable(); } StreamWindow::~StreamWindow() @@ -38,4 +42,20 @@ StreamWindow::~StreamWindow() void StreamWindow::SetImage(const QImage &image) { imageLabel->setPixmap(QPixmap::fromImage(image)); -} \ No newline at end of file +} + +void StreamWindow::FramesAvailable() +{ + QImage prev; + QImage image; + do + { + prev = image; + image = session->GetVideoDecoder()->PullFrame(); + } while(!image.isNull()); + + if(!prev.isNull()) + { + SetImage(prev); + } +}