diff --git a/CMakeLists.txt b/CMakeLists.txt index a647ad076..9faf8b524 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,8 @@ function(xcode_define_schema new_schema) endfunction() project (AAMP) -set(CMAKE_CXX_STANDARD 11) +#set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=format -Wno-multichar -Wno-non-virtual-dtor -Wno-psabi") @@ -95,8 +96,8 @@ if(CMAKE_PLATFORM_UBUNTU OR CMAKE_SYSTEM_NAME STREQUAL Darwin) COMMAND bash -c "xcrun --show-sdk-path" OUTPUT_VARIABLE osxSdkPath OUTPUT_STRIP_TRAILING_WHITESPACE ) set(OS_CXX_FLAGS "${OS_CXX_FLAGS} -g -x objective-c++ -Wno-inconsistent-missing-override -F${osxSdkPath}/System/Library/Frameworks") - set(OS_LD_FLAGS "${OS_LD_FLAGS} -F${osxSdkPath}/System/Library/Frameworks -framework Cocoa -L${osxSdkPath}/../MacOSX.sdk/usr/lib -L.libs/lib -L/usr/local/lib/") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isysroot ${osxSdkPath}/../MacOSX.sdk -I/usr/local/include") + set(OS_LD_FLAGS "${OS_LD_FLAGS} -F${osxSdkPath}/System/Library/Frameworks -framework Cocoa -L${osxSdkPath}/../MacOSX26.1.sdk/usr/lib -L.libs/lib -L/usr/local/lib/") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isysroot ${osxSdkPath}/../MacOSX26.1.sdk -I/usr/local/include") string(STRIP ${OS_LD_FLAGS} OS_LD_FLAGS) pkg_check_modules(GSTREAMERVIDEO REQUIRED gstreamer-video-1.0) set(AAMP_CLI_LD_FLAGS ${AAMP_CLI_LD_FLAGS} ${GSTREAMERVIDEO_LINK_LIBRARIES}) @@ -456,29 +457,47 @@ set(GSTTESTHARNESS_DEPENDS ${CURL_LINK_LIBRARIES} ) set(GSTTESTHARNESS_SOURCES - test/gstTestHarness/gst-port.cpp - test/gstTestHarness/gst-port.h - test/gstTestHarness/gst-utils.cpp - test/gstTestHarness/gst-utils.h - test/gstTestHarness/gst-test.cpp - test/gstTestHarness/gst-test.h + test/gstTestHarness/rialto-api-test.cpp + test/gstTestHarness/rialto-gst-pipeline.cpp + test/gstTestHarness/rialto-gst-pipeline.h test/gstTestHarness/mp4demux.hpp - test/gstTestHarness/dash_adapter.cpp - test/gstTestHarness/dash_adapter.hpp - test/gstTestHarness/downloader.cpp - test/gstTestHarness/downloader.hpp - test/gstTestHarness/stream_utils.cpp - test/gstTestHarness/stream_utils.hpp - test/gstTestHarness/string_utils.cpp - test/gstTestHarness/string_utils.hpp - test/gstTestHarness/tsdemux.hpp - test/gstTestHarness/turbo_xml.hpp ) -add_executable(gstTestHarness ${GSTTESTHARNESS_SOURCES}) -target_link_libraries(gstTestHarness ${GSTTESTHARNESS_DEPENDS} "-lreadline") -install(TARGETS gstTestHarness - DESTINATION bin + +find_path( RIALTO_INCLUDE_DIR NAMES IMediaPipeline.h PATH_SUFFIXES rialto) + + +find_library( RIALTO_LIBRARY NAMES libRialtoClient.so RialtoClient ) + +include( FindPackageHandleStandardArgs ) + +find_package_handle_standard_args( RIALTO DEFAULT_MSG + RIALTO_LIBRARY RIALTO_INCLUDE_DIR ) + +mark_as_advanced( + RIALTO_INCLUDE_DIR + RIALTO_LIBRARY + RIALTO_GSTREAMER_INCLUDE_DIR ) + +if( RIALTO_FOUND ) + set( RIALTO_LIBRARIES ${RIALTO_LIBRARY} ) + set(RIALTO_INCLUDE_DIRS + ${RIALTO_INCLUDE_DIR} + ${RIALTO_GSTREAMER_INCLUDE_DIR} +) +endif() + +if( RIALTO_FOUND AND NOT TARGET Rialto::RialtoClient ) + add_library( Rialto::RialtoClient SHARED IMPORTED ) + set_target_properties( Rialto::RialtoClient PROPERTIES + IMPORTED_LOCATION "${RIALTO_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${RIALTO_INCLUDE_DIR}" ) +endif() + +add_executable(gstTestHarness ${GSTTESTHARNESS_SOURCES}) +target_link_libraries(gstTestHarness ${GSTTESTHARNESS_DEPENDS} "-lreadline" Rialto::RialtoClient) + +install(TARGETS gstTestHarness DESTINATION bin) # XCode schema target xcode_define_schema(gstTestHarness) @@ -507,7 +526,6 @@ install(FILES DESTINATION include ) - if (UTEST_ENABLED) add_subdirectory(test/utests EXCLUDE_FROM_ALL) endif() diff --git a/test/gstTestHarness/mp4demux.hpp b/test/gstTestHarness/mp4demux.hpp index edab454e8..dd633ad99 100644 --- a/test/gstTestHarness/mp4demux.hpp +++ b/test/gstTestHarness/mp4demux.hpp @@ -53,7 +53,7 @@ struct Mp4Sample class Mp4Demux { -private: +public: // temp workaround - used directly in rialtoTest struct { uint16_t channel_count; diff --git a/test/gstTestHarness/rialto-api-test.cpp b/test/gstTestHarness/rialto-api-test.cpp new file mode 100644 index 000000000..a6aad1aa4 --- /dev/null +++ b/test/gstTestHarness/rialto-api-test.cpp @@ -0,0 +1,304 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mp4demux.hpp" +#include "rialto-gst-pipeline.h" + +static const int64_t NS_SECOND = 1000000000LL; + +static Mp4Demux trackAudio; +static Mp4Demux trackVideo; +static std::shared_ptr gstMediaPipeline; +static int gUserPathLen; +static const char *gUserPathPtr; +static int32_t sourceIdAudio; +static int32_t sourceIdVideo; + +using namespace firebolt::rialto; + +uint32_t WaitForNeedDataRequest(int32_t sourceId, int timeoutMs = 5000) +{ + std::unique_lock lock(g_needDataMutex); + + // Wait until a matching event is in the queue + bool ok = g_needDataCv.wait_for(lock, std::chrono::milliseconds(timeoutMs), [&]{ + std::queue tmp = g_needDataQueue; + while (!tmp.empty()) { + if (tmp.front().sourceId == sourceId) + return true; + tmp.pop(); + } + return false; + }); + + if (!ok) + { + fprintf(stderr, "ERROR: Timeout waiting for need-data for source %d\n", sourceId); + return UINT32_MAX; + } + + uint32_t requestId = UINT32_MAX; + size_t qSize = g_needDataQueue.size(); + for (size_t i = 0; i < qSize; ++i) { + NeedDataRequestEvent ev = g_needDataQueue.front(); + g_needDataQueue.pop(); + + if (ev.sourceId == sourceId && requestId == UINT32_MAX) { + requestId = ev.requestId; + + } else { + g_needDataQueue.push(ev); + } + } + + return requestId; +} + +void LoadAndDemuxSegment(Mp4Demux &mp4Demux, const char *path) +{ + char fullpath[512]; + snprintf(fullpath, sizeof(fullpath), "/tmp/data/bipbop-gen/%s", path); + printf("loading rialtotest %s\n", fullpath); + + FILE *f = fopen(fullpath, "rb"); + assert(f); + if (f) + { + fseek(f, 0, SEEK_END); + long len = ftell(f); + if (len > 0) + { + unsigned char *ptr = (unsigned char *)malloc(len); + assert(ptr); + if (ptr) + { + fseek(f, 0, SEEK_SET); + size_t n = fread(ptr, 1, len, f); + assert(n == len); + if (n == len) + { + mp4Demux.Parse(ptr, (uint32_t)len); + } + free(ptr); + } + } + fclose(f); + } +} + +void ConfigureAudio() +{ + LoadAndDemuxSegment(trackAudio, "audio/init-stream0.m4s"); + std::cout << "loading rialtotest /tmp/data/bipbop-gen/audio/init-stream0.m4s" << std::endl; + + bool hasDrm = false; + std::string mimeType; + StreamFormat streamFormat; + AudioConfig audioConfig; + audioConfig.numberOfChannels = trackAudio.audio.channel_count; + audioConfig.sampleRate = trackAudio.audio.samplerate; + + // StreamFormat streamFormat = StreamFormat::AAC; + // SegmentAlignment alignment = SegmentAlignment::AU; + + switch( trackAudio.codec_type ) + { + case MultiChar_Constant("esds"): + mimeType = "audio/mpeg"; + streamFormat = StreamFormat::RAW; + break; + case MultiChar_Constant("dec3"): + mimeType = "audio/x-eac3"; + streamFormat = StreamFormat::UNDEFINED; + break; + default: + assert(0); + break; + } + + // CodecData codecData; + // const char *codec_ptr = trackAudio.codec_data.c_str(); + // codecData.data = std::vector( codec_ptr, &codec_ptr[trackAudio.codec_data.size()] ); + + std::unique_ptr sourceAudio = std::make_unique( + mimeType, + hasDrm, + audioConfig, + SegmentAlignment::UNDEFINED, + streamFormat, + nullptr /* codecData*/ ); + + gstMediaPipeline->attachSource( std::move(sourceAudio), sourceIdAudio ); +} + +void ConfigureVideo() +{ + LoadAndDemuxSegment( trackVideo, "video/init-stream0.m4s" ); + + bool hasDrm = false; + std::string mimeType; + StreamFormat streamFormat; + int32_t width = trackVideo.video.width; + int32_t height = trackVideo.video.height; + SegmentAlignment alignment = SegmentAlignment::AU; + + switch( trackVideo.codec_type ) + { + case MultiChar_Constant("hvcC"): + mimeType = "video/h265"; + streamFormat = StreamFormat::HVC1; + break; + case MultiChar_Constant("avcC"): + mimeType = "video/h264"; + streamFormat = StreamFormat::AVC; + break; + default: + assert(0); + break; + } + CodecData codecData; + const char *codec_ptr = trackVideo.codec_data.c_str(); + codecData.data = std::vector( codec_ptr, codec_ptr + trackVideo.codec_data.size() ); + + std::unique_ptr sourceVideo = + std::make_unique( + mimeType, + hasDrm, + width, + height, + alignment, + streamFormat, + std::make_shared(codecData) ); + + gstMediaPipeline->attachSource( std::move(sourceVideo), sourceIdVideo ); +} + +void ConfigureComplete() +{ + gstMediaPipeline->allSourcesAttached(); +} + +void InjectAudio(int32_t needDataId) +{ + LoadAndDemuxSegment(trackAudio, "audio/chunk-stream0-00001.m4s"); + std::cout << "loading rialtotest /tmp/data/bipbop-gen/audio/chunk-stream0-00001.m4s" << std::endl; + + size_t segmentCount = trackAudio.count(); + printf("adding %zu audio frames\n", segmentCount); + + for (size_t i = 0; i < segmentCount; ++i) + { + double pts = trackAudio.getPts(i); + double dur = trackAudio.getDuration(i); + + std::unique_ptr audioSegment = + std::make_unique( + sourceIdAudio, + (int64_t)(pts * NS_SECOND), + (int64_t)(dur * NS_SECOND)); + + size_t len = trackAudio.getLen(i); + uint8_t *data = new uint8_t[len]; + std::memcpy(data, trackAudio.getPtr(i), len); + audioSegment->setData((uint32_t)len, data); + + AddSegmentStatus status = gstMediaPipeline->addSegment(needDataId, audioSegment); + assert(status == AddSegmentStatus::OK); + } +} + +void InjectVideo(int32_t needDataId) +{ + LoadAndDemuxSegment(trackVideo, "video/chunk-stream0-00001.m4s"); + std::cout << "loading rialtotest /tmp/data/bipbop-gen/video/chunk-stream0-00001.m4s" << std::endl; + + // size_t segmentCount = trackVideo.getNbSegments(); + size_t segmentCount = trackVideo.count(); + printf("adding %zu video frames\n", segmentCount); + + for (size_t i = 0; i < segmentCount; ++i) + { + double pts = trackVideo.getPts(i); + double dur = trackVideo.getDuration(i); + + std::unique_ptr videoSegment = + std::make_unique( + sourceIdVideo, + (int64_t)(pts * NS_SECOND), + (int64_t)(dur * NS_SECOND), + trackVideo.video.width, + trackVideo.video.height); + + size_t len = trackVideo.getLen(i); + uint8_t *data = new uint8_t[len]; + std::memcpy(data, trackVideo.getPtr(i), len); + videoSegment->setData((uint32_t)len, data); + + AddSegmentStatus status = gstMediaPipeline->addSegment(needDataId, videoSegment); + assert(status == AddSegmentStatus::OK); + } +} + +int my_main(int argc, char **argv) +{ + const char *executablePath = argv[0]; + const char *prefix = "/Users/"; + size_t prefixLen = strlen(prefix); + gUserPathPtr = strstr(executablePath, prefix); + const char *delim = strchr(&gUserPathPtr[prefixLen], '/'); + gUserPathLen = (int)(delim - gUserPathPtr); + + gstMediaPipeline = std::make_shared(); + if (!gstMediaPipeline->init()) + { + fprintf(stderr, "FATAL: Failed to initialize Rialto pipeline. Check logs/server status.\n"); + return -1; + } + + + // MUST happen before any attachSource() to create a Rialto Gstreamer player + gstMediaPipeline->load(MediaType::MSE, "video/mp4", "file:///tmp/data/bipbop-gen/video/chunk-stream0-00001.m4s"); // Temp + + if (!gstMediaPipeline->setVideoWindow(0, 0, 1920, 1080)) + { + fprintf(stderr, "Warning: Failed to set video window. Video may not appear.\n"); + } + + ConfigureAudio(); + ConfigureVideo(); + ConfigureComplete(); + + gstMediaPipeline->play(); + + uint32_t audioReqId = WaitForNeedDataRequest(sourceIdAudio); + uint32_t videoReqId = WaitForNeedDataRequest(sourceIdVideo); + + if (audioReqId != UINT32_MAX) + InjectAudio(audioReqId); + + if (videoReqId != UINT32_MAX) + InjectVideo(videoReqId); + + + std::this_thread::sleep_for(std::chrono::seconds(7)); + + gstMediaPipeline->stop(); + + return 0; +} + +int main(int argc, char **argv) +{ +#if defined(__APPLE__) && defined(__GST_MACOS_H__) + return gst_macos_main((GstMainFunc)my_main, argc, argv, nullptr); +#else + return my_main(argc, argv); +#endif +} \ No newline at end of file diff --git a/test/gstTestHarness/rialto-gst-pipeline.cpp b/test/gstTestHarness/rialto-gst-pipeline.cpp new file mode 100644 index 000000000..99fbe3f24 --- /dev/null +++ b/test/gstTestHarness/rialto-gst-pipeline.cpp @@ -0,0 +1,133 @@ +#include "rialto-gst-pipeline.h" +#include +#include +#include +#include +#include +#include +#include + +std::mutex g_needDataMutex; +std::condition_variable g_needDataCv; +std::queue g_needDataQueue; + +using namespace firebolt::rialto; + +GstMediaPipeline::GstMediaPipeline() +{ + std::cout << "Constructing GstMediaPipeline (Rialto-managed, public API)\n"; +} + +GstMediaPipeline::~GstMediaPipeline() +{ + if (m_pipeline) + { + m_pipeline->stop(); + } +} + +bool GstMediaPipeline::init() +{ + // FIX: Calling createFactory() on IMediaPipelineFactory class, as it's not a member of IMediaPipeline. + std::shared_ptr factory = IMediaPipelineFactory::createFactory(); + if (!factory) return false; + + constexpr std::uint32_t kWidth{3840}; + constexpr std::uint32_t kHeight{2160}; + + VideoRequirements kRequirements{kWidth, kHeight}; + + m_pipeline = factory->createMediaPipeline(weak_from_this(), kRequirements); + + return m_pipeline != nullptr; +} + +bool GstMediaPipeline::attachSource(const std::unique_ptr &source) +{ + return m_pipeline ? m_pipeline->attachSource(source) : false; +} + +bool GstMediaPipeline::attachSource(std::unique_ptr &&source, int32_t &sourceId) +{ + if (!source) + { + sourceId = 0; + return false; + } + + bool ok = attachSource(std::move(source)); + + if (ok) + { + sourceId = source->getId(); + } + else + { + sourceId = 0; + } + + return ok; +} + +bool GstMediaPipeline::play() { return m_pipeline ? m_pipeline->play() : false; } +bool GstMediaPipeline::stop() { return m_pipeline ? m_pipeline->stop() : false; } +bool GstMediaPipeline::removeSource(int32_t id) { return m_pipeline ? m_pipeline->removeSource(id) : false; } +bool GstMediaPipeline::allSourcesAttached() { return m_pipeline ? m_pipeline->allSourcesAttached() : false; } +bool GstMediaPipeline::load(MediaType type, const std::string &mimeType, const std::string &url) { return m_pipeline ? m_pipeline->load(type, mimeType, url) : false; } +AddSegmentStatus GstMediaPipeline::addSegment(uint32_t needDataRequestId, const std::unique_ptr &mediaSegment) { return m_pipeline ? m_pipeline->addSegment(needDataRequestId, mediaSegment) : AddSegmentStatus::ERROR; } +bool GstMediaPipeline::pause() { return m_pipeline ? m_pipeline->pause() : false; } +bool GstMediaPipeline::setPlaybackRate(double rate) { return m_pipeline ? m_pipeline->setPlaybackRate(rate) : false; } +bool GstMediaPipeline::setPosition(int64_t position) { return m_pipeline ? m_pipeline->setPosition(position) : false; } +bool GstMediaPipeline::getPosition(int64_t &position) { return m_pipeline ? m_pipeline->getPosition(position) : false; } +bool GstMediaPipeline::getStats(int32_t sourceId, uint64_t &renderedFrames, uint64_t &droppedFrames) { return m_pipeline ? m_pipeline->getStats(sourceId, renderedFrames, droppedFrames) : false; } +bool GstMediaPipeline::setImmediateOutput(int32_t sourceId, bool immediateOutput) { return m_pipeline ? m_pipeline->setImmediateOutput(sourceId, immediateOutput) : false; } +bool GstMediaPipeline::getImmediateOutput(int32_t sourceId, bool &immediateOutput) { return m_pipeline ? m_pipeline->getImmediateOutput(sourceId, immediateOutput) : false; } +bool GstMediaPipeline::setVideoWindow(uint32_t x, uint32_t y, uint32_t width, uint32_t height) { return m_pipeline ? m_pipeline->setVideoWindow(x, y, width, height) : false; } +bool GstMediaPipeline::haveData(MediaSourceStatus status, uint32_t needDataRequestId) { return m_pipeline ? m_pipeline->haveData(status, needDataRequestId) : false; } +bool GstMediaPipeline::renderFrame() { return m_pipeline ? m_pipeline->renderFrame() : false; } +bool GstMediaPipeline::setVolume(double targetVolume, uint32_t volumeDuration, EaseType easeType) { return m_pipeline ? m_pipeline->setVolume(targetVolume, volumeDuration, easeType) : false; } +bool GstMediaPipeline::getTextTrackIdentifier(std::string &textTrackIdentifier) { return m_pipeline ? m_pipeline->getTextTrackIdentifier(textTrackIdentifier) : false; } +bool GstMediaPipeline::setLowLatency(bool lowLatency) { return m_pipeline ? m_pipeline->setLowLatency(lowLatency) : false; } +bool GstMediaPipeline::setSync(bool sync) { return m_pipeline ? m_pipeline->setSync(sync) : false; } +bool GstMediaPipeline::getSync(bool &sync) { return m_pipeline ? m_pipeline->getSync(sync) : false; } +bool GstMediaPipeline::setSyncOff(bool syncOff) { return m_pipeline ? m_pipeline->setSyncOff(syncOff) : false; } +bool GstMediaPipeline::setStreamSyncMode(int32_t sourceId, int32_t streamSyncMode) { return m_pipeline ? m_pipeline->setStreamSyncMode(sourceId, streamSyncMode) : false; } +bool GstMediaPipeline::getStreamSyncMode(int32_t &streamSyncMode) { return m_pipeline ? m_pipeline->getStreamSyncMode(streamSyncMode) : false; } +bool GstMediaPipeline::flush(int32_t sourceId, bool resetTime, bool &async) { return m_pipeline ? m_pipeline->flush(sourceId, resetTime, async) : false; } +bool GstMediaPipeline::setSourcePosition(int32_t sourceId, int64_t position, bool resetTime, double appliedRate, uint64_t stopPosition) { return m_pipeline ? m_pipeline->setSourcePosition(sourceId, position, resetTime, appliedRate, stopPosition) : false; } +bool GstMediaPipeline::setSubtitleOffset(int32_t sourceId, int64_t position) { return m_pipeline ? m_pipeline->setSubtitleOffset(sourceId, position) : false; } +bool GstMediaPipeline::processAudioGap(int64_t position, uint32_t duration, int64_t discontinuityGap, bool audioAac) { return m_pipeline ? m_pipeline->processAudioGap(position, duration, discontinuityGap, audioAac) : false; } +bool GstMediaPipeline::setBufferingLimit(uint32_t limitBufferingMs) { return m_pipeline ? m_pipeline->setBufferingLimit(limitBufferingMs) : false; } +bool GstMediaPipeline::getBufferingLimit(uint32_t &limitBufferingMs) { return m_pipeline ? m_pipeline->getBufferingLimit(limitBufferingMs) : false; } +bool GstMediaPipeline::setUseBuffering(bool useBuffering) { return m_pipeline ? m_pipeline->setUseBuffering(useBuffering) : false; } +bool GstMediaPipeline::getUseBuffering(bool &useBuffering) { return m_pipeline ? m_pipeline->getUseBuffering(useBuffering) : false; } +bool GstMediaPipeline::switchSource(const std::unique_ptr &source) { return m_pipeline ? m_pipeline->switchSource(source->copy()) : false; } +bool GstMediaPipeline::getVolume(double ¤tVolume) { return m_pipeline ? m_pipeline->getVolume(currentVolume) : false; } +bool GstMediaPipeline::setMute(int32_t sourceId, bool mute) { return m_pipeline ? m_pipeline->setMute(sourceId, mute) : false; } +bool GstMediaPipeline::getMute(int32_t sourceId, bool &mute) { return m_pipeline ? m_pipeline->getMute(sourceId, mute) : false; } +bool GstMediaPipeline::setTextTrackIdentifier(const std::string &textTrackIdentifier) { return m_pipeline ? m_pipeline->setTextTrackIdentifier(textTrackIdentifier) : false; } + +// --- IMediaPipelineClient stubs --- + +void GstMediaPipeline::notifyPlaybackState(PlaybackState state) { } +void GstMediaPipeline::notifyPlaybackError(int32_t sourceId, PlaybackError error) { } +void GstMediaPipeline::notifyPosition(int64_t position) {} +void GstMediaPipeline::notifyNetworkState(NetworkState state) {} +void GstMediaPipeline::notifyQos(int32_t sourceId, const QosInfo &qosInfo) {} +void GstMediaPipeline::notifyBufferUnderflow(int32_t sourceId) {} +void GstMediaPipeline::notifySourceFlushed(int32_t sourceId) {} + +void GstMediaPipeline::notifyNeedMediaData(int32_t sourceId, size_t frameCount, + uint32_t needDataRequestId, + const std::shared_ptr &mediaPlayerShmInfo) +{ + std::lock_guard lock(g_needDataMutex); + g_needDataQueue.push({sourceId, needDataRequestId}); + g_needDataCv.notify_one(); +} + +void GstMediaPipeline::notifyDuration(int64_t duration) {} +void GstMediaPipeline::notifyNativeSize(uint32_t width, uint32_t height, double aspect) {} +void GstMediaPipeline::notifyVideoData(bool hasData) {} +void GstMediaPipeline::notifyAudioData(bool hasData) {} +void GstMediaPipeline::notifyCancelNeedMediaData(int32_t sourceId) {} \ No newline at end of file diff --git a/test/gstTestHarness/rialto-gst-pipeline.h b/test/gstTestHarness/rialto-gst-pipeline.h new file mode 100644 index 000000000..0a65320a0 --- /dev/null +++ b/test/gstTestHarness/rialto-gst-pipeline.h @@ -0,0 +1,103 @@ +#ifndef GST_MEDIA_PIPELINE_H +#define GST_MEDIA_PIPELINE_H + +#include "IMediaPipeline.h" +#include +#include +#include + +#include +#include +#include + +struct NeedDataRequestEvent +{ + int32_t sourceId; + uint32_t requestId; +}; + +extern std::mutex g_needDataMutex; +extern std::condition_variable g_needDataCv; +extern std::queue g_needDataQueue; + +using namespace firebolt::rialto; + +class GstMediaPipeline : public IMediaPipeline, + public IMediaPipelineClient, + public std::enable_shared_from_this +{ +private: + std::shared_ptr m_pipeline; + +public: + GstMediaPipeline(); + ~GstMediaPipeline() override; + + bool init(); + + std::weak_ptr getClient() override { return weak_from_this(); } + + // IMediaPipelineClient Implementation (All required pure virtuals) + void notifyNetworkState(NetworkState state) override; + void notifyPlaybackState(PlaybackState state) override; + void notifyPosition(int64_t position) override; + void notifyNeedMediaData(int32_t sourceId, size_t frameCount, + uint32_t needDataRequestId, + const std::shared_ptr &mediaPlayerShmInfo) override; + void notifyQos(int32_t sourceId, const QosInfo &qosInfo) override; + void notifyBufferUnderflow(int32_t sourceId) override; + void notifyPlaybackError(int32_t sourceId, PlaybackError error) override; + void notifySourceFlushed(int32_t sourceId) override; + void notifyDuration(int64_t duration) override; + void notifyNativeSize(uint32_t width, uint32_t height, double aspect = 1.0) override; + void notifyVideoData(bool hasData) override; + void notifyAudioData(bool hasData) override; + void notifyCancelNeedMediaData(int32_t sourceId) override; + + // IMediaPipeline Implementation + + + bool attachSource(const std::unique_ptr &source) override; + bool attachSource(std::unique_ptr &&source, int32_t &sourceId); + + bool removeSource(int32_t id) override; + bool allSourcesAttached() override; + bool load(MediaType type, const std::string &mimeType, const std::string &url) override; + AddSegmentStatus addSegment(uint32_t needDataRequestId, const std::unique_ptr &mediaSegment) override; + + bool play() override; + bool stop() override; + bool setVideoWindow(uint32_t x, uint32_t y, uint32_t width, uint32_t height) override; + bool pause() override; + bool setPlaybackRate(double) override; + bool setPosition(int64_t) override; + bool getPosition(int64_t &p) override; + bool getStats(int32_t, uint64_t &r, uint64_t &d) override; + bool setImmediateOutput(int32_t, bool) override; + bool getImmediateOutput(int32_t, bool &) override; + bool haveData(MediaSourceStatus, uint32_t) override; + bool renderFrame() override; + bool setVolume(double, uint32_t, EaseType) override; + bool getTextTrackIdentifier(std::string &) override; + bool setLowLatency(bool) override; + bool setSync(bool) override; + bool getSync(bool &) override; + bool setSyncOff(bool) override; + bool setStreamSyncMode(int32_t, int32_t) override; + bool getStreamSyncMode(int32_t &) override; + bool flush(int32_t, bool, bool &) override; + bool setSourcePosition(int32_t, int64_t, bool, double, uint64_t) override; + bool setSubtitleOffset(int32_t, int64_t) override; + bool processAudioGap(int64_t, uint32_t, int64_t, bool) override; + bool setBufferingLimit(uint32_t) override; + bool getBufferingLimit(uint32_t &) override; + bool setUseBuffering(bool) override; + bool getUseBuffering(bool &) override; + bool switchSource(const std::unique_ptr &) override; + bool getVolume(double &) override; + bool setMute(int32_t, bool) override; + bool getMute(int32_t, bool &) override; + bool setTextTrackIdentifier(const std::string &) override; +}; + +#endif \ No newline at end of file