Line data Source code
1 : /*
2 : * Copyright (C) 2022 Sky UK
3 : *
4 : * This library is free software; you can redistribute it and/or
5 : * modify it under the terms of the GNU Lesser General Public
6 : * License as published by the Free Software Foundation;
7 : * version 2.1 of the License.
8 : *
9 : * This library is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : * Lesser General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public
15 : * License along with this library; if not, write to the Free Software
16 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 : */
18 :
19 : #include "BufferParser.h"
20 : #include "GStreamerEMEUtils.h"
21 : #include "GStreamerUtils.h"
22 : #include "GstreamerCatLog.h"
23 : #include <cstdint>
24 : #include <cstring>
25 : #include <gst/audio/audio.h>
26 : #include <inttypes.h>
27 :
28 : using namespace firebolt::rialto;
29 : #define GST_CAT_DEFAULT rialtoGStreamerCat
30 :
31 10 : std::unique_ptr<IMediaPipeline::MediaSegment> BufferParser::parseBuffer(const GstRefSample &sample, GstBuffer *buffer,
32 : GstMapInfo map, int streamId)
33 : {
34 10 : int64_t timeStamp = static_cast<int64_t>(GST_BUFFER_PTS(buffer));
35 10 : int64_t duration = static_cast<int64_t>(GST_BUFFER_DURATION(buffer));
36 10 : GstCaps *caps = sample.getCaps();
37 10 : GstStructure *structure = gst_caps_get_structure(caps, 0);
38 :
39 : std::unique_ptr<IMediaPipeline::MediaSegment> mseData =
40 10 : parseSpecificPartOfBuffer(buffer, streamId, structure, timeStamp, duration);
41 :
42 10 : mseData->setData(map.size, map.data);
43 :
44 10 : addCodecDataToSegment(mseData, structure);
45 10 : addProtectionMetadataToSegment(mseData, buffer, map, structure);
46 10 : addDisplayOffsetToSegment(mseData, GST_BUFFER_OFFSET(buffer));
47 :
48 10 : return mseData;
49 : }
50 :
51 10 : void BufferParser::addProtectionMetadataToSegment(std::unique_ptr<IMediaPipeline::MediaSegment> &segment,
52 : GstBuffer *buffer, const GstMapInfo &map, GstStructure *structure)
53 : {
54 10 : EncryptionFormat encryptionFormat = EncryptionFormat::CLEAR;
55 10 : BufferProtectionMetadata metadata;
56 10 : ProcessProtectionMetadata(buffer, metadata);
57 :
58 10 : std::string mediaType = gst_structure_get_name(structure);
59 10 : if (mediaType == "application/x-cenc")
60 : {
61 4 : encryptionFormat = EncryptionFormat::CENC;
62 : }
63 6 : else if (mediaType == "application/x-webm-enc")
64 : {
65 4 : encryptionFormat = EncryptionFormat::WEBM;
66 : }
67 :
68 : // For WEBM encrypted sample without partitioning: add subsample which contains only encrypted data.
69 : // More details: https://www.webmproject.org/docs/webm-encryption/#45-full-sample-encrypted-block-format
70 : // For CENC see CENC specification, section 9.2
71 10 : if ((encryptionFormat == EncryptionFormat::WEBM) || (encryptionFormat == EncryptionFormat::CENC))
72 : {
73 8 : if ((metadata.encrypted) && (metadata.subsamples.size() == 0))
74 : {
75 6 : metadata.subsamples.push_back(std::make_pair((uint32_t)0, (uint32_t)map.size));
76 : }
77 : }
78 :
79 10 : if (metadata.encrypted)
80 : {
81 8 : GST_DEBUG("encrypted: %d mksId: %d key len: %zu iv len: %zu SUBSAMPLES: %zu, initWithLast15: %u",
82 : metadata.encrypted, metadata.mediaKeySessionId, metadata.kid.size(), metadata.iv.size(),
83 : metadata.subsamples.size(), metadata.initWithLast15);
84 :
85 8 : segment->setEncrypted(true);
86 8 : segment->setMediaKeySessionId(metadata.mediaKeySessionId);
87 8 : segment->setKeyId(metadata.kid);
88 8 : segment->setInitVector(metadata.iv);
89 8 : segment->setInitWithLast15(metadata.initWithLast15);
90 8 : segment->setCipherMode(metadata.cipherMode);
91 8 : if (metadata.encryptionPatternSet)
92 : {
93 8 : segment->setEncryptionPattern(metadata.cryptBlocks, metadata.skipBlocks);
94 : }
95 :
96 8 : size_t subSampleCount = metadata.subsamples.size();
97 14 : for (size_t subSampleIdx = 0; subSampleIdx < subSampleCount; ++subSampleIdx)
98 : {
99 6 : GST_DEBUG("SUBSAMPLE: %zu/%zu C: %d E: %d", subSampleIdx, subSampleCount,
100 : metadata.subsamples[subSampleIdx].first, metadata.subsamples[subSampleIdx].second);
101 6 : segment->addSubSample(metadata.subsamples[subSampleIdx].first, metadata.subsamples[subSampleIdx].second);
102 : }
103 : }
104 10 : }
105 :
106 10 : void BufferParser::addCodecDataToSegment(std::unique_ptr<firebolt::rialto::IMediaPipeline::MediaSegment> &segment,
107 : GstStructure *structure)
108 : {
109 : const GValue *codec_data;
110 10 : codec_data = gst_structure_get_value(structure, "codec_data");
111 10 : if (codec_data)
112 : {
113 3 : GstBuffer *buf = gst_value_get_buffer(codec_data);
114 3 : if (buf)
115 : {
116 2 : GstMappedBuffer mappedBuf(buf, GST_MAP_READ);
117 2 : if (mappedBuf)
118 : {
119 1 : auto codecData = std::make_shared<firebolt::rialto::CodecData>();
120 1 : codecData->data = std::vector<std::uint8_t>(mappedBuf.data(), mappedBuf.data() + mappedBuf.size());
121 1 : codecData->type = firebolt::rialto::CodecDataType::BUFFER;
122 1 : segment->setCodecData(codecData);
123 : }
124 : else
125 : {
126 1 : GST_ERROR("Failed to read codec_data");
127 : }
128 2 : return;
129 : }
130 1 : const gchar *str = g_value_get_string(codec_data);
131 1 : if (str)
132 : {
133 1 : auto codecData = std::make_shared<firebolt::rialto::CodecData>();
134 1 : codecData->data = std::vector<std::uint8_t>(str, str + std::strlen(str));
135 1 : codecData->type = firebolt::rialto::CodecDataType::STRING;
136 1 : segment->setCodecData(codecData);
137 : }
138 : }
139 : }
140 :
141 10 : void BufferParser::addDisplayOffsetToSegment(std::unique_ptr<firebolt::rialto::IMediaPipeline::MediaSegment> &segment,
142 : guint64 displayOffset)
143 : {
144 10 : if (GST_BUFFER_OFFSET_NONE != displayOffset)
145 : {
146 8 : segment->setDisplayOffset(displayOffset);
147 : }
148 10 : }
149 :
150 : std::unique_ptr<IMediaPipeline::MediaSegment>
151 8 : AudioBufferParser::parseSpecificPartOfBuffer(GstBuffer *buffer, int streamId, GstStructure *structure,
152 : int64_t timeStamp, int64_t duration)
153 : {
154 8 : gint sampleRate = 0;
155 8 : gint numberOfChannels = 0;
156 8 : guint64 clippingStart = 0;
157 8 : guint64 clippingEnd = 0;
158 8 : gst_structure_get_int(structure, "rate", &sampleRate);
159 8 : gst_structure_get_int(structure, "channels", &numberOfChannels);
160 :
161 8 : const GstAudioClippingMeta *clippingMeta = gst_buffer_get_audio_clipping_meta(buffer);
162 8 : if (clippingMeta)
163 : {
164 1 : clippingStart = clippingMeta->start;
165 1 : clippingEnd = clippingMeta->end;
166 : }
167 :
168 8 : GST_LOG("New audio frame; buffer %p, pts=%" PRId64 " duration=%" PRId64
169 : " sampleRate=%d numberOfChannels=%d, clippingStart=%" PRIu64 ", clippingEnd=%" PRIu64,
170 : buffer, timeStamp, duration, sampleRate, numberOfChannels, clippingStart, clippingEnd);
171 :
172 : std::unique_ptr<IMediaPipeline::MediaSegmentAudio> mseData =
173 : std::make_unique<IMediaPipeline::MediaSegmentAudio>(streamId, timeStamp, duration, sampleRate, numberOfChannels,
174 8 : clippingStart, clippingEnd);
175 :
176 16 : return mseData;
177 8 : }
178 :
179 : std::unique_ptr<IMediaPipeline::MediaSegment>
180 1 : VideoBufferParser::parseSpecificPartOfBuffer(GstBuffer *buffer, int streamId, GstStructure *structure,
181 : int64_t timeStamp, int64_t duration)
182 : {
183 1 : gint width = 0;
184 1 : gint height = 0;
185 1 : firebolt::rialto::Fraction frameRate{firebolt::rialto::kUndefinedSize, firebolt::rialto::kUndefinedSize};
186 1 : gst_structure_get_int(structure, "width", &width);
187 1 : gst_structure_get_int(structure, "height", &height);
188 1 : gst_structure_get_fraction(structure, "framerate", &frameRate.numerator, &frameRate.denominator);
189 :
190 1 : GST_LOG("New video frame; buffer %p, pts=%" PRId64 " duration=%" PRId64 " width=%d height=%d framerate=%d/%d",
191 : buffer, timeStamp, duration, width, height, frameRate.numerator, frameRate.denominator);
192 :
193 : std::unique_ptr<IMediaPipeline::MediaSegmentVideo> mseData =
194 1 : std::make_unique<IMediaPipeline::MediaSegmentVideo>(streamId, timeStamp, duration, width, height, frameRate);
195 :
196 2 : return mseData;
197 1 : }
198 :
199 : std::unique_ptr<IMediaPipeline::MediaSegment>
200 1 : SubtitleBufferParser::parseSpecificPartOfBuffer(GstBuffer *buffer, int streamId, GstStructure *structure,
201 : int64_t timeStamp, int64_t duration)
202 : {
203 : std::unique_ptr<IMediaPipeline::MediaSegment> mseData =
204 1 : std::make_unique<IMediaPipeline::MediaSegment>(streamId, MediaSourceType::SUBTITLE, timeStamp, duration);
205 :
206 1 : return mseData;
207 : }
|