зеркало из https://github.com/mozilla/gecko-dev.git
Bug 68804: Properly parse WAV files, r+sr=roc
This commit is contained in:
Родитель
fdd916ee80
Коммит
dc3cd411d5
|
@ -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);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче