Line data Source code
1 : /*
2 : * If not stated otherwise in this file or this component's LICENSE file the
3 : * following copyright and licenses apply:
4 : *
5 : * Copyright 2022 Sky UK
6 : *
7 : * Licensed under the Apache License, Version 2.0 (the "License");
8 : * you may not use this file except in compliance with the License.
9 : * You may obtain a copy of the License at
10 : *
11 : * http://www.apache.org/licenses/LICENSE-2.0
12 : *
13 : * Unless required by applicable law or agreed to in writing, software
14 : * distributed under the License is distributed on an "AS IS" BASIS,
15 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : * See the License for the specific language governing permissions and
17 : * limitations under the License.
18 : */
19 :
20 : #include "MediaFrameWriterV2.h"
21 : #include "RialtoCommonLogging.h"
22 :
23 : namespace
24 : {
25 : /**
26 : * @brief The version of metadata this object shall write.
27 : */
28 : constexpr uint32_t kMetadataVersion = 2U;
29 :
30 : /**
31 : * @brief Convert SegmentAlignment to protobuf object
32 : */
33 : firebolt::rialto::MediaSegmentMetadata_SegmentAlignment
34 4 : convertSegmentAlignment(const firebolt::rialto::SegmentAlignment &alignment)
35 : {
36 4 : switch (alignment)
37 : {
38 0 : case firebolt::rialto::SegmentAlignment::UNDEFINED:
39 : {
40 0 : return firebolt::rialto::MediaSegmentMetadata_SegmentAlignment_ALIGNMENT_UNDEFINED;
41 : }
42 2 : case firebolt::rialto::SegmentAlignment::NAL:
43 : {
44 2 : return firebolt::rialto::MediaSegmentMetadata_SegmentAlignment_ALIGNMENT_NAL;
45 : }
46 2 : case firebolt::rialto::SegmentAlignment::AU:
47 : {
48 2 : return firebolt::rialto::MediaSegmentMetadata_SegmentAlignment_ALIGNMENT_AU;
49 : }
50 : }
51 0 : return firebolt::rialto::MediaSegmentMetadata_SegmentAlignment_ALIGNMENT_UNDEFINED;
52 : }
53 :
54 : /**
55 : * @brief Convert CipherMode to protobuf object
56 : */
57 6 : firebolt::rialto::MediaSegmentMetadata_CipherMode convertCipherMode(const firebolt::rialto::CipherMode &cipherMode)
58 : {
59 6 : switch (cipherMode)
60 : {
61 2 : case firebolt::rialto::CipherMode::UNKNOWN:
62 : {
63 2 : return firebolt::rialto::MediaSegmentMetadata_CipherMode_UNKNOWN;
64 : }
65 1 : case firebolt::rialto::CipherMode::CENC:
66 : {
67 1 : return firebolt::rialto::MediaSegmentMetadata_CipherMode_CENC;
68 : }
69 1 : case firebolt::rialto::CipherMode::CBC1:
70 : {
71 1 : return firebolt::rialto::MediaSegmentMetadata_CipherMode_CBC1;
72 : }
73 1 : case firebolt::rialto::CipherMode::CENS:
74 : {
75 1 : return firebolt::rialto::MediaSegmentMetadata_CipherMode_CENS;
76 : }
77 1 : case firebolt::rialto::CipherMode::CBCS:
78 : {
79 1 : return firebolt::rialto::MediaSegmentMetadata_CipherMode_CBCS;
80 : }
81 : }
82 0 : return firebolt::rialto::MediaSegmentMetadata_CipherMode_UNKNOWN;
83 : }
84 :
85 4 : firebolt::rialto::MediaSegmentMetadata_CodecData_Type convertCodecDataType(const firebolt::rialto::CodecDataType &type)
86 : {
87 4 : if (firebolt::rialto::CodecDataType::STRING == type)
88 : {
89 0 : return firebolt::rialto::MediaSegmentMetadata_CodecData_Type_STRING;
90 : }
91 4 : return firebolt::rialto::MediaSegmentMetadata_CodecData_Type_BUFFER;
92 : }
93 :
94 : } // namespace
95 :
96 : namespace firebolt::rialto::common
97 : {
98 25 : MediaFrameWriterV2::MediaFrameWriterV2(uint8_t *shmBuffer, const std::shared_ptr<MediaPlayerShmInfo> &shmInfo)
99 25 : : m_shmBuffer(shmBuffer), m_kMaxBytes(shmInfo->maxMediaBytes), m_bytesWritten(0U),
100 50 : m_dataOffset(shmInfo->mediaDataOffset), m_numFrames{0}
101 : {
102 25 : RIALTO_COMMON_LOG_INFO("We are using a writer for Metadata V2");
103 :
104 : // Zero memory
105 25 : m_byteWriter.fillBytes(m_shmBuffer, shmInfo->metadataOffset, 0, shmInfo->maxMetadataBytes);
106 25 : m_byteWriter.fillBytes(m_shmBuffer, m_dataOffset, 0, m_kMaxBytes);
107 :
108 : // Set metadata version
109 25 : m_byteWriter.writeUint32(m_shmBuffer, shmInfo->metadataOffset, kMetadataVersion);
110 : }
111 :
112 20 : AddSegmentStatus MediaFrameWriterV2::writeFrame(const std::unique_ptr<IMediaPipeline::MediaSegment> &data)
113 : try
114 : {
115 20 : auto metadata{buildMetadata(data)};
116 19 : size_t metadataSize{metadata.ByteSizeLong()};
117 19 : if (m_bytesWritten + sizeof(metadataSize) + metadataSize + data->getDataLength() > m_kMaxBytes)
118 : {
119 1 : RIALTO_COMMON_LOG_ERROR("Not enough memory available to write MediaSegment");
120 1 : return AddSegmentStatus::NO_SPACE;
121 : }
122 18 : m_dataOffset = m_byteWriter.writeUint32(m_shmBuffer, m_dataOffset, static_cast<uint32_t>(metadataSize));
123 18 : if (!metadata.SerializeToArray(m_shmBuffer + m_dataOffset, metadataSize))
124 : {
125 0 : RIALTO_COMMON_LOG_ERROR("Failed to write type specific metadata - protobuf serialization failed.");
126 0 : m_dataOffset -= 4; // size of metadata size written in previous step
127 0 : return AddSegmentStatus::ERROR;
128 : }
129 18 : m_dataOffset += metadataSize;
130 18 : m_dataOffset = m_byteWriter.writeBytes(m_shmBuffer, m_dataOffset, data->getData(), data->getDataLength());
131 :
132 : // Track the amount of bytes written
133 18 : m_bytesWritten += sizeof(metadataSize) + metadataSize + data->getDataLength();
134 18 : ++m_numFrames;
135 :
136 18 : return AddSegmentStatus::OK;
137 7 : }
138 1 : catch (std::exception &e)
139 : {
140 1 : RIALTO_COMMON_LOG_ERROR("Failed to write type specific metadata - exception occured");
141 1 : return AddSegmentStatus::ERROR;
142 : }
143 :
144 20 : MediaSegmentMetadata MediaFrameWriterV2::buildMetadata(const std::unique_ptr<IMediaPipeline::MediaSegment> &data) const
145 : {
146 20 : MediaSegmentMetadata metadata;
147 20 : metadata.set_length(data->getDataLength());
148 20 : metadata.set_time_position(data->getTimeStamp());
149 20 : metadata.set_sample_duration(data->getDuration());
150 20 : metadata.set_stream_id(static_cast<uint32_t>(data->getId()));
151 20 : if (MediaSourceType::AUDIO == data->getType())
152 : {
153 9 : IMediaPipeline::MediaSegmentAudio &audioSegment = dynamic_cast<IMediaPipeline::MediaSegmentAudio &>(*data);
154 9 : metadata.set_sample_rate(static_cast<uint32_t>(audioSegment.getSampleRate()));
155 9 : metadata.set_channels_num(static_cast<uint32_t>(audioSegment.getNumberOfChannels()));
156 9 : metadata.set_clipping_start(audioSegment.getClippingStart());
157 9 : metadata.set_clipping_end(audioSegment.getClippingEnd());
158 : }
159 11 : else if (MediaSourceType::VIDEO == data->getType())
160 : {
161 9 : IMediaPipeline::MediaSegmentVideo &videoSegment = dynamic_cast<IMediaPipeline::MediaSegmentVideo &>(*data);
162 9 : metadata.set_width(videoSegment.getWidth());
163 9 : metadata.set_height(videoSegment.getHeight());
164 9 : metadata.mutable_frame_rate()->set_numerator(videoSegment.getFrameRate().numerator);
165 9 : metadata.mutable_frame_rate()->set_denominator(videoSegment.getFrameRate().denominator);
166 : }
167 2 : else if (MediaSourceType::SUBTITLE != data->getType())
168 : {
169 1 : RIALTO_COMMON_LOG_ERROR("Failed to write type specific metadata - media source type unsupported");
170 1 : throw std::exception();
171 : }
172 :
173 19 : if (!data->getExtraData().empty())
174 : {
175 12 : metadata.set_extra_data(std::string(data->getExtraData().begin(), data->getExtraData().end()));
176 : }
177 19 : if (SegmentAlignment::UNDEFINED != data->getSegmentAlignment())
178 : {
179 4 : metadata.set_segment_alignment(convertSegmentAlignment(data->getSegmentAlignment()));
180 : }
181 19 : if (data->getCodecData())
182 : {
183 4 : metadata.mutable_codec_data()->set_data(
184 8 : std::string(data->getCodecData()->data.begin(), data->getCodecData()->data.end()));
185 4 : metadata.mutable_codec_data()->set_type(convertCodecDataType(data->getCodecData()->type));
186 : }
187 19 : if (data->isEncrypted())
188 : {
189 6 : metadata.set_media_key_session_id(data->getMediaKeySessionId());
190 18 : metadata.set_key_id(std::string(data->getKeyId().begin(), data->getKeyId().end()));
191 12 : metadata.set_init_vector(std::string(data->getInitVector().begin(), data->getInitVector().end()));
192 6 : metadata.set_init_with_last_15(data->getInitWithLast15());
193 6 : metadata.set_cipher_mode(convertCipherMode(data->getCipherMode()));
194 6 : uint32_t crypt{0};
195 6 : uint32_t skip{0};
196 6 : if (data->getEncryptionPattern(crypt, skip))
197 : {
198 2 : metadata.set_crypt(crypt);
199 2 : metadata.set_skip(skip);
200 : }
201 :
202 12 : for (const auto &subSample : data->getSubSamples())
203 : {
204 6 : auto subSamplePair = metadata.mutable_sub_sample_info()->Add();
205 6 : subSamplePair->set_num_clear_bytes(static_cast<uint32_t>(subSample.numClearBytes));
206 6 : subSamplePair->set_num_encrypted_bytes(static_cast<uint32_t>(subSample.numEncryptedBytes));
207 : }
208 : }
209 19 : return metadata;
210 1 : }
211 : } // namespace firebolt::rialto::common
|