| 248 | } |
| 249 | |
| 250 | bool Mp3StreamDecoderImpl::findAndDecodeFrame(audio::Sample* out_sample) { |
| 251 | if (!mDecoder) { |
| 252 | return false; |
| 253 | } |
| 254 | |
| 255 | // Try to decode from current buffer |
| 256 | const fl::u8* inptr = mBuffer.data() + mBufferPos; |
| 257 | fl::size bytes_left = mBufferFilled - mBufferPos; |
| 258 | |
| 259 | if (bytes_left == 0) { |
| 260 | return false; |
| 261 | } |
| 262 | |
| 263 | // Find sync word |
| 264 | int offset = mDecoder->findSyncWord(inptr, bytes_left); |
| 265 | if (offset < 0) { |
| 266 | // No sync word found, consume buffer and try again |
| 267 | mBufferPos = mBufferFilled; |
| 268 | return false; |
| 269 | } |
| 270 | |
| 271 | inptr += offset; |
| 272 | bytes_left -= offset; |
| 273 | mBufferPos += offset; |
| 274 | |
| 275 | // Try to decode one frame |
| 276 | const fl::u8* decode_ptr = inptr; |
| 277 | fl::size decode_bytes = bytes_left; |
| 278 | |
| 279 | int result = mDecoder->decodeFrame(&decode_ptr, &decode_bytes); |
| 280 | |
| 281 | // Update buffer position based on how many bytes were consumed |
| 282 | fl::size consumed = (decode_ptr - inptr); |
| 283 | mBufferPos += consumed; |
| 284 | mBytesProcessed += consumed; |
| 285 | |
| 286 | if (result == 0) { |
| 287 | // Successfully decoded a frame |
| 288 | Mp3Frame frame; |
| 289 | frame.pcm = mDecoder->mPcmBuffer.get(); |
| 290 | frame.samples = mDecoder->mFrameInfo.outputSamps / mDecoder->mFrameInfo.nChans; |
| 291 | frame.channels = mDecoder->mFrameInfo.nChans; |
| 292 | frame.sample_rate = mDecoder->mFrameInfo.samprate; |
| 293 | frame.bitrate = mDecoder->mFrameInfo.bitrate; |
| 294 | frame.version = mDecoder->mFrameInfo.version; |
| 295 | frame.layer = mDecoder->mFrameInfo.layer; |
| 296 | |
| 297 | // Update stream info on first successful decode |
| 298 | if (!mHasDecodedFirstFrame) { |
| 299 | mInfo.sampleRate = frame.sample_rate; |
| 300 | mInfo.channels = static_cast<fl::u8>(frame.channels); |
| 301 | mInfo.bitrate = frame.bitrate; |
| 302 | mInfo.version = static_cast<fl::u8>(frame.version); |
| 303 | mInfo.layer = static_cast<fl::u8>(frame.layer); |
| 304 | mInfo.isValid = true; |
| 305 | mHasDecodedFirstFrame = true; |
| 306 | } |
| 307 |
nothing calls this directly
no test coverage detected