gst_plugins_base/gst-libs/gst/cdda/gstcddabasesrc.c
changeset 16 8e837d1bf446
parent 0 0e761a78d257
child 30 7e817e7e631c
equal deleted inserted replaced
15:4b0c6ed43234 16:8e837d1bf446
    79  * among others.
    79  * among others.
    80  * </para>
    80  * </para>
    81  * </refsect2>
    81  * </refsect2>
    82  */
    82  */
    83 
    83 
    84 
       
    85 #ifdef HAVE_CONFIG_H
    84 #ifdef HAVE_CONFIG_H
    86 #include "config.h"
    85 #include "config.h"
    87 #endif
    86 #endif
    88 
    87 
    89 #include <string.h>
    88 #include <string.h>
    90 #include <stdlib.h>             /* for strtol */
    89 #include <stdlib.h>             /* for strtol */
    91 
    90 
    92 #include "gstcddabasesrc.h"
    91 #include "gstcddabasesrc.h"
    93 #include "gst/gst-i18n-plugin.h"
    92 #include "gst/gst-i18n-plugin.h"
    94 
       
    95 #ifdef __SYMBIAN32__
       
    96 #include <glib_global.h>
       
    97 #endif
       
    98 
    93 
    99 GST_DEBUG_CATEGORY_STATIC (gst_cdda_base_src_debug);
    94 GST_DEBUG_CATEGORY_STATIC (gst_cdda_base_src_debug);
   100 #define GST_CAT_DEFAULT gst_cdda_base_src_debug
    95 #define GST_CAT_DEFAULT gst_cdda_base_src_debug
   101 
    96 
   102 #define DEFAULT_DEVICE                       "/dev/cdrom"
    97 #define DEFAULT_DEVICE                       "/dev/cdrom"
   106 #define SECTORS_PER_SECOND                   (75)
   101 #define SECTORS_PER_SECOND                   (75)
   107 #define SECTORS_PER_MINUTE                   (75*60)
   102 #define SECTORS_PER_MINUTE                   (75*60)
   108 #define SAMPLES_PER_SECTOR                   (CD_FRAMESIZE_RAW >> 2)
   103 #define SAMPLES_PER_SECTOR                   (CD_FRAMESIZE_RAW >> 2)
   109 #define TIME_INTERVAL_FROM_SECTORS(sectors)  ((SAMPLES_PER_SECTOR * sectors * GST_SECOND) / 44100)
   104 #define TIME_INTERVAL_FROM_SECTORS(sectors)  ((SAMPLES_PER_SECTOR * sectors * GST_SECOND) / 44100)
   110 #define SECTORS_FROM_TIME_INTERVAL(dtime)    (dtime * 44100 / (SAMPLES_PER_SECTOR * GST_SECOND))
   105 #define SECTORS_FROM_TIME_INTERVAL(dtime)    (dtime * 44100 / (SAMPLES_PER_SECTOR * GST_SECOND))
   111 
       
   112 #define GST_TYPE_CDDA_BASE_SRC_MODE          (gst_cdda_base_src_mode_get_type ())
       
   113 
   106 
   114 enum
   107 enum
   115 {
   108 {
   116   ARG_0,
   109   ARG_0,
   117   ARG_MODE,
   110   ARG_MODE,
   162     );
   155     );
   163 
   156 
   164 /* our two formats */
   157 /* our two formats */
   165 static GstFormat track_format;
   158 static GstFormat track_format;
   166 static GstFormat sector_format;
   159 static GstFormat sector_format;
   167 
   160 #ifdef __SYMBIAN32__
   168 static GType
   161 EXPORT_C
       
   162 #endif
       
   163 
       
   164 
       
   165 GType
   169 gst_cdda_base_src_mode_get_type (void)
   166 gst_cdda_base_src_mode_get_type (void)
   170 {
   167 {
   171   static GType mode_type;       /* 0 */
   168   static GType mode_type;       /* 0 */
   172   static const GEnumValue modes[] = {
   169   static const GEnumValue modes[] = {
   173     {GST_CDDA_BASE_SRC_MODE_NORMAL, "Stream consists of a single track",
   170     {GST_CDDA_BASE_SRC_MODE_NORMAL, "Stream consists of a single track",
   224   gobject_class->get_property = gst_cdda_base_src_get_property;
   221   gobject_class->get_property = gst_cdda_base_src_get_property;
   225   gobject_class->finalize = gst_cdda_base_src_finalize;
   222   gobject_class->finalize = gst_cdda_base_src_finalize;
   226 
   223 
   227   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DEVICE,
   224   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DEVICE,
   228       g_param_spec_string ("device", "Device", "CD device location",
   225       g_param_spec_string ("device", "Device", "CD device location",
   229           NULL, G_PARAM_READWRITE));
   226           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   230   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MODE,
   227   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MODE,
   231       g_param_spec_enum ("mode", "Mode", "Mode", GST_TYPE_CDDA_BASE_SRC_MODE,
   228       g_param_spec_enum ("mode", "Mode", "Mode", GST_TYPE_CDDA_BASE_SRC_MODE,
   232           GST_CDDA_BASE_SRC_MODE_NORMAL, G_PARAM_READWRITE));
   229           GST_CDDA_BASE_SRC_MODE_NORMAL,
       
   230           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   233 
   231 
   234   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TRACK,
   232   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TRACK,
   235       g_param_spec_uint ("track", "Track", "Track", 1, 99, 1,
   233       g_param_spec_uint ("track", "Track", "Track", 1, 99, 1,
   236           G_PARAM_READWRITE));
   234           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   237 
   235 
   238 #if 0
   236 #if 0
   239   /* Do we really need this toc adjustment stuff as properties? does the user
   237   /* Do we really need this toc adjustment stuff as properties? does the user
   240    * have a chance to set it in practice, e.g. when using sound-juicer, rb,
   238    * have a chance to set it in practice, e.g. when using sound-juicer, rb,
   241    * totem, whatever? Shouldn't we rather use environment variables
   239    * totem, whatever? Shouldn't we rather use environment variables
   242    * for this? (tpm) */
   240    * for this? (tpm) */
   243 
   241 
   244   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TOC_OFFSET,
   242   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TOC_OFFSET,
   245       g_param_spec_int ("toc-offset", "Table of contents offset",
   243       g_param_spec_int ("toc-offset", "Table of contents offset",
   246           "Add <n> sectors to the values reported", G_MININT, G_MAXINT, 0,
   244           "Add <n> sectors to the values reported", G_MININT, G_MAXINT, 0,
   247           G_PARAM_READWRITE));
   245           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   248   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TOC_BIAS,
   246   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TOC_BIAS,
   249       g_param_spec_boolean ("toc-bias", "Table of contents bias",
   247       g_param_spec_boolean ("toc-bias", "Table of contents bias",
   250           "Assume that the beginning offset of track 1 as reported in the TOC "
   248           "Assume that the beginning offset of track 1 as reported in the TOC "
   251           "will be addressed as LBA 0.  Necessary for some Toshiba drives to "
   249           "will be addressed as LBA 0.  Necessary for some Toshiba drives to "
   252           "get track boundaries", FALSE, G_PARAM_READWRITE));
   250           "get track boundaries", FALSE,
       
   251           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   253 #endif
   252 #endif
   254 
   253 
   255   element_class->set_index = GST_DEBUG_FUNCPTR (gst_cdda_base_src_set_index);
   254   element_class->set_index = GST_DEBUG_FUNCPTR (gst_cdda_base_src_set_index);
   256   element_class->get_index = GST_DEBUG_FUNCPTR (gst_cdda_base_src_get_index);
   255   element_class->get_index = GST_DEBUG_FUNCPTR (gst_cdda_base_src_get_index);
   257 
   256 
   878       }
   877       }
   879       break;
   878       break;
   880     }
   879     }
   881     default:{
   880     default:{
   882       GST_LOG_OBJECT (src, "let base class handle event");
   881       GST_LOG_OBJECT (src, "let base class handle event");
   883       event = gst_event_ref (event);
       
   884       ret = GST_BASE_SRC_CLASS (parent_class)->event (basesrc, event);
   882       ret = GST_BASE_SRC_CLASS (parent_class)->event (basesrc, event);
   885       break;
   883       break;
   886     }
   884     }
   887   }
   885   }
   888 
   886 
  1032       track->end, (track->is_audio) ? "AUDIO" : "DATA ", track->tags);
  1030       track->end, (track->is_audio) ? "AUDIO" : "DATA ", track->tags);
  1033 
  1031 
  1034   if (src->num_tracks > 0) {
  1032   if (src->num_tracks > 0) {
  1035     guint end_of_previous_track = src->tracks[src->num_tracks - 1].end;
  1033     guint end_of_previous_track = src->tracks[src->num_tracks - 1].end;
  1036 
  1034 
  1037     if (track->start < end_of_previous_track) {
  1035     if (track->start <= end_of_previous_track) {
  1038       GST_WARNING ("track %2u overlaps with previous tracks", track->num);
  1036       GST_WARNING ("track %2u overlaps with previous tracks", track->num);
  1039       return FALSE;
  1037       return FALSE;
  1040     }
  1038     }
  1041   }
  1039   }
  1042 
  1040 
  1089     n /= 10;
  1087     n /= 10;
  1090   }
  1088   }
  1091   return ret;
  1089   return ret;
  1092 }
  1090 }
  1093 
  1091 
  1094 #include "base64.h"
       
  1095 #include "sha1.h"
       
  1096 
       
  1097 static void
  1092 static void
  1098 gst_cddabasesrc_calculate_musicbrainz_discid (GstCddaBaseSrc * src)
  1093 gst_cddabasesrc_calculate_musicbrainz_discid (GstCddaBaseSrc * src)
  1099 {
  1094 {
  1100   GString *s;
  1095   GString *s;
  1101   SHA_INFO sha;
  1096   GChecksum *sha;
  1102   guchar digest[20], *ptr;
  1097   guchar digest[20];
       
  1098   gchar *ptr;
  1103   gchar tmp[9];
  1099   gchar tmp[9];
  1104   gulong i;
  1100   gulong i;
  1105   guint leadout_sector;
  1101   guint leadout_sector;
       
  1102   gsize digest_len;
  1106 
  1103 
  1107   s = g_string_new (NULL);
  1104   s = g_string_new (NULL);
  1108 
  1105 
  1109   leadout_sector = src->tracks[src->num_tracks - 1].end + 1 + CD_MSF_OFFSET;
  1106   leadout_sector = src->tracks[src->num_tracks - 1].end + 1 + CD_MSF_OFFSET;
  1110 
  1107 
  1111   /* generate SHA digest */
  1108   /* generate SHA digest */
  1112   sha_init (&sha);
  1109   sha = g_checksum_new (G_CHECKSUM_SHA1);
  1113   g_snprintf (tmp, sizeof (tmp), "%02X", src->tracks[0].num);
  1110   g_snprintf (tmp, sizeof (tmp), "%02X", src->tracks[0].num);
  1114   g_string_append_printf (s, "%02X", src->tracks[0].num);
  1111   g_string_append_printf (s, "%02X", src->tracks[0].num);
  1115   sha_update (&sha, (SHA_BYTE *) tmp, 2);
  1112   g_checksum_update (sha, (guchar *) tmp, 2);
  1116 
  1113 
  1117   g_snprintf (tmp, sizeof (tmp), "%02X", src->tracks[src->num_tracks - 1].num);
  1114   g_snprintf (tmp, sizeof (tmp), "%02X", src->tracks[src->num_tracks - 1].num);
  1118   g_string_append_printf (s, " %02X", src->tracks[src->num_tracks - 1].num);
  1115   g_string_append_printf (s, " %02X", src->tracks[src->num_tracks - 1].num);
  1119   sha_update (&sha, (SHA_BYTE *) tmp, 2);
  1116   g_checksum_update (sha, (guchar *) tmp, 2);
  1120 
  1117 
  1121   g_snprintf (tmp, sizeof (tmp), "%08X", leadout_sector);
  1118   g_snprintf (tmp, sizeof (tmp), "%08X", leadout_sector);
  1122   g_string_append_printf (s, " %08X", leadout_sector);
  1119   g_string_append_printf (s, " %08X", leadout_sector);
  1123   sha_update (&sha, (SHA_BYTE *) tmp, 8);
  1120   g_checksum_update (sha, (guchar *) tmp, 8);
  1124 
  1121 
  1125   for (i = 0; i < 99; i++) {
  1122   for (i = 0; i < 99; i++) {
  1126     if (i < src->num_tracks) {
  1123     if (i < src->num_tracks) {
  1127       guint frame_offset = src->tracks[i].start + CD_MSF_OFFSET;
  1124       guint frame_offset = src->tracks[i].start + CD_MSF_OFFSET;
  1128 
  1125 
  1129       g_snprintf (tmp, sizeof (tmp), "%08X", frame_offset);
  1126       g_snprintf (tmp, sizeof (tmp), "%08X", frame_offset);
  1130       g_string_append_printf (s, " %08X", frame_offset);
  1127       g_string_append_printf (s, " %08X", frame_offset);
  1131       sha_update (&sha, (SHA_BYTE *) tmp, 8);
  1128       g_checksum_update (sha, (guchar *) tmp, 8);
  1132     } else {
  1129     } else {
  1133       sha_update (&sha, (SHA_BYTE *) "00000000", 8);
  1130       g_checksum_update (sha, (guchar *) "00000000", 8);
  1134     }
  1131     }
  1135   }
  1132   }
  1136   sha_final (digest, &sha);
  1133   digest_len = 20;
       
  1134   g_checksum_get_digest (sha, (guint8 *) & digest, &digest_len);
  1137 
  1135 
  1138   /* re-encode to base64 */
  1136   /* re-encode to base64 */
  1139   ptr = rfc822_binary (digest, 20, &i);
  1137   ptr = g_base64_encode (digest, digest_len);
       
  1138   g_checksum_free (sha);
       
  1139   i = strlen (ptr);
  1140 
  1140 
  1141   g_assert (i < sizeof (src->mb_discid) + 1);
  1141   g_assert (i < sizeof (src->mb_discid) + 1);
  1142   memcpy (src->mb_discid, ptr, i);
  1142   memcpy (src->mb_discid, ptr, i);
  1143   src->mb_discid[i] = '\0';
  1143   src->mb_discid[i] = '\0';
  1144   free (ptr);
  1144   free (ptr);
       
  1145 
       
  1146   /* Replace '/', '+' and '=' by '_', '.' and '-' as specified on
       
  1147    * http://musicbrainz.org/doc/DiscIDCalculation
       
  1148    */
       
  1149   for (ptr = src->mb_discid; *ptr != '\0'; ptr++) {
       
  1150     if (*ptr == '/')
       
  1151       *ptr = '_';
       
  1152     else if (*ptr == '+')
       
  1153       *ptr = '.';
       
  1154     else if (*ptr == '=')
       
  1155       *ptr = '-';
       
  1156   }
  1145 
  1157 
  1146   GST_DEBUG_OBJECT (src, "musicbrainz-discid      = %s", src->mb_discid);
  1158   GST_DEBUG_OBJECT (src, "musicbrainz-discid      = %s", src->mb_discid);
  1147   GST_DEBUG_OBJECT (src, "musicbrainz-discid-full = %s", s->str);
  1159   GST_DEBUG_OBJECT (src, "musicbrainz-discid-full = %s", s->str);
  1148 
  1160 
  1149   gst_tag_list_add (src->tags, GST_TAG_MERGE_REPLACE,
  1161   gst_tag_list_add (src->tags, GST_TAG_MERGE_REPLACE,
  1266     num_sectors = src->tracks[i].end - src->tracks[i].start + 1;
  1278     num_sectors = src->tracks[i].end - src->tracks[i].start + 1;
  1267     gst_cdda_base_src_convert (src, sector_format, num_sectors,
  1279     gst_cdda_base_src_convert (src, sector_format, num_sectors,
  1268         GST_FORMAT_TIME, &duration);
  1280         GST_FORMAT_TIME, &duration);
  1269 
  1281 
  1270     gst_tag_list_add (src->tracks[i].tags,
  1282     gst_tag_list_add (src->tracks[i].tags,
  1271         GST_TAG_MERGE_REPLACE_ALL,
  1283         GST_TAG_MERGE_REPLACE,
  1272         GST_TAG_TRACK_NUMBER, i + 1,
  1284         GST_TAG_TRACK_NUMBER, i + 1,
  1273         GST_TAG_TRACK_COUNT, src->num_tracks, GST_TAG_DURATION, duration, NULL);
  1285         GST_TAG_TRACK_COUNT, src->num_tracks, GST_TAG_DURATION, duration, NULL);
  1274   }
  1286   }
  1275 
  1287 
  1276   /* now fill in per-album tags and include each track's tags
  1288   /* now fill in per-album tags and include each track's tags
  1280   /* /////////////////////////////// FIXME should we rather insert num_tracks
  1292   /* /////////////////////////////// FIXME should we rather insert num_tracks
  1281    * tags by the name of 'track-tags' and have the caller use
  1293    * tags by the name of 'track-tags' and have the caller use
  1282    * gst_tag_list_get_value_index() rather than use tag names incl.
  1294    * gst_tag_list_get_value_index() rather than use tag names incl.
  1283    * the track number ?? *////////////////////////////////////////
  1295    * the track number ?? *////////////////////////////////////////
  1284 
  1296 
  1285   gst_tag_list_add (src->tags, GST_TAG_MERGE_REPLACE_ALL,
  1297   gst_tag_list_add (src->tags, GST_TAG_MERGE_REPLACE,
  1286       GST_TAG_TRACK_COUNT, src->num_tracks, NULL);
  1298       GST_TAG_TRACK_COUNT, src->num_tracks, NULL);
  1287 #if 0
  1299 #if 0
  1288   for (i = 0; i < src->num_tracks; ++i) {
  1300   for (i = 0; i < src->num_tracks; ++i) {
  1289     gst_tag_list_add (src->tags, GST_TAG_MERGE_APPEND,
  1301     gst_tag_list_add (src->tags, GST_TAG_MERGE_APPEND,
  1290         GST_TAG_CDDA_TRACK_TAGS, src->tracks[i].tags, NULL);
  1302         GST_TAG_CDDA_TRACK_TAGS, src->tracks[i].tags, NULL);
  1509 
  1521 
  1510   g_assert (klass->read_sector != NULL);
  1522   g_assert (klass->read_sector != NULL);
  1511 
  1523 
  1512   switch (src->mode) {
  1524   switch (src->mode) {
  1513     case GST_CDDA_BASE_SRC_MODE_NORMAL:
  1525     case GST_CDDA_BASE_SRC_MODE_NORMAL:
  1514       eos = (src->cur_sector >= src->tracks[src->cur_track].end);
  1526       eos = (src->cur_sector > src->tracks[src->cur_track].end);
  1515       break;
  1527       break;
  1516     case GST_CDDA_BASE_SRC_MODE_CONTINUOUS:
  1528     case GST_CDDA_BASE_SRC_MODE_CONTINUOUS:
  1517       eos = (src->cur_sector >= src->tracks[src->num_tracks - 1].end);
  1529       eos = (src->cur_sector > src->tracks[src->num_tracks - 1].end);
  1518       src->cur_track = gst_cdda_base_src_get_track_from_sector (src,
  1530       src->cur_track = gst_cdda_base_src_get_track_from_sector (src,
  1519           src->cur_sector);
  1531           src->cur_sector);
  1520       break;
  1532       break;
  1521     default:
  1533     default:
  1522       g_return_val_if_reached (GST_FLOW_ERROR);
  1534       g_return_val_if_reached (GST_FLOW_ERROR);