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

Generated by: LCOV version 2.0-1