| /* |
| * gstmpegtsdescriptor.c - |
| * Copyright (C) 2013 Edward Hervey |
| * |
| * Authors: |
| * Edward Hervey <edward@collabora.com> |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the |
| * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "mpegts.h" |
| #include "gstmpegts-private.h" |
| |
| |
| /** |
| * SECTION:gst-dvb-descriptor |
| * @title: DVB variants of MPEG-TS descriptors |
| * @short_description: Descriptors for the various DVB specifications |
| * @include: gst/mpegts/mpegts.h |
| * |
| */ |
| |
| /* |
| * TODO |
| * |
| * * Add common validation code for data presence and minimum/maximum expected |
| * size. |
| * * Add parsing methods for the following descriptors that were previously |
| * handled in mpegtsbase: |
| * * GST_MTS_DESC_DVB_DATA_BROADCAST_ID |
| * * GST_MTS_DESC_DVB_DATA_BROADCAST |
| * * GST_MTS_DESC_DVB_CAROUSEL_IDENTIFIER |
| * * GST_MTS_DESC_DVB_STREAM_IDENTIFIER |
| * * GST_MTS_DESC_DVB_EXTENDED_EVENT |
| * * GST_MTS_DESC_DVB_COMPONENT |
| * * GST_MTS_DESC_DVB_TERRESTRIAL_DELIVERY_SYSTEM |
| * * GST_MTS_DESC_DVB_FREQUENCY_LIST |
| */ |
| |
| |
| /* GST_MTS_DESC_DVB_NETWORK_NAME (0x40) */ |
| /** |
| * gst_mpegts_descriptor_parse_dvb_network_name: |
| * @descriptor: a %GST_MTS_DESC_DVB_NETWORK_NAME #GstMpegTsDescriptor |
| * @name: (out) (transfer full): the extracted name |
| * |
| * Parses out the dvb network name from the @descriptor: |
| * |
| * Returns: %TRUE if the parsing happened correctly, else %FALSE. |
| */ |
| gboolean |
| gst_mpegts_descriptor_parse_dvb_network_name (const GstMpegTsDescriptor * |
| descriptor, gchar ** name) |
| { |
| g_return_val_if_fail (descriptor != NULL && descriptor->data != NULL, FALSE); |
| g_return_val_if_fail (descriptor->tag == 0x40, FALSE); |
| |
| *name = get_encoding_and_convert ((gchar *) descriptor->data + 2, |
| descriptor->data[1]); |
| return TRUE; |
| } |
| |
| /* GST_MTS_DESC_DVB_SATELLITE_DELIVERY_SYSTEM (0x43) */ |
| /** |
| * gst_mpegts_descriptor_parse_satellite_delivery_system: |
| * @descriptor: a %GST_MTS_DESC_DVB_SATELLITE_DELIVERY_SYSTEM #GstMpegTsDescriptor |
| * @res: (out) (transfer none): the #GstMpegTsSatelliteDeliverySystemDescriptor to fill |
| * |
| * Extracts the satellite delivery system information from @descriptor. |
| * |
| * Returns: %TRUE if parsing succeeded, else %FALSE. |
| */ |
| gboolean |
| gst_mpegts_descriptor_parse_satellite_delivery_system (const GstMpegTsDescriptor |
| * descriptor, GstMpegTsSatelliteDeliverySystemDescriptor * res) |
| { |
| guint8 *data; |
| guint8 tmp; |
| |
| g_return_val_if_fail (descriptor != NULL && descriptor->data != NULL, FALSE); |
| g_return_val_if_fail (res != NULL, FALSE); |
| g_return_val_if_fail (descriptor->tag == 0x43, FALSE); |
| |
| data = (guint8 *) descriptor->data + 2; |
| |
| #define BCD_UN(a) ((a) & 0x0f) |
| #define BCD_DEC(a) (((a) >> 4) & 0x0f) |
| #define BCD(a) (BCD_UN(a) + 10 * BCD_DEC(a)) |
| #define BCD_16(a) (BCD(a[1]) + 100 * BCD(a[0])) |
| #define BCD_28(a) (BCD_DEC(a[3]) + 10 * BCD(a[2]) + 1000 * BCD(a[1]) + 100000 * BCD(a[0])) |
| #define BCD_32(a) (BCD(a[3]) + 100 * BCD(a[2]) + 10000 * BCD(a[1]) + 1000000 * BCD(a[0])) |
| |
| /* BCD coded frequency in GHz (decimal point occurs after the 3rd character) |
| * So direct BCD gives us units of (GHz / 100 000) = 10 kHz*/ |
| res->frequency = BCD_32 (data) * 10; |
| data += 4; |
| /* BCD codec position in degrees (float pointer after the 3rd character) */ |
| res->orbital_position = (BCD_16 (data)) / 10.0; |
| data += 2; |
| |
| tmp = *data; |
| res->west_east = (tmp & 0x80) == 0x80; |
| res->polarization = (tmp >> 7) & 0x03; |
| res->modulation_system = (tmp & 0x04) == 0x04; |
| if (res->modulation_system) |
| res->roll_off = (tmp >> 3 & 0x03); |
| else |
| res->roll_off = GST_MPEGTS_ROLLOFF_AUTO; |
| switch (tmp & 0x03) { |
| case 0x00: |
| res->modulation_type = GST_MPEGTS_MODULATION_QAM_AUTO; |
| break; |
| case 0x01: |
| res->modulation_type = GST_MPEGTS_MODULATION_QPSK; |
| break; |
| case 0x10: |
| res->modulation_type = GST_MPEGTS_MODULATION_PSK_8; |
| break; |
| case 0x11: |
| res->modulation_type = GST_MPEGTS_MODULATION_QAM_16; |
| break; |
| default: |
| break; |
| } |
| res->modulation_type = tmp & 0x03; |
| data += 1; |
| /* symbol_rate is in Msymbols/ (decimal point occurs after 3rd character) */ |
| /* So direct BCD gives us units of (Msymbol / 10 000) = 100 sym/s */ |
| res->symbol_rate = BCD_28 (data) * 100; |
| data += 3; |
| /* fec_inner */ |
| res->fec_inner = *data >> 4; |
| |
| |
| return TRUE; |
| } |
| |
| |
| /* GST_MTS_DESC_DVB_CABLE_DELIVERY_SYSTEM (0x44) */ |
| /** |
| * gst_mpegts_descriptor_parse_cable_delivery_system: |
| * @descriptor: a %GST_MTS_DESC_DVB_CABLE_DELIVERY_SYSTEM #GstMpegTsDescriptor |
| * @res: (out) (transfer none): the #GstMpegTsCableDeliverySystemDescriptor to fill |
| * |
| * Extracts the cable delivery system information from @descriptor. |
| * |
| * Returns: %TRUE if parsing succeeded, else %FALSE. |
| */ |
| gboolean |
| gst_mpegts_descriptor_parse_cable_delivery_system (const GstMpegTsDescriptor * |
| descriptor, GstMpegTsCableDeliverySystemDescriptor * res) |
| { |
| guint8 *data; |
| |
| g_return_val_if_fail (descriptor != NULL && descriptor->data != NULL, FALSE); |
| g_return_val_if_fail (res != NULL, FALSE); |
| g_return_val_if_fail (descriptor->tag == 0x44, FALSE); |
| |
| data = (guint8 *) descriptor->data + 2; |
| /* BCD in MHz, decimal place after the fourth character */ |
| res->frequency = BCD_32 (data) * 100; |
| data += 5; |
| /* fec_out (4bits) */ |
| res->outer_fec = *data++ & 0x0f; |
| switch (*data) { |
| case 0x00: |
| res->modulation = GST_MPEGTS_MODULATION_NONE; |
| break; |
| case 0x01: |
| res->modulation = GST_MPEGTS_MODULATION_QAM_16; |
| break; |
| case 0x02: |
| res->modulation = GST_MPEGTS_MODULATION_QAM_32; |
| break; |
| case 0x03: |
| res->modulation = GST_MPEGTS_MODULATION_QAM_64; |
| break; |
| case 0x04: |
| res->modulation = GST_MPEGTS_MODULATION_QAM_128; |
| break; |
| case 0x05: |
| res->modulation = GST_MPEGTS_MODULATION_QAM_256; |
| break; |
| default: |
| GST_WARNING ("Unsupported cable modulation type: 0x%02x", *data); |
| res->modulation = GST_MPEGTS_MODULATION_NONE; |
| break; |
| } |
| |
| data += 1; |
| /* symbol_rate is in Msymbols/ (decimal point occurs after 3rd character) */ |
| /* So direct BCD gives us units of (Msymbol / 10 000) = 100 sym/s */ |
| res->symbol_rate = BCD_28 (data) * 100; |
| data += 3; |
| /* fec_inner */ |
| res->fec_inner = *data & 0x0f; |
| |
| return TRUE; |
| } |
| |
| /* GST_MTS_DESC_DVB_SERVICE (0x48) */ |
| /** |
| * gst_mpegts_descriptor_parse_dvb_service: |
| * @descriptor: a %GST_MTS_DESC_DVB_SERVICE #GstMpegTsDescriptor |
| * @service_type: (out) (allow-none): the service type |
| * @service_name: (out) (transfer full) (allow-none): the service name |
| * @provider_name: (out) (transfer full) (allow-none): the provider name |
| * |
| * Extracts the dvb service information from @descriptor. |
| * |
| * Returns: %TRUE if parsing succeeded, else %FALSE. |
| */ |
| gboolean |
| gst_mpegts_descriptor_parse_dvb_service (const GstMpegTsDescriptor * |
| descriptor, GstMpegTsDVBServiceType * service_type, gchar ** service_name, |
| gchar ** provider_name) |
| { |
| guint8 *data; |
| |
| g_return_val_if_fail (descriptor != NULL && descriptor->data != NULL, FALSE); |
| g_return_val_if_fail (descriptor->tag == 0x48, FALSE); |
| |
| data = (guint8 *) descriptor->data + 2; |
| |
| if (service_type) |
| *service_type = *data; |
| data += 1; |
| if (provider_name) |
| *provider_name = get_encoding_and_convert ((const gchar *) data + 1, *data); |
| data += *data + 1; |
| if (service_name) |
| *service_name = get_encoding_and_convert ((const gchar *) data + 1, *data); |
| |
| return TRUE; |
| } |
| |
| /* GST_MTS_DESC_DVB_SHORT_EVENT (0x4D) */ |
| /** |
| * gst_mpegts_descriptor_parse_dvb_short_event: |
| * @descriptor: a %GST_MTS_DESC_DVB_SHORT_EVENT #GstMpegTsDescriptor |
| * @language_code: (out) (transfer full) (allow-none): the language code |
| * @event_name: (out) (transfer full) (allow-none): the event name |
| * @text: (out) (transfer full) (allow-none): the event text |
| * |
| * Extracts the DVB short event information from @descriptor. |
| * |
| * Returns: %TRUE if parsing succeeded, else %FALSE. |
| */ |
| gboolean |
| gst_mpegts_descriptor_parse_dvb_short_event (const GstMpegTsDescriptor * |
| descriptor, gchar ** language_code, gchar ** event_name, gchar ** text) |
| { |
| guint8 *data; |
| |
| g_return_val_if_fail (descriptor != NULL && descriptor->data != NULL, FALSE); |
| g_return_val_if_fail (descriptor->tag == 0x4D, FALSE); |
| |
| data = (guint8 *) descriptor->data + 2; |
| |
| if (language_code) { |
| *language_code = g_malloc0 (4); |
| memcpy (*language_code, data, 3); |
| } |
| data += 3; |
| if (event_name) |
| *event_name = get_encoding_and_convert ((const gchar *) data + 1, *data); |
| data += *data + 1; |
| if (text) |
| *text = get_encoding_and_convert ((const gchar *) data + 1, *data); |
| return TRUE; |
| } |