diff --git a/aegisub/Makefile.am b/aegisub/Makefile.am index 88d4b39ff..8950de531 100644 --- a/aegisub/Makefile.am +++ b/aegisub/Makefile.am @@ -156,6 +156,7 @@ aegisub_SOURCES = \ dialog_tip.cpp \ dialog_translation.cpp \ dialog_version_check.cpp \ + dialog_video_details.cpp \ drop.cpp \ export_clean_info.cpp \ export_fixstyle.cpp \ diff --git a/aegisub/changelog.txt b/aegisub/changelog.txt index 16d9ac7bc..cfad6d568 100644 --- a/aegisub/changelog.txt +++ b/aegisub/changelog.txt @@ -159,6 +159,7 @@ Please visit http://aegisub.net to download latest version - Joining of two lines will no longer take the timings of any line that starts and ends at 0 into consideration. (AMZ) - Added a "new window" command to the file menu, to launch a new instance of Aegisub. (AMZ) - Added "Effect" field to the Select Lines dialog. (demi`) +- Added a new "Video Details" dialog, that lists some information regarding the currently open video. (demi`) = 1.10 beta - 2006.08.07 =========================== diff --git a/aegisub/dialog_video_details.cpp b/aegisub/dialog_video_details.cpp new file mode 100644 index 000000000..2410eefc5 --- /dev/null +++ b/aegisub/dialog_video_details.cpp @@ -0,0 +1,130 @@ +// Copyright (c) 2007, Alysson Souza e Silva (demi_alucard) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Aegisub Group nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 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. +// +// ----------------------------------------------------------------------------- +// +// AEGISUB +// +// Website: http://aegisub.cellosoft.com +// Contact: mailto:zeratul@cellosoft.com +// + + +/////////// +// Headers +#include "dialog_video_details.h" +#include "video_context.h" +#include "video_provider.h" +#include "audio_provider.h" +#include "audio_box.h" +#include "utils.h" + + +/////////////// +// Constructor +DialogVideoDetails::DialogVideoDetails(wxWindow *parent) +: wxDialog(parent , -1, _("Video Details"),wxDefaultPosition,wxDefaultSize) +{ + // Main controls + wxFlexGridSizer *fg = new wxFlexGridSizer(2, 5, 10); + wxBoxSizer *main_sizer = new wxBoxSizer(wxVERTICAL); + wxStaticBoxSizer *video_sizer = new wxStaticBoxSizer(wxVERTICAL,this,_("Video")); + VideoProvider *vprovider = VideoContext::Get()->GetProvider(); + + int width = vprovider->GetWidth(); + int height = vprovider->GetHeight(); + int framecount = vprovider->GetFrameCount(); + double fps = vprovider->GetFPS(); + + wxTextCtrl *fname_text = new wxTextCtrl(this, -1, VideoContext::Get()->videoName, wxDefaultPosition, wxSize(300,-1), wxTE_READONLY); + wxTextCtrl *fps_text = new wxTextCtrl(this, -1, wxString::Format(_T("%.3f"), fps), wxDefaultPosition, wxDefaultSize, wxTE_READONLY); + wxTextCtrl *resolution_text = new wxTextCtrl(this, -1, wxString::Format(_T("%dx%d (%s)"), width, height, PrettyAR(width, height)), wxDefaultPosition, wxDefaultSize, wxTE_READONLY); + wxTextCtrl *length_text = new wxTextCtrl(this, -1, wxString::Format(_T("%d frames (%s)"), framecount, PrettyTimeStamp(framecount, fps)), wxDefaultPosition, wxDefaultSize, wxTE_READONLY); + wxTextCtrl *decoder_text = new wxTextCtrl(this, -1, vprovider->GetDecoderName(), wxDefaultPosition, wxDefaultSize, wxTE_READONLY); + + fg->Add(new wxStaticText(this, -1, _("File name:")), 0, wxALIGN_CENTRE_VERTICAL | wxEXPAND); + fg->Add(fname_text, 0, wxALIGN_CENTRE_VERTICAL | wxEXPAND); + fg->Add(new wxStaticText(this, -1, _("FPS:")), 0, wxALIGN_CENTRE_VERTICAL | wxEXPAND); + fg->Add(fps_text, 0, wxALIGN_CENTRE_VERTICAL | wxEXPAND); + fg->Add(new wxStaticText(this, -1, _("Resolution:")), 0, wxALIGN_CENTRE_VERTICAL | wxEXPAND); + fg->Add(resolution_text, 0, wxALIGN_CENTRE_VERTICAL | wxEXPAND); + fg->Add(new wxStaticText(this, -1, _("Length:")), 0, wxALIGN_CENTRE_VERTICAL | wxEXPAND); + fg->Add(length_text, 0, wxALIGN_CENTRE_VERTICAL | wxEXPAND); + fg->Add(new wxStaticText(this, -1, _("Decoder:")), 0, wxALIGN_CENTRE_VERTICAL | wxEXPAND); + fg->Add(decoder_text, 0, wxALIGN_CENTRE_VERTICAL | wxEXPAND); + + video_sizer->Add(fg); + + main_sizer->Add(video_sizer, 1, wxALL|wxEXPAND, 5); + main_sizer->Add(CreateSeparatedButtonSizer(wxOK), 0, wxALL|wxEXPAND, 5); + main_sizer->SetSizeHints(this); + SetSizer(main_sizer); + + CenterOnParent(); +} + + +//////////// +// PrettyAR +wxString DialogVideoDetails::PrettyAR(int width, int height) +{ + int limit = (int)ceil(sqrt(double(MIN(width, height)))); + for (int i=2;i<=limit;i++) { + while (width % i == 0 && height % i == 0) { + width /= i; + height /= i; + } + } + return wxString::Format(_T("%d:%d"), width, height); +} + + +/////////////////// +// PrettyTimeStamp +wxString DialogVideoDetails::PrettyTimeStamp(int frames, double fps) +{ + int tt = int(frames / fps * 1000); + int cs = tt % 1000; tt /= 1000; + int s = tt % 60; tt /= 60; + int m = tt % 60; tt /= 60; + int h = tt; + return wxString::Format(_T("%d:%02d:%02d.%03d"), h, m, s, cs); +} + + +////////////// +// Destructor +DialogVideoDetails::~DialogVideoDetails() +{ +} + + +/////////////// +// Event table +BEGIN_EVENT_TABLE(DialogVideoDetails,wxDialog) + +END_EVENT_TABLE() diff --git a/aegisub/dialog_video_details.h b/aegisub/dialog_video_details.h new file mode 100644 index 000000000..42b09732d --- /dev/null +++ b/aegisub/dialog_video_details.h @@ -0,0 +1,58 @@ +// Copyright (c) 2007, Alysson Souza e Silva (demi_alucard) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Aegisub Group nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 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. +// +// ----------------------------------------------------------------------------- +// +// AEGISUB +// +// Website: http://aegisub.cellosoft.com +// Contact: mailto:zeratul@cellosoft.com +// + +#ifndef _DIALOG_VIDEO_DETAILS_H +#define _DIALOG_VIDEO_DETAILS_H + +/////////// +// Headers +#include + +class DialogVideoDetails : public wxDialog { +private: + wxString PrettyTimeStamp(int frames, double fps); + wxString PrettyAR(int width, int height); + + int width, height; + int framecount, fps; + +public: + DialogVideoDetails(wxWindow *parent); + virtual ~DialogVideoDetails(); + + DECLARE_EVENT_TABLE() +}; + +#endif diff --git a/aegisub/frame_main.cpp b/aegisub/frame_main.cpp index d2c755607..a7f01d9e1 100644 --- a/aegisub/frame_main.cpp +++ b/aegisub/frame_main.cpp @@ -367,6 +367,7 @@ void FrameMain::InitMenu() { wxMenuItem *RecentVidParent = new wxMenuItem(videoMenu, Menu_File_Recent_Vids_Parent, _("Recent"), _T(""), wxITEM_NORMAL, RecentVids); videoMenu->Append(RecentVidParent); videoMenu->Append(Menu_Video_Dummy, _("Use dummy video..."), _("Opens a video clip with solid colour")); + videoMenu->Append(Menu_Video_Details, _("Show video details..."), _("Shows video details")); videoMenu->AppendSeparator(); videoMenu->Append(Menu_File_Open_VFR, _("Open timecodes file..."), _("Opens a VFR timecodes v1 or v2 file")); videoMenu->Append(Menu_File_Close_VFR, _("Close timecodes file"), _("Closes the currently open timecodes file"))->Enable(false); diff --git a/aegisub/frame_main.h b/aegisub/frame_main.h index 656da4cb4..2aa443c0f 100644 --- a/aegisub/frame_main.h +++ b/aegisub/frame_main.h @@ -211,6 +211,8 @@ private: void OnOpenResample (wxCommandEvent &event); void OnOpenTimingProcessor (wxCommandEvent &event); void OnOpenKanjiTimer (wxCommandEvent &event); + void OnOpenVideoDetails (wxCommandEvent &event); + void OnOpenOptions (wxCommandEvent &event); void OnOpenLog (wxCommandEvent &event); void OnGridEvent (wxCommandEvent &event); @@ -331,6 +333,7 @@ enum { Menu_Video_Detach, Menu_Video_Dummy, Menu_Video_Overscan, + Menu_Video_Details, Menu_Audio_Open_File, Menu_Audio_Open_From_Video, diff --git a/aegisub/frame_main_events.cpp b/aegisub/frame_main_events.cpp index af1d6c4a9..edd79e176 100644 --- a/aegisub/frame_main_events.cpp +++ b/aegisub/frame_main_events.cpp @@ -83,6 +83,7 @@ #include "dialog_spellchecker.h" #include "dialog_associations.h" #include "standard_paths.h" +#include "dialog_video_details.h" //////////////////// @@ -138,6 +139,7 @@ BEGIN_EVENT_TABLE(FrameMain, wxFrame) EVT_MENU(Menu_Video_Detach, FrameMain::OnDetachVideo) EVT_MENU(Menu_Video_Dummy, FrameMain::OnDummyVideo) EVT_MENU(Menu_Video_Overscan, FrameMain::OnOverscan) + EVT_MENU(Menu_Video_Details, FrameMain::OnOpenVideoDetails) EVT_MENU(Menu_Audio_Open_File, FrameMain::OnOpenAudio) EVT_MENU(Menu_Audio_Open_From_Video, FrameMain::OnOpenAudioFromVideo) @@ -311,6 +313,8 @@ void FrameMain::OnMenuOpen (wxMenuEvent &event) { MenuBar->Enable(Menu_File_Close_VFR,VFR_Output.GetFrameRateType() == VFR); MenuBar->Enable(Menu_Video_Close_Keyframes,VideoContext::Get()->OverKeyFramesLoaded()); MenuBar->Enable(Menu_Video_Save_Keyframes,VideoContext::Get()->KeyFramesLoaded()); + MenuBar->Enable(Menu_Video_Details,state); + MenuBar->Enable(Menu_Video_Overscan,state); // Set AR radio int arType = VideoContext::Get()->GetAspectRatioType(); @@ -854,6 +858,15 @@ void FrameMain::OnOverscan (wxCommandEvent &event) { } +////////////////////// +// Show video details +void FrameMain::OnOpenVideoDetails (wxCommandEvent &event) { + VideoContext::Get()->Stop(); + DialogVideoDetails videodetails(this); + videodetails.ShowModal(); +} + + /////////////////////// // Open jump to dialog void FrameMain::OnJumpTo(wxCommandEvent& WXUNUSED(event)) { diff --git a/aegisub/video_provider_avs.cpp b/aegisub/video_provider_avs.cpp index 5ec317c63..dc366cc4e 100644 --- a/aegisub/video_provider_avs.cpp +++ b/aegisub/video_provider_avs.cpp @@ -61,6 +61,7 @@ private: bool usedDirectShow; wxString rendererCallString; + wxString decoderName; int num_frames; int last_fnum; @@ -100,6 +101,7 @@ public: void OverrideFrameTimeList(wxArrayInt list); bool IsNativelyByFrames() { return byFrame; } wxString GetWarning(); + wxString GetDecoderName() { return _T("Avisynth/") + decoderName; } }; @@ -167,6 +169,7 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori byFrame = false; usedDirectShow = false; + decoderName = _("Unknown"); wxString extension = _filename.Right(4); extension.LowerCase(); @@ -193,6 +196,7 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori script = env->Invoke("AviSource", AVSValue(args,2), argnames); AVSTRACE(_T("AvisynthVideoProvider::OpenVideo: Successfully opened .avi file without audio")); byFrame = true; + decoderName = _T("AviSource"); } // On Failure, fallback to DSS @@ -206,6 +210,7 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori else if (extension == _T(".d2v") && env->FunctionExists("Mpeg2Dec3_Mpeg2Source") && mpeg2dec3_priority) { AVSTRACE(_T("AvisynthVideoProvider::OpenVideo: Opening .d2v file with Mpeg2Dec3_Mpeg2Source")); script = env->Invoke("Mpeg2Dec3_Mpeg2Source", videoFilename); + decoderName = _T("Mpeg2Dec3_Mpeg2Source"); //if avisynth is 2.5.7 beta 2 or newer old mpeg2decs will crash without this if (env->FunctionExists("SetPlanarLegacyAlignment")) { @@ -218,6 +223,7 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori else if (extension == _T(".d2v") && env->FunctionExists("DGDecode_Mpeg2Source")) { AVSTRACE(_T("AvisynthVideoProvider::OpenVideo: Opening .d2v file with DGDecode_Mpeg2Source")); script = env->Invoke("Mpeg2Source", videoFilename); + decoderName = _T("DGDecode_Mpeg2Source"); //note that DGDecode will also have issues like if the version is too ancient but no sane person //would use that anyway @@ -226,6 +232,7 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori else if (extension == _T(".d2v") && env->FunctionExists("Mpeg2Source")) { AVSTRACE(_T("AvisynthVideoProvider::OpenVideo: Opening .d2v file with other Mpeg2Source")); script = env->Invoke("Mpeg2Source", videoFilename); + decoderName = _T("Mpeg2Source"); //if avisynth is 2.5.7 beta 2 or newer old mpeg2decs will crash without this if (env->FunctionExists("SetPlanarLegacyAlignment")) @@ -235,7 +242,6 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori // Some other format, such as mkv, mp4, ogm... try FFMpegSource and DirectShowSource else { // Try loading FFMpegSource - directshowOpen: bool ffsource = false; if (env->FunctionExists("ffmpegsource")) ffsource = true; if (!ffsource) { @@ -255,7 +261,9 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori script = env->Invoke("ffmpegsource", videoFilename); AVSTRACE(_T("AvisynthVideoProvider::OpenVideo: Successfully opened file with FFMpegSource")); ffsource = true; + decoderName = _T("FFmpegSource"); } + directshowOpen: // DirectShowSource if (!ffsource) { @@ -285,6 +293,7 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori } AVSTRACE(_T("AvisynthVideoProvider::OpenVideo: Successfully opened file with DSS2")); dss2 = true; + decoderName = _T("DSS2"); } // Try DirectShowSource @@ -302,6 +311,7 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori } AVSTRACE(_T("AvisynthVideoProvider::OpenVideo: Successfully opened file with DSS without audio")); usedDirectShow = true; + decoderName = _T("DirectShowSource"); } // Failed to find a suitable function diff --git a/aegisub/video_provider_dshow.cpp b/aegisub/video_provider_dshow.cpp index 1fc7a7edc..2be69d6fc 100644 --- a/aegisub/video_provider_dshow.cpp +++ b/aegisub/video_provider_dshow.cpp @@ -121,6 +121,7 @@ public: double GetFPS() { return fps; }; int GetWidth() { return width; }; int GetHeight() { return height; }; + wxString GetDecoderName() { return _("DirectShow"); } void OverrideFrameTimeList(wxArrayInt list); }; diff --git a/aegisub/video_provider_dummy.cpp b/aegisub/video_provider_dummy.cpp index c681b1f6d..8274bfdf9 100644 --- a/aegisub/video_provider_dummy.cpp +++ b/aegisub/video_provider_dummy.cpp @@ -242,3 +242,11 @@ int DummyVideoProvider::GetHeight() { double DummyVideoProvider::GetFPS() { return fps; } + + +//////////////////// +// Get decoder name +wxString DummyVideoProvider::GetDecoderName() { + return _("Dummy Video Provider"); +} + diff --git a/aegisub/video_provider_dummy.h b/aegisub/video_provider_dummy.h index 6ac136898..aaff8c3fb 100644 --- a/aegisub/video_provider_dummy.h +++ b/aegisub/video_provider_dummy.h @@ -74,6 +74,7 @@ public: int GetWidth(); int GetHeight(); double GetFPS(); + wxString GetDecoderName(); }; #endif diff --git a/aegisub/video_provider_lavc.cpp b/aegisub/video_provider_lavc.cpp index 5a5bcec45..2e7cfb55c 100644 --- a/aegisub/video_provider_lavc.cpp +++ b/aegisub/video_provider_lavc.cpp @@ -112,6 +112,7 @@ public: int GetWidth(); int GetHeight(); double GetFPS(); + wxString GetDecoderName() { return _T("FFMpeg/libavcodec")); } bool IsNativelyByFrames() { return true; } };