mirror of https://github.com/odrling/Aegisub
Rewrite VFR handling in Aegisub.
Kill vfr.h and vfr.cpp and use the libaegisub versions of them instead. Rather than the globals VFR_Input and VFR_Output, everything related to frame rate is now part of the video context. Most things which used to use VFR_Output now call VideoContext::TimeAtFrame etc.; video providers, rather than modifying VFR_Input directly, now have getters for their frame rates which VideoContext calls. Read-only public access to VFR_Input and VFR_Output are still provided (hopefully temporarily) for a few things which were awkward to do through VideoContext. The Avisynth provider now might correctly handle VFR MKVs which can be opened with DirectShowSource but not DSS2. Rework keyframe handling as well, so that it continues to match the vfr handling in design and implementation. Originally committed to SVN as r4662.
This commit is contained in:
parent
9322f95071
commit
acba2c6b63
|
@ -1011,14 +1011,6 @@
|
|||
RelativePath="..\..\src\vector2d.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\vfr.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\vfr.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Dialogs"
|
||||
|
|
|
@ -181,7 +181,7 @@ Framerate::Framerate(std::vector<int> const& timecodes)
|
|||
: timecodes(timecodes)
|
||||
{
|
||||
validate_timecodes(timecodes);
|
||||
fps = timecodes.size() / (timecodes.back() / 1000.);
|
||||
fps = (timecodes.size() - 1) * 1000. / (timecodes.back() - timecodes.front());
|
||||
last = timecodes.back();
|
||||
}
|
||||
|
||||
|
@ -202,10 +202,6 @@ Framerate &Framerate::operator=(double fps) {
|
|||
return *this = Framerate(fps);
|
||||
}
|
||||
|
||||
bool Framerate::operator==(Framerate const& right) const {
|
||||
return fps == right.fps && timecodes == right.timecodes;
|
||||
}
|
||||
|
||||
Framerate::Framerate(std::string const& filename) : fps(0.) {
|
||||
using namespace std;
|
||||
auto_ptr<ifstream> file(agi::io::Open(filename));
|
||||
|
@ -214,7 +210,8 @@ Framerate::Framerate(std::string const& filename) : fps(0.) {
|
|||
if (line == "# timecode format v2") {
|
||||
copy(line_iterator<int>(*file, encoding), line_iterator<int>(), back_inserter(timecodes));
|
||||
validate_timecodes(timecodes);
|
||||
fps = timecodes.size() / (timecodes.back() / 1000.);
|
||||
fps = (timecodes.size() - 1) * 1000. / (timecodes.back() - timecodes.front());
|
||||
last = timecodes.back();
|
||||
return;
|
||||
}
|
||||
if (line == "# timecode format v1" || line.substr(0, 7) == "Assume ") {
|
||||
|
|
|
@ -132,10 +132,6 @@ public:
|
|||
bool IsVFR() const {return !timecodes.empty(); }
|
||||
bool IsLoaded() const { return !timecodes.empty() || fps; };
|
||||
double FPS() const { return fps; }
|
||||
|
||||
/// @brief Equality operator
|
||||
/// @attention O(n) when both arguments are VFR
|
||||
bool operator==(Framerate const& right) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -302,7 +302,6 @@ aegisub_2_2_SOURCES = \
|
|||
variable_data.cpp \
|
||||
vector2d.cpp \
|
||||
version.cpp \
|
||||
vfr.cpp \
|
||||
video_box.cpp \
|
||||
video_context.cpp \
|
||||
video_display.cpp \
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
#include "ass_dialogue.h"
|
||||
#include "ass_override.h"
|
||||
#include "utils.h"
|
||||
#include "vfr.h"
|
||||
|
||||
AssDialogue::AssDialogue()
|
||||
: Comment(false)
|
||||
|
|
|
@ -60,7 +60,6 @@
|
|||
#include "text_file_writer.h"
|
||||
#include "utils.h"
|
||||
#include "version.h"
|
||||
#include "vfr.h"
|
||||
|
||||
/// @brief AssFile constructor
|
||||
AssFile::AssFile () {
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
|
||||
#include "ass_time.h"
|
||||
#include "utils.h"
|
||||
#include "vfr.h"
|
||||
|
||||
|
||||
/// @brief AssTime constructors
|
||||
|
|
|
@ -65,7 +65,6 @@
|
|||
#include "subs_grid.h"
|
||||
#include "timeedit_ctrl.h"
|
||||
#include "utils.h"
|
||||
#include "vfr.h"
|
||||
#include "video_context.h"
|
||||
|
||||
#ifdef __WXMAC__
|
||||
|
@ -295,7 +294,7 @@ void AudioDisplay::DoUpdateImage() {
|
|||
if (OPT_GET("Audio/Display/Draw/Video Position")->GetBool()) {
|
||||
if (VideoContext::Get()->IsLoaded()) {
|
||||
dc.SetPen(wxPen(lagi_wxColour(OPT_GET("Colour/Audio Display/Play Cursor")->GetColour())));
|
||||
int x = GetXAtMS(VFR_Output.GetTimeAtFrame(VideoContext::Get()->GetFrameN()));
|
||||
int x = GetXAtMS(VideoContext::Get()->TimeAtFrame(VideoContext::Get()->GetFrameN()));
|
||||
dc.DrawLine(x,0,x,h);
|
||||
}
|
||||
}
|
||||
|
@ -477,19 +476,19 @@ void AudioDisplay::DrawInactiveLines(wxDC &dc) {
|
|||
/// @brief Draw keyframe markers
|
||||
/// @param dc The DC to draw to.
|
||||
void AudioDisplay::DrawKeyframes(wxDC &dc) {
|
||||
wxArrayInt KeyFrames = VideoContext::Get()->GetKeyFrames();
|
||||
int nKeys = (int)KeyFrames.Count();
|
||||
std::vector<int> KeyFrames = VideoContext::Get()->GetKeyFrames();
|
||||
int nKeys = (int)KeyFrames.size();
|
||||
dc.SetPen(wxPen(wxColour(255,0,255),1));
|
||||
|
||||
// Get min and max frames to care about
|
||||
int minFrame = VFR_Output.GetFrameAtTime(GetMSAtX(0),true);
|
||||
int maxFrame = VFR_Output.GetFrameAtTime(GetMSAtX(w),true);
|
||||
int minFrame = VideoContext::Get()->FrameAtTime(GetMSAtX(0),agi::vfr::START);
|
||||
int maxFrame = VideoContext::Get()->FrameAtTime(GetMSAtX(w),agi::vfr::END);
|
||||
|
||||
// Scan list
|
||||
for (int i=0;i<nKeys;i++) {
|
||||
int cur = KeyFrames[i];
|
||||
if (cur >= minFrame && cur <= maxFrame) {
|
||||
int x = GetXAtMS(VFR_Output.GetTimeAtFrame(cur,true));
|
||||
int x = GetXAtMS(VideoContext::Get()->TimeAtFrame(cur,agi::vfr::START));
|
||||
dc.DrawLine(x,0,x,h);
|
||||
}
|
||||
else if (cur > maxFrame) break;
|
||||
|
@ -1469,7 +1468,7 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event) {
|
|||
if (middleClick) {
|
||||
SetFocus();
|
||||
if (VideoContext::Get()->IsLoaded()) {
|
||||
VideoContext::Get()->JumpToTime(GetMSAtX(x),true);
|
||||
VideoContext::Get()->JumpToTime(GetMSAtX(x));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1719,13 +1718,13 @@ int AudioDisplay::GetBoundarySnap(int ms,int rangeX,bool shiftHeld,bool start) {
|
|||
if (shiftHeld) snapKey = !snapKey;
|
||||
if (snapKey && VideoContext::Get()->KeyFramesLoaded() && OPT_GET("Audio/Display/Draw/Keyframes")->GetBool()) {
|
||||
int64_t keyMS;
|
||||
wxArrayInt keyFrames = VideoContext::Get()->GetKeyFrames();
|
||||
std::vector<int> keyFrames = VideoContext::Get()->GetKeyFrames();
|
||||
int frame;
|
||||
for (unsigned int i=0;i<keyFrames.Count();i++) {
|
||||
for (unsigned int i=0;i<keyFrames.size();i++) {
|
||||
frame = keyFrames[i];
|
||||
if (!start) frame--;
|
||||
if (frame < 0) frame = 0;
|
||||
keyMS = VFR_Output.GetTimeAtFrame(frame,start);
|
||||
keyMS = VideoContext::Get()->TimeAtFrame(frame,start ? agi::vfr::START : agi::vfr::END);
|
||||
//if (start) keyX++;
|
||||
if (GetXAtMS(keyMS) >= 0 && GetXAtMS(keyMS) < w) boundaries.Add(keyMS);
|
||||
}
|
||||
|
|
|
@ -34,12 +34,8 @@
|
|||
/// @ingroup audio_ui
|
||||
///
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#ifndef AGI_PRE
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -52,9 +48,6 @@
|
|||
#include "audio_provider_manager.h"
|
||||
#include "audio_renderer_spectrum.h"
|
||||
|
||||
|
||||
//////////////
|
||||
// Prototypes
|
||||
class AssDialogue;
|
||||
class StreamAudioProvider;
|
||||
class SubtitlesGrid;
|
||||
|
@ -63,8 +56,6 @@ class AudioKaraoke;
|
|||
class VideoProvider;
|
||||
class FrameMain;
|
||||
|
||||
|
||||
|
||||
/// DOCME
|
||||
/// @class AudioDisplay
|
||||
/// @brief DOCME
|
||||
|
@ -83,11 +74,9 @@ private:
|
|||
/// DOCME
|
||||
AssDialogue *dialogue;
|
||||
|
||||
|
||||
/// DOCME
|
||||
AudioSpectrum *spectrumRenderer;
|
||||
|
||||
|
||||
/// DOCME
|
||||
wxBitmap *origImage;
|
||||
|
||||
|
@ -127,14 +116,12 @@ private:
|
|||
/// DOCME
|
||||
bool playingToEnd;
|
||||
|
||||
|
||||
/// DOCME
|
||||
bool needImageUpdate;
|
||||
|
||||
/// DOCME
|
||||
bool needImageUpdateWeak;
|
||||
|
||||
|
||||
/// DOCME
|
||||
bool hasSel;
|
||||
|
||||
|
@ -186,14 +173,12 @@ private:
|
|||
/// DOCME
|
||||
int holdSyl;
|
||||
|
||||
|
||||
/// DOCME
|
||||
int *peak;
|
||||
|
||||
/// DOCME
|
||||
int *min;
|
||||
|
||||
|
||||
/// DOCME
|
||||
int scrubTime;
|
||||
|
||||
|
@ -239,7 +224,6 @@ public:
|
|||
/// DOCME
|
||||
AudioPlayer *player;
|
||||
|
||||
|
||||
/// DOCME
|
||||
bool NeedCommit;
|
||||
|
||||
|
@ -308,11 +292,8 @@ public:
|
|||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
|
||||
///////
|
||||
// IDs
|
||||
enum {
|
||||
|
||||
/// DOCME
|
||||
Audio_Update_Timer = 1700
|
||||
};
|
||||
|
|
|
@ -64,7 +64,6 @@
|
|||
#include "options.h"
|
||||
#include "standard_paths.h"
|
||||
#include "text_file_reader.h"
|
||||
#include "vfr.h"
|
||||
#include "video_context.h"
|
||||
|
||||
// This must be below the headers above.
|
||||
|
@ -504,8 +503,8 @@ namespace Automation4 {
|
|||
{
|
||||
int ms = (int)lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
if (VFR_Output.IsLoaded()) {
|
||||
lua_pushnumber(L, VFR_Output.GetFrameAtTime(ms, true));
|
||||
if (VideoContext::Get()->TimecodesLoaded()) {
|
||||
lua_pushnumber(L, VideoContext::Get()->FrameAtTime(ms, agi::vfr::START));
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
|
@ -522,8 +521,8 @@ namespace Automation4 {
|
|||
{
|
||||
int frame = (int)lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
if (VFR_Output.IsLoaded()) {
|
||||
lua_pushnumber(L, VFR_Output.GetTimeAtFrame(frame, true));
|
||||
if (VideoContext::Get()->TimecodesLoaded()) {
|
||||
lua_pushnumber(L, VideoContext::Get()->TimeAtFrame(frame, agi::vfr::START));
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#endif
|
||||
|
||||
class wxWindow;
|
||||
namespace agi { namespace vfr { class Framerate; } }
|
||||
|
||||
|
||||
/// DOCME
|
||||
|
|
|
@ -34,9 +34,6 @@
|
|||
/// @ingroup main_ui
|
||||
///
|
||||
|
||||
|
||||
////////////
|
||||
// Includes
|
||||
#include "config.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
|
@ -56,7 +53,6 @@
|
|||
#include "options.h"
|
||||
#include "subs_edit_box.h"
|
||||
#include "utils.h"
|
||||
#include "vfr.h"
|
||||
#include "video_box.h"
|
||||
#include "video_context.h"
|
||||
#include "video_slider.h"
|
||||
|
@ -79,6 +75,7 @@ static inline void set_difference(const S1 &src1, const S2 &src2, D &dst) {
|
|||
///
|
||||
BaseGrid::BaseGrid(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name)
|
||||
: wxWindow(parent, id, pos, size, style, name)
|
||||
, context(VideoContext::Get())
|
||||
{
|
||||
// Misc variables
|
||||
lastRow = -1;
|
||||
|
@ -552,8 +549,8 @@ void BaseGrid::DrawImage(wxDC &dc) {
|
|||
strings.Add(wxString::Format(_T("%i"),curRow+1));
|
||||
strings.Add(wxString::Format(_T("%i"),curDiag->Layer));
|
||||
if (byFrame) {
|
||||
strings.Add(wxString::Format(_T("%i"),VFR_Output.GetFrameAtTime(curDiag->Start.GetMS(),true)));
|
||||
strings.Add(wxString::Format(_T("%i"),VFR_Output.GetFrameAtTime(curDiag->End.GetMS(),false)));
|
||||
strings.Add(wxString::Format(_T("%i"),context->FrameAtTime(curDiag->Start.GetMS(),agi::vfr::START)));
|
||||
strings.Add(wxString::Format(_T("%i"),context->FrameAtTime(curDiag->End.GetMS(),agi::vfr::END)));
|
||||
}
|
||||
else {
|
||||
strings.Add(curDiag->Start.GetASSFormated());
|
||||
|
@ -787,7 +784,7 @@ void BaseGrid::OnMouseEvent(wxMouseEvent &event) {
|
|||
// Normal click
|
||||
if ((click || dclick) && !shift && !ctrl && !alt) {
|
||||
SetActiveLine(dlg);
|
||||
if (dclick) VideoContext::Get()->JumpToTime(dlg->Start.GetMS());
|
||||
if (dclick) context->JumpToTime(dlg->Start.GetMS());
|
||||
SelectRow(row,false);
|
||||
parentFrame->UpdateToolbar();
|
||||
lastRow = row;
|
||||
|
@ -964,9 +961,9 @@ void BaseGrid::SetColumnWidths() {
|
|||
|
||||
// Times
|
||||
if (byFrame) {
|
||||
int tmp = VFR_Output.GetFrameAtTime(curDiag->Start.GetMS(),true);
|
||||
int tmp = context->FrameAtTime(curDiag->Start.GetMS(),agi::vfr::START);
|
||||
if (tmp > maxStart) maxStart = tmp;
|
||||
tmp = VFR_Output.GetFrameAtTime(curDiag->End.GetMS(),true);
|
||||
tmp = context->FrameAtTime(curDiag->End.GetMS(),agi::vfr::END);
|
||||
if (tmp > maxEnd) maxEnd = tmp;
|
||||
}
|
||||
}
|
||||
|
@ -1053,8 +1050,8 @@ int BaseGrid::GetDialogueIndex(AssDialogue *diag) const {
|
|||
bool BaseGrid::IsDisplayed(AssDialogue *line) {
|
||||
VideoContext* con = VideoContext::Get();
|
||||
if (!con->IsLoaded()) return false;
|
||||
int f1 = VFR_Output.GetFrameAtTime(line->Start.GetMS(),true);
|
||||
int f2 = VFR_Output.GetFrameAtTime(line->End.GetMS(),false);
|
||||
int f1 = con->FrameAtTime(line->Start.GetMS(),agi::vfr::START);
|
||||
int f2 = con->FrameAtTime(line->End.GetMS(),agi::vfr::END);
|
||||
if (f1 <= con->GetFrameN() && f2 >= con->GetFrameN()) return true;
|
||||
return false;
|
||||
}
|
||||
|
@ -1106,7 +1103,7 @@ void BaseGrid::OnKeyPress(wxKeyEvent &event) {
|
|||
|
||||
// Left/right, forward to seek bar if video is loaded
|
||||
if (key == WXK_LEFT || key == WXK_RIGHT) {
|
||||
if (VideoContext::Get()->IsLoaded()) {
|
||||
if (context->IsLoaded()) {
|
||||
parentFrame->videoBox->videoSlider->SetFocus();
|
||||
parentFrame->videoBox->videoSlider->GetEventHandler()->ProcessEvent(event);
|
||||
return;
|
||||
|
@ -1197,8 +1194,8 @@ void BaseGrid::OnKeyPress(wxKeyEvent &event) {
|
|||
}
|
||||
|
||||
// Other events, send to audio display
|
||||
if (VideoContext::Get()->audio->loaded) {
|
||||
VideoContext::Get()->audio->GetEventHandler()->ProcessEvent(event);
|
||||
if (context->audio->loaded) {
|
||||
context->audio->GetEventHandler()->ProcessEvent(event);
|
||||
}
|
||||
else event.Skip();
|
||||
}
|
||||
|
|
|
@ -37,8 +37,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
////////////
|
||||
// Includes
|
||||
#ifndef AGI_PRE
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
@ -49,13 +47,11 @@
|
|||
|
||||
#include "selection_controller.h"
|
||||
|
||||
|
||||
//////////////
|
||||
// Prototypes
|
||||
class AssEntry;
|
||||
class AssDialogue;
|
||||
class SubsEditBox;
|
||||
class FrameMain;
|
||||
class VideoContext;
|
||||
|
||||
/// DOCME
|
||||
typedef std::list<AssEntry*>::iterator entryIter;
|
||||
|
@ -71,8 +67,6 @@ typedef SelectionListener<AssDialogue> SubtitleSelectionListener;
|
|||
///
|
||||
/// DOCME
|
||||
class BaseGrid : public wxWindow, public BaseSelectionController<AssDialogue> {
|
||||
private:
|
||||
|
||||
/// DOCME
|
||||
int lineHeight;
|
||||
|
||||
|
@ -120,11 +114,12 @@ protected:
|
|||
/// DOCME
|
||||
FrameMain *parentFrame;
|
||||
|
||||
VideoContext *context;
|
||||
|
||||
/// DOCME
|
||||
static const int columns = 10;
|
||||
bool showCol[columns];
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @param alternate
|
||||
///
|
||||
|
|
|
@ -34,9 +34,6 @@
|
|||
/// @ingroup secondary_ui
|
||||
///
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#include "config.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
|
@ -50,36 +47,26 @@
|
|||
#include "dialog_jumpto.h"
|
||||
#include "libresrc/libresrc.h"
|
||||
#include "utils.h"
|
||||
#include "vfr.h"
|
||||
#include "video_context.h"
|
||||
|
||||
|
||||
///////
|
||||
// IDs
|
||||
/// Event IDs
|
||||
enum {
|
||||
|
||||
/// DOCME
|
||||
TEXT_JUMP_TIME = 1100,
|
||||
|
||||
/// DOCME
|
||||
TEXT_JUMP_FRAME
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// @brief Constructor
|
||||
/// @param parent
|
||||
///
|
||||
DialogJumpTo::DialogJumpTo (wxWindow *parent)
|
||||
: wxDialog(parent, -1, _("Jump to"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxWANTS_CHARS , _T("JumpTo"))
|
||||
{
|
||||
// Set icon
|
||||
SetIcon(BitmapToIcon(GETIMAGE(jumpto_button_24)));
|
||||
|
||||
// Set initial values
|
||||
ready = false;
|
||||
jumpframe = VideoContext::Get()->GetFrameN();
|
||||
jumptime.SetMS(VFR_Output.GetTimeAtFrame(jumpframe,true,true));
|
||||
jumptime.SetMS(VideoContext::Get()->TimeAtFrame(jumpframe));
|
||||
wxString maxLength = wxString::Format(_T("%i"),VideoContext::Get()->GetLength()-1);
|
||||
|
||||
// Times
|
||||
|
@ -117,9 +104,6 @@ DialogJumpTo::DialogJumpTo (wxWindow *parent)
|
|||
ready = true;
|
||||
}
|
||||
|
||||
|
||||
///////////////
|
||||
// Event table
|
||||
BEGIN_EVENT_TABLE(DialogJumpTo, wxDialog)
|
||||
EVT_TEXT_ENTER(TEXT_JUMP_FRAME,DialogJumpTo::OnKey)
|
||||
EVT_TEXT_ENTER(TEXT_JUMP_TIME,DialogJumpTo::OnKey)
|
||||
|
@ -129,42 +113,24 @@ BEGIN_EVENT_TABLE(DialogJumpTo, wxDialog)
|
|||
EVT_TEXT(TEXT_JUMP_FRAME, DialogJumpTo::OnEditFrame)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
|
||||
|
||||
/// @brief Close
|
||||
/// @param event
|
||||
///
|
||||
void DialogJumpTo::OnCloseButton (wxCommandEvent &event) { OnClose(false); }
|
||||
|
||||
/// @brief DOCME
|
||||
/// @param event
|
||||
///
|
||||
void DialogJumpTo::OnOK (wxCommandEvent &event) { OnClose(true); }
|
||||
|
||||
|
||||
void DialogJumpTo::OnCloseButton (wxCommandEvent &) { OnClose(false); }
|
||||
void DialogJumpTo::OnOK (wxCommandEvent &) { OnClose(true); }
|
||||
|
||||
/// @brief On Key pressed
|
||||
/// @param event
|
||||
///
|
||||
void DialogJumpTo::OnKey(wxCommandEvent &event) {
|
||||
void DialogJumpTo::OnKey(wxCommandEvent &) {
|
||||
EndModal(0);
|
||||
if (jumpframe > VideoContext::Get()->GetLength()-1) jumpframe = VideoContext::Get()->GetLength()-1;
|
||||
VideoContext::Get()->JumpToFrame(jumpframe);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief On OK button pressed
|
||||
/// @param ok
|
||||
///
|
||||
void DialogJumpTo::OnClose(bool ok) {
|
||||
EndModal(0);
|
||||
if (jumpframe > VideoContext::Get()->GetLength()-1) jumpframe = VideoContext::Get()->GetLength()-1;
|
||||
if (ok) VideoContext::Get()->JumpToFrame(jumpframe);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Time editbox changed
|
||||
/// @param event
|
||||
///
|
||||
|
@ -173,10 +139,10 @@ void DialogJumpTo::OnEditTime (wxCommandEvent &event) {
|
|||
ready = false;
|
||||
|
||||
// Update frame
|
||||
long newframe = VFR_Output.GetFrameAtTime(JumpTime->time.GetMS());
|
||||
long newframe = VideoContext::Get()->FrameAtTime(JumpTime->time.GetMS());
|
||||
if (jumpframe != newframe) {
|
||||
jumpframe = newframe;
|
||||
JumpFrame->SetValue(wxString::Format(_T("%i"),jumpframe));
|
||||
JumpFrame->ChangeValue(wxString::Format(_T("%i"),jumpframe));
|
||||
}
|
||||
|
||||
ready = true;
|
||||
|
@ -184,8 +150,6 @@ void DialogJumpTo::OnEditTime (wxCommandEvent &event) {
|
|||
else event.Skip();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Frame editbox changed
|
||||
/// @param event
|
||||
///
|
||||
|
@ -199,7 +163,7 @@ void DialogJumpTo::OnEditFrame (wxCommandEvent &event) {
|
|||
JumpFrame->SetValue(wxString::Format(_T("%i"),jumpframe));
|
||||
|
||||
// Update time
|
||||
int newtime = VFR_Output.GetTimeAtFrame(jumpframe,true,true);
|
||||
int newtime = VideoContext::Get()->TimeAtFrame(jumpframe);
|
||||
if (jumptime.GetMS() != newtime) {
|
||||
jumptime.SetMS(newtime);
|
||||
JumpTime->ChangeValue(jumptime.GetASSFormated());
|
||||
|
@ -209,5 +173,3 @@ void DialogJumpTo::OnEditFrame (wxCommandEvent &event) {
|
|||
}
|
||||
else event.Skip();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -61,10 +61,9 @@
|
|||
#include "subs_edit_box.h"
|
||||
#include "subs_grid.h"
|
||||
#include "utils.h"
|
||||
#include "vfr.h"
|
||||
#include "video_context.h"
|
||||
#include "video_display.h"
|
||||
|
||||
|
||||
/// @brief Constructor
|
||||
/// @param parent
|
||||
/// @param _grid
|
||||
|
@ -92,7 +91,7 @@ DialogShiftTimes::DialogShiftTimes (wxWindow *parent,SubtitlesGrid *_grid)
|
|||
ShiftTime->SetToolTip(_("Enter time in h:mm:ss.cs notation"));
|
||||
RadioTime->SetToolTip(_("Shift by time"));
|
||||
ShiftFrame->Disable();
|
||||
if (!VFR_Output.IsLoaded()) RadioFrames->Disable();
|
||||
if (!VideoContext::Get()->TimecodesLoaded()) RadioFrames->Disable();
|
||||
else {
|
||||
ShiftFrame->SetToolTip(_("Enter number of frames to shift by"));
|
||||
RadioFrames->SetToolTip(_("Shift by frames"));
|
||||
|
|
|
@ -34,8 +34,6 @@
|
|||
/// @ingroup tools_ui
|
||||
///
|
||||
|
||||
////////////
|
||||
// Includes
|
||||
#include "config.h"
|
||||
|
||||
#include "ass_dialogue.h"
|
||||
|
@ -49,11 +47,20 @@
|
|||
#include "subs_grid.h"
|
||||
#include "utils.h"
|
||||
#include "validators.h"
|
||||
#include "vfr.h"
|
||||
#include "video_box.h"
|
||||
#include "video_context.h"
|
||||
#include "video_display.h"
|
||||
|
||||
/// Window IDs
|
||||
enum {
|
||||
CHECK_ENABLE_LEADIN = 1850,
|
||||
CHECK_ENABLE_LEADOUT,
|
||||
CHECK_ENABLE_KEYFRAME,
|
||||
CHECK_ENABLE_ADJASCENT,
|
||||
BUTTON_SELECT_ALL,
|
||||
BUTTON_SELECT_NONE,
|
||||
TIMING_STYLE_LIST
|
||||
};
|
||||
|
||||
/// @brief Constructor
|
||||
/// @param parent
|
||||
|
@ -62,7 +69,6 @@
|
|||
DialogTimingProcessor::DialogTimingProcessor(wxWindow *parent,SubtitlesGrid *_grid)
|
||||
: wxDialog(parent,-1,_("Timing Post-Processor"),wxDefaultPosition,wxSize(400,250),wxDEFAULT_DIALOG_STYLE)
|
||||
{
|
||||
// Set icon
|
||||
SetIcon(BitmapToIcon(GETIMAGE(timing_processor_toolbutton_24)));
|
||||
|
||||
// Set variables
|
||||
|
@ -75,7 +81,6 @@ DialogTimingProcessor::DialogTimingProcessor(wxWindow *parent,SubtitlesGrid *_gr
|
|||
thresEndAfter = AegiIntegerToString(OPT_GET("Tool/Timing Post Processor/Threshold/Key End After")->GetInt());
|
||||
adjsThresTime = AegiIntegerToString(OPT_GET("Tool/Timing Post Processor/Threshold/Adjacent")->GetInt());
|
||||
|
||||
|
||||
// Styles box
|
||||
wxSizer *LeftSizer = new wxStaticBoxSizer(wxVERTICAL,this,_("Apply to styles"));
|
||||
wxArrayString styles = grid->ass->GetStyles();
|
||||
|
@ -201,12 +206,9 @@ DialogTimingProcessor::DialogTimingProcessor(wxWindow *parent,SubtitlesGrid *_gr
|
|||
|
||||
CenterOnParent();
|
||||
|
||||
// Update
|
||||
UpdateControls();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Update controls
|
||||
///
|
||||
void DialogTimingProcessor::UpdateControls() {
|
||||
|
@ -237,9 +239,6 @@ void DialogTimingProcessor::UpdateControls() {
|
|||
ApplyButton->Enable(checked && (hasLeadIn->IsChecked() | hasLeadOut->IsChecked() | keysEnable->IsChecked() | adjsEnable->IsChecked()));
|
||||
}
|
||||
|
||||
|
||||
///////////////
|
||||
// Event table
|
||||
BEGIN_EVENT_TABLE(DialogTimingProcessor,wxDialog)
|
||||
EVT_CHECKBOX(CHECK_ENABLE_LEADIN,DialogTimingProcessor::OnCheckBox)
|
||||
EVT_CHECKBOX(CHECK_ENABLE_LEADOUT,DialogTimingProcessor::OnCheckBox)
|
||||
|
@ -251,21 +250,11 @@ BEGIN_EVENT_TABLE(DialogTimingProcessor,wxDialog)
|
|||
EVT_BUTTON(BUTTON_SELECT_NONE,DialogTimingProcessor::OnSelectNone)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
|
||||
|
||||
/// @brief Checkbox clicked
|
||||
/// @param event
|
||||
///
|
||||
void DialogTimingProcessor::OnCheckBox(wxCommandEvent &event) {
|
||||
void DialogTimingProcessor::OnCheckBox(wxCommandEvent &) {
|
||||
UpdateControls();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Select all styles
|
||||
/// @param event
|
||||
///
|
||||
void DialogTimingProcessor::OnSelectAll(wxCommandEvent &event) {
|
||||
void DialogTimingProcessor::OnSelectAll(wxCommandEvent &) {
|
||||
size_t len = StyleList->GetCount();
|
||||
for (size_t i=0;i<len;i++) {
|
||||
StyleList->Check(i);
|
||||
|
@ -273,12 +262,7 @@ void DialogTimingProcessor::OnSelectAll(wxCommandEvent &event) {
|
|||
UpdateControls();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Unselect all styles
|
||||
/// @param event
|
||||
///
|
||||
void DialogTimingProcessor::OnSelectNone(wxCommandEvent &event) {
|
||||
void DialogTimingProcessor::OnSelectNone(wxCommandEvent &) {
|
||||
size_t len = StyleList->GetCount();
|
||||
for (size_t i=0;i<len;i++) {
|
||||
StyleList->Check(i,false);
|
||||
|
@ -286,12 +270,7 @@ void DialogTimingProcessor::OnSelectNone(wxCommandEvent &event) {
|
|||
UpdateControls();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Apply button pressed
|
||||
/// @param event
|
||||
///
|
||||
void DialogTimingProcessor::OnApply(wxCommandEvent &event) {
|
||||
void DialogTimingProcessor::OnApply(wxCommandEvent &) {
|
||||
// Save settings
|
||||
long temp = 0;
|
||||
leadIn->GetValue().ToLong(&temp);
|
||||
|
@ -330,26 +309,16 @@ void DialogTimingProcessor::OnApply(wxCommandEvent &event) {
|
|||
}
|
||||
}
|
||||
|
||||
// Process
|
||||
if (valid) Process();
|
||||
|
||||
// Error message
|
||||
else wxMessageBox(wxString::Format(_("One of the lines in the file (%i) has negative duration. Aborting."),i),_("Invalid script"),wxICON_ERROR|wxOK);
|
||||
|
||||
// Close dialogue
|
||||
EndModal(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Get closest keyframe
|
||||
/// @param frame
|
||||
/// @return
|
||||
///
|
||||
int DialogTimingProcessor::GetClosestKeyFrame(int frame) {
|
||||
// Linear dumb search, not very efficient, but it doesn't really matter
|
||||
int closest = 0;
|
||||
size_t n = KeyFrames.Count();
|
||||
size_t n = KeyFrames.size();
|
||||
for (size_t i=0;i<n;i++) {
|
||||
if (abs(KeyFrames[i]-frame) < abs(closest-frame)) {
|
||||
closest = KeyFrames[i];
|
||||
|
@ -358,8 +327,6 @@ int DialogTimingProcessor::GetClosestKeyFrame(int frame) {
|
|||
return closest;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Check if style is listed
|
||||
/// @param styleName
|
||||
/// @return
|
||||
|
@ -372,9 +339,7 @@ bool DialogTimingProcessor::StyleOK(wxString styleName) {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Sort dialogues
|
||||
/// @brief Sort dialogues
|
||||
///
|
||||
void DialogTimingProcessor::SortDialogues() {
|
||||
// Copy from original to temporary list
|
||||
|
@ -400,8 +365,6 @@ void DialogTimingProcessor::SortDialogues() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Gets sorted dialogue
|
||||
/// @param n
|
||||
/// @return
|
||||
|
@ -415,12 +378,9 @@ AssDialogue *DialogTimingProcessor::GetSortedDialogue(int n) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Actually process subtitles
|
||||
///
|
||||
void DialogTimingProcessor::Process() {
|
||||
// Sort rows
|
||||
SortDialogues();
|
||||
int rows = Sorted.size();
|
||||
|
||||
|
@ -539,8 +499,9 @@ void DialogTimingProcessor::Process() {
|
|||
// Keyframe snapping
|
||||
if (keysEnable->IsChecked()) {
|
||||
// Get keyframes
|
||||
KeyFrames = VideoContext::Get()->GetKeyFrames();
|
||||
KeyFrames.Add(VideoContext::Get()->GetLength()-1);
|
||||
VideoContext *con = VideoContext::Get();
|
||||
KeyFrames = con->GetKeyFrames();
|
||||
KeyFrames.push_back(con->GetLength()-1);
|
||||
|
||||
// Variables
|
||||
int startF,endF;
|
||||
|
@ -563,19 +524,19 @@ void DialogTimingProcessor::Process() {
|
|||
cur = GetSortedDialogue(i);
|
||||
|
||||
// Get start/end frames
|
||||
startF = VFR_Output.GetFrameAtTime(cur->Start.GetMS(),true);
|
||||
endF = VFR_Output.GetFrameAtTime(cur->End.GetMS(),false);
|
||||
startF = con->FrameAtTime(cur->Start.GetMS(),agi::vfr::START);
|
||||
endF = con->FrameAtTime(cur->End.GetMS(),agi::vfr::END);
|
||||
|
||||
// Get closest for start
|
||||
closest = GetClosestKeyFrame(startF);
|
||||
if ((closest > startF && closest-startF <= beforeStart) || (closest < startF && startF-closest <= afterStart)) {
|
||||
cur->Start.SetMS(VFR_Output.GetTimeAtFrame(closest,true));
|
||||
cur->Start.SetMS(con->TimeAtFrame(closest,agi::vfr::START));
|
||||
}
|
||||
|
||||
// Get closest for end
|
||||
closest = GetClosestKeyFrame(endF)-1;
|
||||
if ((closest > endF && closest-endF <= beforeEnd) || (closest < endF && endF-closest <= afterEnd)) {
|
||||
cur->End.SetMS(VFR_Output.GetTimeAtFrame(closest,false));
|
||||
cur->End.SetMS(con->TimeAtFrame(closest,agi::vfr::END));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -584,5 +545,3 @@ void DialogTimingProcessor::Process() {
|
|||
grid->ass->FlagAsModified(_("timing processor"));
|
||||
grid->CommitChanges();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -34,11 +34,6 @@
|
|||
/// @ingroup tools_ui
|
||||
///
|
||||
|
||||
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#ifndef AGI_PRE
|
||||
#include <vector>
|
||||
|
||||
|
@ -51,33 +46,24 @@
|
|||
#include <wx/textctrl.h>
|
||||
#endif
|
||||
|
||||
|
||||
//////////////
|
||||
// Prototypes
|
||||
class SubtitlesGrid;
|
||||
class AssDialogue;
|
||||
|
||||
|
||||
|
||||
/// DOCME
|
||||
/// @class DialogTimingProcessor
|
||||
/// @brief DOCME
|
||||
///
|
||||
/// DOCME
|
||||
class DialogTimingProcessor : public wxDialog {
|
||||
private:
|
||||
|
||||
/// DOCME
|
||||
SubtitlesGrid *grid;
|
||||
|
||||
/// DOCME
|
||||
wxStaticBoxSizer *KeyframesSizer;
|
||||
|
||||
|
||||
/// DOCME
|
||||
wxCheckBox *onlySelection;
|
||||
|
||||
|
||||
/// DOCME
|
||||
wxTextCtrl *leadIn;
|
||||
|
||||
|
@ -90,7 +76,6 @@ private:
|
|||
/// DOCME
|
||||
wxCheckBox *hasLeadOut;
|
||||
|
||||
|
||||
/// DOCME
|
||||
wxCheckBox *keysEnable;
|
||||
|
||||
|
@ -106,7 +91,6 @@ private:
|
|||
/// DOCME
|
||||
wxTextCtrl *keysEndAfter;
|
||||
|
||||
|
||||
/// DOCME
|
||||
wxCheckBox *adjsEnable;
|
||||
|
||||
|
@ -116,7 +100,6 @@ private:
|
|||
/// DOCME
|
||||
wxSlider *adjacentBias;
|
||||
|
||||
|
||||
/// DOCME
|
||||
wxCheckListBox *StyleList;
|
||||
|
||||
|
@ -138,9 +121,8 @@ private:
|
|||
/// DOCME
|
||||
wxString leadInTime,leadOutTime,thresStartBefore,thresStartAfter,thresEndBefore,thresEndAfter,adjsThresTime;
|
||||
|
||||
|
||||
/// DOCME
|
||||
wxArrayInt KeyFrames;
|
||||
std::vector<int> KeyFrames;
|
||||
|
||||
void OnCheckBox(wxCommandEvent &event);
|
||||
void OnSelectAll(wxCommandEvent &event);
|
||||
|
@ -152,7 +134,6 @@ private:
|
|||
int GetClosestKeyFrame(int frame);
|
||||
bool StyleOK(wxString styleName);
|
||||
|
||||
|
||||
/// DOCME
|
||||
std::vector<AssDialogue*> Sorted;
|
||||
AssDialogue *GetSortedDialogue(int n);
|
||||
|
@ -163,30 +144,3 @@ public:
|
|||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
|
||||
///////
|
||||
// IDs
|
||||
enum {
|
||||
|
||||
/// DOCME
|
||||
CHECK_ENABLE_LEADIN = 1850,
|
||||
|
||||
/// DOCME
|
||||
CHECK_ENABLE_LEADOUT,
|
||||
|
||||
/// DOCME
|
||||
CHECK_ENABLE_KEYFRAME,
|
||||
|
||||
/// DOCME
|
||||
CHECK_ENABLE_ADJASCENT,
|
||||
|
||||
/// DOCME
|
||||
BUTTON_SELECT_ALL,
|
||||
|
||||
/// DOCME
|
||||
BUTTON_SELECT_NONE,
|
||||
|
||||
/// DOCME
|
||||
TIMING_STYLE_LIST
|
||||
};
|
||||
|
|
|
@ -66,7 +66,7 @@ DialogVideoDetails::DialogVideoDetails(wxWindow *parent)
|
|||
int width = vprovider->GetWidth();
|
||||
int height = vprovider->GetHeight();
|
||||
int framecount = vprovider->GetFrameCount();
|
||||
double fps = vprovider->GetFPS();
|
||||
double fps = vprovider->GetFPS().FPS();
|
||||
|
||||
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);
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "ass_override.h"
|
||||
#include "export_framerate.h"
|
||||
#include "utils.h"
|
||||
#include "video_context.h"
|
||||
|
||||
/// DOCME
|
||||
/// @class LineData
|
||||
|
@ -93,11 +94,13 @@ void AssTransformFramerateFilter::ProcessSubs(AssFile *subs, wxWindow *export_di
|
|||
wxWindow *AssTransformFramerateFilter::GetConfigDialogWindow(wxWindow *parent) {
|
||||
wxWindow *base = new wxPanel(parent, -1);
|
||||
|
||||
LoadSettings(true);
|
||||
|
||||
// Input sizer
|
||||
wxSizer *InputSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxString initialInput;
|
||||
wxButton *FromVideo = new wxButton(base,Get_Input_From_Video,_("From Video"));
|
||||
if (VFR_Input.IsLoaded()) initialInput = wxString::Format(_T("%2.3f"),VFR_Input.GetAverage());
|
||||
if (Input->IsLoaded()) initialInput = wxString::Format(_T("%2.3f"),Input->FPS());
|
||||
else {
|
||||
initialInput = _T("23.976");
|
||||
FromVideo->Enable(false);
|
||||
|
@ -119,7 +122,7 @@ wxWindow *AssTransformFramerateFilter::GetConfigDialogWindow(wxWindow *parent) {
|
|||
// Output bottom line
|
||||
RadioOutputCFR = new wxRadioButton(base,-1,_("Constant: "));
|
||||
wxString initialOutput = initialInput;
|
||||
if (VFR_Output.GetFrameRateType() != VFR) {
|
||||
if (!Output->IsVFR()) {
|
||||
RadioOutputVFR->Enable(false);
|
||||
RadioOutputCFR->SetValue(true);
|
||||
}
|
||||
|
@ -150,20 +153,20 @@ wxWindow *AssTransformFramerateFilter::GetConfigDialogWindow(wxWindow *parent) {
|
|||
|
||||
void AssTransformFramerateFilter::LoadSettings(bool IsDefault) {
|
||||
if (IsDefault) {
|
||||
Input = &VFR_Input;
|
||||
Output = &VFR_Output;
|
||||
Input = &VideoContext::Get()->VFR_Input;
|
||||
Output = &VideoContext::Get()->VFR_Output;
|
||||
}
|
||||
else {
|
||||
double temp;
|
||||
InputFramerate->GetValue().ToDouble(&temp);
|
||||
t1.SetCFR(temp);
|
||||
t1 = temp;
|
||||
Input = &t1;
|
||||
if (RadioOutputCFR->GetValue()) {
|
||||
OutputFramerate->GetValue().ToDouble(&temp);
|
||||
t2.SetCFR(temp);
|
||||
t2 = temp;
|
||||
Output = &t2;
|
||||
}
|
||||
else Output = &VFR_Output;
|
||||
else Output = &VideoContext::Get()->VFR_Output;
|
||||
|
||||
if (Reverse->IsChecked()) {
|
||||
std::swap(Input, Output);
|
||||
|
@ -215,7 +218,7 @@ void AssTransformFramerateFilter::TransformTimeTags (wxString name,int n,AssOver
|
|||
}
|
||||
|
||||
void AssTransformFramerateFilter::TransformFrameRate(AssFile *subs) {
|
||||
if (!Input->IsLoaded() || !Output->IsLoaded() || Input == Output || *Input == *Output) return;
|
||||
if (!Input->IsLoaded() || !Output->IsLoaded()) return;
|
||||
for (entryIter cur=subs->Line.begin();cur!=subs->Line.end();cur++) {
|
||||
AssDialogue *curDialogue = dynamic_cast<AssDialogue*>(*cur);
|
||||
|
||||
|
@ -225,7 +228,7 @@ void AssTransformFramerateFilter::TransformFrameRate(AssFile *subs) {
|
|||
data.newK = 0;
|
||||
data.oldK = 0;
|
||||
data.newStart = trunc_cs(ConvertTime(curDialogue->Start.GetMS()));
|
||||
data.newEnd = trunc_cs(ConvertTime(curDialogue->End.GetMS()));
|
||||
data.newEnd = trunc_cs(ConvertTime(curDialogue->End.GetMS()) + 9);
|
||||
|
||||
// Process stuff
|
||||
curDialogue->ParseASSTags();
|
||||
|
@ -239,16 +242,18 @@ void AssTransformFramerateFilter::TransformFrameRate(AssFile *subs) {
|
|||
}
|
||||
|
||||
int AssTransformFramerateFilter::ConvertTime(int time) {
|
||||
int frame = Output->GetFrameAtTime(time, false);
|
||||
int frameStart = Output->GetTimeAtFrame(frame, false, true);
|
||||
int frameEnd = Output->GetTimeAtFrame(frame + 1, false, true);
|
||||
int frame = Output->FrameAtTime(time);
|
||||
int frameStart = Output->TimeAtFrame(frame);
|
||||
int frameEnd = Output->TimeAtFrame(frame + 1);
|
||||
int frameDur = frameEnd - frameStart;
|
||||
double dist = double(time - frameStart) / frameDur;
|
||||
|
||||
int newStart = Input->GetTimeAtFrame(frame, false, true);
|
||||
int newEnd = Input->GetTimeAtFrame(frame + 1, false, true);
|
||||
int newStart = Input->TimeAtFrame(frame);
|
||||
int newEnd = Input->TimeAtFrame(frame + 1);
|
||||
int newDur = newEnd - newStart;
|
||||
|
||||
int dongs = Input->FrameAtTime(newStart + newDur * dist, agi::vfr::END);
|
||||
|
||||
return newStart + newDur * dist;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
///
|
||||
|
||||
#include "ass_export_filter.h"
|
||||
#include "vfr.h"
|
||||
#include <libaegisub/vfr.h>
|
||||
|
||||
class AssDialogue;
|
||||
class AssOverrideParameter;
|
||||
|
@ -51,10 +51,10 @@ class AssTransformFramerateFilter : public AssExportFilter {
|
|||
static AssTransformFramerateFilter instance;
|
||||
|
||||
// Yes, these are backwards
|
||||
FrameRate *Input; /// Destination frame rate
|
||||
FrameRate *Output; /// Source frame rate
|
||||
const agi::vfr::Framerate *Input; /// Destination frame rate
|
||||
const agi::vfr::Framerate *Output; /// Source frame rate
|
||||
|
||||
FrameRate t1,t2;
|
||||
agi::vfr::Framerate t1,t2;
|
||||
|
||||
wxTextCtrl *InputFramerate; /// Input frame rate text box
|
||||
wxTextCtrl *OutputFramerate; /// Output frame rate text box
|
||||
|
|
|
@ -34,17 +34,13 @@
|
|||
/// @ingroup export
|
||||
///
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#include "config.h"
|
||||
|
||||
#include "ass_dialogue.h"
|
||||
#include "ass_file.h"
|
||||
#include "ass_override.h"
|
||||
#include "export_visible_lines.h"
|
||||
#include "vfr.h"
|
||||
|
||||
#include "video_context.h"
|
||||
|
||||
/// @brief Constructor
|
||||
///
|
||||
|
@ -53,11 +49,6 @@ AssLimitToVisibleFilter::AssLimitToVisibleFilter() {
|
|||
frame = -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Init
|
||||
/// @return
|
||||
///
|
||||
void AssLimitToVisibleFilter::Init() {
|
||||
if (initialized) return;
|
||||
initialized = true;
|
||||
|
@ -67,15 +58,10 @@ void AssLimitToVisibleFilter::Init() {
|
|||
description = _("Limit to Visible Lines");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Process
|
||||
/// @param subs
|
||||
/// @param export_dialog
|
||||
/// @return
|
||||
///
|
||||
void AssLimitToVisibleFilter::ProcessSubs(AssFile *subs, wxWindow *export_dialog) {
|
||||
// Nothing to do
|
||||
if (frame == -1) return;
|
||||
|
||||
AssDialogue *diag;
|
||||
|
@ -86,8 +72,8 @@ void AssLimitToVisibleFilter::ProcessSubs(AssFile *subs, wxWindow *export_dialog
|
|||
diag = dynamic_cast<AssDialogue*>(*cur);
|
||||
if (diag) {
|
||||
// Invisible, remove frame
|
||||
if (VFR_Output.GetFrameAtTime(diag->Start.GetMS(),true) > frame ||
|
||||
VFR_Output.GetFrameAtTime(diag->End.GetMS(),false) < frame) {
|
||||
if (VideoContext::Get()->FrameAtTime(diag->Start.GetMS(),agi::vfr::START) > frame ||
|
||||
VideoContext::Get()->FrameAtTime(diag->End.GetMS(),agi::vfr::END) < frame) {
|
||||
|
||||
delete *cur;
|
||||
subs->Line.erase(cur);
|
||||
|
@ -96,8 +82,6 @@ void AssLimitToVisibleFilter::ProcessSubs(AssFile *subs, wxWindow *export_dialog
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Set limitation time
|
||||
/// @param _frame
|
||||
///
|
||||
|
@ -105,9 +89,5 @@ void AssLimitToVisibleFilter::SetFrame(int _frame) {
|
|||
instance.frame = _frame;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// DOCME
|
||||
AssLimitToVisibleFilter AssLimitToVisibleFilter::instance;
|
||||
|
||||
|
||||
|
|
|
@ -79,7 +79,6 @@
|
|||
#include "text_file_writer.h"
|
||||
#include "utils.h"
|
||||
#include "version.h"
|
||||
#include "vfr.h"
|
||||
#include "video_box.h"
|
||||
#include "video_context.h"
|
||||
#include "video_display.h"
|
||||
|
@ -642,6 +641,7 @@ void FrameMain::DeInitContents() {
|
|||
AssFile::StackReset();
|
||||
delete AssFile::top;
|
||||
HelpButton::ClearPages();
|
||||
VideoContext::Get()->audio = NULL;
|
||||
}
|
||||
|
||||
/// @brief Update toolbar
|
||||
|
@ -760,6 +760,8 @@ void FrameMain::LoadSubtitles (wxString filename,wxString charset) {
|
|||
|
||||
// Update title bar
|
||||
UpdateTitle();
|
||||
|
||||
VideoContext::Get()->Refresh();
|
||||
}
|
||||
|
||||
/// @brief Save subtitles
|
||||
|
@ -949,7 +951,7 @@ void FrameMain::SynchronizeProject(bool fromSubs) {
|
|||
int autoLoadMode = OPT_GET("App/Auto/Load Linked Files")->GetInt();
|
||||
bool hasToLoad = false;
|
||||
if (curSubsAudio != audioBox->audioName ||
|
||||
curSubsVFR != VFR_Output.GetFilename() ||
|
||||
curSubsVFR != VideoContext::Get()->GetTimecodesName() ||
|
||||
curSubsVideo != VideoContext::Get()->videoName ||
|
||||
curSubsKeyframes != VideoContext::Get()->GetKeyFramesName()
|
||||
#ifdef WITH_AUTOMATION
|
||||
|
@ -970,25 +972,18 @@ void FrameMain::SynchronizeProject(bool fromSubs) {
|
|||
}
|
||||
|
||||
if (doLoad) {
|
||||
// Variable frame rate
|
||||
LoadVFR(curSubsVFR);
|
||||
|
||||
// Video
|
||||
if (curSubsVideo != VideoContext::Get()->videoName) {
|
||||
//if (curSubsVideo != _T("")) {
|
||||
LoadVideo(curSubsVideo);
|
||||
if (VideoContext::Get()->IsLoaded()) {
|
||||
VideoContext::Get()->SetAspectRatio(videoAr,videoArValue);
|
||||
videoBox->videoDisplay->SetZoom(videoZoom);
|
||||
VideoContext::Get()->JumpToFrame(videoPos);
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
// Keyframes
|
||||
if (curSubsKeyframes != _T("")) {
|
||||
KeyFrameFile::Load(curSubsKeyframes);
|
||||
}
|
||||
VideoContext::Get()->LoadTimecodes(curSubsVFR);
|
||||
VideoContext::Get()->LoadKeyframes(curSubsKeyframes);
|
||||
|
||||
// Audio
|
||||
if (curSubsAudio != audioBox->audioName) {
|
||||
|
@ -1058,7 +1053,7 @@ void FrameMain::SynchronizeProject(bool fromSubs) {
|
|||
subs->SetScriptInfo(_T("Video Aspect Ratio"),ar);
|
||||
subs->SetScriptInfo(_T("Video Zoom Percent"),zoom);
|
||||
subs->SetScriptInfo(_T("Video Position"),seekpos);
|
||||
subs->SetScriptInfo(_T("VFR File"),MakeRelativePath(VFR_Output.GetFilename(),AssFile::top->filename));
|
||||
subs->SetScriptInfo(_T("VFR File"),MakeRelativePath(VideoContext::Get()->GetTimecodesName(),AssFile::top->filename));
|
||||
subs->SetScriptInfo(_T("Keyframes File"),MakeRelativePath(VideoContext::Get()->GetKeyFramesName(),AssFile::top->filename));
|
||||
|
||||
// Store Automation script data
|
||||
|
@ -1104,26 +1099,11 @@ void FrameMain::SynchronizeProject(bool fromSubs) {
|
|||
void FrameMain::LoadVideo(wxString file,bool autoload) {
|
||||
if (blockVideoLoad) return;
|
||||
Freeze();
|
||||
VideoContext::Get()->Stop();
|
||||
try {
|
||||
if (VideoContext::Get()->IsLoaded()) {
|
||||
if (VFR_Output.GetFrameRateType() == VFR) {
|
||||
if (!autoload) {
|
||||
int result = wxMessageBox(_("You have timecodes loaded currently. Would you like to unload them?"), _("Unload timecodes?"), wxYES_NO, this);
|
||||
if (result == wxYES) {
|
||||
VFR_Output.Unload();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
VFR_Output.Unload();
|
||||
}
|
||||
}
|
||||
VideoContext::Get()->SetVideo(file);
|
||||
}
|
||||
catch (const wchar_t *error) {
|
||||
wxString err(error);
|
||||
wxMessageBox(err, _T("Error opening video file"), wxOK | wxICON_ERROR, this);
|
||||
wxMessageBox(error, _T("Error opening video file"), wxOK | wxICON_ERROR, this);
|
||||
}
|
||||
catch (...) {
|
||||
wxMessageBox(_T("Unknown error"), _T("Error opening video file"), wxOK | wxICON_ERROR, this);
|
||||
|
@ -1199,43 +1179,17 @@ void FrameMain::LoadAudio(wxString filename,bool FromVideo) {
|
|||
}
|
||||
}
|
||||
|
||||
/// @brief Loads VFR
|
||||
/// @param filename
|
||||
void FrameMain::LoadVFR(wxString filename) {
|
||||
VideoContext::Get()->Stop();
|
||||
if (filename != _T("")) {
|
||||
try {
|
||||
VFR_Output.Load(filename);
|
||||
SubsGrid->Refresh(false);
|
||||
}
|
||||
|
||||
// Fail
|
||||
catch (const wchar_t *error) {
|
||||
wxString err(error);
|
||||
wxMessageBox(err, _T("Error opening timecodes file"), wxOK | wxICON_ERROR, this);
|
||||
}
|
||||
catch (...) {
|
||||
wxMessageBox(_T("Unknown error"), _T("Error opening timecodes file"), wxOK | wxICON_ERROR, this);
|
||||
}
|
||||
if (filename.empty()) {
|
||||
VideoContext::Get()->CloseTimecodes();
|
||||
}
|
||||
|
||||
else {
|
||||
VFR_Output.Unload();
|
||||
if (VideoContext::Get()->IsLoaded() && !VFR_Output.IsLoaded()) {
|
||||
VFR_Output.SetCFR(VideoContext::Get()->GetFPS());
|
||||
}
|
||||
VideoContext::Get()->LoadTimecodes(filename);
|
||||
}
|
||||
|
||||
SubsGrid->CommitChanges();
|
||||
EditBox->UpdateFrameTiming();
|
||||
}
|
||||
|
||||
/// @brief Saves VFR
|
||||
/// @param filename
|
||||
void FrameMain::SaveVFR(wxString filename) {
|
||||
VFR_Output.Save(filename);
|
||||
}
|
||||
|
||||
/// @brief Open help
|
||||
void FrameMain::OpenHelp(wxString) {
|
||||
HelpButton::OpenPage(_T("Main"));
|
||||
|
|
|
@ -315,7 +315,6 @@ private:
|
|||
void LoadVideo(wxString filename,bool autoload=false);
|
||||
void LoadAudio(wxString filename,bool FromVideo=false);
|
||||
void LoadVFR(wxString filename);
|
||||
void SaveVFR(wxString filename);
|
||||
void LoadSubtitles(wxString filename,wxString charset=_T(""));
|
||||
bool SaveSubtitles(bool saveas=false,bool withCharset=false);
|
||||
int TryToCloseSubs(bool enableCancel=true);
|
||||
|
|
|
@ -89,7 +89,6 @@
|
|||
#include "subs_grid.h"
|
||||
#include "toggle_bitmap.h"
|
||||
#include "utils.h"
|
||||
#include "vfr.h"
|
||||
#include "video_box.h"
|
||||
#include "video_context.h"
|
||||
#include "video_display.h"
|
||||
|
@ -336,8 +335,8 @@ void FrameMain::OnMenuOpen (wxMenuEvent &event) {
|
|||
MenuBar->Enable(Menu_Video_AR_235,attached);
|
||||
MenuBar->Enable(Menu_Video_AR_Custom,attached);
|
||||
MenuBar->Enable(Menu_Video_Detach,state);
|
||||
MenuBar->Enable(Menu_File_Save_VFR,VFR_Output.GetFrameRateType() == VFR);
|
||||
MenuBar->Enable(Menu_File_Close_VFR,VFR_Output.GetFrameRateType() == VFR);
|
||||
MenuBar->Enable(Menu_File_Save_VFR,VideoContext::Get()->TimecodesLoaded());
|
||||
MenuBar->Enable(Menu_File_Close_VFR,VideoContext::Get()->OverTimecodesLoaded());
|
||||
MenuBar->Enable(Menu_Video_Close_Keyframes,VideoContext::Get()->OverKeyFramesLoaded());
|
||||
MenuBar->Enable(Menu_Video_Save_Keyframes,VideoContext::Get()->KeyFramesLoaded());
|
||||
MenuBar->Enable(Menu_Video_Details,state);
|
||||
|
@ -399,7 +398,7 @@ void FrameMain::OnMenuOpen (wxMenuEvent &event) {
|
|||
MenuBar->Enable(Menu_Subtitles_Insert,state);
|
||||
state = count > 0 && continuous;
|
||||
MenuBar->Enable(MENU_DUPLICATE,state);
|
||||
state = count > 0 && continuous && VFR_Output.IsLoaded();
|
||||
state = count > 0 && continuous && VideoContext::Get()->TimecodesLoaded();
|
||||
MenuBar->Enable(MENU_DUPLICATE_NEXT_FRAME,state);
|
||||
state = count == 2;
|
||||
MenuBar->Enable(MENU_SWAP,state);
|
||||
|
@ -540,7 +539,7 @@ void FrameMain::OnOpenRecentTimecodes(wxCommandEvent &event) {
|
|||
/// @param event
|
||||
void FrameMain::OnOpenRecentKeyframes(wxCommandEvent &event) {
|
||||
int number = event.GetId()-Menu_Keyframes_Recent;
|
||||
KeyFrameFile::Load(lagi_wxString(config::mru->GetEntry("Keyframes", number)));
|
||||
VideoContext::Get()->LoadKeyframes(lagi_wxString(config::mru->GetEntry("Keyframes", number)));
|
||||
videoBox->videoSlider->Refresh();
|
||||
audioBox->audioDisplay->Update();
|
||||
Refresh();
|
||||
|
@ -789,7 +788,7 @@ void FrameMain::OnSaveVFR(wxCommandEvent &) {
|
|||
+ _("All Files") + _T(" (*.*)|*.*");
|
||||
wxString filename = wxFileSelector(_("Save timecodes file"),path,_T(""),_T(""),str,wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
|
||||
if (!filename.empty()) {
|
||||
SaveVFR(filename);
|
||||
VideoContext::Get()->SaveTimecodes(filename);
|
||||
OPT_SET("Path/Last/Timecodes")->SetString(STD_STR(filename));
|
||||
}
|
||||
}
|
||||
|
@ -797,19 +796,26 @@ void FrameMain::OnSaveVFR(wxCommandEvent &) {
|
|||
|
||||
/// @brief Close VFR tags
|
||||
void FrameMain::OnCloseVFR(wxCommandEvent &) {
|
||||
LoadVFR(_T(""));
|
||||
LoadVFR("");
|
||||
}
|
||||
|
||||
/// @brief Open keyframes
|
||||
void FrameMain::OnOpenKeyframes (wxCommandEvent &) {
|
||||
// Pick file
|
||||
wxString path = lagi_wxString(OPT_GET("Path/Last/Keyframes")->GetString());
|
||||
wxString filename = wxFileSelector(_T("Select the keyframes file to open"),path,_T(""),_T(".txt"),_T("All supported formats (*.txt, *.pass, *.stats, *.log)|*.txt;*.pass;*.stats;*.log|All files (*.*)|*.*"),wxFD_FILE_MUST_EXIST | wxFD_OPEN);
|
||||
if (filename.IsEmpty()) return;
|
||||
wxString filename = wxFileSelector(
|
||||
_T("Select the keyframes file to open"),
|
||||
path,
|
||||
_T("")
|
||||
,_T(".txt"),
|
||||
_T("All supported formats (*.txt, *.pass, *.stats, *.log)|*.txt;*.pass;*.stats;*.log|All files (*.*)|*.*"),
|
||||
wxFD_FILE_MUST_EXIST | wxFD_OPEN);
|
||||
|
||||
if (filename.empty()) return;
|
||||
OPT_SET("Path/Last/Keyframes")->SetString(STD_STR(filename));
|
||||
|
||||
// Load
|
||||
KeyFrameFile::Load(filename);
|
||||
VideoContext::Get()->LoadKeyframes(filename);
|
||||
videoBox->videoSlider->Refresh();
|
||||
audioBox->audioDisplay->Update();
|
||||
Refresh();
|
||||
|
@ -817,7 +823,7 @@ void FrameMain::OnOpenKeyframes (wxCommandEvent &) {
|
|||
|
||||
/// @brief Close keyframes
|
||||
void FrameMain::OnCloseKeyframes (wxCommandEvent &) {
|
||||
VideoContext::Get()->CloseOverKeyFrames();
|
||||
VideoContext::Get()->CloseKeyframes();
|
||||
videoBox->videoSlider->Refresh();
|
||||
audioBox->audioDisplay->Update();
|
||||
Refresh();
|
||||
|
@ -831,8 +837,7 @@ void FrameMain::OnSaveKeyframes (wxCommandEvent &) {
|
|||
if (filename.IsEmpty()) return;
|
||||
OPT_SET("Path/Last/Keyframes")->SetString(STD_STR(filename));
|
||||
|
||||
// Save
|
||||
KeyFrameFile::Save(filename);
|
||||
VideoContext::Get()->SaveKeyframes(filename);
|
||||
}
|
||||
|
||||
/// @brief Zoom levels
|
||||
|
@ -1064,118 +1069,100 @@ void FrameMain::OnAutomationMacro (wxCommandEvent &event) {
|
|||
|
||||
/// @brief Snap subs to video
|
||||
void FrameMain::OnSnapSubsStartToVid (wxCommandEvent &) {
|
||||
if (VideoContext::Get()->IsLoaded() && SubsGrid->GetSelection().Count() > 0) {
|
||||
SubsGrid->SetSubsToVideo(true);
|
||||
}
|
||||
SubsGrid->SetSubsToVideo(true);
|
||||
}
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
void FrameMain::OnSnapSubsEndToVid (wxCommandEvent &) {
|
||||
if (VideoContext::Get()->IsLoaded() && SubsGrid->GetSelection().Count() > 0) {
|
||||
SubsGrid->SetSubsToVideo(false);
|
||||
}
|
||||
SubsGrid->SetSubsToVideo(false);
|
||||
}
|
||||
|
||||
/// @brief Jump video to subs
|
||||
void FrameMain::OnSnapVidToSubsStart (wxCommandEvent &) {
|
||||
if (VideoContext::Get()->IsLoaded() && SubsGrid->GetSelection().Count() > 0) {
|
||||
SubsGrid->SetVideoToSubs(true);
|
||||
}
|
||||
SubsGrid->SetVideoToSubs(true);
|
||||
}
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
void FrameMain::OnSnapVidToSubsEnd (wxCommandEvent &) {
|
||||
if (VideoContext::Get()->IsLoaded() && SubsGrid->GetSelection().Count() > 0) {
|
||||
SubsGrid->SetVideoToSubs(false);
|
||||
}
|
||||
SubsGrid->SetVideoToSubs(false);
|
||||
}
|
||||
|
||||
/// @brief Snap to scene
|
||||
void FrameMain::OnSnapToScene (wxCommandEvent &) {
|
||||
if (VideoContext::Get()->IsLoaded()) {
|
||||
// Get frames
|
||||
wxArrayInt sel = SubsGrid->GetSelection();
|
||||
int curFrame = VideoContext::Get()->GetFrameN();
|
||||
int prev = 0;
|
||||
int next = 0;
|
||||
int frame = 0;
|
||||
wxArrayInt keyframes = VideoContext::Get()->GetKeyFrames();
|
||||
size_t n = keyframes.Count();
|
||||
bool found = false;
|
||||
for (size_t i=0;i<n;i++) {
|
||||
frame = keyframes[i];
|
||||
VideoContext *con = VideoContext::Get();
|
||||
if (!con->IsLoaded() || !con->KeyFramesLoaded()) return;
|
||||
|
||||
if (frame == curFrame) {
|
||||
prev = frame;
|
||||
if (i < n-1) next = keyframes[i+1];
|
||||
else next = VideoContext::Get()->GetLength();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
// Get frames
|
||||
wxArrayInt sel = SubsGrid->GetSelection();
|
||||
int curFrame = con->GetFrameN();
|
||||
int prev = 0;
|
||||
int next = 0;
|
||||
|
||||
if (frame > curFrame) {
|
||||
if (i != 0) prev = keyframes[i-1];
|
||||
else prev = 0;
|
||||
next = frame;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Last section?
|
||||
if (!found) {
|
||||
if (n > 0) prev = keyframes[n-1];
|
||||
else prev = 0;
|
||||
next = VideoContext::Get()->GetLength();
|
||||
}
|
||||
|
||||
// Get times
|
||||
int start_ms = VFR_Output.GetTimeAtFrame(prev,true);
|
||||
int end_ms = VFR_Output.GetTimeAtFrame(next-1,false);
|
||||
AssDialogue *cur;
|
||||
|
||||
// Update rows
|
||||
for (size_t i=0;i<sel.Count();i++) {
|
||||
cur = SubsGrid->GetDialogue(sel[i]);
|
||||
cur->Start.SetMS(start_ms);
|
||||
cur->End.SetMS(end_ms);
|
||||
}
|
||||
|
||||
// Commit
|
||||
SubsGrid->editBox->Update(true);
|
||||
SubsGrid->ass->FlagAsModified(_("snap to scene"));
|
||||
SubsGrid->CommitChanges();
|
||||
const std::vector<int> &keyframes = con->GetKeyFrames();
|
||||
if (curFrame < keyframes.front()) {
|
||||
next = keyframes.front();
|
||||
}
|
||||
else if (curFrame >= keyframes.back()) {
|
||||
prev = keyframes.back();
|
||||
next = con->GetLength();
|
||||
}
|
||||
else {
|
||||
std::vector<int>::const_iterator kf = std::lower_bound(keyframes.begin(), keyframes.end(), curFrame);
|
||||
if (*kf == curFrame) {
|
||||
prev = *kf;
|
||||
next = *(kf + 1);
|
||||
}
|
||||
else {
|
||||
prev = *(kf - 1);
|
||||
next = *kf;
|
||||
}
|
||||
}
|
||||
|
||||
// Get times
|
||||
int start_ms = con->TimeAtFrame(prev,agi::vfr::START);
|
||||
int end_ms = con->TimeAtFrame(next-1,agi::vfr::END);
|
||||
AssDialogue *cur;
|
||||
|
||||
// Update rows
|
||||
for (size_t i=0;i<sel.Count();i++) {
|
||||
cur = SubsGrid->GetDialogue(sel[i]);
|
||||
cur->Start.SetMS(start_ms);
|
||||
cur->End.SetMS(end_ms);
|
||||
}
|
||||
|
||||
// Commit
|
||||
SubsGrid->editBox->Update(true);
|
||||
SubsGrid->ass->FlagAsModified(_("snap to scene"));
|
||||
SubsGrid->CommitChanges();
|
||||
}
|
||||
|
||||
/// @brief Shift to frame
|
||||
void FrameMain::OnShiftToFrame (wxCommandEvent &) {
|
||||
if (VideoContext::Get()->IsLoaded()) {
|
||||
wxArrayInt sels = SubsGrid->GetSelection();
|
||||
size_t n=sels.Count();
|
||||
if (n == 0) return;
|
||||
if (!VideoContext::Get()->IsLoaded()) return;
|
||||
|
||||
// Get shifting in ms
|
||||
AssDialogue *cur = SubsGrid->GetDialogue(sels[0]);
|
||||
if (!cur) return;
|
||||
int shiftBy = VFR_Output.GetTimeAtFrame(VideoContext::Get()->GetFrameN(),true) - cur->Start.GetMS();
|
||||
wxArrayInt sels = SubsGrid->GetSelection();
|
||||
size_t n=sels.Count();
|
||||
if (n == 0) return;
|
||||
|
||||
// Update
|
||||
for (size_t i=0;i<n;i++) {
|
||||
cur = SubsGrid->GetDialogue(sels[i]);
|
||||
if (cur) {
|
||||
cur->Start.SetMS(cur->Start.GetMS()+shiftBy);
|
||||
cur->End.SetMS(cur->End.GetMS()+shiftBy);
|
||||
}
|
||||
// Get shifting in ms
|
||||
AssDialogue *cur = SubsGrid->GetDialogue(sels[0]);
|
||||
if (!cur) return;
|
||||
int shiftBy = VideoContext::Get()->TimeAtFrame(VideoContext::Get()->GetFrameN(),agi::vfr::START) - cur->Start.GetMS();
|
||||
|
||||
// Update
|
||||
for (size_t i=0;i<n;i++) {
|
||||
cur = SubsGrid->GetDialogue(sels[i]);
|
||||
if (cur) {
|
||||
cur->Start.SetMS(cur->Start.GetMS()+shiftBy);
|
||||
cur->End.SetMS(cur->End.GetMS()+shiftBy);
|
||||
}
|
||||
|
||||
// Commit
|
||||
SubsGrid->ass->FlagAsModified(_("shift to frame"));
|
||||
SubsGrid->CommitChanges();
|
||||
SubsGrid->editBox->Update(true,false);
|
||||
}
|
||||
|
||||
// Commit
|
||||
SubsGrid->ass->FlagAsModified(_("shift to frame"));
|
||||
SubsGrid->CommitChanges();
|
||||
SubsGrid->editBox->Update(true,false);
|
||||
}
|
||||
|
||||
/// @brief Undo
|
||||
|
|
|
@ -34,16 +34,10 @@
|
|||
/// @ingroup main_headers video_input
|
||||
///
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//////////
|
||||
// Headers
|
||||
#include "aegisub.h"
|
||||
#include "vfr.h"
|
||||
#include "video_frame.h"
|
||||
|
||||
#include <libaegisub/vfr.h>
|
||||
|
||||
/// @class VideoProvider
|
||||
/// @brief DOCME
|
||||
|
@ -51,62 +45,31 @@
|
|||
/// DOCME
|
||||
class VideoProvider {
|
||||
public:
|
||||
|
||||
/// @brief // Virtual destructor
|
||||
/// @return
|
||||
///
|
||||
virtual ~VideoProvider() {}
|
||||
|
||||
// Override this method to actually get frames
|
||||
virtual const AegiVideoFrame GetFrame(int n)=0;
|
||||
|
||||
// Override the following methods to get video information:
|
||||
virtual int GetPosition()=0; // Get the number of the last frame loaded
|
||||
virtual int GetFrameCount()=0; // Get total number of frames
|
||||
virtual int GetWidth()=0; // Returns the video width in pixels
|
||||
virtual int GetHeight()=0; // Returns the video height in pixels
|
||||
virtual double GetFPS()=0; // Get framerate in frames per second
|
||||
virtual bool AreKeyFramesLoaded()=0; // Returns true if keyframe info is loaded, false otherwise
|
||||
virtual bool IsVFR()=0; // Returns true if video is VFR
|
||||
virtual wxArrayInt GetKeyFrames()=0; // Returns list of keyframes
|
||||
virtual FrameRate GetTrueFrameRate()=0; // Returns magic VFR stuff
|
||||
virtual int GetPosition() const=0; ///< Get the number of the last frame loaded
|
||||
virtual int GetFrameCount() const=0; ///< Get total number of frames
|
||||
virtual int GetWidth() const=0; ///< Returns the video width in pixels
|
||||
virtual int GetHeight() const=0; ///< Returns the video height in pixels
|
||||
virtual agi::vfr::Framerate GetFPS() const=0; ///< Get frame rate
|
||||
virtual std::vector<int> GetKeyFrames() const=0;///< Returns list of keyframes
|
||||
|
||||
|
||||
/// @brief // Use this to set any post-loading warnings, such as "being loaded with unreliable seeking"
|
||||
/// @return
|
||||
///
|
||||
virtual wxString GetWarning() { return L""; }
|
||||
|
||||
|
||||
/// @brief // Name of decoder, e.g. "Avisynth/FFMpegSource"
|
||||
/// @return
|
||||
///
|
||||
virtual wxString GetDecoderName() { return L"Unknown"; }
|
||||
/// @brief Use this to set any post-loading warnings, such as "being loaded with unreliable seeking"
|
||||
virtual wxString GetWarning() const { return L""; }
|
||||
|
||||
/// @brief Name of decoder, e.g. "Avisynth/FFMpegSource"
|
||||
virtual wxString GetDecoderName() const = 0;
|
||||
|
||||
/// @brief Does this provider want Aegisub to cache video frames?
|
||||
/// @return Returns true if caching is desired, false otherwise.
|
||||
virtual bool WantsCaching() { return false; }
|
||||
|
||||
|
||||
/// @brief // For "special" providers that don't deal well with VFR (i.e. Avisynth)
|
||||
/// @return
|
||||
///
|
||||
virtual bool NeedsVFRHack() { return false; }; // Returns true if provider needs special VFR treatment
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
virtual bool IsNativelyByFrames() { return true; };
|
||||
|
||||
/// @brief DOCME
|
||||
/// @param list
|
||||
///
|
||||
virtual void OverrideFrameTimeList(std::vector<int> list) {} // Override the list with the provided one, for VFR handling
|
||||
virtual bool WantsCaching() const { return false; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// @class VideoProviderFactory
|
||||
/// @brief DOCME
|
||||
///
|
||||
|
@ -119,5 +82,3 @@ public:
|
|||
virtual ~VideoProviderFactory() {}
|
||||
virtual VideoProvider *CreateProvider(wxString video)=0;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -34,8 +34,6 @@
|
|||
/// @ingroup video_input
|
||||
///
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#include "config.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
|
@ -48,19 +46,11 @@
|
|||
#include "options.h"
|
||||
#include "text_file_reader.h"
|
||||
#include "text_file_writer.h"
|
||||
#include "vfr.h"
|
||||
#include "video_context.h"
|
||||
|
||||
|
||||
/// @brief Load Keyframes
|
||||
/// @param filename
|
||||
///
|
||||
void KeyFrameFile::Load(wxString filename) {
|
||||
// Load
|
||||
std::vector<int> KeyFrameFile::Load(wxString filename) {
|
||||
try {
|
||||
// Open file
|
||||
wxArrayInt keyFrames;
|
||||
keyFrames.Empty();
|
||||
std::vector<int> keyFrames;
|
||||
TextFileReader file(filename,_T("ASCII"));
|
||||
|
||||
wxString cur = file.ReadLineFromFile();
|
||||
|
@ -71,53 +61,36 @@ void KeyFrameFile::Load(wxString filename) {
|
|||
else if (cur.StartsWith(_T("#options:"))) { Openx264KeyFrames(file, keyFrames); }
|
||||
else { throw(_T("Invalid or unsupported keyframes file.")); }
|
||||
|
||||
// Set keyframes
|
||||
VideoContext::Get()->SetOverKeyFrames(keyFrames);
|
||||
VideoContext::Get()->SetKeyFramesName(filename);
|
||||
|
||||
// Add to recent
|
||||
config::mru->Add("Keyframes", STD_STR(filename));
|
||||
return keyFrames;
|
||||
}
|
||||
// Fail
|
||||
catch (const wchar_t *error) {
|
||||
wxString err(error);
|
||||
wxMessageBox(err, _T("Error opening keyframes file"), wxOK | wxICON_ERROR, NULL);
|
||||
wxMessageBox(error, _T("Error opening keyframes file"), wxOK | wxICON_ERROR, NULL);
|
||||
}
|
||||
catch (...) {
|
||||
wxMessageBox(_T("Unknown error"), _T("Error opening keyframes file"), wxOK | wxICON_ERROR, NULL);
|
||||
}
|
||||
return std::vector<int>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Save Keyframes
|
||||
/// @param filename
|
||||
///
|
||||
void KeyFrameFile::Save(wxString filename) {
|
||||
// Get keyframes
|
||||
wxArrayInt keyFrames = VideoContext::Get()->GetKeyFrames();
|
||||
|
||||
// Write header
|
||||
void KeyFrameFile::Save(wxString filename, std::vector<int> const& keyFrames) {
|
||||
TextFileWriter file(filename,_T("ASCII"));
|
||||
file.WriteLineToFile(_T("# keyframe format v1"));
|
||||
file.WriteLineToFile(wxString::Format(_T("fps %f"),VideoContext::Get()->GetFPS()));
|
||||
file.WriteLineToFile(wxString::Format(_T("fps %f"),VideoContext::Get()->VFR_Input.FPS()));
|
||||
|
||||
// Write keyframes
|
||||
for (unsigned int i=0;i<keyFrames.Count();i++) {
|
||||
for (unsigned int i=0;i<keyFrames.size();i++) {
|
||||
file.WriteLineToFile(wxString::Format(_T("%i"),keyFrames[i]));
|
||||
}
|
||||
|
||||
// Add to recent
|
||||
config::mru->Add("Keyframes", STD_STR(filename));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Aegisub keyframes file
|
||||
/// @param file
|
||||
/// @param keyFrames
|
||||
///
|
||||
void KeyFrameFile::OpenAegiKeyFrames(TextFileReader& file, wxArrayInt& keyFrames)
|
||||
void KeyFrameFile::OpenAegiKeyFrames(TextFileReader& file, std::vector<int>& keyFrames)
|
||||
{
|
||||
double fps;
|
||||
wxString cur = file.ReadLineFromFile();
|
||||
|
@ -129,10 +102,8 @@ void KeyFrameFile::OpenAegiKeyFrames(TextFileReader& file, wxArrayInt& keyFrames
|
|||
if (fps == 0.0) throw _T("Invalid FPS.");
|
||||
|
||||
// Set FPS
|
||||
if (!VideoContext::Get()->IsLoaded()) {
|
||||
VideoContext::Get()->SetFPS(fps);
|
||||
VFR_Input.SetCFR(fps);
|
||||
if (!VFR_Output.IsLoaded()) VFR_Output.SetCFR(fps);
|
||||
if (!VideoContext::Get()->TimecodesLoaded()) {
|
||||
VideoContext::Get()->ovrFPS = fps;
|
||||
}
|
||||
|
||||
// Read lines
|
||||
|
@ -141,26 +112,24 @@ void KeyFrameFile::OpenAegiKeyFrames(TextFileReader& file, wxArrayInt& keyFrames
|
|||
if (!cur.IsEmpty() && !cur.StartsWith(_T("#")) && cur.IsNumber()) {
|
||||
long temp;
|
||||
cur.ToLong(&temp);
|
||||
keyFrames.Add(temp);
|
||||
keyFrames.push_back(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief XviD stats file
|
||||
/// @param file
|
||||
/// @param keyFrames
|
||||
///
|
||||
void KeyFrameFile::OpenXviDKeyFrames(TextFileReader& file, wxArrayInt& keyFrames)
|
||||
void KeyFrameFile::OpenXviDKeyFrames(TextFileReader& file, std::vector<int>& keyFrames)
|
||||
{
|
||||
wxString cur = file.ReadLineFromFile();
|
||||
unsigned int count = 0;
|
||||
|
||||
// Read lines
|
||||
while (file.HasMoreLines()) {
|
||||
if (cur.StartsWith(_T("i"))) {
|
||||
keyFrames.Add(count);
|
||||
if (cur.StartsWith(_T("i"))) {
|
||||
keyFrames.push_back(count);
|
||||
count++;
|
||||
}
|
||||
else if (cur.StartsWith(_T("p")) || cur.StartsWith(_T("b"))) {
|
||||
|
@ -170,12 +139,11 @@ void KeyFrameFile::OpenXviDKeyFrames(TextFileReader& file, wxArrayInt& keyFrames
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// @brief DivX stats file
|
||||
/// @param file
|
||||
/// @param keyFrames
|
||||
///
|
||||
void KeyFrameFile::OpenDivXKeyFrames(TextFileReader& file, wxArrayInt& keyFrames)
|
||||
void KeyFrameFile::OpenDivXKeyFrames(TextFileReader& file, std::vector<int>& keyFrames)
|
||||
{
|
||||
wxString cur = file.ReadLineFromFile();
|
||||
unsigned int count = 0;
|
||||
|
@ -184,7 +152,7 @@ void KeyFrameFile::OpenDivXKeyFrames(TextFileReader& file, wxArrayInt& keyFrames
|
|||
while (file.HasMoreLines())
|
||||
{
|
||||
if (cur.Contains(_T("I"))) {
|
||||
keyFrames.Add(count);
|
||||
keyFrames.push_back(count);
|
||||
count++;
|
||||
}
|
||||
else if (cur.Contains(_T("P")) || cur.Contains(_T("B"))) {
|
||||
|
@ -194,12 +162,11 @@ void KeyFrameFile::OpenDivXKeyFrames(TextFileReader& file, wxArrayInt& keyFrames
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// @brief x264 stats file
|
||||
/// @param file
|
||||
/// @param keyFrames
|
||||
///
|
||||
void KeyFrameFile::Openx264KeyFrames(TextFileReader& file, wxArrayInt& keyFrames)
|
||||
void KeyFrameFile::Openx264KeyFrames(TextFileReader& file, std::vector<int>& keyFrames)
|
||||
{
|
||||
wxString cur = file.ReadLineFromFile();
|
||||
unsigned int count = 0;
|
||||
|
@ -210,7 +177,7 @@ void KeyFrameFile::Openx264KeyFrames(TextFileReader& file, wxArrayInt& keyFrames
|
|||
{
|
||||
pos = cur.Find(_T("type:"));
|
||||
if (cur.Mid(pos,6).Right(1).Lower() == (_T("i"))) {
|
||||
keyFrames.Add(count);
|
||||
keyFrames.push_back(count);
|
||||
count++;
|
||||
}
|
||||
else if (cur.Mid(pos,6).Right(1).Lower() == (_T("p")) || cur.Mid(pos,6).Right(1).Lower() == (_T("b"))) {
|
||||
|
@ -219,5 +186,3 @@ void KeyFrameFile::Openx264KeyFrames(TextFileReader& file, wxArrayInt& keyFrames
|
|||
cur = file.ReadLineFromFile();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -34,9 +34,6 @@
|
|||
/// @ingroup video_input
|
||||
///
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#include "text_file_reader.h"
|
||||
|
||||
|
||||
|
@ -48,13 +45,13 @@
|
|||
class KeyFrameFile
|
||||
{
|
||||
public:
|
||||
static void Load(wxString filename);
|
||||
static void Save(wxString filename);
|
||||
static std::vector<int> Load(wxString filename);
|
||||
static void Save(wxString filename, std::vector<int> const& keyframes);
|
||||
private:
|
||||
static void OpenAegiKeyFrames(TextFileReader& file, wxArrayInt& keyFrames);
|
||||
static void OpenXviDKeyFrames(TextFileReader& file, wxArrayInt& keyFrames);
|
||||
static void OpenDivXKeyFrames(TextFileReader& file, wxArrayInt& keyFrames);
|
||||
static void Openx264KeyFrames(TextFileReader& file, wxArrayInt& keyFrames);
|
||||
static void OpenAegiKeyFrames(TextFileReader& file, std::vector<int>& keyFrames);
|
||||
static void OpenXviDKeyFrames(TextFileReader& file, std::vector<int>& keyFrames);
|
||||
static void OpenDivXKeyFrames(TextFileReader& file, std::vector<int>& keyFrames);
|
||||
static void Openx264KeyFrames(TextFileReader& file, std::vector<int>& keyFrames);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -280,7 +280,6 @@ bool AegisubApp::OnInit() {
|
|||
///
|
||||
int AegisubApp::OnExit() {
|
||||
SubtitleFormat::DestroyFormats();
|
||||
VideoContext::Clear();
|
||||
delete plugins;
|
||||
delete config::opt;
|
||||
delete config::mru;
|
||||
|
|
|
@ -34,9 +34,6 @@
|
|||
/// @ingroup video_input
|
||||
///
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#include "config.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
|
@ -44,6 +41,7 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
#include <wx/filename.h>
|
||||
#include <wx/tokenzr.h>
|
||||
|
@ -53,6 +51,7 @@
|
|||
#include "ass_file.h"
|
||||
#include "ass_time.h"
|
||||
#include "dialog_progress.h"
|
||||
#include <libaegisub/vfr.h>
|
||||
#include "mkv_wrap.h"
|
||||
|
||||
|
||||
|
@ -259,51 +258,21 @@ void MatroskaWrapper::Parse() {
|
|||
}
|
||||
|
||||
|
||||
static int mkv_round(double num) {
|
||||
return (int)(num + .5);
|
||||
}
|
||||
|
||||
/// @brief Set target to timecodes
|
||||
/// @param target
|
||||
/// @return
|
||||
///
|
||||
void MatroskaWrapper::SetToTimecodes(FrameRate &target) {
|
||||
// Enough frames?
|
||||
int frames = timecodes.size();
|
||||
if (frames <= 1) return;
|
||||
void MatroskaWrapper::SetToTimecodes(agi::vfr::Framerate &target) {
|
||||
if (timecodes.size() <= 1) return;
|
||||
|
||||
// Sort
|
||||
//std::sort<std::vector<double>::iterator>(timecodes.begin(),timecodes.end());
|
||||
|
||||
// Check if it's CFR
|
||||
/*
|
||||
bool isCFR = true;
|
||||
double estimateCFR = timecodes.back() / (timecodes.size()-1);
|
||||
double t1,t2;
|
||||
for (int i=1;i<frames;i++) {
|
||||
t1 = timecodes[i];
|
||||
t2 = timecodes[i-1];
|
||||
int delta = abs(int(t1 - t2 - estimateCFR));
|
||||
if (delta > 2) {
|
||||
isCFR = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
bool isCFR = false;
|
||||
double estimateCFR = 0;
|
||||
|
||||
// Constant framerate
|
||||
if (isCFR) {
|
||||
estimateCFR = 1/estimateCFR * 1000.0;
|
||||
if (fabs(estimateCFR - 24000.0/1001.0) < 0.02) estimateCFR = 24000.0 / 1001.0;
|
||||
if (fabs(estimateCFR - 30000.0/1001.0) < 0.02) estimateCFR = 30000.0 / 1001.0;
|
||||
target.SetCFR(estimateCFR);
|
||||
}
|
||||
|
||||
// Variable framerate
|
||||
else {
|
||||
std::vector<int> times;
|
||||
for (int i=0;i<frames;i++) times.push_back(int(timecodes[i]+0.5));
|
||||
target.SetVFR(times);
|
||||
}
|
||||
std::vector<int> times;
|
||||
times.reserve(timecodes.size());
|
||||
std::transform(timecodes.begin(), timecodes.end(), std::back_inserter(times), &mkv_round);
|
||||
target = agi::vfr::Framerate(times);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -34,11 +34,6 @@
|
|||
/// @ingroup video_input
|
||||
///
|
||||
|
||||
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#ifndef AGI_PRE
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
@ -48,14 +43,9 @@
|
|||
#endif
|
||||
|
||||
#include "MatroskaParser.h"
|
||||
#include "vfr.h"
|
||||
|
||||
|
||||
//////////////
|
||||
// Prototypes
|
||||
class AssFile;
|
||||
|
||||
|
||||
namespace agi { namespace vfr { class Framerate; } }
|
||||
|
||||
/// DOCME
|
||||
/// @class MkvStdIO
|
||||
|
@ -161,7 +151,7 @@ public:
|
|||
void Close();
|
||||
void Parse();
|
||||
|
||||
void SetToTimecodes(FrameRate &target);
|
||||
void SetToTimecodes(agi::vfr::Framerate &target);
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
|
|
|
@ -299,9 +299,6 @@ void SubsEditBox::Update (bool timeOnly,bool weak) {
|
|||
// Audio
|
||||
if (!weak) audio->SetDialogue(grid,curdiag,grid->GetDialogueIndex(curdiag));
|
||||
|
||||
// Video
|
||||
VideoContext::Get()->curLine = curdiag;
|
||||
|
||||
TextEdit->EmptyUndoBuffer();
|
||||
}
|
||||
else enabled = false;
|
||||
|
@ -550,7 +547,7 @@ void SubsEditBox::SetControlsState (bool state) {
|
|||
/// @brief Disables or enables frame timing
|
||||
///
|
||||
void SubsEditBox::UpdateFrameTiming () {
|
||||
if (VideoContext::Get()->IsLoaded()) ByFrame->Enable(enabled);
|
||||
if (VideoContext::Get()->TimecodesLoaded()) ByFrame->Enable(enabled);
|
||||
else {
|
||||
ByFrame->Enable(false);
|
||||
ByTime->SetValue(true);
|
||||
|
|
|
@ -34,9 +34,6 @@
|
|||
/// @ingroup main_ui
|
||||
///
|
||||
|
||||
|
||||
////////////
|
||||
// Includes
|
||||
#include "config.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
|
@ -61,13 +58,9 @@
|
|||
#include "subs_edit_box.h"
|
||||
#include "subs_grid.h"
|
||||
#include "utils.h"
|
||||
#include "vfr.h"
|
||||
#include "video_context.h"
|
||||
#include "video_display.h"
|
||||
|
||||
|
||||
///////////////
|
||||
// Event table
|
||||
BEGIN_EVENT_TABLE(SubtitlesGrid, BaseGrid)
|
||||
EVT_KEY_DOWN(SubtitlesGrid::OnKeyDown)
|
||||
EVT_MENU(MENU_SWAP,SubtitlesGrid::OnSwap)
|
||||
|
@ -171,14 +164,14 @@ void SubtitlesGrid::OnPopupMenu(bool alternate) {
|
|||
state = (sels == 1);
|
||||
menu.Append(MENU_INSERT_BEFORE,_("&Insert (before)"),_T("Inserts a line before current"))->Enable(state);
|
||||
menu.Append(MENU_INSERT_AFTER,_("Insert (after)"),_T("Inserts a line after current"))->Enable(state);
|
||||
state = (sels == 1 && VideoContext::Get()->IsLoaded());
|
||||
state = (sels == 1 && context->IsLoaded());
|
||||
menu.Append(MENU_INSERT_BEFORE_VIDEO,_("Insert at video time (before)"),_T("Inserts a line after current, starting at video time"))->Enable(state);
|
||||
menu.Append(MENU_INSERT_AFTER_VIDEO,_("Insert at video time (after)"),_T("Inserts a line after current, starting at video time"))->Enable(state);
|
||||
menu.AppendSeparator();
|
||||
|
||||
// Duplicate selection
|
||||
menu.Append(MENU_DUPLICATE,_("&Duplicate"),_("Duplicate the selected lines"))->Enable(continuous);
|
||||
menu.Append(MENU_DUPLICATE_NEXT_FRAME,_("&Duplicate and shift by 1 frame"),_("Duplicate lines and shift by one frame"))->Enable(continuous && VFR_Output.IsLoaded());
|
||||
menu.Append(MENU_DUPLICATE_NEXT_FRAME,_("&Duplicate and shift by 1 frame"),_("Duplicate lines and shift by one frame"))->Enable(continuous && context->TimecodesLoaded());
|
||||
menu.Append(MENU_SPLIT_BY_KARAOKE,_("Split (by karaoke)"),_("Uses karaoke timing to split line into multiple smaller lines"))->Enable(sels > 0);
|
||||
|
||||
// Swaps selection
|
||||
|
@ -318,7 +311,7 @@ void SubtitlesGrid::OnKeyDown(wxKeyEvent &event) {
|
|||
}
|
||||
|
||||
// Duplicate and shift
|
||||
if (VFR_Output.IsLoaded()) {
|
||||
if (context->TimecodesLoaded()) {
|
||||
if (Hotkeys.IsPressed(_T("Grid duplicate and shift one frame"))) {
|
||||
DuplicateLines(n,n2,true);
|
||||
return;
|
||||
|
@ -518,7 +511,7 @@ void SubtitlesGrid::OnInsertBeforeVideo (wxCommandEvent &event) {
|
|||
|
||||
// Create line to add
|
||||
AssDialogue *def = new AssDialogue;
|
||||
int video_ms = VFR_Output.GetTimeAtFrame(VideoContext::Get()->GetFrameN(),true);
|
||||
int video_ms = context->TimeAtFrame(context->GetFrameN(),agi::vfr::START);
|
||||
def->Start.SetMS(video_ms);
|
||||
def->End.SetMS(video_ms+OPT_GET("Timing/Default Duration")->GetInt());
|
||||
def->Style = GetDialogue(n)->Style;
|
||||
|
@ -542,7 +535,7 @@ void SubtitlesGrid::OnInsertAfterVideo (wxCommandEvent &event) {
|
|||
|
||||
// Create line to add
|
||||
AssDialogue *def = new AssDialogue;
|
||||
int video_ms = VFR_Output.GetTimeAtFrame(VideoContext::Get()->GetFrameN(),true);
|
||||
int video_ms = context->TimeAtFrame(context->GetFrameN(),agi::vfr::START);
|
||||
def->Start.SetMS(video_ms);
|
||||
def->End.SetMS(video_ms+OPT_GET("Timing/Default Duration")->GetInt());
|
||||
def->Style = GetDialogue(n)->Style;
|
||||
|
@ -819,7 +812,6 @@ void SubtitlesGrid::ClearMaps() {
|
|||
void SubtitlesGrid::UpdateMaps() {
|
||||
BeginBatch();
|
||||
|
||||
VideoContext::Get()->curLine = NULL;
|
||||
line_iter_map.clear();
|
||||
BaseGrid::ClearMaps();
|
||||
|
||||
|
@ -1244,9 +1236,9 @@ void SubtitlesGrid::DuplicateLines(int n1,int n2,bool nextFrame) {
|
|||
|
||||
// Shift to next frame
|
||||
if (nextFrame) {
|
||||
int posFrame = VFR_Output.GetFrameAtTime(cur->End.GetMS(),false) + 1;
|
||||
cur->Start.SetMS(VFR_Output.GetTimeAtFrame(posFrame,true));
|
||||
cur->End.SetMS(VFR_Output.GetTimeAtFrame(posFrame,false));
|
||||
int posFrame = context->FrameAtTime(cur->End.GetMS(),agi::vfr::END) + 1;
|
||||
cur->Start.SetMS(context->TimeAtFrame(posFrame,agi::vfr::START));
|
||||
cur->End.SetMS(context->TimeAtFrame(posFrame,agi::vfr::END));
|
||||
}
|
||||
|
||||
// Insert
|
||||
|
@ -1292,8 +1284,8 @@ void SubtitlesGrid::ShiftLineByTime(int n,int len,int type) {
|
|||
void SubtitlesGrid::ShiftLineByFrames(int n,int len,int type) {
|
||||
AssDialogue *cur = GetDialogue(n);
|
||||
|
||||
if (type != 2) cur->Start.SetMS(VFR_Output.GetTimeAtFrame(len + VFR_Output.GetFrameAtTime(cur->Start.GetMS(),true),true));
|
||||
if (type != 1) cur->End.SetMS(VFR_Output.GetTimeAtFrame(len + VFR_Output.GetFrameAtTime(cur->End.GetMS(),false),false));
|
||||
if (type != 2) cur->Start.SetMS(context->TimeAtFrame(len + context->FrameAtTime(cur->Start.GetMS(),agi::vfr::START),agi::vfr::START));
|
||||
if (type != 1) cur->End.SetMS(context->TimeAtFrame(len + context->FrameAtTime(cur->End.GetMS(),agi::vfr::END),agi::vfr::END));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1394,19 +1386,19 @@ bool SubtitlesGrid::SplitLineByKaraoke(int lineNumber) {
|
|||
/// @param videoOnly
|
||||
///
|
||||
void SubtitlesGrid::CommitChanges(bool force,bool videoOnly) {
|
||||
if (VideoContext::Get()->IsLoaded() || force) {
|
||||
if (context->IsLoaded() || force) {
|
||||
// Check if it's playing
|
||||
bool playing = false;
|
||||
if (VideoContext::Get()->IsPlaying()) {
|
||||
if (context->IsPlaying()) {
|
||||
playing = true;
|
||||
VideoContext::Get()->Stop();
|
||||
context->Stop();
|
||||
}
|
||||
|
||||
// Update video
|
||||
if (VideoContext::Get()->IsLoaded()) VideoContext::Get()->Refresh();
|
||||
if (context->IsLoaded()) context->Refresh();
|
||||
|
||||
// Resume play
|
||||
if (playing) VideoContext::Get()->Play();
|
||||
if (playing) context->Play();
|
||||
}
|
||||
|
||||
if (!videoOnly) {
|
||||
|
@ -1422,18 +1414,15 @@ void SubtitlesGrid::CommitChanges(bool force,bool videoOnly) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Set start to video pos
|
||||
/// @param start
|
||||
/// @return
|
||||
///
|
||||
void SubtitlesGrid::SetSubsToVideo(bool start) {
|
||||
// Check if it's OK to do it
|
||||
if (!VFR_Output.IsLoaded()) return;
|
||||
if (!context->IsLoaded()) return;
|
||||
|
||||
// Get new time
|
||||
int ms = VFR_Output.GetTimeAtFrame(VideoContext::Get()->GetFrameN(),start);
|
||||
int ms = context->TimeAtFrame(context->GetFrameN(),start ? agi::vfr::START : agi::vfr::END);
|
||||
|
||||
// Update selection
|
||||
wxArrayInt sel = GetSelection();
|
||||
|
@ -1468,9 +1457,9 @@ void SubtitlesGrid::SetVideoToSubs(bool start) {
|
|||
AssDialogue *cur = GetDialogue(sel[0]);
|
||||
if (cur) {
|
||||
if (start)
|
||||
VideoContext::Get()->JumpToTime(cur->Start.GetMS());
|
||||
context->JumpToTime(cur->Start.GetMS());
|
||||
else
|
||||
VideoContext::Get()->JumpToFrame(VFR_Output.GetFrameAtTime(cur->End.GetMS(),false));
|
||||
context->JumpToTime(cur->End.GetMS(), agi::vfr::END);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,11 +34,6 @@
|
|||
/// @ingroup main_ui
|
||||
///
|
||||
|
||||
|
||||
|
||||
|
||||
////////////
|
||||
// Includes
|
||||
#ifndef AGI_PRE
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
@ -54,9 +49,6 @@
|
|||
#include "audio_provider_manager.h"
|
||||
#include "base_grid.h"
|
||||
|
||||
|
||||
//////////////
|
||||
// Prototypes
|
||||
class AssFile;
|
||||
class AssEntry;
|
||||
class AssDialogue;
|
||||
|
@ -64,13 +56,9 @@ class SubsEditBox;
|
|||
class FrameMain;
|
||||
class AudioDisplay;
|
||||
|
||||
|
||||
|
||||
/// DOCME
|
||||
typedef std::list<AssEntry*>::iterator entryIter;
|
||||
|
||||
|
||||
|
||||
/// DOCME
|
||||
/// @class SubtitlesGrid
|
||||
/// @brief DOCME
|
||||
|
|
|
@ -34,9 +34,6 @@
|
|||
/// @ingroup subtitle_io
|
||||
///
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#include "config.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
|
@ -55,8 +52,7 @@
|
|||
#include "subtitle_format_transtation.h"
|
||||
#include "subtitle_format_ttxt.h"
|
||||
#include "subtitle_format_txt.h"
|
||||
#include "vfr.h"
|
||||
|
||||
#include "video_context.h"
|
||||
|
||||
/// @brief Constructor
|
||||
///
|
||||
|
@ -66,24 +62,18 @@ SubtitleFormat::SubtitleFormat() {
|
|||
isCopy = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Destructor
|
||||
///
|
||||
SubtitleFormat::~SubtitleFormat () {
|
||||
Remove();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// DOCME
|
||||
std::list<SubtitleFormat*> SubtitleFormat::formats;
|
||||
|
||||
/// DOCME
|
||||
bool SubtitleFormat::loaded = false;
|
||||
|
||||
|
||||
|
||||
/// @brief Set target
|
||||
/// @param file
|
||||
///
|
||||
|
@ -94,8 +84,6 @@ void SubtitleFormat::SetTarget(AssFile *file) {
|
|||
assFile = file;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Create copy
|
||||
///
|
||||
void SubtitleFormat::CreateCopy() {
|
||||
|
@ -103,8 +91,6 @@ void SubtitleFormat::CreateCopy() {
|
|||
isCopy = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Clear copy
|
||||
///
|
||||
void SubtitleFormat::ClearCopy() {
|
||||
|
@ -115,16 +101,12 @@ void SubtitleFormat::ClearCopy() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Clear subtitles
|
||||
///
|
||||
void SubtitleFormat::Clear() {
|
||||
assFile->Clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Load default
|
||||
/// @param defline
|
||||
///
|
||||
|
@ -132,8 +114,6 @@ void SubtitleFormat::LoadDefault(bool defline) {
|
|||
assFile->LoadDefault(defline);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Add line
|
||||
/// @param data
|
||||
/// @param group
|
||||
|
@ -143,8 +123,6 @@ void SubtitleFormat::AddLine(wxString data,wxString group,int &version,wxString
|
|||
assFile->AddLine(data,group,version,outgroup);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Add formats
|
||||
///
|
||||
void SubtitleFormat::LoadFormats () {
|
||||
|
@ -164,8 +142,6 @@ void SubtitleFormat::LoadFormats () {
|
|||
loaded = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Destroy formats
|
||||
///
|
||||
void SubtitleFormat::DestroyFormats () {
|
||||
|
@ -176,8 +152,6 @@ void SubtitleFormat::DestroyFormats () {
|
|||
formats.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Get an appropriate reader
|
||||
/// @param filename
|
||||
/// @return
|
||||
|
@ -193,8 +167,6 @@ SubtitleFormat *SubtitleFormat::GetReader(wxString filename) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Get an appropriate writer
|
||||
/// @param filename
|
||||
/// @return
|
||||
|
@ -210,8 +182,6 @@ SubtitleFormat *SubtitleFormat::GetWriter(wxString filename) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Register
|
||||
/// @return
|
||||
///
|
||||
|
@ -223,8 +193,6 @@ void SubtitleFormat::Register() {
|
|||
formats.push_back(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Remove
|
||||
/// @return
|
||||
///
|
||||
|
@ -238,8 +206,6 @@ void SubtitleFormat::Remove() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Get read wildcards
|
||||
/// @return
|
||||
///
|
||||
|
@ -247,8 +213,6 @@ wxArrayString SubtitleFormat::GetReadWildcards() {
|
|||
return wxArrayString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Get write wildcards
|
||||
/// @return
|
||||
///
|
||||
|
@ -256,8 +220,6 @@ wxArrayString SubtitleFormat::GetWriteWildcards() {
|
|||
return wxArrayString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Get wildcard list
|
||||
/// @param mode
|
||||
/// @return
|
||||
|
@ -313,8 +275,6 @@ wxString SubtitleFormat::GetWildcards(int mode) {
|
|||
return final;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Ask the user to enter the FPS
|
||||
/// @param showSMPTE
|
||||
/// @return
|
||||
|
@ -325,11 +285,12 @@ SubtitleFormat::FPSRational SubtitleFormat::AskForFPS(bool showSMPTE) {
|
|||
fps_rat.smpte_dropframe = false; // ensure it's false by default
|
||||
|
||||
// Video FPS
|
||||
bool vidLoaded = VFR_Output.IsLoaded();
|
||||
VideoContext *context = VideoContext::Get();
|
||||
bool vidLoaded = context->TimecodesLoaded();
|
||||
if (vidLoaded) {
|
||||
wxString vidFPS;
|
||||
if (VFR_Output.GetFrameRateType() == VFR) vidFPS = _T("VFR");
|
||||
else vidFPS = wxString::Format(_T("%.3f"),VFR_Output.GetAverage());
|
||||
if (context->FPS().IsVFR()) vidFPS = _T("VFR");
|
||||
else vidFPS = wxString::Format(_T("%.3f"),context->FPS().FPS());
|
||||
choices.Add(wxString::Format(_T("From video (%s)"),vidFPS.c_str()));
|
||||
}
|
||||
|
||||
|
@ -403,16 +364,12 @@ SubtitleFormat::FPSRational SubtitleFormat::AskForFPS(bool showSMPTE) {
|
|||
return fps_rat;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Sort lines
|
||||
///
|
||||
void SubtitleFormat::SortLines() {
|
||||
AssFile::Sort(*Line);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Convert tags
|
||||
/// @param format
|
||||
/// @param lineEnd
|
||||
|
@ -438,8 +395,6 @@ void SubtitleFormat::ConvertTags(int format,const wxString &lineEnd,bool mergeLi
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Remove all comment lines
|
||||
///
|
||||
void SubtitleFormat::StripComments() {
|
||||
|
@ -458,8 +413,6 @@ void SubtitleFormat::StripComments() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Remove all non-dialogue lines
|
||||
///
|
||||
void SubtitleFormat::StripNonDialogue() {
|
||||
|
@ -477,8 +430,6 @@ void SubtitleFormat::StripNonDialogue() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Helper function for RecombineOverlaps()
|
||||
/// @param list
|
||||
/// @param next
|
||||
|
@ -501,7 +452,6 @@ static void InsertLineSortedIntoList(std::list<AssEntry*> &list, std::list<AssEn
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// @brief Split and merge lines so there are no overlapping lines
|
||||
///
|
||||
/// Algorithm described at http://devel.aegisub.org/wiki/Technical/SplitMerge
|
||||
|
@ -580,8 +530,6 @@ void SubtitleFormat::RecombineOverlaps() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Merge identical lines that follow each other
|
||||
///
|
||||
void SubtitleFormat::MergeIdentical() {
|
||||
|
@ -608,6 +556,3 @@ void SubtitleFormat::MergeIdentical() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -34,12 +34,8 @@
|
|||
/// @ingroup subtitle_io
|
||||
///
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#ifndef AGI_PRE
|
||||
#include <list>
|
||||
|
||||
|
@ -49,22 +45,15 @@
|
|||
|
||||
#include <libaegisub/exception.h>
|
||||
|
||||
|
||||
//////////////
|
||||
// Prototypes
|
||||
class AssFile;
|
||||
class AssEntry;
|
||||
|
||||
|
||||
|
||||
/// DOCME
|
||||
/// @class SubtitleFormat
|
||||
/// @brief DOCME
|
||||
///
|
||||
/// DOCME
|
||||
class SubtitleFormat {
|
||||
private:
|
||||
|
||||
/// DOCME
|
||||
bool isCopy;
|
||||
|
||||
|
@ -74,7 +63,6 @@ private:
|
|||
void Register();
|
||||
void Remove();
|
||||
|
||||
|
||||
/// DOCME
|
||||
static std::list<SubtitleFormat*> formats;
|
||||
|
||||
|
@ -82,7 +70,6 @@ private:
|
|||
static bool loaded;
|
||||
|
||||
protected:
|
||||
|
||||
/// DOCME
|
||||
struct FPSRational {
|
||||
|
||||
|
@ -96,7 +83,6 @@ protected:
|
|||
bool smpte_dropframe;
|
||||
};
|
||||
|
||||
|
||||
/// DOCME
|
||||
std::list<AssEntry*> *Line;
|
||||
|
||||
|
@ -131,7 +117,6 @@ public:
|
|||
|
||||
static wxString GetWildcards(int mode);
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @param filename
|
||||
/// @return
|
||||
|
@ -162,6 +147,4 @@ public:
|
|||
static void DestroyFormats();
|
||||
};
|
||||
|
||||
|
||||
DEFINE_SIMPLE_EXCEPTION(SubtitleFormatParseError, agi::InvalidInputException, "subtitle_io/parse/generic")
|
||||
|
||||
|
|
|
@ -34,9 +34,6 @@
|
|||
/// @ingroup subtitle_io
|
||||
///
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#include "config.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
|
@ -48,42 +45,22 @@
|
|||
#include "subtitle_format_microdvd.h"
|
||||
#include "text_file_reader.h"
|
||||
#include "text_file_writer.h"
|
||||
#include "vfr.h"
|
||||
#include "video_context.h"
|
||||
|
||||
|
||||
/// @brief Get format name
|
||||
/// @return
|
||||
///
|
||||
wxString MicroDVDSubtitleFormat::GetName() {
|
||||
return _T("MicroDVD");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Get read wildcards
|
||||
/// @return
|
||||
///
|
||||
wxArrayString MicroDVDSubtitleFormat::GetReadWildcards() {
|
||||
wxArrayString formats;
|
||||
formats.Add(_T("sub"));
|
||||
return formats;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Get write wildcards
|
||||
/// @return
|
||||
///
|
||||
wxArrayString MicroDVDSubtitleFormat::GetWriteWildcards() {
|
||||
return GetReadWildcards();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Can read a file?
|
||||
/// @param filename
|
||||
/// @return
|
||||
///
|
||||
bool MicroDVDSubtitleFormat::CanReadFile(wxString filename) {
|
||||
// Return false immediately if extension is wrong
|
||||
if (filename.Right(4).Lower() != _T(".sub")) return false;
|
||||
|
@ -98,43 +75,25 @@ bool MicroDVDSubtitleFormat::CanReadFile(wxString filename) {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Can write a file?
|
||||
/// @param filename
|
||||
/// @return
|
||||
///
|
||||
bool MicroDVDSubtitleFormat::CanWriteFile(wxString filename) {
|
||||
return (filename.Right(4).Lower() == _T(".sub"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Read a file
|
||||
/// @param filename
|
||||
/// @param forceEncoding
|
||||
/// @return
|
||||
///
|
||||
void MicroDVDSubtitleFormat::ReadFile(wxString filename,wxString forceEncoding) {
|
||||
// Load and prepare regexp
|
||||
TextFileReader file(filename);
|
||||
wxRegEx exp(_T("^[\\{\\[]([0-9]+)[\\}\\]][\\{\\[]([0-9]+)[\\}\\]](.*)$"),wxRE_ADVANCED);
|
||||
|
||||
// Load default
|
||||
LoadDefault(false);
|
||||
|
||||
// Prepare conversion
|
||||
FrameRate cfr;
|
||||
FrameRate *rate = 𝔠
|
||||
agi::vfr::Framerate cfr;
|
||||
const agi::vfr::Framerate *rate = 𝔠
|
||||
|
||||
// Loop
|
||||
bool isFirst = true;
|
||||
FPSRational fps_rat;
|
||||
double fps = 0.0;
|
||||
while (file.HasMoreLines()) {
|
||||
wxString line = file.ReadLineFromFile();
|
||||
if (exp.Matches(line)) {
|
||||
// Parse
|
||||
long f1,f2;
|
||||
exp.GetMatch(line,1).ToLong(&f1);
|
||||
exp.GetMatch(line,2).ToLong(&f2);
|
||||
|
@ -147,7 +106,7 @@ void MicroDVDSubtitleFormat::ReadFile(wxString filename,wxString forceEncoding)
|
|||
try {
|
||||
text.ToDouble(&fps);
|
||||
}
|
||||
catch (...) {}
|
||||
catch (...) { }
|
||||
}
|
||||
isFirst = false;
|
||||
|
||||
|
@ -155,24 +114,22 @@ void MicroDVDSubtitleFormat::ReadFile(wxString filename,wxString forceEncoding)
|
|||
if (fps <= 0.0) {
|
||||
fps_rat = AskForFPS();
|
||||
if (fps_rat.num == 0) return;
|
||||
else if (fps_rat.num > 0) cfr.SetCFR(double(fps_rat.num)/double(fps_rat.den));
|
||||
else rate = &VFR_Output;
|
||||
else if (fps_rat.num > 0) cfr = double(fps_rat.num)/fps_rat.den;
|
||||
else rate = &VideoContext::Get()->FPS();
|
||||
}
|
||||
else {
|
||||
cfr.SetCFR(fps);
|
||||
cfr = fps;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Start and end times
|
||||
int start,end;
|
||||
start = rate->GetTimeAtFrame(f1,true);
|
||||
end = rate->GetTimeAtFrame(f2,false);
|
||||
start = rate->TimeAtFrame(f1,agi::vfr::START);
|
||||
end = rate->TimeAtFrame(f2,agi::vfr::END);
|
||||
|
||||
// Process text
|
||||
text.Replace(_T("|"),_T("\\N"));
|
||||
|
||||
// Create and insert line
|
||||
AssDialogue *line = new AssDialogue();
|
||||
line->group = _T("[Events]");
|
||||
line->Style = _T("Default");
|
||||
|
@ -184,21 +141,15 @@ void MicroDVDSubtitleFormat::ReadFile(wxString filename,wxString forceEncoding)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Write a file
|
||||
/// @param filename
|
||||
/// @param encoding
|
||||
///
|
||||
void MicroDVDSubtitleFormat::WriteFile(wxString filename,wxString encoding) {
|
||||
// Set FPS
|
||||
FrameRate cfr;
|
||||
FrameRate *rate = 𝔠
|
||||
agi::vfr::Framerate cfr;
|
||||
const agi::vfr::Framerate *rate = 𝔠
|
||||
|
||||
FPSRational fps_rat = AskForFPS();
|
||||
if (fps_rat.num == 0 || fps_rat.den == 0) return;
|
||||
double fps = double(fps_rat.num) / double(fps_rat.den);
|
||||
if (fps > 0.0) cfr.SetCFR(fps);
|
||||
else rate = &VFR_Output;
|
||||
double fps = double(fps_rat.num) / fps_rat.den;
|
||||
if (fps > 0.0) cfr = fps;
|
||||
else rate = &VideoContext::Get()->FPS();
|
||||
|
||||
// Convert file
|
||||
CreateCopy();
|
||||
|
@ -208,12 +159,11 @@ void MicroDVDSubtitleFormat::WriteFile(wxString filename,wxString encoding) {
|
|||
MergeIdentical();
|
||||
ConvertTags(1,_T("|"));
|
||||
|
||||
// Open file
|
||||
TextFileWriter file(filename,encoding);
|
||||
|
||||
// Write FPS line
|
||||
if (rate->GetFrameRateType() != VFR) {
|
||||
file.WriteLineToFile(wxString::Format(_T("{1}{1}%.6f"),rate->GetAverage()));
|
||||
if (!rate->IsVFR()) {
|
||||
file.WriteLineToFile(wxString::Format(_T("{1}{1}%.6f"),rate->FPS()));
|
||||
}
|
||||
|
||||
// Write lines
|
||||
|
@ -221,17 +171,12 @@ void MicroDVDSubtitleFormat::WriteFile(wxString filename,wxString encoding) {
|
|||
for (list<AssEntry*>::iterator cur=Line->begin();cur!=Line->end();cur++) {
|
||||
AssDialogue *current = dynamic_cast<AssDialogue*>(*cur);
|
||||
if (current && !current->Comment) {
|
||||
// Prepare data
|
||||
int start = rate->GetFrameAtTime(current->Start.GetMS(),true);
|
||||
int end = rate->GetFrameAtTime(current->End.GetMS(),false);
|
||||
int start = rate->FrameAtTime(current->Start.GetMS(),agi::vfr::START);
|
||||
int end = rate->FrameAtTime(current->End.GetMS(),agi::vfr::END);
|
||||
|
||||
// Write data
|
||||
file.WriteLineToFile(wxString::Format(_T("{%i}{%i}%s"),start,end,current->Text.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
ClearCopy();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -34,14 +34,8 @@
|
|||
/// @ingroup subtitle_io
|
||||
///
|
||||
|
||||
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#include "subtitle_format.h"
|
||||
|
||||
|
||||
/// DOCME
|
||||
/// @class MicroDVDSubtitleFormat
|
||||
/// @brief DOCME
|
||||
|
@ -59,5 +53,3 @@ public:
|
|||
bool CanWriteFile(wxString filename);
|
||||
void WriteFile(wxString filename,wxString encoding);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
#include "text_file_writer.h"
|
||||
#include "video_context.h"
|
||||
|
||||
|
||||
/// @brief Constructor
|
||||
/// @param type
|
||||
///
|
||||
|
@ -56,17 +55,14 @@ CSRISubtitlesProvider::CSRISubtitlesProvider(wxString type) {
|
|||
instance = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Destructor
|
||||
///
|
||||
CSRISubtitlesProvider::~CSRISubtitlesProvider() {
|
||||
if (!tempfile.empty()) wxRemoveFile(tempfile);
|
||||
if (instance) csri_close(instance);
|
||||
instance = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Load subtitles
|
||||
/// @param subs
|
||||
///
|
||||
|
@ -108,14 +104,16 @@ void CSRISubtitlesProvider::LoadSubtitles(AssFile *subs) {
|
|||
|
||||
// Open from disk
|
||||
else {
|
||||
wxString subsFileName = VideoContext::Get()->GetTempWorkFile();
|
||||
subs->Save(subsFileName,false,false,wxSTRING_ENCODING);
|
||||
instance = csri_open_file(renderer,subsFileName.mb_str(wxConvUTF8),NULL);
|
||||
if (tempfile.empty()) {
|
||||
tempfile = wxFileName::CreateTempFileName(_T("aegisub"));
|
||||
wxRemoveFile(tempfile);
|
||||
tempfile += L".ass";
|
||||
}
|
||||
subs->Save(tempfile,false,false,wxSTRING_ENCODING);
|
||||
instance = csri_open_file(renderer,tempfile.utf8_str(),NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Draw subtitles
|
||||
/// @param dst
|
||||
/// @param time
|
||||
|
@ -155,8 +153,6 @@ void CSRISubtitlesProvider::DrawSubtitles(AegiVideoFrame &dst,double time) {
|
|||
csri_render(instance,&frame,time);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Get CSRI subtypes
|
||||
///
|
||||
wxArrayString CSRISubtitlesProviderFactory::GetSubTypes() {
|
||||
|
@ -179,7 +175,4 @@ wxArrayString CSRISubtitlesProviderFactory::GetSubTypes() {
|
|||
return final;
|
||||
}
|
||||
|
||||
|
||||
#endif // WITH_CSRI
|
||||
|
||||
|
||||
|
|
|
@ -34,15 +34,10 @@
|
|||
/// @ingroup subtitle_rendering
|
||||
///
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
|
||||
#ifdef WITH_CSRI
|
||||
|
||||
#include "include/aegisub/subtitles_provider.h"
|
||||
#ifdef WIN32
|
||||
|
||||
/// DOCME
|
||||
#define CSRIAPI
|
||||
#endif
|
||||
|
@ -53,21 +48,19 @@
|
|||
#include <csri/csri.h>
|
||||
#endif
|
||||
|
||||
|
||||
/// DOCME
|
||||
/// @class CSRISubtitlesProvider
|
||||
/// @brief DOCME
|
||||
///
|
||||
/// DOCME
|
||||
class CSRISubtitlesProvider : public SubtitlesProvider {
|
||||
private:
|
||||
|
||||
/// DOCME
|
||||
wxString subType;
|
||||
|
||||
/// DOCME
|
||||
csri_inst *instance;
|
||||
|
||||
wxString tempfile;
|
||||
public:
|
||||
CSRISubtitlesProvider(wxString subType);
|
||||
~CSRISubtitlesProvider();
|
||||
|
@ -76,8 +69,6 @@ public:
|
|||
void DrawSubtitles(AegiVideoFrame &dst,double time);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// DOCME
|
||||
/// @class CSRISubtitlesProviderFactory
|
||||
/// @brief DOCME
|
||||
|
@ -85,7 +76,6 @@ public:
|
|||
/// DOCME
|
||||
class CSRISubtitlesProviderFactory : public SubtitlesProviderFactory {
|
||||
public:
|
||||
|
||||
/// @brief DOCME
|
||||
/// @param subType
|
||||
///
|
||||
|
@ -94,5 +84,3 @@ public:
|
|||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -34,9 +34,6 @@
|
|||
/// @ingroup custom_control
|
||||
///
|
||||
|
||||
|
||||
////////////
|
||||
// Includes
|
||||
#include "config.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
|
@ -51,8 +48,7 @@
|
|||
#include "main.h"
|
||||
#include "options.h"
|
||||
#include "timeedit_ctrl.h"
|
||||
#include "vfr.h"
|
||||
|
||||
#include "video_context.h"
|
||||
|
||||
#ifdef __WXGTK__
|
||||
/// Use the multiline style only on wxGTK to workaround some wxGTK bugs with the default singleline style.
|
||||
|
@ -63,7 +59,6 @@
|
|||
#define TimeEditWindowStyle wxTE_CENTRE
|
||||
#endif
|
||||
|
||||
|
||||
/// @brief Constructor
|
||||
/// @param parent
|
||||
/// @param id
|
||||
|
@ -114,9 +109,6 @@ wxTextCtrl(parent,id,value,pos,size,TimeEditWindowStyle | style,validator,name)
|
|||
Connect(wxEVT_KILL_FOCUS,wxFocusEventHandler(TimeEdit::OnKillFocus));
|
||||
}
|
||||
|
||||
|
||||
///////////////
|
||||
// Event table
|
||||
BEGIN_EVENT_TABLE(TimeEdit, wxTextCtrl)
|
||||
EVT_MOUSE_EVENTS(TimeEdit::OnMouseEvent)
|
||||
EVT_KEY_DOWN(TimeEdit::OnKeyDown)
|
||||
|
@ -124,30 +116,20 @@ BEGIN_EVENT_TABLE(TimeEdit, wxTextCtrl)
|
|||
EVT_MENU(Time_Edit_Paste,TimeEdit::OnPaste)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
|
||||
|
||||
/// @brief Modified event
|
||||
/// @param event
|
||||
/// @return
|
||||
///
|
||||
void TimeEdit::OnModified(wxCommandEvent &event) {
|
||||
event.Skip();
|
||||
if (!ready) return;
|
||||
Modified();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Modified function
|
||||
/// @param byUser
|
||||
/// @return
|
||||
///
|
||||
void TimeEdit::Modified(bool byUser) {
|
||||
// Lock
|
||||
if (!ready) return;
|
||||
ready = false;
|
||||
|
||||
// Update
|
||||
if (byFrame) Update();
|
||||
else UpdateTime(byUser);
|
||||
|
||||
|
@ -156,13 +138,9 @@ void TimeEdit::Modified(bool byUser) {
|
|||
SetBackgroundColour(lagi_wxColour(OPT_GET("Colour/Background/Modified")->GetColour()));
|
||||
}
|
||||
modified = true;
|
||||
|
||||
// Done
|
||||
ready = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Set time and update stuff
|
||||
/// @param ms
|
||||
/// @param setModified
|
||||
|
@ -174,18 +152,14 @@ void TimeEdit::SetTime(int ms,bool setModified) {
|
|||
if (setModified && oldMs != ms) Modified(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Toggles between set by frame and time
|
||||
/// @param enable
|
||||
/// @return
|
||||
///
|
||||
void TimeEdit::SetByFrame(bool enable) {
|
||||
if (enable == byFrame) return;
|
||||
|
||||
// By frames
|
||||
if (enable) {
|
||||
if (VFR_Output.IsLoaded()) {
|
||||
if (VideoContext::Get()->IsLoaded()) {
|
||||
byFrame = true;
|
||||
UpdateText();
|
||||
}
|
||||
|
@ -198,22 +172,18 @@ void TimeEdit::SetByFrame(bool enable) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Update text to reflect time value
|
||||
///
|
||||
void TimeEdit::UpdateText() {
|
||||
ready = false;
|
||||
if (byFrame) {
|
||||
int frame_n = VFR_Output.GetFrameAtTime(time.GetMS(),!isEnd);
|
||||
int frame_n = VideoContext::Get()->FrameAtTime(time.GetMS(),isEnd ? agi::vfr::END : agi::vfr::START);
|
||||
SetValue(wxString::Format(_T("%i"),frame_n));
|
||||
}
|
||||
else SetValue(time.GetASSFormated());
|
||||
ready = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Update
|
||||
///
|
||||
void TimeEdit::Update() {
|
||||
|
@ -221,7 +191,7 @@ void TimeEdit::Update() {
|
|||
if (byFrame) {
|
||||
long temp;
|
||||
GetValue().ToLong(&temp);
|
||||
time.SetMS(VFR_Output.GetTimeAtFrame(temp,!isEnd));
|
||||
time.SetMS(VideoContext::Get()->TimeAtFrame(temp,isEnd ? agi::vfr::END : agi::vfr::START));
|
||||
}
|
||||
|
||||
// Update time if not on insertion mode
|
||||
|
@ -238,8 +208,6 @@ void TimeEdit::Update() {
|
|||
modified = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Reads value from a text control and update it
|
||||
/// @param byUser
|
||||
///
|
||||
|
@ -273,8 +241,6 @@ void TimeEdit::UpdateTime(bool byUser) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Key pressed
|
||||
/// @param event
|
||||
///
|
||||
|
@ -316,8 +282,6 @@ void TimeEdit::OnKeyDown(wxKeyEvent &event) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Focus lost
|
||||
/// @param event
|
||||
///
|
||||
|
@ -331,14 +295,10 @@ void TimeEdit::OnKillFocus(wxFocusEvent &event) {
|
|||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
///// Mouse/copy/paste events down here /////
|
||||
|
||||
|
||||
/// @brief Mouse event
|
||||
/// @param event
|
||||
/// @return
|
||||
///
|
||||
void TimeEdit::OnMouseEvent(wxMouseEvent &event) {
|
||||
// Right click context menu
|
||||
if (event.RightUp()) {
|
||||
|
@ -355,8 +315,6 @@ void TimeEdit::OnMouseEvent(wxMouseEvent &event) {
|
|||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Menu Copy
|
||||
/// @param event
|
||||
///
|
||||
|
@ -367,8 +325,6 @@ void TimeEdit::OnCopy(wxCommandEvent &event) {
|
|||
Refresh();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Menu Paste
|
||||
/// @param event
|
||||
///
|
||||
|
@ -378,10 +334,7 @@ void TimeEdit::OnPaste(wxCommandEvent &event) {
|
|||
Refresh();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Copy to clipboard
|
||||
/// @return
|
||||
///
|
||||
void TimeEdit::CopyTime() {
|
||||
// Frame
|
||||
|
@ -397,8 +350,6 @@ void TimeEdit::CopyTime() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Paste from clipboard
|
||||
///
|
||||
void TimeEdit::PasteTime() {
|
||||
|
@ -432,5 +383,3 @@ void TimeEdit::PasteTime() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,393 +0,0 @@
|
|||
// Copyright (c) 2005-2006, Rodrigo Braz Monteiro, Fredrik Mellbin
|
||||
// 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 Project http://www.aegisub.org/
|
||||
//
|
||||
// $Id$
|
||||
|
||||
/// @file vfr.cpp
|
||||
/// @brief Handle variable frame rate files
|
||||
/// @ingroup video_input
|
||||
///
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#include <wx/filename.h>
|
||||
#endif
|
||||
|
||||
#include "compat.h"
|
||||
#include "main.h"
|
||||
#include "options.h"
|
||||
#include "text_file_reader.h"
|
||||
#include "text_file_writer.h"
|
||||
#include "utils.h"
|
||||
#include "vfr.h"
|
||||
|
||||
|
||||
/// @brief V2 Clear function
|
||||
void FrameRate::Clear () {
|
||||
Frame.clear();
|
||||
}
|
||||
|
||||
/// @brief V2 Add frame
|
||||
/// @param ms
|
||||
void FrameRate::AddFrame(int ms) {
|
||||
Frame.push_back(ms);
|
||||
}
|
||||
|
||||
/// @brief V2 Get Average
|
||||
void FrameRate::CalcAverage() {
|
||||
if (Frame.size() <= 1)
|
||||
throw _("No timecodes to average");
|
||||
|
||||
AverageFrameRate = double(Frame.back()) / (Frame.size()-1);
|
||||
}
|
||||
|
||||
/// @brief Constructor
|
||||
FrameRate::FrameRate() {
|
||||
Unload();
|
||||
}
|
||||
|
||||
/// @brief Destructor
|
||||
FrameRate::~FrameRate() {
|
||||
Unload();
|
||||
}
|
||||
|
||||
/// @brief Loads VFR file
|
||||
/// @param filename
|
||||
void FrameRate::Load(wxString filename) {
|
||||
using namespace std;
|
||||
|
||||
Unload();
|
||||
|
||||
// Check if file exists
|
||||
wxFileName filetest(filename);
|
||||
if (!filetest.FileExists()) throw _T("File not found.");
|
||||
|
||||
// Open file
|
||||
TextFileReader file(filename);
|
||||
|
||||
try {
|
||||
// Read header
|
||||
wxString curLine;
|
||||
curLine = file.ReadLineFromFile();
|
||||
wxString header = curLine;
|
||||
bool first = (header.Left(7).Lower() == _T("assume "));
|
||||
|
||||
// V1, code converted from avcvfr9
|
||||
if (header == _T("# timecode format v1") || first) {
|
||||
// Locate the default fps line
|
||||
do {
|
||||
// Get next line
|
||||
if (!first) curLine = file.ReadLineFromFile();
|
||||
first = false;
|
||||
|
||||
// Skip empty lines and comments
|
||||
if (curLine == _T("") || curLine.Left(1) == _T("#")) continue;
|
||||
|
||||
else if (curLine.Left(7).Lower() != _T("assume ")) throw _T("Encountered data before 'Assume <fps>' line");
|
||||
else {
|
||||
if (!curLine.Mid(6).ToDouble(&AverageFrameRate) || AverageFrameRate <= 0) throw _T("Invalid 'Assume <fps>' line");
|
||||
break;
|
||||
}
|
||||
} while (file.HasMoreLines());
|
||||
|
||||
// Read and expand all timecodes to v2
|
||||
wxString curline;
|
||||
|
||||
double currenttime = 0;
|
||||
int lposition = -1;
|
||||
|
||||
long lstart;
|
||||
long lend;
|
||||
double lfps;
|
||||
|
||||
while (file.HasMoreLines()) {
|
||||
curLine = file.ReadLineFromFile();
|
||||
|
||||
// Skip empty lines and comments
|
||||
if (curLine == _T("") || curLine.Left(1) == _T("#"))
|
||||
continue;
|
||||
|
||||
wxString tmp = curLine.AfterFirst(_T(','));
|
||||
wxString temp = curLine.BeforeFirst(_T(','));
|
||||
if (!temp.ToLong(&lstart) || lstart < 0)
|
||||
throw _T("Timecode parsing error, invalid start format found");
|
||||
temp = tmp.BeforeLast(_T(','));
|
||||
if (!temp.ToLong(&lend) || lend < 0)
|
||||
throw _T("Timecode parsing error, invalid end format found");
|
||||
temp = tmp.AfterLast(_T(','));
|
||||
if (!temp.ToDouble(&lfps) || lfps <= 0)
|
||||
throw _T("Timecode parsing error, invalid fps format found");
|
||||
|
||||
if (lstart <= lposition)
|
||||
throw _T("Timecode parsing error, out of order or overlapping timecode range found");
|
||||
|
||||
|
||||
for (int i = 0; i <= lstart - lposition - 2; i++)
|
||||
AddFrame((int)(floor(currenttime+(i*1000) / AverageFrameRate)));
|
||||
|
||||
currenttime += ((lstart - lposition - 1)*1000) / AverageFrameRate;
|
||||
|
||||
for (int i = 0; i <= lend - lstart; i++)
|
||||
AddFrame((int)(floor(currenttime+(i*1000) / lfps)));
|
||||
|
||||
currenttime += ((lend - lstart + 1)*1000) / lfps;
|
||||
|
||||
lposition = lend;
|
||||
}
|
||||
|
||||
AddFrame(currenttime);
|
||||
last_time = currenttime;
|
||||
last_frame = (int)Frame.size() - 1;
|
||||
}
|
||||
|
||||
// V2
|
||||
else if (header == _T("# timecode format v2")) {
|
||||
// Assigns new VFR file
|
||||
FrameRateType = VFR;
|
||||
|
||||
long lftime = -1;
|
||||
long cftime = 0;
|
||||
last_frame = 0;
|
||||
|
||||
// Reads body
|
||||
while (file.HasMoreLines()) {
|
||||
curLine = file.ReadLineFromFile();
|
||||
|
||||
//skip empty lines and comments
|
||||
if (curLine == _T("") || curLine.Left(1) == _T("#"))
|
||||
continue;
|
||||
|
||||
wxString tmp = curLine.BeforeFirst(_T('.'));
|
||||
tmp.ToLong(&cftime);
|
||||
|
||||
if (lftime >= cftime)
|
||||
throw _T("Out of order/too close timecodes found");
|
||||
|
||||
AddFrame(cftime);
|
||||
lftime = cftime;
|
||||
}
|
||||
|
||||
last_time = cftime;
|
||||
last_frame = (int)Frame.size() - 1;
|
||||
|
||||
CalcAverage();
|
||||
|
||||
}
|
||||
|
||||
// Unknown
|
||||
else {
|
||||
throw _T("Unknown time code file format.");
|
||||
}
|
||||
|
||||
}
|
||||
catch (...) {
|
||||
Unload();
|
||||
throw;
|
||||
}
|
||||
|
||||
// Close file
|
||||
loaded = true;
|
||||
vfrFile = filename;
|
||||
FrameRateType = VFR;
|
||||
|
||||
// Add to recent
|
||||
config::mru->Add("Timecodes", STD_STR(filename));
|
||||
}
|
||||
|
||||
/// @brief Save
|
||||
/// @param filename
|
||||
void FrameRate::Save(wxString filename) {
|
||||
TextFileWriter file(filename,_T("ASCII"));
|
||||
file.WriteLineToFile(_T("# timecode format v2"));
|
||||
for (size_t i=0;i<Frame.size();i++) {
|
||||
file.WriteLineToFile(wxString::Format(_T("%f"),(float)Frame[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Unload
|
||||
void FrameRate::Unload () {
|
||||
FrameRateType = NONE;
|
||||
AverageFrameRate = 0;
|
||||
last_time = 0;
|
||||
last_frame = 0;
|
||||
Clear();
|
||||
loaded = false;
|
||||
vfrFile = _T("");
|
||||
}
|
||||
|
||||
/// @brief Sets to CFR
|
||||
/// @param fps
|
||||
void FrameRate::SetCFR(double fps) {
|
||||
Unload();
|
||||
loaded = true;
|
||||
FrameRateType = CFR;
|
||||
AverageFrameRate = fps;
|
||||
}
|
||||
|
||||
/// @brief Sets to VFR
|
||||
/// @param newTimes
|
||||
void FrameRate::SetVFR(std::vector<int> newTimes) {
|
||||
Unload();
|
||||
|
||||
loaded = true;
|
||||
FrameRateType = VFR;
|
||||
|
||||
// Set new VFR;
|
||||
Frame = newTimes;
|
||||
CalcAverage();
|
||||
last_time = newTimes.back();
|
||||
last_frame = (int)newTimes.size();
|
||||
}
|
||||
|
||||
/// @brief Gets frame number at time
|
||||
/// @param ms
|
||||
/// @param start
|
||||
/// @return
|
||||
int FrameRate::PFrameAtTime(int ms,bool start) const {
|
||||
if (!loaded) return -1;
|
||||
|
||||
// Lines begin on the first frame whose start time is greater than or equal
|
||||
// to the line's start time, and are last visible on the last frame whose
|
||||
// start time is less than (note: not equal) the line's end time
|
||||
|
||||
if (FrameRateType == CFR || Frame.size() == 0 || ms < 0) {
|
||||
double value = double(ms) * AverageFrameRate / 1000.;
|
||||
if (start) return (int)ceil(value);
|
||||
else return (int)floor(value - .0001);
|
||||
}
|
||||
else if (FrameRateType == VFR) {
|
||||
// Inside VFR range
|
||||
if (ms <= Frame.back()) {
|
||||
int frame = std::distance(Frame.begin(), std::lower_bound(Frame.begin(), Frame.end(), ms));
|
||||
if (!start && frame > 0) {
|
||||
// In the end case, frame is the first frame in which the line
|
||||
// is no longer visible, so subtract 1
|
||||
|
||||
// Don't need to worry about the equal case here as lower_bound
|
||||
// finds the entry >= ms
|
||||
|
||||
// The frame > 0 check isn't actually correct -- the frame
|
||||
// ending at time 0 should be -1, but parts of the program
|
||||
// (like PTimeAtFrame below) assume that frames are positive
|
||||
--frame;
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
// After VFR range
|
||||
else {
|
||||
if (start) return (int)(last_frame + ceil((ms-last_time) * AverageFrameRate / 1000.));
|
||||
else return (int)(last_frame + floor((ms-last_time - .0001) * AverageFrameRate / 1000.));
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// @brief Gets time at frame
|
||||
/// @param frame
|
||||
/// @return
|
||||
int FrameRate::PTimeAtFrame(int frame) const {
|
||||
// Not loaded
|
||||
if (!loaded) return -1;
|
||||
|
||||
// For negative/zero times, fallback to zero
|
||||
if (frame <= 0) return 0;
|
||||
|
||||
// Constant frame rate
|
||||
if (FrameRateType == CFR || Frame.size() == 0) {
|
||||
return (int)floor(double(frame) / AverageFrameRate * 1000.0);
|
||||
}
|
||||
|
||||
// Variable frame rate
|
||||
else if (FrameRateType == VFR) {
|
||||
// Is it inside frame rate range? If so, just get the value from timecodes table
|
||||
if (frame < (signed) Frame.size()) return Frame.at(frame);
|
||||
|
||||
// Otherwise, calculate it
|
||||
else return (int)floor(Frame.back() + double(frame-Frame.size()+1) / AverageFrameRate * 1000.0);
|
||||
}
|
||||
|
||||
// Unknown frame rate type
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// @brief otherwise for start frames returns the adjusted time for end frames when start=false Get correct frame at time
|
||||
/// @param ms
|
||||
/// @param start
|
||||
/// @return
|
||||
int FrameRate::GetFrameAtTime(int ms,bool start) const {
|
||||
return PFrameAtTime(ms,start);
|
||||
}
|
||||
|
||||
/// @brief compensates and returns an end time when start=false Get correct time at frame
|
||||
/// @param frame Frame number
|
||||
/// @param start Adjust for start time
|
||||
/// @param exact Don't do awful things to avoid rounding errors
|
||||
/// @return
|
||||
int FrameRate::GetTimeAtFrame(int frame,bool start,bool exact) const {
|
||||
int finalTime;
|
||||
|
||||
// Exact, for display
|
||||
if (exact) {
|
||||
finalTime = PTimeAtFrame(frame);
|
||||
}
|
||||
|
||||
// Adjusted, for subs sync
|
||||
else {
|
||||
if (start) {
|
||||
finalTime = (PTimeAtFrame(frame-1) + PTimeAtFrame(frame))/2;
|
||||
}
|
||||
else {
|
||||
//if (FrameRateType == VFR) finalTime = PTimeAtFrame(frame);
|
||||
//else finalTime = (PTimeAtFrame(frame) + PTimeAtFrame(frame+1))/2;
|
||||
finalTime = (PTimeAtFrame(frame) + PTimeAtFrame(frame+1))/2;
|
||||
}
|
||||
}
|
||||
|
||||
return finalTime;
|
||||
}
|
||||
|
||||
/// @brief Get the current list of frames/times
|
||||
/// @return
|
||||
std::vector<int> FrameRate::GetFrameTimeList() const {
|
||||
return Frame;
|
||||
}
|
||||
|
||||
bool FrameRate::operator==(FrameRate const& rgt) {
|
||||
if (FrameRateType != rgt.FrameRateType) return false;
|
||||
if (FrameRateType == NONE) return true;
|
||||
if (FrameRateType == CFR) return AverageFrameRate == rgt.AverageFrameRate;
|
||||
return Frame == rgt.Frame;
|
||||
}
|
||||
|
||||
/// DOCME
|
||||
FrameRate VFR_Output;
|
||||
|
||||
/// DOCME
|
||||
FrameRate VFR_Input;
|
|
@ -1,142 +0,0 @@
|
|||
// Copyright (c) 2005-2006, Rodrigo Braz Monteiro, Fredrik Mellbin
|
||||
// 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 Project http://www.aegisub.org/
|
||||
//
|
||||
// $Id$
|
||||
|
||||
/// @file vfr.h
|
||||
/// @see vfr.cpp
|
||||
/// @ingroup video_input
|
||||
///
|
||||
|
||||
// The FrameRate class stores all times internally as ints in ms precision
|
||||
// V1 timecodes are partially expanded to v2 up until their last override line
|
||||
// V2 timecodes are kept as is and if n frames beyond the end is requested a
|
||||
// time is calculated by last_time+n/average_fps
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include <wx/dynarray.h>
|
||||
#include <wx/string.h>
|
||||
#endif
|
||||
|
||||
/// DOCME
|
||||
enum ASS_FrameRateType {
|
||||
NONE,
|
||||
CFR,
|
||||
VFR
|
||||
};
|
||||
|
||||
|
||||
/// DOCME
|
||||
/// @class FrameRate
|
||||
/// @brief DOCME
|
||||
///
|
||||
/// DOCME
|
||||
class FrameRate {
|
||||
friend class VideoContext;
|
||||
|
||||
private:
|
||||
|
||||
/// DOCME
|
||||
double last_time;
|
||||
|
||||
/// DOCME
|
||||
int last_frame;
|
||||
|
||||
/// DOCME
|
||||
std::vector<int> Frame;
|
||||
|
||||
|
||||
/// DOCME
|
||||
double AverageFrameRate;
|
||||
|
||||
void AddFrame(int ms);
|
||||
void Clear();
|
||||
|
||||
void CalcAverage();
|
||||
int PFrameAtTime(int ms,bool useCeil=false) const;
|
||||
int PTimeAtFrame(int frame) const;
|
||||
|
||||
|
||||
/// DOCME
|
||||
ASS_FrameRateType FrameRateType;
|
||||
|
||||
/// DOCME
|
||||
bool loaded;
|
||||
|
||||
/// DOCME
|
||||
wxString vfrFile;
|
||||
|
||||
public:
|
||||
FrameRate();
|
||||
~FrameRate();
|
||||
|
||||
void SetCFR(double fps);
|
||||
void SetVFR(std::vector<int> times);
|
||||
|
||||
// Loading always unloads even on failure
|
||||
void Load(wxString file);
|
||||
void Save(wxString file);
|
||||
void Unload();
|
||||
|
||||
int GetFrameAtTime(int ms,bool start=true) const;
|
||||
int GetTimeAtFrame(int frame,bool start=true,bool exact=false) const;
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
double GetAverage() const { return AverageFrameRate; };
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
bool IsLoaded() const { return loaded; };
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
ASS_FrameRateType GetFrameRateType() const { return FrameRateType; };
|
||||
|
||||
/// @brief DOCME
|
||||
///
|
||||
wxString GetFilename() const { return vfrFile; };
|
||||
|
||||
std::vector<int> GetFrameTimeList() const;
|
||||
|
||||
bool operator==(FrameRate const& rgt);
|
||||
};
|
||||
|
||||
extern FrameRate VFR_Output;
|
||||
extern FrameRate VFR_Input;
|
|
@ -58,7 +58,6 @@
|
|||
#include "subs_grid.h"
|
||||
#include "toggle_bitmap.h"
|
||||
#include "utils.h"
|
||||
#include "vfr.h"
|
||||
#include "video_box.h"
|
||||
#include "video_context.h"
|
||||
#include "video_display.h"
|
||||
|
|
|
@ -34,9 +34,6 @@
|
|||
/// @ingroup video
|
||||
///
|
||||
|
||||
|
||||
////////////
|
||||
// Includes
|
||||
#include "config.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
|
@ -63,6 +60,8 @@
|
|||
#include "ass_time.h"
|
||||
#include "audio_display.h"
|
||||
#include "compat.h"
|
||||
#include "keyframe.h"
|
||||
#include <libaegisub/access.h>
|
||||
#include "main.h"
|
||||
#include "mkv_wrap.h"
|
||||
#include "options.h"
|
||||
|
@ -71,97 +70,64 @@
|
|||
#include "subs_grid.h"
|
||||
#include "subtitles_provider_manager.h"
|
||||
#include "utils.h"
|
||||
#include "vfr.h"
|
||||
#include "video_box.h"
|
||||
#include "video_context.h"
|
||||
#include "video_display.h"
|
||||
#include "video_provider_manager.h"
|
||||
|
||||
|
||||
///////
|
||||
// IDs
|
||||
/// IDs
|
||||
enum {
|
||||
|
||||
/// DOCME
|
||||
VIDEO_PLAY_TIMER = 1300
|
||||
};
|
||||
|
||||
|
||||
///////////////
|
||||
// Event table
|
||||
BEGIN_EVENT_TABLE(VideoContext, wxEvtHandler)
|
||||
EVT_TIMER(VIDEO_PLAY_TIMER,VideoContext::OnPlayTimer)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
/// DOCME
|
||||
VideoContext *VideoContext::instance = NULL;
|
||||
|
||||
/// @brief Constructor
|
||||
///
|
||||
VideoContext::VideoContext()
|
||||
: ownGlContext(false)
|
||||
, glContext(NULL)
|
||||
, provider(NULL)
|
||||
, subsProvider(NULL)
|
||||
, keyFramesLoaded(false)
|
||||
, overKeyFramesLoaded(false)
|
||||
, startFrame(-1)
|
||||
, endFrame(-1)
|
||||
, playNextFrame(-1)
|
||||
, nextFrame(-1)
|
||||
, loaded(false)
|
||||
, isPlaying(false)
|
||||
, keepAudioSync(true)
|
||||
, w(-1)
|
||||
, h(-1)
|
||||
, frame_n(0)
|
||||
, length(0)
|
||||
, fps(0)
|
||||
, arValue(1.)
|
||||
, arType(0)
|
||||
, hasSubtitles(false)
|
||||
, playAudioOnStep(OPT_GET("Audio/Plays When Stepping Video"))
|
||||
, grid(NULL)
|
||||
, curLine(NULL)
|
||||
, audio(NULL)
|
||||
, VFR_Input(videoFPS)
|
||||
, VFR_Output(ovrFPS)
|
||||
{
|
||||
}
|
||||
|
||||
/// @brief Destructor
|
||||
///
|
||||
VideoContext::~VideoContext () {
|
||||
Reset();
|
||||
if (audio && audio->temporary) {
|
||||
delete audio->provider;
|
||||
delete audio->player;
|
||||
}
|
||||
tempFrame.Clear();
|
||||
if (ownGlContext)
|
||||
delete glContext;
|
||||
glContext = NULL;
|
||||
}
|
||||
|
||||
/// @brief Get Instance
|
||||
/// @return
|
||||
///
|
||||
VideoContext *VideoContext::Get() {
|
||||
if (!instance) {
|
||||
instance = new VideoContext;
|
||||
}
|
||||
return instance;
|
||||
static VideoContext instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
/// @brief Clear
|
||||
///
|
||||
void VideoContext::Clear() {
|
||||
instance->audio = NULL;
|
||||
delete instance;
|
||||
instance = NULL;
|
||||
}
|
||||
|
||||
/// @brief Reset
|
||||
///
|
||||
void VideoContext::Reset() {
|
||||
loaded = false;
|
||||
StandardPaths::SetPathValue(_T("?video"),_T(""));
|
||||
StandardPaths::SetPathValue(_T("?video"), "");
|
||||
|
||||
KeyFrames.Clear();
|
||||
keyFramesLoaded = false;
|
||||
keyFrames.clear();
|
||||
videoFPS = agi::vfr::Framerate();
|
||||
|
||||
// Remove temporary audio provider
|
||||
if (audio && audio->temporary) {
|
||||
|
@ -175,133 +141,82 @@ void VideoContext::Reset() {
|
|||
// Remove video data
|
||||
frame_n = 0;
|
||||
length = 0;
|
||||
fps = 0;
|
||||
keyFramesLoaded = false;
|
||||
overKeyFramesLoaded = false;
|
||||
isPlaying = false;
|
||||
nextFrame = -1;
|
||||
curLine = NULL;
|
||||
|
||||
// Update displays
|
||||
UpdateDisplays(true);
|
||||
|
||||
// Clean up video data
|
||||
wxRemoveFile(tempfile);
|
||||
tempfile = _T("");
|
||||
videoName = _T("");
|
||||
videoName.clear();
|
||||
tempFrame.Clear();
|
||||
|
||||
// Remove provider
|
||||
if (provider) {
|
||||
delete provider;
|
||||
provider = NULL;
|
||||
}
|
||||
delete subsProvider;
|
||||
subsProvider = NULL;
|
||||
provider.reset();
|
||||
subsProvider.reset();
|
||||
}
|
||||
|
||||
/// @brief Reload video
|
||||
///
|
||||
void VideoContext::Reload() {
|
||||
if (IsLoaded()) {
|
||||
wxString name = videoName;
|
||||
int n = frame_n;
|
||||
SetVideo(_T(""));
|
||||
SetVideo(name);
|
||||
JumpToFrame(n);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Sets video filename
|
||||
/// @param filename
|
||||
///
|
||||
void VideoContext::SetVideo(const wxString &filename) {
|
||||
// Unload video
|
||||
Stop();
|
||||
Reset();
|
||||
if (filename.empty()) return;
|
||||
|
||||
// Load video
|
||||
if (!filename.IsEmpty()) {
|
||||
try {
|
||||
grid->CommitChanges(true);
|
||||
|
||||
// Set GL context
|
||||
GetGLContext(displayList.front())->SetCurrent(*displayList.front());
|
||||
|
||||
// Choose a provider
|
||||
provider.reset(VideoProviderFactoryManager::GetProvider(filename));
|
||||
|
||||
// Get subtitles provider
|
||||
try {
|
||||
grid->CommitChanges(true);
|
||||
|
||||
// Set GL context
|
||||
GetGLContext(displayList.front())->SetCurrent(*displayList.front());
|
||||
|
||||
// Choose a provider
|
||||
provider = VideoProviderFactoryManager::GetProvider(filename);
|
||||
loaded = provider != NULL;
|
||||
|
||||
// Get subtitles provider
|
||||
try {
|
||||
subsProvider = SubtitlesProviderFactoryManager::GetProvider();
|
||||
}
|
||||
catch (wxString err) { wxMessageBox(_T("Error while loading subtitles provider: ") + err,_T("Subtitles provider")); }
|
||||
catch (const wchar_t *err) { wxMessageBox(_T("Error while loading subtitles provider: ") + wxString(err),_T("Subtitles provider")); }
|
||||
|
||||
KeyFrames.Clear();
|
||||
// load keyframes if available
|
||||
if (provider->AreKeyFramesLoaded()) {
|
||||
KeyFrames = provider->GetKeyFrames();
|
||||
keyFramesLoaded = true;
|
||||
}
|
||||
else {
|
||||
keyFramesLoaded = false;
|
||||
}
|
||||
|
||||
// Set frame rate
|
||||
fps = provider->GetFPS();
|
||||
// does this provider need special vfr treatment?
|
||||
if (provider->NeedsVFRHack()) {
|
||||
// FIXME:
|
||||
// Unfortunately, this hack does not actually work for the one
|
||||
// provider that needs it (Avisynth). Go figure.
|
||||
bool isVfr = provider->IsVFR();
|
||||
if (!isVfr || provider->IsNativelyByFrames()) {
|
||||
VFR_Input.SetCFR(fps);
|
||||
if (VFR_Output.GetFrameRateType() != VFR) VFR_Output.SetCFR(fps);
|
||||
}
|
||||
else {
|
||||
FrameRate temp = provider->GetTrueFrameRate();
|
||||
provider->OverrideFrameTimeList(temp.GetFrameTimeList());
|
||||
}
|
||||
}
|
||||
|
||||
// Gather video parameters
|
||||
length = provider->GetFrameCount();
|
||||
w = provider->GetWidth();
|
||||
h = provider->GetHeight();
|
||||
|
||||
// Set filename
|
||||
videoName = filename;
|
||||
config::mru->Add("Video", STD_STR(filename));
|
||||
wxFileName fn(filename);
|
||||
StandardPaths::SetPathValue(_T("?video"),fn.GetPath());
|
||||
|
||||
// Get frame
|
||||
frame_n = 0;
|
||||
|
||||
// Show warning
|
||||
wxString warning = provider->GetWarning().c_str();
|
||||
if (!warning.IsEmpty()) wxMessageBox(warning,_T("Warning"),wxICON_WARNING | wxOK);
|
||||
|
||||
hasSubtitles = false;
|
||||
if (filename.Right(4).Lower() == L".mkv") {
|
||||
hasSubtitles = MatroskaWrapper::HasSubtitles(filename);
|
||||
}
|
||||
|
||||
UpdateDisplays(true);
|
||||
subsProvider.reset(SubtitlesProviderFactoryManager::GetProvider());
|
||||
}
|
||||
|
||||
catch (wxString &e) {
|
||||
wxMessageBox(e,_T("Error setting video"),wxICON_ERROR | wxOK);
|
||||
catch (wxString err) { wxMessageBox(_T("Error while loading subtitles provider: ") + err,_T("Subtitles provider")); }
|
||||
catch (const wchar_t *err) { wxMessageBox(_T("Error while loading subtitles provider: ") + wxString(err),_T("Subtitles provider")); }
|
||||
|
||||
keyFrames = provider->GetKeyFrames();
|
||||
|
||||
// Set frame rate
|
||||
videoFPS = provider->GetFPS();
|
||||
if (ovrFPS.IsLoaded()) {
|
||||
int ovr = wxMessageBox(_("You already have timecodes loaded. Would you like to replace them with timecodes from the video file?"), _("Replace timecodes?"), wxYES_NO | wxICON_QUESTION);
|
||||
if (ovr == wxYES) {
|
||||
ovrFPS = agi::vfr::Framerate();
|
||||
ovrTimecodeFile.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Gather video parameters
|
||||
length = provider->GetFrameCount();
|
||||
|
||||
// Set filename
|
||||
videoName = filename;
|
||||
config::mru->Add("Video", STD_STR(filename));
|
||||
wxFileName fn(filename);
|
||||
StandardPaths::SetPathValue(_T("?video"),fn.GetPath());
|
||||
|
||||
// Get frame
|
||||
frame_n = 0;
|
||||
|
||||
// Show warning
|
||||
wxString warning = provider->GetWarning();
|
||||
if (!warning.empty()) wxMessageBox(warning,_T("Warning"),wxICON_WARNING | wxOK);
|
||||
|
||||
hasSubtitles = false;
|
||||
if (filename.Right(4).Lower() == L".mkv") {
|
||||
hasSubtitles = MatroskaWrapper::HasSubtitles(filename);
|
||||
}
|
||||
|
||||
UpdateDisplays(true);
|
||||
}
|
||||
|
||||
catch (wxString &e) {
|
||||
wxMessageBox(e,_T("Error setting video"),wxICON_ERROR | wxOK);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Add new display
|
||||
/// @param display
|
||||
/// @return
|
||||
///
|
||||
void VideoContext::AddDisplay(VideoDisplay *display) {
|
||||
for (std::list<VideoDisplay*>::iterator cur=displayList.begin();cur!=displayList.end();cur++) {
|
||||
if ((*cur) == display) return;
|
||||
|
@ -309,15 +224,12 @@ void VideoContext::AddDisplay(VideoDisplay *display) {
|
|||
displayList.push_back(display);
|
||||
}
|
||||
|
||||
/// @brief Remove display
|
||||
/// @param display
|
||||
///
|
||||
void VideoContext::RemoveDisplay(VideoDisplay *display) {
|
||||
displayList.remove(display);
|
||||
}
|
||||
|
||||
void VideoContext::UpdateDisplays(bool full, bool seek) {
|
||||
if (!loaded) return;
|
||||
if (!IsLoaded()) return;
|
||||
|
||||
for (std::list<VideoDisplay*>::iterator cur=displayList.begin();cur!=displayList.end();cur++) {
|
||||
VideoDisplay *display = *cur;
|
||||
|
@ -343,9 +255,8 @@ void VideoContext::UpdateDisplays(bool full, bool seek) {
|
|||
}
|
||||
}
|
||||
|
||||
/// @brief Refresh subtitles
|
||||
void VideoContext::Refresh () {
|
||||
if (subsProvider) {
|
||||
if (subsProvider.get()) {
|
||||
AssExporter exporter(grid->ass);
|
||||
exporter.AddAutoFilters();
|
||||
try {
|
||||
|
@ -358,12 +269,8 @@ void VideoContext::Refresh () {
|
|||
UpdateDisplays(false);
|
||||
}
|
||||
|
||||
/// @brief Jumps to a frame and update display
|
||||
/// @param n
|
||||
/// @return
|
||||
///
|
||||
void VideoContext::JumpToFrame(int n) {
|
||||
if (!loaded) return;
|
||||
if (!IsLoaded()) return;
|
||||
|
||||
// Prevent intervention during playback
|
||||
if (isPlaying && n != playNextFrame) return;
|
||||
|
@ -372,30 +279,14 @@ void VideoContext::JumpToFrame(int n) {
|
|||
|
||||
UpdateDisplays(false, true);
|
||||
|
||||
// Update grid
|
||||
static agi::OptionValue* highlight = OPT_GET("Subtitle/Grid/Highlight Subtitles in Frame");
|
||||
if (!isPlaying && highlight->GetBool()) grid->Refresh(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Jumps to a specific time
|
||||
/// @param ms
|
||||
/// @param exact
|
||||
///
|
||||
void VideoContext::JumpToTime(int ms,bool exact) {
|
||||
int frame;
|
||||
if (exact) frame = VFR_Output.PFrameAtTime(ms);
|
||||
else frame = VFR_Output.GetFrameAtTime(ms);
|
||||
JumpToFrame(frame);
|
||||
void VideoContext::JumpToTime(int ms, agi::vfr::Time end) {
|
||||
JumpToFrame(FrameAtTime(ms, end));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Get GL context
|
||||
/// @param canvas
|
||||
/// @return
|
||||
///
|
||||
wxGLContext *VideoContext::GetGLContext(wxGLCanvas *canvas) {
|
||||
if (!glContext) {
|
||||
glContext = new wxGLContext(canvas);
|
||||
|
@ -404,25 +295,17 @@ wxGLContext *VideoContext::GetGLContext(wxGLCanvas *canvas) {
|
|||
return glContext;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Requests a new frame
|
||||
/// @param n
|
||||
/// @param raw
|
||||
/// @return
|
||||
///
|
||||
AegiVideoFrame VideoContext::GetFrame(int n,bool raw) {
|
||||
// Current frame if -1
|
||||
if (n == -1) n = frame_n;
|
||||
|
||||
// Get frame
|
||||
AegiVideoFrame frame = provider->GetFrame(n);
|
||||
|
||||
// Raster subtitles if available/necessary
|
||||
if (!raw && subsProvider) {
|
||||
if (!raw && subsProvider.get()) {
|
||||
tempFrame.CopyFrom(frame);
|
||||
try {
|
||||
subsProvider->DrawSubtitles(tempFrame,VFR_Input.GetTimeAtFrame(n,true,true)/1000.0);
|
||||
subsProvider->DrawSubtitles(tempFrame,videoFPS.TimeAtFrame(n)/1000.0);
|
||||
}
|
||||
catch (...) {
|
||||
wxLogError(L"Subtitle rendering for the current frame failed.\n");
|
||||
|
@ -434,9 +317,13 @@ AegiVideoFrame VideoContext::GetFrame(int n,bool raw) {
|
|||
else return frame;
|
||||
}
|
||||
|
||||
/// @brief Save snapshot
|
||||
/// @param raw
|
||||
///
|
||||
int VideoContext::GetWidth() const {
|
||||
return provider->GetWidth();
|
||||
}
|
||||
int VideoContext::GetHeight() const {
|
||||
return provider->GetHeight();
|
||||
}
|
||||
|
||||
void VideoContext::SaveSnapshot(bool raw) {
|
||||
// Get folder
|
||||
static agi::OptionValue* ssPath = OPT_GET("Path/Screenshot");
|
||||
|
@ -452,7 +339,7 @@ void VideoContext::SaveSnapshot(bool raw) {
|
|||
}
|
||||
// Find out where the ?specifier points to
|
||||
basepath = StandardPaths::DecodePath(option);
|
||||
// If whereever that is isn't defined, we can't save there
|
||||
// If where ever that is isn't defined, we can't save there
|
||||
if ((basepath == _T("\\")) || (basepath == _T("/"))) {
|
||||
// So save to the current user's home dir instead
|
||||
basepath = wxGetHomeDir();
|
||||
|
@ -472,21 +359,13 @@ void VideoContext::SaveSnapshot(bool raw) {
|
|||
if (!tryPath.FileExists()) break;
|
||||
}
|
||||
|
||||
// Save
|
||||
GetFrame(frame_n,raw).GetImage().SaveFile(path,wxBITMAP_TYPE_PNG);
|
||||
}
|
||||
|
||||
/// @brief Get dimensions of script
|
||||
/// @param sw
|
||||
/// @param sh
|
||||
///
|
||||
void VideoContext::GetScriptSize(int &sw,int &sh) {
|
||||
grid->ass->GetResolution(sw,sh);
|
||||
}
|
||||
|
||||
/// @brief Play the next frame, possibly with audio
|
||||
/// @return
|
||||
///
|
||||
void VideoContext::PlayNextFrame() {
|
||||
if (isPlaying)
|
||||
return;
|
||||
|
@ -495,12 +374,9 @@ void VideoContext::PlayNextFrame() {
|
|||
JumpToFrame(frame_n + 1);
|
||||
// Start playing audio
|
||||
if (playAudioOnStep->GetBool())
|
||||
audio->Play(VFR_Output.GetTimeAtFrame(thisFrame),VFR_Output.GetTimeAtFrame(thisFrame + 1));
|
||||
audio->Play(TimeAtFrame(thisFrame),TimeAtFrame(thisFrame + 1));
|
||||
}
|
||||
|
||||
/// @brief Play the previous frame, possibly with audio
|
||||
/// @return
|
||||
///
|
||||
void VideoContext::PlayPrevFrame() {
|
||||
if (isPlaying)
|
||||
return;
|
||||
|
@ -509,14 +385,10 @@ void VideoContext::PlayPrevFrame() {
|
|||
JumpToFrame(frame_n -1);
|
||||
// Start playing audio
|
||||
if (playAudioOnStep->GetBool())
|
||||
audio->Play(VFR_Output.GetTimeAtFrame(thisFrame - 1),VFR_Output.GetTimeAtFrame(thisFrame));
|
||||
audio->Play(TimeAtFrame(thisFrame - 1),TimeAtFrame(thisFrame));
|
||||
}
|
||||
|
||||
/// @brief Play
|
||||
/// @return
|
||||
///
|
||||
void VideoContext::Play() {
|
||||
// Stop if already playing
|
||||
if (isPlaying) {
|
||||
Stop();
|
||||
return;
|
||||
|
@ -527,7 +399,7 @@ void VideoContext::Play() {
|
|||
endFrame = -1;
|
||||
|
||||
// Start playing audio
|
||||
audio->Play(VFR_Output.GetTimeAtFrame(startFrame),-1);
|
||||
audio->Play(TimeAtFrame(startFrame),-1);
|
||||
|
||||
//audio->Play will override this if we put it before, so put it after.
|
||||
isPlaying = true;
|
||||
|
@ -538,14 +410,7 @@ void VideoContext::Play() {
|
|||
playback.Start(10);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// @brief Play line
|
||||
/// @return
|
||||
///
|
||||
void VideoContext::PlayLine() {
|
||||
// Get line
|
||||
AssDialogue *curline = grid->GetActiveLine();
|
||||
if (!curline) return;
|
||||
|
||||
|
@ -554,8 +419,8 @@ void VideoContext::PlayLine() {
|
|||
|
||||
// Set variables
|
||||
isPlaying = true;
|
||||
startFrame = VFR_Output.GetFrameAtTime(curline->Start.GetMS(),true);
|
||||
endFrame = VFR_Output.GetFrameAtTime(curline->End.GetMS(),false);
|
||||
startFrame = FrameAtTime(curline->Start.GetMS(),agi::vfr::START);
|
||||
endFrame = FrameAtTime(curline->End.GetMS(),agi::vfr::END);
|
||||
|
||||
// Jump to start
|
||||
playNextFrame = startFrame;
|
||||
|
@ -569,8 +434,6 @@ void VideoContext::PlayLine() {
|
|||
playback.Start(10);
|
||||
}
|
||||
|
||||
/// @brief Stop
|
||||
///
|
||||
void VideoContext::Stop() {
|
||||
if (isPlaying) {
|
||||
playback.Stop();
|
||||
|
@ -579,10 +442,6 @@ void VideoContext::Stop() {
|
|||
}
|
||||
}
|
||||
|
||||
/// @brief Play timer
|
||||
/// @param event
|
||||
/// @return
|
||||
///
|
||||
void VideoContext::OnPlayTimer(wxTimerEvent &event) {
|
||||
// Lock
|
||||
wxMutexError res = playMutex.TryLock();
|
||||
|
@ -594,12 +453,12 @@ void VideoContext::OnPlayTimer(wxTimerEvent &event) {
|
|||
int dif = playTime.Time();
|
||||
|
||||
// Find next frame
|
||||
int startMs = VFR_Output.GetTimeAtFrame(startFrame);
|
||||
int startMs = TimeAtFrame(startFrame);
|
||||
int nextFrame = frame_n;
|
||||
int i=0;
|
||||
for (i=0;i<10;i++) {
|
||||
if (nextFrame >= length) break;
|
||||
if (dif < VFR_Output.GetTimeAtFrame(nextFrame) - startMs) {
|
||||
if (dif < TimeAtFrame(nextFrame) - startMs) {
|
||||
break;
|
||||
}
|
||||
nextFrame++;
|
||||
|
@ -615,7 +474,7 @@ void VideoContext::OnPlayTimer(wxTimerEvent &event) {
|
|||
if (nextFrame == frame_n) return;
|
||||
|
||||
// Next frame is before or over 2 frames ahead, so force audio resync
|
||||
if (audio->player && keepAudioSync && (nextFrame < frame_n || nextFrame > frame_n + 2)) audio->player->SetCurrentPosition(audio->GetSampleAtMS(VFR_Output.GetTimeAtFrame(nextFrame)));
|
||||
if (audio->player && keepAudioSync && (nextFrame < frame_n || nextFrame > frame_n + 2)) audio->player->SetCurrentPosition(audio->GetSampleAtMS(TimeAtFrame(nextFrame)));
|
||||
|
||||
// Jump to next frame
|
||||
playNextFrame = nextFrame;
|
||||
|
@ -624,7 +483,7 @@ void VideoContext::OnPlayTimer(wxTimerEvent &event) {
|
|||
|
||||
// Sync audio
|
||||
if (keepAudioSync && nextFrame % 10 == 0 && audio && audio->provider && audio->player) {
|
||||
int64_t audPos = audio->GetSampleAtMS(VFR_Output.GetTimeAtFrame(nextFrame));
|
||||
int64_t audPos = audio->GetSampleAtMS(TimeAtFrame(nextFrame));
|
||||
int64_t curPos = audio->player->GetCurrentPosition();
|
||||
int delta = int(audPos-curPos);
|
||||
if (delta < 0) delta = -delta;
|
||||
|
@ -633,67 +492,7 @@ void VideoContext::OnPlayTimer(wxTimerEvent &event) {
|
|||
}
|
||||
}
|
||||
|
||||
/// @brief Get name of temp work file
|
||||
/// @return
|
||||
///
|
||||
wxString VideoContext::GetTempWorkFile () {
|
||||
if (tempfile.IsEmpty()) {
|
||||
tempfile = wxFileName::CreateTempFileName(_T("aegisub"));
|
||||
wxRemoveFile(tempfile);
|
||||
tempfile += _T(".ass");
|
||||
}
|
||||
return tempfile;
|
||||
}
|
||||
|
||||
/// @brief Get keyframes
|
||||
/// @return
|
||||
///
|
||||
wxArrayInt VideoContext::GetKeyFrames() {
|
||||
if (OverKeyFramesLoaded()) return overKeyFrames;
|
||||
return KeyFrames;
|
||||
}
|
||||
|
||||
/// @brief Set keyframes
|
||||
/// @param frames
|
||||
///
|
||||
void VideoContext::SetKeyFrames(wxArrayInt frames) {
|
||||
KeyFrames = frames;
|
||||
}
|
||||
|
||||
/// @brief Set keyframe override
|
||||
/// @param frames
|
||||
///
|
||||
void VideoContext::SetOverKeyFrames(wxArrayInt frames) {
|
||||
overKeyFrames = frames;
|
||||
overKeyFramesLoaded = true;
|
||||
}
|
||||
|
||||
/// @brief Close keyframes
|
||||
///
|
||||
void VideoContext::CloseOverKeyFrames() {
|
||||
overKeyFrames.Clear();
|
||||
overKeyFramesLoaded = false;
|
||||
}
|
||||
|
||||
/// @brief Check if override keyframes are loaded
|
||||
/// @return
|
||||
///
|
||||
bool VideoContext::OverKeyFramesLoaded() {
|
||||
return overKeyFramesLoaded;
|
||||
}
|
||||
|
||||
/// @brief Check if keyframes are loaded
|
||||
/// @return
|
||||
///
|
||||
bool VideoContext::KeyFramesLoaded() {
|
||||
return overKeyFramesLoaded || keyFramesLoaded;
|
||||
}
|
||||
|
||||
/// @brief Calculate aspect ratio
|
||||
/// @param type
|
||||
/// @return
|
||||
///
|
||||
double VideoContext::GetARFromType(int type) {
|
||||
double VideoContext::GetARFromType(int type) const {
|
||||
if (type == 0) return (double)VideoContext::Get()->GetWidth()/(double)VideoContext::Get()->GetHeight();
|
||||
if (type == 1) return 4.0/3.0;
|
||||
if (type == 2) return 16.0/9.0;
|
||||
|
@ -701,18 +500,77 @@ double VideoContext::GetARFromType(int type) {
|
|||
return 1.0; //error
|
||||
}
|
||||
|
||||
/// @brief Sets aspect ratio
|
||||
/// @param _type
|
||||
/// @param value
|
||||
///
|
||||
void VideoContext::SetAspectRatio(int _type, double value) {
|
||||
// Get value
|
||||
if (_type != 4) value = GetARFromType(_type);
|
||||
void VideoContext::SetAspectRatio(int type, double value) {
|
||||
if (type != 4) value = GetARFromType(type);
|
||||
if (value < 0.5) value = 0.5;
|
||||
if (value > 5.0) value = 5.0;
|
||||
|
||||
// Set
|
||||
arType = _type;
|
||||
arType = type;
|
||||
arValue = value;
|
||||
UpdateDisplays(true);
|
||||
}
|
||||
|
||||
void VideoContext::LoadKeyframes(wxString filename) {
|
||||
if (filename == keyFramesFilename || filename.empty()) return;
|
||||
keyFrames = KeyFrameFile::Load(filename);
|
||||
keyFramesFilename = filename;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void VideoContext::SaveKeyframes(wxString filename) {
|
||||
KeyFrameFile::Save(filename, GetKeyFrames());
|
||||
}
|
||||
|
||||
void VideoContext::CloseKeyframes() {
|
||||
keyFramesFilename.clear();
|
||||
if (provider.get()) {
|
||||
keyFrames = provider->GetKeyFrames();
|
||||
}
|
||||
else {
|
||||
keyFrames.clear();
|
||||
}
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void VideoContext::LoadTimecodes(wxString filename) {
|
||||
if (filename == ovrTimecodeFile || filename.empty()) return;
|
||||
try {
|
||||
ovrFPS = agi::vfr::Framerate(STD_STR(filename));
|
||||
ovrTimecodeFile = filename;
|
||||
config::mru->Add("Timecodes", STD_STR(filename));
|
||||
Refresh();
|
||||
}
|
||||
catch (const agi::acs::AcsError&) {
|
||||
wxLogError(L"Could not open file " + filename);
|
||||
}
|
||||
catch (const agi::vfr::Error& e) {
|
||||
wxLogError(L"Timecode file parse error: %s", e.GetMessage().c_str());
|
||||
}
|
||||
}
|
||||
void VideoContext::SaveTimecodes(wxString filename) {
|
||||
try {
|
||||
ovrFPS.Save(STD_STR(filename), IsLoaded() ? length : -1);
|
||||
config::mru->Add("Timecodes", STD_STR(filename));
|
||||
}
|
||||
catch(const agi::acs::AcsError&) {
|
||||
wxLogError(L"Could not write to " + filename);
|
||||
}
|
||||
}
|
||||
void VideoContext::CloseTimecodes() {
|
||||
ovrFPS = agi::vfr::Framerate();
|
||||
ovrTimecodeFile.clear();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
int VideoContext::TimeAtFrame(int frame, agi::vfr::Time type) const {
|
||||
if (ovrFPS.IsLoaded()) {
|
||||
return ovrFPS.TimeAtFrame(frame, type);
|
||||
}
|
||||
return videoFPS.TimeAtFrame(frame, type);
|
||||
}
|
||||
int VideoContext::FrameAtTime(int time, agi::vfr::Time type) const {
|
||||
if (ovrFPS.IsLoaded()) {
|
||||
return ovrFPS.FrameAtTime(time, type);
|
||||
}
|
||||
return videoFPS.FrameAtTime(time, type);
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include <time.h>
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
#include <wx/glcanvas.h>
|
||||
#include <wx/timer.h>
|
||||
|
@ -56,12 +57,14 @@
|
|||
#include <GL/glu.h>
|
||||
#endif
|
||||
|
||||
#include <libaegisub/vfr.h>
|
||||
#include "video_frame.h"
|
||||
|
||||
class SubtitlesGrid;
|
||||
class AudioProvider;
|
||||
class AudioDisplay;
|
||||
class AssDialogue;
|
||||
class KeyFrameFile;
|
||||
class SubtitlesProvider;
|
||||
class VideoProvider;
|
||||
class VideoDisplay;
|
||||
|
@ -77,11 +80,9 @@ namespace agi {
|
|||
/// DOCME
|
||||
class VideoContext : public wxEvtHandler {
|
||||
friend class AudioProvider;
|
||||
friend class KeyFrameFile;
|
||||
|
||||
private:
|
||||
/// DOCME
|
||||
static VideoContext *instance;
|
||||
|
||||
/// DOCME
|
||||
std::list<VideoDisplay*> displayList;
|
||||
|
||||
|
@ -94,27 +95,14 @@ private:
|
|||
/// DOCME
|
||||
AegiVideoFrame tempFrame;
|
||||
|
||||
/// DOCME
|
||||
std::auto_ptr<VideoProvider> provider;
|
||||
|
||||
/// DOCME
|
||||
wxString tempfile;
|
||||
std::auto_ptr<SubtitlesProvider> subsProvider;
|
||||
|
||||
/// DOCME
|
||||
VideoProvider *provider;
|
||||
|
||||
/// DOCME
|
||||
SubtitlesProvider *subsProvider;
|
||||
|
||||
/// DOCME
|
||||
bool keyFramesLoaded;
|
||||
|
||||
/// DOCME
|
||||
bool overKeyFramesLoaded;
|
||||
|
||||
/// DOCME
|
||||
wxArrayInt KeyFrames;
|
||||
|
||||
/// DOCME
|
||||
wxArrayInt overKeyFrames;
|
||||
std::vector<int> keyFrames;
|
||||
|
||||
/// DOCME
|
||||
wxString keyFramesFilename;
|
||||
|
@ -140,29 +128,18 @@ private:
|
|||
/// DOCME
|
||||
int nextFrame;
|
||||
|
||||
/// DOCME
|
||||
bool loaded;
|
||||
|
||||
/// DOCME
|
||||
bool isPlaying;
|
||||
|
||||
/// DOCME
|
||||
bool keepAudioSync;
|
||||
|
||||
/// DOCME
|
||||
|
||||
/// DOCME
|
||||
int w,h;
|
||||
|
||||
/// DOCME
|
||||
int frame_n;
|
||||
|
||||
/// DOCME
|
||||
int length;
|
||||
|
||||
/// DOCME
|
||||
double fps;
|
||||
|
||||
/// DOCME
|
||||
double arValue;
|
||||
|
||||
|
@ -171,24 +148,28 @@ private:
|
|||
|
||||
bool hasSubtitles;
|
||||
|
||||
wxString ovrTimecodeFile;
|
||||
|
||||
agi::OptionValue* playAudioOnStep;
|
||||
|
||||
void OnPlayTimer(wxTimerEvent &event);
|
||||
|
||||
agi::vfr::Framerate videoFPS;
|
||||
agi::vfr::Framerate ovrFPS;
|
||||
|
||||
public:
|
||||
/// DOCME
|
||||
SubtitlesGrid *grid;
|
||||
|
||||
/// DOCME
|
||||
/// File name of currently open video, if any
|
||||
wxString videoName;
|
||||
|
||||
|
||||
/// DOCME
|
||||
AssDialogue *curLine;
|
||||
|
||||
/// DOCME
|
||||
AudioDisplay *audio;
|
||||
|
||||
const agi::vfr::Framerate &VFR_Input;
|
||||
const agi::vfr::Framerate &VFR_Output;
|
||||
|
||||
VideoContext();
|
||||
~VideoContext();
|
||||
|
||||
|
@ -196,110 +177,114 @@ public:
|
|||
void RemoveDisplay(VideoDisplay *display);
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
VideoProvider *GetProvider() { return provider; }
|
||||
/// @brief Get the video provider used for the currently open video
|
||||
VideoProvider *GetProvider() const { return provider.get(); }
|
||||
AegiVideoFrame GetFrame(int n,bool raw=false);
|
||||
|
||||
/// @brief Save the currently displayed frame as an image
|
||||
/// @param raw Should the frame have subtitles?
|
||||
void SaveSnapshot(bool raw);
|
||||
|
||||
wxGLContext *GetGLContext(wxGLCanvas *canvas);
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
bool IsLoaded() { return loaded; }
|
||||
/// @brief Is there a video loaded?
|
||||
bool IsLoaded() const { return !!provider.get(); }
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
bool IsPlaying() { return isPlaying; }
|
||||
/// @brief Is the video currently playing?
|
||||
bool IsPlaying() const { return isPlaying; }
|
||||
|
||||
/// @brief Does the video file loaded have muxed subtitles that we can load?
|
||||
bool HasSubtitles() {return hasSubtitles; }
|
||||
bool HasSubtitles() const { return hasSubtitles; }
|
||||
|
||||
/// @brief DOCME
|
||||
/// @param sync
|
||||
/// @return
|
||||
void EnableAudioSync(bool sync = true) { keepAudioSync = sync; }
|
||||
|
||||
/// @brief Get the width of the currently open video
|
||||
int GetWidth() const;
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
int GetWidth() { return w; }
|
||||
/// @brief Get the height of the currently open video
|
||||
int GetHeight() const;
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
int GetHeight() { return h; }
|
||||
/// @brief Get the length in frames of the currently open video
|
||||
int GetLength() const { return length; }
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
int GetLength() { return length; }
|
||||
/// @brief Get the current frame number
|
||||
int GetFrameN() const { return frame_n; }
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
int GetFrameN() { return frame_n; }
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
double GetFPS() { return fps; }
|
||||
|
||||
/// @brief DOCME
|
||||
/// @param _fps
|
||||
/// @return
|
||||
void SetFPS(double fps) { this->fps = fps; }
|
||||
|
||||
double GetARFromType(int type);
|
||||
double GetARFromType(int type) const;
|
||||
void SetAspectRatio(int type,double value=1.0);
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
int GetAspectRatioType() { return arType; }
|
||||
int GetAspectRatioType() const { return arType; }
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
double GetAspectRatioValue() { return arValue; }
|
||||
double GetAspectRatioValue() const { return arValue; }
|
||||
|
||||
/// @brief Open a new video
|
||||
/// @param filename Video to open, or empty to close the current video
|
||||
void SetVideo(const wxString &filename);
|
||||
/// @brief Close the video, keyframes and timecodes
|
||||
void Reset();
|
||||
void Reload();
|
||||
|
||||
/// @brief Jump to the beginning of a frame
|
||||
/// @param n Frame number to jump to
|
||||
void JumpToFrame(int n);
|
||||
void JumpToTime(int ms,bool exact=false);
|
||||
/// @brief Jump to a time
|
||||
/// @param ms Time to jump to in milliseconds
|
||||
/// @param end Type of time
|
||||
void JumpToTime(int ms, agi::vfr::Time end = agi::vfr::START);
|
||||
|
||||
/// @brief Refresh the subtitle provider
|
||||
void Refresh();
|
||||
|
||||
/// @brief Update the video display
|
||||
/// @param full Recalculate size and slider lengths
|
||||
/// @param seek Update is just a seek and file has not changed
|
||||
void UpdateDisplays(bool full, bool seek = false);
|
||||
|
||||
/// @brief Get the height and width of the current script
|
||||
/// @param[out] w Width
|
||||
/// @param[out] h Height
|
||||
///
|
||||
/// This probably shouldn't be in VideoContext
|
||||
void GetScriptSize(int &w,int &h);
|
||||
wxString GetTempWorkFile ();
|
||||
|
||||
/// Starting playing the video
|
||||
void Play();
|
||||
/// Play the next frame then stop
|
||||
void PlayNextFrame();
|
||||
/// Play the previous frame then stop
|
||||
void PlayPrevFrame();
|
||||
/// Seek to the beginning of the current line, then play to the end of it
|
||||
void PlayLine();
|
||||
/// Stop playing
|
||||
void Stop();
|
||||
|
||||
wxArrayInt GetKeyFrames();
|
||||
void SetKeyFrames(wxArrayInt frames);
|
||||
void SetOverKeyFrames(wxArrayInt frames);
|
||||
void CloseOverKeyFrames();
|
||||
bool OverKeyFramesLoaded();
|
||||
bool KeyFramesLoaded();
|
||||
const std::vector<int>& GetKeyFrames() const { return keyFrames; };
|
||||
wxString GetKeyFramesName() const { return keyFramesFilename; }
|
||||
void LoadKeyframes(wxString filename);
|
||||
void SaveKeyframes(wxString filename);
|
||||
void CloseKeyframes();
|
||||
bool OverKeyFramesLoaded() const { return !keyFramesFilename.empty(); }
|
||||
bool KeyFramesLoaded() const { return !keyFrames.empty(); }
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
wxString GetKeyFramesName() { return keyFramesFilename; }
|
||||
wxString GetTimecodesName() const { return ovrTimecodeFile; }
|
||||
void LoadTimecodes(wxString filename);
|
||||
void SaveTimecodes(wxString filename);
|
||||
void CloseTimecodes();
|
||||
bool OverTimecodesLoaded() const { return ovrFPS.IsLoaded(); }
|
||||
bool TimecodesLoaded() const { return videoFPS.IsLoaded() || ovrFPS.IsLoaded(); };
|
||||
|
||||
/// @brief DOCME
|
||||
/// @param name
|
||||
///
|
||||
void SetKeyFramesName(wxString name) { keyFramesFilename = name; }
|
||||
const agi::vfr::Framerate& FPS() const { return ovrFPS.IsLoaded() ? ovrFPS : videoFPS; }
|
||||
|
||||
int TimeAtFrame(int frame, agi::vfr::Time type = agi::vfr::EXACT) const;
|
||||
int FrameAtTime(int time, agi::vfr::Time type = agi::vfr::EXACT) const;
|
||||
|
||||
static VideoContext *Get();
|
||||
static void Clear();
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
|
|
@ -60,8 +60,8 @@
|
|||
#include "hotkeys.h"
|
||||
#include "options.h"
|
||||
#include "main.h"
|
||||
#include "subs_grid.h"
|
||||
#include "video_out_gl.h"
|
||||
#include "vfr.h"
|
||||
#include "video_box.h"
|
||||
#include "video_context.h"
|
||||
#include "video_slider.h"
|
||||
|
@ -166,7 +166,7 @@ void VideoDisplay::SetFrame(int frameNumber) {
|
|||
|
||||
// Get time for frame
|
||||
{
|
||||
int time = VFR_Output.GetTimeAtFrame(frameNumber, true, true);
|
||||
int time = context->TimeAtFrame(frameNumber, agi::vfr::EXACT);
|
||||
int h = time / 3600000;
|
||||
int m = time % 3600000 / 60000;
|
||||
int s = time % 60000 / 1000;
|
||||
|
@ -174,7 +174,7 @@ void VideoDisplay::SetFrame(int frameNumber) {
|
|||
|
||||
// Set the text box for frame number and time
|
||||
PositionDisplay->SetValue(wxString::Format(L"%01i:%02i:%02i.%03i - %i", h, m, s, ms, frameNumber));
|
||||
if (context->GetKeyFrames().Index(frameNumber) != wxNOT_FOUND) {
|
||||
if (std::binary_search(context->GetKeyFrames().begin(), context->GetKeyFrames().end(), frameNumber)) {
|
||||
// Set the background color to indicate this is a keyframe
|
||||
PositionDisplay->SetBackgroundColour(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Background/Selection")->GetColour()));
|
||||
PositionDisplay->SetForegroundColour(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Selection")->GetColour()));
|
||||
|
@ -189,7 +189,7 @@ void VideoDisplay::SetFrame(int frameNumber) {
|
|||
int startOff = 0;
|
||||
int endOff = 0;
|
||||
|
||||
if (AssDialogue *curLine = context->curLine) {
|
||||
if (AssDialogue *curLine = context->grid->GetActiveLine()) {
|
||||
startOff = time - curLine->Start.GetMS();
|
||||
endOff = time - curLine->End.GetMS();
|
||||
}
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
#include "mkv_wrap.h"
|
||||
#include "options.h"
|
||||
#include "standard_paths.h"
|
||||
#include "vfr.h"
|
||||
#include "vfw_wrap.h"
|
||||
#include "video_context.h"
|
||||
#include "video_provider_avs.h"
|
||||
|
@ -63,13 +62,9 @@ AvisynthVideoProvider::AvisynthVideoProvider(wxString _filename) {
|
|||
AVSTRACE(wxString::Format(_T("AvisynthVideoProvider: Creating new AvisynthVideoProvider: \"%s\", \"%s\""), _filename, _subfilename));
|
||||
bool mpeg2dec3_priority = true;
|
||||
RGB32Video = NULL;
|
||||
fps = 0;
|
||||
num_frames = 0;
|
||||
last_fnum = -1;
|
||||
byFrame = false;
|
||||
KeyFrames.Clear();
|
||||
keyFramesLoaded = false;
|
||||
isVfr = false;
|
||||
KeyFrames.clear();
|
||||
|
||||
AVSTRACE(_T("AvisynthVideoProvider: Opening video"));
|
||||
RGB32Video = OpenVideo(_filename,mpeg2dec3_priority);
|
||||
|
@ -92,12 +87,6 @@ AvisynthVideoProvider::~AvisynthVideoProvider() {
|
|||
AVSTRACE(_T("AvisynthVideoProvider: AvisynthVideoProvider destroyed"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////// VIDEO PROVIDER //////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
/// @brief Actually open the video into Avisynth
|
||||
/// @param _filename
|
||||
/// @param mpeg2dec3_priority
|
||||
|
@ -109,7 +98,6 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori
|
|||
AVSTRACE(_T("AvisynthVideoProvider::OpenVideo: Got AVS mutex"));
|
||||
AVSValue script;
|
||||
|
||||
byFrame = false;
|
||||
usedDirectShow = false;
|
||||
decoderName = _("Unknown");
|
||||
|
||||
|
@ -138,7 +126,6 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori
|
|||
AVSValue args[2] = { videoFilename, false };
|
||||
script = env->Invoke("AviSource", AVSValue(args,2), argnames);
|
||||
AVSTRACE(_T("AvisynthVideoProvider::OpenVideo: Successfully opened .avi file without audio"));
|
||||
byFrame = true;
|
||||
decoderName = _T("AviSource");
|
||||
}
|
||||
|
||||
|
@ -155,10 +142,10 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori
|
|||
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 avisynth is 2.5.7 beta 2 or newer old mpeg2decs will crash without this
|
||||
if (env->FunctionExists("SetPlanarLegacyAlignment")) {
|
||||
AVSValue args[2] = { script, true };
|
||||
script = env->Invoke("SetPlanarLegacyAlignment", AVSValue(args,2));
|
||||
script = env->Invoke("SetPlanarLegacyAlignment", AVSValue(args,2));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,8 +155,8 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori
|
|||
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
|
||||
//note that DGDecode will also have issues like if the version is too ancient but no sane person
|
||||
//would use that anyway
|
||||
}
|
||||
|
||||
else if (extension == _T(".d2v") && env->FunctionExists("Mpeg2Source")) {
|
||||
|
@ -177,9 +164,9 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori
|
|||
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"))
|
||||
script = env->Invoke("SetPlanarLegacyAlignment", script);
|
||||
//if avisynth is 2.5.7 beta 2 or newer old mpeg2decs will crash without this
|
||||
if (env->FunctionExists("SetPlanarLegacyAlignment"))
|
||||
script = env->Invoke("SetPlanarLegacyAlignment", script);
|
||||
}
|
||||
|
||||
// Some other format, such as mkv, mp4, ogm... try both flavors of DirectShowSource
|
||||
|
@ -253,30 +240,16 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori
|
|||
}
|
||||
|
||||
// Read keyframes and timecodes from MKV file
|
||||
isVfr = false;
|
||||
FrameRate temp;
|
||||
bool mkvOpen = MatroskaWrapper::wrapper.IsOpen();
|
||||
KeyFrames.Clear();
|
||||
KeyFrames.clear();
|
||||
if (extension == _T(".mkv") || mkvOpen) {
|
||||
// Parse mkv
|
||||
if (!mkvOpen) MatroskaWrapper::wrapper.Open(_filename);
|
||||
|
||||
// Get keyframes
|
||||
KeyFrames = MatroskaWrapper::wrapper.GetKeyFrames();
|
||||
keyFramesLoaded = true;
|
||||
|
||||
// Ask to override timecodes
|
||||
int override = wxYES;
|
||||
if (VFR_Output.IsLoaded()) override = wxMessageBox(_("You already have timecodes loaded. Replace them with the timecodes from the Matroska file?"),_("Replace timecodes?"),wxYES_NO | wxICON_QUESTION);
|
||||
if (override == wxYES) {
|
||||
MatroskaWrapper::wrapper.SetToTimecodes(temp);
|
||||
isVfr = temp.GetFrameRateType() == VFR;
|
||||
if (isVfr) {
|
||||
MatroskaWrapper::wrapper.SetToTimecodes(VFR_Input);
|
||||
MatroskaWrapper::wrapper.SetToTimecodes(VFR_Output);
|
||||
trueFrameRate = temp;
|
||||
}
|
||||
}
|
||||
|
||||
MatroskaWrapper::wrapper.SetToTimecodes(vfr_fps);
|
||||
|
||||
// Close mkv
|
||||
MatroskaWrapper::wrapper.Close();
|
||||
|
@ -284,16 +257,14 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori
|
|||
// check if we have windows, if so we can load keyframes from AVI files using VFW
|
||||
#ifdef __WINDOWS__
|
||||
else if (extension == _T(".avi")) {
|
||||
keyFramesLoaded = false;
|
||||
KeyFrames.Clear();
|
||||
KeyFrames.clear();
|
||||
KeyFrames = VFWWrapper::GetKeyFrames(_filename);
|
||||
keyFramesLoaded = true;
|
||||
}
|
||||
#endif /* __WINDOWS__ */
|
||||
|
||||
// Check if the file is all keyframes
|
||||
bool isAllKeyFrames = true;
|
||||
for (unsigned int i=1; i<KeyFrames.GetCount(); i++) {
|
||||
for (unsigned int i=1; i<KeyFrames.size(); i++) {
|
||||
// Is the last keyframe not this keyframe -1?
|
||||
if (KeyFrames[i-1] != (int)(i-1)) {
|
||||
// It's not all keyframes, go ahead
|
||||
|
@ -304,10 +275,11 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori
|
|||
|
||||
// If it is all keyframes, discard the keyframe info as it is useless
|
||||
if (isAllKeyFrames) {
|
||||
KeyFrames.Clear();
|
||||
keyFramesLoaded = false;
|
||||
KeyFrames.clear();
|
||||
}
|
||||
|
||||
real_fps = (double)vi.fps_numerator / vi.fps_denominator;
|
||||
|
||||
// Convert to RGB32
|
||||
script = env->Invoke("ConvertToRGB32", script);
|
||||
AVSTRACE(_T("AvisynthVideoProvider::OpenVideo: Converted to RGB32"));
|
||||
|
@ -323,17 +295,10 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori
|
|||
/// @param _n
|
||||
/// @return
|
||||
///
|
||||
const AegiVideoFrame AvisynthVideoProvider::GetFrame(int _n) {
|
||||
// Transform n if overriden
|
||||
int n = _n;
|
||||
if (frameTime.Count()) {
|
||||
if (n < 0) n = 0;
|
||||
if (n >= (signed) frameTime.Count()) n = frameTime.Count()-1;
|
||||
int time = frameTime[n];
|
||||
double curFps = (double)vi.fps_numerator/(double)vi.fps_denominator;
|
||||
n = time * curFps / 1000.0;
|
||||
const AegiVideoFrame AvisynthVideoProvider::GetFrame(int n) {
|
||||
if (vfr_fps.IsLoaded()) {
|
||||
n = real_fps.FrameAtTime(vfr_fps.TimeAtFrame(n));
|
||||
}
|
||||
|
||||
// Get avs frame
|
||||
AVSTRACE(_T("AvisynthVideoProvider::GetFrame"));
|
||||
wxMutexLocker lock(AviSynthMutex);
|
||||
|
@ -362,24 +327,11 @@ const AegiVideoFrame AvisynthVideoProvider::GetFrame(int _n) {
|
|||
return final;
|
||||
}
|
||||
|
||||
|
||||
/// @brief Override frame times
|
||||
/// @param list
|
||||
///
|
||||
void AvisynthVideoProvider::OverrideFrameTimeList(wxArrayInt list) {
|
||||
frameTime = list;
|
||||
num_frames = frameTime.Count();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Get warning
|
||||
///
|
||||
wxString AvisynthVideoProvider::GetWarning() {
|
||||
wxString AvisynthVideoProvider::GetWarning() const {
|
||||
if (usedDirectShow) return L"Warning! The file is being opened using Avisynth's DirectShowSource, which has unreliable seeking. Frame numbers might not match the real number. PROCEED AT YOUR OWN RISK!";
|
||||
else return L"";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -34,22 +34,16 @@
|
|||
/// @ingroup video_input
|
||||
///
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#ifdef WITH_AVISYNTH
|
||||
#include "avisynth_wrap.h"
|
||||
#include "include/aegisub/video_provider.h"
|
||||
|
||||
|
||||
/// DOCME
|
||||
/// @class AvisynthVideoProvider
|
||||
/// @brief DOCME
|
||||
///
|
||||
/// DOCME
|
||||
class AvisynthVideoProvider: public VideoProvider, AviSynthWrapper {
|
||||
private:
|
||||
|
||||
/// DOCME
|
||||
VideoInfo vi;
|
||||
|
||||
|
@ -75,27 +69,11 @@ private:
|
|||
|
||||
|
||||
/// DOCME
|
||||
double fps;
|
||||
agi::vfr::Framerate real_fps;
|
||||
agi::vfr::Framerate vfr_fps;
|
||||
|
||||
/// DOCME
|
||||
wxArrayInt frameTime;
|
||||
|
||||
/// DOCME
|
||||
bool byFrame;
|
||||
|
||||
|
||||
/// DOCME
|
||||
wxArrayInt KeyFrames;
|
||||
|
||||
/// DOCME
|
||||
bool keyFramesLoaded;
|
||||
|
||||
/// DOCME
|
||||
bool isVfr;
|
||||
|
||||
/// DOCME
|
||||
FrameRate trueFrameRate;
|
||||
|
||||
std::vector<int> KeyFrames;
|
||||
|
||||
/// DOCME
|
||||
PClip RGB32Video;
|
||||
|
@ -108,72 +86,16 @@ public:
|
|||
|
||||
const AegiVideoFrame GetFrame(int n);
|
||||
|
||||
/// @brief // properties
|
||||
/// @return
|
||||
///
|
||||
int GetPosition() { return last_fnum; };
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
int GetFrameCount() { return num_frames? num_frames: vi.num_frames; };
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
double GetFPS() { return (double)vi.fps_numerator/(double)vi.fps_denominator; };
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
int GetWidth() { return vi.width; };
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
int GetHeight() { return vi.height; };
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
bool AreKeyFramesLoaded() { return keyFramesLoaded; };
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
wxArrayInt GetKeyFrames() { return KeyFrames; };
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
bool IsVFR() { return isVfr; };
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
FrameRate GetTrueFrameRate() { return isVfr? trueFrameRate: FrameRate(); };
|
||||
|
||||
void OverrideFrameTimeList(wxArrayInt list);
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
bool IsNativelyByFrames() { return byFrame; }
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
bool NeedsVFRHack() { return true; }
|
||||
wxString GetWarning();
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
wxString GetDecoderName() { return wxString(L"Avisynth/") + decoderName; }
|
||||
int GetPosition() const { return last_fnum; };
|
||||
int GetFrameCount() const { return num_frames? num_frames: vi.num_frames; };
|
||||
agi::vfr::Framerate GetFPS() const { return vfr_fps.IsLoaded() ? vfr_fps : real_fps; };
|
||||
int GetWidth() const { return vi.width; };
|
||||
int GetHeight() const { return vi.height; };
|
||||
std::vector<int> GetKeyFrames() const { return KeyFrames; };
|
||||
wxString GetWarning() const;
|
||||
wxString GetDecoderName() const { return wxString(L"Avisynth/") + decoderName; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// DOCME
|
||||
/// @class AvisynthVideoProviderFactory
|
||||
/// @brief DOCME
|
||||
|
@ -188,7 +110,4 @@ public:
|
|||
VideoProvider *CreateProvider(wxString video) { return new AvisynthVideoProvider(video); }
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -34,39 +34,43 @@
|
|||
/// @ingroup video_input
|
||||
///
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#include "config.h"
|
||||
#include "main.h"
|
||||
#include "options.h"
|
||||
|
||||
#include "video_provider_cache.h"
|
||||
|
||||
/// DOCME
|
||||
/// @class CachedFrame
|
||||
/// @brief DOCME
|
||||
///
|
||||
/// DOCME
|
||||
struct CachedFrame {
|
||||
/// DOCME
|
||||
AegiVideoFrame frame;
|
||||
|
||||
/// DOCME
|
||||
int n;
|
||||
};
|
||||
|
||||
/// @brief Constructor
|
||||
/// @param parent
|
||||
///
|
||||
VideoProviderCache::VideoProviderCache(VideoProvider *parent) {
|
||||
master = parent;
|
||||
cacheMax = 0;
|
||||
if (parent->WantsCaching())
|
||||
cacheMax = OPT_GET("Provider/Video/Cache/Size")->GetInt() << 20; // convert MB to bytes
|
||||
else
|
||||
cacheMax = 0;
|
||||
VideoProviderCache::VideoProviderCache(VideoProvider *parent)
|
||||
: master(parent)
|
||||
, cacheMax(OPT_GET("Provider/Video/Cache/Size")->GetInt() << 20) // convert MB to bytes
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Destructor
|
||||
///
|
||||
VideoProviderCache::~VideoProviderCache() {
|
||||
delete master;
|
||||
ClearCache();
|
||||
while (cache.size()) {
|
||||
cache.front().frame.Clear();
|
||||
cache.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Get frame
|
||||
/// @param n
|
||||
/// @return
|
||||
|
@ -88,21 +92,14 @@ const AegiVideoFrame VideoProviderCache::GetFrame(int n) {
|
|||
const AegiVideoFrame *srcFrame = &frame;
|
||||
|
||||
// Cache frame
|
||||
pos = n;
|
||||
Cache(n,*srcFrame);
|
||||
return *srcFrame;
|
||||
}
|
||||
|
||||
|
||||
/// @brief Add to cache
|
||||
/// @param n
|
||||
/// @param frame
|
||||
/// @return
|
||||
///
|
||||
void VideoProviderCache::Cache(int n,const AegiVideoFrame frame) {
|
||||
// Cache enabled?
|
||||
if (cacheMax == 0) return;
|
||||
|
||||
// Cache full, use frame at front
|
||||
if (GetCurCacheSize() >= cacheMax) {
|
||||
cache.push_back(cache.front());
|
||||
|
@ -119,17 +116,6 @@ void VideoProviderCache::Cache(int n,const AegiVideoFrame frame) {
|
|||
cache.back().frame.CopyFrom(frame);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Clear cache
|
||||
///
|
||||
void VideoProviderCache::ClearCache() {
|
||||
while (cache.size()) {
|
||||
cache.front().frame.Clear();
|
||||
cache.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Get the current size of the cache
|
||||
/// @return Returns the size in bytes
|
||||
unsigned VideoProviderCache::GetCurCacheSize() {
|
||||
|
@ -138,103 +124,3 @@ unsigned VideoProviderCache::GetCurCacheSize() {
|
|||
sz += i->frame.memSize;
|
||||
return sz;
|
||||
}
|
||||
|
||||
|
||||
/// @brief Wrapper methods
|
||||
/// @return
|
||||
///
|
||||
int VideoProviderCache::GetPosition() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
int VideoProviderCache::GetFrameCount() {
|
||||
return master->GetFrameCount();
|
||||
}
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
int VideoProviderCache::GetWidth() {
|
||||
return master->GetWidth();
|
||||
}
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
int VideoProviderCache::GetHeight() {
|
||||
return master->GetHeight();
|
||||
}
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
double VideoProviderCache::GetFPS() {
|
||||
return master->GetFPS();
|
||||
}
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
bool VideoProviderCache::IsVFR() {
|
||||
return master->IsVFR();
|
||||
}
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
bool VideoProviderCache::AreKeyFramesLoaded() {
|
||||
return master->AreKeyFramesLoaded();
|
||||
}
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
wxArrayInt VideoProviderCache::GetKeyFrames() {
|
||||
return master->GetKeyFrames();
|
||||
}
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
FrameRate VideoProviderCache::GetTrueFrameRate() {
|
||||
return master->GetTrueFrameRate();
|
||||
}
|
||||
|
||||
/// @brief DOCME
|
||||
/// @param list
|
||||
///
|
||||
void VideoProviderCache::OverrideFrameTimeList(std::vector<int> list) {
|
||||
master->OverrideFrameTimeList(list);
|
||||
}
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
bool VideoProviderCache::IsNativelyByFrames() {
|
||||
return master->IsNativelyByFrames();
|
||||
}
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
bool VideoProviderCache::NeedsVFRHack() {
|
||||
return master->NeedsVFRHack();
|
||||
}
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
wxString VideoProviderCache::GetWarning() {
|
||||
return master->GetWarning();
|
||||
}
|
||||
|
||||
/// @brief DOCME
|
||||
///
|
||||
wxString VideoProviderCache::GetDecoderName() {
|
||||
return master->GetDecoderName();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -34,34 +34,14 @@
|
|||
/// @ingroup video_input
|
||||
///
|
||||
|
||||
|
||||
|
||||
|
||||
//////////
|
||||
// Headers
|
||||
#ifndef AGI_PRE
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#endif
|
||||
|
||||
#include "include/aegisub/video_provider.h"
|
||||
#include "vfr.h"
|
||||
|
||||
|
||||
/// DOCME
|
||||
/// @class CachedFrame
|
||||
/// @brief DOCME
|
||||
///
|
||||
/// DOCME
|
||||
class CachedFrame {
|
||||
public:
|
||||
|
||||
/// DOCME
|
||||
AegiVideoFrame frame;
|
||||
|
||||
/// DOCME
|
||||
int n;
|
||||
};
|
||||
|
||||
struct CachedFrame;
|
||||
|
||||
/// DOCME
|
||||
/// @class VideoProviderCache
|
||||
|
@ -69,10 +49,8 @@ public:
|
|||
///
|
||||
/// DOCME
|
||||
class VideoProviderCache : public VideoProvider {
|
||||
private:
|
||||
|
||||
/// DOCME
|
||||
VideoProvider *master;
|
||||
std::auto_ptr<VideoProvider> master;
|
||||
|
||||
/// DOCME
|
||||
unsigned int cacheMax;
|
||||
|
@ -80,16 +58,11 @@ private:
|
|||
/// DOCME
|
||||
std::list<CachedFrame> cache;
|
||||
|
||||
/// DOCME
|
||||
int pos;
|
||||
|
||||
void Cache(int n,const AegiVideoFrame frame);
|
||||
AegiVideoFrame GetCachedFrame(int n);
|
||||
|
||||
protected:
|
||||
// Cache functions
|
||||
unsigned GetCurCacheSize();
|
||||
void ClearCache();
|
||||
|
||||
public:
|
||||
// Base methods
|
||||
|
@ -98,20 +71,14 @@ public:
|
|||
virtual ~VideoProviderCache();
|
||||
|
||||
// Override the following methods:
|
||||
virtual int GetPosition(); // Get the number of the last frame loaded
|
||||
virtual int GetFrameCount(); // Get total number of frames
|
||||
virtual int GetWidth(); // Returns the video width in pixels
|
||||
virtual int GetHeight(); // Returns the video height in pixels
|
||||
virtual double GetFPS(); // Get framerate in frames per second
|
||||
virtual bool AreKeyFramesLoaded();
|
||||
virtual bool IsVFR();
|
||||
virtual wxArrayInt GetKeyFrames();
|
||||
virtual FrameRate GetTrueFrameRate();
|
||||
virtual void OverrideFrameTimeList(std::vector<int> list); // Override the list with the provided one, for VFR handling
|
||||
virtual bool IsNativelyByFrames();
|
||||
virtual bool NeedsVFRHack();
|
||||
virtual wxString GetWarning();
|
||||
virtual wxString GetDecoderName();
|
||||
virtual int GetPosition() const { return master->GetPosition(); }
|
||||
virtual int GetFrameCount() const { return master->GetFrameCount(); }
|
||||
virtual int GetWidth() const { return master->GetWidth(); }
|
||||
virtual int GetHeight() const { return master->GetHeight(); }
|
||||
virtual agi::vfr::Framerate GetFPS() const { return master->GetFPS(); }
|
||||
virtual std::vector<int> GetKeyFrames() const { return master->GetKeyFrames(); }
|
||||
virtual wxString GetWarning() const { return master->GetWarning(); }
|
||||
virtual wxString GetDecoderName() const { return master->GetDecoderName(); }
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -34,9 +34,6 @@
|
|||
/// @ingroup video_input
|
||||
///
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#include "config.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
|
@ -46,18 +43,6 @@
|
|||
#include "colorspace.h"
|
||||
#include "video_provider_dummy.h"
|
||||
|
||||
|
||||
///////////
|
||||
// Factory
|
||||
// Shouldn't be needed
|
||||
/*class DummyVideoProviderFactory : public VideoProviderFactory {
|
||||
public:
|
||||
VideoProvider *CreateProvider(wxString video,double fps=0.0) { return new DummyVideoProvider(video,fps); }
|
||||
DummyVideoProviderFactory() : VideoProviderFactory(_T("dummy")) {}
|
||||
} registerDummyVideo; */
|
||||
|
||||
|
||||
|
||||
/// @brief Constructor
|
||||
/// @param _fps
|
||||
/// @param frames
|
||||
|
@ -130,8 +115,6 @@ void DummyVideoProvider::Create(double _fps, int frames, int _width, int _height
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Parsing constructor
|
||||
/// @param filename
|
||||
///
|
||||
|
@ -194,8 +177,6 @@ DummyVideoProvider::DummyVideoProvider(wxString filename)
|
|||
Create(fps, _frames, _width, _height, wxColour(red, green, blue), pattern);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Direct constructor
|
||||
/// @param _fps
|
||||
/// @param frames
|
||||
|
@ -208,16 +189,12 @@ DummyVideoProvider::DummyVideoProvider(double _fps, int frames, int _width, int
|
|||
Create(_fps, frames, _width, _height, colour, pattern);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Destructor
|
||||
///
|
||||
DummyVideoProvider::~DummyVideoProvider() {
|
||||
frame.Clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Construct a fake filename describing the video
|
||||
/// @param fps
|
||||
/// @param frames
|
||||
|
@ -231,8 +208,6 @@ wxString DummyVideoProvider::MakeFilename(double fps, int frames, int _width, in
|
|||
return wxString::Format(_T("?dummy:%f:%d:%d:%d:%d:%d:%d:%s"), fps, frames, _width, _height, colour.Red(), colour.Green(), colour.Blue(), pattern?_T("c"):_T(""));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Get frame
|
||||
/// @param n
|
||||
/// @return
|
||||
|
@ -241,59 +216,3 @@ const AegiVideoFrame DummyVideoProvider::GetFrame(int n) {
|
|||
lastFrame = n;
|
||||
return frame;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Get position
|
||||
/// @return
|
||||
///
|
||||
int DummyVideoProvider::GetPosition() {
|
||||
return lastFrame;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Get frame count
|
||||
/// @return
|
||||
///
|
||||
int DummyVideoProvider::GetFrameCount() {
|
||||
return framecount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Get width
|
||||
/// @return
|
||||
///
|
||||
int DummyVideoProvider::GetWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Get height
|
||||
/// @return
|
||||
///
|
||||
int DummyVideoProvider::GetHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Get FPS
|
||||
/// @return
|
||||
///
|
||||
double DummyVideoProvider::GetFPS() {
|
||||
return fps;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Get decoder name
|
||||
///
|
||||
wxString DummyVideoProvider::GetDecoderName() {
|
||||
return L"Dummy Video Provider";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -36,18 +36,11 @@
|
|||
|
||||
// The dummy video provider needs a header, since it needs to be created directly as a special case
|
||||
|
||||
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#ifndef AGI_PRE
|
||||
#include <wx/colour.h>
|
||||
#endif
|
||||
|
||||
#include "include/aegisub/video_provider.h"
|
||||
#include "vfr.h"
|
||||
|
||||
|
||||
/// DOCME
|
||||
/// @class DummyVideoProvider
|
||||
|
@ -55,8 +48,6 @@
|
|||
///
|
||||
/// DOCME
|
||||
class DummyVideoProvider : public VideoProvider {
|
||||
private:
|
||||
|
||||
/// DOCME
|
||||
int lastFrame;
|
||||
|
||||
|
@ -64,7 +55,7 @@ private:
|
|||
int framecount;
|
||||
|
||||
/// DOCME
|
||||
double fps;
|
||||
agi::vfr::Framerate fps;
|
||||
|
||||
/// DOCME
|
||||
int width;
|
||||
|
@ -85,37 +76,11 @@ public:
|
|||
const AegiVideoFrame GetFrame(int n);
|
||||
static wxString MakeFilename(double fps, int frames, int _width, int _height, const wxColour &colour, bool pattern);
|
||||
|
||||
int GetPosition();
|
||||
int GetFrameCount();
|
||||
|
||||
int GetWidth();
|
||||
int GetHeight();
|
||||
double GetFPS();
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
bool AreKeyFramesLoaded() { return false; };
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
wxArrayInt GetKeyFrames() { return wxArrayInt(); };
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
bool IsVFR() { return false; };
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
bool NeedsVFRHack() { return true; }
|
||||
|
||||
/// @brief DOCME
|
||||
///
|
||||
FrameRate GetTrueFrameRate() { return FrameRate(); };
|
||||
|
||||
wxString GetDecoderName();
|
||||
int GetPosition() const { return lastFrame; }
|
||||
int GetFrameCount() const { return framecount; }
|
||||
int GetWidth() const { return width; }
|
||||
int GetHeight() const { return height; }
|
||||
agi::vfr::Framerate GetFPS() const { return fps; }
|
||||
std::vector<int> GetKeyFrames() const { return std::vector<int>(); };
|
||||
wxString GetDecoderName() const { return L"Dummy Video Provider"; }
|
||||
};
|
||||
|
|
|
@ -38,8 +38,6 @@
|
|||
|
||||
#ifdef WITH_FFMPEGSOURCE
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#ifndef AGI_PRE
|
||||
#ifdef __WINDOWS__
|
||||
#include <objbase.h>
|
||||
|
@ -79,7 +77,6 @@ FFmpegSourceVideoProvider::FFmpegSourceVideoProvider(wxString filename) {
|
|||
|
||||
// clean up variables
|
||||
VideoSource = NULL;
|
||||
KeyFramesLoaded = false;
|
||||
FrameNumber = -1;
|
||||
ErrInfo.Buffer = FFMSErrMsg;
|
||||
ErrInfo.BufferSize = sizeof(FFMSErrMsg);
|
||||
|
@ -197,7 +194,7 @@ void FFmpegSourceVideoProvider::LoadVideo(wxString filename) {
|
|||
FFMS_DestroyIndex(Index);
|
||||
Index = NULL;
|
||||
ErrorMsg.Append(wxString::Format(_T("Couldn't find any video tracks: %s"), ErrInfo.Buffer));
|
||||
throw ErrorMsg;
|
||||
throw ErrorMsg;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -249,6 +246,7 @@ void FFmpegSourceVideoProvider::LoadVideo(wxString filename) {
|
|||
const FFMS_FrameInfo *CurFrameData;
|
||||
|
||||
// build list of keyframes and timecodes
|
||||
std::vector<int> TimecodesVector;
|
||||
for (int CurFrameNum = 0; CurFrameNum < VideoInfo->NumFrames; CurFrameNum++) {
|
||||
CurFrameData = FFMS_GetFrameInfo(FrameData, CurFrameNum);
|
||||
if (CurFrameData == NULL) {
|
||||
|
@ -258,47 +256,29 @@ void FFmpegSourceVideoProvider::LoadVideo(wxString filename) {
|
|||
|
||||
// keyframe?
|
||||
if (CurFrameData->KeyFrame)
|
||||
KeyFramesList.Add(CurFrameNum);
|
||||
KeyFramesList.push_back(CurFrameNum);
|
||||
|
||||
// calculate timestamp and add to timecodes vector
|
||||
int Timestamp = (int)((CurFrameData->PTS * TimeBase->Num) / TimeBase->Den);
|
||||
TimecodesVector.push_back(Timestamp);
|
||||
}
|
||||
KeyFramesLoaded = true;
|
||||
|
||||
// override already loaded timecodes?
|
||||
Timecodes.SetVFR(TimecodesVector);
|
||||
int OverrideTC = wxYES;
|
||||
if (VFR_Output.IsLoaded()) {
|
||||
OverrideTC = wxMessageBox(_("You already have timecodes loaded. Would you like to replace them with timecodes from the video file?"), _("Replace timecodes?"), wxYES_NO | wxICON_QUESTION);
|
||||
if (OverrideTC == wxYES) {
|
||||
VFR_Input.SetVFR(TimecodesVector);
|
||||
VFR_Output.SetVFR(TimecodesVector);
|
||||
}
|
||||
} else { // no timecodes loaded, go ahead and apply
|
||||
VFR_Input.SetVFR(TimecodesVector);
|
||||
VFR_Output.SetVFR(TimecodesVector);
|
||||
}
|
||||
Timecodes = agi::vfr::Framerate(TimecodesVector);
|
||||
|
||||
FrameNumber = 0;
|
||||
}
|
||||
|
||||
|
||||
/// @brief Close video
|
||||
///
|
||||
void FFmpegSourceVideoProvider::Close() {
|
||||
FFMS_DestroyVideoSource(VideoSource);
|
||||
VideoSource = NULL;
|
||||
|
||||
KeyFramesLoaded = false;
|
||||
KeyFramesList.clear();
|
||||
TimecodesVector.clear();
|
||||
FrameNumber = -1;
|
||||
Timecodes = agi::vfr::Framerate();
|
||||
CurFrame.Clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Get frame
|
||||
/// @param _n
|
||||
/// @return
|
||||
|
@ -323,48 +303,4 @@ const AegiVideoFrame FFmpegSourceVideoProvider::GetFrame(int _n) {
|
|||
CurFrame.SetTo(SrcFrame->Data, Width, Height, SrcFrame->Linesize, FORMAT_RGB32);
|
||||
return CurFrame;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Utility functions
|
||||
/// @return
|
||||
///
|
||||
int FFmpegSourceVideoProvider::GetWidth() {
|
||||
return Width;
|
||||
}
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
int FFmpegSourceVideoProvider::GetHeight() {
|
||||
return Height;
|
||||
}
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
int FFmpegSourceVideoProvider::GetFrameCount() {
|
||||
return VideoInfo->NumFrames;
|
||||
}
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
int FFmpegSourceVideoProvider::GetPosition() {
|
||||
return FrameNumber;
|
||||
}
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
///
|
||||
double FFmpegSourceVideoProvider::GetFPS() {
|
||||
return double(VideoInfo->FPSNumerator) / double(VideoInfo->FPSDenominator);
|
||||
}
|
||||
|
||||
|
||||
#endif /* WITH_FFMPEGSOURCE */
|
||||
|
||||
|
||||
|
|
|
@ -34,8 +34,6 @@
|
|||
/// @ingroup video_input ffms
|
||||
///
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#ifdef WITH_FFMPEGSOURCE
|
||||
#ifndef AGI_PRE
|
||||
#include <vector>
|
||||
|
@ -43,7 +41,6 @@
|
|||
|
||||
#include "ffmpegsource_common.h"
|
||||
#include "include/aegisub/video_provider.h"
|
||||
#include "vfr.h"
|
||||
|
||||
|
||||
/// @class FFmpegSourceVideoProvider
|
||||
|
@ -56,10 +53,8 @@ private:
|
|||
int Width; /// width in pixels
|
||||
int Height; /// height in pixels
|
||||
int FrameNumber; /// current framenumber
|
||||
wxArrayInt KeyFramesList; /// list of keyframes
|
||||
bool KeyFramesLoaded; /// keyframe loading state
|
||||
std::vector<int> TimecodesVector; /// list of timestamps
|
||||
FrameRate Timecodes; /// vfr object
|
||||
std::vector<int> KeyFramesList; /// list of keyframes
|
||||
agi::vfr::Framerate Timecodes; /// vfr object
|
||||
bool COMInited; /// COM initialization state
|
||||
|
||||
AegiVideoFrame CurFrame; /// current video frame
|
||||
|
@ -76,35 +71,22 @@ public:
|
|||
~FFmpegSourceVideoProvider();
|
||||
|
||||
const AegiVideoFrame GetFrame(int n);
|
||||
int GetPosition();
|
||||
int GetFrameCount();
|
||||
|
||||
int GetWidth();
|
||||
int GetHeight();
|
||||
double GetFPS();
|
||||
int GetPosition() const { return FrameNumber; }
|
||||
int GetFrameCount() const { return VideoInfo->NumFrames; }
|
||||
int GetWidth() const { return Width; }
|
||||
int GetHeight() const { return Height; }
|
||||
agi::vfr::Framerate GetFPS() const { return Timecodes; }
|
||||
|
||||
/// @brief Reports keyframe status
|
||||
/// @return Returns true if keyframes are loaded, false otherwise.
|
||||
bool AreKeyFramesLoaded() { return KeyFramesLoaded; };
|
||||
/// @brief Gets a list of keyframes
|
||||
/// @return Returns a wxArrayInt of keyframes.
|
||||
wxArrayInt GetKeyFrames() { return KeyFramesList; };
|
||||
/// @brief Checks if source is VFR
|
||||
/// @return Returns true.
|
||||
bool IsVFR() { return true; };
|
||||
/// @brief Gets a VFR framerate object
|
||||
/// @return Returns the framerate object.
|
||||
FrameRate GetTrueFrameRate() { return Timecodes; };
|
||||
/// @brief Gets the name of the provider
|
||||
/// @return Returns "FFmpegSource".
|
||||
wxString GetDecoderName() { return L"FFmpegSource"; }
|
||||
std::vector<int> GetKeyFrames() const { return KeyFramesList; };
|
||||
wxString GetDecoderName() const { return L"FFmpegSource"; }
|
||||
/// @brief Gets the desired cache behavior.
|
||||
/// @return Returns true.
|
||||
bool WantsCaching() { return true; }
|
||||
bool WantsCaching() const { return true; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// @class FFmpegSourceVideoProviderFactory
|
||||
/// @brief Creates a FFmpegSource video provider.
|
||||
class FFmpegSourceVideoProviderFactory : public VideoProviderFactory {
|
||||
|
@ -115,7 +97,4 @@ public:
|
|||
VideoProvider *CreateProvider(wxString video) { return new FFmpegSourceVideoProvider(video); }
|
||||
};
|
||||
|
||||
|
||||
#endif /* WITH_FFMPEGSOURCE */
|
||||
|
||||
|
||||
|
|
|
@ -34,9 +34,6 @@
|
|||
/// @ingroup video_input
|
||||
///
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#include "config.h"
|
||||
|
||||
#include <libaegisub/log.h>
|
||||
|
@ -44,7 +41,7 @@
|
|||
#include "compat.h"
|
||||
#include "main.h"
|
||||
#include "options.h"
|
||||
#include "vfr.h"
|
||||
|
||||
#ifdef WITH_AVISYNTH
|
||||
#include "video_provider_avs.h"
|
||||
#endif
|
||||
|
|
|
@ -54,8 +54,6 @@
|
|||
#define MacOffsetRect OffsetRect
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @param filename
|
||||
///
|
||||
|
@ -99,8 +97,6 @@ QuickTimeVideoProvider::QuickTimeVideoProvider(wxString filename) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
///
|
||||
QuickTimeVideoProvider::~QuickTimeVideoProvider() {
|
||||
|
@ -108,8 +104,6 @@ QuickTimeVideoProvider::~QuickTimeVideoProvider() {
|
|||
DeInitQuickTime();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
///
|
||||
void QuickTimeVideoProvider::Close() {
|
||||
|
@ -123,15 +117,10 @@ void QuickTimeVideoProvider::Close() {
|
|||
DisposeHandle(in_dataref);
|
||||
in_dataref = NULL;
|
||||
|
||||
keyframes.Clear();
|
||||
keyframes.clear();
|
||||
qt_timestamps.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @param _filename
|
||||
///
|
||||
|
@ -175,28 +164,11 @@ void QuickTimeVideoProvider::LoadVideo(const wxString _filename) {
|
|||
throw wxString(_T("QuickTime video provider: failed to index file"));
|
||||
|
||||
// ask about vfr override etc
|
||||
vfr_fps.SetVFR(timecodes);
|
||||
int override_tc = wxYES;
|
||||
if (VFR_Output.IsLoaded()) {
|
||||
override_tc = wxMessageBox(_("You already have timecodes loaded. Would you like to replace them with timecodes from the video file?"), _("Replace timecodes?"), wxYES_NO | wxICON_QUESTION);
|
||||
if (override_tc == wxYES) {
|
||||
VFR_Input.SetVFR(timecodes);
|
||||
VFR_Output.SetVFR(timecodes);
|
||||
}
|
||||
} else { // no timecodes loaded, go ahead and apply
|
||||
VFR_Input.SetVFR(timecodes);
|
||||
VFR_Output.SetVFR(timecodes);
|
||||
}
|
||||
|
||||
// set assumed "cfr" fps (dunno if this is actually used anywhere)
|
||||
double len_s = (double)GetMovieDuration(movie) / (double)GetMovieTimeScale(movie);
|
||||
assumed_fps = (double)num_frames / len_s;
|
||||
vfr_fps = agi::vfr::Framerate(timecodes);
|
||||
|
||||
cur_fn = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
|
@ -237,8 +209,6 @@ std::vector<int> QuickTimeVideoProvider::IndexFile() {
|
|||
return timecodes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @param n
|
||||
/// @return
|
||||
|
@ -283,76 +253,4 @@ const AegiVideoFrame QuickTimeVideoProvider::GetFrame(int n) {
|
|||
return dst_frame;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// @brief Utility functions
|
||||
/// @return
|
||||
///
|
||||
int QuickTimeVideoProvider::GetWidth() {
|
||||
return w;
|
||||
}
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
int QuickTimeVideoProvider::GetHeight() {
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
int QuickTimeVideoProvider::GetFrameCount() {
|
||||
return num_frames;
|
||||
}
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
int QuickTimeVideoProvider::GetPosition() {
|
||||
return cur_fn;
|
||||
}
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
double QuickTimeVideoProvider::GetFPS() {
|
||||
return assumed_fps;
|
||||
}
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
bool QuickTimeVideoProvider::AreKeyFramesLoaded() {
|
||||
if (keyframes.GetCount() > 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
wxArrayInt QuickTimeVideoProvider::GetKeyFrames() {
|
||||
return keyframes;
|
||||
}
|
||||
|
||||
|
||||
/// @brief DOCME
|
||||
///
|
||||
FrameRate QuickTimeVideoProvider::GetTrueFrameRate() {
|
||||
return vfr_fps;
|
||||
}
|
||||
|
||||
|
||||
#endif /* WITH_QUICKTIME */
|
||||
|
||||
|
||||
|
|
|
@ -49,8 +49,6 @@
|
|||
|
||||
|
||||
#include "include/aegisub/video_provider.h"
|
||||
#include "vfr.h"
|
||||
|
||||
|
||||
/// DOCME
|
||||
/// @class QuickTimeVideoProvider
|
||||
|
@ -58,47 +56,42 @@
|
|||
///
|
||||
/// DOCME
|
||||
class QuickTimeVideoProvider : public VideoProvider, QuickTimeProvider {
|
||||
private:
|
||||
/// source object
|
||||
Movie movie;
|
||||
|
||||
/// DOCME
|
||||
Movie movie; // source object
|
||||
/// render buffer
|
||||
GWorldPtr gw;
|
||||
|
||||
/// DOCME
|
||||
GWorldPtr gw; // render buffer
|
||||
|
||||
/// DOCME
|
||||
Handle in_dataref; // input data handle
|
||||
/// input data handle
|
||||
Handle in_dataref;
|
||||
|
||||
|
||||
/// DOCME
|
||||
|
||||
/// DOCME
|
||||
int w, h; // width/height
|
||||
/// width/height
|
||||
int w, h;
|
||||
|
||||
/// DOCME
|
||||
int num_frames; // length of file in frames
|
||||
/// length of file in frames
|
||||
int num_frames;
|
||||
|
||||
/// DOCME
|
||||
int cur_fn; // current frame number
|
||||
/// current frame number
|
||||
int cur_fn;
|
||||
|
||||
/// DOCME
|
||||
FrameRate vfr_fps; // vfr framerate
|
||||
/// vfr framerate
|
||||
Framerate vfr_fps;
|
||||
|
||||
/// DOCME
|
||||
double assumed_fps; // average framerate
|
||||
/// list of keyframes
|
||||
std::vector<int> keyframes;
|
||||
|
||||
/// DOCME
|
||||
wxArrayInt keyframes; // list of keyframes
|
||||
|
||||
/// DOCME
|
||||
std::vector<int> qt_timestamps; // qt timestamps (used for seeking)
|
||||
/// qt timestamps (used for seeking)
|
||||
std::vector<int> qt_timestamps;
|
||||
|
||||
|
||||
/// DOCME
|
||||
OSErr qt_err; // quicktime error code
|
||||
/// quicktime error code
|
||||
OSErr qt_err;
|
||||
|
||||
/// DOCME
|
||||
wxString errmsg; // aegisub error message
|
||||
/// aegisub error message
|
||||
wxString errmsg;
|
||||
|
||||
void LoadVideo(const wxString filename);
|
||||
std::vector<int> IndexFile();
|
||||
|
@ -109,34 +102,18 @@ public:
|
|||
~QuickTimeVideoProvider();
|
||||
|
||||
const AegiVideoFrame GetFrame(int n);
|
||||
int GetPosition();
|
||||
int GetFrameCount();
|
||||
|
||||
int GetWidth();
|
||||
int GetHeight();
|
||||
double GetFPS();
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
bool IsVFR() { return true; };
|
||||
FrameRate GetTrueFrameRate();
|
||||
wxArrayInt GetKeyFrames();
|
||||
bool QuickTimeVideoProvider::AreKeyFramesLoaded();
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
wxString GetDecoderName() { return L"QuickTime"; };
|
||||
|
||||
/// @brief DOCME
|
||||
/// @return
|
||||
///
|
||||
bool WantsCaching() { return true; };
|
||||
int GetPosition() const { return cur_fn; }
|
||||
int GetFrameCount() const { return num_frames; }
|
||||
int GetWidth() const { return w; }
|
||||
int GetHeight() const { return h; }
|
||||
agi::vfr::Framerate GetFPS() const { return vfr_fps; }
|
||||
std::vector<int> GetKeyFrames() const { return keyframes; };
|
||||
wxString GetDecoderName() const { return L"QuickTime"; };
|
||||
bool WantsCaching() const { return true; };
|
||||
wxString GetWarning() const { return errmsg; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// DOCME
|
||||
/// @class QuickTimeVideoProviderFactory
|
||||
/// @brief DOCME
|
||||
|
@ -151,7 +128,4 @@ public:
|
|||
VideoProvider *CreateProvider(wxString video) { return new QuickTimeVideoProvider(video); }
|
||||
};
|
||||
|
||||
|
||||
#endif /* WITH_QUICKTIME */
|
||||
|
||||
|
||||
|
|
|
@ -309,6 +309,7 @@ void YUV4MPEGVideoProvider::ParseFileHeader(const std::vector<wxString>& tags) {
|
|||
fps_rat.den = t_fps_den;
|
||||
pixfmt = t_pixfmt != Y4M_PIXFMT_NONE ? t_pixfmt : Y4M_PIXFMT_420JPEG;
|
||||
imode = t_imode != Y4M_ILACE_NOTSET ? t_imode : Y4M_ILACE_UNKNOWN;
|
||||
fps = double(fps_rat.num) / fps_rat.den;
|
||||
inited = true;
|
||||
}
|
||||
}
|
||||
|
@ -430,27 +431,3 @@ const AegiVideoFrame YUV4MPEGVideoProvider::GetFrame(int n) {
|
|||
|
||||
return dst_frame;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Utility functions
|
||||
int YUV4MPEGVideoProvider::GetWidth() {
|
||||
return w;
|
||||
}
|
||||
|
||||
int YUV4MPEGVideoProvider::GetHeight() {
|
||||
return h;
|
||||
}
|
||||
|
||||
int YUV4MPEGVideoProvider::GetFrameCount() {
|
||||
return num_frames;
|
||||
}
|
||||
|
||||
int YUV4MPEGVideoProvider::GetPosition() {
|
||||
return cur_fn;
|
||||
}
|
||||
|
||||
double YUV4MPEGVideoProvider::GetFPS() {
|
||||
return double(fps_rat.num) / double(fps_rat.den);
|
||||
}
|
||||
|
||||
|
|
|
@ -34,8 +34,6 @@
|
|||
/// @ingroup video_input
|
||||
///
|
||||
|
||||
|
||||
|
||||
#include "include/aegisub/video_provider.h"
|
||||
#ifndef AGI_PRE
|
||||
#include <stdio.h>
|
||||
|
@ -46,16 +44,12 @@
|
|||
#include <wx/log.h>
|
||||
#endif
|
||||
|
||||
|
||||
/// the maximum allowed header length, in bytes
|
||||
#define YUV4MPEG_HEADER_MAXLEN 128
|
||||
|
||||
|
||||
|
||||
/// @class YUV4MPEGVideoProvider
|
||||
/// @brief Implements reading of YUV4MPEG uncompressed video files
|
||||
class YUV4MPEGVideoProvider : public VideoProvider {
|
||||
private:
|
||||
/// Pixel formats
|
||||
enum Y4M_PixelFormat {
|
||||
Y4M_PIXFMT_NONE = -1, /// not set/unknown
|
||||
|
@ -131,6 +125,8 @@ private:
|
|||
int den; /// denominator
|
||||
} fps_rat; /// framerate
|
||||
|
||||
agi::vfr::Framerate fps;
|
||||
|
||||
/// a list of byte positions detailing where in the file
|
||||
/// each frame header can be found
|
||||
std::vector<int64_t> seek_table;
|
||||
|
@ -151,20 +147,13 @@ public:
|
|||
~YUV4MPEGVideoProvider();
|
||||
|
||||
const AegiVideoFrame GetFrame(int n);
|
||||
int GetPosition();
|
||||
int GetFrameCount();
|
||||
|
||||
int GetWidth();
|
||||
int GetHeight();
|
||||
double GetFPS();
|
||||
|
||||
bool AreKeyFramesLoaded() { return false; }
|
||||
wxArrayInt GetKeyFrames() { return wxArrayInt(); }
|
||||
bool IsVFR() { return false; };
|
||||
FrameRate GetTrueFrameRate() { return FrameRate(); }
|
||||
wxString GetDecoderName() { return L"YUV4MPEG"; }
|
||||
bool WantsCaching() { return true; }
|
||||
int GetPosition() const { return cur_fn; }
|
||||
int GetFrameCount() const { return num_frames; }
|
||||
int GetWidth() const { return w; }
|
||||
int GetHeight() const { return h; }
|
||||
agi::vfr::Framerate GetFPS() const { return fps; }
|
||||
std::vector<int> GetKeyFrames() const { return std::vector<int>(); };
|
||||
wxString GetDecoderName() const { return L"YU4MPEG"; };
|
||||
bool WantsCaching() const { return true; };
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -49,7 +49,6 @@
|
|||
#include "subs_edit_box.h"
|
||||
#include "subs_grid.h"
|
||||
#include "utils.h"
|
||||
#include "vfr.h"
|
||||
#include "video_context.h"
|
||||
#include "video_display.h"
|
||||
#include "video_slider.h"
|
||||
|
@ -226,8 +225,8 @@ void VideoSlider::OnMouse(wxMouseEvent &event) {
|
|||
if (canDrag) {
|
||||
// Shift click to snap to keyframe
|
||||
if (shift && Display) {
|
||||
wxArrayInt KeyFrames = VideoContext::Get()->GetKeyFrames();
|
||||
int keys = KeyFrames.Count();
|
||||
std::vector<int> KeyFrames = VideoContext::Get()->GetKeyFrames();
|
||||
int keys = KeyFrames.size();
|
||||
int clickedFrame = GetValueAtX(x);
|
||||
int closest = 0;
|
||||
int cur;
|
||||
|
@ -332,8 +331,8 @@ void VideoSlider::OnKeyDown(wxKeyEvent &event) {
|
|||
|
||||
// Jump to next sub boundary
|
||||
if (direction != 0) {
|
||||
int target1 = VFR_Output.GetFrameAtTime(curDiag->Start.GetMS(),true);
|
||||
int target2 = VFR_Output.GetFrameAtTime(curDiag->End.GetMS(),false);
|
||||
int target1 = VideoContext::Get()->FrameAtTime(curDiag->Start.GetMS(),agi::vfr::START);
|
||||
int target2 = VideoContext::Get()->FrameAtTime(curDiag->End.GetMS(),agi::vfr::END);
|
||||
bool drawn = false;
|
||||
|
||||
// Forward
|
||||
|
@ -376,8 +375,8 @@ void VideoSlider::OnKeyDown(wxKeyEvent &event) {
|
|||
// Prepare
|
||||
int prevKey = 0;
|
||||
int nextKey = VideoContext::Get()->GetLength()-1;
|
||||
wxArrayInt KeyFrames = VideoContext::Get()->GetKeyFrames();
|
||||
int keys = KeyFrames.Count();
|
||||
std::vector<int> KeyFrames = VideoContext::Get()->GetKeyFrames();
|
||||
int keys = KeyFrames.size();
|
||||
int cur = VideoContext::Get()->GetFrameN();
|
||||
int i;
|
||||
int temp;
|
||||
|
@ -481,8 +480,8 @@ void VideoSlider::DrawImage(wxDC &destdc) {
|
|||
int curX;
|
||||
if (Display && OPT_GET("Video/Slider/Show Keyframes")->GetBool()) {
|
||||
dc.SetPen(wxPen(shad));
|
||||
wxArrayInt KeyFrames = VideoContext::Get()->GetKeyFrames();
|
||||
int keys = KeyFrames.Count();
|
||||
std::vector<int> KeyFrames = VideoContext::Get()->GetKeyFrames();
|
||||
int keys = KeyFrames.size();
|
||||
for (int i=0;i<keys;i++) {
|
||||
curX = GetXAtValue(KeyFrames[i]);
|
||||
dc.DrawLine(curX,2,curX,8);
|
||||
|
|
|
@ -57,7 +57,6 @@
|
|||
#include "subs_edit_box.h"
|
||||
#include "subs_grid.h"
|
||||
#include "utils.h"
|
||||
#include "vfr.h"
|
||||
#include "video_context.h"
|
||||
#include "video_display.h"
|
||||
#include "video_provider_manager.h"
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
#include "subs_edit_box.h"
|
||||
#include "subs_grid.h"
|
||||
#include "utils.h"
|
||||
#include "vfr.h"
|
||||
#include "video_context.h"
|
||||
#include "video_display.h"
|
||||
#include "visual_tool_drag.h"
|
||||
|
@ -290,7 +289,7 @@ bool VisualToolDrag::InitializeDrag(feature_iterator feature) {
|
|||
// Set time of clicked feature to the current frame and shift all other
|
||||
// selected features by the same amount
|
||||
if (feature->type != DRAG_ORIGIN) {
|
||||
int time = VFR_Output.GetTimeAtFrame(frameNumber,true,true) - feature->line->Start.GetMS();
|
||||
int time = VideoContext::Get()->TimeAtFrame(frameNumber) - feature->line->Start.GetMS();
|
||||
int change = time - feature->time;
|
||||
|
||||
for (sel_iterator cur = selectedFeatures.begin(); cur != selectedFeatures.end(); ++cur) {
|
||||
|
|
Loading…
Reference in New Issue