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