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: 83.8 % 136 114
Test Date: 2025-11-16 07:16:50 Functions: 100.0 % 11 11

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

Generated by: LCOV version 2.0-1