1/* GStreamer EME Utilities class
2 *
3 * Copyright (C) 2017 Metrological
4 * Copyright (C) 2017 Igalia S.L
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22#pragma once
23
24#if ENABLE(ENCRYPTED_MEDIA) && USE(GSTREAMER)
25
26#include "GStreamerCommon.h"
27#include "SharedBuffer.h"
28#include <gst/gst.h>
29#include <wtf/text/WTFString.h>
30
31#define WEBCORE_GSTREAMER_EME_UTILITIES_CLEARKEY_UUID "1077efec-c0b2-4d02-ace3-3c1e52e2fb4b"
32
33namespace WebCore {
34class InitData {
35public:
36 InitData()
37 : m_payload(SharedBuffer::create()) { }
38
39 // FIXME: We should have an enum for system uuids for better type safety.
40 InitData(const String& systemId, GstBuffer* initData)
41 : m_systemId(systemId)
42 {
43 auto mappedInitData = GstMappedBuffer::create(initData, GST_MAP_READ);
44 if (!mappedInitData) {
45 GST_ERROR("cannot map %s protection data", systemId.utf8().data());
46 ASSERT_NOT_REACHED();
47 }
48 m_payload = mappedInitData->createSharedBuffer();
49 }
50
51 void append(InitData&& initData)
52 {
53 // FIXME: There is some confusion here about how to detect the
54 // correct "initialization data type", if the system ID is
55 // GST_PROTECTION_UNSPECIFIED_SYSTEM_ID, then we know it came
56 // from WebM. If the system id is specified with one of the
57 // defined ClearKey / Playready / Widevine / etc UUIDs, then
58 // we know it's MP4. For the latter case, it does not matter
59 // which of the UUIDs it is, so we just overwrite it. This is
60 // a quirk of how GStreamer provides protection events, and
61 // it's not very robust, so be careful here!
62 m_systemId = initData.m_systemId;
63
64 m_payload->append(*initData.payload());
65 }
66
67 const RefPtr<SharedBuffer> payload() const { return m_payload; }
68 const String& systemId() const { return m_systemId; }
69 String payloadContainerType() const
70 {
71#if GST_CHECK_VERSION(1, 15, 0)
72 if (m_systemId == GST_PROTECTION_UNSPECIFIED_SYSTEM_ID)
73 return "webm"_s;
74#endif
75 return "cenc"_s;
76 }
77
78private:
79 String m_systemId;
80 RefPtr<SharedBuffer> m_payload;
81};
82
83class ProtectionSystemEvents {
84public:
85 using EventVector = Vector<GRefPtr<GstEvent>>;
86
87 explicit ProtectionSystemEvents(GstMessage* message)
88 {
89 const GstStructure* structure = gst_message_get_structure(message);
90
91 const GValue* streamEncryptionEventsList = gst_structure_get_value(structure, "stream-encryption-events");
92 ASSERT(streamEncryptionEventsList && GST_VALUE_HOLDS_LIST(streamEncryptionEventsList));
93 unsigned numEvents = gst_value_list_get_size(streamEncryptionEventsList);
94 m_events.reserveInitialCapacity(numEvents);
95 for (unsigned i = 0; i < numEvents; ++i)
96 m_events.uncheckedAppend(GRefPtr<GstEvent>(static_cast<GstEvent*>(g_value_get_boxed(gst_value_list_get_value(streamEncryptionEventsList, i)))));
97 const GValue* streamEncryptionAllowedSystemsValue = gst_structure_get_value(structure, "available-stream-encryption-systems");
98 const char** streamEncryptionAllowedSystems = reinterpret_cast<const char**>(g_value_get_boxed(streamEncryptionAllowedSystemsValue));
99 if (streamEncryptionAllowedSystems) {
100 for (unsigned i = 0; streamEncryptionAllowedSystems[i]; ++i)
101 m_availableSystems.append(streamEncryptionAllowedSystems[i]);
102 }
103 }
104 const EventVector& events() const { return m_events; }
105 const Vector<String>& availableSystems() const { return m_availableSystems; }
106
107private:
108 EventVector m_events;
109 Vector<String> m_availableSystems;
110};
111
112
113class GStreamerEMEUtilities {
114
115public:
116 static constexpr char const* s_ClearKeyUUID = WEBCORE_GSTREAMER_EME_UTILITIES_CLEARKEY_UUID;
117 static constexpr char const* s_ClearKeyKeySystem = "org.w3.clearkey";
118
119 static bool isClearKeyKeySystem(const String& keySystem)
120 {
121 return equalIgnoringASCIICase(keySystem, s_ClearKeyKeySystem);
122 }
123
124 static const char* keySystemToUuid(const String& keySystem)
125 {
126 if (isClearKeyKeySystem(keySystem))
127 return s_ClearKeyUUID;
128
129 ASSERT_NOT_REACHED();
130 return { };
131 }
132};
133
134}
135
136#endif // ENABLE(ENCRYPTED_MEDIA) && USE(GSTREAMER)
137