Bug 68804: Properly parse WAV files, r+sr=roc

This commit is contained in:
flamingice%sourmilk.net 2006-08-17 16:52:41 +00:00
Родитель fdd916ee80
Коммит dc3cd411d5
1 изменённых файлов: 81 добавлений и 50 удалений

Просмотреть файл

@ -166,9 +166,10 @@ NS_IMETHODIMP nsSound::OnStreamComplete(nsIStreamLoader *aLoader,
}
int fd, mask = 0;
unsigned long samples_per_sec=0, avg_bytes_per_sec=0;
unsigned long rate=0;
unsigned short format, channels = 1, block_align, bits_per_sample=0;
PRUint32 samples_per_sec = 0, avg_bytes_per_sec = 0, chunk_len = 0;
PRUint16 format, channels = 1, bits_per_sample = 0;
const PRUint8 *audio = nsnull;
size_t audio_len = 0;
if (memcmp(data, "RIFF", 4)) {
#ifdef DEBUG
@ -182,48 +183,81 @@ NS_IMETHODIMP nsSound::OnStreamComplete(nsIStreamLoader *aLoader,
return NS_ERROR_FAILURE;
}
PRUint32 i;
for (i= 0; i < dataLen; i++) {
if (i+3 <= dataLen)
if ((data[i] == 'f') &&
(data[i+1] == 'm') &&
(data[i+2] == 't') &&
(data[i+3] == ' ')) {
i += 4;
PRUint32 i = 12;
while (i + 7 < dataLen) {
if (!memcmp(data + i, "fmt ", 4) && !chunk_len) {
i += 4;
/* length of the rest of this subblock (should be 16 for PCM data */
i+=4;
format = GET_WORD(data, i);
i+=2;
/* length of the rest of this subblock (should be 16 for PCM data */
chunk_len = GET_DWORD(data, i);
i += 4;
channels = GET_WORD(data, i);
i+=2;
samples_per_sec = GET_DWORD(data, i);
i+=4;
avg_bytes_per_sec = GET_DWORD(data, i);
i+=4;
block_align = GET_WORD(data, i);
i+=2;
bits_per_sample = GET_WORD(data, i);
i+=2;
rate = samples_per_sec;
break;
if (chunk_len < 16 || i + chunk_len >= dataLen) {
NS_WARNING("Invalid WAV file: bad fmt chunk.");
return NS_ERROR_FAILURE;
}
format = GET_WORD(data, i);
i += 2;
channels = GET_WORD(data, i);
i += 2;
samples_per_sec = GET_DWORD(data, i);
i += 4;
avg_bytes_per_sec = GET_DWORD(data, i);
i += 4;
// block align
i += 2;
bits_per_sample = GET_WORD(data, i);
i += 2;
/* we don't support WAVs with odd compression codes */
if (chunk_len != 16)
NS_WARNING("Extra format bits found in WAV. Ignoring");
i += chunk_len - 16;
} else if (!memcmp(data + i, "data", 4)) {
i += 4;
if (!chunk_len) {
NS_WARNING("Invalid WAV file: no fmt chunk found");
return NS_ERROR_FAILURE;
}
audio_len = GET_DWORD(data, i);
i += 4;
/* try to play truncated WAVs */
if (i + audio_len > dataLen)
audio_len = dataLen - i;
audio = data + i;
break;
} else {
i += 4;
i += GET_DWORD(data, i);
i += 4;
}
}
if (!audio) {
NS_WARNING("Invalid WAV file: no data chunk found");
return NS_ERROR_FAILURE;
}
/* No audio data? well, at least the WAV was valid. */
if (!audio_len)
return NS_OK;
#if 0
printf("f: %d | c: %d | sps: %li | abps: %li | ba: %d | bps: %d | rate: %li\n",
format, channels, samples_per_sec, avg_bytes_per_sec, block_align, bits_per_sample, rate);
#endif
/* open up conneciton to esd */
/* open up connection to esd */
EsdPlayStreamType EsdPlayStream =
(EsdPlayStreamType) PR_FindSymbol(elib,
"esd_play_stream");
@ -247,22 +281,19 @@ NS_IMETHODIMP nsSound::OnStreamComplete(nsIStreamLoader *aLoader,
// Swap the byte order if we're on a big-endian architecture.
#ifdef IS_BIG_ENDIAN
if (bits_per_sample != 8) {
buf = new PRUint8[dataLen - WAV_MIN_LENGTH];
// According to the wav file format, the first 44 bytes are headers.
// We don't really need to send them.
buf = new PRUint8[audio_len];
if (!buf)
return NS_ERROR_OUT_OF_MEMORY;
for (PRUint32 j = 0; j < dataLen - WAV_MIN_LENGTH - 1; j += 2) {
buf[j] = data[j + WAV_MIN_LENGTH + 1];
buf[j + 1] = data[j + WAV_MIN_LENGTH];
for (PRUint32 j = 0; j + 2 < audio_len; j += 2) {
buf[j] = audio[j + 1];
buf[j + 1] = audio[j];
}
data = buf;
dataLen -= WAV_MIN_LENGTH;
audio = buf;
}
#endif
fd = (*EsdPlayStream)(mask, rate, NULL, "mozillaSound");
fd = (*EsdPlayStream)(mask, samples_per_sec, NULL, "mozillaSound");
if (fd < 0) {
int *esd_audio_format = (int *) PR_FindSymbol(elib, "esd_audio_format");
@ -272,21 +303,21 @@ NS_IMETHODIMP nsSound::OnStreamComplete(nsIStreamLoader *aLoader,
EsdAudioCloseType EsdAudioClose = (EsdAudioCloseType) PR_FindSymbol(elib, "esd_audio_close");
*esd_audio_format = mask;
*esd_audio_rate = rate;
*esd_audio_rate = samples_per_sec;
fd = (*EsdAudioOpen)();
if (fd < 0)
return NS_ERROR_FAILURE;
(*EsdAudioWrite)(data, dataLen);
(*EsdAudioWrite)(audio, audio_len);
(*EsdAudioClose)();
} else {
while (dataLen > 0) {
size_t written = write(fd, data, dataLen);
while (audio_len > 0) {
size_t written = write(fd, audio, audio_len);
if (written <= 0)
break;
data += written;
dataLen -= written;
audio += written;
audio_len -= written;
}
close(fd);
}