LCOV - code coverage report
Current view: top level - src/lib/packet.c (source / functions) Coverage Total Hit
Test: coverage.filtered.info Lines: 87.5 % 96 84
Test Date: 2025-09-18 00:43:48 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              :   guint64 unsigned_time;
      51        13048 :   int ret = gst_segment_to_stream_time_full(
      52        13048 :     priv->segment, GST_FORMAT_TIME, time, &unsigned_time);
      53        13048 :   if (ret == 0)
      54            0 :     goto fail;
      55              : 
      56              :   // It's possible that DTS is negative, so we need to offset it with the
      57              :   // DTS value
      58        13048 :   gboolean is_negative = ret < 0;
      59        13048 :   if (is_dts && is_negative && !priv->dts_offset_set) {
      60            8 :     priv->dts_offset = (gint64)unsigned_time;
      61            8 :     priv->dts_offset_set = TRUE;
      62              :   }
      63              : 
      64              :   // Offset the time with the initial DTS offset
      65        13048 :   if (is_dts) {
      66         6524 :     if (is_negative) {
      67           16 :       unsigned_time = priv->dts_offset - unsigned_time;
      68              :     } else {
      69         6508 :       unsigned_time = priv->dts_offset + unsigned_time;
      70              :     }
      71         6524 :   } else if (is_negative) {
      72            0 :     GST_ELEMENT_WARNING(element,
      73              :                         STREAM,
      74              :                         FAILED,
      75              :                         ("PTS %" GST_TIME_FORMAT
      76              :                          " is not valid, likely not related to current segment",
      77              :                          GST_TIME_ARGS(time)),
      78              :                         (NULL));
      79              :   }
      80              : 
      81        13048 :   return unsigned_time;
      82              : 
      83            0 : fail:
      84            0 :   GST_ELEMENT_ERROR(element,
      85              :                     STREAM,
      86              :                     FAILED,
      87              :                     ("Failed to convert time %" GST_TIME_FORMAT
      88              :                      " to stream time",
      89              :                      GST_TIME_ARGS(time)),
      90              :                     (NULL));
      91            0 :   return 0;
      92              : }
      93              : 
      94              : void
      95         4637 : gpac_configure_video(GstBuffer* buffer,
      96              :                      GpacPadPrivate* priv,
      97              :                      GF_FilterPacket* packet)
      98              : {
      99              :   // Decide on sample dependency flags
     100         4637 :   gboolean is_delta =
     101         4637 :     GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT);
     102         4637 :   gboolean is_droppable =
     103         4637 :     GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DROPPABLE);
     104         4637 :   gboolean is_discontinuity =
     105         4637 :     GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DISCONT);
     106              : 
     107              :   // Set the SAP type for video streams
     108         4637 :   gf_filter_pck_set_sap(packet,
     109              :                         is_delta ? GF_FILTER_SAP_NONE : GF_FILTER_SAP_1);
     110              : 
     111              :   // Note that acceptance tests doesn't like SAP, is_leading, sample_depends_on
     112         4637 :   u32 flags = 0;
     113              : 
     114              :   // is_leading
     115         4637 :   if (is_delta)
     116         4538 :     flags |= (priv->last_frame_was_keyframe ? 3 : 2) << 6;
     117              : 
     118              :   // sample_depends_on
     119         4637 :   if (is_discontinuity)
     120           17 :     flags |= 2 << 4;
     121              :   else
     122         4620 :     flags |= ((is_delta ? 1 : 2) << 4);
     123              : 
     124         4637 :   flags |= ((is_droppable ? 2 : 1) << 2); // sample_is_depended_on
     125         4637 :   flags |= (2 << 0);                      // sample_has_redundancy
     126              : 
     127         4637 :   gf_filter_pck_set_dependency_flags(packet, flags);
     128         4637 :   priv->last_frame_was_keyframe = !is_delta;
     129         4637 : }
     130              : 
     131              : void
     132         6524 : gpac_pck_prop_configure(GPAC_PCK_PROP_IMPL_ARGS)
     133              : {
     134              :   // Check arguments
     135         6524 :   g_return_if_fail(buffer != NULL);
     136         6524 :   g_return_if_fail(priv != NULL);
     137         6524 :   g_return_if_fail(pck != NULL);
     138              : 
     139              :   // Go through the property registry
     140        13048 :   for (u32 i = 0; i < gpac_pck_get_num_supported_props(); i++) {
     141         6524 :     prop_registry_entry* entry = &prop_registry[i];
     142              : 
     143              :     // Run the handler for the property
     144         6524 :     entry->handler(buffer, priv, pck, pid);
     145              :   }
     146              : }
     147              : 
     148              : GF_FilterPacket*
     149         6524 : gpac_pck_new_from_buffer(GstBuffer* buffer,
     150              :                          GpacPadPrivate* priv,
     151              :                          GF_FilterPid* pid)
     152              : {
     153              :   const GF_PropertyValue* p;
     154         6524 :   GstElement* element = gst_pad_get_parent_element(priv->self);
     155              : 
     156              :   // Map the buffer
     157         6524 :   g_auto(GstBufferMapInfo) map = GST_MAP_INFO_INIT;
     158         6524 :   if (G_UNLIKELY(!gst_buffer_map(buffer, &map, GST_MAP_READ))) {
     159            0 :     GST_ELEMENT_ERROR(
     160              :       element, STREAM, FAILED, (NULL), ("Failed to map buffer"));
     161            0 :     return NULL;
     162              :   }
     163              : 
     164              :   // Create a new shared packet
     165              :   GF_FilterPacket* packet =
     166         6524 :     gf_filter_pck_new_shared(pid, map.data, map.size, gpac_pck_destructor);
     167              : 
     168              :   // Ref the buffer so that we can free it later
     169         6524 :   GstBuffer* ref = gst_buffer_ref(buffer);
     170              :   GF_Err err =
     171         6524 :     gf_filter_pck_set_property(packet, GF_PROP_PCK_UDTA, &PROP_POINTER(ref));
     172         6524 :   if (G_UNLIKELY(err != GF_OK)) {
     173            0 :     GST_ELEMENT_ERROR(element,
     174              :                       STREAM,
     175              :                       FAILED,
     176              :                       (NULL),
     177              :                       ("Failed to save the buffer ref to the packet"));
     178            0 :     gst_buffer_unref(ref);
     179            0 :     gf_filter_pck_unref(packet);
     180            0 :     return NULL;
     181              :   }
     182              : 
     183              :   // Get the fps from the PID
     184         6524 :   GF_Fraction fps = { 30, 1 };
     185         6524 :   p = gf_filter_pid_get_property(pid, GF_PROP_PID_FPS);
     186         6524 :   if (p)
     187         4637 :     fps = p->value.frac;
     188              : 
     189              :   // Get the timescale from the PID
     190         6524 :   guint64 timescale = GST_SECOND;
     191         6524 :   p = gf_filter_pid_get_property(pid, GF_PROP_PID_TIMESCALE);
     192         6524 :   if (p)
     193         6524 :     timescale = p->value.uint;
     194              : 
     195              :   // Set the DTS to DTS or PTS, whichever is valid
     196         6524 :   if (GST_BUFFER_DTS_IS_VALID(buffer) || GST_BUFFER_PTS_IS_VALID(buffer)) {
     197              :     guint64 dts =
     198         6524 :       gpac_pck_get_stream_time(GST_BUFFER_DTS_OR_PTS(buffer), priv, TRUE);
     199         6524 :     dts = gpac_time_rescale_with_fps(dts, fps, timescale);
     200         6524 :     gf_filter_pck_set_dts(packet, dts);
     201              :   }
     202              : 
     203              :   // Set the CTS to PTS if it's valid
     204         6524 :   if (GST_BUFFER_PTS_IS_VALID(buffer)) {
     205         6524 :     guint64 cts = gpac_pck_get_stream_time(GST_BUFFER_PTS(buffer), priv, FALSE);
     206         6524 :     cts = gpac_time_rescale_with_fps(cts, fps, timescale);
     207         6524 :     gf_filter_pck_set_cts(packet, cts);
     208              :   }
     209              : 
     210              :   // Set the duration
     211         6524 :   if (GST_BUFFER_DURATION_IS_VALID(buffer)) {
     212         6524 :     guint64 duration = GST_BUFFER_DURATION(buffer);
     213         6524 :     duration = gpac_time_rescale_with_fps(duration, fps, timescale);
     214         6524 :     gf_filter_pck_set_duration(packet, duration);
     215              :   }
     216              : 
     217              :   // Set packet framing
     218         6524 :   gf_filter_pck_set_framing(packet, GF_TRUE, GF_TRUE);
     219              : 
     220              :   // Set the default SAP type
     221         6524 :   gf_filter_pck_set_sap(packet, GF_FILTER_SAP_1);
     222              : 
     223              :   // Check if this is a video
     224              :   const GF_PropertyValue* p_typ =
     225         6524 :     gf_filter_pid_get_property(pid, GF_PROP_PID_STREAM_TYPE);
     226         6524 :   gboolean is_video = p_typ && p_typ->value.uint == GF_STREAM_VISUAL;
     227              : 
     228              :   // For video streams, we need further configuration
     229         6524 :   if (is_video) {
     230         4637 :     gpac_configure_video(buffer, priv, packet);
     231              :   }
     232              : 
     233              :   // Configure the packet properties
     234         6524 :   gpac_pck_prop_configure(buffer, priv, packet, pid);
     235              : 
     236         6524 :   return packet;
     237              : }
        

Generated by: LCOV version 2.0-1