diff --git a/mainwindow.cpp b/mainwindow.cpp
index 6a300cdd7..f4c76a839 100644
--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -3,6 +3,8 @@
#include "io/config.h"
+#include "project/sequence.h"
+
#include "panels/panels.h"
#include "panels/project.h"
#include "panels/effectcontrols.h"
@@ -85,6 +87,7 @@ MainWindow::MainWindow(QWidget *parent) :
setup_layout();
connect(ui->menuWindow, SIGNAL(aboutToShow()), this, SLOT(windowMenu_About_To_Be_Shown()));
+ connect(ui->menu_View, SIGNAL(aboutToShow()), this, SLOT(viewMenu_About_To_Be_Shown()));
QString data_dir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
if (!data_dir.isEmpty()) {
@@ -454,3 +457,37 @@ void MainWindow::windowMenu_About_To_Be_Shown() {
ui->actionTimeline->setChecked(panel_timeline->isVisible());
ui->actionViewer->setChecked(panel_viewer->isVisible());
}
+
+void MainWindow::viewMenu_About_To_Be_Shown() {
+ ui->actionFrames->setChecked(panel_viewer->timecode_view == TIMECODE_FRAMES);
+ ui->actionDrop_Frame->setChecked(panel_viewer->timecode_view == TIMECODE_DROP);
+ if (sequence != NULL) ui->actionDrop_Frame->setEnabled(frame_rate_is_droppable(sequence->frame_rate));
+ ui->actionNon_Drop_Frame->setChecked(panel_viewer->timecode_view == TIMECODE_NONDROP);
+}
+
+void MainWindow::on_actionFrames_triggered()
+{
+ panel_viewer->timecode_view = TIMECODE_FRAMES;
+ if (sequence != NULL) {
+ panel_viewer->update_playhead_timecode();
+ panel_viewer->update_end_timecode();
+ }
+}
+
+void MainWindow::on_actionDrop_Frame_triggered()
+{
+ panel_viewer->timecode_view = TIMECODE_DROP;
+ if (sequence != NULL) {
+ panel_viewer->update_playhead_timecode();
+ panel_viewer->update_end_timecode();
+ }
+}
+
+void MainWindow::on_actionNon_Drop_Frame_triggered()
+{
+ panel_viewer->timecode_view = TIMECODE_NONDROP;
+ if (sequence != NULL) {
+ panel_viewer->update_playhead_timecode();
+ panel_viewer->update_end_timecode();
+ }
+}
diff --git a/mainwindow.h b/mainwindow.h
index 6bce28352..ba01fdc2c 100644
--- a/mainwindow.h
+++ b/mainwindow.h
@@ -117,6 +117,14 @@ private slots:
void windowMenu_About_To_Be_Shown();
+ void on_actionFrames_triggered();
+
+ void on_actionDrop_Frame_triggered();
+
+ void on_actionNon_Drop_Frame_triggered();
+
+ void viewMenu_About_To_Be_Shown();
+
private:
Ui::MainWindow *ui;
void setup_layout();
diff --git a/mainwindow.ui b/mainwindow.ui
index f1cd0cb57..f8eb3c884 100644
--- a/mainwindow.ui
+++ b/mainwindow.ui
@@ -94,6 +94,10 @@
+
+
+
+
diff --git a/panels/timeline.cpp b/panels/timeline.cpp
index 627b3a7bb..2dff352f6 100644
--- a/panels/timeline.cpp
+++ b/panels/timeline.cpp
@@ -215,25 +215,6 @@ void Timeline::redo() {
}
}
-QString frame_to_timecode(long f) {
- int hours = 0;
- int mins = 0;
- int secs = 0;
- int frames = 0;
- if (sequence != NULL) {
- int int_fps = qRound(sequence->frame_rate);
- hours = f/ (3600 * int_fps);
- mins = f / (60*int_fps) % 60;
- secs = f/int_fps % 60;
- frames = f%int_fps;
- }
- return QString(QString::number(hours).rightJustified(2, '0') +
- ":" + QString::number(mins).rightJustified(2, '0') +
- ":" + QString::number(secs).rightJustified(2, '0') +
- ":" + QString::number(frames).rightJustified(2, '0')
- );
-}
-
void Timeline::repaint_timeline() {
if (playing) {
playhead = round(playhead_start + ((QDateTime::currentMSecsSinceEpoch()-start_msecs) * 0.001 * sequence->frame_rate));
@@ -245,7 +226,7 @@ void Timeline::repaint_timeline() {
panel_viewer->viewer_widget->update();
last_frame = playhead;
}
- panel_viewer->ui->currentTimecode->setText(frame_to_timecode(playhead));
+ panel_viewer->update_playhead_timecode();
}
void Timeline::redraw_all_clips(bool changed) {
@@ -261,7 +242,7 @@ void Timeline::redraw_all_clips(bool changed) {
ui->audio_area->redraw_clips();
ui->headers->update();
- panel_viewer->ui->endTimecode->setText(frame_to_timecode(sequence->getEndFrame()));
+ panel_viewer->update_end_timecode();
}
}
diff --git a/panels/viewer.cpp b/panels/viewer.cpp
index 9f3416c5c..9ba2a36af 100644
--- a/panels/viewer.cpp
+++ b/panels/viewer.cpp
@@ -6,6 +6,9 @@
#include "project/sequence.h"
#include "panels/panels.h"
+#define FRAMES_IN_ONE_MINUTE 1798 // 1800 - 2
+#define FRAMES_IN_TEN_MINUTES 17978 // (FRAMES_IN_ONE_MINUTE * 10) - 2
+
extern "C" {
#include
}
@@ -19,6 +22,7 @@ Viewer::Viewer(QWidget *parent) :
ui->setupUi(this);
ui->glViewerPane->child = ui->openGLWidget;
viewer_widget = ui->openGLWidget;
+ timecode_view = TIMECODE_DROP;
update_sequence();
}
@@ -28,6 +32,81 @@ Viewer::~Viewer()
delete ui;
}
+QString Viewer::frame_to_timecode(long f) {
+ if (timecode_view == TIMECODE_FRAMES) {
+ return QString::number(f);
+ }
+
+ // return timecode
+ int hours = 0;
+ int mins = 0;
+ int secs = 0;
+ int frames = 0;
+ QString token = ":";
+
+ if (sequence != NULL) {
+ if (timecode_view == TIMECODE_DROP && frame_rate_is_droppable(sequence->frame_rate)) {
+ //CONVERT A FRAME NUMBER TO DROP FRAME TIMECODE
+ //Code by David Heidelberger, adapted from Andrew Duncan, further adapted for Olive by Olive Team
+ //Given an int called framenumber and a double called framerate
+ //Framerate should be 29.97, 59.94, or 23.976, otherwise the calculations will be off.
+
+ int d;
+ int m;
+
+ int dropFrames = round(sequence->frame_rate * .066666); //Number of frames to drop on the minute marks is the nearest integer to 6% of the framerate
+ int framesPerHour = round(sequence->frame_rate*60*60); //Number of frames in an hour
+ int framesPer24Hours = framesPerHour*24; //Number of frames in a day - timecode rolls over after 24 hours
+ int framesPer10Minutes = round(sequence->frame_rate * 60 * 10); //Number of frames per ten minutes
+ int framesPerMinute = (round(sequence->frame_rate)*60)- dropFrames; //Number of frames per minute is the round of the framerate * 60 minus the number of dropped frames
+
+ //If framenumber is greater than 24 hrs, next operation will rollover clock
+ f = f % framesPer24Hours; //% is the modulus operator, which returns a remainder. a % b = the remainder of a/b
+
+ d = f / framesPer10Minutes; // \ means integer division, which is a/b without a remainder. Some languages you could use floor(a/b)
+ m = f % framesPer10Minutes;
+
+ //In the original post, the next line read m>1, which only worked for 29.97. Jean-Baptiste Mardelle correctly pointed out that m should be compared to dropFrames.
+ if (m > dropFrames) {
+ f = f + (dropFrames*9*d) + dropFrames * ((m - dropFrames) / framesPerMinute);
+ } else {
+ f = f + dropFrames*9*d;
+ }
+
+ int frRound = round(sequence->frame_rate);
+ frames = f % frRound;
+ secs = (f / frRound) % 60;
+ mins = ((f / frRound) / 60) % 60;
+ hours = (((f / frRound) / 60) / 60);
+
+ token = ";";
+ } else {
+ int int_fps = qRound(sequence->frame_rate);
+ hours = f/ (3600 * int_fps);
+ mins = f / (60*int_fps) % 60;
+ secs = f/int_fps % 60;
+ frames = f%int_fps;
+ }
+ }
+ return QString(QString::number(hours).rightJustified(2, '0') +
+ ":" + QString::number(mins).rightJustified(2, '0') +
+ ":" + QString::number(secs).rightJustified(2, '0') +
+ token + QString::number(frames).rightJustified(2, '0')
+ );
+}
+
+bool frame_rate_is_droppable(float rate) {
+ return (rate == 23.976f || rate == 29.97f || rate == 59.94f);
+}
+
+void Viewer::update_playhead_timecode() {
+ ui->currentTimecode->setText(frame_to_timecode(panel_timeline->playhead));
+}
+
+void Viewer::update_end_timecode() {
+ ui->endTimecode->setText(frame_to_timecode(sequence->getEndFrame()));
+}
+
void Viewer::update_sequence() {
bool null_sequence = (sequence == NULL);
@@ -42,6 +121,15 @@ void Viewer::update_sequence() {
init_audio();
if (!null_sequence) {
+ if (frame_rate_is_droppable(sequence->frame_rate)) {
+ timecode_view = TIMECODE_DROP;
+ } else {
+ timecode_view = TIMECODE_NONDROP;
+ }
+
+ update_playhead_timecode();
+ update_end_timecode();
+
ui->glViewerPane->aspect_ratio = (float) sequence->width / (float) sequence->height;
ui->glViewerPane->adjust();
}
diff --git a/panels/viewer.h b/panels/viewer.h
index 63be105bc..2f30bed66 100644
--- a/panels/viewer.h
+++ b/panels/viewer.h
@@ -1,6 +1,10 @@
#ifndef VIEWER_H
#define VIEWER_H
+#define TIMECODE_DROP 0
+#define TIMECODE_NONDROP 1
+#define TIMECODE_FRAMES 2
+
#include
class Timeline;
@@ -11,6 +15,8 @@ namespace Ui {
class Viewer;
}
+bool frame_rate_is_droppable(float rate);
+
class Viewer : public QDockWidget
{
Q_OBJECT
@@ -21,6 +27,9 @@ public:
void update_sequence();
void compose();
void set_playpause_icon(bool play);
+ int timecode_view;
+ void update_playhead_timecode();
+ void update_end_timecode();
ViewerWidget* viewer_widget;
@@ -36,8 +45,8 @@ private slots:
void on_pushButton_3_clicked();
-private:
-
+private:
+ QString frame_to_timecode(long f);
};
#endif // VIEWER_H
diff --git a/panels/viewer.ui b/panels/viewer.ui
index 8ef5d0b8c..7a748347c 100644
--- a/panels/viewer.ui
+++ b/panels/viewer.ui
@@ -82,7 +82,7 @@
-
- 00:00:00:00
+ 0
@@ -299,7 +299,7 @@
-
- 00:00:00:00
+ 0