From 26b2d57fcb1a50c9bcfa4ca4ab1d25f903a8578b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sat, 8 Jun 2019 15:34:44 +0200 Subject: [PATCH] Add QtAV Output --- cmake/FindQtAV.cmake | 56 +++++++++++++++++++++++++ gui/CMakeLists.txt | 9 ++++- gui/include/streamwindow.h | 83 ++++++++++++++++++++++++++++++++++++++ gui/src/main.cpp | 15 +++++-- gui/src/streamwindow.cpp | 31 ++++++++++++++ lib/src/nagare.c | 2 +- 6 files changed, 190 insertions(+), 6 deletions(-) create mode 100644 cmake/FindQtAV.cmake diff --git a/cmake/FindQtAV.cmake b/cmake/FindQtAV.cmake new file mode 100644 index 0000000..0c4f3a5 --- /dev/null +++ b/cmake/FindQtAV.cmake @@ -0,0 +1,56 @@ +# - Try to find the QtAV library +# +# Once done this will define +# +# QTAV_FOUND - system has libqtav +# QTAV_INCLUDE_DIRS - the libqtav include directory +# QTAV_LIBRARIES - Link these to use libqtav + +find_package(Qt5 QUIET REQUIRED NO_MODULE COMPONENTS Core) + +get_target_property(qmake Qt5::qmake LOCATION) +execute_process( + COMMAND ${qmake} -query QT_INSTALL_HEADERS + OUTPUT_VARIABLE QT_INSTALL_HEADERS + OUTPUT_STRIP_TRAILING_WHITESPACE +) +execute_process( + COMMAND ${qmake} -query QT_INSTALL_LIBS + OUTPUT_VARIABLE QT_INSTALL_LIBS + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +find_path(QTAV_INCLUDE_DIR NAMES QtAV.h + HINTS ${QT_INSTALL_HEADERS} + PATH_SUFFIXES QtAV +) +find_library(QTAV_LIBRARY NAMES QtAV QtAV1 + HINTS ${QT_INSTALL_LIBS} +) + +find_path(QTAVWIDGETS_INCLUDE_DIR NAMES QtAVWidgets.h + HINTS ${QT_INSTALL_HEADERS} + PATH_SUFFIXES QtAVWidgets +) +find_library(QTAVWIDGETS_LIBRARY NAMES QtAVWidgets QtAVWidgets1 + HINTS ${QT_INSTALL_LIBS} +) + +set(QTAV_INCLUDE_DIRS ${QTAV_INCLUDE_DIR} ${QTAV_INCLUDE_DIR}/..) +set(QTAV_LIBRARIES ${QTAV_LIBRARY}) +if(NOT QTAVWIDGETS_INCLUDE_DIR MATCHES "QTAVWIDGETS_INCLUDE_DIR-NOTFOUND") + set(QTAVWIDGETS_INCLUDE_DIRS ${QTAVWIDGETS_INCLUDE_DIR} ${QTAVWIDGETS_INCLUDE_DIR}/.. ${QTAV_INCLUDE_DIRS}) +endif() +if(NOT QTAV_LIBRARIES MATCHES "QTAV_LIBRARIES-NOTFOUND") + set(QTAVWIDGETS_LIBRARIES ${QTAVWIDGETS_LIBRARY} ${QTAV_LIBRARY}) +endif() + +find_package(PackageHandleStandardArgs REQUIRED) +find_package_handle_standard_args(QtAV REQUIRED_VARS QTAV_LIBRARIES QTAV_INCLUDE_DIRS) +mark_as_advanced(QTAV_INCLUDE_DIRS QTAV_LIBRARIES QTAVWIDGETS_INCLUDE_DIRS QTAVWIDGETS_LIBRARIES) + +message("QtAV_FOUND = ${QTAV_FOUND}") +message("QTAV_INCLUDE_DIRS = ${QTAV_INCLUDE_DIRS}") +message("QTAV_LIBRARIES = ${QTAV_LIBRARIES}") +message("QTAVWIDGETS_INCLUDE_DIRS = ${QTAVWIDGETS_INCLUDE_DIRS}") +message("QTAVWIDGETS_LIBRARIES = ${QTAVWIDGETS_LIBRARIES}") diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index dc87630..021d5ac 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -3,7 +3,9 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) -find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui Multimedia) +find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui Multimedia OpenGL) + +find_package(QtAV REQUIRED) add_executable(chiaki src/main.cpp @@ -13,4 +15,7 @@ target_include_directories(chiaki PRIVATE include) target_link_libraries(chiaki chiaki-lib) -target_link_libraries(chiaki Qt5::Core Qt5::Widgets Qt5::Gui Qt5::Multimedia) \ No newline at end of file +target_link_libraries(chiaki Qt5::Core Qt5::Widgets Qt5::Gui Qt5::OpenGL Qt5::Multimedia) + +target_include_directories(chiaki PRIVATE ${QTAV_INCLUDE_DIRS} ${QTAVWIDGETS_INCLUDE_DIRS}) +target_link_libraries(chiaki ${QTAV_LIBRARIES} ${QTAVWIDGETS_LIBRARIES}) \ No newline at end of file diff --git a/gui/include/streamwindow.h b/gui/include/streamwindow.h index d5f22e6..7fc804c 100644 --- a/gui/include/streamwindow.h +++ b/gui/include/streamwindow.h @@ -20,6 +20,80 @@ #include +namespace QtAV +{ + class VideoOutput; + class AVPlayer; +} + +#include +#include +#include +#include + +class StreamRelayIODevice : public QIODevice +{ + private: + QMutex *mutex; + QByteArray buffer; + + public: + explicit StreamRelayIODevice(QObject *parent = nullptr) + : QIODevice(parent), + mutex(new QMutex(QMutex::Recursive)) + { + setOpenMode(OpenModeFlag::ReadOnly); + } + + ~StreamRelayIODevice() override = default; + + void PushSample(uint8_t *buf, size_t size) + { + { + QMutexLocker locker(mutex); + printf("push sample %zu\n", size); + buffer.append(reinterpret_cast(buf), static_cast(size)); + } + emit readyRead(); + } + + + qint64 pos() const override { return 0; } + bool open(QIODevice::OpenMode mode) override { return true; } + bool isSequential() const override { return true; } + + qint64 bytesAvailable() const override + { + QMutexLocker locker(mutex); + return buffer.size() + QIODevice::bytesAvailable(); + } + + protected: + qint64 readData(char *data, qint64 maxSize) + { + while(true) + { + { + QMutexLocker locker(mutex); + if(buffer.size() >= maxSize) + { + printf("read %lld\n", maxSize); + memcpy(data, buffer.constData(), maxSize); + buffer.remove(0, maxSize); + return maxSize; + } + } + QThread::msleep(100); + } + } + + qint64 writeData(const char *data, qint64 maxSize) + { + return -1; + } +}; + + class StreamWindow: public QMainWindow { Q_OBJECT @@ -27,6 +101,15 @@ class StreamWindow: public QMainWindow public: explicit StreamWindow(QWidget *parent = nullptr); ~StreamWindow(); + + StreamRelayIODevice *GetIODevice() { return io_device; } + + private: + QtAV::VideoOutput *video_output; + QtAV::AVPlayer *av_player; + + StreamRelayIODevice *io_device; + }; #endif // CHIAKI_GUI_STREAMWINDOW_H diff --git a/gui/src/main.cpp b/gui/src/main.cpp index d177d79..d47f18b 100644 --- a/gui/src/main.cpp +++ b/gui/src/main.cpp @@ -21,6 +21,13 @@ 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) +{ + //StreamRelayIODevice *io_device = reinterpret_cast(user); + //io_device->PushSample(buf, buf_size); +} + + int main(int argc, char *argv[]) { if(argc != 7) @@ -64,8 +71,6 @@ int main(int argc, char *argv[]) window.resize(640, 360); window.show(); - return app.exec(); - QAudioFormat audio_format; audio_format.setSampleRate(48000); @@ -87,11 +92,15 @@ int main(int argc, char *argv[]) ChiakiSession session; chiaki_session_init(&session, &connect_info); chiaki_session_set_audio_frame_cb(&session, audio_frame_cb, NULL); + chiaki_session_set_video_sample_cb(&session, video_sample_cb, window.GetIODevice()); chiaki_session_start(&session); + + int ret = app.exec(); + chiaki_session_join(&session); chiaki_session_fini(&session); delete audio_out; - return 0; + return ret; } \ No newline at end of file diff --git a/gui/src/streamwindow.cpp b/gui/src/streamwindow.cpp index 1e8aa4a..a3a9747 100644 --- a/gui/src/streamwindow.cpp +++ b/gui/src/streamwindow.cpp @@ -17,9 +17,40 @@ #include +#include +#include + +#include + + StreamWindow::StreamWindow(QWidget *parent) : QMainWindow(parent) { + video_output = new QtAV::VideoOutput(QtAV::VideoRendererId_GLWidget2, this); + setCentralWidget(video_output->widget()); + + av_player = new QtAV::AVPlayer(this); + + connect(av_player, &QtAV::AVPlayer::stateChanged, this, [](QtAV::AVPlayer::State state){ + printf("state changed to %d\n", state); + }); + + av_player->setRenderer(video_output); + + io_device = new StreamRelayIODevice(this); + io_device->open(QIODevice::ReadOnly); + + QString test_filename = QProcessEnvironment::systemEnvironment().value("CHIAKI_TEST_VIDEO"); + if(!test_filename.isEmpty()) + { + QFile *test_file = new QFile(test_filename, this); + test_file->open(QIODevice::OpenModeFlag::ReadOnly); + QByteArray sample = test_file->readAll(); + io_device->PushSample((uint8_t *)sample.constData(), (size_t)sample.size()); + test_file->close(); + av_player->setIODevice(io_device); + av_player->play(); + } } StreamWindow::~StreamWindow() diff --git a/lib/src/nagare.c b/lib/src/nagare.c index c2de32c..37629e7 100644 --- a/lib/src/nagare.c +++ b/lib/src/nagare.c @@ -570,7 +570,7 @@ static void nagare_takion_av(ChiakiTakionAVPacket *header, uint8_t *buf, size_t if(header->codec == 5/*buf[0] == 0xf4 && buf_size >= 0x50*/) { //CHIAKI_LOGD(nagare->log, "audio!\n"); - chiaki_audio_receiver_frame_packet(nagare->session->audio_receiver, buf, 0x50); // TODO: why 0x50? + chiaki_audio_receiver_frame_packet(nagare->session->audio_receiver, buf, 0x50); // TODO: why 0x50? this is dangerous!!! } else {