1 /*
2 * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files or portions
6 * thereof (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so, subject
10 * to the following conditions:
11 *
12 * * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above copyright notice
16 * in the binary, as well as this list of conditions and the following
17 * disclaimer in the documentation and/or other materials provided with
18 * the distribution.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 * THE SOFTWARE.
27 *
28 */
29
30 /*
31 * The undocumented BTrackReader class,
32 * used by BSound and the GameSound classes
33 */
34
35 #include <File.h>
36 #include <MediaTrack.h>
37 #include <MediaFile.h>
38 #include <string.h>
39 #include "TrackReader.h"
40 #include "MediaDebug.h"
41
42 namespace BPrivate
43 {
44
BTrackReader(BMediaTrack * track,media_raw_audio_format const & format)45 BTrackReader::BTrackReader(BMediaTrack *track, media_raw_audio_format const &format) :
46 fFrameSize(0),
47 fBuffer(0),
48 fBufferOffset(0),
49 fBufferUsedSize(0),
50 fMediaFile(0),
51 fMediaTrack(0),
52 fFormat(format)
53 {
54 CALLED();
55 if (track == NULL)
56 return;
57 if (track->InitCheck() != B_OK)
58 return;
59
60 SetToTrack(track);
61
62 // if the track was not set abort now
63 if (fMediaTrack == 0)
64 return;
65
66 fBuffer = new uint8[fFormat.buffer_size];
67 fFrameSize = fFormat.channel_count * (fFormat.format & media_raw_audio_format::B_AUDIO_SIZE_MASK);
68
69 TRACE("BTrackReader::BTrackReader successful\n");
70 }
71
72
BTrackReader(BFile * file,media_raw_audio_format const & format)73 BTrackReader::BTrackReader(BFile *file, media_raw_audio_format const &format) :
74 fFrameSize(0),
75 fBuffer(0),
76 fBufferOffset(0),
77 fBufferUsedSize(0),
78 fMediaFile(0),
79 fMediaTrack(0),
80 fFormat(format)
81 {
82 CALLED();
83 if (file == NULL)
84 return;
85 if (file->InitCheck() != B_OK)
86 return;
87
88 fMediaFile = new BMediaFile(file);
89 if (fMediaFile->InitCheck() != B_OK)
90 return;
91
92 int count = fMediaFile->CountTracks();
93 if (count == 0) {
94 ERROR("BTrackReader: no tracks in file\n");
95 return;
96 }
97
98 // find the first audio track
99 BMediaTrack *track;
100 BMediaTrack *audiotrack = 0;
101 for (int tr = 0; tr < count; tr++) {
102 track = fMediaFile->TrackAt(tr);
103 if (track == 0 || track->InitCheck() != B_OK)
104 continue;
105 media_format fmt;
106 if (track->DecodedFormat(&fmt) != B_OK)
107 continue;
108 if (fmt.type == B_MEDIA_RAW_AUDIO) {
109 audiotrack = track;
110 break;
111 }
112 fMediaFile->ReleaseTrack(track);
113 }
114 if (audiotrack == 0) {
115 ERROR("BTrackReader: no audio track in file\n");
116 return;
117 }
118
119 SetToTrack(audiotrack);
120
121 // if the track was not set, release it
122 if (fMediaTrack == 0) {
123 fMediaFile->ReleaseTrack(audiotrack);
124 return;
125 }
126
127 fBuffer = new uint8[fFormat.buffer_size];
128 fFrameSize = fFormat.channel_count * (fFormat.format & media_raw_audio_format::B_AUDIO_SIZE_MASK);
129
130 TRACE("BTrackReader::BTrackReader successful\n");
131 }
132
133
134 void
SetToTrack(BMediaTrack * track)135 BTrackReader::SetToTrack(BMediaTrack *track)
136 {
137 media_format fmt;
138 fmt.Clear(); //wildcard
139 memcpy(&fmt.u.raw_audio, &fFormat, sizeof(fFormat));
140 fmt.type = B_MEDIA_RAW_AUDIO;
141 //try to find a output format
142 if (track->DecodedFormat(&fmt) == B_OK) {
143 memcpy(&fFormat, &fmt.u.raw_audio, sizeof(fFormat));
144 fMediaTrack = track;
145 return;
146 }
147
148 //try again
149 fmt.u.raw_audio.buffer_size = 2 * 4096;
150 fmt.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT;
151 if (track->DecodedFormat(&fmt) == B_OK) {
152 memcpy(&fFormat, &fmt.u.raw_audio, sizeof(fFormat));
153 fMediaTrack = track;
154 return;
155 }
156
157 //try again
158 fmt.u.raw_audio.buffer_size = 4096;
159 fmt.u.raw_audio.format = media_raw_audio_format::B_AUDIO_SHORT;
160 if (track->DecodedFormat(&fmt) == B_OK) {
161 memcpy(&fFormat, &fmt.u.raw_audio, sizeof(fFormat));
162 fMediaTrack = track;
163 return;
164 }
165
166 //we have failed
167 ERROR("BTrackReader::SetToTrack failed\n");
168 }
169
170
~BTrackReader()171 BTrackReader::~BTrackReader()
172 {
173 CALLED();
174 if (fMediaFile && fMediaTrack)
175 fMediaFile->ReleaseTrack(fMediaTrack);
176 delete fMediaFile;
177 delete[] fBuffer;
178 }
179
180
181 status_t
InitCheck()182 BTrackReader::InitCheck()
183 {
184 CALLED();
185 return fMediaTrack ? fMediaTrack->InitCheck() : B_ERROR;
186 }
187
188
189 int64
CountFrames(void)190 BTrackReader::CountFrames(void)
191 {
192 CALLED();
193 return fMediaTrack ? fMediaTrack->CountFrames() : 0;
194 }
195
196
197 const media_raw_audio_format &
Format(void) const198 BTrackReader::Format(void) const
199 {
200 CALLED();
201 return fFormat;
202 }
203
204
205 int32
FrameSize(void)206 BTrackReader::FrameSize(void)
207 {
208 CALLED();
209 return fFrameSize;
210 }
211
212
213 status_t
ReadFrames(void * in_buffer,int32 frame_count)214 BTrackReader::ReadFrames(void* in_buffer, int32 frame_count)
215 {
216 CALLED();
217
218 uint8* buffer = static_cast<uint8*>(in_buffer);
219 int32 bytes_to_read = frame_count * fFrameSize;
220
221 status_t last_status = B_OK;
222 while (bytes_to_read > 0) {
223 int32 bytes_to_copy = min_c(fBufferUsedSize, bytes_to_read);
224 if (bytes_to_copy > 0) {
225 memcpy(buffer, fBuffer + fBufferOffset, bytes_to_copy);
226 buffer += bytes_to_copy;
227 bytes_to_read -= bytes_to_copy;
228 fBufferOffset += bytes_to_copy;
229 fBufferUsedSize -= bytes_to_copy;
230 }
231 if (last_status != B_OK)
232 break;
233 if (fBufferUsedSize == 0) {
234 int64 outFrameCount;
235 last_status = fMediaTrack->ReadFrames(fBuffer,
236 &outFrameCount);
237 fBufferOffset = 0;
238 fBufferUsedSize = outFrameCount * fFrameSize;
239 }
240 }
241 if (bytes_to_read > 0) {
242 memset(buffer, 0, bytes_to_read);
243 return B_LAST_BUFFER_ERROR;
244 }
245 return B_OK;
246 }
247
248
249 status_t
SeekToFrame(int64 * in_out_frame)250 BTrackReader::SeekToFrame(int64* in_out_frame)
251 {
252 CALLED();
253 status_t s = fMediaTrack->SeekToFrame(in_out_frame, B_MEDIA_SEEK_CLOSEST_BACKWARD);
254 if (s != B_OK)
255 return s;
256 fBufferUsedSize = 0;
257 fBufferOffset = 0;
258 return B_OK;
259 }
260
261
262 BMediaTrack*
Track(void)263 BTrackReader::Track(void)
264 {
265 CALLED();
266 return fMediaTrack;
267 }
268
269 }; //namespace BPrivate
270
271