2 * Copyright (c) 2003-2004, Marcus Overhagen
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
22 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
23 * OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <ByteOrder.h>
30 #include <InterfaceDefs.h>
31 #include "WavReaderPlugin.h"
32 #include "RawFormats.h"
34 #define TRACE_WAVE_READER
35 #ifdef TRACE_WAVE_READER
41 #define ERROR(a...) fprintf(stderr, a)
43 #define BUFFER_SIZE 16384 // must be > 5200 for mp3 decoder to work
45 #define FOURCC(a,b,c,d) ((((uint32)(d)) << 24) | (((uint32)(c)) << 16) | (((uint32)(b)) << 8) | ((uint32)(a)))
46 #define UINT16(a) ((uint16)B_LENDIAN_TO_HOST_INT16((a)))
47 #define UINT32(a) ((uint32)B_LENDIAN_TO_HOST_INT32((a)))
49 // This Reader only deals with CBR audio
50 // My understanding is that no WAV file will have VBR audio anyway
71 static bigtime_t
FrameToTime(uint64 frame
, uint32 fps
) {
72 return frame
* 1000000LL / fps
;
75 static uint64
TimeToFrame(bigtime_t time
, uint32 fps
) {
76 return (time
* fps
) / 1000000LL;
79 static int64
TimeToPosition(bigtime_t time
, uint32 bitrate
) {
80 return (time
* bitrate
) / 8000000LL;
83 static bigtime_t
PositionToTime(int64 position
, uint32 bitrate
) {
84 return (position
* 8000000LL) / bitrate
;
87 static int64
FrameToPosition(uint64 frame
, uint32 bitrate
, uint32 fps
) {
88 return TimeToPosition(FrameToTime(frame
,fps
),bitrate
);
91 static uint64
PositionToFrame(int64 position
, uint32 bitrate
, uint32 fps
) {
92 return TimeToFrame(PositionToTime(position
,bitrate
),fps
);
95 WavReader::WavReader()
97 TRACE("WavReader::WavReader\n");
100 WavReader::~WavReader()
105 WavReader::Copyright()
107 return "WAV reader, " B_UTF8_COPYRIGHT
" by Marcus Overhagen";
112 WavReader::Sniff(int32
*streamCount
)
114 TRACE("WavReader::Sniff\n");
116 fSource
= dynamic_cast<BPositionIO
*>(Reader::Source());
118 fFileSize
= Source()->Seek(0, SEEK_END
);
119 if (fFileSize
< 44) {
120 TRACE("WavReader::Sniff: File too small\n");
128 if (sizeof(riff
) != Source()->ReadAt(pos
, &riff
, sizeof(riff
))) {
129 TRACE("WavReader::Sniff: RIFF WAVE header reading failed\n");
134 if (UINT32(riff
.riff_id
) != FOURCC('R','I','F','F') || UINT32(riff
.wave_id
) != FOURCC('W','A','V','E')) {
135 TRACE("WavReader::Sniff: RIFF WAVE header not recognized\n");
139 wave_format_ex format
;
140 format_struct_extensible format_ext
;
141 mpeg1_wav_format mpeg1_format
;
142 mpeg3_wav_format mpeg3_format
;
144 uint32 wavFmtSize
= sizeof(format_struct
) + 2;
148 // read all chunks and search for "fact", "fmt" (normal or extensible) and "data"
149 // everything else is ignored;
150 bool foundFact
= false;
151 bool foundFmt
= false;
152 bool foundFmtExt
= false;
153 bool foundData
= false;
154 bool foundMPEG1
= false;
155 bool foundMPEG3
= false;
157 while (pos
+ sizeof(chunk_struct
) <= fFileSize
) {
159 if (sizeof(chunk
) != Source()->ReadAt(pos
, &chunk
, sizeof(chunk
))) {
160 ERROR("WavReader::Sniff: chunk header reading failed\n");
163 pos
+= sizeof(chunk
);
164 if (UINT32(chunk
.len
) == 0) {
165 ERROR("WavReader::Sniff: Error: chunk of size 0 found\n");
168 switch (UINT32(chunk
.fourcc
)) {
169 case FOURCC('f','m','t',' '):
170 // So what do we have a std format structure, a wav_format structure or a extended structure
171 if (UINT32(chunk
.len
) >= wavFmtSize
) {
172 // Must be some sort of extended format structure
173 // First Read common data + extra size
174 if (wavFmtSize
!= Source()->ReadAt(pos
, &format
, wavFmtSize
)) {
175 ERROR("WavReader::Sniff: format chunk reading failed\n");
179 // If extra size seems valid then re-read with the extra data included
180 if (UINT16(format
.extra_size
) > 0 && UINT16(format
.extra_size
) < 64) {
181 // Read the extra data we need to pass across to the decoder
182 if ((wavFmtSize
+ format
.extra_size
) != Source()->ReadAt(pos
, &format
, wavFmtSize
+ format
.extra_size
)) {
183 ERROR("WavReader::Sniff: format extensible chunk reading failed\n");
189 // Check for structure we recognise and might need values from.
190 if (UINT16(format
.extra_size
) == 12) {
191 // MPEG3 WAV FORMAT Structure
192 if (sizeof(mpeg3_format
) != Source()->ReadAt(pos
, &mpeg3_format
, sizeof(mpeg3_format
))) {
193 ERROR("WavReader::Sniff: format chunk reading failed\n");
197 } else if (UINT16(format
.extra_size
) == 22) {
198 if (UINT16(format
.format_tag
) == 0xfffe) {
200 if (sizeof(format_ext
) != Source()->ReadAt(pos
, &format_ext
, sizeof(format_ext
))) {
201 ERROR("WavReader::Sniff: format extensible chunk reading failed\n");
206 // MPEG1 WAV FORMAT Structure
207 if (sizeof(mpeg1_format
) != Source()->ReadAt(pos
, &mpeg1_format
, sizeof(mpeg1_format
))) {
208 ERROR("WavReader::Sniff: format chunk reading failed\n");
214 } else if (UINT32(chunk
.len
) >= wavFmtSize
- 2) {
215 if ((wavFmtSize
- 2) != Source()->ReadAt(pos
, &format
, wavFmtSize
- 2)) {
216 ERROR("WavReader::Sniff: format chunk reading failed\n");
219 format
.extra_size
= 0;
223 case FOURCC('f','a','c','t'):
224 if (UINT32(chunk
.len
) >= sizeof(fact
)) {
225 if (sizeof(fact
) != Source()->ReadAt(pos
, &fact
, sizeof(fact
))) {
226 ERROR("WavReader::Sniff: fact chunk reading failed\n");
232 case FOURCC('d','a','t','a'):
234 fDataSize
= UINT32(chunk
.len
);
236 // If file size is >= 2GB and we already found a format chunk,
237 // assume the rest of the file is data and get out of here.
238 // This should allow reading wav files much bigger than 2 or 4 GB.
239 if (fFileSize
>= 0x7fffffff && foundFmt
) {
241 fDataSize
= fFileSize
- fDataStart
;
242 TRACE("WavReader::Sniff: big file size %Ld, indicated data size %lu, assuming data size is %Ld\n",
243 fFileSize
, UINT32(chunk
.len
), fDataSize
);
247 TRACE("WavReader::Sniff: ignoring chunk 0x%08lx of %lu bytes\n", UINT32(chunk
.fourcc
), UINT32(chunk
.len
));
250 pos
+= UINT32(chunk
.len
);
255 ERROR("WavReader::Sniff: couldn't find format chunk\n");
259 ERROR("WavReader::Sniff: couldn't find data chunk\n");
263 TRACE("WavReader::Sniff: we found something that looks like:\n");
265 TRACE(" format_tag 0x%04x\n", UINT16(format
.format_tag
));
266 TRACE(" channels %d\n", UINT16(format
.channels
));
267 TRACE(" samples_per_sec %ld\n", UINT32(format
.samples_per_sec
));
268 TRACE(" avg_bytes_per_sec %ld\n", UINT32(format
.avg_bytes_per_sec
));
269 TRACE(" block_align %d\n", UINT16(format
.block_align
));
270 TRACE(" bits_per_sample %d\n", UINT16(format
.bits_per_sample
));
271 TRACE(" ext_size %d\n", UINT16(format
.extra_size
));
273 TRACE(" valid_bits_per_sample %d\n", UINT16(format_ext
.valid_bits_per_sample
));
274 TRACE(" channel_mask %ld\n", UINT32(format_ext
.channel_mask
));
275 TRACE(" guid[0-1] format 0x%04x\n", (format_ext
.guid
[1] << 8) | format_ext
.guid
[0]);
278 TRACE(" sample_length %ld\n", UINT32(fact
.sample_length
));
282 TRACE(" layer %d\n", UINT16(mpeg1_format
.head_layer
));
283 TRACE(" bitrate %ld\n", UINT32(mpeg1_format
.head_bitrate
));
284 TRACE(" mode %d\n", UINT16(mpeg1_format
.head_mode
));
285 TRACE(" mode ext %d\n", UINT16(mpeg1_format
.head_mode_ext
));
286 TRACE(" emphisis %d\n", UINT16(mpeg1_format
.head_emphasis
));
287 TRACE(" flags %d\n", UINT16(mpeg1_format
.head_flags
));
288 TRACE(" pts low %ld\n", UINT32(mpeg1_format
.pts_low
));
289 TRACE(" pts high %ld\n", UINT32(mpeg1_format
.pts_high
));
293 TRACE(" id %d\n", UINT16(mpeg3_format
.id
));
294 TRACE(" flags %ld\n", UINT32(mpeg3_format
.flags
));
295 TRACE(" block size %d\n", UINT16(mpeg3_format
.block_size
));
296 TRACE(" frames per block %d\n", UINT16(mpeg3_format
.frames_per_block
));
297 TRACE(" codec delay %d\n", UINT16(mpeg3_format
.codec_delay
));
298 fBufferSize
= mpeg3_format
.block_size
;
300 fBufferSize
= BUFFER_SIZE
;
303 fMetaData
.extra_size
= format
.extra_size
;
304 if (fMetaData
.extra_size
> 0) {
305 memcpy(fMetaData
.extra_data
, format
.extra_data
, min_c(format
.extra_size
, sizeof(format
.extra_data
)));
307 fMetaData
.channels
= UINT16(format
.channels
);
308 fMetaData
.samples_per_sec
= UINT32(format
.samples_per_sec
);
309 fMetaData
.block_align
= UINT16(format
.block_align
);
310 fMetaData
.bits_per_sample
= UINT16(format
.bits_per_sample
);
311 if (fMetaData
.bits_per_sample
== 0) {
312 fMetaData
.bits_per_sample
= fMetaData
.block_align
* 8 / fMetaData
.channels
;
313 ERROR("WavReader::Sniff: Error, bits_per_sample = 0 calculating as %d\n",fMetaData
.bits_per_sample
);
315 fFrameRate
= fMetaData
.samples_per_sec
* fMetaData
.channels
;
317 fMetaData
.avg_bytes_per_sec
= format
.avg_bytes_per_sec
;
319 // fact.sample_length is really no of samples for all channels
320 fFrameCount
= foundFact
? UINT32(fact
.sample_length
) / fMetaData
.channels
: 0;
321 fMetaData
.format_tag
= UINT16(format
.format_tag
);
322 if (fMetaData
.format_tag
== 0xfffe && foundFmtExt
)
323 fMetaData
.format_tag
= (format_ext
.guid
[1] << 8) | format_ext
.guid
[0];
325 int min_align
= (fMetaData
.format_tag
== 0x0001) ? (fMetaData
.bits_per_sample
* fMetaData
.channels
+ 7) / 8 : 1;
326 if (fMetaData
.block_align
< min_align
)
327 fMetaData
.block_align
= min_align
;
329 TRACE(" fDataStart %Ld\n", fDataStart
);
330 TRACE(" fDataSize %Ld\n", fDataSize
);
331 TRACE(" Channels %d\n", fMetaData
.channels
);
332 TRACE(" SampleRate %ld\n", fMetaData
.samples_per_sec
);
333 TRACE(" fFrameRate %ld\n", fFrameRate
);
334 TRACE(" fFrameCount %Ld\n", fFrameCount
);
335 TRACE(" BitsPerSample %d\n", fMetaData
.bits_per_sample
);
336 TRACE(" BlockAlign %d\n", fMetaData
.block_align
);
337 TRACE(" min_align %d\n", min_align
);
338 TRACE(" Format 0x%04x\n", fMetaData
.format_tag
);
340 // XXX fact.sample_length contains duration of encoded files?
348 WavReader::GetFileFormatInfo(media_file_format
*mff
)
350 mff
->capabilities
= media_file_format::B_READABLE
351 | media_file_format::B_KNOWS_ENCODED_AUDIO
352 | media_file_format::B_IMPERFECTLY_SEEKABLE
;
353 mff
->family
= B_WAV_FORMAT_FAMILY
;
355 strcpy(mff
->mime_type
, "audio/x-wav");
356 strcpy(mff
->file_extension
, "wav");
357 strcpy(mff
->short_name
, "RIFF WAV audio");
358 strcpy(mff
->pretty_name
, "RIFF WAV audio");
363 WavReader::AllocateCookie(int32 streamNumber
, void **cookie
)
365 TRACE("WavReader::AllocateCookie\n");
367 wavdata
*data
= new wavdata
;
370 data
->datasize
= fDataSize
;
371 data
->fps
= fMetaData
.samples_per_sec
;
372 data
->buffersize
= (fBufferSize
/ fMetaData
.block_align
) * fMetaData
.block_align
;
373 data
->buffer
= malloc(data
->buffersize
);
374 data
->framecount
= fFrameCount
? fFrameCount
: (8 * fDataSize
) / (fMetaData
.channels
* fMetaData
.bits_per_sample
);
375 data
->raw
= fMetaData
.format_tag
== 0x0001;
377 if (!fMetaData
.avg_bytes_per_sec
) {
378 fMetaData
.avg_bytes_per_sec
= fMetaData
.samples_per_sec
* fMetaData
.block_align
;
381 data
->duration
= (data
->datasize
* 1000000LL) / fMetaData
.avg_bytes_per_sec
;
382 data
->bitrate
= fMetaData
.avg_bytes_per_sec
* 8;
384 TRACE(" raw %s\n", data
->raw
? "true" : "false");
385 TRACE(" framecount %Ld\n", data
->framecount
);
386 TRACE(" duration %Ld\n", data
->duration
);
387 TRACE(" bitrate %ld\n", data
->bitrate
);
388 TRACE(" fps %ld\n", data
->fps
);
389 TRACE(" buffersize %ld\n", data
->buffersize
);
391 BMediaFormats formats
;
392 if (fMetaData
.format_tag
== 0x0001) {
394 media_format_description description
;
395 description
.family
= B_BEOS_FORMAT_FAMILY
;
396 description
.u
.beos
.format
= B_BEOS_FORMAT_RAW_AUDIO
;
397 formats
.GetFormatFor(description
, &data
->format
);
399 data
->format
.u
.raw_audio
.frame_rate
= fMetaData
.samples_per_sec
;
400 data
->format
.u
.raw_audio
.channel_count
= fMetaData
.channels
;
401 switch (fMetaData
.bits_per_sample
) {
403 data
->format
.u
.raw_audio
.format
= B_AUDIO_FORMAT_UINT8
;
406 data
->format
.u
.raw_audio
.format
= B_AUDIO_FORMAT_INT16
;
409 data
->format
.u
.raw_audio
.format
= B_AUDIO_FORMAT_INT24
;
412 data
->format
.u
.raw_audio
.format
= B_AUDIO_FORMAT_INT32
;
415 ERROR("WavReader::AllocateCookie: unhandled bits per sample %d\n", fMetaData
.bits_per_sample
);
419 data
->format
.u
.raw_audio
.format
|= B_AUDIO_FORMAT_CHANNEL_ORDER_WAVE
;
420 data
->format
.u
.raw_audio
.byte_order
= B_MEDIA_LITTLE_ENDIAN
;
421 data
->format
.u
.raw_audio
.buffer_size
= data
->buffersize
;
423 // some encoded format
424 media_format_description description
;
425 description
.family
= B_WAV_FORMAT_FAMILY
;
426 description
.u
.wav
.codec
= fMetaData
.format_tag
;
427 formats
.GetFormatFor(description
, &data
->format
);
429 data
->format
.u
.encoded_audio
.bit_rate
= data
->bitrate
;
430 data
->format
.u
.encoded_audio
.output
.frame_rate
= fMetaData
.samples_per_sec
;
431 data
->format
.u
.encoded_audio
.output
.channel_count
= fMetaData
.channels
;
434 printf("SetMetaData called with size %ld\n",sizeof(format_struct
) + fMetaData
.extra_size
+ 2);
436 if (data
->format
.SetMetaData(&fMetaData
, (sizeof(format_struct
) + fMetaData
.extra_size
+ 2)) != B_OK
) {
437 ERROR("WavReader::Failed to SetMetaData\n");
449 WavReader::FreeCookie(void *cookie
)
451 TRACE("WavReader::FreeCookie\n");
452 wavdata
*data
= reinterpret_cast<wavdata
*>(cookie
);
462 WavReader::GetStreamInfo(void *cookie
, int64
*frameCount
, bigtime_t
*duration
,
463 media_format
*format
, const void **infoBuffer
, size_t *infoSize
)
465 wavdata
*data
= reinterpret_cast<wavdata
*>(cookie
);
467 *frameCount
= data
->framecount
;
468 *duration
= data
->duration
;
469 *format
= data
->format
;
470 *infoBuffer
= &fMetaData
;
471 *infoSize
= (sizeof(format_struct
) + fMetaData
.extra_size
+ 2);
476 WavReader::CalculateNewPosition(void *cookie
,
478 int64
*frame
, bigtime_t
*time
, int64
*position
)
480 wavdata
*data
= reinterpret_cast<wavdata
*>(cookie
);
482 if (flags
& B_MEDIA_SEEK_TO_FRAME
) {
483 TRACE(" to frame %Ld",*frame
);
484 *position
= FrameToPosition(*frame
, data
->bitrate
, data
->fps
);
486 } else if (flags
& B_MEDIA_SEEK_TO_TIME
) {
487 TRACE(" to time %Ld", *time
);
488 *position
= TimeToPosition(*time
, data
->bitrate
);
490 printf("WavReader::CalculateNewPosition invalid flag passed %ld\n", flags
);
494 *position
= (*position
/ fMetaData
.block_align
) * fMetaData
.block_align
; // round down to a block start
496 TRACE(", position %Ld ", *position
);
498 *frame
= PositionToFrame(*position
, data
->bitrate
, data
->fps
);
499 *time
= FrameToTime(*frame
,data
->fps
);
501 TRACE("newtime %Ld ", *time
);
502 TRACE("newframe %Ld\n", *frame
);
504 if (*position
< 0 || *position
> data
->datasize
) {
505 ERROR("WavReader::CalculateNewPosition invalid position %Ld\n", *position
);
513 WavReader::Seek(void *cookie
,
515 int64
*frame
, bigtime_t
*time
)
517 // Seek to the given position
518 wavdata
*data
= reinterpret_cast<wavdata
*>(cookie
);
522 TRACE("WavReader::Seek");
523 status
= CalculateNewPosition(cookie
, flags
, frame
, time
, &pos
);
525 if (status
== B_OK
) {
526 // set the new position so next GetNextChunk will read from new seek pos
527 data
->position
= pos
;
534 WavReader::FindKeyFrame(void* cookie
, uint32 flags
,
535 int64
* frame
, bigtime_t
* time
)
537 // Find a seek position without actually seeking
539 TRACE("WavReader::FindKeyFrame");
541 return CalculateNewPosition(cookie
, flags
, frame
, time
, &pos
);
545 WavReader::GetNextChunk(void *cookie
,
546 const void **chunkBuffer
, size_t *chunkSize
,
547 media_header
*mediaHeader
)
549 wavdata
*data
= reinterpret_cast<wavdata
*>(cookie
);
551 // XXX it might be much better to not return any start_time information for encoded formats here,
552 // XXX and instead use the last time returned from seek and count forward after decoding.
553 mediaHeader
->start_time
= PositionToTime(data
->position
,data
->bitrate
);
554 mediaHeader
->file_pos
= fDataStart
+ data
->position
;
556 TRACE("(%s) position = %9Ld ", data
->raw
? "raw" : "encoded", data
->position
);
557 TRACE("frame = %9Ld ", PositionToFrame(data
->position
,data
->bitrate
,data
->fps
));
558 TRACE("fDataSize = %9Ld ", fDataSize
);
559 TRACE("start_time = %9Ld\n", mediaHeader
->start_time
);
561 int64 maxreadsize
= data
->datasize
- data
->position
;
562 int32 readsize
= data
->buffersize
;
563 if (maxreadsize
< readsize
)
564 readsize
= maxreadsize
;
566 ERROR("WavReader::GetNextChunk: LAST BUFFER ERROR at time %9Ld\n",mediaHeader
->start_time
);
567 return B_LAST_BUFFER_ERROR
;
570 if (readsize
!= Source()->ReadAt(fDataStart
+ data
->position
, data
->buffer
, readsize
)) {
571 ERROR("WavReader::GetNextChunk: unexpected read error at position %9Ld\n",fDataStart
+ data
->position
);
575 // XXX if the stream has more than two channels, we need to reorder channel data here
577 data
->position
+= readsize
;
578 *chunkBuffer
= data
->buffer
;
579 *chunkSize
= readsize
;
585 WavReaderPlugin::NewReader()
587 return new WavReader
;
591 MediaPlugin
*instantiate_plugin()
593 return new WavReaderPlugin
;