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