1 /* Copyright 2005-2009 SHINTA 2 * Distributed under the terms of the MIT license 3 */ 4 5 6 #include <InterfaceDefs.h> 7 8 #include "APEReader.h" 9 #include "MACLib.h" 10 11 12 static const char* kCopyrightString 13 = "Copyright " B_UTF8_COPYRIGHT " 2005-2009 by SHINTA"; 14 15 16 TAPEReader::TAPEReader() 17 : SUPER() 18 { 19 mDecodedData = NULL; 20 mDecomp = NULL; 21 Unset(); 22 } 23 24 25 TAPEReader::~TAPEReader() 26 { 27 } 28 29 30 status_t 31 TAPEReader::AllocateCookie(int32 oStreamNumber, void** oCookie) 32 { 33 *oCookie = NULL; 34 return B_OK; 35 } 36 37 38 const char* 39 TAPEReader::Copyright() 40 { 41 return kCopyrightString; 42 } 43 44 45 bigtime_t 46 TAPEReader::CurrentTime() const 47 { 48 return mDecomp->GetInfo(APE_DECOMPRESS_CURRENT_MS) 49 * static_cast<bigtime_t>(1000); 50 } 51 52 53 status_t 54 TAPEReader::FreeCookie(void* oCookie) 55 { 56 return B_OK; 57 } 58 59 60 void 61 TAPEReader::GetFileFormatInfo(media_file_format* oMFF) 62 { 63 oMFF->capabilities = media_file_format::B_READABLE 64 | media_file_format::B_PERFECTLY_SEEKABLE 65 // | media_file_format::B_IMPERFECTLY_SEEKABLE 66 | media_file_format::B_KNOWS_RAW_AUDIO 67 | media_file_format::B_KNOWS_ENCODED_AUDIO; 68 oMFF->family = B_ANY_FORMAT_FAMILY; 69 oMFF->version = MEDIA_FILE_FORMAT_VERSION; 70 strcpy(oMFF->mime_type, MIME_TYPE_APE); 71 strcpy(oMFF->pretty_name, MIME_TYPE_APE_LONG_DESCRIPTION); 72 strcpy(oMFF->short_name, MIME_TYPE_APE_SHORT_DESCRIPTION); 73 strcpy(oMFF->file_extension, MIME_TYPE_APE_EXTENSION); 74 } 75 76 77 status_t 78 TAPEReader::GetNextChunk(void* oCookie, const void** oChunkBuffer, 79 size_t* oChunkSize, media_header* oMediaHeader) 80 { 81 int64 aOutSize; 82 83 // check whether song is finished or not 84 if (mReadPosTotal - mReadPos + mPlayPos >= mDataSize) 85 return B_ERROR; 86 87 // reading data 88 if (mPlayPos >= mReadPos ) 89 ReadBlocks(); 90 91 // passing data 92 if (mReadPos-mPlayPos >= BUFFER_SIZE) 93 aOutSize = BUFFER_SIZE; 94 else 95 aOutSize = mReadPos-mPlayPos; 96 97 *oChunkBuffer = &mDecodedData[mPlayPos]; 98 mPlayPos += aOutSize; 99 100 // passing info 101 *oChunkSize = aOutSize; 102 oMediaHeader->start_time = CurrentTime(); 103 oMediaHeader->file_pos = mPlayPos; 104 return B_OK; 105 } 106 107 108 status_t 109 TAPEReader::GetStreamInfo(void* oCookie, int64* oFrameCount, 110 bigtime_t* oDuration, media_format* oFormat, const void** oInfoBuffer, 111 size_t* oInfoSize) 112 { 113 if (LoadAPECheck() != B_OK) 114 return LoadAPECheck(); 115 116 *oFrameCount = mDataSize / (mDecomp->GetInfo(APE_INFO_BITS_PER_SAMPLE) / 8 117 * mDecomp->GetInfo(APE_INFO_CHANNELS)); 118 *oDuration = mDecomp->GetInfo(APE_INFO_LENGTH_MS) 119 * static_cast<bigtime_t>(1000); 120 // media_format 121 oFormat->type = B_MEDIA_RAW_AUDIO; 122 oFormat->u.raw_audio.frame_rate = mDecomp->GetInfo(APE_INFO_SAMPLE_RATE); 123 oFormat->u.raw_audio.channel_count = mDecomp->GetInfo(APE_INFO_CHANNELS); 124 if ( mDecomp->GetInfo(APE_INFO_BITS_PER_SAMPLE) == 16 ) 125 oFormat->u.raw_audio.format = media_raw_audio_format::B_AUDIO_SHORT; 126 else 127 oFormat->u.raw_audio.format = media_raw_audio_format::B_AUDIO_UCHAR; 128 129 oFormat->u.raw_audio.byte_order = B_MEDIA_LITTLE_ENDIAN; 130 oFormat->u.raw_audio.buffer_size = BUFFER_SIZE; 131 oInfoBuffer = NULL; 132 oInfoSize = NULL; 133 return B_OK; 134 } 135 136 137 status_t 138 TAPEReader::LoadAPECheck() const 139 { 140 return mLoadAPECheck; 141 } 142 143 144 status_t 145 TAPEReader::ReadBlocks() 146 { 147 int aBlocksRead; 148 int aRetVal = 0; 149 150 aRetVal = mDecomp->GetData(reinterpret_cast<char*>(mDecodedData), 151 BLOCK_COUNT, &aBlocksRead); 152 if (aRetVal != ERROR_SUCCESS) 153 return B_ERROR; 154 155 mPlayPos = 0; 156 mReadPos = aBlocksRead*mDecomp->GetInfo(APE_INFO_BLOCK_ALIGN); 157 mReadPosTotal += mReadPos; 158 return B_OK; 159 } 160 161 162 status_t 163 TAPEReader::FindKeyFrame(void* cookie, uint32 flags, int64* frame, 164 bigtime_t* time) 165 { 166 if (flags & B_MEDIA_SEEK_TO_FRAME) { 167 *time = *frame * 1000 / mDecomp->GetInfo(APE_DECOMPRESS_TOTAL_BLOCKS) 168 * mDecomp->GetInfo(APE_DECOMPRESS_LENGTH_MS); 169 printf("FindKeyFrame for frame %Ld: %Ld\n", *frame, *time); 170 } else if (flags & B_MEDIA_SEEK_TO_TIME) { 171 *frame = (*time) / 1000 * mDecomp->GetInfo(APE_DECOMPRESS_TOTAL_BLOCKS) 172 / mDecomp->GetInfo(APE_DECOMPRESS_LENGTH_MS); 173 printf("FindKeyFrame for time %Ld: %Ld\n", *time, *frame); 174 } else 175 return B_ERROR; 176 177 return B_OK; 178 } 179 180 181 status_t 182 TAPEReader::Seek(void *cookie, uint32 flags, int64 *frame, bigtime_t *time) 183 { 184 int32 aNewBlock; 185 186 if (flags & B_MEDIA_SEEK_TO_FRAME) { 187 printf("Seek to frame %Ld\n", *frame); 188 aNewBlock = *frame; 189 } else if (flags & B_MEDIA_SEEK_TO_TIME) { 190 printf("Seek for time %Ld\n", *time); 191 aNewBlock = (*time) / 1000 * mDecomp->GetInfo(APE_DECOMPRESS_TOTAL_BLOCKS) 192 / mDecomp->GetInfo(APE_DECOMPRESS_LENGTH_MS); 193 } else 194 return B_ERROR; 195 196 int64 aNewTime = aNewBlock * mDecomp->GetInfo(APE_INFO_BLOCK_ALIGN); 197 if (mReadPosTotal - mReadPos < aNewTime && mReadPosTotal > aNewTime) { 198 // Requested seek frame is already in the current buffer, no need to 199 // actually seek, just set the play position 200 mPlayPos = aNewTime - mReadPosTotal + mReadPos; 201 } else { 202 mReadPosTotal = aNewBlock * mDecomp->GetInfo(APE_INFO_BLOCK_ALIGN); 203 mDecomp->Seek(aNewBlock); 204 ReadBlocks(); 205 } 206 return B_OK; 207 } 208 209 210 status_t 211 TAPEReader::Sniff(int32* oStreamCount) 212 { 213 Unset(); 214 // prepare about file 215 mSrcPIO = dynamic_cast<BPositionIO*>(Source()); 216 if (mSrcPIO == NULL) 217 return B_ERROR; 218 219 mPositionBridgeIO.SetPositionIO(mSrcPIO); 220 mDecomp = CreateIAPEDecompressEx(&mPositionBridgeIO); 221 if (mDecomp == NULL) 222 return B_ERROR; 223 224 // prepare about data 225 mDataSize = static_cast<int64>(mDecomp->GetInfo(APE_DECOMPRESS_TOTAL_BLOCKS)) 226 *mDecomp->GetInfo(APE_INFO_BLOCK_ALIGN); 227 mDecodedData = new char [max_c(BUFFER_SIZE*mDecomp->GetInfo(APE_INFO_CHANNELS), 228 BLOCK_COUNT*mDecomp->GetInfo(APE_INFO_BLOCK_ALIGN))]; 229 mLoadAPECheck = B_OK; 230 *oStreamCount = 1; 231 return B_OK; 232 } 233 234 235 void 236 TAPEReader::Unset() 237 { 238 mLoadAPECheck = B_NO_INIT; 239 // about file 240 mPositionBridgeIO.SetPositionIO(NULL); 241 mSrcPIO = NULL; 242 delete mDecomp; 243 // about data 244 mDataSize = 0; 245 mReadPos = 0; 246 mReadPosTotal = 0; 247 mPlayPos = 0; 248 delete [] mDecodedData; 249 } 250 251 252 TAPEReaderPlugin::TAPEReaderPlugin() 253 { 254 } 255 256 257 TAPEReaderPlugin::~TAPEReaderPlugin() 258 { 259 } 260 261 262 Reader* 263 TAPEReaderPlugin::NewReader() 264 { 265 return new TAPEReader(); 266 } 267 268 269 MediaPlugin* 270 instantiate_plugin() 271 { 272 return new TAPEReaderPlugin(); 273 } 274