xref: /haiku/src/kits/media/TrackReader.cpp (revision b84955d416f92e89c9d73999f545a2dec353d988)
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