Skip to content

Commit

Permalink
Reattach source method unified for two tasks (#351)
Browse files Browse the repository at this point in the history
Summary: Reattach source method unified for two tasks
Type: Feature
Test Plan: UT/ CT, Fullstack
Jira: RIALTO-635
  • Loading branch information
skywojciechowskim authored Nov 28, 2024
1 parent 3adb8c7 commit 3c62692
Show file tree
Hide file tree
Showing 29 changed files with 421 additions and 916 deletions.
18 changes: 18 additions & 0 deletions media/server/gstplayer/include/GstGenericPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ class GstGenericPlayer : public IGstGenericPlayer, public IGstGenericPlayerPriva
const VideoRequirements &videoRequirements,
const std::shared_ptr<firebolt::rialto::wrappers::IGstWrapper> &gstWrapper,
const std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapper> &glibWrapper,
const std::shared_ptr<firebolt::rialto::wrappers::IRdkGstreamerUtilsWrapper> &rdkGstreamerUtilsWrapper,
const std::shared_ptr<IGstSrcFactory> &gstSrcFactory,
std::shared_ptr<common::ITimerFactory> timerFactory,
std::unique_ptr<IGenericPlayerTaskFactory> taskFactory,
Expand Down Expand Up @@ -175,6 +176,7 @@ class GstGenericPlayer : public IGstGenericPlayer, public IGstGenericPlayerPriva
void removeAutoAudioSinkChild(GObject *object) override;
void setPlaybinFlags(bool enableAudio = true) override;
void pushSampleIfRequired(GstElement *source, const std::string &typeStr) override;
bool reattachSource(const std::unique_ptr<IMediaPipeline::MediaSource> &source) override;
GstElement *getSink(const MediaSourceType &mediaSourceType) const override;

private:
Expand Down Expand Up @@ -294,6 +296,17 @@ class GstGenericPlayer : public IGstGenericPlayer, public IGstGenericPlayerPriva
*/
GstElement *getParser(const MediaSourceType &mediaSourceType);

/**
* @brief Constructs new Audio Attributes structure based on MediaSource
* Called by worker thread only!
*
* @param[in] source : the media source, which contains params needed by Audio Attributes struct
*
* @retval The Audio Attributes structure on success, std::nullopt on failure
*/
std::optional<firebolt::rialto::wrappers::AudioAttributesPrivate>
createAudioAttributes(const std::unique_ptr<IMediaPipeline::MediaSource> &source) const;

private:
/**
* @brief The player context.
Expand All @@ -315,6 +328,11 @@ class GstGenericPlayer : public IGstGenericPlayer, public IGstGenericPlayerPriva
*/
std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapper> m_glibWrapper;

/**
* @brief The rdk gstreamer utils wrapper object
*/
std::shared_ptr<firebolt::rialto::wrappers::IRdkGstreamerUtilsWrapper> m_rdkGstreamerUtilsWrapper;

/**
* @brief Thread for handling player tasks.
*/
Expand Down
9 changes: 9 additions & 0 deletions media/server/gstplayer/include/IGstGenericPlayerPrivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,15 @@ class IGstGenericPlayerPrivate
* @param[in] typeStr : The media source type string
*/
virtual void pushSampleIfRequired(GstElement *source, const std::string &typeStr) = 0;

/**
* @brief Reattaches source (or switches it)
*
* @param[in] source : The new media source
*
* @retval True on success
*/
virtual bool reattachSource(const std::unique_ptr<IMediaPipeline::MediaSource> &source) = 0;
};
} // namespace firebolt::rialto::server

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -508,13 +508,13 @@ class IGenericPlayerTaskFactory
/**
* @brief Creates a SwitchSource task.
*
* @param[in] context : The GstGenericPlayer context
* @param[in] player : The GstGenericPlayer instance
* @param[in] source : The source to switch.
*
* @retval the new SwitchSource task instance.
*/
virtual std::unique_ptr<IPlayerTask>
createSwitchSource(GenericPlayerContext &context,
createSwitchSource(IGstGenericPlayerPrivate &player,
const std::unique_ptr<IMediaPipeline::MediaSource> &source) const = 0;
};

Expand Down
7 changes: 2 additions & 5 deletions media/server/gstplayer/include/tasks/generic/AttachSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,18 @@ class AttachSource : public IPlayerTask
AttachSource(GenericPlayerContext &context,
const std::shared_ptr<firebolt::rialto::wrappers::IGstWrapper> &gstWrapper,
const std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapper> &glibWrapper,
const std::shared_ptr<firebolt::rialto::wrappers::IRdkGstreamerUtilsWrapper> &rdkGstreamerUtilsWrapper,
const std::shared_ptr<IGstTextTrackSinkFactory> &gstTextTrackSinkFactory,
IGstGenericPlayerPrivate &player, const std::unique_ptr<IMediaPipeline::MediaSource> &source);
~AttachSource() override;
void execute() const override;

private:
void addSource(GstCaps *caps, bool isDrm) const;
void reattachAudioSource(GstCaps *caps, const std::string &strCaps) const;
std::optional<firebolt::rialto::wrappers::AudioAttributesPrivate> createAudioAttributes() const;
void addSource() const;
void reattachAudioSource() const;

GenericPlayerContext &m_context;
std::shared_ptr<firebolt::rialto::wrappers::IGstWrapper> m_gstWrapper;
std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapper> m_glibWrapper;
std::shared_ptr<firebolt::rialto::wrappers::IRdkGstreamerUtilsWrapper> m_rdkGstreamerUtilsWrapper;
std::shared_ptr<IGstTextTrackSinkFactory> m_gstTextTrackSinkFactory;
IGstGenericPlayerPrivate &m_player;
std::unique_ptr<IMediaPipeline::MediaSource> m_attachedSource;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ class GenericPlayerTaskFactory : public IGenericPlayerTaskFactory
std::unique_ptr<IPlayerTask> createSetUseBuffering(GenericPlayerContext &context, IGstGenericPlayerPrivate &player,
bool useBuffering) const override;
std::unique_ptr<IPlayerTask>
createSwitchSource(GenericPlayerContext &context,
createSwitchSource(IGstGenericPlayerPrivate &player,
const std::unique_ptr<IMediaPipeline::MediaSource> &source) const override;

private:
Expand Down
15 changes: 3 additions & 12 deletions media/server/gstplayer/include/tasks/generic/SwitchSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include "GenericPlayerContext.h"
#include "IGlibWrapper.h"
#include "IGstGenericPlayerPrivate.h"
#include "IGstWrapper.h"
#include "IMediaPipeline.h"
#include "IPlayerTask.h"
Expand All @@ -35,22 +36,12 @@ namespace firebolt::rialto::server::tasks::generic
class SwitchSource : public IPlayerTask
{
public:
SwitchSource(GenericPlayerContext &context,
const std::shared_ptr<firebolt::rialto::wrappers::IGstWrapper> &gstWrapper,
const std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapper> &glibWrapper,
const std::shared_ptr<firebolt::rialto::wrappers::IRdkGstreamerUtilsWrapper> rdkGstreamerUtilsWrapper,
const std::unique_ptr<IMediaPipeline::MediaSource> &source);
SwitchSource(IGstGenericPlayerPrivate &player, const std::unique_ptr<IMediaPipeline::MediaSource> &source);
~SwitchSource() override;
void execute() const override;

private:
std::optional<firebolt::rialto::wrappers::AudioAttributesPrivate> createAudioAttributes() const;

private:
GenericPlayerContext &m_context;
std::shared_ptr<firebolt::rialto::wrappers::IGstWrapper> m_gstWrapper;
std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapper> m_glibWrapper;
std::shared_ptr<firebolt::rialto::wrappers::IRdkGstreamerUtilsWrapper> m_rdkGstreamerUtilsWrapper;
IGstGenericPlayerPrivate &m_player;
std::unique_ptr<IMediaPipeline::MediaSource> m_source;
};
} // namespace firebolt::rialto::server::tasks::generic
Expand Down
137 changes: 123 additions & 14 deletions media/server/gstplayer/source/GstGenericPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "ITimer.h"
#include "RialtoServerLogging.h"
#include "TypeConverters.h"
#include "Utils.h"
#include "WorkerThread.h"
#include "tasks/generic/GenericPlayerTaskFactory.h"

Expand Down Expand Up @@ -96,7 +97,7 @@ std::unique_ptr<IGstGenericPlayer> GstGenericPlayerFactory::createGstGenericPlay
}
gstPlayer = std::make_unique<
GstGenericPlayer>(client, decryptionService, type, videoRequirements, gstWrapper, glibWrapper,
IGstSrcFactory::getFactory(), common::ITimerFactory::getFactory(),
rdkGstreamerUtilsWrapper, IGstSrcFactory::getFactory(), common::ITimerFactory::getFactory(),
std::make_unique<GenericPlayerTaskFactory>(client, gstWrapper, glibWrapper,
rdkGstreamerUtilsWrapper,
IGstTextTrackSinkFactory::createFactory()),
Expand All @@ -111,18 +112,19 @@ std::unique_ptr<IGstGenericPlayer> GstGenericPlayerFactory::createGstGenericPlay
return gstPlayer;
}

GstGenericPlayer::GstGenericPlayer(IGstGenericPlayerClient *client, IDecryptionService &decryptionService,
MediaType type, const VideoRequirements &videoRequirements,
const std::shared_ptr<firebolt::rialto::wrappers::IGstWrapper> &gstWrapper,
const std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapper> &glibWrapper,
const std::shared_ptr<IGstSrcFactory> &gstSrcFactory,
std::shared_ptr<common::ITimerFactory> timerFactory,
std::unique_ptr<IGenericPlayerTaskFactory> taskFactory,
std::unique_ptr<IWorkerThreadFactory> workerThreadFactory,
std::unique_ptr<IGstDispatcherThreadFactory> gstDispatcherThreadFactory,
std::shared_ptr<IGstProtectionMetadataHelperFactory> gstProtectionMetadataFactory)
: m_gstPlayerClient(client), m_gstWrapper{gstWrapper}, m_glibWrapper{glibWrapper}, m_timerFactory{timerFactory},
m_taskFactory{std::move(taskFactory)}
GstGenericPlayer::GstGenericPlayer(
IGstGenericPlayerClient *client, IDecryptionService &decryptionService, MediaType type,
const VideoRequirements &videoRequirements,
const std::shared_ptr<firebolt::rialto::wrappers::IGstWrapper> &gstWrapper,
const std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapper> &glibWrapper,
const std::shared_ptr<firebolt::rialto::wrappers::IRdkGstreamerUtilsWrapper> &rdkGstreamerUtilsWrapper,
const std::shared_ptr<IGstSrcFactory> &gstSrcFactory, std::shared_ptr<common::ITimerFactory> timerFactory,
std::unique_ptr<IGenericPlayerTaskFactory> taskFactory, std::unique_ptr<IWorkerThreadFactory> workerThreadFactory,
std::unique_ptr<IGstDispatcherThreadFactory> gstDispatcherThreadFactory,
std::shared_ptr<IGstProtectionMetadataHelperFactory> gstProtectionMetadataFactory)
: m_gstPlayerClient(client), m_gstWrapper{gstWrapper}, m_glibWrapper{glibWrapper},
m_rdkGstreamerUtilsWrapper{rdkGstreamerUtilsWrapper}, m_timerFactory{timerFactory}, m_taskFactory{
std::move(taskFactory)}
{
RIALTO_SERVER_LOG_DEBUG("GstGenericPlayer is constructed.");

Expand Down Expand Up @@ -554,6 +556,45 @@ GstElement *GstGenericPlayer::getParser(const MediaSourceType &mediaSourceType)
return nullptr;
}

std::optional<firebolt::rialto::wrappers::AudioAttributesPrivate>
GstGenericPlayer::createAudioAttributes(const std::unique_ptr<IMediaPipeline::MediaSource> &source) const
{
std::optional<firebolt::rialto::wrappers::AudioAttributesPrivate> audioAttributes;
const IMediaPipeline::MediaSourceAudio *kSource = dynamic_cast<IMediaPipeline::MediaSourceAudio *>(source.get());
if (kSource)
{
firebolt::rialto::AudioConfig audioConfig = kSource->getAudioConfig();
audioAttributes =
firebolt::rialto::wrappers::AudioAttributesPrivate{"", // param set below.
audioConfig.numberOfChannels, audioConfig.sampleRate,
0, // used only in one of logs in rdk_gstreamer_utils, no
// need to set this param.
0, // used only in one of logs in rdk_gstreamer_utils, no
// need to set this param.
audioConfig.codecSpecificConfig.data(),
static_cast<std::uint32_t>(
audioConfig.codecSpecificConfig.size())};
if (source->getMimeType() == "audio/mp4" || source->getMimeType() == "audio/aac")
{
audioAttributes->m_codecParam = "mp4a";
}
else if (source->getMimeType() == "audio/x-eac3")
{
audioAttributes->m_codecParam = "ec-3";
}
else if (source->getMimeType() == "audio/b-wav" || source->getMimeType() == "audio/x-raw")
{
audioAttributes->m_codecParam = "lpcm";
}
}
else
{
RIALTO_SERVER_LOG_ERROR("Failed to cast source");
}

return audioAttributes;
}

bool GstGenericPlayer::setImmediateOutput(const MediaSourceType &mediaSourceType, bool immediateOutputParam)
{
if (!m_workerThread)
Expand Down Expand Up @@ -909,6 +950,74 @@ void GstGenericPlayer::pushSampleIfRequired(GstElement *source, const std::strin
return;
}

bool GstGenericPlayer::reattachSource(const std::unique_ptr<IMediaPipeline::MediaSource> &source)
{
if (m_context.streamInfo.find(source->getType()) == m_context.streamInfo.end())
{
RIALTO_SERVER_LOG_ERROR("Unable to switch source, type does not exist");
return false;
}
if (source->getMimeType().empty())
{
RIALTO_SERVER_LOG_WARN("Skip switch audio source. Unknown mime type");
return false;
}
std::optional<firebolt::rialto::wrappers::AudioAttributesPrivate> audioAttributes{createAudioAttributes(source)};
if (!audioAttributes)
{
RIALTO_SERVER_LOG_ERROR("Failed to create audio attributes");
return false;
}
std::int64_t currentDispPts64b; // In netflix code it's currentDisplayPosition + offset
m_gstWrapper->gstElementQueryPosition(m_context.pipeline, GST_FORMAT_TIME, &currentDispPts64b);
long long currentDispPts = currentDispPts64b; // NOLINT(runtime/int)
GstCaps *caps{createCapsFromMediaSource(m_gstWrapper, m_glibWrapper, source)};
GstAppSrc *appSrc{GST_APP_SRC(m_context.streamInfo[source->getType()].appSrc)};
GstCaps *oldCaps = m_gstWrapper->gstAppSrcGetCaps(appSrc);
if ((!oldCaps) || (!m_gstWrapper->gstCapsIsEqual(caps, oldCaps)))
{
RIALTO_SERVER_LOG_DEBUG("Caps not equal. Perform audio track codec channel switch.");
int sampleAttributes{
0}; // rdk_gstreamer_utils::performAudioTrackCodecChannelSwitch checks if this param != NULL only.
std::uint32_t status{0}; // must be 0 to make rdk_gstreamer_utils::performAudioTrackCodecChannelSwitch work
unsigned int ui32Delay{0}; // output param
long long audioChangeTargetPts{-1}; // NOLINT(runtime/int) output param. Set audioChangeTargetPts =
// currentDispPts in rdk_gstreamer_utils function stub
unsigned int audioChangeStage{0}; // Output param. Set to AUDCHG_ALIGN in rdk_gstreamer_utils function stub
gchar *oldCapsCStr = m_gstWrapper->gstCapsToString(oldCaps);
std::string oldCapsStr = std::string(oldCapsCStr);
m_glibWrapper->gFree(oldCapsCStr);
bool audioAac{oldCapsStr.find("audio/mpeg") != std::string::npos};
bool svpEnabled{true}; // assume always true
bool retVal{false}; // Output param. Set to TRUE in rdk_gstreamer_utils function stub
bool result =
m_rdkGstreamerUtilsWrapper
->performAudioTrackCodecChannelSwitch(&m_context.playbackGroup, &sampleAttributes, &(*audioAttributes),
&status, &ui32Delay, &audioChangeTargetPts, &currentDispPts,
&audioChangeStage,
&caps, // may fail for amlogic - that implementation changes
// this parameter, it's probably used by Netflix later
&audioAac, svpEnabled, GST_ELEMENT(appSrc), &retVal);

if (!result || !retVal)
{
RIALTO_SERVER_LOG_WARN("performAudioTrackCodecChannelSwitch failed! Result: %d, retval %d", result, retVal);
}
}
else
{
RIALTO_SERVER_LOG_DEBUG("Skip switching audio source - caps are the same.");
}

m_context.lastAudioSampleTimestamps = currentDispPts;
if (caps)
m_gstWrapper->gstCapsUnref(caps);
if (oldCaps)
m_gstWrapper->gstCapsUnref(oldCaps);

return true;
}

void GstGenericPlayer::scheduleNeedMediaData(GstAppSrc *src)
{
if (m_workerThread)
Expand Down Expand Up @@ -1790,7 +1899,7 @@ void GstGenericPlayer::switchSource(const std::unique_ptr<IMediaPipeline::MediaS
{
if (m_workerThread)
{
m_workerThread->enqueueTask(m_taskFactory->createSwitchSource(m_context, mediaSource));
m_workerThread->enqueueTask(m_taskFactory->createSwitchSource(*this, mediaSource));
}
}

Expand Down
Loading

0 comments on commit 3c62692

Please sign in to comment.