LCOV - code coverage report
Current view: top level - source - BufferParser.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 90 90
Test Date: 2025-06-24 14:11:58 Functions: 100.0 % 7 7

            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              : }
        

Generated by: LCOV version 2.0-1