int main(int argc, char *argv[]) { // 256 frames * 4 buffer parts * 2 channels * 2 bytes per sample // will give us internal buffer of 4096 bytes size_t framesPerBufferPart = 256; size_t bufferPartCount = 4; if (argc != 2 && argc != 4) { printf("Usage: %s <sound file name> [<frames per part> <parts>]\n", argv[0]); return 0; } if (argc == 4) { size_t size = strtoul(argv[2], NULL, 10); if (size > 0) framesPerBufferPart = size; size = strtoul(argv[3], NULL, 10); if (size == 1) { printf("at least 2 buffer parts are needed\n"); return 1; } if (size > 0) bufferPartCount = size; } printf("frames per buffer part: %ld\n", framesPerBufferPart); printf("buffer part count: %ld\n", bufferPartCount); BEntry entry(argv[1]); if (entry.InitCheck() != B_OK || !entry.Exists()) { printf("cannot open input file\n"); return 1; } entry_ref entryRef; entry.GetRef(&entryRef); BMediaFile mediaFile(&entryRef); if (mediaFile.InitCheck() != B_OK) { printf("file not supported\n"); return 1; } if (mediaFile.CountTracks() == 0) { printf("no tracks found in file\n"); return 1; } BMediaTrack *mediaTrack = mediaFile.TrackAt(0); if (mediaTrack == NULL) { printf("problem getting track from file\n"); return 1; } // propose format, let it decide frame rate, channels number and buf size media_format format; memset(&format, 0, sizeof(format)); format.type = B_MEDIA_RAW_AUDIO; format.u.raw_audio.format = media_raw_audio_format::B_AUDIO_SHORT; format.u.raw_audio.byte_order = B_MEDIA_LITTLE_ENDIAN; if (mediaTrack->DecodedFormat(&format) != B_OK) { printf("cannot set decoder output format\n"); return 1; } printf("negotiated format:\n"); printf("frame rate: %g Hz\n", format.u.raw_audio.frame_rate); printf("channel count: %ld\n", format.u.raw_audio.channel_count); printf("buffer size: %ld bytes\n", format.u.raw_audio.buffer_size); gs_audio_format gsFormat; memset(&gsFormat, 0, sizeof(gsFormat)); gsFormat.frame_rate = format.u.raw_audio.frame_rate; gsFormat.channel_count = format.u.raw_audio.channel_count; gsFormat.format = format.u.raw_audio.format; gsFormat.byte_order = format.u.raw_audio.byte_order; BPushGameSound pushGameSound(framesPerBufferPart, &gsFormat, bufferPartCount); if (pushGameSound.InitCheck() != B_OK) { printf("trouble initializing push game sound: %s\n", strerror(pushGameSound.InitCheck())); return 1; } uint8 *buffer; size_t bufferSize; if (pushGameSound.LockForCyclic((void **)&buffer, &bufferSize) != BPushGameSound::lock_ok) { printf("cannot lock buffer\n"); return 1; } memset(buffer, 0, bufferSize); if (pushGameSound.StartPlaying() != B_OK) { printf("cannot start playback\n"); return 1; } printf("playing, press [esc] to exit...\n"); uint8 decoded[format.u.raw_audio.buffer_size * 2]; size_t bufferPartSize = framesPerBufferPart * format.u.raw_audio.channel_count * (format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK); size_t decodedSize = 0; size_t partPos = 0; size_t pos = 0; /*pushGameSound.CurrentPosition();*/ key_info keyInfo; while (true) { // fill buffer part with data from decoded buffer while (partPos < bufferPartSize && decodedSize) { size_t size = min_c(bufferPartSize - partPos, decodedSize); memcpy(buffer + pos + partPos, decoded, size); partPos += size; decodedSize -= size; memmove(decoded, decoded + size, decodedSize); } // if there are too little data to fill next buffer part // read next decoded frames if (partPos < bufferPartSize) { int64 frameCount; if (mediaTrack->ReadFrames(decoded + decodedSize, &frameCount) != B_OK) break; if (frameCount == 0) break; decodedSize += frameCount * format.u.raw_audio.channel_count * (format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK); printf("\rtime: %.2f", (double)mediaTrack->CurrentTime() / 1000000LL); fflush(stdout); continue; } // this buffer part is done partPos = 0; pos += bufferPartSize; if (bufferSize <= pos) pos = 0; // playback sync - wait for the buffer part we're about to fill to be // played while (pushGameSound.CurrentPosition() >= pos + bufferPartSize || pushGameSound.CurrentPosition() < pos) snooze(1000 * framesPerBufferPart / gsFormat.frame_rate); // check escape key state if (get_key_info(&keyInfo) != B_OK) { printf("\nkeyboard state read error\n"); break; } if ((keyInfo.key_states[0] & 0x40) != 0) break; } pushGameSound.StopPlaying(); mediaFile.ReleaseTrack(mediaTrack); mediaFile.CloseFile(); printf("\nfinished.\n"); return 0; }
int32 MediaView::MediaPlayer( void *arg) { MediaView* view = (MediaView *)arg; BWindow* window = view->Window(); BBitmap* bitmap = view->fBitmap; BMediaTrack* videoTrack = view->fVideoTrack; BMediaTrack* audioTrack = view->fAudioTrack; BMediaTrack* counterTrack = (videoTrack != NULL) ? videoTrack : audioTrack; AudioOutput* audioOutput = view->fAudioOutput; void* adBuffer = view->fAudioDumpingBuffer; int64 numFrames = counterTrack->CountFrames(); int64 numFramesToSkip = 0; int64 numSkippedFrames = 0; bool scrubbing = false; bool seekNeeded = false; int64 dummy; media_header mh; bigtime_t vStartTime, aStartTime, seekTime, snoozeTime, startTime; bigtime_t curScrubbing, lastScrubbing, lastTime; curScrubbing = lastScrubbing = system_time(); seekTime = 0LL; // Main processing loop (handle stop->start->stop) while (acquire_sem(view->fPlaySem) == B_OK) { release_sem(view->fPlaySem); // as we are doing stop->start, restart audio if needed. if (audioTrack != NULL) audioOutput->Play(); startTime = system_time()-counterTrack->CurrentTime(); // This will loop until the end of the stream while ((counterTrack->CurrentFrame() < numFrames) || scrubbing) { // We are in scrub mode if (acquire_sem(view->fScrubSem) == B_OK) { curScrubbing = system_time(); // We are entering scrub mode if (!scrubbing) { if (audioTrack != NULL) audioOutput->Stop(); scrubbing = true; } // Do a seek. seekNeeded = true; seekTime = view->fScrubTime; } // We are not scrubbing else if (scrubbing) { if (audioTrack != NULL) audioOutput->Play(); scrubbing = false; } // Handle seeking if (seekNeeded) { if (videoTrack) { // Seek the seekTime as close as possible vStartTime = seekTime; videoTrack->SeekToTime(&vStartTime); // Read frames until we get less than 50ms ahead. lastTime = vStartTime; do { bitmap->LockBits(); status_t err = videoTrack->ReadFrames((char*)bitmap->Bits(), &dummy, &mh); bitmap->UnlockBits(); if (err != B_OK) break; vStartTime = mh.start_time; if ((dummy == 0) || (vStartTime <= lastTime)) break; lastTime = vStartTime; } while (seekTime - vStartTime > 50000); } if (audioTrack) { // Seek the extractor as close as possible aStartTime = seekTime; audioOutput->SeekToTime(&aStartTime); // Read frames until we get less than 50ms ahead. lastTime = aStartTime; while (seekTime - aStartTime > 50000) { if (audioTrack->ReadFrames((char *)adBuffer, &dummy, &mh) != B_OK) break; aStartTime = mh.start_time; if ((dummy == 0) || (aStartTime <= lastTime)) break; lastTime = aStartTime; } } else startTime = system_time() - vStartTime; // Set the current time view->fCurTime = seekTime; seekNeeded = false; } // Handle normal playing mode else { // Get the next video frame, if any if (videoTrack != NULL) { bitmap->LockBits(); status_t err = videoTrack->ReadFrames((char*)bitmap->Bits(), &dummy, &mh); bitmap->UnlockBits(); if (err != B_OK) goto do_reset; if (dummy == 0) goto do_reset; vStartTime = mh.start_time; } // Estimated snoozeTime if (audioTrack != NULL) startTime = audioOutput->TrackTimebase(); if (videoTrack != NULL) snoozeTime = vStartTime - (system_time() - startTime); else snoozeTime = 25000; // Handle timing issues if (snoozeTime > 5000LL) { view->fSnoozing = true; snooze(snoozeTime-1000); view->fSnoozing = false; } else if (snoozeTime < -5000) { numSkippedFrames++; numFramesToSkip++; } // Set the current time if (!scrubbing) { view->fCurTime = system_time() - startTime; if (view->fCurTime < seekTime) view->fCurTime = seekTime; } } // Handle the drawing : no drawing if we need to skip a frame... if (numSkippedFrames > 0) numSkippedFrames--; // If we can't lock the window after 50ms, better to give up for // that frame... else if (window->LockWithTimeout(50000) == B_OK) { if ((videoTrack != NULL) && !view->fUsingOverlay) view->DrawBitmap(bitmap, view->VideoBounds()); view->fMediaBar->SetCurTime(view->fCurTime); window->Unlock(); // In scrub mode, don't scrub more than 10 times a second if (scrubbing) { snoozeTime = (100000LL+lastScrubbing) - system_time(); if (snoozeTime > 4000LL) { view->fSnoozing = true; snooze(snoozeTime-1000LL); view->fSnoozing = false; } lastScrubbing = curScrubbing; } } // Check if we are required to stop. if (acquire_sem_etc(view->fPlaySem, 1, B_TIMEOUT, 0) == B_OK) release_sem(view->fPlaySem); // The MediaView asked us to stop. else { if (audioTrack != NULL) audioOutput->Stop(); goto do_restart; } DEBUG("############ Current frame:%Ld, total frame:%Ld\n", counterTrack->CurrentFrame(), numFrames); } // If we exited the main streaming loop because we are at the end, // then we need to loop. if (counterTrack->CurrentFrame() >= numFrames) { do_reset: if (audioTrack != NULL) audioOutput->Stop(); seekNeeded = true; seekTime = 0LL; scrubbing = true; } do_restart:; } return (B_NO_ERROR); }