From 8a26c6ba8551edc29d643e25e5b33e36e5fb73f5 Mon Sep 17 00:00:00 2001 From: pingkai Date: Sun, 26 Apr 2020 15:32:45 +0800 Subject: [PATCH] feat(cmdline): add syncPlayer example Signed-off-by: pingkai --- cmdline/CMakeLists.txt | 2 + cmdline/example/CMakeLists.txt | 129 +++++++++ .../example/communication/playerMessage.cpp | 12 + cmdline/example/communication/playerMessage.h | 21 ++ cmdline/example/syncPlayer.cpp | 264 ++++++++++++++++++ cmdline/example/syncPlayerEventListener.h | 46 +++ 6 files changed, 474 insertions(+) create mode 100644 cmdline/example/CMakeLists.txt create mode 100644 cmdline/example/communication/playerMessage.cpp create mode 100644 cmdline/example/communication/playerMessage.h create mode 100644 cmdline/example/syncPlayer.cpp create mode 100644 cmdline/example/syncPlayerEventListener.h diff --git a/cmdline/CMakeLists.txt b/cmdline/CMakeLists.txt index fda88b0c4..d05db66f7 100644 --- a/cmdline/CMakeLists.txt +++ b/cmdline/CMakeLists.txt @@ -105,6 +105,8 @@ else () endif () target_link_libraries(cicadaPlayer PUBLIC coverage_config) +add_subdirectory(example) + if (USEASAN) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fsanitize-address-use-after-scope") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fsanitize-address-use-after-scope") diff --git a/cmdline/example/CMakeLists.txt b/cmdline/example/CMakeLists.txt new file mode 100644 index 000000000..e56f3f001 --- /dev/null +++ b/cmdline/example/CMakeLists.txt @@ -0,0 +1,129 @@ +cmake_minimum_required(VERSION 3.15) +project(example) + +set(CMAKE_CXX_STANDARD 11) + +include(../../framework/${TARGET_PLATFORM}.cmake) + +include(../../framework/module_config.cmake) + +add_executable(syncPlayer "") + +target_sources(syncPlayer PRIVATE + syncPlayer.cpp + communication/playerMessage.cpp + ../cicadaEventListener.cpp + ../NetWorkEventReceiver.cpp + ) + +if (ENABLE_SDL) + target_sources(syncPlayer PRIVATE + ../SDLEventReceiver.cpp + ../SDLEventReceiver.h + ) +endif () + +target_include_directories(syncPlayer PUBLIC + ../../mediaPlayer + ../) +target_link_directories(syncPlayer PRIVATE + ../../external/install/ffmpeg/${CMAKE_SYSTEM_NAME}/x86_64/lib + ../../external/install/curl/${CMAKE_SYSTEM_NAME}/x86_64/lib + ../../external/install/openssl/${CMAKE_SYSTEM_NAME}/x86_64/lib + ${COMMON_LIB_DIR}) + +target_link_libraries(syncPlayer PRIVATE + media_player + demuxer + data_source + render + videodec + communication) +if (ENABLE_CACHE_MODULE) + target_link_libraries(syncPlayer PRIVATE + cacheModule) +endif () +if (ENABLE_MUXER) + target_link_libraries(syncPlayer PRIVATE + muxer) +endif () +target_link_libraries(syncPlayer PRIVATE + framework_filter + framework_utils + avfilter + avformat + avcodec + swresample + avutil + curl + ${FRAMEWORK_LIBS}) +if (ENABLE_SDL) + target_link_libraries(syncPlayer PUBLIC + SDL2 + ) +endif () + +if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") + target_link_libraries(syncPlayer PUBLIC + bcrypt + ) +else () + target_link_libraries(syncPlayer PUBLIC + z + dl + ) +endif () + +if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + target_link_libraries(syncPlayer PUBLIC + bz2 + ) +endif () + +if (APPLE) + target_link_libraries( + syncPlayer PUBLIC + iconv + bz2 + ${FRAMEWORK_LIBS} + ) +else () + target_link_libraries( + syncPlayer PUBLIC + dl + ssl + crypto + pthread + ) +endif () +target_link_libraries(syncPlayer PUBLIC coverage_config) + +if (USEASAN) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fsanitize-address-use-after-scope") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fsanitize-address-use-after-scope") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address") + # set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} -fsanitize=address") +endif (USEASAN) + +if (USETSAN) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=thread") + # set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} -fsanitize=address") +endif (USETSAN) + +if (USEUBSAN) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined, -fsanitize=integer, -fsanitize=nullability") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined, -fsanitize=integer, -fsanitize=nullability") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=undefined, -fsanitize=integer, -fsanitize=nullability") + # set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} -fsanitize=address") +endif (USEUBSAN) + +if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + if (USEMSAN) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory, -fsanitize-memory-track-origins -fno-omit-frame-pointer") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=memory, -fsanitize-memory-track-origins -fno-omit-frame-pointer") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=memory, -fsanitize-memory-track-origins -fno-omit-frame-pointer") + # set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} -fsanitize=address") + endif (USEMSAN) +endif () \ No newline at end of file diff --git a/cmdline/example/communication/playerMessage.cpp b/cmdline/example/communication/playerMessage.cpp new file mode 100644 index 000000000..608468f88 --- /dev/null +++ b/cmdline/example/communication/playerMessage.cpp @@ -0,0 +1,12 @@ +// +// Created by moqi on 2020/4/23. +// + +#include "playerMessage.h" +using namespace Cicada; +const std::string playerMessage::prepare = "prepare"; +const std::string playerMessage::pause = "pause"; +const std::string playerMessage::start = "start"; +const std::string playerMessage::exit = "exit"; +const std::string playerMessage::fullScreen = "fullScreen"; +const std::string playerMessage::clock = "clock"; diff --git a/cmdline/example/communication/playerMessage.h b/cmdline/example/communication/playerMessage.h new file mode 100644 index 000000000..9d7e9ae63 --- /dev/null +++ b/cmdline/example/communication/playerMessage.h @@ -0,0 +1,21 @@ +// +// Created by moqi on 2020/4/23. +// + +#ifndef CICADAMEDIA_PLAYERMESSAGE_H +#define CICADAMEDIA_PLAYERMESSAGE_H +#include +namespace Cicada { + class playerMessage { + public: + const static std::string prepare; + const static std::string start; + const static std::string pause; + const static std::string exit; + const static std::string fullScreen; + const static std::string clock; + }; +}// namespace Cicada + + +#endif//CICADAMEDIA_PLAYERMESSAGE_H diff --git a/cmdline/example/syncPlayer.cpp b/cmdline/example/syncPlayer.cpp new file mode 100644 index 000000000..5e6fb3cfa --- /dev/null +++ b/cmdline/example/syncPlayer.cpp @@ -0,0 +1,264 @@ +#include +#include +#include + +using namespace Cicada; +using namespace std; + +#include "NetWorkEventReceiver.h" +#include "SDLEventReceiver.h" +#include "cicadaEventListener.h" +#include + +#ifdef ENABLE_SDL +#include +#define SDL_MAIN_HANDLED +#endif + +#include "communication/playerMessage.h" +#include "syncPlayerEventListener.h" +#include +#include + +using IEvent = IEventReceiver::IEvent; +struct cicadaCont { + unique_ptr player; + IEventReceiver *receiver; + bool error; + bool bMaster; + messageServer *server; + af_clock masterClock; +#ifdef ENABLE_SDL + SDL_Window *window; + SDL_Renderer *rendere; +#endif +}; + +static void onStatusChanged(int64_t oldStatus, int64_t newStatus, void *userData) +{ + AF_TRACE; + auto *cont = static_cast(userData); + + if (cont->server) { + if (newStatus == PLAYER_PLAYING) + cont->server->write(playerMessage::start); + else if (newStatus == PLAYER_PAUSED) { + cont->server->write(playerMessage::pause); + } + } +} +static void onLoadingStart(void *userData) +{ + auto *cont = static_cast(userData); + if (cont->server) { + cont->server->write(playerMessage::pause); + } +} +static void onLoadingEnd(void *userData) +{ + auto *cont = static_cast(userData); + if (cont->server) { + cont->server->write(playerMessage::start); + } +} + +static void onEOS(void *userData) +{ + auto *cont = static_cast(userData); + + if (cont->receiver) { + cont->receiver->push(std::unique_ptr(new IEvent(IEvent::TYPE_EXIT))); + } +} + +static void onEvent(int64_t errorCode, const void *errorMsg, void *userData) +{ + auto *cont = static_cast(userData); + + if (errorMsg) { + AF_LOGD("%s\n", errorMsg); + } + + switch (errorCode) { + case MediaPlayerEventType::MEDIA_PLAYER_EVENT_NETWORK_RETRY: + cont->player->Reload(); + break; + + default: + break; + } +} + +static void onError(int64_t errorCode, const void *errorMsg, void *userData) +{ + auto *cont = static_cast(userData); + + if (errorMsg) { + AF_LOGE("%s\n", errorMsg); + } + + if (cont->receiver) { + auto *event = new IEvent(IEvent::TYPE_EXIT); + cont->receiver->push(std::unique_ptr(event)); + } else { + cont->error = true; + } +} + +static MediaPlayer *createPlayer(cicadaCont &cicada, const string &url) +{ + cicada.player = unique_ptr(new MediaPlayer()); + playerListener pListener{nullptr}; + pListener.userData = &cicada; + pListener.Completion = onEOS; + pListener.EventCallback = onEvent; + pListener.ErrorCallback = onError; + pListener.StatusChanged = onStatusChanged; + pListener.LoadingStart = onLoadingStart; + pListener.LoadingEnd = onLoadingEnd; + cicada.player->SetListener(pListener); + cicada.player->SetDefaultBandWidth(1000 * 1000); + cicada.player->SetDataSource(url.c_str()); +#ifdef ENABLE_SDL + Uint32 flags = 0; + flags |= SDL_WINDOW_ALLOW_HIGHDPI; + flags |= SDL_WINDOW_RESIZABLE; + SDL_CreateWindowAndRenderer(640, 360, flags, &(cicada.window), &(cicada.rendere)); + SDL_SetWindowTitle(cicada.window, cicada.bMaster ? "master" : "slave"); + cicada.player->SetView(cicada.window); +#else + int view = 0; + cicada.player->SetView(&view); +#endif + return cicada.player.get(); +} +static int64_t getMasterClock(void *arg) +{ + auto *cont = static_cast(arg); + return cont->masterClock.get(); +}; + +static string serverIp = "tcp://localhost:8888"; + +int main(int argc, const char **argv) +{ + string url; + bool connected = false; + bool bMaster = true; + if (argc > 2) { + bMaster = false; + } + if (bMaster) { + AF_LOGW("master"); + } + + if (argc > 1) { + url = argv[1]; + } else { + url = "http://player.alicdn.com/video/aliyunmedia.mp4"; + } + + log_enable_color(1); + log_set_level(AF_LOG_LEVEL_WARNING, 1); + cicadaCont cicada{}; +#ifdef ENABLE_SDL + SDL_Init(SDL_INIT_VIDEO); +#endif + cicada.bMaster = bMaster; + createPlayer(cicada, url); + unique_ptr client{}; + unique_ptr server{}; + + if (bMaster) { + // player->SetAutoPlay(true); + // player->SetLoop(true); + server = static_cast>(new messageServer()); + server->init(); + cicada.server = server.get(); + } else { + cicada.player->SetStreamTypeFlags(VIDEO_FLAG); + cicada.player->SetClockRefer(getMasterClock, &cicada); + client = static_cast>(new messageClient()); + int ret = client->connect(serverIp); + if (ret >= 0) { + connected = true; + } + } +#ifdef ENABLE_SDL + syncPlayerEventListener eListener(cicada.player.get(), server.get(), cicada.window); + SDLEventReceiver receiver(eListener); +#else + syncPlayerEventListener eListener(cicada.player.get(), server.get(), nullptr); +#endif + NetWorkEventReceiver netWorkEventReceiver(eListener); + + cicada.player->SelectTrack(-1); + + + bool quite = false; + string msg{}; + + while (!quite && !cicada.error) { + +#ifdef ENABLE_SDL + receiver.poll(quite); +#endif + + if (!bMaster) { + if (!connected) { + connected = client->connect(serverIp) >= 0; + } else { + msg = client->readMessage(); + if (!msg.empty()) { + // AF_LOGE("client msg %s\n", msg.c_str()); + if (msg == playerMessage::start) { + cicada.player->Start(); + cicada.masterClock.start(); + } else if (msg == playerMessage::pause) { + cicada.player->Pause(); + cicada.masterClock.pause(); + } else if (msg == playerMessage::exit) { + quite = true; + } else if (msg == playerMessage::prepare) { + cicada.player->Prepare(); + } else if (msg == playerMessage::clock) { + int64_t pts = atoll(client->readMessage().c_str()); + cicada.masterClock.set(pts); + if (llabs(pts - cicada.player->GetMasterClockPts()) > 40000) { + AF_LOGW("delta pts is %lld\n", pts - cicada.player->GetMasterClockPts()); + } + } else if (msg == playerMessage::fullScreen) { +#ifdef ENABLE_SDL + bool full = atoll(client->readMessage().c_str()) != 0; + SDL_SetWindowFullscreen(cicada.window, full ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); +#endif + } + } + } + } else { + static int64_t pts = 0; + int64_t pts1 = cicada.player->GetMasterClockPts(); + if (pts1 - pts > 100000) { + server->write(playerMessage::clock); + server->write(to_string(pts1)); + pts = pts1; + } + if (!quite) { + netWorkEventReceiver.poll(quite); + } + } + if (quite) { + auto *event = new IEvent(IEvent::TYPE_EXIT); +#ifdef ENABLE_SDL + receiver.push(std::unique_ptr(event)); +#endif + if (server) { + server->write(playerMessage::exit); + } + } else { + af_msleep(10); + } + } + + return 0; +} \ No newline at end of file diff --git a/cmdline/example/syncPlayerEventListener.h b/cmdline/example/syncPlayerEventListener.h new file mode 100644 index 000000000..3e8ba79da --- /dev/null +++ b/cmdline/example/syncPlayerEventListener.h @@ -0,0 +1,46 @@ +// +// Created by moqi on 2020/4/24. +// + +#ifndef CICADAMEDIA_SYNCPLAYEREVENTLISTENER_H +#define CICADAMEDIA_SYNCPLAYEREVENTLISTENER_H +#include "../cicadaEventListener.h" +#include "communication/playerMessage.h" +#include +namespace Cicada { + class syncPlayerEventListener : public cicadaEventListener { + public: + syncPlayerEventListener(MediaPlayer *player, messageServer *server, void *window) + : cicadaEventListener(player), mServer(server), mWindow(window) + {} + ~syncPlayerEventListener() override = default; + + void onPrePare() override + { + mediaPlayer->Prepare(); + if (mServer) { + mServer->write(playerMessage::prepare); + } + } + + void onFullScreen(bool full) override + { +#ifdef ENABLE_SDL + if (mWindow) { + SDL_SetWindowFullscreen((SDL_Window *) mWindow, full ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); + } +#endif + if (mServer) { + mServer->write(playerMessage::fullScreen); + mServer->write(full ? "1" : "0"); + } + } + + private: + messageServer *mServer; + void *mWindow; + }; +}// namespace Cicada + + +#endif//CICADAMEDIA_SYNCPLAYEREVENTLISTENER_H