3rdparty/licenseReport: Add seperate LGPL checks
[haiku.git] / src / add-ons / media / plugins / wav_reader / WavReaderPlugin.cpp
blobccae89d733abed961023f44f9d9e6c343e791a50
1 /*
2 * Copyright (c) 2003-2004, Marcus Overhagen
3 * All rights reserved.
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.
25 #include <stdio.h>
26 #include <string.h>
27 #include <malloc.h>
28 #include <DataIO.h>
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
36 #define TRACE printf
37 #else
38 #define TRACE(a...)
39 #endif
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
52 struct wavdata
54 int64 position;
55 int64 datasize;
57 uint32 bitrate;
58 uint32 fps;
60 void *buffer;
61 uint32 buffersize;
63 uint64 framecount;
64 bigtime_t duration;
66 bool raw;
68 media_format format;
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()
104 const char *
105 WavReader::Copyright()
107 return "WAV reader, " B_UTF8_COPYRIGHT " by Marcus Overhagen";
111 status_t
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");
121 return B_ERROR;
124 int64 pos = 0;
126 riff_struct riff;
128 if (sizeof(riff) != Source()->ReadAt(pos, &riff, sizeof(riff))) {
129 TRACE("WavReader::Sniff: RIFF WAVE header reading failed\n");
130 return B_ERROR;
132 pos += sizeof(riff);
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");
136 return B_ERROR;
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;
146 fact_struct fact;
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) {
158 chunk_struct chunk;
159 if (sizeof(chunk) != Source()->ReadAt(pos, &chunk, sizeof(chunk))) {
160 ERROR("WavReader::Sniff: chunk header reading failed\n");
161 return B_ERROR;
163 pos += sizeof(chunk);
164 if (UINT32(chunk.len) == 0) {
165 ERROR("WavReader::Sniff: Error: chunk of size 0 found\n");
166 return B_ERROR;
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");
176 break;
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");
184 break;
187 foundFmt = true;
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");
194 break;
196 foundMPEG3 = true;
197 } else if (UINT16(format.extra_size) == 22) {
198 if (UINT16(format.format_tag) == 0xfffe) {
199 // GUID structure
200 if (sizeof(format_ext) != Source()->ReadAt(pos, &format_ext, sizeof(format_ext))) {
201 ERROR("WavReader::Sniff: format extensible chunk reading failed\n");
202 break;
204 foundFmtExt = true;
205 } else {
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");
209 break;
211 foundMPEG1 = true;
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");
217 break;
219 format.extra_size = 0;
220 foundFmt = true;
222 break;
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");
227 break;
229 foundFact = true;
231 break;
232 case FOURCC('d','a','t','a'):
233 fDataStart = pos;
234 fDataSize = UINT32(chunk.len);
235 foundData = true;
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) {
240 pos += fFileSize;
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);
245 break;
246 default:
247 TRACE("WavReader::Sniff: ignoring chunk 0x%08lx of %lu bytes\n", UINT32(chunk.fourcc), UINT32(chunk.len));
248 break;
250 pos += UINT32(chunk.len);
251 pos += (pos & 1);
254 if (!foundFmt) {
255 ERROR("WavReader::Sniff: couldn't find format chunk\n");
256 return B_ERROR;
258 if (!foundData) {
259 ERROR("WavReader::Sniff: couldn't find data chunk\n");
260 return B_ERROR;
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));
272 if (foundFmtExt) {
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]);
277 if (foundFact) {
278 TRACE(" sample_length %ld\n", UINT32(fact.sample_length));
281 if (foundMPEG1) {
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));
292 if (foundMPEG3) {
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;
299 } else {
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?
342 *streamCount = 1;
343 return B_OK;
347 void
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;
354 mff->version = 100;
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");
362 status_t
363 WavReader::AllocateCookie(int32 streamNumber, void **cookie)
365 TRACE("WavReader::AllocateCookie\n");
367 wavdata *data = new wavdata;
369 data->position = 0;
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) {
393 // a raw PCM format
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);
398 // Really SampleRate
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) {
402 case 8:
403 data->format.u.raw_audio.format = B_AUDIO_FORMAT_UINT8;
404 break;
405 case 16:
406 data->format.u.raw_audio.format = B_AUDIO_FORMAT_INT16;
407 break;
408 case 24:
409 data->format.u.raw_audio.format = B_AUDIO_FORMAT_INT24;
410 break;
411 case 32:
412 data->format.u.raw_audio.format = B_AUDIO_FORMAT_INT32;
413 break;
414 default:
415 ERROR("WavReader::AllocateCookie: unhandled bits per sample %d\n", fMetaData.bits_per_sample);
416 delete data;
417 return B_ERROR;
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;
422 } else {
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);
428 // Really SampleRate
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");
438 delete data;
439 return B_ERROR;
442 // store the cookie
443 *cookie = data;
444 return B_OK;
448 status_t
449 WavReader::FreeCookie(void *cookie)
451 TRACE("WavReader::FreeCookie\n");
452 wavdata *data = reinterpret_cast<wavdata *>(cookie);
454 free(data->buffer);
455 delete data;
457 return B_OK;
461 status_t
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);
472 return B_OK;
475 status_t
476 WavReader::CalculateNewPosition(void *cookie,
477 uint32 flags,
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);
489 } else {
490 printf("WavReader::CalculateNewPosition invalid flag passed %ld\n", flags);
491 return B_ERROR;
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);
506 return B_ERROR;
509 return B_OK;
512 status_t
513 WavReader::Seek(void *cookie,
514 uint32 flags,
515 int64 *frame, bigtime_t *time)
517 // Seek to the given position
518 wavdata *data = reinterpret_cast<wavdata *>(cookie);
519 status_t status;
520 int64 pos;
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;
530 return status;
533 status_t
534 WavReader::FindKeyFrame(void* cookie, uint32 flags,
535 int64* frame, bigtime_t* time)
537 // Find a seek position without actually seeking
538 int64 pos;
539 TRACE("WavReader::FindKeyFrame");
541 return CalculateNewPosition(cookie, flags, frame, time, &pos);
544 status_t
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;
565 if (readsize == 0) {
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);
572 return B_ERROR;
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;
580 return B_OK;
584 Reader *
585 WavReaderPlugin::NewReader()
587 return new WavReader;
591 MediaPlugin *instantiate_plugin()
593 return new WavReaderPlugin;