///////////////////////////////////////////////////////////////////////////// // Name: ProgressDlg.cpp // Purpose: Progress of generation/burning dialog // Author: Alex Thuering // Created: 14.08.2004 // RCS-ID: $Id: ProgressDlg.cpp,v 1.42 2007/07/08 17:11:04 ntalex Exp $ // Copyright: (c) Alex Thuering // Licence: GPL ///////////////////////////////////////////////////////////////////////////// #include "ProgressDlg.h" #include "Config.h" #include "MPEG.h" #include #include #include #include #include #include #define DATA_FILE(fname) wxFindDataFile(_T("data") + wxString(wxFILE_SEP_PATH) + fname) ////////////////////////// Process Execute /////////////////////////////////// #define MAX_WARNINGS 10 class ProcessExecute: public wxPipeExecute { public: ProcessExecute(ProgressDlg* processDlg): m_processDlg(processDlg) {} virtual ~ProcessExecute() {}; virtual void ProcessOutput(wxString line) { m_processDlg->AddDetailText(line + _T("\n")); } virtual bool IsCanceled() { return m_processDlg->IsCanceled(); } protected: ProgressDlg* m_processDlg; }; class ProgressExecute: public ProcessExecute { public: ProgressExecute(ProgressDlg* processDlg, wxString filter): ProcessExecute(processDlg), m_percent(0) { m_percentPattern.Compile(wxT("(([0-9]+[\\.,][0-9]+)|([0-9]+))%"),wxRE_ICASE); m_blockPattern.Compile(wxT("([0-9]+)[[:space:]]+of[[:space:]]+([0-9]+)"),wxRE_ICASE); m_filterPattern.Compile(filter,wxRE_ICASE); m_initSubStep = m_processDlg->GetSubStep(); } virtual ~ProgressExecute() {}; virtual void ProcessOutput(wxString line) { // get last output if program is using \b (remove \b at begin/end, then get text after last \b) while (line.at(0) == wxT('\b')) line.Remove(0,1); while (line.Last() == wxT('\b')) line.RemoveLast(1); line = line.AfterLast(wxT('\b')); if (m_filterPattern.Matches(line)) { if (m_blockPattern.Matches(line)) { long blocks = 0; long totalBlocks = 0; long percent = 0; if (m_blockPattern.GetMatch(line,1).ToLong(&blocks) && m_blockPattern.GetMatch(line,2).ToLong(&totalBlocks)) { percent = (totalBlocks > 0)?(blocks*100)/totalBlocks:0; m_processDlg->SetSubStep(m_initSubStep + (int)m_percent); if (percent >= m_percent) { m_percent += 5; } else { return; } } } else if (m_percentPattern.Matches(line)) { long percent = 0; wxString percentStr = m_percentPattern.GetMatch(line,1); percentStr = percentStr.BeforeFirst(wxT('.')).BeforeFirst(wxT(',')); if (percentStr.ToLong(&percent)) { m_processDlg->SetSubStep(m_initSubStep + (int)percent); if (percent >= m_percent) { m_percent += 5; } else if (percent < m_percent - 5) { m_initSubStep += 100; m_percent = 5; } else { return; } } } } m_processDlg->AddDetailText(line + _T("\n")); } protected: wxRegEx m_percentPattern; wxRegEx m_blockPattern; wxRegEx m_filterPattern; int m_initSubStep; int m_percent; }; class BlocksExecute: public ProcessExecute { public: BlocksExecute(ProgressDlg* processDlg): ProcessExecute(processDlg), m_percent(0) { m_initSubStep = m_processDlg->GetSubStep(); } virtual ~BlocksExecute() {}; virtual void ProcessOutput(wxString line) { long blocks = 0; long totalBlocks = 0; wxRegEx pattern(wxT(".*[[:space:]]+([0-9]+)[[:space:]]+of[[:space:]]+([0-9]+)[[:space:]]+.*")); if (pattern.Matches(line)) { pattern.GetMatch(line,1).ToLong(&blocks); pattern.GetMatch(line,2).ToLong(&totalBlocks); m_percent = (totalBlocks > 0)?(blocks*100)/totalBlocks:0; m_processDlg->SetSubStep(m_initSubStep + (int)m_percent); } m_processDlg->AddDetailText(line + _T("\n")); } protected: int m_initSubStep; int m_percent; }; class DVDAuthorExecute: public ProgressExecute { public: DVDAuthorExecute(ProgressDlg* processDlg, int totalSize): ProgressExecute(processDlg, wxT(".*")), m_totalSize(totalSize), m_warnings(0), m_warnStep(1), m_dvdauthorStep(0) { if (m_totalSize == 0) m_totalSize++; } virtual ~DVDAuthorExecute() {}; virtual void ProcessOutput(wxString line) { if (m_dvdauthorStep) return ProgressExecute::ProcessOutput(line); if (line.Mid(0,11) == _T("STAT: fixed")) { m_dvdauthorStep++; m_initSubStep += 200; m_processDlg->SetSubStep(m_initSubStep); } else if (line.Mid(0,10) == _T("STAT: VOBU")) { long size = 0; wxString sizeStr = line.BeforeLast(wxT(',')).AfterLast(wxT(' ')); if (sizeStr.Mid(sizeStr.Length()-2) == _T("MB") && sizeStr.Remove(sizeStr.Length()-2).ToLong(&size)) m_processDlg->SetSubStep(m_initSubStep + (int)size*200/m_totalSize); } else if (line.Mid(0,5) == _T("WARN:")) { m_warnings++; if (m_warnings > m_warnStep*10) m_warnStep = m_warnStep*10; else if (m_warnings % m_warnStep != 0) return; } m_processDlg->AddDetailText(line + _T("\n")); } protected: int m_totalSize; int m_warnings; int m_warnStep; int m_dvdauthorStep; }; /////////////////////////// Process Dialog /////////////////////////////////// BEGIN_EVENT_TABLE(ProgressDlg, wxDialog) EVT_BUTTON(wxID_CANCEL, ProgressDlg::OnCancel) EVT_BUTTON(HIDE_BT_ID, ProgressDlg::OnHideDetails) EVT_BUTTON(ICONIZE_BT_ID, ProgressDlg::OnMinimize) END_EVENT_TABLE() ProgressDlg::ProgressDlg(wxWindow* parent): wxDialog(parent, -1, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxCAPTION|wxRESIZE_BORDER|wxSYSTEM_MENU|wxTHICK_FRAME) { // begin wxGlade: ProgressDlg::ProgressDlg m_summaryLabel = new wxStaticText(this, -1, _("Summary:")); m_summaryText = new wxTextCtrl(this, -1, wxT(""), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxTE_RICH); m_gauge = new wxGauge(this, -1, 10, wxDefaultPosition, wxDefaultSize, wxGA_HORIZONTAL|wxGA_PROGRESSBAR|wxGA_SMOOTH); m_detailsLabel = new wxStaticText(this, -1, _("Details:")); m_detailsText = new wxTextCtrl(this, -1, wxT(""), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxTE_RICH); m_detailsBt = new wxButton(this, HIDE_BT_ID, _("Hide details")); m_minimizeBt = new wxButton(this, ICONIZE_BT_ID, _("Minimize")); m_cancelBt = new wxButton(this, wxID_CANCEL, _("Cancel")); set_properties(); do_layout(); // end wxGlade m_cancel = false; m_subStepCount = 0; } void ProgressDlg::set_properties() { // begin wxGlade: ProgressDlg::set_properties SetTitle(_("Generate DVD")); SetSize(wxSize(600, 600)); // end wxGlade m_detailsBtLabel = m_detailsBt->GetLabel(); m_detailsBt->SetLabel(_T("<< ") + m_detailsBtLabel); } void ProgressDlg::do_layout() { // begin wxGlade: ProgressDlg::do_layout wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); wxBoxSizer* btSizer = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* panelSizer = new wxBoxSizer(wxVERTICAL); panelSizer->Add(m_summaryLabel, 0, wxBOTTOM, 2); panelSizer->Add(m_summaryText, 1, wxBOTTOM|wxEXPAND, 8); panelSizer->Add(m_gauge, 0, wxBOTTOM|wxEXPAND, 4); panelSizer->Add(m_detailsLabel, 0, wxBOTTOM, 2); panelSizer->Add(m_detailsText, 1, wxEXPAND, 0); mainSizer->Add(panelSizer, 1, wxLEFT|wxRIGHT|wxTOP|wxEXPAND, 10); btSizer->Add(m_detailsBt, 0, wxALIGN_CENTER_VERTICAL, 0); btSizer->Add(20, 20, 1, wxEXPAND, 0); btSizer->Add(m_minimizeBt, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 8); btSizer->Add(m_cancelBt, 0, 0, 0); mainSizer->Add(btSizer, 0, wxALL|wxEXPAND, 10); SetAutoLayout(true); SetSizer(mainSizer); Layout(); Centre(); // end wxGlade m_panelSizer = panelSizer; #ifdef __WXMSW__ m_minimizeBt->Hide(); #endif } void ProgressDlg::OnHideDetails(wxCommandEvent& WXUNUSED(event)) { if (m_detailsText->IsShown()) { m_detailsLabel->Hide(); m_detailsText->Hide(); m_detailsText->Freeze(); m_panelSizer->Remove(m_detailsLabel); m_panelSizer->Remove(m_detailsText); int height = m_detailsLabel->GetSize().GetY() + m_detailsText->GetSize().GetY() + 2; SetSize(GetSize().GetX(), GetSize().GetY() - height); m_detailsBt->SetLabel(_("Show details") + wxString(_T(" >>"))); } else { m_detailsLabel->Show(); m_detailsText->Show(); m_detailsText->Thaw(); m_panelSizer->Insert(3, m_detailsLabel, 0, wxBOTTOM, 2); m_panelSizer->Insert(4, m_detailsText, 1, wxEXPAND, 0); int height = m_detailsLabel->GetSize().GetY() + m_detailsText->GetSize().GetY() + 2; SetSize(GetSize().GetX(), GetSize().GetY() + height); m_detailsBt->SetLabel(_T("<< ") + m_detailsBtLabel); } } void ProgressDlg::OnMinimize(wxCommandEvent& WXUNUSED(event)) { ((wxFrame*)GetParent())->Iconize(); } void ProgressDlg::AddSummaryMsg(const wxString& message, const wxString& details, const wxColour& colour) { m_summaryText->SetDefaultStyle(wxTextAttr(colour.Ok() ? colour : *wxBLACK)); m_summaryText->AppendText(message + _T("\n")); m_summaryText->ShowPosition(m_summaryText->GetLastPosition()); AddDetailMsg(details.length() ? details : message, colour.Ok() ? colour : *wxBLACK); } void ProgressDlg::AddDetailMsg(const wxString& message, const wxColour& colour) { if (m_cancel) return; if (colour.Ok()) m_detailsText->SetDefaultStyle(wxTextAttr(colour)); AddDetailText(message + _T("\n")); m_detailsText->SetDefaultStyle(wxTextAttr(wxColour(64,64,64))); } void ProgressDlg::AddDetailText(const wxString& text) { m_detailsText->AppendText(text); m_detailsText->ShowPosition(m_detailsText->GetLastPosition()); } void ProgressDlg::UpdateGauge() { int subStep = 0; if (m_subStepCount > 0) subStep = m_subStep*100/m_subStepCount; m_gauge->SetValue(m_step*100 + subStep); } void ProgressDlg::Failed(const wxString& message) { AddSummaryMsg(_("Failed"), message, *wxRED); } void ProgressDlg::FailedExec(const wxString& command) { Failed(_("Error executing of command: ") + command); } void ProgressDlg::OnCancel(wxCommandEvent& WXUNUSED(event)) { if (!m_cancel) { AddSummaryMsg(_("Aborted"), wxEmptyString, *wxRED); End(); } else EndModal(wxID_OK); } void ProgressDlg::End() { m_cancelBt->SetLabel(_("Close")); m_cancel = true; } bool ProgressDlg::IsCanceled() { wxYield(); return m_cancel; } void ProgressDlg::Start(BurnDlg* burnDlg, DVD* dvd) { m_winDisabler = new wxWindowDisabler(this); Show(); Run(burnDlg, dvd); End(); delete m_winDisabler; m_winDisabler = NULL; ShowModal(); } void ProgressDlg::Run(BurnDlg* burnDlg, DVD* dvd) { if (IsCanceled()) return; wxString tmpDir = burnDlg->GetTempDir(); if (tmpDir.Last() != wxFILE_SEP_PATH) tmpDir += wxFILE_SEP_PATH; wxString tmpDVDDir = tmpDir + wxString(wxT("dvd")) + wxFILE_SEP_PATH; // menus wxArrayPtrVoid menuVobs; int menuSubSteps = 0; for (int tsi = -1; tsi<(int)dvd->GetTitlesets().Count(); tsi++) { PgcArray& pgcs = dvd->GetPgcArray(tsi, true); for (int pgci = 0; pgci<(int)pgcs.Count(); pgci++) { Pgc* pgc = pgcs[pgci]; if (pgc->GetVobs().Count() == 0) continue; wxString menuFile = tmpDVDDir + wxString::Format(_T("menu%d-%d.mpg"), tsi+1, pgci); Vob* vob = pgc->GetVobs()[0]; vob->SetTmpFilename(menuFile); menuSubSteps += 10; if (vob->GetMenu()->HasVideoBackground()) { if (!MPEG::HasNavPacks(vob->GetMenu()->GetBackground())) menuSubSteps += 200; // fixvob(200) menuSubSteps += 100; // spumux(100) } else menuSubSteps += 150; // jpeg->mpg(50) + mplex(50) + spumux(50) menuVobs.Add(vob); } } // titles wxArrayPtrVoid titleVobs; int titleSubSteps = 0; for (int tsi = 0; tsi<(int)dvd->GetTitlesets().Count(); tsi++) { Titleset* ts = dvd->GetTitlesets()[tsi]; for (int pgci = 0; pgci<(int)ts->GetTitles().Count(); pgci++) { Pgc* pgc = ts->GetTitles()[pgci]; for (int vobi = 0; vobi<(int)pgc->GetVobs().Count(); vobi++) { Vob* vob = pgc->GetVobs()[vobi]; vob->SetTmpFilename(_T("")); if (vob->GetSlideshow()) continue; else if (vob->GetFilename().length()) { if (MPEG::HasNavPacks(vob->GetFilename()) && vob->GetAudioFilenames().Count() == 0) continue; titleSubSteps += 200; } else { if (!vob->GetVideoFilename().length() || !vob->GetAudioFilenames().Count()) continue; titleSubSteps += 100; } vob->SetTmpFilename(tmpDVDDir + wxString::Format(_T("title%d-%d-%d.vob"), tsi, pgci, vobi)); titleVobs.Add(vob); } } } // slideshow wxArrayPtrVoid slideshowVobs; int slideshowSubSteps = 0; for (int tsi = 0; tsi<(int)dvd->GetTitlesets().Count(); tsi++) { Titleset* ts = dvd->GetTitlesets()[tsi]; for (int pgci = 0; pgci<(int)ts->GetTitles().Count(); pgci++) { Pgc* pgc = ts->GetTitles()[pgci]; for (int vobi = 0; vobi<(int)pgc->GetVobs().Count(); vobi++) { Vob* vob = pgc->GetVobs()[vobi]; if (vob->GetSlideshow()) { slideshowSubSteps += 24*vob->GetSlideshow()->Count(); vob->SetTmpFilename(tmpDVDDir + wxString::Format(_T("title%d-%d-%d.vob"), tsi, pgci, vobi)); slideshowVobs.Add(vob); } } } } // subtitle wxArrayPtrVoid subtitleVobs; int subtitleSubSteps = 0; for (int tsi = 0; tsi<(int)dvd->GetTitlesets().Count(); tsi++) { Titleset* ts = dvd->GetTitlesets()[tsi]; for (int pgci = 0; pgci<(int)ts->GetTitles().Count(); pgci++) { Pgc* pgc = ts->GetTitles()[pgci]; for (int vobi = 0; vobi<(int)pgc->GetVobs().Count(); vobi++) { Vob* vob = pgc->GetVobs()[vobi]; if (vob->GetSubtitles().Count()) { subtitleSubSteps += vob->GetSize()*vob->GetSubtitles().Count(); vob->SetTmpFilename(tmpDVDDir + wxString::Format(_T("title%d-%d-%d.vob"), tsi, pgci, vobi)); subtitleVobs.Add(vob); } } } } // BEGIN int stepCount = 1; if (menuVobs.Count()>0) stepCount++; if (titleVobs.Count()>0) stepCount++; if (slideshowVobs.Count()>0) stepCount++; if (subtitleVobs.Count()>0) stepCount++; if (burnDlg->DoCreateIso() || (burnDlg->DoBurn() && burnDlg->DoAddECC())) { stepCount++; } if (burnDlg->DoAddECC()) stepCount++; if (burnDlg->DoBurn()) { stepCount++; if (burnDlg->DoFormat()) stepCount++; } SetSteps(stepCount); // 1. Prepare AddSummaryMsg(_("Prepare")); AddDetailMsg(_("Cleaning temporary directory")); if (wxDir::Exists(tmpDir) && wxFindFirstFile(tmpDir + _T("*"), wxDIR|wxFILE).length()) { if (wxMessageBox(_("The temporary directory isn't empty.\nThis directory must be cleaned.\nContinue?"), _("Burn"), wxYES_NO|wxICON_QUESTION, this) != wxYES) { AddSummaryMsg(_("Aborted"), wxEmptyString, *wxRED); return; } if (tmpDir.length()<=3 || !DeleteTempDir(tmpDir)) { Failed(wxString::Format(_("Can't remove directory '%s'"), tmpDir.c_str())); return; } } // create tmp dir if (!wxDir::Exists(tmpDir) && !wxMkdir(tmpDir)) { Failed(wxString::Format(_("Can't create directory '%s'"), tmpDir.c_str())); return; } if (!wxDir::Exists(tmpDVDDir) && !wxMkdir(tmpDVDDir)) { Failed(wxString::Format(_("Can't create directory '%s'"), tmpDVDDir.c_str())); return; } // 2. Generate menus if (menuVobs.Count()>0) { if (IsCanceled()) return; AddSummaryMsg(_("Generating menus")); SetSubSteps(menuSubSteps); for (int i=0; i<(int)menuVobs.Count(); i++) { AddDetailMsg(wxString::Format(_("Generating menu %d of %d"), i+1, menuVobs.Count())); Vob* vob = (Vob*)menuVobs[i]; if (!GenerateMenu(vob->GetMenu(), vob->GetTmpFilename(), dvd->GetAudioFormat())) return; } IncStep(); } // 3. Fix mpeg-files if (titleVobs.Count()>0) { if (IsCanceled()) return; AddSummaryMsg(_("Create VOB files")); SetSubSteps(titleSubSteps); for (int i=0; i<(int)titleVobs.Count(); i++) { Vob* vob = (Vob*)titleVobs[i]; if (vob->GetFilename().length()) { if (!FixVob(vob->GetFilename(), vob->GetAudioFilenames(), vob->GetTmpFilename())) return; } else { if (!MakeVob(vob->GetVideoFilename(), vob->GetAudioFilenames(), vob->GetTmpFilename())) return; } } IncStep(); } // 4. Generate slideshow if (slideshowVobs.Count()>0) { if (IsCanceled()) return; AddSummaryMsg(_("Generate slideshow")); SetSubSteps(slideshowSubSteps); for (int i=0; i<(int)slideshowVobs.Count(); i++) { AddDetailMsg(wxString::Format(_("Generating slideshow %d of %d"), i+1, slideshowVobs.Count())); Vob* vob = (Vob*)slideshowVobs[i]; if (!GenerateSlideshow(vob->GetSlideshow(), vob->GetTmpFilename(), dvd->GetAudioFormat())) return; } IncStep(); } // 5. Multiplex subtitles if (subtitleVobs.Count()>0) { if (IsCanceled()) return; AddSummaryMsg(_("Multiplexing subtitles")); SetSubSteps(subtitleSubSteps); for (int i=0; i<(int)subtitleVobs.Count(); i++) { AddDetailMsg(wxString::Format(_("Multiplexing subtitles %d of %d"), i+1, subtitleVobs.Count())); Vob* vob = (Vob*)subtitleVobs[i]; for (unsigned int s=0; sGetSubtitles().Count(); s++) { wxString vobFile = vob->GetFilename(); if (wxFileExists(vob->GetTmpFilename())) { if (!wxRenameFile(vob->GetTmpFilename(), vob->GetTmpFilename() + wxT(".old"))) { Failed(wxString::Format(_("Can't rename temporary file '%s'"),vob->GetTmpFilename().c_str())); return; } vobFile = vob->GetTmpFilename() + wxT(".old"); } if (!MultiplexSubtitles(vobFile, vob->GetSubtitles()[s], vob->GetTmpFilename())) return; IncSubStep(vob->GetSize()); } } IncStep(); } // 5. Generate dvd filesystem if (IsCanceled()) return; wxString dvdauthFile = tmpDVDDir + _T("dvdauthor.xml"); dvd->SaveDVDAuthor(dvdauthFile); AddSummaryMsg(_("Generating DVD")); SetSubSteps(300); wxString cmd = s_config.GetDvdauthorCmd(); cmd.Replace(_T("$FILE_CONF"), dvdauthFile); cmd.Replace(_T("$DIR"), tmpDVDDir); DVDAuthorExecute dvdauthorExec(this, dvd->GetSize(true)/1024); if (!dvdauthorExec.Execute(cmd)) { FailedExec(cmd); return; } // remove temp files if (s_config.GetRemoveTempFiles()) { wxDir d(tmpDir + wxString(wxT("dvd"))); wxString fname; while (d.GetFirst(&fname, _T("*.vob"), wxDIR_FILES)) if (!DeleteFile(tmpDVDDir + fname)) return; while (d.GetFirst(&fname, _T("menu*"), wxDIR_FILES)) if (!DeleteFile(tmpDVDDir + fname)) return; if (!DeleteFile(dvdauthFile)) return; } IncStep(); // 6. Preview if (burnDlg->DoPreview()) { if (IsCanceled()) return; AddSummaryMsg(_("Start preview")); wxString cmd = s_config.GetPreviewCmd(); cmd.Replace(_T("$DIR"), tmpDVDDir); if (!Exec(cmd)) FailedExec(cmd); if (burnDlg->DoBurn() && wxMessageBox(_("Burn this video to dvd?"), _("Burn"), wxYES_NO|wxICON_QUESTION, this) == wxNO) { AddSummaryMsg(_("Aborted"), wxEmptyString, *wxRED); return; } if (burnDlg->DoCreateIso() && wxMessageBox(_("Create iso image of this video?"), _("Burn"), wxYES_NO|wxICON_QUESTION, this) == wxNO) { AddSummaryMsg(_("Aborted"), wxEmptyString, *wxRED); return; } } // 7. Create ISO-Image if (burnDlg->DoCreateIso() || (burnDlg->DoBurn() && burnDlg->DoAddECC())) { if (IsCanceled()) return; AddSummaryMsg(_("Creating ISO image")); SetSubSteps(100); wxString cmd = s_config.GetIsoCmd(); cmd.Replace(_T("$VOL_ID"), dvd->GetName()); cmd.Replace(_T("$DIR"), tmpDVDDir); cmd.Replace(_T("$FILE"), burnDlg->DoCreateIso() ? burnDlg->GetIsoFile() : tmpDir + wxT("dvd.iso")); ProgressExecute exec(this, wxT(".*")); if (!exec.Execute(cmd)) { FailedExec(cmd); return; } IncStep(); } // 8. Add ECC-data if (burnDlg->DoAddECC()) { if (IsCanceled()) return; AddSummaryMsg(_("Adding ECC data")); SetSubSteps(200); wxString cmd = s_config.GetAddECCCmd(); cmd.Replace(_T("$FILE"), burnDlg->DoCreateIso() ? burnDlg->GetIsoFile() : tmpDir + wxT("dvd.iso")); ProgressExecute exec(this,wxT("(Preparing|Ecc).*")); if (!exec.Execute(cmd)) { FailedExec(cmd); return; } IncStep(); } // 9. Format DVD if (burnDlg->DoBurn() && burnDlg->DoFormat()) { if (IsCanceled()) return; AddSummaryMsg(_("Formating DVD-RW")); while (1) { SetSubSteps(100); wxString cmd = s_config.GetFormatCmd(); cmd.Replace(_T("$DEV"), burnDlg->GetDevice()); if (!Exec(cmd)) { int repeat = wxMessageBox(_("Formating DVD-RW failed. Try again?"), _("Burn"), wxYES_NO|wxCANCEL|wxICON_QUESTION, this); if (repeat == wxYES) continue; else if (repeat == wxNO) { AddSummaryMsg(_("-> skipped <-"), wxEmptyString, wxColour(128, 64, 64)); break; } else { FailedExec(cmd); return; } } break; } IncStep(); } // 10. Burn DVD if (burnDlg->DoBurn()) { if (IsCanceled()) return; AddSummaryMsg(_("Burning")); SetSubSteps(100); // burn if (burnDlg->DoAddECC()) { cmd = s_config.GetBurnISOCmd(); cmd.Replace(_T("$FILE"), tmpDir + wxT("dvd.iso")); // get iso size in sectors long size = wxFile(tmpDir + wxT("dvd.iso")).Length()/2048; cmd.Replace(_T("$SIZE"), wxString::Format(wxT("%d"),size)); } else { cmd = s_config.GetBurnCmd(); cmd.Replace(_T("$DIR"), tmpDVDDir); } cmd.Replace(_T("$VOL_ID"), dvd->GetName()); cmd.Replace(_T("$DEV"), burnDlg->GetDevice()); wxString speedStr; if (burnDlg->GetSpeed() > 0) { speedStr = s_config.GetBurnSpeedOpt(); speedStr.Replace(_T("$SPEED"), wxString::Format(_T("%d"), burnDlg->GetSpeed())); } cmd.Replace(_T("$SPEEDSTR"), speedStr); ProgressExecute exec(this, wxT(".*")); if (!exec.Execute(cmd)) { FailedExec(cmd); return; } IncStep(); } if (IsCanceled()) return; // remove tmp dir if ((burnDlg->DoCreateIso() || burnDlg->DoBurn()) && s_config.GetRemoveTempFiles()) DeleteTempDir(tmpDir); if (burnDlg->DoBurn()) AddSummaryMsg(_("Burning was successful."), wxEmptyString, wxColour(0,128,0)); else AddSummaryMsg(_("Generating was successful."), wxEmptyString, wxColour(0,128,0)); IncStep(); if (s_config.GetKey()<9) s_config.SetKey(s_config.GetKey()+1); } bool ProgressDlg::MakeVob(const wxString& videoFile, const wxArrayString& audioFiles, const wxString& vobFile) { if (IsCanceled()) return false; AddSummaryMsg(wxString::Format(_("Make Vob-file from '%s' and '%s'"), videoFile.c_str(), audioFiles[0].c_str())); // remove old wxString cmd = s_config.GetMplexCmd(); cmd.Replace(_T("$FILE_VIDEO"), videoFile); wxString audio; for (unsigned int i = 0; i0 ? wxT("\" \"") : wxT("")) + audioFiles[i]; cmd.Replace(_T("$FILE_AUDIO"), audio); cmd.Replace(_T("$FILE_OUT"), vobFile); if (!Exec(cmd)) { FailedExec(cmd); return false; } return true; } bool ProgressDlg::FixVob(const wxString& mpegFile, const wxArrayString& audioFiles, const wxString& vobFile) { if (IsCanceled()) return false; wxString tmpDir = vobFile.BeforeLast(wxFILE_SEP_PATH) + wxFILE_SEP_PATH; wxString tmpFile = vobFile.AfterLast(wxFILE_SEP_PATH).BeforeLast(wxT('.')); AddDetailMsg(_("Fix MPEG-file: ") + mpegFile); // remove old wxDir d(tmpDir); wxString fname; while (d.GetFirst(&fname, tmpFile + _T("*"), wxDIR_FILES)) if (!DeleteFile(tmpDir + fname)) return false; wxString cmd = s_config.GetDemplexCmd(); cmd.Replace(_T("$FILE_IN"), mpegFile); cmd.Replace(_T("$FILES_OUT"), tmpDir + tmpFile); ProgressExecute exec(this,wxT(".*")); if (!exec.Execute(cmd)) { FailedExec(cmd); return false; } cmd = s_config.GetMplexCmd(); d.GetFirst(&fname, tmpFile + _T("*"), wxDIR_FILES); cmd.Replace(_T("$FILE_VIDEO"), tmpDir + fname); d.GetNext(&fname); wxString audio = tmpDir + fname; for (unsigned int i = 0; iHasVideoBackground(); wxYield(); // save background and buttons AddDetailMsg(_("Prepare")); menu->SetTransparentColor(); wxImage* images = menu->GetImages(); if (!videoMenu) { images[0].SetOption(_T("quality"), 100); images[0].SaveFile(bgFile); } images[1].SaveFile(btFile); images[2].SaveFile(hlFile); images[3].SaveFile(selFile); delete[] images; // save spumux menu->SaveSpumux(spuFile, btFile, hlFile, selFile); IncSubStep(10); // convert jpeg to mpeg if (videoMenu) { if (!MPEG::HasNavPacks(menu->GetBackground())) { int subStep = GetSubStep(); wxArrayString audioFiles; if (!FixVob(menu->GetBackground(), audioFiles, bgmFile)) return false; SetSubStep(subStep+200); } else bgmFile = menu->GetBackground(); } else { AddDetailMsg(_("Converting jpg to mpeg")); wxString videoNorm; wxString frameRate = wxT("25"); if (menu->GetVideoFormat() == vfNTSC) { videoNorm = wxT(" --video-norm n --frame-rate 4"); frameRate = wxT("29.97"); } wxString cmd = s_config.GetJpeg2MpegCmd(); cmd.Replace(_T("$FRAME_RATE"), frameRate); cmd.Replace(_T("$VIDEO_NORM"), videoNorm); cmd.Replace(_T("$FRAMES"), wxString::Format(_T("%d"), s_config.GetMenuFrameCount())); cmd.Replace(_T("$BITRATE"), wxString::Format(_T("%d"), s_config.GetMenuVideoBitrate())); cmd.Replace(_T("$FILE_IN"), bgFile); cmd.Replace(_T("$FILE_OUT"), bgvFile); long ret = Exec(cmd); if (!ret) { FailedExec(cmd); return false; } if (s_config.GetRemoveTempFiles()) if (!DeleteFile(bgFile)) return false; IncSubStep(50); if (IsCanceled()) return false; AddDetailMsg(_("Multiplexing audio and video")); cmd = s_config.GetMplexCmd(); cmd.Replace(_T("$FILE_VIDEO"), bgvFile); cmd.Replace(_T("$FILE_AUDIO"), silenceFile); cmd.Replace(_T("$FILE_OUT"), bgmFile); if (!Exec(cmd)) { FailedExec(cmd); return false; } if (s_config.GetRemoveTempFiles()) if (!DeleteFile(bgvFile)) return false; IncSubStep(50); } //spumux if (IsCanceled()) return false; AddDetailMsg(_("Multiplexing subtitles (buttons) into mpeg")); wxString cmd = s_config.GetSpumuxCmd(); cmd.Replace(_T("$FILE_CONF"), spuFile); if (!Exec(cmd, bgmFile, menuFile)) { FailedExec(cmd); return false; } if (s_config.GetRemoveTempFiles()) { if ((!videoMenu || bgmFile != menu->GetBackground()) && !DeleteFile(bgmFile)) return false; if (!DeleteFile(btFile) || !DeleteFile(hlFile) || !DeleteFile(selFile) || !DeleteFile(spuFile)) return false; } IncSubStep(videoMenu ? 100 : 50); wxYield(); return true; } bool ProgressDlg::GenerateSlideshow(Slideshow* slideshow, const wxString& vobFile, AudioFormat audioFormat) { if (IsCanceled()) return false; AddDetailMsg(_("Generate slideshow")); wxString tmpFile = vobFile.BeforeLast(wxT('.')); wxString jpgFile = tmpFile + _T(".jpg"); wxString m2vFile = tmpFile + _T(".m2v"); wxString m2vTmpFile = tmpFile + _T("_tmp.m2v"); wxString mp2File = tmpFile + _T(".mp2"); wxString silenceFile = audioFormat == afMP2 ? DATA_FILE(_T("silence.mp2")) : DATA_FILE(_T("silence.ac3")); wxYield(); for (unsigned i=0; iCount(); i++) { // save background AddDetailMsg(wxString::Format(_("Save slide %d image"),i)); wxImage img = slideshow->GetImage(i); img.SetOption(_T("quality"), 100); img.SaveFile(jpgFile); IncSubStep(1); // convert jpeg to mpeg AddDetailMsg(wxString::Format(_("Converting slide %d image to video"),i)); wxString videoNorm; wxString frameRate = wxT("25"); if (slideshow->GetVideoFormat() == vfNTSC) { videoNorm = wxT(" --video-norm n --frame-rate 4"); frameRate = wxT("29.97"); } wxString cmd = s_config.GetJpeg2MpegCmd(); cmd.Replace(_T("$FRAME_RATE"), frameRate); cmd.Replace(_T("$VIDEO_NORM"), videoNorm); cmd.Replace(_T("$FRAMES"), wxString::Format(_T("%d"), (int)(slideshow->GetDuration()*slideshow->GetFPS()))); cmd.Replace(_T("$BITRATE"), wxString::Format(_T("%d"), s_config.GetSlideshowVideoBitrate())); cmd.Replace(_T("$FILE_IN"), jpgFile); cmd.Replace(_T("$FILE_OUT"), i == 0 ? m2vFile : m2vTmpFile); long ret = Exec(cmd); if (!ret) { FailedExec(cmd); return false; } if (s_config.GetRemoveTempFiles()) if (!DeleteFile(jpgFile)) return false; if (i>0) { wxFile src(m2vTmpFile, wxFile::read); wxFile dst(m2vFile, wxFile::write_append); char buf[4096]; while (!src.Eof()) { int count = src.Read(buf, 4096); dst.Write(buf, count); } src.Close(); if (!DeleteFile(m2vTmpFile)) return false; } IncSubStep(20); } // create silence mp2 AddDetailMsg(_("Create silence audio file")); wxString cmd = s_config.GetSilenceCmd(); cmd.Replace(_T("$DURATION"), wxString::Format(_T("%d"), slideshow->GetDuration()*slideshow->Count())); cmd.Replace(_T("$FILE_IN"), silenceFile); cmd.Replace(_T("$FILE_OUT"), mp2File); long ret = Exec(cmd); if (!ret) { FailedExec(cmd); return false; } IncSubStep(slideshow->Count()); if (IsCanceled()) return false; AddDetailMsg(_("Multiplexing audio and video")); cmd = s_config.GetMplexCmd(); cmd.Replace(_T("$FILE_VIDEO"), m2vFile); cmd.Replace(_T("$FILE_AUDIO"), mp2File); cmd.Replace(_T("$FILE_OUT"), vobFile); if (!Exec(cmd)) { FailedExec(cmd); return false; } if (s_config.GetRemoveTempFiles() && !DeleteFile(m2vFile) || !DeleteFile(mp2File)) return false; IncSubStep(2*slideshow->Count()); wxYield(); return true; } bool ProgressDlg::MultiplexSubtitles(const wxString& vobFile, TextSub* textSub, const wxString& resultFile) { if (IsCanceled()) return false; //spumux wxString cmd = s_config.GetSpumuxCmd(); wxString spuFile = resultFile + wxT("_spumux.xml"); textSub->SaveSpumux(spuFile); cmd.Replace(_T("$FILE_CONF"), spuFile); if (!Exec(cmd, vobFile, resultFile)) { FailedExec(cmd); return false; } if (s_config.GetRemoveTempFiles()) { if (vobFile == resultFile + _T(".old") && !DeleteFile(vobFile)) return false; if (!DeleteFile(spuFile)) return false; } wxYield(); return true; } bool ProgressDlg::DeleteFile(wxString fname) { if (!wxRemoveFile(fname)) { Failed(wxString::Format(_("Can't remove file '%s'"), fname.c_str())); return false; } return true; } bool ProgressDlg::DeleteDir(wxString dir, bool subdirs) { if (dir.Last() != wxFILE_SEP_PATH) dir += wxFILE_SEP_PATH; wxDir d(dir); wxString fname; while (subdirs && d.GetFirst(&fname, wxEmptyString, wxDIR_DIRS)) if (!DeleteDir(dir + fname, true)) return false; while (d.GetFirst(&fname, wxEmptyString, wxDIR_FILES | wxDIR_HIDDEN)) if (!DeleteFile(dir + fname)) return false; d.Open(wxGetHomeDir()); wxLogNull log; wxRmdir(dir); return true; } bool ProgressDlg::DeleteTempDir(wxString dir) { if (dir.Last() != wxFILE_SEP_PATH) dir += wxFILE_SEP_PATH; wxDir d(dir + wxT("dvd")); wxString fname; d.GetFirst(&fname, wxEmptyString, wxDIR_DIRS); while (1) { if (fname.Lower() == _T("video_ts") || fname.Lower() == _T("audio_ts")) if (!DeleteDir(dir + wxT("dvd") + wxFILE_SEP_PATH + fname, false)) return false; if (!d.GetNext(&fname)) break; } d.GetFirst(&fname, wxEmptyString, wxDIR_FILES | wxDIR_HIDDEN); while(1) { if (fname.Mid(0,4).Lower() == _T("menu") || fname.Mid(0,5).Lower() == _T("title")) if (!DeleteFile(dir + wxT("dvd") + wxFILE_SEP_PATH + fname)) return false; if (!d.GetNext(&fname)) break; } if (wxFileName(dir + wxT("dvd.iso")).FileExists() && DeleteFile(dir + wxT("dvd.iso"))) return false; d.Open(wxGetHomeDir()); wxLogNull log; wxRmdir(dir + wxT("dvd")); wxRmdir(dir); return true; } bool ProgressDlg::Exec(wxString command, wxString inputFile, wxString outputFile) { ProcessExecute exec(this); return exec.Execute(command, inputFile, outputFile); }