Skip to content

Commit

Permalink
Merge r228316 - [EME][GStreamer] Add support for encrypted caps in GS…
Browse files Browse the repository at this point in the history
…treamerUtilities

https://bugs.webkit.org/show_bug.cgi?id=181990

Patch by Yacine Bandou <yacine.bandou_ext@softathome.com> on 2018-02-09
Reviewed by Xabier Rodriguez-Calvar.

Add the support of encrypted caps in GStreamerUtilities.
Refactor the manner that the caps are handled, such as how to extract the resolution
from the video caps or how to check if the caps are encrypted.

The attachTrack function in PlaybackPipeline doesn't need the "structure" parameter,
it is already included in the "caps" parameter.

Replace the "mediaType" parameter by the "caps" parameter in reattachTrack function,
it allows to use the new functions that handle the caps in GStreamerUtilities.

Tests:
    media/encrypted-media/clearKey/clearKey-cenc-audio-playback-mse.html
    media/encrypted-media/clearKey/clearKey-cenc-video-playback-mse.html

* platform/graphics/gstreamer/GStreamerUtilities.cpp:
(WebCore::getVideoSizeAndFormatFromCaps): Add the support of video encrypted caps.
(WebCore::getVideoResolutionFromCaps):
(WebCore::capsMediaType):
(WebCore::doCapsHaveType):
(WebCore::areEncryptedCaps): Add a new functions in order to handle the caps properly.
* platform/graphics/gstreamer/GStreamerUtilities.h:
* platform/graphics/gstreamer/mse/AppendPipeline.cpp:
(WebCore::AppendPipeline::parseDemuxerSrcPadCaps):
* platform/graphics/gstreamer/mse/GStreamerMediaDescription.cpp:
(WebCore::GStreamerMediaDescription::codec const):
(WebCore::GStreamerMediaDescription::isVideo const):
(WebCore::GStreamerMediaDescription::isAudio const):
* platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp:
(WebCore::MediaPlayerPrivateGStreamerMSE::trackDetected):
* platform/graphics/gstreamer/mse/PlaybackPipeline.cpp:
(WebCore::PlaybackPipeline::attachTrack):
(WebCore::PlaybackPipeline::reattachTrack):
* platform/graphics/gstreamer/mse/PlaybackPipeline.h:
* platform/graphics/gstreamer/mse/WebKitMediaSourceGStreamer.cpp:
(webKitMediaSrcUpdatePresentationSize): Refactor some parts by using the new added functions.
  • Loading branch information
Yacine Bandou authored and carlosgcampos committed Feb 19, 2018
1 parent 0e285df commit 54c5b38
Show file tree
Hide file tree
Showing 10 changed files with 241 additions and 124 deletions.
43 changes: 43 additions & 0 deletions Source/WebCore/ChangeLog
@@ -1,3 +1,46 @@
2018-02-09 Yacine Bandou <yacine.bandou_ext@softathome.com>

[EME][GStreamer] Add support for encrypted caps in GStreamerUtilities
https://bugs.webkit.org/show_bug.cgi?id=181990

Reviewed by Xabier Rodriguez-Calvar.

Add the support of encrypted caps in GStreamerUtilities.
Refactor the manner that the caps are handled, such as how to extract the resolution
from the video caps or how to check if the caps are encrypted.

The attachTrack function in PlaybackPipeline doesn't need the "structure" parameter,
it is already included in the "caps" parameter.

Replace the "mediaType" parameter by the "caps" parameter in reattachTrack function,
it allows to use the new functions that handle the caps in GStreamerUtilities.

Tests:
media/encrypted-media/clearKey/clearKey-cenc-audio-playback-mse.html
media/encrypted-media/clearKey/clearKey-cenc-video-playback-mse.html

* platform/graphics/gstreamer/GStreamerUtilities.cpp:
(WebCore::getVideoSizeAndFormatFromCaps): Add the support of video encrypted caps.
(WebCore::getVideoResolutionFromCaps):
(WebCore::capsMediaType):
(WebCore::doCapsHaveType):
(WebCore::areEncryptedCaps): Add a new functions in order to handle the caps properly.
* platform/graphics/gstreamer/GStreamerUtilities.h:
* platform/graphics/gstreamer/mse/AppendPipeline.cpp:
(WebCore::AppendPipeline::parseDemuxerSrcPadCaps):
* platform/graphics/gstreamer/mse/GStreamerMediaDescription.cpp:
(WebCore::GStreamerMediaDescription::codec const):
(WebCore::GStreamerMediaDescription::isVideo const):
(WebCore::GStreamerMediaDescription::isAudio const):
* platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp:
(WebCore::MediaPlayerPrivateGStreamerMSE::trackDetected):
* platform/graphics/gstreamer/mse/PlaybackPipeline.cpp:
(WebCore::PlaybackPipeline::attachTrack):
(WebCore::PlaybackPipeline::reattachTrack):
* platform/graphics/gstreamer/mse/PlaybackPipeline.h:
* platform/graphics/gstreamer/mse/WebKitMediaSourceGStreamer.cpp:
(webKitMediaSrcUpdatePresentationSize): Refactor some parts by using the new added functions.

2018-02-09 Philippe Normand <pnormand@igalia.com>

[GStreamer] Layout test fast/replaced/border-radius-clip.html crashes with GStreamer-CRITICAL **: gst_segment_to_stream_time: assertion 'segment->format == format' failed in gst_segment_to_stream_time()
Expand Down
111 changes: 101 additions & 10 deletions Source/WebCore/platform/graphics/gstreamer/GStreamerUtilities.cpp
Expand Up @@ -59,22 +59,72 @@ GstPad* webkitGstGhostPadFromStaticTemplate(GstStaticPadTemplate* staticPadTempl
#if ENABLE(VIDEO)
bool getVideoSizeAndFormatFromCaps(GstCaps* caps, WebCore::IntSize& size, GstVideoFormat& format, int& pixelAspectRatioNumerator, int& pixelAspectRatioDenominator, int& stride)
{
GstVideoInfo info;

gst_video_info_init(&info);
if (!gst_video_info_from_caps(&info, caps))
if (!doCapsHaveType(caps, GST_VIDEO_CAPS_TYPE_PREFIX)) {
GST_WARNING("Failed to get the video size and format, these are not a video caps");
return false;
}

format = GST_VIDEO_INFO_FORMAT(&info);
size.setWidth(GST_VIDEO_INFO_WIDTH(&info));
size.setHeight(GST_VIDEO_INFO_HEIGHT(&info));
pixelAspectRatioNumerator = GST_VIDEO_INFO_PAR_N(&info);
pixelAspectRatioDenominator = GST_VIDEO_INFO_PAR_D(&info);
stride = GST_VIDEO_INFO_PLANE_STRIDE(&info, 0);
if (areEncryptedCaps(caps)) {
GstStructure* structure = gst_caps_get_structure(caps, 0);
format = GST_VIDEO_FORMAT_ENCODED;
stride = 0;
int width = 0, height = 0;
gst_structure_get_int(structure, "width", &width);
gst_structure_get_int(structure, "height", &height);
if (!gst_structure_get_fraction(structure, "pixel-aspect-ratio", &pixelAspectRatioNumerator, &pixelAspectRatioDenominator)) {
pixelAspectRatioNumerator = 1;
pixelAspectRatioDenominator = 1;
}

size.setWidth(width);
size.setHeight(height);
} else {
GstVideoInfo info;
gst_video_info_init(&info);
if (!gst_video_info_from_caps(&info, caps))
return false;

format = GST_VIDEO_INFO_FORMAT(&info);
size.setWidth(GST_VIDEO_INFO_WIDTH(&info));
size.setHeight(GST_VIDEO_INFO_HEIGHT(&info));
pixelAspectRatioNumerator = GST_VIDEO_INFO_PAR_N(&info);
pixelAspectRatioDenominator = GST_VIDEO_INFO_PAR_D(&info);
stride = GST_VIDEO_INFO_PLANE_STRIDE(&info, 0);
}

return true;
}

std::optional<FloatSize> getVideoResolutionFromCaps(const GstCaps* caps)
{
if (!doCapsHaveType(caps, GST_VIDEO_CAPS_TYPE_PREFIX)) {
GST_WARNING("Failed to get the video resolution, these are not a video caps");
return std::nullopt;
}

int width = 0, height = 0;
int pixelAspectRatioNumerator = 1, pixelAspectRatioDenominator = 1;

if (areEncryptedCaps(caps)) {
GstStructure* structure = gst_caps_get_structure(caps, 0);
gst_structure_get_int(structure, "width", &width);
gst_structure_get_int(structure, "height", &height);
gst_structure_get_fraction(structure, "pixel-aspect-ratio", &pixelAspectRatioNumerator, &pixelAspectRatioDenominator);
} else {
GstVideoInfo info;
gst_video_info_init(&info);
if (!gst_video_info_from_caps(&info, caps))
return std::nullopt;

width = GST_VIDEO_INFO_WIDTH(&info);
height = GST_VIDEO_INFO_HEIGHT(&info);
pixelAspectRatioNumerator = GST_VIDEO_INFO_PAR_N(&info);
pixelAspectRatioDenominator = GST_VIDEO_INFO_PAR_D(&info);
}

return std::make_optional(FloatSize(width, height * (static_cast<float>(pixelAspectRatioNumerator) / static_cast<float>(pixelAspectRatioDenominator))));
}

bool getSampleVideoInfo(GstSample* sample, GstVideoInfo& videoInfo)
{
if (!GST_IS_SAMPLE(sample))
Expand Down Expand Up @@ -113,6 +163,47 @@ GstBuffer* createGstBufferForData(const char* data, int length)
return buffer;
}

const char* capsMediaType(const GstCaps* caps)
{
ASSERT(caps);
GstStructure* structure = gst_caps_get_structure(caps, 0);
if (!structure) {
GST_WARNING("caps are empty");
return nullptr;
}
#if ENABLE(ENCRYPTED_MEDIA)
if (gst_structure_has_name(structure, "application/x-cenc"))
return gst_structure_get_string(structure, "original-media-type");
#endif
return gst_structure_get_name(structure);
}

bool doCapsHaveType(const GstCaps* caps, const char* type)
{
const char* mediaType = capsMediaType(caps);
if (!mediaType) {
GST_WARNING("Failed to get MediaType");
return false;
}
return g_str_has_prefix(mediaType, type);
}

bool areEncryptedCaps(const GstCaps* caps)
{
ASSERT(caps);
#if ENABLE(ENCRYPTED_MEDIA)
GstStructure* structure = gst_caps_get_structure(caps, 0);
if (!structure) {
GST_WARNING("caps are empty");
return false;
}
return gst_structure_has_name(structure, "application/x-cenc");
#else
UNUSED_PARAM(caps);
return false;
#endif
}

char* getGstBufferDataPointer(GstBuffer* buffer)
{
GstMiniObject* miniObject = reinterpret_cast<GstMiniObject*>(buffer);
Expand Down
Expand Up @@ -20,6 +20,7 @@
#pragma once


#include "FloatSize.h"
#include <gst/gst.h>
#include <gst/video/video-format.h>
#include <gst/video/video-info.h>
Expand Down Expand Up @@ -50,14 +51,22 @@ inline bool webkitGstCheckVersion(guint major, guint minor, guint micro)
return true;
}

#define GST_VIDEO_CAPS_TYPE_PREFIX "video/"
#define GST_AUDIO_CAPS_TYPE_PREFIX "audio/"
#define GST_TEXT_CAPS_TYPE_PREFIX "text/"

GstPad* webkitGstGhostPadFromStaticTemplate(GstStaticPadTemplate*, const gchar* name, GstPad* target);
#if ENABLE(VIDEO)
bool getVideoSizeAndFormatFromCaps(GstCaps*, WebCore::IntSize&, GstVideoFormat&, int& pixelAspectRatioNumerator, int& pixelAspectRatioDenominator, int& stride);
std::optional<FloatSize> getVideoResolutionFromCaps(const GstCaps*);
bool getSampleVideoInfo(GstSample*, GstVideoInfo&);
#endif
GstBuffer* createGstBuffer(GstBuffer*);
GstBuffer* createGstBufferForData(const char* data, int length);
char* getGstBufferDataPointer(GstBuffer*);
const char* capsMediaType(const GstCaps*);
bool doCapsHaveType(const GstCaps*, const char*);
bool areEncryptedCaps(const GstCaps*);
void mapGstBuffer(GstBuffer*, uint32_t);
void unmapGstBuffer(GstBuffer*);
bool initializeGStreamer();
Expand Down
75 changes: 19 additions & 56 deletions Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp
Expand Up @@ -27,6 +27,7 @@
#include "GRefPtrGStreamer.h"
#include "GStreamerEMEUtilities.h"
#include "GStreamerMediaDescription.h"
#include "GStreamerUtilities.h"
#include "MediaSampleGStreamer.h"
#include "InbandTextTrackPrivateGStreamer.h"
#include "MediaDescription.h"
Expand Down Expand Up @@ -582,74 +583,36 @@ void AppendPipeline::parseDemuxerSrcPadCaps(GstCaps* demuxerSrcPadCaps)

m_demuxerSrcPadCaps = adoptGRef(demuxerSrcPadCaps);
m_streamType = WebCore::MediaSourceStreamTypeGStreamer::Unknown;

GstStructure* structure = gst_caps_get_structure(m_demuxerSrcPadCaps.get(), 0);
bool sizeConfigured = false;

#if GST_CHECK_VERSION(1, 5, 3) && ENABLE(ENCRYPTED_MEDIA)
if (gst_structure_has_name(structure, "application/x-cenc")) {
#if ENABLE(ENCRYPTED_MEDIA)
if (areEncryptedCaps(m_demuxerSrcPadCaps.get())) {
// Any previous decryptor should have been removed from the pipeline by disconnectFromAppSinkFromStreamingThread()
ASSERT(!m_decryptor);

GstStructure* structure = gst_caps_get_structure(m_demuxerSrcPadCaps.get(), 0);
m_decryptor = GStreamerEMEUtilities::createDecryptor(gst_structure_get_string(structure, "protection-system"));
if (!m_decryptor) {
GST_ERROR("decryptor not found for caps: %" GST_PTR_FORMAT, m_demuxerSrcPadCaps.get());
return;
}

const gchar* originalMediaType = gst_structure_get_string(structure, "original-media-type");

if (!MediaPlayerPrivateGStreamerMSE::supportsCodec(originalMediaType)) {
m_presentationSize = WebCore::FloatSize();
m_streamType = WebCore::MediaSourceStreamTypeGStreamer::Invalid;
} else if (g_str_has_prefix(originalMediaType, "video/")) {
int width = 0;
int height = 0;
float finalHeight = 0;

if (gst_structure_get_int(structure, "width", &width) && gst_structure_get_int(structure, "height", &height)) {
int ratioNumerator = 1;
int ratioDenominator = 1;

gst_structure_get_fraction(structure, "pixel-aspect-ratio", &ratioNumerator, &ratioDenominator);
finalHeight = height * ((float) ratioDenominator / (float) ratioNumerator);
}

m_presentationSize = WebCore::FloatSize(width, finalHeight);
m_streamType = WebCore::MediaSourceStreamTypeGStreamer::Video;
} else {
m_presentationSize = WebCore::FloatSize();
if (g_str_has_prefix(originalMediaType, "audio/"))
m_streamType = WebCore::MediaSourceStreamTypeGStreamer::Audio;
else if (g_str_has_prefix(originalMediaType, "text/"))
m_streamType = WebCore::MediaSourceStreamTypeGStreamer::Text;
}
sizeConfigured = true;
}
#endif

if (!sizeConfigured) {
const char* structureName = gst_structure_get_name(structure);
GstVideoInfo info;

if (!MediaPlayerPrivateGStreamerMSE::supportsCodec(structureName)) {
const char* originalMediaType = capsMediaType(m_demuxerSrcPadCaps.get());
if (!MediaPlayerPrivateGStreamerMSE::supportsCodec(originalMediaType)) {
m_presentationSize = WebCore::FloatSize();
m_streamType = WebCore::MediaSourceStreamTypeGStreamer::Invalid;
} else if (g_str_has_prefix(structureName, "video/") && gst_video_info_from_caps(&info, demuxerSrcPadCaps)) {
float width, height;

width = info.width;
height = info.height * ((float) info.par_d / (float) info.par_n);

m_presentationSize = WebCore::FloatSize(width, height);
m_streamType = WebCore::MediaSourceStreamTypeGStreamer::Video;
} else {
} else if (doCapsHaveType(m_demuxerSrcPadCaps.get(), GST_VIDEO_CAPS_TYPE_PREFIX)) {
std::optional<FloatSize> size = getVideoResolutionFromCaps(m_demuxerSrcPadCaps.get());
if (size.has_value())
m_presentationSize = size.value();
else
m_presentationSize = WebCore::FloatSize();
if (g_str_has_prefix(structureName, "audio/"))
m_streamType = WebCore::MediaSourceStreamTypeGStreamer::Audio;
else if (g_str_has_prefix(structureName, "text/"))
m_streamType = WebCore::MediaSourceStreamTypeGStreamer::Text;
}

m_streamType = WebCore::MediaSourceStreamTypeGStreamer::Video;
} else {
m_presentationSize = WebCore::FloatSize();
if (doCapsHaveType(m_demuxerSrcPadCaps.get(), GST_AUDIO_CAPS_TYPE_PREFIX))
m_streamType = WebCore::MediaSourceStreamTypeGStreamer::Audio;
else if (doCapsHaveType(m_demuxerSrcPadCaps.get(), GST_TEXT_CAPS_TYPE_PREFIX))
m_streamType = WebCore::MediaSourceStreamTypeGStreamer::Text;
}
}

Expand Down

0 comments on commit 54c5b38

Please sign in to comment.