From 6af4da5dcbc291265146f6cd6b6c7708d7d99a44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Thu, 21 Jun 2007 22:19:02 +0000 Subject: [PATCH] * added MediaConverter, the improved version by Jun Suzuki, to the source tree * I completely rearranged the source and fixed a few bugs, one of which prevented me to use this tool to convert some XViD encoded AVIs that had sound to PJPEG encoding. * it is currently agreed to have this in the source, but not on the image yet, the MediaKit doesn't support writing anyways as of now git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21489 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/Jamfile | 1 + src/apps/mediaconverter/Jamfile | 15 + src/apps/mediaconverter/LICENSE | 31 + src/apps/mediaconverter/MediaConverter.rdef | 77 ++ src/apps/mediaconverter/MediaConverterApp.cpp | 599 ++++++++++ src/apps/mediaconverter/MediaConverterApp.h | 56 + .../mediaconverter/MediaConverterWindow.cpp | 1045 +++++++++++++++++ .../mediaconverter/MediaConverterWindow.h | 121 ++ .../mediaconverter/MediaEncoderWindow.cpp | 58 + src/apps/mediaconverter/MediaEncoderWindow.h | 29 + src/apps/mediaconverter/MediaFileInfoView.cpp | 195 +++ src/apps/mediaconverter/MediaFileInfoView.h | 43 + src/apps/mediaconverter/MediaFileListView.cpp | 109 ++ src/apps/mediaconverter/MediaFileListView.h | 47 + src/apps/mediaconverter/MessageConstants.h | 30 + src/apps/mediaconverter/StatusView.cpp | 70 ++ src/apps/mediaconverter/StatusView.h | 35 + src/apps/mediaconverter/Strings.h | 92 ++ .../languages/MediaConverter.frFR | 56 + .../languages/MediaConverter.itIT | 56 + .../languages/MediaConverter.jaJP | 56 + 21 files changed, 2821 insertions(+) create mode 100644 src/apps/mediaconverter/Jamfile create mode 100644 src/apps/mediaconverter/LICENSE create mode 100644 src/apps/mediaconverter/MediaConverter.rdef create mode 100644 src/apps/mediaconverter/MediaConverterApp.cpp create mode 100644 src/apps/mediaconverter/MediaConverterApp.h create mode 100644 src/apps/mediaconverter/MediaConverterWindow.cpp create mode 100644 src/apps/mediaconverter/MediaConverterWindow.h create mode 100644 src/apps/mediaconverter/MediaEncoderWindow.cpp create mode 100644 src/apps/mediaconverter/MediaEncoderWindow.h create mode 100644 src/apps/mediaconverter/MediaFileInfoView.cpp create mode 100644 src/apps/mediaconverter/MediaFileInfoView.h create mode 100644 src/apps/mediaconverter/MediaFileListView.cpp create mode 100644 src/apps/mediaconverter/MediaFileListView.h create mode 100644 src/apps/mediaconverter/MessageConstants.h create mode 100644 src/apps/mediaconverter/StatusView.cpp create mode 100644 src/apps/mediaconverter/StatusView.h create mode 100644 src/apps/mediaconverter/Strings.h create mode 100644 src/apps/mediaconverter/languages/MediaConverter.frFR create mode 100644 src/apps/mediaconverter/languages/MediaConverter.itIT create mode 100644 src/apps/mediaconverter/languages/MediaConverter.jaJP diff --git a/src/apps/Jamfile b/src/apps/Jamfile index b23e641514..1cfd396a9c 100644 --- a/src/apps/Jamfile +++ b/src/apps/Jamfile @@ -17,6 +17,7 @@ SubInclude HAIKU_TOP src apps launchbox ; SubInclude HAIKU_TOP src apps magnify ; SubInclude HAIKU_TOP src apps mail ; SubInclude HAIKU_TOP src apps mandelbrot ; +SubInclude HAIKU_TOP src apps mediaconverter ; SubInclude HAIKU_TOP src apps mediaplayer ; SubInclude HAIKU_TOP src apps midiplayer ; SubInclude HAIKU_TOP src apps networkstatus ; diff --git a/src/apps/mediaconverter/Jamfile b/src/apps/mediaconverter/Jamfile new file mode 100644 index 0000000000..792e91ff5f --- /dev/null +++ b/src/apps/mediaconverter/Jamfile @@ -0,0 +1,15 @@ +SubDir HAIKU_TOP src apps mediaconverter ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +Application MediaConverter : + MediaConverterApp.cpp + MediaConverterWindow.cpp + MediaEncoderWindow.cpp + MediaFileInfoView.cpp + MediaFileListView.cpp + StatusView.cpp + + : be media tracker + : MediaConverter.rdef +; diff --git a/src/apps/mediaconverter/LICENSE b/src/apps/mediaconverter/LICENSE new file mode 100644 index 0000000000..86a4268fa9 --- /dev/null +++ b/src/apps/mediaconverter/LICENSE @@ -0,0 +1,31 @@ +---------------------- +Be Sample Code License +---------------------- + +Copyright 1991-1999, Be Incorporated. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions, and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions, and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/apps/mediaconverter/MediaConverter.rdef b/src/apps/mediaconverter/MediaConverter.rdef new file mode 100644 index 0000000000..9b72048138 --- /dev/null +++ b/src/apps/mediaconverter/MediaConverter.rdef @@ -0,0 +1,77 @@ + +resource app_signature "application/x-vnd.Haiku-MediaConverter"; + +resource app_version { + major = 1, + middle = 3, + minor = 1, + variety = B_APPV_BETA, + internal = 0, + short_info = "MediaConverter", + long_info = "MediaConverter ©1999, Be, Inc., ©2000-2004 Jun Suzuki, ©2007 Haiku, Inc." +}; + +resource app_flags B_SINGLE_LAUNCH; + +resource file_types message { + "types" = "application/ogg", + "types" = "application/x-ogg", + "types" = "audio", + "types" = "video" +}; + + +resource large_icon { + $"FFFFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFFFF00003F3F3F3F3F3F0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFF003F3F3F000000003F3F3F00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFF003F3F3F0000000000003F3F3F00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FF003F3F3F3F0000000000003F3F3F3F00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FF003F3F3F3F3F000000003F3F3F3F3F00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"003F3F00003F3F3F00003F3F3F00003F3F00FFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"003F000000003F3F3F3F3F3F000000003F00FFFF010101010101FFFFFFFFFFFF" + $"003F00000000003F00003F00000000003F00FFFF01FAFAFAFAFA01FFFFFFFFFF" + $"003F00000000003F00003F00000000003F00FFFF01FAFAFAFAFAFA01FFFFFFFF" + $"003F000000003F3F3F3F3F3F000000003F00FFFF0101010101FAFAFA01FFFFFF" + $"003F3F00003F3F3F00003F3F3F00003F3F00FFFFFFFFFFFFFF01FAFA01FFFFFF" + $"FF003F3F3F3F3F000000003F3F3F3F3F00FFFFFFFFFFFFFFFF01FAFA01FFFFFF" + $"FF003F3F3F3F0000000000003F3F3F3F00FFFFFFFFFF01010101FAFA01010101" + $"FFFF003F3F3F0000000000003F3F3F00FFFFFFFFFFFF01FAFAFAFAFAFAFAFA01" + $"FFFFFF003F3F3F000000003F3F3F00FFFFFFFFFFFFFFFF01FAFAFAFAFAFA01FF" + $"FFFFFFFF00003F3F3F3F3F3F0000FFFFFFFFFFFFFFFFFFFF01FAFAFAFA01FFFF" + $"FFFFFFFFFFFF000000000000FFFFFFFFFFFFFFFFFFFFFFFFFF01FAFA01FFFFFF" + $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0101FFFFFFFF" + $"FFFFFFFF0101FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + $"FFFFFF01FAFA01FFFFFFFFFFFF00000000000000000000000000000000000000" + $"FFFF01FAFAFAFA01FFFFFFFFFF00003F003F003F003F003F003F003F003F0000" + $"FF01FAFAFAFAFAFA01FFFFFFFF00000000000000000000000000000000000000" + $"01FAFAFAFAFAFAFAFA01FFFFFF00000000000000000000000000000000000000" + $"01010101FAFA01010101FFFFFF0000003F3F3F3F003F3F3F003F3F3F3F000000" + $"FFFFFF01FAFA01FFFFFFFFFFFF00003F3F3F3F3F3F003F003F3F3F3F3F3F0000" + $"FFFFFF01FAFA01FFFFFFFFFFFF00003F3F00003F3F003F003F3F00003F3F0000" + $"FFFFFF01FAFAFA0101010101FF00003F3F00003F3F003F003F3F00003F3F0000" + $"FFFFFFFF01FAFAFAFAFAFA01FF00003F3F3F3F3F3F003F003F3F3F3F3F3F0000" + $"FFFFFFFFFF01FAFAFAFAFA01FF0000003F3F3F3F003F3F3F003F3F3F3F000000" + $"FFFFFFFFFFFF010101010101FF00000000000000000000000000000000000000" + $"FFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000000000" +}; + +resource mini_icon { + $"FFFFFFFFFFFF00000000FFFFFFFFFFFF" + $"FFFFFFFF00003F3F3F3F0000FFFFFFFF" + $"FFFFFF003F3F3F00003F3F3F00FFFFFF" + $"FFFF003F3F0000000000003F3F00FFFF" + $"FF003F3F3F3F000000003F3F3F3F00FF" + $"FF003F003F3F3F00003F3F3F003F00FF" + $"003F3F00003F3F3F3F3F3F00003F3F00" + $"003F000000003F00003F000000003F00" + $"003F000000003F00003F000000003F00" + $"003F3F00003F3F3F3F3F3F00003F3F00" + $"FF003F003F3F3F00003F3F3F003F00FF" + $"FF003F3F3F3F000000003F3F3F3F00FF" + $"FFFF003F3F0000000000003F3F00FFFF" + $"FFFFFF003F3F3F00003F3F3F00FFFFFF" + $"FFFFFFFF00003F3F3F3F0000FFFFFFFF" + $"FFFFFFFFFFFF00000000FFFFFFFFFFFF" +}; + diff --git a/src/apps/mediaconverter/MediaConverterApp.cpp b/src/apps/mediaconverter/MediaConverterApp.cpp new file mode 100644 index 0000000000..3c8c49900f --- /dev/null +++ b/src/apps/mediaconverter/MediaConverterApp.cpp @@ -0,0 +1,599 @@ +// Copyright 1999, Be Incorporated. All Rights Reserved. +// Copyright 2000-2004, Jun Suzuki. All Rights Reserved. +// Copyright 2007, Stephan Aßmus. All Rights Reserved. +// This file may be used under the terms of the Be Sample Code License. +#include "MediaConverterApp.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "MediaConverterWindow.h" +#include "MediaEncoderWindow.h" +#include "MessageConstants.h" +#include "Strings.h" + + +using std::nothrow; + +const char APP_SIGNATURE[] = "application/x-vnd.Haiku-MediaConverter"; + + +MediaConverterApp::MediaConverterApp() + : BApplication(APP_SIGNATURE) + , fWin(NULL) + , fConvertThreadID(-1) + , fConverting(false) + , fCancel(false) +{ + // TODO: implement settings for window pos + fWin = new MediaConverterWindow(BRect(50, 50, 520, 555)); +} + + +MediaConverterApp::~MediaConverterApp() +{ + if (fConvertThreadID >= 0) { + fCancel = true; + status_t exitValue; + wait_for_thread(fConvertThreadID, &exitValue); + } +} + + +// #pragma mark - + + +void +MediaConverterApp::MessageReceived(BMessage *msg) +{ + switch (msg->what) { + case FILE_LIST_CHANGE_MESSAGE: + if (fWin->Lock()) { + bool enable = fWin->CountSourceFiles() > 0; + fWin->SetEnabled(enable, enable); + fWin->Unlock(); + } + break; + + case START_CONVERSION_MESSAGE: + if (!fConverting) + StartConverting(); + break; + + case CANCEL_CONVERSION_MESSAGE: + fCancel = true; + break; + + case CONVERSION_DONE_MESSAGE: + fCancel = false; + fConverting = false; + DetachCurrentMessage(); + BMessenger(fWin).SendMessage(msg); + break; + + default: + BApplication::MessageReceived(msg); + } +} + + +void +MediaConverterApp::ReadyToRun() +{ + fWin->Show(); + fWin->PostMessage(INIT_FORMAT_MENUS); +} + +void +MediaConverterApp::RefsReceived(BMessage *msg) +{ + entry_ref ref; + int32 i = 0; + BMediaFile *f; + BString errorFiles; + int32 errors = 0; + + // from Open dialog or drag & drop + + while (msg->FindRef("refs", i++, &ref) == B_OK) { + f = new BMediaFile(&ref/*, B_MEDIA_FILE_NO_READ_AHEAD*/); + if (f->InitCheck() != B_OK) { + errorFiles << ref.name << "\n"; + errors++; + delete f; + continue; + } + if (fWin->Lock()) { + fWin->AddSourceFile(f, ref); + fWin->Unlock(); + } + } + + if (errors) { + BString alertText; + alertText << errors << ((errors > 1) ? FILES : FILE) + << NOTRECOGNIZE << "\n"; + alertText << errorFiles; + BAlert *alert = new BAlert(ERROR_LOAD_STRING, alertText.String(), + CONTINUE_STRING , NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT); + alert->Go(); + } +} + + +// #pragma mark - + + +bool +MediaConverterApp::IsConverting() const +{ + return fConverting; +} + + +void +MediaConverterApp::StartConverting() +{ + bool locked = fWin->Lock(); + + if (locked && (fWin->CountSourceFiles() > 0)) { + fConvertThreadID = spawn_thread(MediaConverterApp::_RunConvertEntry, + "converter thread", B_LOW_PRIORITY, (void *)this); + if (fConvertThreadID >= 0) { + fConverting = true; + fCancel = false; + resume_thread(fConvertThreadID); + } + } + + if (locked) { + fWin->Unlock(); + } +} + + +void +MediaConverterApp::SetStatusMessage(const char *message) +{ + if (fWin != NULL && fWin->Lock()) { + fWin->SetStatusMessage(message); + fWin->Unlock(); + } +} + + +// #pragma mark - + + +BEntry +MediaConverterApp::_CreateOutputFile(BDirectory directory, + entry_ref* ref, media_file_format* outputFormat) +{ + BString name(ref->name); + // create output file name + int32 extIndex = name.FindLast('.'); + if (extIndex != B_ERROR) + name.Truncate(extIndex + 1); + else + name.Append("."); + + name.Append(outputFormat->file_extension); + + BEntry inEntry(ref); + BEntry outEntry; + + if (inEntry.InitCheck() == B_OK) { + // ensure that output name is unique + int32 len = name.Length(); + int32 i = 1; + while (directory.Contains(name.String())) { + name.Truncate(len); + name << " " << i; + i++; + } + outEntry.SetTo(&directory, name.String()); + } + + return outEntry; +} + + +int32 +MediaConverterApp::_RunConvertEntry(void* castToMediaConverterApp) +{ + MediaConverterApp* app = (MediaConverterApp*)castToMediaConverterApp; + app->_RunConvert(); + return 0; +} + + +void +MediaConverterApp::_RunConvert() +{ + bigtime_t start = 0; + bigtime_t end = 0; + int32 audioQuality = 75; + int32 videoQuality = 75; + + if (fWin->Lock()) { + char *a; + start = strtoimax(fWin->StartDuration(), &a, 0) * 1000; + end = strtoimax(fWin->EndDuration(), &a, 0) * 1000; + audioQuality = fWin->AudioQuality(); + videoQuality = fWin->VideoQuality(); + fWin->Unlock(); + } + + int32 srcIndex = 0; + + BMediaFile *inFile(NULL), *outFile(NULL); + BEntry outEntry; + entry_ref inRef; + entry_ref outRef; + BPath path; + BString name; + + while (!fCancel) { + if (fWin->Lock()) { + status_t r = fWin->GetSourceFileAt(srcIndex, &inFile, &inRef); + if (r == B_OK) { + media_codec_info* audioCodec; + media_codec_info* videoCodec; + media_file_format* fileFormat; + fWin->GetSelectedFormatInfo(&fileFormat, &audioCodec, &videoCodec); + BDirectory directory = fWin->OutputDirectory(); + fWin->Unlock(); + outEntry = _CreateOutputFile(directory, &inRef, fileFormat); + + // display file name + + outEntry.GetPath(&path); + name.SetTo(path.Leaf()); + + if (outEntry.InitCheck() == B_OK) { + entry_ref outRef; + outEntry.GetRef(&outRef); + outFile = new BMediaFile(&outRef, fileFormat); + + name.Prepend(" '"); + name.Prepend(OUTPUT_FILE_STRING1); + name.Append("' "); + name.Append(OUTPUT_FILE_STRING2); + } else { + name.Prepend(" '"); + name.Prepend(OUTPUT_FILE_STRING3); + name.Append("'"); + } + + if (fWin->Lock()) { + fWin->SetFileMessage(name.String()); + fWin->Unlock(); + } + + if (outFile != NULL) { + r = _ConvertFile(inFile, outFile, audioCodec, videoCodec, + audioQuality, videoQuality, start, end); + + // set mime + update_mime_info(path.Path(), false, false, false); + + fWin->Lock(); + if (r == B_OK) { + fWin->RemoveSourceFile(srcIndex); + } else { + srcIndex++; + BString error(CONVERT_ERROR_STRING); + error << " '" << inRef.name << "'"; + fWin->SetStatusMessage(error.String()); + } + fWin->Unlock(); + } + + + } else { + fWin->Unlock(); + break; + } + } else { + break; + } + } + + BMessenger(this).SendMessage(CONVERSION_DONE_MESSAGE); +} + + +// #pragma mark - + + +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; + + short audioFrameSize = 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(AUDIO_SUPPORT_STRING); + 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->pixel_width_aspect = 1; + rvf->pixel_height_aspect = 1; + 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; + } + + videoBuffer = new (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 = VIDEO_PARAMFORM_STRING; + } else { + if (outVidTrack->SetQuality(videoQuality / 100.0f) >= B_OK) + videoQualitySupport = VIDEO_SUPPORT_STRING; + } + 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 canceld 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 %Ld: %s\n", i, + strerror(ret)); + status.SetTo(ERROR_READ_VIDEO_STRING); + status << i; + SetStatusMessage(status.String()); + + break; + } +//printf("writing frame %lld\n", i); + if ((ret = outVidTrack->WriteFrames(videoBuffer, framesRead, + mh.u.encoded_video.field_flags)) != B_OK) { + fprintf(stderr, "Error writing video frame %Ld: %s\n", i, + strerror(ret)); + status.SetTo(ERROR_WRITE_VIDEO_STRING); + status << i; + SetStatusMessage(status.String()); + break; + } + completePercent = (float)(i - start) / (float)(end - start) * 100; + currPercent = (int16)floor(completePercent); + if (currPercent > lastPercent) { + lastPercent = currPercent; + status.SetTo(WRITE_VIDEO_STRING); + status.Append(" "); + status << currPercent << "% " << COMPLETE_STRING; + 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)); + status.SetTo(ERROR_READ_AUDIO_STRING); + status << i; + SetStatusMessage(status.String()); + break; + } +//printf("writing audio frames %lld\n", i); + if ((ret = outAudTrack->WriteFrames(audioBuffer, + framesRead)) != B_OK) { + fprintf(stderr, "Error writing audio frames: %s\n", + strerror(ret)); + status.SetTo(ERROR_WRITE_AUDIO_STRING); + status << i; + SetStatusMessage(status.String()); + break; + } + completePercent = (float)(i - start) / (float)(end - start) * 100; + currPercent = (int16)floor(completePercent); + if (currPercent > lastPercent) { + lastPercent = currPercent; + status.SetTo(WRITE_AUDIO_STRING); + status.Append(" "); + status << currPercent << "% " << COMPLETE_STRING; + SetStatusMessage(status.String()); + } + } + outAudTrack->Flush(); + inFile->ReleaseTrack(inAudTrack); + + } + + outFile->CloseFile(); + delete outFile; + + delete[] videoBuffer; + delete[] audioBuffer; + + return ret; +} + + +// #pragma mark - + + +int +main(int, char **) +{ + MediaConverterApp app; + app.Run(); + + return 0; +} diff --git a/src/apps/mediaconverter/MediaConverterApp.h b/src/apps/mediaconverter/MediaConverterApp.h new file mode 100644 index 0000000000..8139f04d8a --- /dev/null +++ b/src/apps/mediaconverter/MediaConverterApp.h @@ -0,0 +1,56 @@ +// Copyright 1999, Be Incorporated. All Rights Reserved. +// Copyright 2000-2004, Jun Suzuki. All Rights Reserved. +// Copyright 2007, Stephan Aßmus. All Rights Reserved. +// This file may be used under the terms of the Be Sample Code License. +#ifndef MEDIA_CONVERTER_APP_H +#define MEDIA_CONVERTER_APP_H + + +#include +#include +#include +#include +#include + + +class BMediaFile; +class MediaConverterWindow; + +class MediaConverterApp : public BApplication { + public: + MediaConverterApp(); + virtual ~MediaConverterApp(); + + protected: + + virtual void MessageReceived(BMessage* message); + virtual void ReadyToRun(); + virtual void RefsReceived(BMessage* message); + + public: + bool IsConverting() const; + void StartConverting(); + + void SetStatusMessage(const char* message); + + private: + BEntry _CreateOutputFile(BDirectory directory, + entry_ref* ref, + media_file_format* outputFormat); + + static int32 _RunConvertEntry(void* castToMediaConverterApp); + void _RunConvert(); + status_t _ConvertFile(BMediaFile* inFile, + BMediaFile* outFile, + media_codec_info* audioCodec, + media_codec_info* videoCodec, + int32 audioQuality, int32 videoQuality, + bigtime_t StartTime, bigtime_t EndTime); + + MediaConverterWindow* fWin; + thread_id fConvertThreadID; + bool fConverting; + volatile bool fCancel; +}; + +#endif // MEDIA_CONVERTER_APP_H diff --git a/src/apps/mediaconverter/MediaConverterWindow.cpp b/src/apps/mediaconverter/MediaConverterWindow.cpp new file mode 100644 index 0000000000..8d0c302490 --- /dev/null +++ b/src/apps/mediaconverter/MediaConverterWindow.cpp @@ -0,0 +1,1045 @@ +// Copyright 1999, Be Incorporated. All Rights Reserved. +// Copyright 2000-2004, Jun Suzuki. All Rights Reserved. +// Copyright 2007, Stephan Aßmus. All Rights Reserved. +// This file may be used under the terms of the Be Sample Code License. +#include "MediaConverterWindow.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MediaFileInfoView.h" +#include "MediaFileListView.h" +#include "MessageConstants.h" +#include "StatusView.h" +#include "Strings.h" + + +// #pragma mark - DirectoryFilter + + +class DirectoryFilter : public BRefFilter +{ +public: + DirectoryFilter(){}; + virtual bool Filter(const entry_ref *ref, + BNode *node, struct stat *st, const char *filetype) + { + return node->IsDirectory(); + } +private: +}; + + +// #pragma mark - FileFormatMenuItem + + +class FileFormatMenuItem : public BMenuItem { + public: + FileFormatMenuItem(media_file_format* format); + virtual ~FileFormatMenuItem(); + + media_file_format fFileFormat; +}; + + +FileFormatMenuItem::FileFormatMenuItem(media_file_format *format) + : BMenuItem(format->pretty_name, new BMessage(FORMAT_SELECT_MESSAGE)) +{ + memcpy(&fFileFormat, format, sizeof(fFileFormat)); +} + + +FileFormatMenuItem::~FileFormatMenuItem() +{ +} + + +// #pragma mark - CodecMenuItem + + +class CodecMenuItem : public BMenuItem { + public: + CodecMenuItem(media_codec_info *ci, uint32 msg_type); + virtual ~CodecMenuItem(); + + media_codec_info fCodecInfo; +}; + + +CodecMenuItem::CodecMenuItem(media_codec_info *ci, uint32 msg_type) + : BMenuItem(ci->pretty_name, new BMessage(msg_type)) +{ + memcpy(&fCodecInfo, ci, sizeof(fCodecInfo)); +} + + +CodecMenuItem::~CodecMenuItem() +{ +} + + +// #pragma mark - MediaConverterWindow + + +MediaConverterWindow::MediaConverterWindow(BRect frame) + : BWindow(frame, "MediaConverter", B_TITLED_WINDOW_LOOK, + B_NORMAL_WINDOW_FEEL, B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS) + + , fVideoQuality(75) + , fAudioQuality(75) + + , fSaveFilePanel(NULL) + , fOpenFilePanel(NULL) + + , fOutputDirSpecified(false) + + , fEnabled(true) + , fConverting(false) + , fCancelling(false) +{ + char defaultdirectory[] = "/boot/home"; + fOutputDir.SetTo(defaultdirectory); + +#if B_BEOS_VERSION >= 0x530 // 0x520 RC2 0x530 RC3 + // load Locale files for ZETA + entry_ref mypath; + app_info info; + + be_app->GetAppInfo(&info); + mypath = info.ref; + + BPath path(&mypath); + path.GetParent(&path); + path.Append("Language/Dictionaries"); + path.Append("MediaConverter"); + be_locale.LoadLanguageFile(path.Path()); + +#endif + + BRect dummyRect(0, 0, 10, 10); + fMenuBar = new BMenuBar(dummyRect, "menubar"); + _CreateMenu(); + AddChild(fMenuBar); + + // background + BRect r(frame); + r.OffsetTo(0, 0); + BView *background = new BView(r, NULL, B_FOLLOW_ALL_SIDES, 0); + rgb_color c = ui_color(B_PANEL_BACKGROUND_COLOR); + background->SetViewColor(c); + background->SetLowColor(c); + r.InsetBy(5, 25); + + // file list view box + BRect r2(r); + r2.bottom = r2.top + 420; + r2.right = r2.left + 150; + fBox1 = new BBox(r2, NULL, B_FOLLOW_ALL); + + BRect r3(r2); + r3.OffsetTo(0, 0); + r3.InsetBy(8, 8); + r3.top += be_bold_font->Size() - 3; + bool useHorizontalScrollBar = false; + if (useHorizontalScrollBar) + r3.bottom -= B_H_SCROLL_BAR_HEIGHT; + r3.right -= B_V_SCROLL_BAR_WIDTH; + fListView = new MediaFileListView(r3, B_FOLLOW_ALL); + BScrollView *scroller = new BScrollView(NULL, fListView, + B_FOLLOW_ALL, 0, useHorizontalScrollBar, true); + fBox1->AddChild(scroller); + background->AddChild(fBox1); + + // info box + r2.left = r2.right + 5; + r2.right = r.right - 5; + r2.bottom = r2.top + 120; + fBox2 = new BBox(r2, NULL, B_FOLLOW_RIGHT | B_FOLLOW_TOP); + + r3 = r2; + r3.OffsetTo(0, 0); + r3.InsetBy(5, 5); + r3.top += 12; + fInfoView = new MediaFileInfoView(r3, B_FOLLOW_ALL); + fBox2->AddChild(fInfoView); + background->AddChild(fBox2); + + r2.top = r2.bottom + 5; + r2.bottom = r2.top + 295; + fBox3 = new BBox(r2, NULL, B_FOLLOW_RIGHT | B_FOLLOW_TOP_BOTTOM); + + r3 = r2; + r3.OffsetTo(0, 0); + r3.InsetBy(8, 8); + r3.top += be_bold_font->Size() - 3; + + BRect r4(r3); + r4.bottom = r4.top + 20; + BPopUpMenu* popmenu = new BPopUpMenu(""); + fFormatMenu = new BMenuField(r4, NULL, FORMAT_LABEL, popmenu, + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); + fBox3->AddChild(fFormatMenu); + + r4.top = r4.bottom + 5; + r4.bottom = r4.top + 20; + popmenu = new BPopUpMenu(""); + fAudioMenu = new BMenuField(r4, NULL, AUDIO_LABEL, popmenu, + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); + fBox3->AddChild(fAudioMenu); + + r4.top = r4.bottom + 5; + r4.bottom = r4.top + 20; + popmenu = new BPopUpMenu(""); + fVideoMenu = new BMenuField(r4, NULL, VIDEO_LABEL, popmenu, + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); + fBox3->AddChild(fVideoMenu); + + // output folder + r4.top = r4.bottom + 5; + r4.bottom = r4.top + 20; + r4.right = 80; + fDestButton = new BButton(r4, NULL, OUTPUT_FOLDER_LABEL, + new BMessage(OUTPUT_FOLDER_MESSAGE), + B_FOLLOW_LEFT | B_FOLLOW_TOP); + fBox3->AddChild(fDestButton); + fDestButton->ResizeToPreferred(); + BRect buttonFrame2(fDestButton->Frame()); + buttonFrame2.OffsetTo(r.right - buttonFrame2.Width(), + r.bottom - buttonFrame2.Height()); + + fOutputFolder = new BStringView(r4, NULL, defaultdirectory, + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, B_WILL_DRAW); + fBox3->AddChild(fOutputFolder); + fOutputFolder->MoveBy(buttonFrame2.Width() + 10, 5); + fOutputFolder->ResizeToPreferred(); + + // start/end duration + r4.top = r4.bottom + 10; + r4.bottom = r4.top + 20; + r4.right = r3.right; + fStartDurationTC = new BTextControl(r4, NULL, "", "0", NULL, + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); + fBox3->AddChild(fStartDurationTC); + fStartDurationTC->SetText("0"); + + r4.top = r4.bottom + 5; + r4.bottom = r4.top + 20; + fEndDurationTC = new BTextControl(r4, NULL, "", "0", NULL, + B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); + fBox3->AddChild(fEndDurationTC); + fEndDurationTC->SetText("0"); + + r4.top = r4.bottom + 5; + r4.bottom = r4.top + 50; + + // Video Quality + fVideoQualitySlider = new BSlider(r4, "VSlider", "" , + new BMessage(VIDEO_QUALITY_CHANGED_MESSAGE), 1, 100, B_HORIZONTAL, + B_BLOCK_THUMB, B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); + fVideoQualitySlider->SetValue(fVideoQuality); + fVideoQualitySlider->SetEnabled(false); + fBox3->AddChild(fVideoQualitySlider); + + r4.top = r4.bottom + 5; + r4.bottom = r4.top + 50; + + // Audio Quality + fAudioQualitySlider = new BSlider(r4,"ASlider", "" , + new BMessage(AUDIO_QUALITY_CHANGED_MESSAGE), 1, 100, B_HORIZONTAL, + B_BLOCK_THUMB, B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); + fAudioQualitySlider->SetValue(fAudioQuality); + fAudioQualitySlider->SetEnabled(false); + fBox3->AddChild(fAudioQualitySlider); + background->AddChild(fBox3); + + // buttons + r2.top = r2.bottom + 15; + r2.bottom = r2.top + 20; + r2.left = r.left - 120; + r2.right = r.right; + + fPreviewButton = new BButton(r2, NULL, PREVIEW_BUTTON_LABEL, + new BMessage(PREVIEW_MESSAGE), B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + background->AddChild(fPreviewButton); + fPreviewButton->SetEnabled(false); + + fConvertButton = new BButton(r2, NULL, CONVERT_LABEL, + new BMessage(CONVERT_BUTTON_MESSAGE), + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + background->AddChild(fConvertButton); + + // Status view + r2.bottom = r2.top + 20; + r2.left = r.left; + r2.right = r.right; + + fStatusView2 = new StatusView(r2, B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM); + background->AddChild(fStatusView2); + + r2.top += 15; + r2.bottom += 20; + + fStatusView = new StatusView(r2, B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM); + background->AddChild(fStatusView); + AddChild(background); + + SetStatusMessage(""); + _UpdateLabels(); + + SetSizeLimits(frame.Width(), 32000, frame.Height(), 32000); +} + + +MediaConverterWindow::~MediaConverterWindow() +{ +} + + +// #pragma mark - + + +/* +void +MediaConverterWindow::DispatchMessage(BMessage *msg, BHandler *handler) +{ + if (msg->WasDropped() && msg->what == B_SIMPLE_DATA) { + + printf("Dispatch 1\n"); + DetachCurrentMessage(); + msg->what = B_REFS_RECEIVED; + BMessenger(be_app).SendMessage(msg); + delete msg; + } else { + BWindow::DispatchMessage(msg, handler); + } +} +*/ + + +void +MediaConverterWindow::MessageReceived(BMessage *msg) +{ + status_t status; + entry_ref ref; + entry_ref inRef; + + BString string, string2; + + BEntry entry("/boot/beos/apps/MediaPlayer", true); + char buffer[40]; + char buffer2[B_PATH_NAME_LENGTH]; + char *argv[3]; + argv[0] = "-pos"; + BMediaFile *inFile(NULL); + int32 srcIndex = 0; + BPath name; + BEntry inentry; + int32 value; + BRect ButtonRect; + + switch (msg->what) { + #if B_BEOS_VERSION <= B_BEOS_VERSION_6 + case B_LANGUAGE_CHANGED: + LanguageChanged(); + break; + #endif + + case INIT_FORMAT_MENUS: + BuildFormatMenu(); + if (CountSourceFiles() == 0) + SetEnabled(false, false); + break; + + case B_SIMPLE_DATA: + if (msg->WasDropped()) + { + DetachCurrentMessage(); + msg->what = B_REFS_RECEIVED; + BMessenger(be_app).SendMessage(msg); + delete msg; + } + break; + + case FORMAT_SELECT_MESSAGE: + BuildAudioVideoMenus(); + break; + case AUDIO_CODEC_SELECT_MESSAGE: + break; + case VIDEO_CODEC_SELECT_MESSAGE: + break; + + case CONVERT_BUTTON_MESSAGE: + if (!fConverting) { + fConvertButton->SetLabel(CANCEL_LABEL); + fConverting = true; + SetStatusMessage(CONVERT_LABEL); + SetEnabled(false, true); + BMessenger(be_app).SendMessage(START_CONVERSION_MESSAGE); + } else if (!fCancelling) { + fCancelling = true; + SetStatusMessage(CANCELLING_LABEL B_UTF8_ELLIPSIS); + BMessenger(be_app).SendMessage(CANCEL_CONVERSION_MESSAGE); + } + break; + + case CONVERSION_DONE_MESSAGE: + SetStatusMessage(fCancelling ? CONV_CANCEL_LABEL : CONV_COMPLETE_LABEL); + fConverting = false; + fCancelling = false; + { + bool enable = CountSourceFiles() > 0; + SetEnabled(enable, enable); + } + fConvertButton->SetLabel(CONVERT_LABEL); + + + break; + + case OUTPUT_FOLDER_MESSAGE: + // Execute Save Panel + if (!fSaveFilePanel) { + BButton *SelectThisDir; + + fSaveFilePanel = new BFilePanel(B_OPEN_PANEL, NULL, NULL, B_DIRECTORY_NODE, true, new BMessage(FOLDER_SELECT_MESSAGE), NULL, false, true); + fSaveFilePanel->SetButtonLabel(B_DEFAULT_BUTTON, SELECT_LABEL); + fSaveFilePanel->Window()->SetTitle(SAVE_DIR_LABEL); + fSaveFilePanel->SetTarget(this); + + fSaveFilePanel->Window()->Lock(); + ButtonRect = fSaveFilePanel->Window()->ChildAt(0)->FindView("cancel button")->Frame(); + ButtonRect.right = ButtonRect.left - 20; + ButtonRect.left = ButtonRect.right - 130; + SelectThisDir = new BButton(ButtonRect, NULL, SELECT_DIR_LABEL, + new BMessage(SELECT_THIS_DIR_MESSAGE), B_FOLLOW_BOTTOM | B_FOLLOW_RIGHT); + SelectThisDir->SetTarget(this); + fSaveFilePanel->Window()->ChildAt(0)->AddChild(SelectThisDir); + fSaveFilePanel->Window()->Unlock(); + + BRefFilter *filter; + filter = new DirectoryFilter; + fSaveFilePanel->SetRefFilter(filter); + } + fSaveFilePanel->Show(); + break; + + case FOLDER_SELECT_MESSAGE: + // "SELECT" Button at Save Panel Pushed + fSaveFilePanel->GetNextSelectedRef(&inRef); + inentry.SetTo(&inRef, true); + _SetOutputFolder(inentry); + fOutputDirSpecified = true; + break; + + case SELECT_THIS_DIR_MESSAGE: + // "THIS DIR" Button at Save Panel Pushed + fSaveFilePanel->GetPanelDirectory(&inRef); + fSaveFilePanel->Hide(); + inentry.SetTo(&inRef, true); + _SetOutputFolder(inentry); + fOutputDirSpecified = true; + break; + + case OPEN_FILE_MESSAGE: + // Execute Open Panel + if (!fOpenFilePanel) { + fOpenFilePanel = new BFilePanel(B_OPEN_PANEL, NULL, NULL, B_FILE_NODE, true, NULL, NULL, false, true); + fOpenFilePanel->SetTarget(this); + } + fOpenFilePanel->Show(); + break; + + case B_REFS_RECEIVED: + // Media Files Seleced by Open Panel + DetachCurrentMessage(); + msg->what = B_REFS_RECEIVED; + BMessenger(be_app).SendMessage(msg); + // fall through + + case B_CANCEL: + break; + + case DISP_ABOUT_MESSAGE: { + (new BAlert(ABOUT_TITLE_LABEL B_UTF8_ELLIPSIS, + "MediaConverter\n" + VERSION"\n" + B_UTF8_COPYRIGHT" 1999, Be Incorporated.\n" + B_UTF8_COPYRIGHT" 2000-2004 Jun Suzuki\n" + B_UTF8_COPYRIGHT" 2007 Stephan Aßmus", + OK_LABEL))->Go(); + break; + } + + case QUIT_MESSAGE: + MediaConverterWindow::QuitRequested(); + break; + + case PREVIEW_MESSAGE: + entry.GetRef(&ref); + string = ""; + string << fStartDurationTC->Text(); + string << "000"; + + strcpy(buffer,string.String()); + argv[1] = buffer; + srcIndex = fListView->CurrentSelection(); + status = GetSourceFileAt(srcIndex, &inFile, &inRef); + if (status == B_OK) { + inentry.SetTo(&inRef); + inentry.GetPath(&name); + + strcpy(buffer, string.String()); + + strcpy(buffer2, name.Path()); + argv[2]= buffer2; + } + + status = be_roster->Launch(&ref, 3, argv); + + if (status != B_OK) { + string2 << LAUNCH_ERROR << strerror(status); + (new BAlert("", string2.String(), OK_LABEL))->Go(); + } + break; + + case VIDEO_QUALITY_CHANGED_MESSAGE: + msg->FindInt32("be:value",&value); + sprintf(buffer, VIDEO_QUALITY_LABEL, (int8)value); + fVideoQualitySlider->SetLabel(buffer); + fVideoQuality = value; + break; + + case AUDIO_QUALITY_CHANGED_MESSAGE: + msg->FindInt32("be:value",&value); + sprintf(buffer, AUDIO_QUALITY_LABEL, (int8)value); + fAudioQualitySlider->SetLabel(buffer); + fAudioQuality = value; + break; + + default: + BWindow::MessageReceived(msg); + } +} + + +bool +MediaConverterWindow::QuitRequested() +{ + if (!fConverting) { + BMessenger(be_app).SendMessage(B_QUIT_REQUESTED); + return true; + } else if (!fCancelling) { + fCancelling = true; + SetStatusMessage(CANCELLING_LABEL); + BMessenger(be_app).SendMessage(CANCEL_CONVERSION_MESSAGE); + } + return false; +} + + +// #pragma mark - + + +void +MediaConverterWindow::LanguageChanged() +{ + _DestroyMenu(); + _CreateMenu(); + _UpdateLabels(); + BuildAudioVideoMenus(); + Lock(); + fInfoView->Invalidate(); + Unlock(); +} + + +void +MediaConverterWindow::BuildAudioVideoMenus() +{ + BMenu *menu = fAudioMenu->Menu(); + BMenuItem *item; + // clear out old audio codec menu items + while ((item = menu->RemoveItem((int32)0)) != NULL) { + delete item; + } + + bool separator = true; + + // get selected file format + FileFormatMenuItem *ffmi = (FileFormatMenuItem*)fFormatMenu->Menu()->FindMarked(); + media_file_format *mf_format = &(ffmi->fFileFormat); + + media_format format, outfmt; + memset(&format, 0, sizeof(format)); + media_codec_info codec_info; + int32 cookie = 0; + CodecMenuItem* cmi; + + // add available audio encoders to menu + format.type = B_MEDIA_RAW_AUDIO; + format.u.raw_audio = media_raw_audio_format::wildcard; + while (get_next_encoder(&cookie, mf_format, &format, &outfmt, &codec_info) == B_OK) { + if (separator) { + menu->AddItem(new BMenuItem("No Audio", + new BMessage(AUDIO_CODEC_SELECT_MESSAGE))); + menu->AddSeparatorItem(); + separator = false; + } + + cmi = new CodecMenuItem(&codec_info, AUDIO_CODEC_SELECT_MESSAGE); + menu->AddItem(cmi); + // reset media format struct +/* + format.type = B_MEDIA_RAW_AUDIO; + format.u.raw_audio = media_raw_audio_format::wildcard; +*/ + } + + // mark first audio encoder + item = menu->ItemAt(0); + if (item != NULL) { + fAudioMenu->SetEnabled(fEnabled); + fAudioQualitySlider->SetEnabled(fEnabled); + item->SetMarked(true); + ((BInvoker *)item)->Invoke(); + } else { + item = new BMenuItem(NONE_LABEL, NULL); + menu->AddItem(item); + item->SetMarked(true); + fAudioMenu->SetEnabled(false); + fAudioQualitySlider->SetEnabled(false); + } + + // clear out old video codec menu items + menu = fVideoMenu->Menu(); + while ((item = menu->RemoveItem((int32)0)) != NULL) { + delete item; + } + + separator = true; + + // construct a generic video format. Some of these parameters + // seem silly, but are needed for R4.5.x, which is more picky + // than subsequent BeOS releases will be. + memset(&format, 0, sizeof(format)); + format.type = B_MEDIA_RAW_VIDEO; + format.u.raw_video.last_active = (uint32)(240 - 1); + format.u.raw_video.orientation = B_VIDEO_TOP_LEFT_RIGHT; + format.u.raw_video.display.format = B_RGB32; + format.u.raw_video.display.line_width = (int32)320; + format.u.raw_video.display.line_count = (int32)240; + format.u.raw_video.display.bytes_per_row = 4 * 320; + + // add available video encoders to menu + cookie = 0; + while (get_next_encoder(&cookie, mf_format, &format, &outfmt, &codec_info) == B_OK) { + if (separator) { + menu->AddItem(new BMenuItem("No Video", + new BMessage(VIDEO_CODEC_SELECT_MESSAGE))); + menu->AddSeparatorItem(); + separator = false; + } + + cmi = new CodecMenuItem(&codec_info, VIDEO_CODEC_SELECT_MESSAGE); + menu->AddItem(cmi); + } + + // mark first video encoder + item = menu->ItemAt(0); + if (item != NULL) { + fVideoMenu->SetEnabled(fEnabled); + fVideoQualitySlider->SetEnabled(fEnabled); + item->SetMarked(true); + ((BInvoker *)item)->Invoke(); + } else { + item = new BMenuItem(NONE_LABEL, NULL); + menu->AddItem(item); + item->SetMarked(true); + fVideoMenu->SetEnabled(false); + fVideoQualitySlider->SetEnabled(false); + } +} + +void +MediaConverterWindow::GetSelectedFormatInfo(media_file_format** format, + media_codec_info** audio, media_codec_info** video) +{ + *audio = NULL; + *video = NULL; + *format = NULL; + + FileFormatMenuItem *formatItem = + dynamic_cast(fFormatMenu->Menu()->FindMarked()); + if (formatItem != NULL) { + *format = &(formatItem->fFileFormat); + } + + *audio = *video = NULL; + CodecMenuItem *codecItem = + dynamic_cast(fAudioMenu->Menu()->FindMarked()); + if (codecItem != NULL) { + *audio = &(codecItem->fCodecInfo); + } + + codecItem = dynamic_cast(fVideoMenu->Menu()->FindMarked()); + if (codecItem != NULL) { + *video = &(codecItem->fCodecInfo); + } +} + + +void +MediaConverterWindow::BuildFormatMenu() +{ + BMenu *menu = fFormatMenu->Menu(); + BMenuItem *item; + // clear out old format menu items + while ((item = menu->RemoveItem((int32)0)) != NULL) { + delete item; + } + + // add menu items for each file format + media_file_format mfi; + int32 cookie = 0; + FileFormatMenuItem *ff_item; + while (get_next_file_format(&cookie, &mfi) == B_OK) { + ff_item = new FileFormatMenuItem(&mfi); + menu->AddItem(ff_item); + } + + // mark first item + item = menu->ItemAt(0); + if (item != NULL) { + item->SetMarked(true); + ((BInvoker *)item)->Invoke(); + } +} + +void +MediaConverterWindow::SetFileMessage(const char *message) +{ + fStatusView->SetStatus(message); +} + +void +MediaConverterWindow::SetStatusMessage(const char *message) +{ + fStatusView2->SetStatus(message); +} + + +// #pragma mark - + + +void +MediaConverterWindow::AddSourceFile(BMediaFile* file, const entry_ref& ref) +{ + fListView->AddItem(file, ref); + + if (!fOutputDirSpecified) { + BEntry entry(&ref); + entry.GetParent(&entry); + _SetOutputFolder(entry); + } +} + + +void +MediaConverterWindow::RemoveSourceFile(int32 index) +{ + delete fListView->RemoveItem(index); + fStartDurationTC->SetText("0"); + fEndDurationTC->SetText("0"); +} + + +int32 +MediaConverterWindow::CountSourceFiles() +{ + return fListView->CountItems(); +} + + +status_t +MediaConverterWindow::GetSourceFileAt(int32 index, BMediaFile** _file, + entry_ref* ref) +{ + MediaFileListItem* item = dynamic_cast( + fListView->ItemAt(index)); + if (item != NULL) { + *_file = item->fMediaFile; + *ref = item->fRef; + return B_OK; + } else { + return B_ERROR; + } +} + + +void +MediaConverterWindow::SourceFileSelectionChanged() +{ + int32 selected = fListView->CurrentSelection(); + BMediaFile* file = NULL; + entry_ref* _ref = NULL; + entry_ref ref; + bool enabled = false; + if (GetSourceFileAt(selected, &file, &ref) == B_OK) { + _ref = &ref; + enabled = true; + } + + fPreviewButton->SetEnabled(enabled); + fVideoQualitySlider->SetEnabled(enabled); + fAudioQualitySlider->SetEnabled(enabled); + fStartDurationTC->SetEnabled(enabled); + fEndDurationTC->SetEnabled(enabled); + + fInfoView->Update(file, _ref); + + // HACK: get the fInfoView to update the duration "synchronously" + UpdateIfNeeded(); + + // update duration text controls + fStartDurationTC->SetText("0"); + BString duration; + duration << fInfoView->Duration() / 1000; + fEndDurationTC->SetText(duration.String()); +} + + +// #pragma mark - + + +void +MediaConverterWindow::SetEnabled(bool enabled, bool convertEnabled) +{ + fConvertButton->SetEnabled(convertEnabled); + if (enabled == fEnabled) + return; + + fFormatMenu->SetEnabled(enabled); + fAudioMenu->SetEnabled(enabled); + fVideoMenu->SetEnabled(enabled); + fListView->SetEnabled(enabled); + fStartDurationTC->SetEnabled(enabled); + fEndDurationTC->SetEnabled(enabled); + + fEnabled = enabled; +} + + +bool +MediaConverterWindow::IsEnabled() +{ + return fEnabled; +} + + +const char* +MediaConverterWindow::StartDuration() const +{ + return fStartDurationTC->Text(); +} + + +const char* +MediaConverterWindow::EndDuration() const +{ + return fEndDurationTC->Text(); +} + + +BDirectory +MediaConverterWindow::OutputDirectory() const +{ + return fOutputDir; +} + + +void +MediaConverterWindow::SetAudioQualityLabel(const char* label) +{ + fAudioQualitySlider->SetLabel(label); +} + + +void +MediaConverterWindow::SetVideoQualityLabel(const char* label) +{ + fVideoQualitySlider->SetLabel(label); +} + + +// #pragma mark - + + +void +MediaConverterWindow::_UpdateLabels() +{ + char buffer[255]; + + if (fBox1 != NULL) + fBox1->SetLabel(SOURCE_BOX_LABEL); + if (fBox2 != NULL) + fBox2->SetLabel(INFO_BOX_LABEL); + if (fBox3 != NULL) + fBox3->SetLabel(OUTPUT_BOX_LABEL); + + BRect r(Bounds()); + float w = 0; + + if (fConvertButton != NULL) { + fConvertButton->SetLabel(CONVERT_LABEL); + fConvertButton->ResizeToPreferred(); + BRect buttonFrame(fConvertButton->Frame()); + w = buttonFrame.Width(); + buttonFrame.OffsetTo(r.right - w - 10, r.bottom - buttonFrame.Height() - 25); + fConvertButton->MoveTo(buttonFrame.LeftTop()); + } + + if (fPreviewButton != NULL) { + fPreviewButton->SetLabel(PREVIEW_BUTTON_LABEL); + fPreviewButton->ResizeToPreferred(); + BRect buttonFrame(fPreviewButton->Frame()); + w = buttonFrame.Width(); + buttonFrame.OffsetTo(r.right - w - buttonFrame.Width() - 40, + r.bottom - buttonFrame.Height() - 25); + fPreviewButton->MoveTo(buttonFrame.LeftTop()); + } + + if (fDestButton != NULL) { + fDestButton->SetLabel(OUTPUT_FOLDER_LABEL); + fDestButton->ResizeToPreferred(); + } + + if (fOutputFolder != NULL) { + BRect destrect; + destrect = fDestButton->Frame(); + fOutputFolder->MoveTo(destrect.right + 10, destrect.top + 5); + fOutputFolder->ResizeToPreferred(); + } + + sprintf(buffer, VIDEO_QUALITY_LABEL, (int8)fVideoQuality); + if (fVideoQualitySlider != NULL) { + fVideoQualitySlider->SetLabel(buffer); + fVideoQualitySlider->SetLimitLabels(SLIDER_LOW_LABEL, + SLIDER_HIGH_LABEL); + } + + sprintf(buffer, AUDIO_QUALITY_LABEL, (int8)fAudioQuality); + + if (fAudioQualitySlider != NULL) { + fAudioQualitySlider->SetLabel(buffer); + fAudioQualitySlider->SetLimitLabels(SLIDER_LOW_LABEL, + SLIDER_HIGH_LABEL); + } + + float maxLabelLen = 0; + if (fStartDurationTC != NULL) { + fStartDurationTC->SetLabel(START_LABEL); + maxLabelLen = fStartDurationTC->StringWidth(START_LABEL); + } + if (fEndDurationTC != NULL) { + fEndDurationTC->SetLabel(END_LABEL); + maxLabelLen = MAX(maxLabelLen, fEndDurationTC->StringWidth(END_LABEL)); + } + if (fStartDurationTC != NULL) + fStartDurationTC->SetDivider(maxLabelLen + 5); + if (fEndDurationTC != NULL) + fEndDurationTC->SetDivider(maxLabelLen + 5); + + if (fFormatMenu != NULL) { + fFormatMenu->SetLabel(FORMAT_LABEL); + maxLabelLen = MAX(maxLabelLen, fFormatMenu->StringWidth( + fFormatMenu->Label())); + } + if (fAudioMenu != NULL) { + fAudioMenu->SetLabel(AUDIO_LABEL); + maxLabelLen = MAX(maxLabelLen, fAudioMenu->StringWidth( + fAudioMenu->Label())); + } + if (fVideoMenu != NULL) { + fVideoMenu->SetLabel(VIDEO_LABEL); + maxLabelLen = MAX(maxLabelLen, fVideoMenu->StringWidth( + fVideoMenu->Label())); + } + maxLabelLen += 10; + + if (fStartDurationTC != NULL) + fStartDurationTC->SetDivider(maxLabelLen); + if (fEndDurationTC != NULL) + fEndDurationTC->SetDivider(maxLabelLen); + if (fFormatMenu != NULL) + fFormatMenu->SetDivider(maxLabelLen + 3); + if (fAudioMenu != NULL) + fAudioMenu->SetDivider(maxLabelLen + 3); + if (fVideoMenu != NULL) + fVideoMenu->SetDivider(maxLabelLen + 3); + + SetFileMessage(DROP_MEDIA_FILE_LABEL); +} + + +void +MediaConverterWindow::_DestroyMenu() +{ + BMenu* Menu; + + while ((Menu = fMenuBar->SubmenuAt(0)) != NULL) { + fMenuBar->RemoveItem(Menu); + delete Menu; + } +} + + +void +MediaConverterWindow::_CreateMenu() +{ + BMenuItem* item; + BMenu* menu; + + menu = new BMenu(FILE_MENU_LABEL); + item = new BMenuItem(OPEN_MENU_LABEL B_UTF8_ELLIPSIS, + new BMessage(OPEN_FILE_MESSAGE)); + menu->AddItem(item); + menu->AddSeparatorItem(); + item = new BMenuItem(ABOUT_MENU_LABEL B_UTF8_ELLIPSIS, + new BMessage(DISP_ABOUT_MESSAGE)); + menu->AddItem(item); + menu->AddSeparatorItem(); + item = new BMenuItem(QUIT_MENU_LABEL, new BMessage(QUIT_MESSAGE)); + menu->AddItem(item); + + fMenuBar->AddItem(menu); +} + + +void +MediaConverterWindow::_SetOutputFolder(BEntry entry) +{ + BPath path; + entry.GetPath(&path); + fOutputFolder->SetText(path.Path()); + fOutputFolder->ResizeToPreferred(); + fOutputDir.SetTo(path.Path()); +} + + diff --git a/src/apps/mediaconverter/MediaConverterWindow.h b/src/apps/mediaconverter/MediaConverterWindow.h new file mode 100644 index 0000000000..da140f1bfc --- /dev/null +++ b/src/apps/mediaconverter/MediaConverterWindow.h @@ -0,0 +1,121 @@ +// Copyright 1999, Be Incorporated. All Rights Reserved. +// Copyright 2000-2004, Jun Suzuki. All Rights Reserved. +// Copyright 2007, Stephan Aßmus. All Rights Reserved. +// This file may be used under the terms of the Be Sample Code License. +#ifndef MEDIA_CONVERTER_WINDOW_H +#define MEDIA_CONVERTER_WINDOW_H + + +#include +#include +#include +#include + + +class BBox; +class BButton; +class BFilePanel; +class BMenuField; +class BSlider; +class BStringView; +class BTextControl; +class MediaFileInfoView; +class MediaFileListView; +class StatusView; + +class MediaConverterWindow : public BWindow { + public: + MediaConverterWindow(BRect frame); + virtual ~MediaConverterWindow(); + + protected: +// virtual void DispatchMessage(BMessage* message, +// BHandler* handler); + virtual void MessageReceived(BMessage* message); + virtual bool QuitRequested(); + + public: + void LanguageChanged(); + + void BuildFormatMenu(); + void BuildAudioVideoMenus(); + void GetSelectedFormatInfo( + media_file_format** _format, + media_codec_info** _audio, + media_codec_info** _video); + + void SetStatusMessage(const char *message); + void SetFileMessage(const char *message); + + void AddSourceFile(BMediaFile* file, + const entry_ref& ref); + void RemoveSourceFile(int32 index); + int32 CountSourceFiles(); + status_t GetSourceFileAt(int32 index, BMediaFile** _file, + entry_ref* ref); + + void SourceFileSelectionChanged(); + + void SetEnabled(bool enabled, bool convertEnabled); + bool IsEnabled(); + + const char* StartDuration() const; + const char* EndDuration() const; + + int32 AudioQuality() const + { return fAudioQuality; } + int32 VideoQuality() const + { return fVideoQuality; } + + void SetAudioQualityLabel(const char* label); + void SetVideoQualityLabel(const char* label); + + BDirectory OutputDirectory() const; + + private: + void _UpdateLabels(); + void _CreateMenu(); + void _DestroyMenu(); + void _SetOutputFolder(BEntry entry); + + media_format fDummyFormat; + BButton* fConvertButton; + + BButton* fDestButton; + BButton* fPreviewButton; + BBox* fBox1; + BBox* fBox2; + BBox* fBox3; + + BMenuBar* fMenuBar; + BMenuField* fFormatMenu; + BMenuField* fVideoMenu; + BMenuField* fAudioMenu; + StatusView* fStatusView; + StatusView* fStatusView2; + MediaFileListView* fListView; + MediaFileInfoView* fInfoView; + BStringView* fOutputFolder; + BTextControl* fStartDurationTC; + BTextControl* fEndDurationTC; + + BSlider* fVideoQualitySlider; + BSlider* fAudioQualitySlider; + + int32 fVideoQuality; + int32 fAudioQuality; + + BFilePanel* fSaveFilePanel; + BFilePanel* fOpenFilePanel; + + BDirectory fOutputDir; + bool fOutputDirSpecified; + + bool fEnabled; + bool fConverting; + bool fCancelling; +}; + +#endif // MEDIA_CONVERTER_WINDOW_H + + diff --git a/src/apps/mediaconverter/MediaEncoderWindow.cpp b/src/apps/mediaconverter/MediaEncoderWindow.cpp new file mode 100644 index 0000000000..e85a8824ae --- /dev/null +++ b/src/apps/mediaconverter/MediaEncoderWindow.cpp @@ -0,0 +1,58 @@ +// Copyright 1999, Be Incorporated. All Rights Reserved. +// Copyright 2000-2004, Jun Suzuki. All Rights Reserved. +// Copyright 2007, Stephan Aßmus. All Rights Reserved. +// This file may be used under the terms of the Be Sample Code License. +#include "MediaEncoderWindow.h" + +#include + +#include + +#include "Strings.h" + + +MediaEncoderWindow::MediaEncoderWindow(BRect frame, BView* view) + : BWindow(frame, ENCODER_PARAMETERS, B_DOCUMENT_WINDOW_LOOK, + B_MODAL_APP_WINDOW_FEEL, + B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS) +{ + // create and acquire the quit semaphore + fQuitSem = create_sem(0, "encoder_view"); + + fView = view; + AddChild(fView); + ResizeTo(fView->Bounds().Width(), fView->Bounds().Height()); +} + + +MediaEncoderWindow::~MediaEncoderWindow() +{ + // The view must continue to exist until conversion complete. + RemoveChild(fView); + delete_sem(fQuitSem); +} + + +void +MediaEncoderWindow::MessageReceived(BMessage *msg) +{ +} + + +bool +MediaEncoderWindow::QuitRequested() +{ + return true; +} + + +void +MediaEncoderWindow::Go() +{ + this->Show(); + + // wait until window is quit + while (acquire_sem(fQuitSem) == B_INTERRUPTED) + ; +} + diff --git a/src/apps/mediaconverter/MediaEncoderWindow.h b/src/apps/mediaconverter/MediaEncoderWindow.h new file mode 100644 index 0000000000..678468db29 --- /dev/null +++ b/src/apps/mediaconverter/MediaEncoderWindow.h @@ -0,0 +1,29 @@ +// Copyright 1999, Be Incorporated. All Rights Reserved. +// Copyright 2000-2004, Jun Suzuki. All Rights Reserved. +// Copyright 2007, Stephan Aßmus. All Rights Reserved. +// This file may be used under the terms of the Be Sample Code License. +#ifndef MEDIA_ENCODER_WINDOW_H +#define MEDIA_ENCODER_WINDOW_H + + +#include + +class MediaEncoderWindow : public BWindow { + public: + MediaEncoderWindow(BRect frame, + BView* pBView); + virtual ~MediaEncoderWindow(); + + void Go(); + + protected: + virtual void MessageReceived(BMessage *msg); + virtual bool QuitRequested(); + + private: + BView* fView; + sem_id fQuitSem; + +}; + +#endif // MEDIA_ENCODER_WINDOW_H diff --git a/src/apps/mediaconverter/MediaFileInfoView.cpp b/src/apps/mediaconverter/MediaFileInfoView.cpp new file mode 100644 index 0000000000..ab7863c04a --- /dev/null +++ b/src/apps/mediaconverter/MediaFileInfoView.cpp @@ -0,0 +1,195 @@ +// Copyright 1999, Be Incorporated. All Rights Reserved. +// Copyright 2000-2004, Jun Suzuki. All Rights Reserved. +// Copyright 2007, Stephan Aßmus. All Rights Reserved. +// This file may be used under the terms of the Be Sample Code License. +#include "MediaFileInfoView.h" + +#include + +#include +#include +#include + +#include "Strings.h" + + +MediaFileInfoView::MediaFileInfoView(BRect frame, uint32 resizingMode) + : BView(frame, "MediaFileInfoView", resizingMode, + B_FULL_UPDATE_ON_RESIZE | B_WILL_DRAW) + , fRef() + , fMediaFile(NULL) + , fDuration(0) +{ +} + + +MediaFileInfoView::~MediaFileInfoView() +{ +} + + +void +MediaFileInfoView::Draw(BRect /*update*/) +{ + font_height fh; + GetFontHeight(&fh); + BPoint p(2, fh.ascent + fh.leading); + BFont font; + GetFont(&font); + font.SetFace(B_BOLD_FACE); + font.SetSize(12); + SetFont(&font); + + if (fMediaFile == NULL) { + DrawString(NO_FILE_LABEL, p); + return; + } + + BString aFmt, vFmt, aDetails, vDetails, duration; + _GetFileInfo(&aFmt, &vFmt, &aDetails, &vDetails, &duration); + + // draw filename + DrawString(fRef.name, p); + float lineHeight = fh.ascent + fh.descent + fh.leading; + p.y += (float)ceil(lineHeight * 1.5); + + float durLen = StringWidth(DURATION_LABEL) + 5; + float audLen = StringWidth(AUDIO_INFO_LABEL) + 5; + float vidLen = StringWidth(VIDEO_INFO_LABEL) + 5; + float maxLen = MAX(durLen, audLen); + maxLen = MAX(maxLen, vidLen); + + // draw labels + DrawString(AUDIO_INFO_LABEL, p + BPoint(maxLen - audLen, 0)); + BPoint p2 = p; + p2.x += maxLen + 4; + p.y += lineHeight * 2; + DrawString(VIDEO_INFO_LABEL, p + BPoint(maxLen - vidLen, 0)); + p.y += lineHeight * 2; + DrawString(DURATION_LABEL, p + BPoint(maxLen - durLen, 0)); + + // draw audio/video/duration info + font.SetFace(B_REGULAR_FACE); + font.SetSize(10); + SetFont(&font); + + DrawString(aFmt.String(), p2); + p2.y += lineHeight; + DrawString(aDetails.String(), p2); + p2.y += lineHeight; + DrawString(vFmt.String(), p2); + p2.y += lineHeight; + DrawString(vDetails.String(), p2); + p2.y += lineHeight; + DrawString(duration.String(), p2); +} + + +void +MediaFileInfoView::AttachedToWindow() +{ + rgb_color c = Parent()->LowColor(); + SetViewColor(c); + SetLowColor(c); +} + + +void +MediaFileInfoView::Update(BMediaFile* file, entry_ref* ref) +{ + if (fMediaFile == file) + return; + + fMediaFile = file; + + if (file != NULL && ref != NULL) + fRef = *ref; + else + fRef = entry_ref(); + + Invalidate(); +} + + +// #pragma mark - + + +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"; +} + + diff --git a/src/apps/mediaconverter/MediaFileInfoView.h b/src/apps/mediaconverter/MediaFileInfoView.h new file mode 100644 index 0000000000..0ac2afcf41 --- /dev/null +++ b/src/apps/mediaconverter/MediaFileInfoView.h @@ -0,0 +1,43 @@ +// Copyright 1999, Be Incorporated. All Rights Reserved. +// Copyright 2000-2004, Jun Suzuki. All Rights Reserved. +// Copyright 2007, Stephan Aßmus. All Rights Reserved. +// This file may be used under the terms of the Be Sample Code License. +#ifndef MEDIA_FILE_INFO_VIEW_H +#define MEDIA_FILE_INFO_VIEW_H + + +#include +#include + + +class BMediaFile; +class BString; + +class MediaFileInfoView : public BView { + public: + MediaFileInfoView(BRect frame, + uint32 resizingMode); + virtual ~MediaFileInfoView(); + + protected: + virtual void Draw(BRect updateRect); + virtual void AttachedToWindow(); + + public: + void Update(BMediaFile* file, entry_ref* ref); + bigtime_t Duration() const + { return fDuration; } + + private: + void _GetFileInfo(BString* audioFormat, + BString* videoFormat, + BString* audioDetails, + BString* videoDetails, + BString* duration); + + entry_ref fRef; + BMediaFile* fMediaFile; + bigtime_t fDuration; +}; + +#endif // MEDIA_FILE_INFO_VIEW_H diff --git a/src/apps/mediaconverter/MediaFileListView.cpp b/src/apps/mediaconverter/MediaFileListView.cpp new file mode 100644 index 0000000000..2c7db3c46e --- /dev/null +++ b/src/apps/mediaconverter/MediaFileListView.cpp @@ -0,0 +1,109 @@ +// Copyright 1999, Be Incorporated. All Rights Reserved. +// Copyright 2000-2004, Jun Suzuki. All Rights Reserved. +// Copyright 2007, Stephan Aßmus. All Rights Reserved. +// This file may be used under the terms of the Be Sample Code License. +#include "MediaFileListView.h" + +#include +#include +#include + +#include "MediaConverterWindow.h" +#include "MessageConstants.h" + + +// #pragma mark - MediaFileListItem + + +MediaFileListItem::MediaFileListItem(BMediaFile* file, const entry_ref& ref) + : BStringItem(ref.name), + fRef(ref), + fMediaFile(file) +{ +} + + +MediaFileListItem::~MediaFileListItem() +{ + delete fMediaFile; +} + + +// #pragma mark - MediaFileListView + + +MediaFileListView::MediaFileListView(BRect frame, uint32 resizingMode) + : BListView(frame, "MediaFileListView", B_SINGLE_SELECTION_LIST, resizingMode, + B_WILL_DRAW | B_NAVIGABLE | B_FRAME_EVENTS) +{ + fEnabled = true; +} + + +MediaFileListView::~MediaFileListView() +{ + BListItem *item; + while ((item = RemoveItem((int32)0)) != NULL) { + delete item; + } +} + + +void +MediaFileListView::SetEnabled(bool enabled) +{ + if (enabled == fEnabled) + return; + + fEnabled = enabled; + // TODO: visual indication of enabled status? +} + + +bool +MediaFileListView::IsEnabled() const +{ + return fEnabled; +} + + +void +MediaFileListView::AddItem(BMediaFile* file, const entry_ref& ref) +{ + BListView::AddItem(new MediaFileListItem(file, ref)); + be_app_messenger.SendMessage(FILE_LIST_CHANGE_MESSAGE); +} + + +void +MediaFileListView::KeyDown(const char *bytes, int32 numBytes) +{ + switch (bytes[0]) { + case B_DELETE: + if (IsEnabled()) { + int32 selection = CurrentSelection(); + if (selection >= 0) { + delete RemoveItem(selection); + // select the previous item + int32 count = CountItems(); + if (selection >= count) + selection = count - 1; + Select(selection); + be_app_messenger.SendMessage(FILE_LIST_CHANGE_MESSAGE); + } + } + break; + default: + BListView::KeyDown(bytes, numBytes); + } +} + + +void +MediaFileListView::SelectionChanged() +{ + MediaConverterWindow* win = dynamic_cast(Window()); + if (win != NULL) + win->SourceFileSelectionChanged(); +} + diff --git a/src/apps/mediaconverter/MediaFileListView.h b/src/apps/mediaconverter/MediaFileListView.h new file mode 100644 index 0000000000..9ed44283d9 --- /dev/null +++ b/src/apps/mediaconverter/MediaFileListView.h @@ -0,0 +1,47 @@ +// Copyright 1999, Be Incorporated. All Rights Reserved. +// Copyright 2000-2004, Jun Suzuki. All Rights Reserved. +// Copyright 2007, Stephan Aßmus. All Rights Reserved. +// This file may be used under the terms of the Be Sample Code License. +#ifndef MEDIA_FILE_LIST_VIEW_H +#define MEDIA_FILE_LIST_VIEW_H + + +#include +#include + + +class BMediaFile; +struct entry_ref; + + +class MediaFileListItem : public BStringItem { + public: + MediaFileListItem(BMediaFile* file, const entry_ref& ref); + virtual ~MediaFileListItem(); + + entry_ref fRef; + BMediaFile* fMediaFile; +}; + + +class MediaFileListView : public BListView { + public: + MediaFileListView(BRect frame, + uint32 resizingMode); + virtual ~MediaFileListView(); + + protected: + virtual void KeyDown(const char *bytes, int32 numBytes); + virtual void SelectionChanged(); + + public: + void AddItem(BMediaFile* file, const entry_ref& ref); + + void SetEnabled(bool enabled); + bool IsEnabled() const; + + private: + bool fEnabled; +}; + +#endif //MEDIACONVERTER_H diff --git a/src/apps/mediaconverter/MessageConstants.h b/src/apps/mediaconverter/MessageConstants.h new file mode 100644 index 0000000000..d492b94aec --- /dev/null +++ b/src/apps/mediaconverter/MessageConstants.h @@ -0,0 +1,30 @@ +// Copyright 1999, Be Incorporated. All Rights Reserved. +// Copyright 2000-2004, Jun Suzuki. All Rights Reserved. +// Copyright 2007, Stephan Aßmus. All Rights Reserved. +// This file may be used under the terms of the Be Sample Code License. +#ifndef MESSAGE_CONSTANTS_H +#define MESSAGE_CONSTANTS_H + +#define CONVERT_BUTTON_MESSAGE 'cVTB' +#define FORMAT_SELECT_MESSAGE 'fMTS' +#define AUDIO_CODEC_SELECT_MESSAGE 'aCSL' +#define VIDEO_CODEC_SELECT_MESSAGE 'vCSL' +#define FILE_LIST_CHANGE_MESSAGE 'fLCH' +#define START_CONVERSION_MESSAGE 'stCV' +#define CANCEL_CONVERSION_MESSAGE 'cNCV' +#define CONVERSION_DONE_MESSAGE 'cVSD' + +#define OUTPUT_FOLDER_MESSAGE 'oUTF' +#define FOLDER_SELECT_MESSAGE 'sLFO' +#define OPEN_FILE_MESSAGE 'oFIL' +#define DISP_ABOUT_MESSAGE 'aBUT' +#define QUIT_MESSAGE 'qUIT' +#define PREVIEW_MESSAGE 'pVEW' +#define PRIORITY_CHANGED_MESSAGE 'cPRI' +#define VIDEO_QUALITY_CHANGED_MESSAGE 'vQCG' +#define AUDIO_QUALITY_CHANGED_MESSAGE 'aQCG' +#define SELECT_THIS_DIR_MESSAGE 'sDir' + +#define INIT_FORMAT_MENUS 'iFMN' + +#endif // MESSAGE_CONSTANTS_H diff --git a/src/apps/mediaconverter/StatusView.cpp b/src/apps/mediaconverter/StatusView.cpp new file mode 100644 index 0000000000..703b503402 --- /dev/null +++ b/src/apps/mediaconverter/StatusView.cpp @@ -0,0 +1,70 @@ +// Copyright 1999, Be Incorporated. All Rights Reserved. +// Copyright 2000-2004, Jun Suzuki. All Rights Reserved. +// Copyright 2007, Stephan Aßmus. All Rights Reserved. +// This file may be used under the terms of the Be Sample Code License. +#include "StatusView.h" + + +StatusView::StatusView(BRect frame, uint32 resizingMode) + : BView(frame, "StatusView", resizingMode, + B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE) + , fStatusString(B_EMPTY_STRING) +{ + frame.OffsetTo(0, 0); + fStatusRect = frame; + + // TODO: bad! + BFont font; + GetFont(&font); + font.SetSize(12); + SetFont(&font); +} + + +StatusView::~StatusView() +{ +} + + +void +StatusView::AttachedToWindow() +{ + rgb_color c = Parent()->LowColor(); + SetViewColor(c); + SetLowColor(c); +} + + +void +StatusView::Draw(BRect /*update*/) +{ + // TODO: placement information should be cached here + // for better performance + font_height fh; + GetFontHeight(&fh); + DrawString(fStatusString.String(), + fStatusRect.LeftBottom() + BPoint(1, -fh.descent)); +} + + +void +StatusView::MessageReceived(BMessage* message) +{ + BView::MessageReceived(message); +} + + +void +StatusView::SetStatus(const char* text) +{ + fStatusString.SetTo(text); + Invalidate(); +} + + +const char* +StatusView::Status() +{ + return fStatusString.String(); +} + diff --git a/src/apps/mediaconverter/StatusView.h b/src/apps/mediaconverter/StatusView.h new file mode 100644 index 0000000000..54eba4ab1d --- /dev/null +++ b/src/apps/mediaconverter/StatusView.h @@ -0,0 +1,35 @@ +// Copyright 1999, Be Incorporated. All Rights Reserved. +// Copyright 2000-2004, Jun Suzuki. All Rights Reserved. +// Copyright 2007, Stephan Aßmus. All Rights Reserved. +// This file may be used under the terms of the Be Sample Code License. +#ifndef STATUS_VIEW_H +#define STATUS_VIEW_H + + +#include +#include + + +class StatusView : public BView { + public: + StatusView(BRect frame, + uint32 resizingMode); + virtual ~StatusView(); + + protected: + virtual void AttachedToWindow(); + virtual void Draw(BRect update); + virtual void MessageReceived(BMessage* message); + + public: + void SetStatus(const char* text); + const char* Status(); + + private: + BRect fStatusRect; + BString fStatusString; +}; + + +#endif // STATUS_VIEW_H + diff --git a/src/apps/mediaconverter/Strings.h b/src/apps/mediaconverter/Strings.h new file mode 100644 index 0000000000..ce98e19d39 --- /dev/null +++ b/src/apps/mediaconverter/Strings.h @@ -0,0 +1,92 @@ +// Copyright 1999, Be Incorporated. All Rights Reserved. +// Copyright 2000-2004, Jun Suzuki. All Rights Reserved. +// Copyright 2007, Stephan Aßmus. All Rights Reserved. +// This file may be used under the terms of the Be Sample Code License. +#ifndef STRINGS_H +#define STRINGS_H + + +#include + + +#if B_BEOS_VERSION >= 0x520 + typedef const char Char; + #if B_BEOS_VERSION>=0x530 // 0x530 RC3 + #include + #else + #include + #endif +#else + #define _T(str) str + typedef char Char; +#endif + +#define VERSION "1.3.0" + +#define SOURCE_BOX_LABEL _T("Source files") +#define INFO_BOX_LABEL _T("File details") +#define OUTPUT_BOX_LABEL _T("Output format") +#define FORMAT_LABEL _T("File format") +#define VIDEO_LABEL _T("Video encoding") +#define AUDIO_LABEL _T("Audio encoding") +// +#define OUTPUT_FOLDER_LABEL _T("Output Folder") +#define PREVIEW_BUTTON_LABEL _T("Preview") +#define START_LABEL _T("Start mSec ") +#define END_LABEL _T("End mSec ") +// +#define FORMAT_MENU_LABEL _T("Format") +#define VIDEO_MENU_LABEL _T("Video") +#define AUDIO_MENU_LABEL _T("Audio") +#define DURATION_LABEL _T("Duration:") +#define VIDEO_INFO_LABEL _T("Video:") +#define AUDIO_INFO_LABEL _T("Audio:") +#define CONVERT_LABEL _T("Convert") +#define CANCEL_LABEL _T("Cancel") +#define VIDEO_QUALITY_LABEL _T("Video quality %3d%%") +#define AUDIO_QUALITY_LABEL _T("Audio quality %3d%%") +#define SLIDER_LOW_LABEL _T("Low") +#define SLIDER_HIGH_LABEL _T("High") +#define NONE_LABEL _T("None available") +#define DROP_MEDIA_FILE_LABEL _T("Drop media files onto this window") +#define CANCELLING_LABEL _T("Cancelling") +#define ABOUT_TITLE_LABEL _T("About") +#define OK_LABEL _T("OK") +#define CONV_COMPLETE_LABEL _T("Conversion completed") +#define CONV_CANCEL_LABEL _T("Conversion cancelled") +#define SELECT_DIR_LABEL _T("Select This Directory") +#define SELECT_LABEL _T("Select") +#define SAVE_DIR_LABEL _T("MediaConverter+:SaveDirectory") +#define NO_FILE_LABEL _T("No file selected") +// +#define FILE_MENU_LABEL _T("File") +#define OPEN_MENU_LABEL _T("Open") +#define ABOUT_MENU_LABEL _T("About") +#define QUIT_MENU_LABEL _T("Quit") + +#define WRITE_AUDIO_STRING _T("Writing audio track:") +#define WRITE_VIDEO_STRING _T("Writing video track:") +#define COMPLETE_STRING _T("complete") +#define OUTPUT_FILE_STRING1 _T("Output file") +#define OUTPUT_FILE_STRING2 _T("created") +#define AUDIO_SUPPORT_STRING _T("Audio quality not supported") +#define VIDEO_SUPPORT_STRING _T("Video quality not supported") +#define VIDEO_PARAMFORM_STRING _T("Video using parameters form settings") +#define CONTINUE_STRING _T("Continue") +#define FILES _T("files") +#define FILE _T("file") +#define NOTRECOGNIZE _T(" were not recognized as supported media files:") +// +#define LAUNCH_ERROR _T("Error launching: ") +#define OUTPUT_FILE_STRING3 _T("Error creating") +#define CONVERT_ERROR_STRING _T("Error converting") +#define ERROR_WRITE_VIDEO_STRING _T("Error writing video frame ") +#define ERROR_WRITE_AUDIO_STRING _T("Error writing audio frame ") +#define ERROR_READ_VIDEO_STRING _T("Error read video frame ") +#define ERROR_READ_AUDIO_STRING _T("Error read audio frame ") +#define ERROR_LOAD_STRING _T("Error loading file") + +#define ENCODER_PARAMETERS _T("Encoder Parameters") + + +#endif // STRINGS_H diff --git a/src/apps/mediaconverter/languages/MediaConverter.frFR b/src/apps/mediaconverter/languages/MediaConverter.frFR new file mode 100644 index 0000000000..24d4db034e --- /dev/null +++ b/src/apps/mediaconverter/languages/MediaConverter.frFR @@ -0,0 +1,56 @@ +"File" "Fichier" +"Open" "Ouvrir" +"About" "A propos" +"Priority" "Priorité" +"Source files" "Fichiers sources" +"File details" "Détail du fichier" +"Output format" "Format de sortie" +"File format" "Format du fichier" +"Video encoding" "Codage Vidéo" +"Audio encoding" "Codage Audio" +"Output Folder" "Dossier de sortie" +"Preview" "Prévue" +"Start mSec " "Début (mSec)" +"End mSec " "FIn (mSec)" +"Format" "Format" +"Video" "Vidéo" +"Audio" "Audio" +"Video:" "Vidéo:" +"Audio:" "Audio:" +"Duration:" "Durée:" +"Convert" "Convertir" +"Cancel" "Annuler" +"Low" "Faible" +"High" "Haute" +"Video quality %3d%%" "QualitéVidéo %3d%%" +"Audio quality %3d%%" "QualitéAudio %3d%%" +"Drop media files onto this window" "Jeter les fichiers media dans cette fenêtre" +"None available" "Non disponible" +"Converting" "Conversion en cours" +"Conversion cancelled" "Conversion annulée" +"Conversion completed" "Conversion terminée" +"About" "A propos" +"Cancelling" "Annulation en cours" +"OK" "Ok" +"No file selected" "Aucun fichier sélectionné" +"Select This Directory" "Choisir ce dossier" +"Select" "Sélectionner" +"MediaConverter+:SaveDirectory" "MediaConverter+:DossierSauvegarde" +"Output file" "Fichier cible" +"created" "créé" +"AudioQuality doesn't support" "Qualité Audio non supportée" +"VideoQuality doesn't support" "Qualité Vidéo non supportée" +"Writing audio track:" "Ecriture de la piste audio:" +"Writing video track:" "Ecriture de la piste vidéo:" +"Error launching: " "Erreur de lancement : " +"Error creating" "Erreur de création" +"Error converting" "Erreur de conversion" +"Error writing video frame " "Erreur d'écriture de la frame vidéo" +"Error writing audio frame " "Erreur d'écriture de la frame audio" +"Error read video frame " "Erreur de lecture de la frame vidéo" +"Error read audio frame " "Erreur de lecture de la frame audio" +"complete" "terminé" +"file" "fichier" +"files" "fichiers" +"Continue" "Continuer" +" were not recognized as supported media files:" " ne sont pas reconnus comme des fichiers media supportés:" diff --git a/src/apps/mediaconverter/languages/MediaConverter.itIT b/src/apps/mediaconverter/languages/MediaConverter.itIT new file mode 100644 index 0000000000..79141a0e6e --- /dev/null +++ b/src/apps/mediaconverter/languages/MediaConverter.itIT @@ -0,0 +1,56 @@ +"File" "F) File" +"Open" "A) Apri" +"About" "R) A Proposito" +"Priority" "P) Priorità" +"Source files" "Files sorgente" +"File details" "Dettagli" +"Output format" "Formato di output" +"File format" "Formato del file" +"Video encoding" "Codifica video" +"Audio encoding" "Codifica audio" +"Output Folder" "Cartella di destinazione" +"Preview" "Anteprima" +"Start mSec " "Inizio mSec" +"End mSec " "Fine mSec" +"Format" "Formato" +"Video" "Video" +"Audio" "Audio" +"Video:" "Video:" +"Audio:" "Audio:" +"Duration:" "Durata:" +"Convert" "Converti" +"Cancel" "Annulla" +"Low" "Bassa" +"High" "Alta" +"Video quality %3d%%" "Qualità video %3d%%" +"Audio quality %3d%%" "Qualità audio %3d%%" +"Drop media files onto this window" "Trascina i files multimediali in questa finestra" +"None available" "Nessuno disponibile" +"Converting" "Conversione in corso" +"Conversion cancelled" "Conversione annullata" +"Conversion completed" "Conversione completata" +"About" "A Proposito" +"Cancelling" "Interruzione" +"OK" "OK" +"No file selected" "Nessun file selezionato" +"Select This Directory" "Seleziona questa directory" +"Select" "Seleziona" +"MediaConverter+:SaveDirectory" "MediaConverter+:Directory di salvataggio" +"Output file" "File di output" +"created" "creato" +"Audio-Quality doesn't support" "Audio-Quality non supportata" +"Video-Quality doesn't support" "Video-Quality non supportata" +"Writing audio track:" "Scrittura traccia audio in corso:" +"Writing video track:" "Scrittura traccia video in corso:" +"Error launching: " "Errore lanciando: " +"Error creating" "Errore creando" +"Error converting" "Errore convertendo" +"Error writing video frame " "Errore scrivendo un frame video" +"Error writing audio frame " "Errore scrivendo un frame audio" +"Error read video frame " "Errore leggendo un frame video" +"Error read audio frame " "Errore leggendo un frame audio" +"complete" "completato" +"file" "file" +"files" "files" +"Continue" "Continua" +" were not recognized as supported media files:" "non sono stati riconosciuti come files multimediali:" diff --git a/src/apps/mediaconverter/languages/MediaConverter.jaJP b/src/apps/mediaconverter/languages/MediaConverter.jaJP new file mode 100644 index 0000000000..a545b0013c --- /dev/null +++ b/src/apps/mediaconverter/languages/MediaConverter.jaJP @@ -0,0 +1,56 @@ +"File" "F) ファイル" +"Open" "O) 開く" +"About" "A) アプリケーション情報" +"Priority" "P) 優先度" +"Source files" "ソースファイル" +"File details" "ファイルの詳細" +"Output format" "出力形式" +"File format" "ファイル形式" +"Video encoding" "映像エンコード形式" +"Audio encoding" "音声エンコード形式" +"Output Folder" "出力フォルダ" +"Preview" "プレビュー" +"Start mSec " "開始 mSec" +"End mSec " "終了 mSec" +"Format" "形式" +"Video" "映像" +"Audio" "音声" +"Video:" "映像:" +"Audio:" "音声:" +"Duration:" "長さ:" +"Convert" "変換開始" +"Cancel" "キャンセル" +"Low" "低" +"High" "高" +"Video quality %3d%%" "画質 %3d%%" +"Audio quality %3d%%" "音質 %3d%%" +"Drop media files onto this window" "メディア・ファイルをドロップできます。" +"None available" "利用不可" +"Converting" "変寒中" +"Conversion cancelled" "変換中止" +"Conversion completed" "変換完了" +"About" "アプリケーション情報" +"Cancelling" "中止しています" +"OK" "了解" +"No file selected" "ファイル未選択" +"Select This Directory" "現在のディレクトリを選択" +"Select" "選択" +"MediaConverter+:SaveDirectory" "MediaConverter+:保存先のディレクトリ" +"Output file" "出力ファイル" +"created" "生成" +"AudioQuality doesn't support" "音質調整機能なし" +"VideoQuality doesn't support" "画質調整機能なし" +"Writing audio track:" "音声トラック書き込み中:" +"Writing video track:" "映像トラック書き込み中:" +"Error launching: " "起動エラー : " +"Error creating" "ファイル書き込みエラー " +"Error converting" "変換エラー" +"Error writing video frame " "映像トラック書き込みエラー" +"Error writing audio frame " "音声トラック書き込みエラー" +"Error read video frame " "映像トラック読み込みエラー" +"Error read audio frame " "音声トラック読み込みエラー" +"complete" "完了" +"file" "つのメディアファイル" +"files" "つのメディアファイル" +"Continue" "継続" +" were not recognized as supported media files:" "はサポート外形式のため処理できません:"