xref: /haiku/src/kits/media/TrackReader.cpp (revision b671e9bbdbd10268a042b4f4cc4317ccd03d105e)
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 <MediaTrack.h>
36 #include <MediaFile.h>
37 #include <File.h>
38 #include <string.h>
39 #include "TrackReader.h"
40 #include "debug.h"
41 
42 namespace BPrivate
43 {
44 
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::BTrackReader(BFile *file, media_raw_audio_format const &format) :
73 	fFrameSize(0),
74 	fBuffer(0),
75 	fBufferOffset(0),
76 	fBufferUsedSize(0),
77 	fMediaFile(0),
78 	fMediaTrack(0),
79 	fFormat(format)
80 {
81 	CALLED();
82 	if (file == NULL)
83 		return;
84 	if (file->InitCheck() != B_OK)
85 		return;
86 
87 	fMediaFile = new BMediaFile(file);
88 	if (fMediaFile->InitCheck() != B_OK)
89 		return;
90 
91 	int count = fMediaFile->CountTracks();
92 	if (count == 0) {
93 		ERROR("BTrackReader: no tracks in file\n");
94 		return;
95 	}
96 
97 	// find the first audio track
98 	BMediaTrack *track;
99 	BMediaTrack *audiotrack = 0;
100 	for (int tr = 0; tr < count; tr++) {
101 		track = fMediaFile->TrackAt(tr);
102 		if (track == 0 || track->InitCheck() != B_OK)
103 			continue;
104 		media_format fmt;
105 		if (track->DecodedFormat(&fmt) != B_OK)
106 			continue;
107 		if (fmt.type == B_MEDIA_RAW_AUDIO) {
108 			audiotrack = track;
109 			break;
110 		}
111 		fMediaFile->ReleaseTrack(track);
112 	}
113 	if (audiotrack == 0) {
114 		ERROR("BTrackReader: no audio track in file\n");
115 		return;
116 	}
117 
118 	SetToTrack(audiotrack);
119 
120 	// if the track was not set, release it
121 	if (fMediaTrack == 0) {
122 		fMediaFile->ReleaseTrack(audiotrack);
123 		return;
124 	}
125 
126 	fBuffer = new uint8[fFormat.buffer_size];
127 	fFrameSize = fFormat.channel_count * (fFormat.format & media_raw_audio_format::B_AUDIO_SIZE_MASK);
128 
129 	TRACE("BTrackReader::BTrackReader successful\n");
130 }
131 
132 void
133 BTrackReader::SetToTrack(BMediaTrack *track)
134 {
135 	media_format fmt;
136 	memset(&fmt,0,sizeof(fmt)); //wildcard
137 	memcpy(&fmt.u.raw_audio,&fFormat,sizeof(fFormat));
138 	fmt.type = B_MEDIA_RAW_AUDIO;
139 	//try to find a output format
140 	if (B_OK == track->DecodedFormat(&fmt)) {
141 		memcpy(&fFormat,&fmt.u.raw_audio,sizeof(fFormat));
142 		fMediaTrack = track;
143 		return;
144 	}
145 
146 	//try again
147 	fmt.u.raw_audio.buffer_size = 2 * 4096;
148 	fmt.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT;
149 	if (B_OK == track->DecodedFormat(&fmt)) {
150 		memcpy(&fFormat,&fmt.u.raw_audio,sizeof(fFormat));
151 		fMediaTrack = track;
152 		return;
153 	}
154 
155 	//try again
156 	fmt.u.raw_audio.buffer_size = 4096;
157 	fmt.u.raw_audio.format = media_raw_audio_format::B_AUDIO_SHORT;
158 	if (B_OK == track->DecodedFormat(&fmt)) {
159 		memcpy(&fFormat,&fmt.u.raw_audio,sizeof(fFormat));
160 		fMediaTrack = track;
161 		return;
162 	}
163 
164 	//we have failed
165 	ERROR("BTrackReader::SetToTrack failed\n");
166 }
167 
168 BTrackReader::~BTrackReader()
169 {
170 	CALLED();
171 	if (fMediaFile && fMediaTrack)
172 		fMediaFile->ReleaseTrack(fMediaTrack);
173 	delete fMediaFile;
174 	delete [] fBuffer;
175 }
176 
177 status_t
178 BTrackReader::InitCheck()
179 {
180 	CALLED();
181 	return fMediaTrack ? fMediaTrack->InitCheck() : B_ERROR;
182 }
183 
184 int64
185 BTrackReader::CountFrames(void)
186 {
187 	CALLED();
188 	return fMediaTrack ? fMediaTrack->CountFrames() : 0;
189 }
190 
191 const media_raw_audio_format &
192 BTrackReader::Format(void) const
193 {
194 	CALLED();
195 	return fFormat;
196 }
197 
198 int32
199 BTrackReader::FrameSize(void)
200 {
201 	CALLED();
202 	return fFrameSize;
203 }
204 
205 status_t
206 BTrackReader::ReadFrames(void *in_buffer, int32 frame_count)
207 {
208 	CALLED();
209 
210 	uint8 *buffer = static_cast<uint8 *>(in_buffer);
211 	int32 bytes_to_read = frame_count * fFrameSize;
212 
213 	status_t last_status = B_OK;
214 	while (bytes_to_read > 0) {
215 		int32 bytes_to_copy = min_c(fBufferUsedSize,bytes_to_read);
216 		if (bytes_to_copy > 0) {
217 			memcpy(buffer,fBuffer + fBufferOffset,bytes_to_copy);
218 			buffer += bytes_to_copy;
219 			bytes_to_read -= bytes_to_copy;
220 			fBufferOffset += bytes_to_copy;
221 			fBufferUsedSize -= bytes_to_copy;
222 		}
223 		if (last_status != B_OK)
224 			break;
225 		if (fBufferUsedSize == 0) {
226 			int64 outFrameCount;
227 			last_status = fMediaTrack->ReadFrames(fBuffer,&outFrameCount);
228 			fBufferOffset = 0;
229 			fBufferUsedSize = outFrameCount * fFrameSize;
230 		}
231 	}
232 	if (bytes_to_read > 0) {
233 		memset(buffer,0,bytes_to_read);
234 		return B_LAST_BUFFER_ERROR;
235 	} else {
236 		return B_OK;
237 	}
238 }
239 
240 status_t
241 BTrackReader::SeekToFrame(int64 *in_out_frame)
242 {
243 	CALLED();
244 	status_t s = fMediaTrack->SeekToFrame(in_out_frame, B_MEDIA_SEEK_CLOSEST_BACKWARD);
245 	if (s != B_OK)
246 		return s;
247 	fBufferUsedSize = 0;
248 	fBufferOffset = 0;
249 	return B_OK;
250 }
251 
252 BMediaTrack *
253 BTrackReader::Track(void)
254 {
255 	CALLED();
256 	return fMediaTrack;
257 }
258 
259 }; //namespace BPrivate
260 
261