LCOV - code coverage report
Current view: top level - src/lib/packet.c (source / functions) Coverage Total Hit
Test: coverage.filtered.info Lines: 86.7 % 98 85
Test Date: 2025-11-16 07:16:50 Functions: 100.0 % 5 5

            Line data    Source code
       1              : /*
       2              :  *                      GPAC - Multimedia Framework C SDK
       3              :  *
       4              :  *                      Authors: Deniz Ugur, Romain Bouqueau, Sohaib Larbi
       5              :  *                      Copyright (c) Motion Spell
       6              :  *                              All rights reserved
       7              :  *
       8              :  *  This file is part of the GPAC/GStreamer wrapper
       9              :  *
      10              :  *  This GPAC/GStreamer wrapper is free software; you can redistribute it
      11              :  *  and/or modify it under the terms of the GNU Affero General Public License
      12              :  *  as published by the Free Software Foundation; either version 3, or (at
      13              :  *  your option) any later version.
      14              :  *
      15              :  *  This GPAC/GStreamer wrapper is distributed in the hope that it will be
      16              :  *  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
      17              :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18              :  *  GNU Affero General Public License for more details.
      19              :  *
      20              :  *  You should have received a copy of the GNU Affero General Public
      21              :  *  License along with this library; see the file LICENSE.  If not, write to
      22              :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23              :  *
      24              :  */
      25              : 
      26              : #include "lib/packet.h"
      27              : #include "conversion/packet/registry.h"
      28              : #include "utils.h"
      29              : 
      30              : static void
      31         6524 : gpac_pck_destructor(GF_Filter* filter, GF_FilterPid* PID, GF_FilterPacket* pck)
      32              : {
      33              :   const GF_PropertyValue* prop =
      34         6524 :     gf_filter_pck_get_property(pck, GF_PROP_PCK_UDTA);
      35         6524 :   if (prop) {
      36         6524 :     GstBuffer* buffer = prop->value.ptr;
      37         6524 :     gst_buffer_unref(buffer);
      38              :   }
      39         6524 : }
      40              : 
      41              : guint64
      42        13048 : gpac_pck_get_stream_time(GstClockTime time,
      43              :                          GpacPadPrivate* priv,
      44              :                          gboolean is_dts)
      45              : {
      46        13048 :   GstElement* element = gst_pad_get_parent_element(priv->self);
      47        13048 :   if (!GST_CLOCK_TIME_IS_VALID(time))
      48            0 :     goto fail;
      49              : 
      50              :   // Identity if segment isn't time based
      51        13048 :   if (!priv->segment || priv->segment->format != GST_FORMAT_TIME)
      52            0 :     return time;
      53              : 
      54              :   guint64 unsigned_time;
      55        13048 :   int ret = gst_segment_to_stream_time_full(
      56        13048 :     priv->segment, GST_FORMAT_TIME, time, &unsigned_time);
      57        13048 :   if (ret == 0)
      58            0 :     goto fail;
      59              : 
      60              :   // It's possible that DTS is negative, so we need to offset it with the
      61              :   // DTS value
      62        13048 :   gboolean is_negative = ret < 0;
      63        13048 :   if (is_dts && is_negative && !priv->dts_offset_set) {
      64            8 :     priv->dts_offset = (gint64)unsigned_time;
      65            8 :     priv->dts_offset_set = TRUE;
      66              :   }
      67              : 
      68              :   // Offset the time with the initial DTS offset
      69        13048 :   if (is_dts) {
      70         6524 :     if (is_negative) {
      71           16 :       unsigned_time = priv->dts_offset - unsigned_time;
      72              :     } else {
      73         6508 :       unsigned_time = priv->dts_offset + unsigned_time;
      74              :     }
      75         6524 :   } else if (is_negative) {
      76            0 :     GST_ELEMENT_WARNING(element,
      77              :                         STREAM,
      78              :                         FAILED,
      79              :                         ("PTS %" GST_TIME_FORMAT
      80              :                          " is not valid, likely not related to current segment",
      81              :                          GST_TIME_ARGS(time)),
      82              :                         (NULL));
      83              :   }
      84              : 
      85        13048 :   return unsigned_time;
      86              : 
      87            0 : fail:
      88            0 :   GST_ELEMENT_ERROR(element,
      89              :                     STREAM,
      90              :                     FAILED,
      91              :                     ("Failed to convert time %" GST_TIME_FORMAT
      92              :                      " to stream time",
      93              :                      GST_TIME_ARGS(time)),
      94              :                     (NULL));
      95            0 :   return 0;
      96              : }
      97              : 
      98              : void
      99         4637 : gpac_configure_video(GstBuffer* buffer,
     100              :                      GpacPadPrivate* priv,
     101              :                      GF_FilterPacket* packet)
     102              : {
     103              :   // Decide on sample dependency flags
     104         4637 :   gboolean is_delta =
     105         4637 :     GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT);
     106         4637 :   gboolean is_droppable =
     107         4637 :     GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DROPPABLE);
     108         4637 :   gboolean is_discontinuity =
     109         4637 :     GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DISCONT);
     110              : 
     111              :   // Set the SAP type for video streams
     112         4637 :   gf_filter_pck_set_sap(packet,
     113              :                         is_delta ? GF_FILTER_SAP_NONE : GF_FILTER_SAP_1);
     114              : 
     115              :   // Note that acceptance tests doesn't like SAP, is_leading, sample_depends_on
     116         4637 :   u32 flags = 0;
     117              : 
     118              :   // is_leading
     119         4637 :   if (is_delta)
     120         4538 :     flags |= (priv->last_frame_was_keyframe ? 3 : 2) << 6;
     121              : 
     122              :   // sample_depends_on
     123         4637 :   if (is_discontinuity)
     124           17 :     flags |= 2 << 4;
     125              :   else
     126         4620 :     flags |= ((is_delta ? 1 : 2) << 4);
     127              : 
     128         4637 :   flags |= ((is_droppable ? 2 : 1) << 2); // sample_is_depended_on
     129         4637 :   flags |= (2 << 0);                      // sample_has_redundancy
     130              : 
     131         4637 :   gf_filter_pck_set_dependency_flags(packet, flags);
     132         4637 :   priv->last_frame_was_keyframe = !is_delta;
     133         4637 : }
     134              : 
     135              : void
     136         6524 : gpac_pck_prop_configure(GPAC_PCK_PROP_IMPL_ARGS)
     137              : {
     138              :   // Check arguments
     139         6524 :   g_return_if_fail(buffer != NULL);
     140         6524 :   g_return_if_fail(priv != NULL);
     141         6524 :   g_return_if_fail(pck != NULL);
     142              : 
     143              :   // Go through the property registry
     144        13048 :   for (u32 i = 0; i < gpac_pck_get_num_supported_props(); i++) {
     145         6524 :     prop_registry_entry* entry = &prop_registry[i];
     146              : 
     147              :     // Run the handler for the property
     148         6524 :     entry->handler(buffer, priv, pck, pid);
     149              :   }
     150              : }
     151              : 
     152              : GF_FilterPacket*
     153         6524 : gpac_pck_new_from_buffer(GstBuffer* buffer,
     154              :                          GpacPadPrivate* priv,
     155              :                          GF_FilterPid* pid)
     156              : {
     157              :   const GF_PropertyValue* p;
     158         6524 :   GstElement* element = gst_pad_get_parent_element(priv->self);
     159              : 
     160              :   // Map the buffer
     161         6524 :   g_auto(GstBufferMapInfo) map = GST_MAP_INFO_INIT;
     162         6524 :   if (G_UNLIKELY(!gst_buffer_map(buffer, &map, GST_MAP_READ))) {
     163            0 :     GST_ELEMENT_ERROR(
     164              :       element, STREAM, FAILED, (NULL), ("Failed to map buffer"));
     165            0 :     return NULL;
     166              :   }
     167              : 
     168              :   // Create a new shared packet
     169              :   GF_FilterPacket* packet =
     170         6524 :     gf_filter_pck_new_shared(pid, map.data, map.size, gpac_pck_destructor);
     171              : 
     172              :   // Ref the buffer so that we can free it later
     173         6524 :   GstBuffer* ref = gst_buffer_ref(buffer);
     174              :   GF_Err err =
     175         6524 :     gf_filter_pck_set_property(packet, GF_PROP_PCK_UDTA, &PROP_POINTER(ref));
     176         6524 :   if (G_UNLIKELY(err != GF_OK)) {
     177            0 :     GST_ELEMENT_ERROR(element,
     178              :                       STREAM,
     179              :                       FAILED,
     180              :                       (NULL),
     181              :                       ("Failed to save the buffer ref to the packet"));
     182            0 :     gst_buffer_unref(ref);
     183            0 :     gf_filter_pck_unref(packet);
     184            0 :     return NULL;
     185              :   }
     186              : 
     187              :   // Get the fps from the PID
     188         6524 :   GF_Fraction fps = { 1, 1 };
     189         6524 :   p = gf_filter_pid_get_property(pid, GF_PROP_PID_FPS);
     190         6524 :   if (p)
     191         4637 :     fps = p->value.frac;
     192              : 
     193              :   // Get the timescale from the PID
     194         6524 :   guint64 timescale = GST_SECOND;
     195         6524 :   p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
     196         6524 :   if (p)
     197         6524 :     timescale = p->value.uint;
     198              : 
     199              :   // Set the DTS to DTS or PTS, whichever is valid
     200         6524 :   if (GST_BUFFER_DTS_IS_VALID(buffer) || GST_BUFFER_PTS_IS_VALID(buffer)) {
     201              :     guint64 dts =
     202         6524 :       gpac_pck_get_stream_time(GST_BUFFER_DTS_OR_PTS(buffer), priv, TRUE);
     203         6524 :     dts = gpac_time_rescale_with_fps(dts, fps, timescale);
     204         6524 :     gf_filter_pck_set_dts(packet, dts);
     205              :   }
     206              : 
     207              :   // Set the CTS to PTS if it's valid
     208         6524 :   if (GST_BUFFER_PTS_IS_VALID(buffer)) {
     209         6524 :     guint64 cts = gpac_pck_get_stream_time(GST_BUFFER_PTS(buffer), priv, FALSE);
     210         6524 :     cts = gpac_time_rescale_with_fps(cts, fps, timescale);
     211         6524 :     gf_filter_pck_set_cts(packet, cts);
     212              :   }
     213              : 
     214              :   // Set the duration
     215         6524 :   if (GST_BUFFER_DURATION_IS_VALID(buffer)) {
     216         6524 :     guint64 duration = GST_BUFFER_DURATION(buffer);
     217         6524 :     duration = gpac_time_rescale_with_fps(duration, fps, timescale);
     218         6524 :     gf_filter_pck_set_duration(packet, duration);
     219              :   }
     220              : 
     221              :   // Set packet framing
     222         6524 :   gf_filter_pck_set_framing(packet, GF_TRUE, GF_TRUE);
     223              : 
     224              :   // Set the default SAP type
     225         6524 :   gf_filter_pck_set_sap(packet, GF_FILTER_SAP_1);
     226              : 
     227              :   // Check if this is a video
     228              :   const GF_PropertyValue* p_typ =
     229         6524 :     gf_filter_pid_get_property(pid, GF_PROP_PID_STREAM_TYPE);
     230         6524 :   gboolean is_video = p_typ && p_typ->value.uint == GF_STREAM_VISUAL;
     231              : 
     232              :   // For video streams, we need further configuration
     233         6524 :   if (is_video) {
     234         4637 :     gpac_configure_video(buffer, priv, packet);
     235              :   }
     236              : 
     237              :   // Configure the packet properties
     238         6524 :   gpac_pck_prop_configure(buffer, priv, packet, pid);
     239              : 
     240         6524 :   return packet;
     241              : }
        

Generated by: LCOV version 2.0-1