LCOV - code coverage report
Current view: top level - src/lib/conversion/pid/caps_handlers.c (source / functions) Coverage Total Hit
Test: coverage.filtered.info Lines: 84.7 % 150 127
Test Date: 2026-03-11 21:42:04 Functions: 100.0 % 12 12

            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 "common.h"
      27              : #include "gpacmessages.h"
      28              : #include "lib/pid.h"
      29              : 
      30              : #define CAPS_HANDLER_SIGNATURE(prop_nickname)                    \
      31              :   gboolean prop_nickname##_caps_handler(GPAC_PID_PROP_IMPL_ARGS)
      32              : 
      33              : #define DEFAULT_HANDLER(prop_nickname)                           \
      34              :   gboolean prop_nickname##_caps_handler(GPAC_PID_PROP_IMPL_ARGS) \
      35              :   {                                                              \
      36              :     return FALSE;                                                \
      37              :   }
      38              : 
      39              : #define GET_MEDIA_AND_CODEC                                             \
      40              :   GstStructure* structure = gst_caps_get_structure(priv->caps, 0);      \
      41              :   const gchar* media_type_full = gst_structure_get_name(structure);     \
      42              :   g_auto(GStrv) media_type_parts = g_strsplit(media_type_full, "/", 2); \
      43              :   gchar* media = media_type_parts[0];                                   \
      44              :   gchar* codec = media_type_parts[1];
      45              : 
      46              : void
      47           66 : gpac_push_capability(GpacPadPrivate* priv, u32 code, GF_PropertyValue* val)
      48              : {
      49          132 :   for (GList* l = priv->gpac_caps; l != NULL; l = l->next) {
      50           72 :     GF_FilterCapability* cap = l->data;
      51           72 :     if (cap->code == code) {
      52              :       // Check if the value is the same
      53            6 :       if (!gf_props_equal(&cap->val, val))
      54            0 :         priv->caps_changed = TRUE;
      55              : 
      56              :       // Update existing capability
      57            6 :       cap->val = *val;
      58            6 :       return;
      59              :     }
      60              :   }
      61              : 
      62              :   // Add new capability
      63           60 :   GF_FilterCapability* new_cap = g_new0(GF_FilterCapability, 1);
      64           60 :   new_cap->code = code;
      65           60 :   new_cap->val = *val;
      66           60 :   new_cap->flags = GF_CAPS_OUTPUT;
      67           60 :   priv->gpac_caps = g_list_append(priv->gpac_caps, new_cap);
      68           60 :   priv->caps_changed = TRUE;
      69              : }
      70              : 
      71              : //
      72              : // Default Caps handlers
      73              : //
      74           22 : DEFAULT_HANDLER(duration)
      75              : 
      76              : //
      77              : // Caps handlers
      78              : //
      79           22 : CAPS_HANDLER_SIGNATURE(stream_type)
      80              : {
      81           44 :   GET_MEDIA_AND_CODEC
      82              : 
      83              :   // Get the stream type
      84           22 :   u32 stream_type = gf_stream_type_by_name(media);
      85           22 :   if (stream_type == GF_STREAM_UNKNOWN) {
      86            0 :     GST_ELEMENT_ERROR(
      87              :       element, LIBRARY, FAILED, (NULL), ("Unknown stream type"));
      88            0 :     return FALSE;
      89              :   }
      90              : 
      91              :   // Check the subtype
      92           22 :   if (!g_strcmp0(media, "video")) {
      93           19 :     const gchar* subtype = gst_structure_get_string(structure, "stream-format");
      94           19 :     if (!g_strcmp0(subtype, "avc") || !g_strcmp0(subtype, "hev1"))
      95           17 :       SET_PROP(GF_PROP_PID_ISOM_SUBTYPE, PROP_STRING(subtype));
      96              :   }
      97              : 
      98              :   // Push the caps with the codecid property
      99           22 :   gpac_push_capability(priv, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(stream_type));
     100              : 
     101              :   // Set the stream type
     102           22 :   SET_PROP(GF_PROP_PID_STREAM_TYPE, PROP_UINT(stream_type));
     103           22 :   return TRUE;
     104              : }
     105              : 
     106           22 : CAPS_HANDLER_SIGNATURE(codec_id)
     107              : {
     108           44 :   GET_MEDIA_AND_CODEC
     109           22 :   GF_CodecID codec_id = GF_CODECID_NONE;
     110              : 
     111              :   // In most cases the substring after "x-" can be used to query the codec id
     112           22 :   if (g_str_has_prefix(codec, "x-")) {
     113           19 :     size_t offset = 2;
     114              :     // Subtitle doesn't have "raw" codec
     115           19 :     if (!g_strcmp0(media, "text") && !g_strcmp0(codec, "x-raw")) {
     116            0 :       codec_id = GF_CODECID_SIMPLE_TEXT;
     117            0 :       goto finish;
     118              :     }
     119              : 
     120           19 :     codec_id = gf_codecid_parse(codec + offset);
     121           19 :     if (codec_id != GF_CODECID_NONE)
     122           19 :       goto finish;
     123              :   }
     124              : 
     125              :   // See caps.h for the supported formats
     126              :   // For the other cases, we will match the codec id manually
     127            3 :   if (!g_strcmp0(media, "audio")) {
     128            3 :     if (!g_strcmp0(codec, "mpeg"))
     129            3 :       codec_id = GF_CODECID_AAC_MPEG4;
     130              :   }
     131              : 
     132              :   // If we still couldn't determine the codec id, log a warning
     133            3 :   if (codec_id == GF_CODECID_NONE) {
     134            0 :     GST_ELEMENT_ERROR(element,
     135              :                       STREAM,
     136              :                       FAILED,
     137              :                       (NULL),
     138              :                       ("Could not determine codec id for %s/%s", media, codec));
     139            0 :     return FALSE;
     140              :   }
     141              : 
     142            3 : finish:
     143              :   // Push the caps with the codecid property
     144           22 :   gpac_push_capability(priv, GF_PROP_PID_CODECID, &PROP_UINT(codec_id));
     145              : 
     146              :   // Set the codec id
     147           22 :   SET_PROP(GF_PROP_PID_CODECID, PROP_UINT(codec_id));
     148           22 :   return TRUE;
     149              : }
     150              : 
     151           22 : CAPS_HANDLER_SIGNATURE(unframed)
     152              : {
     153           44 :   GET_MEDIA_AND_CODEC
     154              : 
     155              :   const gchar* stream_format =
     156           22 :     gst_structure_get_string(structure, "stream-format");
     157              : 
     158              :   // Check if the stream is framed
     159           22 :   gboolean framed = TRUE;
     160           22 :   if (!g_strcmp0(media, "video")) {
     161           19 :     if (stream_format) {
     162           37 :       if (!g_strcmp0(stream_format, "byte-stream") ||
     163           18 :           !g_strcmp0(stream_format, "obu-stream"))
     164            2 :         framed = FALSE;
     165              :     }
     166            3 :   } else if (!g_strcmp0(media, "audio")) {
     167            3 :     gst_structure_get_boolean(structure, "framed", &framed);
     168            0 :   } else if (!g_strcmp0(media, "text")) {
     169              :     // For text media we assume unframed data
     170            0 :     framed = FALSE;
     171              :   }
     172              : 
     173              :   //* For AVC, HEVC, AV1, etc. our caps always ask for streams with start codes.
     174              :   //* So we'll always have unframed data. But for maximum compatibility, we may
     175              :   //* allow framed data and explicitly load "unframer" in gpac.
     176              : 
     177              :   // Push the caps with the unframed property
     178           22 :   gpac_push_capability(priv, GF_PROP_PID_UNFRAMED, &PROP_BOOL(!framed));
     179              : 
     180              :   // Set the unframed property
     181           22 :   SET_PROP(GF_PROP_PID_UNFRAMED, PROP_BOOL(!framed));
     182           22 :   return TRUE;
     183              : }
     184              : 
     185           22 : CAPS_HANDLER_SIGNATURE(width)
     186              : {
     187           44 :   GET_MEDIA_AND_CODEC
     188              : 
     189              :   // Only process video media
     190           22 :   if (g_strcmp0(media, "video"))
     191            3 :     return TRUE;
     192              : 
     193           19 :   gint width = -1;
     194           19 :   gst_structure_get_int(structure, "width", &width);
     195           19 :   if (width <= 0) {
     196            0 :     GST_ELEMENT_ERROR(element, LIBRARY, FAILED, (NULL), ("Invalid width"));
     197            0 :     return FALSE;
     198              :   }
     199              : 
     200              :   // Set the width property
     201           19 :   SET_PROP(GF_PROP_PID_WIDTH, PROP_UINT(width));
     202           19 :   return TRUE;
     203              : }
     204              : 
     205           22 : CAPS_HANDLER_SIGNATURE(height)
     206              : {
     207           44 :   GET_MEDIA_AND_CODEC
     208              : 
     209              :   // Only process video media
     210           22 :   if (g_strcmp0(media, "video"))
     211            3 :     return TRUE;
     212              : 
     213           19 :   gint height = -1;
     214           19 :   gst_structure_get_int(structure, "height", &height);
     215           19 :   if (height <= 0) {
     216            0 :     GST_ELEMENT_ERROR(element, LIBRARY, FAILED, (NULL), ("Invalid height"));
     217            0 :     return FALSE;
     218              :   }
     219              : 
     220              :   // Set the height property
     221           19 :   SET_PROP(GF_PROP_PID_HEIGHT, PROP_UINT(height));
     222           19 :   return TRUE;
     223              : }
     224              : 
     225           22 : CAPS_HANDLER_SIGNATURE(sample_rate)
     226              : {
     227           44 :   GET_MEDIA_AND_CODEC
     228              : 
     229              :   // Only process audio media
     230           22 :   if (g_strcmp0(media, "audio"))
     231           19 :     return TRUE;
     232              : 
     233            3 :   gint rate = -1;
     234            3 :   gst_structure_get_int(structure, "rate", &rate);
     235            3 :   if (rate <= 0) {
     236            0 :     GST_ELEMENT_ERROR(
     237              :       element, LIBRARY, FAILED, (NULL), ("Invalid sample rate"));
     238            0 :     return FALSE;
     239              :   }
     240              : 
     241              :   // Set the sample rate property
     242            3 :   SET_PROP(GF_PROP_PID_SAMPLE_RATE, PROP_UINT(rate));
     243            3 :   return TRUE;
     244              : }
     245              : 
     246           22 : CAPS_HANDLER_SIGNATURE(fps)
     247              : {
     248           44 :   GET_MEDIA_AND_CODEC
     249              : 
     250              :   // Only process video media
     251           22 :   if (g_strcmp0(media, "video"))
     252            3 :     return TRUE;
     253              : 
     254           19 :   gint num = -1, denom = -1;
     255           19 :   gst_structure_get_fraction(structure, "framerate", &num, &denom);
     256           19 :   if (num < 0 || denom < 0)
     257            0 :     return FALSE;
     258              : 
     259              :   // Set the framerate property
     260           19 :   SET_PROP(GF_PROP_PID_FPS, PROP_FRAC_INT(num, denom));
     261           19 :   return TRUE;
     262              : }
     263              : 
     264           22 : CAPS_HANDLER_SIGNATURE(timescale)
     265              : {
     266           44 :   GET_MEDIA_AND_CODEC
     267              : 
     268           22 :   guint64 timescale = 0;
     269           22 :   if (!g_strcmp0(media, "video")) {
     270              :     const GF_PropertyValue* p =
     271           19 :       gf_filter_pid_get_property(pid, GF_PROP_PID_FPS);
     272           19 :     if (p)
     273           19 :       timescale = p->value.frac.num;
     274            3 :   } else if (!g_strcmp0(media, "audio")) {
     275              :     const GF_PropertyValue* p =
     276            3 :       gf_filter_pid_get_property(pid, GF_PROP_PID_SAMPLE_RATE);
     277            3 :     if (p)
     278            3 :       timescale = p->value.uint;
     279            0 :   } else if (!g_strcmp0(media, "text")) {
     280              :     // For text media we can use a default timescale
     281            0 :     timescale = 1000;
     282              :   } else {
     283            0 :     GST_ELEMENT_ERROR(element,
     284              :                       LIBRARY,
     285              :                       FAILED,
     286              :                       ("Unsupported media type (%s) for timescale", media),
     287              :                       (NULL));
     288            0 :     return FALSE;
     289              :   }
     290              : 
     291           22 :   if (timescale == 0)
     292            0 :     return FALSE;
     293              : 
     294              :   // Set the timescale property
     295           22 :   SET_PROP(GF_PROP_PID_TIMESCALE, PROP_UINT(timescale));
     296           22 :   return TRUE;
     297              : }
     298              : 
     299           22 : CAPS_HANDLER_SIGNATURE(num_channels)
     300              : {
     301           44 :   GET_MEDIA_AND_CODEC
     302              : 
     303              :   // Only process audio media
     304           22 :   if (g_strcmp0(media, "audio"))
     305           19 :     return TRUE;
     306              : 
     307            3 :   gint channels = -1;
     308            3 :   gst_structure_get_int(structure, "channels", &channels);
     309              : 
     310              :   // Set the number of channels property
     311            3 :   SET_PROP(GF_PROP_PID_NUM_CHANNELS, PROP_UINT(channels));
     312            3 :   return TRUE;
     313              : }
     314              : 
     315           22 : CAPS_HANDLER_SIGNATURE(decoder_config)
     316              : {
     317           22 :   SKIP_IF_SET(GF_PROP_PID_DECODER_CONFIG);
     318              : 
     319           21 :   GstStructure* structure = gst_caps_get_structure(priv->caps, 0);
     320              : 
     321              :   // Get the codec data
     322           21 :   const GValue* codec_data = gst_structure_get_value(structure, "codec_data");
     323           21 :   if (!GST_VALUE_HOLDS_BUFFER(codec_data))
     324            2 :     return TRUE;
     325              : 
     326           19 :   GstBuffer* buffer = gst_value_get_buffer(codec_data);
     327           19 :   g_auto(GstBufferMapInfo) map = GST_MAP_INFO_INIT;
     328           19 :   if (!gst_buffer_map(buffer, &map, GST_MAP_READ)) {
     329            0 :     GST_ELEMENT_ERROR(
     330              :       element, STREAM, FAILED, (NULL), ("Failed to map codec_data buffer"));
     331            0 :     return FALSE;
     332              :   }
     333              : 
     334              :   // Copy the data
     335           19 :   u8* data = (u8*)g_malloc0(map.size);
     336           19 :   memcpy((void*)data, map.data, map.size);
     337              : 
     338              :   // Set the decoder config property
     339           19 :   SET_PROP(GF_PROP_PID_DECODER_CONFIG, PROP_CONST_DATA(data, map.size));
     340           19 :   return TRUE;
     341              : }
        

Generated by: LCOV version 2.0-1