mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
cdiocddasrc: detect whether drive produces samples in non-host endianness
If drive produces samples in other endianness than the host, we need to byte swap them before pushing them out, or we produce nothing but noise. cdparanoia detects this automatically, but libcdio does not, so we have to do it ourselves. This is needed on e.g. the PowerBook G4 with Matshita UJ-816 drive. https://bugzilla.gnome.org/show_bug.cgi?id=377280
This commit is contained in:
parent
a4d74604d4
commit
1ab41f83b7
2 changed files with 125 additions and 0 deletions
|
@ -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 */
|
||||
|
@ -194,6 +204,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)
|
||||
{
|
||||
|
@ -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 */
|
||||
|
|
|
@ -38,6 +38,8 @@ struct _GstCdioCddaSrc
|
|||
|
||||
gint read_speed; /* ATOMIC */
|
||||
|
||||
gboolean swap_le_be; /* Drive produces samples in other endianness */
|
||||
|
||||
CdIo *cdio; /* NULL if not open */
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue