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 "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 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 135 BTrackReader::SetToTrack(BMediaTrack *track) 136 { 137 media_format fmt; 138 memset(&fmt, 0, sizeof(fmt)); //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 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 182 BTrackReader::InitCheck() 183 { 184 CALLED(); 185 return fMediaTrack ? fMediaTrack->InitCheck() : B_ERROR; 186 } 187 188 189 int64 190 BTrackReader::CountFrames(void) 191 { 192 CALLED(); 193 return fMediaTrack ? fMediaTrack->CountFrames() : 0; 194 } 195 196 197 const media_raw_audio_format & 198 BTrackReader::Format(void) const 199 { 200 CALLED(); 201 return fFormat; 202 } 203 204 205 int32 206 BTrackReader::FrameSize(void) 207 { 208 CALLED(); 209 return fFrameSize; 210 } 211 212 213 status_t 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 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* 263 BTrackReader::Track(void) 264 { 265 CALLED(); 266 return fMediaTrack; 267 } 268 269 }; //namespace BPrivate 270 271