void MediaFileInfoView::_GetFileInfo(BString* audioFormat, BString* videoFormat, BString* audioDetails, BString* videoDetails, BString* duration) { fDuration = 0; if (fMediaFile == NULL) return; BMediaTrack* track; media_format format; memset(&format, 0, sizeof(format)); media_codec_info codecInfo; bool audioDone(false), videoDone(false); bigtime_t audioDuration = 0; bigtime_t videoDuration = 0; int32 tracks = fMediaFile->CountTracks(); int64 videoFrames = 0; int64 audioFrames = 0; for (int32 i = 0; i < tracks && (!audioDone || !videoDone); i++) { track = fMediaFile->TrackAt(i); if (track != NULL) { track->EncodedFormat(&format); if (format.IsVideo()) { memset(&format, 0, sizeof(format)); format.type = B_MEDIA_RAW_VIDEO; track->DecodedFormat(&format); media_raw_video_format *rvf = &(format.u.raw_video); track->GetCodecInfo(&codecInfo); *videoFormat << codecInfo.pretty_name; videoDuration = track->Duration(); videoFrames = track->CountFrames(); *videoDetails << (int32)format.Width() << "x" << (int32)format.Height() << " " << (int32)(rvf->field_rate / rvf->interlace) << " fps / " << videoFrames << " frames"; videoDone = true; } else if (format.IsAudio()) { memset(&format, 0, sizeof(format)); format.type = B_MEDIA_RAW_AUDIO; track->DecodedFormat(&format); media_raw_audio_format *raf = &(format.u.raw_audio); char bytesPerSample = (char)(raf->format & 0xf); if (bytesPerSample == 1) { *audioDetails << "8 bit "; } else if (bytesPerSample == 2) { *audioDetails << "16 bit "; } else { *audioDetails << bytesPerSample << "byte "; } track->GetCodecInfo(&codecInfo); *audioFormat << codecInfo.pretty_name; audioDuration = track->Duration(); audioFrames = track->CountFrames(); *audioDetails << (float)(raf->frame_rate / 1000.0f) << " kHz"; if (raf->channel_count == 1) { *audioDetails << " mono / "; } else if (raf->channel_count == 2) { *audioDetails << " stereo / "; } else { *audioDetails << (int32)raf->channel_count << " channel / " ; } *audioDetails << audioFrames << " frames"; audioDone = true; } fMediaFile->ReleaseTrack(track); } } fDuration = MAX(audioDuration, videoDuration); *duration << (int32)(fDuration / 1000000) << " seconds"; }
status_t MainView::LoadWave(const entry_ref& ref) { bigtime_t startLoadWave = system_time(); fDestCursor = 0; fSourceCursor = 0; fAverage = 0.0f; fAverageCursor = 0; fDownsamplingWidth = 0; fDownsampleCount = 0; // instantiate a BMediaFile object, and make sure there was no error. /*BEntry entry("./song.wav"); entry_ref ref; entry.GetRef(&ref);*/ BMediaFile* mediaFile = new BMediaFile(&ref); status_t err = mediaFile->InitCheck(); if (err != B_OK) { printf("cannot contruct BMediaFile object -- %s\n", strerror(err)); return err; } for (int32 i = 0; i < mediaFile->CountTracks(); i++) { BMediaTrack* track = mediaFile->TrackAt(i); if (track == NULL) { printf("cannot contruct BMediaTrack object\n"); return B_ERROR; } media_format format; format.type = B_MEDIA_RAW_AUDIO; format.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT; err = track->DecodedFormat(&format); if (err != B_OK) { printf("BMediaTrack::DecodedFormat error -- %s\n", strerror(err)); return err; } if (format.type == B_MEDIA_RAW_AUDIO) { // get the actual sourceWindow.left obtained by seeking bigtime_t start = system_time(); int64 actualSeekFrame = fSourceWindow.left; err = track->SeekToFrame(&actualSeekFrame); if (err != B_OK) { printf("BMediaTrack::SeekToFrame(%lli) error -- %s\n", fSourceWindow.left, strerror(err)); return err; } printf("BMediaTrack::SeekToFrame(%lli) seekedto=%lli in %llims\n", fSourceWindow.left, actualSeekFrame, (system_time() - start) / 1000); fSourceWindow.left = actualSeekFrame; frame_range destWindow(0, (uint64) fWaveFrame.Width()); int64 totalSourceFrameCount = track->CountFrames(); fDownsamplingWidth = fSourceWindow.Width() / destWindow.Width(); printf("Source window left=%lli right=%lli width=%lli (total=%lli)\n", fSourceWindow.left, fSourceWindow.right, fSourceWindow.Width(), totalSourceFrameCount); printf("Dest window left=%lli right=%lli width=%lli\n", destWindow.left, destWindow.right, destWindow.Width()); printf("Downsampling width=%lli\n", fDownsamplingWidth); delete [] fWave; fWave = NULL; fWave = new(std::nothrow) float[fSourceWindow.Width() / fDownsamplingWidth]; // ATT: on en prend plus que la largeur de dest car downsampling width entier if (fWave == NULL) return B_NO_MEMORY; char* buffer = new(std::nothrow) char[format.u.raw_audio.buffer_size]; if (buffer == NULL) return B_NO_MEMORY; int64 readFrameCount = 0; media_header mediaHeader; fSourceCursor = fSourceWindow.left; for(int64 j = 0; j < fSourceWindow.Width(); j += readFrameCount) { err = track->ReadFrames(buffer, &readFrameCount, &mediaHeader); if (err) { printf("BMediaTrack::ReadFrames error -- %s\n", strerror(err)); delete [] buffer; break; // TODO fatal error? } if (fSourceCursor + readFrameCount >= fSourceWindow.right) { readFrameCount = fSourceWindow.right - fSourceCursor; printf("yes readFrameCount = %lli\n", readFrameCount); } _ProcessAudio(buffer, &format, readFrameCount); } printf("Source cursor %li (read %li)\n", fSourceCursor, fSourceCursor - fSourceWindow.left); printf("Dest cursor %li\n", fDestCursor); delete [] buffer; } mediaFile->ReleaseTrack(track); } delete mediaFile; printf("LoadWave in %lims\n", (system_time() - startLoadWave) / 1000 ); fCurrentEntryRef = ref; return B_OK; }
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); }
status_t MediaFileInfo::LoadInfo(BMediaFile* file) { _Reset(); if (!file) return B_BAD_VALUE; BMediaTrack* track; media_format format; memset(&format, 0, sizeof(format)); media_codec_info codecInfo; bool audioDone(false), videoDone(false); bigtime_t audioDuration = 0; bigtime_t videoDuration = 0; int32 tracks = file->CountTracks(); int64 videoFrames = 0; int64 audioFrames = 0; status_t ret = B_OK; for (int32 i = 0; i < tracks && (!audioDone || !videoDone); i++) { track = file->TrackAt(i); if (track == NULL) return B_ERROR; ret = track->InitCheck(); if (ret != B_OK) return ret; ret = track->EncodedFormat(&format); if (ret != B_OK) return ret; if (format.IsVideo()) { memset(&format, 0, sizeof(format)); format.type = B_MEDIA_RAW_VIDEO; ret = track->DecodedFormat(&format); if (ret != B_OK) return ret; media_raw_video_format *rvf = &(format.u.raw_video); ret = track->GetCodecInfo(&codecInfo); if (ret != B_OK) return ret; video.format << codecInfo.pretty_name; videoDuration = track->Duration(); videoFrames = track->CountFrames(); BString details; snprintf(details.LockBuffer(256), 256, B_TRANSLATE_COMMENT("%u x %u, %.2ffps / %Ld frames", "Width x Height, fps / frames"), format.Width(), format.Height(), rvf->field_rate / rvf->interlace, videoFrames); details.UnlockBuffer(); video.details << details; videoDone = true; } else if (format.IsAudio()) { memset(&format, 0, sizeof(format)); format.type = B_MEDIA_RAW_AUDIO; ret = track->DecodedFormat(&format); if (ret != B_OK) return ret; media_raw_audio_format *raf = &(format.u.raw_audio); char bytesPerSample = (char)(raf->format & 0xf); BString details; if (bytesPerSample == 1 || bytesPerSample == 2) { snprintf(details.LockBuffer(16), 16, B_TRANSLATE("%d bit "), bytesPerSample * 8); } else { snprintf(details.LockBuffer(16), 16, B_TRANSLATE("%d byte "), bytesPerSample); } details.UnlockBuffer(); audio.details << details; ret = track->GetCodecInfo(&codecInfo); if (ret != B_OK) return ret; audio.format << codecInfo.pretty_name; audioDuration = track->Duration(); audioFrames = track->CountFrames(); BString channels; if (raf->channel_count == 1) { snprintf(channels.LockBuffer(64), 64, B_TRANSLATE("%.1f kHz mono / %lld frames"), raf->frame_rate / 1000.f, audioFrames); } else if (raf->channel_count == 2) { snprintf(channels.LockBuffer(64), 64, B_TRANSLATE("%.1f kHz stereo / %lld frames"), raf->frame_rate / 1000.f, audioFrames); } else { snprintf(channels.LockBuffer(64), 64, B_TRANSLATE("%.1f kHz %ld channel / %lld frames"), raf->frame_rate / 1000.f, raf->channel_count, audioFrames); } channels.UnlockBuffer(); audio.details << channels; audioDone = true; } ret = file->ReleaseTrack(track); if (ret != B_OK) return ret; } useconds = MAX(audioDuration, videoDuration); duration << (int32)(useconds / 1000000) << B_TRANSLATE(" seconds"); return B_OK; }
status_t MediaConverterApp::_ConvertFile(BMediaFile* inFile, BMediaFile* outFile, media_codec_info* audioCodec, media_codec_info* videoCodec, int32 audioQuality, int32 videoQuality, bigtime_t startDuration, bigtime_t endDuration) { BMediaTrack* inVidTrack = NULL; BMediaTrack* inAudTrack = NULL; BMediaTrack* outVidTrack = NULL; BMediaTrack* outAudTrack = NULL; media_format inFormat; media_format outAudFormat; media_format outVidFormat; media_raw_audio_format* raf = NULL; media_raw_video_format* rvf = NULL; int32 width = -1; int32 height = -1; uint8* videoBuffer = NULL; uint8* audioBuffer = NULL; // gather the necessary format information and construct output tracks int64 videoFrameCount = 0; int64 audioFrameCount = 0; status_t ret = B_OK; int32 tracks = inFile->CountTracks(); for (int32 i = 0; i < tracks && (!outAudTrack || !outVidTrack); i++) { BMediaTrack* inTrack = inFile->TrackAt(i); memset(&inFormat, 0, sizeof(media_format)); inTrack->EncodedFormat(&inFormat); if (inFormat.IsAudio() && (audioCodec != NULL)) { inAudTrack = inTrack; memset(&outAudFormat, 0, sizeof(media_format)); outAudFormat.type = B_MEDIA_RAW_AUDIO; raf = &(outAudFormat.u.raw_audio); inTrack->DecodedFormat(&outAudFormat); audioBuffer = new uint8[raf->buffer_size]; // audioFrameSize = (raf->format & media_raw_audio_format::B_AUDIO_SIZE_MASK) // audioFrameSize = (raf->format & 0xf) * raf->channel_count; outAudTrack = outFile->CreateTrack(&outAudFormat, audioCodec); if (outAudTrack != NULL) { if (outAudTrack->SetQuality(audioQuality / 100.0f) != B_OK && fWin->Lock()) { fWin->SetAudioQualityLabel( B_TRANSLATE("Audio quality not supported")); fWin->Unlock(); } } } else if (inFormat.IsVideo() && (videoCodec != NULL)) { inVidTrack = inTrack; width = (int32)inFormat.Width(); height = (int32)inFormat.Height(); // construct desired decoded video format memset(&outVidFormat, 0, sizeof(outVidFormat)); outVidFormat.type = B_MEDIA_RAW_VIDEO; rvf = &(outVidFormat.u.raw_video); rvf->last_active = (uint32)(height - 1); rvf->orientation = B_VIDEO_TOP_LEFT_RIGHT; rvf->display.format = B_RGB32; rvf->display.bytes_per_row = 4 * width; rvf->display.line_width = width; rvf->display.line_count = height; inVidTrack->DecodedFormat(&outVidFormat); if (rvf->display.format == B_RGBA32) { printf("fixing color space (B_RGBA32 -> B_RGB32)"); rvf->display.format = B_RGB32; } // Transfer the display aspect ratio. if (inFormat.type == B_MEDIA_ENCODED_VIDEO) { rvf->pixel_width_aspect = inFormat.u.encoded_video.output.pixel_width_aspect; rvf->pixel_height_aspect = inFormat.u.encoded_video.output.pixel_height_aspect; } else { rvf->pixel_width_aspect = inFormat.u.raw_video.pixel_width_aspect; rvf->pixel_height_aspect = inFormat.u.raw_video.pixel_height_aspect; } videoBuffer = new (std::nothrow) uint8[height * rvf->display.bytes_per_row]; outVidTrack = outFile->CreateTrack(&outVidFormat, videoCodec); if (outVidTrack != NULL) { // DLM Added to use 3ivx Parameter View const char* videoQualitySupport = NULL; BView* encoderView = outVidTrack->GetParameterView(); if (encoderView) { MediaEncoderWindow* encoderWin = new MediaEncoderWindow(BRect(50, 50, 520, 555), encoderView); encoderWin->Go(); // blocks until the window is quit // The quality setting is ignored by the 3ivx encoder if the // view was displayed, but this method is the trigger to read // all the parameter settings outVidTrack->SetQuality(videoQuality / 100.0f); // We can now delete the encoderView created for us by the encoder delete encoderView; encoderView = NULL; videoQualitySupport = B_TRANSLATE("Video using parameters form settings"); } else { if (outVidTrack->SetQuality(videoQuality / 100.0f) >= B_OK) videoQualitySupport = B_TRANSLATE("Video quality not supported"); } if (videoQualitySupport && fWin->Lock()) { fWin->SetVideoQualityLabel(videoQualitySupport); fWin->Unlock(); } } } else { // didn't do anything with the track inFile->ReleaseTrack(inTrack); } } if (!outVidTrack && !outAudTrack) { printf("MediaConverterApp::_ConvertFile() - no tracks found!\n"); ret = B_ERROR; } if (fCancel) { // don't have any video or audio tracks here, or cancelled printf("MediaConverterApp::_ConvertFile()" " - user canceled before transcoding\n"); ret = B_CANCELED; } if (ret < B_OK) { delete[] audioBuffer; delete[] videoBuffer; delete outFile; return ret; } outFile->CommitHeader(); // this is where you would call outFile->AddCopyright(...) int64 framesRead; media_header mh; int32 lastPercent, currPercent; float completePercent; BString status; int64 start; int64 end; int32 stat = 0; // read video from source and write to destination, if necessary if (outVidTrack != NULL) { lastPercent = -1; videoFrameCount = inVidTrack->CountFrames(); if (endDuration == 0 || endDuration < startDuration) { start = 0; end = videoFrameCount; } else { inVidTrack->SeekToTime(&endDuration, stat); end = inVidTrack->CurrentFrame(); inVidTrack->SeekToTime(&startDuration, stat); start = inVidTrack->CurrentFrame(); if (end > videoFrameCount) end = videoFrameCount; if (start > end) start = 0; } framesRead = 0; for (int64 i = start; (i <= end) && !fCancel; i += framesRead) { if ((ret = inVidTrack->ReadFrames(videoBuffer, &framesRead, &mh)) != B_OK) { fprintf(stderr, "Error reading video frame %" B_PRId64 ": %s\n", i, strerror(ret)); snprintf(status.LockBuffer(128), 128, B_TRANSLATE("Error read video frame %" B_PRId64), i); status.UnlockBuffer(); SetStatusMessage(status.String()); break; } if ((ret = outVidTrack->WriteFrames(videoBuffer, framesRead, mh.u.encoded_video.field_flags)) != B_OK) { fprintf(stderr, "Error writing video frame %" B_PRId64 ": %s\n", i, strerror(ret)); snprintf(status.LockBuffer(128), 128, B_TRANSLATE("Error writing video frame %" B_PRId64), i); status.UnlockBuffer(); SetStatusMessage(status.String()); break; } completePercent = (float)(i - start) / (float)(end - start) * 100; currPercent = (int32)completePercent; if (currPercent > lastPercent) { lastPercent = currPercent; snprintf(status.LockBuffer(128), 128, B_TRANSLATE("Writing video track: %" B_PRId32 "%% complete"), currPercent); status.UnlockBuffer(); SetStatusMessage(status.String()); } } outVidTrack->Flush(); inFile->ReleaseTrack(inVidTrack); } // read audio from source and write to destination, if necessary if (outAudTrack != NULL) { lastPercent = -1; audioFrameCount = inAudTrack->CountFrames(); if (endDuration == 0 || endDuration < startDuration) { start = 0; end = audioFrameCount; } else { inAudTrack->SeekToTime(&endDuration, stat); end = inAudTrack->CurrentFrame(); inAudTrack->SeekToTime(&startDuration, stat); start = inAudTrack->CurrentFrame(); if (end > audioFrameCount) end = audioFrameCount; if (start > end) start = 0; } for (int64 i = start; (i <= end) && !fCancel; i += framesRead) { if ((ret = inAudTrack->ReadFrames(audioBuffer, &framesRead, &mh)) != B_OK) { fprintf(stderr, "Error reading audio frames: %s\n", strerror(ret)); snprintf(status.LockBuffer(128), 128, B_TRANSLATE("Error read audio frame %" B_PRId64), i); status.UnlockBuffer(); SetStatusMessage(status.String()); break; } if ((ret = outAudTrack->WriteFrames(audioBuffer, framesRead)) != B_OK) { fprintf(stderr, "Error writing audio frames: %s\n", strerror(ret)); snprintf(status.LockBuffer(128), 128, B_TRANSLATE("Error writing audio frame %" B_PRId64), i); status.UnlockBuffer(); SetStatusMessage(status.String()); break; } completePercent = (float)(i - start) / (float)(end - start) * 100; currPercent = (int32)completePercent; if (currPercent > lastPercent) { lastPercent = currPercent; snprintf(status.LockBuffer(128), 128, B_TRANSLATE("Writing audio track: %" B_PRId32 "%% complete"), currPercent); status.UnlockBuffer(); SetStatusMessage(status.String()); } } outAudTrack->Flush(); inFile->ReleaseTrack(inAudTrack); } outFile->CloseFile(); delete outFile; delete[] videoBuffer; delete[] audioBuffer; return ret; }