xref: /haiku/src/add-ons/media/plugins/ape_reader/APEReader.cpp (revision e661df29804f2703a65e23f5789c3c87c0915298)
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