From a28dc9532fb0fe6f9dd07cfdb1029ce17bd98e4b Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Mardelle Date: Wed, 24 Mar 2010 07:59:07 +0000 Subject: [PATCH] Fix dropframe timecode, patch from John T. Mertz http://kdenlive.org/mantis/view.php?id=1033 svn path=/trunk/kdenlive/; revision=4353 --- src/clipdurationdialog.cpp | 5 +++ src/clipproperties.cpp | 1 + src/dvdwizardchapters.cpp | 2 +- src/mainwindow.cpp | 6 ++- src/markerdialog.cpp | 2 +- src/monitor.cpp | 5 ++- src/monitormanager.cpp | 2 + src/projectlist.cpp | 8 +++- src/projectlist.h | 1 + src/slideshowclip.cpp | 9 +++- src/timecode.cpp | 89 +++++++++++++++++++++++--------------- src/timecode.h | 3 ++ src/titlewidget.cpp | 3 ++ 13 files changed, 94 insertions(+), 42 deletions(-) diff --git a/src/clipdurationdialog.cpp b/src/clipdurationdialog.cpp index 273b2f08..91ced7ca 100644 --- a/src/clipdurationdialog.cpp +++ b/src/clipdurationdialog.cpp @@ -69,6 +69,11 @@ ClipDurationDialog::ClipDurationDialog(AbstractClipItem *clip, Timecode tc, GenT m_view.clip_position->setValidator(valid); m_view.end_position->setInputMask(""); m_view.clip_position->setValidator(valid); + } else { + m_view.clip_position->setInputMask(m_tc.inputMask()); + m_view.crop_position->setInputMask(m_tc.inputMask()); + m_view.clip_duration->setInputMask(m_tc.inputMask()); + m_view.end_position->setInputMask(m_tc.inputMask()); } m_view.clip_position->setText(tc.getDisplayTimecode(m_clip->startPos(), m_framesDisplay)); m_view.crop_position->setText(tc.getDisplayTimecode(m_clip->cropStart(), m_framesDisplay)); diff --git a/src/clipproperties.cpp b/src/clipproperties.cpp index 89dcc6dc..4b8c9dc5 100644 --- a/src/clipproperties.cpp +++ b/src/clipproperties.cpp @@ -265,6 +265,7 @@ ClipProperties::ClipProperties(DocClipBase *clip, Timecode tc, double fps, QWidg m_view.clip_filesize->setHidden(true); m_view.label_size->setHidden(true); } + m_view.clip_duration->setInputMask(tc.inputMask()); m_view.clip_duration->setText(tc.getTimecode(m_clip->duration())); if (t != IMAGE && t != COLOR && t != TEXT) m_view.clip_duration->setReadOnly(true); else connect(m_view.clip_duration, SIGNAL(editingFinished()), this, SLOT(slotCheckMaxLength())); diff --git a/src/dvdwizardchapters.cpp b/src/dvdwizardchapters.cpp index e0749817..2b4aa3bc 100644 --- a/src/dvdwizardchapters.cpp +++ b/src/dvdwizardchapters.cpp @@ -131,7 +131,7 @@ void DvdWizardChapters::slotRemoveChapter() void DvdWizardChapters::slotGoToChapter() { - m_monitor->setTimePos(m_view.chapters_list->currentItem()->text() + ":00"); + m_monitor->setTimePos(m_tc.reformatSeparators(m_view.chapters_list->currentItem()->text() + ":00")); } void DvdWizardChapters::setVobFiles(bool isPal, bool isWide, const QStringList movies, const QStringList durations, const QStringList chapters) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 4a1a0c67..84a74679 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1844,6 +1844,7 @@ void MainWindow::slotEditProjectSettings() m_transitionConfig->updateProjectFormat(m_activeDocument->mltProfile(), m_activeDocument->timecode(), m_activeDocument->tracksList()); m_effectStack->updateProjectFormat(m_activeDocument->mltProfile(), m_activeDocument->timecode()); + m_projectList->updateProjectFormat(m_activeDocument->timecode()); if (m_renderWidget) m_renderWidget->setProfile(m_activeDocument->mltProfile()); m_timelineArea->setTabText(m_timelineArea->currentIndex(), m_activeDocument->description()); //m_activeDocument->clipManager()->resetProducersList(m_projectMonitor->render->producersList()); @@ -1851,6 +1852,8 @@ void MainWindow::slotEditProjectSettings() if (updateFps) m_activeTimeline->updateProjectFps(); m_activeDocument->setModified(true); m_commandStack->activeStack()->clear(); + //Update the mouse position display so it will display in DF/NDF format by default based on the project setting. + slotUpdateMousePosition(0); // We need to desactivate & reactivate monitors to get a refresh //m_monitorManager->switchMonitors(); } @@ -2082,7 +2085,8 @@ void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc) //cha m_activeTimeline->updateProjectFps(); m_activeDocument->checkProjectClips(); if (KdenliveSettings::dropbframes()) slotUpdatePreviewSettings(); - + //Update the mouse position display so it will display in DF/NDF format by default based on the project setting. + slotUpdateMousePosition(0); // set tool to select tool m_buttonSelectTool->setChecked(true); } diff --git a/src/markerdialog.cpp b/src/markerdialog.cpp index 64bc1ee9..2f9ff112 100644 --- a/src/markerdialog.cpp +++ b/src/markerdialog.cpp @@ -87,7 +87,7 @@ MarkerDialog::MarkerDialog(DocClipBase *clip, CommentedTime t, Timecode tc, cons QValidator *valid = new QIntValidator(this); marker_position->setInputMask(""); marker_position->setValidator(valid); - } + } else marker_position->setInputMask(tc.inputMask()); marker_position->setText(tc.getDisplayTimecode(t.time(), m_frameDisplay)); marker_comment->setText(t.comment()); diff --git a/src/monitor.cpp b/src/monitor.cpp index 912df46e..9504ec4f 100644 --- a/src/monitor.cpp +++ b/src/monitor.cpp @@ -118,7 +118,8 @@ Monitor::Monitor(QString name, MonitorManager *manager, QString profile, QWidget if (m_frametimecode) { m_timePos->setInputMask(QString()); m_timePos->setValidator(new QIntValidator(this)); - } else m_timePos->setInputMask("99:99:99:99"); + } else m_timePos->setInputMask(m_monitorManager->timecode().inputMask()); + toolbar->addWidget(m_timePos); connect(m_timePos, SIGNAL(editingFinished()), this, SLOT(slotSeek())); @@ -844,7 +845,7 @@ void Monitor::updateTimecodeFormat() } else { int pos = m_timePos->text().toInt(); m_timePos->setValidator(0); - m_timePos->setInputMask("99:99:99:99"); + m_timePos->setInputMask(m_monitorManager->timecode().inputMask()); m_timePos->setText(m_monitorManager->timecode().getTimecodeFromFrames(pos)); } } diff --git a/src/monitormanager.cpp b/src/monitormanager.cpp index 968de22e..9348c9de 100644 --- a/src/monitormanager.cpp +++ b/src/monitormanager.cpp @@ -165,8 +165,10 @@ void MonitorManager::slotResetProfiles() if (m_projectMonitor == NULL || m_clipMonitor == NULL) return; activateMonitor("clip"); m_clipMonitor->resetProfile(KdenliveSettings::current_profile()); + m_clipMonitor->updateTimecodeFormat(); activateMonitor("project"); m_projectMonitor->resetProfile(KdenliveSettings::current_profile()); + m_projectMonitor->updateTimecodeFormat(); //m_projectMonitor->refreshMonitor(true); } diff --git a/src/projectlist.cpp b/src/projectlist.cpp index a0618d18..2c33398a 100644 --- a/src/projectlist.cpp +++ b/src/projectlist.cpp @@ -202,6 +202,11 @@ void ProjectList::setHeaderInfo(const QByteArray &state) m_listView->header()->restoreState(state); } +void ProjectList::updateProjectFormat(Timecode t) +{ + m_timecode = t; +} + void ProjectList::slotEditClip() { QList list = m_listView->selectedItems(); @@ -978,7 +983,8 @@ void ProjectList::slotAddColorClip() dia_ui.setupUi(dia); dia->setWindowTitle(i18n("Color Clip")); dia_ui.clip_name->setText(i18n("Color Clip")); - dia_ui.clip_duration->setText(KdenliveSettings::color_duration()); + dia_ui.clip_duration->setInputMask(m_timecode.inputMask()); + dia_ui.clip_duration->setText(m_timecode.reformatSeparators(KdenliveSettings::color_duration())); if (dia->exec() == QDialog::Accepted) { QString color = dia_ui.clip_color->color().name(); color = color.replace(0, 1, "0x") + "ff"; diff --git a/src/projectlist.h b/src/projectlist.h index a3e31063..ac8c509a 100644 --- a/src/projectlist.h +++ b/src/projectlist.h @@ -140,6 +140,7 @@ public: void slotUpdateClipProperties(const QString &id, QMap properties); QByteArray headerInfo() const; void setHeaderInfo(const QByteArray &state); + void updateProjectFormat(Timecode t); void setupMenu(QMenu *addMenu, QAction *defaultAction); void setupGeneratorMenu(QMenu *addMenu, QMenu *transcodeMenu); QString currentClipUrl() const; diff --git a/src/slideshowclip.cpp b/src/slideshowclip.cpp index 620cc4cb..04c2914d 100644 --- a/src/slideshowclip.cpp +++ b/src/slideshowclip.cpp @@ -52,8 +52,11 @@ SlideshowClip::SlideshowClip(Timecode tc, QWidget * parent) : m_view.image_type->addItem("TGA (*.tga)", "tga"); m_view.image_type->addItem("TIFF (*.tiff)", "tiff"); m_view.image_type->addItem("Open EXR (*.exr)", "exr"); - m_view.clip_duration->setText(KdenliveSettings::image_duration()); - m_view.luma_duration->setText("00:00:00:24"); + + m_view.clip_duration->setInputMask(m_timecode.inputMask()); + m_view.clip_duration->setText(m_timecode.reformatSeparators(KdenliveSettings::image_duration())); + m_view.luma_duration->setInputMask(m_timecode.inputMask()); + m_view.luma_duration->setText(m_timecode.getTimecodeFromFrames(int(ceil(m_timecode.fps())))); m_view.folder_url->setUrl(QDir::homePath()); m_view.clip_duration_format->addItem(i18n("hh:mm:ss::ff")); @@ -225,7 +228,9 @@ void SlideshowClip::slotUpdateDurationFormat(int ix) m_view.luma_duration_frames->setValue(m_timecode.getFrameCount(m_view.luma_duration->text())); } else { // switching to timecode format + m_view.clip_duration->setInputMask(m_timecode.inputMask()); m_view.clip_duration->setText(m_timecode.getTimecodeFromFrames(m_view.clip_duration_frames->value())); + m_view.luma_duration->setInputMask(m_timecode.inputMask()); m_view.luma_duration->setText(m_timecode.getTimecodeFromFrames(m_view.luma_duration_frames->value())); } m_view.clip_duration_frames->setHidden(!framesFormat); diff --git a/src/timecode.cpp b/src/timecode.cpp index 1b25df21..5be3c3f6 100644 --- a/src/timecode.cpp +++ b/src/timecode.cpp @@ -36,6 +36,24 @@ double Timecode::fps() const return m_realFps; //m_displayedFramesPerSecond; } +bool Timecode::df() const +{ + return m_dropFrame; +} + +QString Timecode::inputMask() const +{ + if (m_dropFrame) return "99:99.99:99"; + return "99:99:99:99"; +} + +QString Timecode::reformatSeparators(QString duration) const +{ + if (m_dropFrame) { + return duration.replace(5, 1, '.'); + } + return duration.replace(5, 1, ':'); +} int Timecode::getDisplayFrameCount(const QString duration, bool frameDisplay) const { @@ -46,30 +64,25 @@ int Timecode::getDisplayFrameCount(const QString duration, bool frameDisplay) co int Timecode::getFrameCount(const QString duration) const { if (m_dropFrame) { - // calculate how many frames need to be dropped every minute. - int frames; - int toDrop = (int) floor(600.0 * (m_displayedFramesPerSecond - m_realFps) + 0.5); - - int perMinute = toDrop / 9; - int tenthMinute = toDrop % 9; - - // calculate how many frames are in a normal minute, and how many are in a tenth minute. - int normalMinuteFrames = (m_displayedFramesPerSecond * 60) - perMinute; - int tenthMinuteFrames = (m_displayedFramesPerSecond * 60) - tenthMinute;; - - // Number of actual frames in a 10 minute interval : - int tenMinutes = (normalMinuteFrames * 9) + tenthMinuteFrames; - frames = 6 * duration.section(':', 0, 0).toInt() * tenMinutes; - int minutes = duration.section(':', 1, 1).toInt(); - frames += ((int) minutes / 10) * tenMinutes; - int mins = minutes % 10; - if (mins > 0) { - frames += tenthMinuteFrames; - mins--; - if (mins > 0) frames += mins * normalMinuteFrames; + //Get Hours, Minutes, Seconds, Frames from timecode + int hours, minutes, seconds, frames; + + hours = duration.section(':', 0, 0).toInt(); + if (duration.contains('.')) { + minutes = duration.section('.', 0, 0).section(':', 1, 1).toInt(); + seconds = duration.section('.', 1, 1).section(':', 0, 0).toInt(); + frames = duration.section('.', 1, 1).section(':', 1, 1).toInt(); + } else { + //Handle Drop Frame timecode frame calculations, even if the timecode supplied uses incorrect "99:99:99:99" format instead of "99:99.99:99" + minutes = duration.section(':', 1, 1).toInt(); + seconds = duration.section(':', 2, 2).toInt(); + frames = duration.section(':', 3, 3).toInt(); } - if (minutes % 10 > 0) frames -= perMinute; - frames += duration.section(':', 2, 2).toInt() * m_displayedFramesPerSecond + duration.section(':', 3, 3).toInt(); + + //Calculate the frame count + int dropRate = (int) ((ceil(m_displayedFramesPerSecond) / 30) * 2); + frames += ((hours * 60 + minutes) * 60 + seconds) * m_displayedFramesPerSecond; + frames -= dropRate * ((hours * 60 + minutes) - (floor((hours * 60 + minutes) / 10))); return frames; } return (int)((duration.section(':', 0, 0).toInt()*3600.0 + duration.section(':', 1, 1).toInt()*60.0 + duration.section(':', 2, 2).toInt()) * m_realFps + duration.section(':', 3, 3).toInt()); @@ -229,9 +242,13 @@ QString Timecode::getTimecodeHH_MM_SS_HH(const GenTime & time) const text.append(QString::number(hours).rightJustified(2, '0', false)); text.append(':'); text.append(QString::number(minutes).rightJustified(2, '0', false)); - text.append(':'); + if (m_dropFrame) { + text.append('.'); + } else { + text.append(':'); + } text.append(QString::number(seconds).rightJustified(2, '0', false)); - text.append(':'); + text.append(':'); text.append(QString::number(hundredths).rightJustified(2, '0', false)); return text; @@ -258,14 +275,14 @@ QString Timecode::getTimecodeDropFrame(int frames) const // for NTSC times, but is untested for any others - it is in no way an "official" algorithm, unless it's by fluke. // calculate how many frames need to be dropped every minute. - int toDrop = (int) floor(600.0 * (m_displayedFramesPerSecond - m_realFps) + 0.5); - - int perMinute = toDrop / 9; - int tenthMinute = toDrop % 9; + int dropRate = 0; + if (m_dropFrame) { + dropRate = (int) ((ceil(m_displayedFramesPerSecond) / 30) * 2); + } // calculate how many frames are in a normal minute, and how many are in a tenth minute. - int normalMinuteFrames = (m_displayedFramesPerSecond * 60) - perMinute; - int tenthMinuteFrames = (m_displayedFramesPerSecond * 60) - tenthMinute;; + int normalMinuteFrames = (m_displayedFramesPerSecond * 60) - dropRate; + int tenthMinuteFrames = (m_displayedFramesPerSecond * 60); // Number of actual frames in a 10 minute interval : int tenMinutes = (normalMinuteFrames * 9) + tenthMinuteFrames; @@ -287,7 +304,7 @@ QString Timecode::getTimecodeDropFrame(int frames) const // normal minute logic applies. numMinutes = 1 + (frames - tenthMinuteFrames) / normalMinuteFrames; frames = (frames - tenthMinuteFrames) % normalMinuteFrames; - frames += tenthMinute + perMinute; + frames += dropRate; } // We now have HH:MM:??:?? @@ -303,9 +320,13 @@ QString Timecode::getTimecodeDropFrame(int frames) const text.append(':'); text.append(QString::number(tenMinuteIntervals)); text.append(QString::number(numMinutes)); - text.append(':'); + if (m_dropFrame) { + text.append('.'); + } else { + text.append(':'); + } text.append(QString::number(seconds).rightJustified(2, '0', false)); - text.append(':'); + text.append(':'); text.append(QString::number(frames).rightJustified(2, '0', false)); return text; diff --git a/src/timecode.h b/src/timecode.h index e10ae4af..3fac0644 100644 --- a/src/timecode.h +++ b/src/timecode.h @@ -58,6 +58,9 @@ public: const QString getDisplayTimecodeFromFrames(int frames, bool frameDisplay) const; const QString getTimecodeFromFrames(int frames) const; double fps() const; + bool df() const; + QString inputMask() const; + QString reformatSeparators(QString duration) const; private: Formats m_format; diff --git a/src/titlewidget.cpp b/src/titlewidget.cpp index 7872fff8..05c5ad72 100644 --- a/src/titlewidget.cpp +++ b/src/titlewidget.cpp @@ -142,6 +142,9 @@ TitleWidget::TitleWidget(KUrl url, Timecode tc, QString projectTitlePath, Render m_frameHeight = render->renderHeight(); showToolbars(TITLE_SELECT); + //If project is drop frame, set the input mask as such. + title_duration->setInputMask(m_tc.inputMask()); + //TODO: get default title duration instead of hardcoded one title_duration->setText(m_tc.getTimecode(GenTime(5000 / 1000.0))); -- 2.39.2