Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 36 additions & 10 deletions middleware/InterfacePlayerRDK.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1393,6 +1393,18 @@ void InterfacePlayerRDK::TearDownStream(int type)
else if (mediaType == eGST_MEDIATYPE_SUBTITLE)
{
g_clear_object(&interfacePlayerPriv->gstPrivateContext->subtitle_sink);
pthread_mutex_lock(&stream->sourceLock);
if (stream->sinkbin)
{
MW_LOG_WARN("InterfacePlayerRDK::TearDownStream: CC sinkbin still assigned, clearing");
g_clear_object(&stream->sinkbin);
}
if (stream->source)
{
MW_LOG_WARN("InterfacePlayerRDK::TearDownStream: CC source still assigned, clearing");
g_clear_object(&stream->source);
}
pthread_mutex_unlock(&stream->sourceLock);
}
tearDownCb(false, mediaType);
MW_LOG_MIL("InterfacePlayerRDK::TearDownStream: exit mediaType = %d", mediaType);
Expand Down Expand Up @@ -2274,7 +2286,7 @@ int InterfacePlayerRDK::SetupStream(int streamId, void *playerInstance, std::st
gst_element_add_pad(subtitlebin, gst_ghost_pad_new("sink", gst_element_get_static_pad(vipertransform, "sink")));

g_object_set(stream->sinkbin, "text-sink", subtitlebin, NULL);
interfacePlayerPriv->gstPrivateContext->subtitle_sink = textsink;
interfacePlayerPriv->gstPrivateContext->subtitle_sink = GST_ELEMENT(gst_object_ref(textsink));
MW_LOG_MIL("using rialtomsesubtitlesink muted=%d sink=%p", interfacePlayerPriv->gstPrivateContext->subtitleMuted, interfacePlayerPriv->gstPrivateContext->subtitle_sink);
g_object_set(textsink, "mute", interfacePlayerPriv->gstPrivateContext->subtitleMuted ? TRUE : FALSE, NULL);
}
Expand Down Expand Up @@ -2343,7 +2355,7 @@ int InterfacePlayerRDK::SetupStream(int streamId, void *playerInstance, std::st
MW_LOG_INFO("setting has-drm=false for clear HLS/TS playback");
g_object_set(vidsink, "has-drm", FALSE, NULL);
}
interfacePlayerPriv->gstPrivateContext->video_sink = vidsink;
interfacePlayerPriv->gstPrivateContext->video_sink = GST_ELEMENT(gst_object_ref(vidsink));

// RDKEMW-18286: Set show-video-window=FALSE at sink creation time.
// This is the earliest possible point. The Rialto delegate will queue
Expand Down Expand Up @@ -2374,7 +2386,7 @@ int InterfacePlayerRDK::SetupStream(int streamId, void *playerInstance, std::st
{
MW_LOG_INFO("Created rialtomseaudiosink : %s",GST_ELEMENT_NAME(audSink));
g_object_set(stream->sinkbin, "audio-sink", audSink, NULL);
interfacePlayerPriv->gstPrivateContext->audio_sink = audSink;
interfacePlayerPriv->gstPrivateContext->audio_sink = GST_ELEMENT(gst_object_ref(audSink));
}
else
{
Expand Down Expand Up @@ -3235,16 +3247,30 @@ void InterfacePlayerPriv::SendNewSegmentEvent(int type, GstClockTime startPts ,G
if (gstPrivateContext->usingRialtoSink)
{
GstCaps *currentCaps = gst_app_src_get_caps(GST_APP_SRC(stream->source));
GstSample *sample = gst_sample_new (nullptr, currentCaps, &segment, nullptr);

MW_LOG_INFO("Pushing sample with segment for mediaType[%d]. start %" G_GUINT64_FORMAT " stop %" G_GUINT64_FORMAT" rate %f applied_rate %f", mediaType, segment.start, segment.stop, segment.rate, segment.applied_rate);
if (GST_FLOW_OK != gst_app_src_push_sample(GST_APP_SRC(stream->source), sample))
if (currentCaps != NULL)
{
MW_LOG_ERR("Failed to push sample with segment for mediaType[%d]", mediaType);
GstSample *sample = gst_sample_new (nullptr, currentCaps, &segment, nullptr);
if (sample != NULL)
{
MW_LOG_INFO("Pushing sample with segment for mediaType[%d]. start %" G_GUINT64_FORMAT " stop %" G_GUINT64_FORMAT" rate %f applied_rate %f", mediaType, segment.start, segment.stop, segment.rate, segment.applied_rate);
if (GST_FLOW_OK != gst_app_src_push_sample(GST_APP_SRC(stream->source), sample))
{
MW_LOG_ERR("Failed to push sample with segment for mediaType[%d]", mediaType);
}
gst_sample_unref(sample);
}
else
{
MW_LOG_ERR("Failed to create sample for mediaType[%d]", mediaType);
}
gst_caps_unref(currentCaps);
}
else
{
MW_LOG_WARN("Cannot push segment for mediaType[%d] - caps not yet set on appsrc", mediaType);
}
gst_sample_unref(sample);
gst_caps_unref(currentCaps);
}

else
{
MW_LOG_INFO("Sending segment event for mediaType[%d]. start %" G_GUINT64_FORMAT " stop %" G_GUINT64_FORMAT" rate %f applied_rate %f", mediaType, segment.start, segment.stop, segment.rate, segment.applied_rate);
Expand Down
12 changes: 12 additions & 0 deletions middleware/test/utests/fakes/FakeGStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1010,18 +1010,30 @@ GstPad * gst_ghost_pad_new (const gchar * name, GstPad * target)
GstCaps *gst_app_src_get_caps(GstAppSrc *appsrc)
{
TRACE_FUNC();
if (g_mockGStreamer != nullptr)
{
return g_mockGStreamer->gst_app_src_get_caps(appsrc);
}
return NULL;
}

GstSample *gst_sample_new (GstBuffer * buffer, GstCaps * caps, const GstSegment * segment, GstStructure * info)
{
TRACE_FUNC();
if (g_mockGStreamer != nullptr)
{
return g_mockGStreamer->gst_sample_new(buffer, caps, segment, info);
}
return NULL;
}

GstFlowReturn gst_app_src_push_sample (GstAppSrc * appsrc, GstSample * sample)
{
TRACE_FUNC();
if (g_mockGStreamer != nullptr)
{
return g_mockGStreamer->gst_app_src_push_sample(appsrc, sample);
}
return GST_FLOW_OK;
}

Expand Down
3 changes: 3 additions & 0 deletions middleware/test/utests/mocks/MockGStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ class MockGStreamer
MOCK_METHOD(void, gst_segment_init, (GstSegment *segment, GstFormat format));
MOCK_METHOD(GstEvent *, gst_event_new_segment, (GstSegment *segment));
MOCK_METHOD(GstEvent*, gst_event_new_custom, (GstEventType type, GstStructure* structure), ());
MOCK_METHOD(GstCaps *, gst_app_src_get_caps, (GstAppSrc *appsrc));
MOCK_METHOD(GstSample *, gst_sample_new, (GstBuffer *buffer, GstCaps *caps, const GstSegment *segment, GstStructure *info));
MOCK_METHOD(GstFlowReturn, gst_app_src_push_sample, (GstAppSrc *appsrc, GstSample *sample));
MOCK_METHOD(void, gst_caps_set_simple, (GstCaps *, const char *));
MOCK_METHOD(GstBuffer*, gst_buffer_new_allocate, (GstAllocator *allocator, gsize size, GstAllocationParams *params));
MOCK_METHOD(void, gst_structure_set, (GstStructure * structure, const char * fieldname));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1915,6 +1915,81 @@ TEST_F(InterfacePlayerTests, SendNewSegmentEvent_VideoMediaType)
mInterfacePrivatePlayer->SendNewSegmentEvent(mediaType, startPts, stopPts); //failure
}

TEST_F(InterfacePlayerTests, SendNewSegmentEvent_RialtoSink_CapsNull)
{
GstMediaType mediaType = eGST_MEDIATYPE_VIDEO;
GstClockTime startPts = 1000;
GstClockTime stopPts = 2000;
mPlayerContext->stream[mediaType].format = GST_FORMAT_ISO_BMFF;
mPlayerContext->usingRialtoSink = true;

// gst_app_src_get_caps returns NULL - segment cannot be pushed
EXPECT_CALL(*g_mockGStreamer, gst_segment_init(_, GST_FORMAT_TIME))
.Times(1);
EXPECT_CALL(*g_mockGStreamer, gst_app_src_get_caps(_))
.WillOnce(Return(nullptr));

// gst_sample_new and gst_app_src_push_sample should NOT be called
EXPECT_CALL(*g_mockGStreamer, gst_sample_new(_, _, _, _))
.Times(0);
EXPECT_CALL(*g_mockGStreamer, gst_app_src_push_sample(_, _))
.Times(0);

mInterfacePrivatePlayer->SendNewSegmentEvent(mediaType, startPts, stopPts);
}

TEST_F(InterfacePlayerTests, SendNewSegmentEvent_RialtoSink_PushSampleSuccess)
{
GstMediaType mediaType = eGST_MEDIATYPE_VIDEO;
GstClockTime startPts = 1000;
GstClockTime stopPts = 2000;
mPlayerContext->stream[mediaType].format = GST_FORMAT_ISO_BMFF;
mPlayerContext->usingRialtoSink = true;

GstCaps fakeCaps = {};
GstSample fakeSample = {};

EXPECT_CALL(*g_mockGStreamer, gst_segment_init(_, GST_FORMAT_TIME))
.Times(1);
EXPECT_CALL(*g_mockGStreamer, gst_app_src_get_caps(_))
.WillOnce(Return(&fakeCaps));
EXPECT_CALL(*g_mockGStreamer, gst_sample_new(nullptr, &fakeCaps, _, nullptr))
.WillOnce(Return(&fakeSample));
EXPECT_CALL(*g_mockGStreamer, gst_app_src_push_sample(_, &fakeSample))
.WillOnce(Return(GST_FLOW_OK));
// gst_sample_unref and gst_caps_unref expand to gst_mini_object_unref
EXPECT_CALL(*g_mockGStreamer, gst_mini_object_unref(_))
.Times(2);

mInterfacePrivatePlayer->SendNewSegmentEvent(mediaType, startPts, stopPts);
}

TEST_F(InterfacePlayerTests, SendNewSegmentEvent_RialtoSink_PushSampleFailure)
{
GstMediaType mediaType = eGST_MEDIATYPE_VIDEO;
GstClockTime startPts = 1000;
GstClockTime stopPts = 2000;
mPlayerContext->stream[mediaType].format = GST_FORMAT_ISO_BMFF;
mPlayerContext->usingRialtoSink = true;

GstCaps fakeCaps = {};
GstSample fakeSample = {};

EXPECT_CALL(*g_mockGStreamer, gst_segment_init(_, GST_FORMAT_TIME))
.Times(1);
EXPECT_CALL(*g_mockGStreamer, gst_app_src_get_caps(_))
.WillOnce(Return(&fakeCaps));
EXPECT_CALL(*g_mockGStreamer, gst_sample_new(nullptr, &fakeCaps, _, nullptr))
.WillOnce(Return(&fakeSample));
EXPECT_CALL(*g_mockGStreamer, gst_app_src_push_sample(_, &fakeSample))
.WillOnce(Return(GST_FLOW_ERROR));
// gst_sample_unref and gst_caps_unref still called even on push failure
EXPECT_CALL(*g_mockGStreamer, gst_mini_object_unref(_))
.Times(2);

mInterfacePrivatePlayer->SendNewSegmentEvent(mediaType, startPts, stopPts);
}

TEST_F(InterfacePlayerTests, Queue_and_ClearProtectionEvent)
{
std::string formatType = "cenc";
Expand Down