1 #include <stdio.h> 2 #include <string.h> 3 #include <malloc.h> 4 #include <DataIO.h> 5 #include <ByteOrder.h> 6 #include <InterfaceDefs.h> 7 #include "RawFormats.h" 8 #include "au_reader.h" 9 10 #define TRACE_THIS 1 11 #if TRACE_THIS 12 #define TRACE printf 13 #else 14 #define TRACE(a...) 15 #endif 16 17 #define BUFFER_SIZE 16384 18 19 #define UINT32(a) ((uint32)B_BENDIAN_TO_HOST_INT32((a))) 20 21 auReader::auReader() 22 { 23 TRACE("auReader::auReader\n"); 24 fBuffer = 0; 25 } 26 27 28 auReader::~auReader() 29 { 30 if (fBuffer) 31 free(fBuffer); 32 } 33 34 35 const char * 36 auReader::Copyright() 37 { 38 return ".au & .snd reader, " B_UTF8_COPYRIGHT " by Marcus Overhagen"; 39 } 40 41 42 status_t 43 auReader::Sniff(int32 *streamCount) 44 { 45 TRACE("auReader::Sniff\n"); 46 47 fSource = dynamic_cast<BPositionIO *>(Reader::Source()); 48 if (!fSource) { 49 TRACE("auReader::Sniff: not a BPositionIO\n"); 50 return B_ERROR; 51 } 52 53 int64 filesize = Source()->Seek(0, SEEK_END); 54 if (filesize < 28) { 55 TRACE("auReader::Sniff: File too small\n"); 56 return B_ERROR; 57 } 58 59 snd_header header; 60 61 if (sizeof(header) != Source()->ReadAt(0, &header, sizeof(header))) { 62 TRACE("auReader::Sniff: header reading failed\n"); 63 return B_ERROR; 64 } 65 66 if (UINT32(header.magic) != SND_MAGIC) { 67 TRACE("auReader::Sniff: header not recognized\n"); 68 return B_ERROR; 69 } 70 71 TRACE("auReader::Sniff: we found something that looks like:\n"); 72 73 TRACE(" data_start %ld\n", UINT32(header.data_start)); 74 TRACE(" data_size %ld\n", UINT32(header.data_size)); 75 TRACE(" data_format %ld\n", UINT32(header.data_format)); 76 TRACE(" sampling_rate %ld\n", UINT32(header.sampling_rate)); 77 TRACE(" channel_count %ld\n", UINT32(header.channel_count)); 78 79 fDataStart = UINT32(header.data_start); 80 fDataSize = UINT32(header.data_size); 81 fChannelCount = UINT32(header.channel_count); 82 fFrameRate = UINT32(header.sampling_rate); 83 fFormatCode = UINT32(header.data_format); 84 85 if (fDataStart > filesize) { 86 TRACE("auReader::Sniff: data start too large\n"); 87 return B_ERROR; 88 } 89 if (fDataStart + fDataSize > filesize) 90 fDataSize = filesize - fDataStart; 91 if (fDataSize < 1) { 92 TRACE("auReader::Sniff: data size too small\n"); 93 return B_ERROR; 94 } 95 if (fChannelCount < 1) 96 fChannelCount = 1; 97 if (fFrameRate < 1) 98 fFrameRate = 44100; 99 100 switch (fFormatCode) { 101 case SND_FORMAT_UNSPECIFIED: TRACE("SND_FORMAT_UNSPECIFIED\n"); break; 102 case SND_FORMAT_MULAW_8: TRACE("SND_FORMAT_MULAW_8\n"); break; 103 case SND_FORMAT_LINEAR_8: TRACE("SND_FORMAT_LINEAR_8\n"); break; 104 case SND_FORMAT_LINEAR_16: TRACE("SND_FORMAT_LINEAR_16\n"); break; 105 case SND_FORMAT_LINEAR_24: TRACE("SND_FORMAT_LINEAR_24\n"); break; 106 case SND_FORMAT_LINEAR_32: TRACE("SND_FORMAT_LINEAR_32\n"); break; 107 case SND_FORMAT_FLOAT: TRACE("SND_FORMAT_FLOAT\n"); break; 108 case SND_FORMAT_DOUBLE: TRACE("SND_FORMAT_DOUBLE\n"); break; 109 case SND_FORMAT_INDIRECT: TRACE("SND_FORMAT_INDIRECT\n"); break; 110 case SND_FORMAT_NESTED: TRACE("SND_FORMAT_NESTED\n"); break; 111 case SND_FORMAT_DSP_CORE: TRACE("SND_FORMAT_DSP_CORE\n"); break; 112 case SND_FORMAT_DSP_DATA_8: TRACE("SND_FORMAT_DSP_DATA_8\n"); break; 113 case SND_FORMAT_DSP_DATA_16: TRACE("SND_FORMAT_DSP_DATA_16\n"); break; 114 case SND_FORMAT_DSP_DATA_24: TRACE("SND_FORMAT_DSP_DATA_24\n"); break; 115 case SND_FORMAT_DSP_DATA_32: TRACE("SND_FORMAT_DSP_DATA_32\n"); break; 116 case SND_FORMAT_DISPLAY: TRACE("SND_FORMAT_DISPLAY\n"); break; 117 case SND_FORMAT_MULAW_SQUELCH: TRACE("SND_FORMAT_MULAW_SQUELCH\n"); break; 118 case SND_FORMAT_EMPHASIZED: TRACE("SND_FORMAT_EMPHASIZED\n"); break; 119 case SND_FORMAT_COMPRESSED: TRACE("SND_FORMAT_COMPRESSED\n"); break; 120 case SND_FORMAT_COMPRESSED_EMPHASIZED: TRACE("SND_FORMAT_COMPRESSED_EMPHASIZED\n"); break; 121 case SND_FORMAT_DSP_COMMANDS: TRACE("SND_FORMAT_DSP_COMMANDS\n"); break; 122 case SND_FORMAT_DSP_COMMANDS_SAMPLES: TRACE("SND_FORMAT_DSP_COMMANDS_SAMPLES\n"); break; 123 case SND_FORMAT_ADPCM_G721: TRACE("SND_FORMAT_ADPCM_G721\n"); break; 124 case SND_FORMAT_ADPCM_G722: TRACE("SND_FORMAT_ADPCM_G722\n"); break; 125 case SND_FORMAT_ADPCM_G723_3: TRACE("SND_FORMAT_ADPCM_G723_3\n"); break; 126 case SND_FORMAT_ADPCM_G723_5: TRACE("SND_FORMAT_ADPCM_G723_5\n"); break; 127 case SND_FORMAT_ALAW_8: TRACE("SND_FORMAT_ALAW_8\n"); break; 128 } 129 130 switch (fFormatCode) { 131 case SND_FORMAT_MULAW_8: 132 fBitsPerSample = 8; fRaw = false; break; 133 case SND_FORMAT_LINEAR_8: 134 fBitsPerSample = 8; fRaw = true; break; 135 case SND_FORMAT_LINEAR_16: 136 fBitsPerSample = 16; fRaw = true; break; 137 case SND_FORMAT_LINEAR_24: 138 fBitsPerSample = 24; fRaw = true; break; 139 case SND_FORMAT_LINEAR_32: 140 fBitsPerSample = 32; fRaw = true; break; 141 case SND_FORMAT_FLOAT: 142 fBitsPerSample = 32; fRaw = true; break; 143 case SND_FORMAT_DOUBLE: 144 fBitsPerSample = 64; fRaw = true; break; 145 case SND_FORMAT_ADPCM_G721: 146 fBitsPerSample = 4; fRaw = false; break; 147 case SND_FORMAT_ADPCM_G722: 148 fBitsPerSample = 8; fRaw = false; break; 149 case SND_FORMAT_ADPCM_G723_3: 150 fBitsPerSample = 3; fRaw = false; break; 151 case SND_FORMAT_ADPCM_G723_5: 152 fBitsPerSample = 5; fRaw = false; break; 153 case SND_FORMAT_ALAW_8: 154 fBitsPerSample = 8; fRaw = false; break; 155 default: 156 fBitsPerSample = 0; break; 157 } 158 if (fBitsPerSample == 0) { 159 TRACE("auReader::Sniff: sample format not recognized\n"); 160 return B_ERROR; 161 } 162 163 fFrameCount = (8 * fDataSize) / (fChannelCount * fBitsPerSample); 164 fDuration = (1000000LL * fFrameCount) / fFrameRate; 165 fBitsPerFrame = fChannelCount * fBitsPerSample; 166 fBlockAlign = fBitsPerFrame; 167 while (fBlockAlign % 8 && fBlockAlign < 1000) 168 fBlockAlign += fBlockAlign; 169 if (fBlockAlign % 8) { 170 TRACE("auReader::Sniff: can't find block alignment, fChannelCount %d, fBitsPerSample %d\n", fChannelCount, fBitsPerSample); 171 return B_ERROR; 172 } 173 fBlockAlign /= 8; 174 175 fPosition = 0; 176 177 fBufferSize = (BUFFER_SIZE / fBlockAlign) * fBlockAlign; 178 fBuffer = malloc(fBufferSize); 179 180 TRACE(" fDataStart %Ld\n", fDataStart); 181 TRACE(" fDataSize %Ld\n", fDataSize); 182 TRACE(" fFrameCount %Ld\n", fFrameCount); 183 TRACE(" fDuration %Ld\n", fDuration); 184 TRACE(" fChannelCount %d\n", fChannelCount); 185 TRACE(" fFrameRate %ld\n", fFrameRate); 186 TRACE(" fBitsPerSample %d\n", fBitsPerSample); 187 TRACE(" fBlockAlign %d\n", fBlockAlign); 188 TRACE(" fFormatCode %ld\n", fFormatCode); 189 TRACE(" fRaw %d\n", fRaw); 190 191 BMediaFormats formats; 192 if (fRaw) { 193 // a raw PCM format 194 media_format_description description; 195 description.family = B_BEOS_FORMAT_FAMILY; 196 description.u.beos.format = B_BEOS_FORMAT_RAW_AUDIO; 197 formats.GetFormatFor(description, &fFormat); 198 fFormat.u.raw_audio.frame_rate = (fFrameRate == 8012) ? SND_RATE_8012 : fFrameRate; 199 fFormat.u.raw_audio.channel_count = fChannelCount; 200 switch (fFormatCode) { 201 case SND_FORMAT_LINEAR_8: 202 fFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_UCHAR; 203 break; 204 case SND_FORMAT_LINEAR_16: 205 fFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_SHORT; 206 break; 207 case SND_FORMAT_LINEAR_24: 208 fFormat.u.raw_audio.format = B_AUDIO_FORMAT_INT24; 209 break; 210 case SND_FORMAT_LINEAR_32: 211 fFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_INT; 212 break; 213 case SND_FORMAT_FLOAT: 214 fFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT; 215 break; 216 case SND_FORMAT_DOUBLE: 217 fFormat.u.raw_audio.format = B_AUDIO_FORMAT_FLOAT64; 218 break; 219 default: 220 TRACE("WavReader::Sniff: unhandled raw format\n"); 221 return B_ERROR; 222 } 223 fFormat.u.raw_audio.byte_order = B_MEDIA_BIG_ENDIAN; 224 fFormat.u.raw_audio.buffer_size = fBufferSize; 225 } else { 226 // some encoded format 227 media_format_description description; 228 description.family = B_MISC_FORMAT_FAMILY; 229 description.u.misc.file_format = 'au'; 230 description.u.misc.codec = fFormatCode; 231 formats.GetFormatFor(description, &fFormat); 232 fFormat.u.encoded_audio.output.frame_rate = fFrameRate; 233 fFormat.u.encoded_audio.output.channel_count = fChannelCount; 234 } 235 236 *streamCount = 1; 237 return B_OK; 238 } 239 240 241 void 242 auReader::GetFileFormatInfo(media_file_format *mff) 243 { 244 mff->capabilities = media_file_format::B_READABLE 245 | media_file_format::B_KNOWS_ENCODED_AUDIO 246 | media_file_format::B_IMPERFECTLY_SEEKABLE; 247 mff->family = B_MISC_FORMAT_FAMILY; 248 mff->version = 100; 249 strcpy(mff->mime_type, "audio/x-au"); 250 strcpy(mff->file_extension, "au"); 251 strcpy(mff->short_name, "Sun audio file"); 252 strcpy(mff->pretty_name, "Sun audio file"); 253 } 254 255 256 status_t 257 auReader::AllocateCookie(int32 streamNumber, void **cookie) 258 { 259 return B_OK; 260 } 261 262 status_t 263 auReader::FreeCookie(void *cookie) 264 { 265 return B_OK; 266 } 267 268 269 status_t 270 auReader::GetStreamInfo(void *cookie, int64 *frameCount, bigtime_t *duration, 271 media_format *format, void **infoBuffer, int32 *infoSize) 272 { 273 *frameCount = fFrameCount; 274 *duration = fDuration; 275 *format = fFormat; 276 *infoBuffer = 0; 277 *infoSize = 0; 278 return B_OK; 279 } 280 281 282 status_t 283 auReader::Seek(void *cookie, 284 uint32 seekTo, 285 int64 *frame, bigtime_t *time) 286 { 287 int64 pos; 288 289 if (seekTo & B_MEDIA_SEEK_TO_FRAME) { 290 if (fRaw) 291 pos = (*frame * fBitsPerFrame) / 8; 292 else 293 pos = (*frame * fDataSize) / fFrameCount; 294 pos = (pos / fBlockAlign) * fBlockAlign; // round down to a block start 295 TRACE("auReader::Seek to frame %Ld, pos %Ld\n", *frame, pos); 296 } else if (seekTo & B_MEDIA_SEEK_TO_TIME) { 297 if (fRaw) 298 pos = (*time * fFrameRate * fBitsPerFrame) / (1000000LL * 8); 299 else 300 pos = (*time * fDataSize) / fDuration; 301 pos = (pos / fBlockAlign) * fBlockAlign; // round down to a block start 302 TRACE("auReader::Seek to time %Ld, pos %Ld\n", *time, pos); 303 } else { 304 return B_ERROR; 305 } 306 307 if (fRaw) 308 *frame = (8 * pos) / fBitsPerFrame; 309 else 310 *frame = (pos * fFrameCount) / fDataSize; 311 *time = (*frame * 1000000LL) / fFrameRate; 312 313 TRACE("auReader::Seek newtime %Ld\n", *time); 314 TRACE("auReader::Seek newframe %Ld\n", *frame); 315 316 if (pos < 0 || pos > fDataSize) { 317 TRACE("auReader::Seek invalid position %Ld\n", pos); 318 return B_ERROR; 319 } 320 321 fPosition = pos; 322 return B_OK; 323 } 324 325 326 status_t 327 auReader::GetNextChunk(void *cookie, 328 void **chunkBuffer, int32 *chunkSize, 329 media_header *mediaHeader) 330 { 331 // XXX it might be much better to not return any start_time information for encoded formats here, 332 // XXX and instead use the last time returned from seek and count forward after decoding. 333 mediaHeader->start_time = (((8 * fPosition) / fBitsPerFrame) * 1000000LL) / fFrameRate; 334 mediaHeader->file_pos = fDataStart + fPosition; 335 336 int64 maxreadsize = fDataSize - fPosition; 337 int32 readsize = fBufferSize; 338 if (maxreadsize < readsize) 339 readsize = maxreadsize; 340 if (readsize == 0) 341 return B_LAST_BUFFER_ERROR; 342 343 if (readsize != Source()->ReadAt(fDataStart + fPosition, fBuffer, readsize)) { 344 TRACE("auReader::GetNextChunk: unexpected read error\n"); 345 return B_ERROR; 346 } 347 348 // XXX if the stream has more than two channels, we need to reorder channel data here 349 350 fPosition += readsize; 351 *chunkBuffer = fBuffer; 352 *chunkSize = readsize; 353 return B_OK; 354 } 355 356 357 Reader * 358 auReaderPlugin::NewReader() 359 { 360 return new auReader; 361 } 362 363 364 MediaPlugin *instantiate_plugin() 365 { 366 return new auReaderPlugin; 367 } 368