vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / media / plugins / ape_reader / APEReader.cpp
blob09c1a21609535ca77eae36ac0ae388997b9ae140
1 /* Copyright 2005-2009 SHINTA
2 * Distributed under the terms of the MIT license
3 */
6 #include <InterfaceDefs.h>
7 #include <MediaIO.h>
9 #include "APEReader.h"
10 #include "MACLib.h"
13 static const char* kCopyrightString
14 = "Copyright " B_UTF8_COPYRIGHT " 2005-2009 by SHINTA";
17 TAPEReader::TAPEReader()
18 : SUPER()
20 mDecodedData = NULL;
21 mDecomp = NULL;
22 Unset();
26 TAPEReader::~TAPEReader()
31 status_t
32 TAPEReader::AllocateCookie(int32 oStreamNumber, void** oCookie)
34 *oCookie = NULL;
35 return B_OK;
39 const char*
40 TAPEReader::Copyright()
42 return kCopyrightString;
46 bigtime_t
47 TAPEReader::CurrentTime() const
49 return mDecomp->GetInfo(APE_DECOMPRESS_CURRENT_MS)
50 * static_cast<bigtime_t>(1000);
54 status_t
55 TAPEReader::FreeCookie(void* oCookie)
57 return B_OK;
61 void
62 TAPEReader::GetFileFormatInfo(media_file_format* oMFF)
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 strcpy(oMFF->mime_type, MIME_TYPE_APE);
72 strcpy(oMFF->pretty_name, MIME_TYPE_APE_LONG_DESCRIPTION);
73 strcpy(oMFF->short_name, MIME_TYPE_APE_SHORT_DESCRIPTION);
74 strcpy(oMFF->file_extension, MIME_TYPE_APE_EXTENSION);
78 status_t
79 TAPEReader::GetNextChunk(void* oCookie, const void** oChunkBuffer,
80 size_t* oChunkSize, media_header* oMediaHeader)
82 int64 aOutSize;
84 // check whether song is finished or not
85 if (mReadPosTotal - mReadPos + mPlayPos >= mDataSize)
86 return B_ERROR;
88 // reading data
89 if (mPlayPos >= mReadPos )
90 ReadBlocks();
92 // passing data
93 if (mReadPos-mPlayPos >= BUFFER_SIZE)
94 aOutSize = BUFFER_SIZE;
95 else
96 aOutSize = mReadPos-mPlayPos;
98 *oChunkBuffer = &mDecodedData[mPlayPos];
99 mPlayPos += aOutSize;
101 // passing info
102 *oChunkSize = aOutSize;
103 oMediaHeader->start_time = CurrentTime();
104 oMediaHeader->file_pos = mPlayPos;
105 return B_OK;
109 status_t
110 TAPEReader::GetStreamInfo(void* oCookie, int64* oFrameCount,
111 bigtime_t* oDuration, media_format* oFormat, const void** oInfoBuffer,
112 size_t* oInfoSize)
114 if (LoadAPECheck() != B_OK)
115 return LoadAPECheck();
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;
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;
138 status_t
139 TAPEReader::LoadAPECheck() const
141 return mLoadAPECheck;
145 status_t
146 TAPEReader::ReadBlocks()
148 int aBlocksRead;
149 int aRetVal = 0;
151 aRetVal = mDecomp->GetData(reinterpret_cast<char*>(mDecodedData),
152 BLOCK_COUNT, &aBlocksRead);
153 if (aRetVal != ERROR_SUCCESS)
154 return B_ERROR;
156 mPlayPos = 0;
157 mReadPos = aBlocksRead*mDecomp->GetInfo(APE_INFO_BLOCK_ALIGN);
158 mReadPosTotal += mReadPos;
159 return B_OK;
163 status_t
164 TAPEReader::FindKeyFrame(void* cookie, uint32 flags, int64* frame,
165 bigtime_t* time)
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 %Ld: %Ld\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 %Ld: %Ld\n", *time, *frame);
175 } else
176 return B_ERROR;
178 return B_OK;
182 status_t
183 TAPEReader::Seek(void *cookie, uint32 flags, int64 *frame, bigtime_t *time)
185 int32 aNewBlock;
187 if (flags & B_MEDIA_SEEK_TO_FRAME) {
188 printf("Seek to frame %Ld\n", *frame);
189 aNewBlock = *frame;
190 } else if (flags & B_MEDIA_SEEK_TO_TIME) {
191 printf("Seek for time %Ld\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;
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();
207 return B_OK;
211 status_t
212 TAPEReader::Sniff(int32* oStreamCount)
214 Unset();
215 // prepare about file
216 mSrcPIO = dynamic_cast<BPositionIO*>(Source());
217 if (mSrcPIO == NULL)
218 return B_ERROR;
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;
231 int nFunctionRetVal = ERROR_SUCCESS;
232 mPositionBridgeIO.SetPositionIO(mSrcPIO);
234 mDecomp = CreateIAPEDecompressEx(&mPositionBridgeIO, &nFunctionRetVal);
235 if (mDecomp == NULL || nFunctionRetVal != ERROR_SUCCESS)
236 return B_ERROR;
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;
249 void
250 TAPEReader::Unset()
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;
266 TAPEReaderPlugin::TAPEReaderPlugin()
271 TAPEReaderPlugin::~TAPEReaderPlugin()
276 Reader*
277 TAPEReaderPlugin::NewReader()
279 return new TAPEReader();
283 MediaPlugin*
284 instantiate_plugin()
286 return new TAPEReaderPlugin();