diff options
Diffstat (limited to 'ext/cdio/gstcdiocddasrc.c')
-rw-r--r-- | ext/cdio/gstcdiocddasrc.c | 127 |
1 files changed, 125 insertions, 2 deletions
diff --git a/ext/cdio/gstcdiocddasrc.c b/ext/cdio/gstcdiocddasrc.c index 830839e..a13d908 100644 --- a/ext/cdio/gstcdiocddasrc.c +++ b/ext/cdio/gstcdiocddasrc.c @@ -13,8 +13,8 @@ * * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ /** @@ -85,6 +85,8 @@ #include <string.h> #include <errno.h> +#define SAMPLES_PER_SECTOR (CDIO_CD_FRAMESIZE_RAW / sizeof (gint16)) + #define DEFAULT_READ_SPEED -1 enum @@ -179,6 +181,14 @@ gst_cdio_cdda_src_read_sector (GstAudioCdSrc * audiocdsrc, gint sector) if (cdio_read_audio_sector (src->cdio, data, sector) != 0) goto read_failed; + if (src->swap_le_be) { + gint16 *pcm_data = (gint16 *) data; + gint i; + + for (i = 0; i < SAMPLES_PER_SECTOR; ++i) + pcm_data[i] = GUINT16_SWAP_LE_BE (pcm_data[i]); + } + return gst_buffer_new_wrapped (data, CDIO_CD_FRAMESIZE_RAW); /* ERRORS */ @@ -195,6 +205,106 @@ read_failed: } static gboolean +gst_cdio_cdda_src_do_detect_drive_endianness (GstCdioCddaSrc * src, gint from, + gint to) +{ + gint16 pcm_data[SAMPLES_PER_SECTOR], last_pcm_ne, last_pcm_oe; + gdouble ne_sumd0, ne_sumd1, ne_factor; + gdouble oe_sumd0, oe_sumd1, oe_factor; + gdouble diff; + gint sector; + gint i; + + ne_sumd0 = ne_sumd1 = 0.0; + oe_sumd0 = oe_sumd1 = 0.0; + last_pcm_ne = 0; + last_pcm_oe = 0; + + GST_LOG_OBJECT (src, "checking sector %d to %d", from, to); + + for (sector = from; sector < to; ++sector) { + if (cdio_read_audio_sector (src->cdio, pcm_data, sector) != 0) + goto read_failed; + + /* only evaluate samples for left channel */ + for (i = 0; i < SAMPLES_PER_SECTOR; i += 2) { + gint16 pcm; + + /* Native endianness first */ + pcm = pcm_data[i]; + ne_sumd0 += abs (pcm); + ne_sumd1 += abs (pcm - last_pcm_ne); + last_pcm_ne = pcm; + + /* other endianness next */ + pcm = GUINT16_SWAP_LE_BE (pcm); + oe_sumd0 += abs (pcm); + oe_sumd1 += abs (pcm - last_pcm_oe); + last_pcm_oe = pcm; + } + + } + + ne_factor = (ne_sumd1 / ne_sumd0); + oe_factor = (oe_sumd1 / oe_sumd0); + diff = ne_factor - oe_factor; + + GST_DEBUG_OBJECT (src, "Native: %.2f, Other: %.2f, diff: %.2f", + ne_factor, oe_factor, diff); + + if (diff > 0.5) { + GST_INFO_OBJECT (src, "Drive produces samples in other endianness"); + src->swap_le_be = TRUE; + return TRUE; + } else if (diff < -0.5) { + GST_INFO_OBJECT (src, "Drive produces samples in host endianness"); + src->swap_le_be = FALSE; + return TRUE; + } else { + GST_INFO_OBJECT (src, "Inconclusive, assuming host endianness"); + src->swap_le_be = FALSE; + return FALSE; + } + +/* ERRORS */ +read_failed: + { + GST_WARNING_OBJECT (src, "could not read sector %d", sector); + src->swap_le_be = FALSE; + return FALSE; + } +} + +static void +gst_cdio_cdda_src_detect_drive_endianness (GstCdioCddaSrc * src, gint first, + gint last) +{ + gint from, to; + + GST_INFO ("Detecting drive endianness"); + + /* try middle of disc first */ + from = (first + last) / 2; + to = MIN (from + 10, last); + if (gst_cdio_cdda_src_do_detect_drive_endianness (src, from, to)) + return; + + /* if that was inconclusive, try other places */ + from = (first + last) / 4; + to = MIN (from + 10, last); + if (gst_cdio_cdda_src_do_detect_drive_endianness (src, from, to)) + return; + + from = (first + last) * 3 / 4; + to = MIN (from + 10, last); + if (gst_cdio_cdda_src_do_detect_drive_endianness (src, from, to)) + return; + + /* if that's still inconclusive, we give up and assume host endianness */ + return; +} + +static gboolean notcdio_track_is_audio_track (const CdIo * p_cdio, track_t i_track) { return (cdio_get_track_format (p_cdio, i_track) == TRACK_FORMAT_AUDIO); @@ -206,6 +316,7 @@ gst_cdio_cdda_src_open (GstAudioCdSrc * audiocdsrc, const gchar * device) GstCdioCddaSrc *src; discmode_t discmode; gint first_track, num_tracks, i; + gint first_audio_sector = 0, last_audio_sector = 0; #if LIBCDIO_VERSION_NUM > 83 cdtext_t *cdtext; #endif @@ -263,6 +374,11 @@ gst_cdio_cdda_src_open (GstAudioCdSrc * audiocdsrc, const gchar * device) * the right thing here (for cddb id calculations etc. as well) */ track.start = cdio_get_track_lsn (src->cdio, i + first_track); track.end = track.start + len_sectors - 1; /* -1? */ + + if (track.is_audio) { + first_audio_sector = MIN (first_audio_sector, track.start); + last_audio_sector = MAX (last_audio_sector, track.end); + } #if LIBCDIO_VERSION_NUM > 83 if (NULL != cdtext) track.tags = gst_cdio_get_cdtext (GST_OBJECT (src), cdtext, @@ -274,6 +390,13 @@ gst_cdio_cdda_src_open (GstAudioCdSrc * audiocdsrc, const gchar * device) gst_audio_cd_src_add_track (GST_AUDIO_CD_SRC (src), &track); } + + /* Try to detect if we need to byte-order swap the samples coming from the + * drive, which might be the case if the CD drive operates in a different + * endianness than the host CPU's endianness (happens on e.g. Powerbook G4) */ + gst_cdio_cdda_src_detect_drive_endianness (src, first_audio_sector, + last_audio_sector); + return TRUE; /* ERRORS */ |