From 614488fd7f7898091b65d6768b87c5623e0bc087 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 6 Sep 2018 11:14:53 +1000 Subject: [PATCH] updated readme --- README.md | 4 ++- mainwindow.cpp | 2 ++ panels/timeline.cpp | 1 + playback/audio.cpp | 22 ++++++++++----- playback/audio.h | 31 +++++++++++---------- playback/cacher.cpp | 42 +++++++++++++--------------- playback/playback.cpp | 6 +++- ui/keyframeview.cpp | 64 ++++++++++++++++++++++--------------------- 8 files changed, 95 insertions(+), 77 deletions(-) diff --git a/README.md b/README.md index 59c1e2593..f9b69b00c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ # Olive Video Editor -Olive is a non-linear video editor for Windows, macOS, and Linux. Binaries are not available as of yet, but will be very soon. If you're building from source, you'll need Qt and FFmpeg (recommended versions are Qt 5.5 and FFmpeg 3.4.2). \ No newline at end of file +Olive is a non-linear video editor for Windows, macOS, and Linux. + +Discover more and download binaries at: https://www.olivevideoeditor.org/ \ No newline at end of file diff --git a/mainwindow.cpp b/mainwindow.cpp index e4bc4829a..1fe305467 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -374,11 +374,13 @@ void MainWindow::closeEvent(QCloseEvent *e) { void MainWindow::paintEvent(QPaintEvent *event) { QMainWindow::paintEvent(event); +#ifndef QT_DEBUG if (!demoNoticeShown) { DemoNotice* d = new DemoNotice(this); d->open(); demoNoticeShown = true; } +#endif } void MainWindow::on_action_Save_Project_triggered() diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 381db8cb5..d157124a7 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -176,6 +176,7 @@ void Timeline::play() { playback_updater.start(); playing = true; panel_viewer->set_playpause_icon(false); + audio_thread->notifyReceiver(); } void Timeline::pause() { diff --git a/playback/audio.cpp b/playback/audio.cpp index c29afb1fe..186a6da5b 100644 --- a/playback/audio.cpp +++ b/playback/audio.cpp @@ -41,7 +41,7 @@ void init_audio() { qWarning() << "[WARNING] Couldn't initialize audio. Audio format is not supported by backend"; } else { audio_output = new QAudioOutput(audio_format); - audio_output->setBufferSize(20480); + audio_output->setNotifyInterval(5); // connect audio_io_device = audio_output->start(); @@ -49,7 +49,8 @@ void init_audio() { // start sender thread audio_thread = new AudioSenderThread(); - audio_thread->start(); + QObject::connect(audio_output, SIGNAL(notify()), audio_thread, SLOT(notifyReceiver())); + audio_thread->start(QThread::TimeCriticalPriority); clear_audio_ibuffer(); } @@ -67,7 +68,7 @@ void stop_audio() { } void clear_audio_ibuffer() { - memset(audio_ibuffer, 0, audio_ibuffer_size); + memset(audio_ibuffer, 0, audio_ibuffer_size); audio_ibuffer_read = 0; } @@ -90,13 +91,17 @@ void AudioSenderThread::stop() { wait(); } +void AudioSenderThread::notifyReceiver() { + cond.wakeAll(); +} + void AudioSenderThread::run() { // start data loop send_audio_to_output(0, audio_ibuffer_size); lock.lock(); while (true) { - msleep(15); + cond.wait(&lock); if (close) { break; } else if (panel_timeline->playing) { @@ -118,7 +123,8 @@ void AudioSenderThread::run() { int AudioSenderThread::send_audio_to_output(int offset, int max) { // send audio to device int actual_write = audio_io_device->write((const char*) audio_ibuffer+offset, max); - audio_ibuffer_read += actual_write; + + int audio_ibuffer_limit = audio_ibuffer_read + actual_write; // send samples to audio monitor cache if (panel_timeline->ui->audio_monitor->sample_cache_offset == -1) { @@ -132,9 +138,9 @@ int AudioSenderThread::send_audio_to_output(int offset, int max) { samples.fill(0); // TODO: I don't like this, but i'm not sure if there's a smarter way to do it - while (buffer_offset < audio_ibuffer_read) { + while (buffer_offset < audio_ibuffer_limit) { sample_cache_playhead++; - next_buffer_offset = qMin(get_buffer_offset_from_frame(sample_cache_playhead), audio_ibuffer_read); + next_buffer_offset = qMin(get_buffer_offset_from_frame(sample_cache_playhead), audio_ibuffer_limit); while (buffer_offset < next_buffer_offset) { for (i=0;i samples; + int send_audio_to_output(int offset, int max); +}; + extern QAudioOutput* audio_output; extern QIODevice* audio_io_device; +extern AudioSenderThread* audio_thread; #define audio_ibuffer_size 192000 extern qint8 audio_ibuffer[audio_ibuffer_size]; @@ -27,18 +44,4 @@ void init_audio(); void stop_audio(); int get_buffer_offset_from_frame(long frame); -class AudioSenderThread : public QThread { - Q_OBJECT -public: - AudioSenderThread(); - void run(); - void stop(); - QWaitCondition cond; - bool close; - QMutex lock; -private: - QVector samples; - int send_audio_to_output(int offset, int max); -}; - #endif // AUDIO_H diff --git a/playback/cacher.cpp b/playback/cacher.cpp index d47eae22f..63449a2e4 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -69,13 +69,7 @@ void cache_audio_worker(Clip* c, Clip* nest) { if (nest != NULL) { timeline_in = refactor_frame_number(timeline_in, c->sequence->frame_rate, sequence->frame_rate) + nest->timeline_in; timeline_out = refactor_frame_number(timeline_out, c->sequence->frame_rate, sequence->frame_rate) + nest->timeline_in; - } - - // - // (c->clip_in / c->sequence->frame_rate) is the starting point in seconds - // we need to convert it to bytes - // - // + } while (written < max_write) { // gets one frame worth of audio and sends it to the audio buffer @@ -126,15 +120,15 @@ void cache_audio_worker(Clip* c, Clip* nest) { if (c->audio_buffer_write == 0) { c->audio_buffer_write = get_buffer_offset_from_frame(qMax(timeline_in, c->audio_target_frame)); - int offset = audio_ibuffer_read - c->audio_buffer_write; - if (offset > 0) { + int offset = audio_ibuffer_read - c->audio_buffer_write; + if (offset > 0) { c->audio_buffer_write += offset; c->frame_sample_index += offset; - } + } } bool apply_effects = false; while (c->frame_sample_index > nb_bytes) { - // get new frame + // get new frame retrieve_next_frame_raw_data(c, frame); apply_effects = true; nb_bytes = av_samples_get_buffer_size(NULL, frame->channels, frame->nb_samples, static_cast(frame->format), 1); @@ -142,7 +136,7 @@ void cache_audio_worker(Clip* c, Clip* nest) { // code DISGUSTINGLY copy/pasted from above int offset = audio_ibuffer_read - c->audio_buffer_write; - if (offset > 0) { + if (offset > 0) { c->audio_buffer_write += offset; c->frame_sample_index += offset; } @@ -153,30 +147,32 @@ void cache_audio_worker(Clip* c, Clip* nest) { if (nest != NULL) apply_audio_effects(nest, timebase, frame, nb_bytes); } + long buffer_timeline_out = get_buffer_offset_from_frame(timeline_out); while (c->frame_sample_index < nb_bytes) { - if (c->audio_buffer_write >= audio_ibuffer_read+half_buffer || c->audio_buffer_write >= get_buffer_offset_from_frame(timeline_out)) { + if (c->audio_buffer_write >= audio_ibuffer_read+half_buffer || c->audio_buffer_write >= buffer_timeline_out) { written = max_write; break; - } else { - int upper_byte_index = (c->audio_buffer_write+1)%audio_ibuffer_size; + } else { + int upper_byte_index = (c->audio_buffer_write+1)%audio_ibuffer_size; int lower_byte_index = (c->audio_buffer_write)%audio_ibuffer_size; - qint16 old_sample = (qint16) ((audio_ibuffer[upper_byte_index] & 0xFF) << 8 | (audio_ibuffer[lower_byte_index] & 0xFF)); - qint16 new_sample = (qint16) ((frame->data[0][c->frame_sample_index+1] & 0xFF) << 8 | (frame->data[0][c->frame_sample_index] & 0xFF)); - qint32 mixed_sample = old_sample + new_sample; - mixed_sample = qMax(qMin(mixed_sample, (qint32)INT16_MAX), (qint32)INT16_MIN); + qint16 old_sample = static_cast((audio_ibuffer[upper_byte_index] & 0xFF) << 8 | (audio_ibuffer[lower_byte_index] & 0xFF)); + qint16 new_sample = static_cast((frame->data[0][c->frame_sample_index+1] & 0xFF) << 8 | (frame->data[0][c->frame_sample_index] & 0xFF)); + qint32 mixed_sample = static_cast(old_sample) + static_cast(new_sample); + mixed_sample = qMax(qMin(mixed_sample, static_cast(INT16_MAX)), static_cast(INT16_MIN)); + + audio_ibuffer[upper_byte_index] = static_cast((mixed_sample >> 8) & 0xFF); + audio_ibuffer[lower_byte_index] = static_cast(mixed_sample & 0xFF); - audio_ibuffer[upper_byte_index] = (quint8) (mixed_sample >> 8); - audio_ibuffer[lower_byte_index] = (quint8) mixed_sample; c->audio_buffer_write+=2; c->frame_sample_index+=2; - written+=2; + written+=2; } } if (c->frame_sample_index == nb_bytes) { c->need_new_audio_frame = true; } } - } + } } void cache_video_worker(Clip* c, long playhead, ClipCache* cache) { diff --git a/playback/playback.cpp b/playback/playback.cpp index 3b5112062..d29759bc2 100644 --- a/playback/playback.cpp +++ b/playback/playback.cpp @@ -35,7 +35,11 @@ void open_clip(Clip* clip, bool multithreaded) { clip->cacher = new Cacher(clip); QObject::connect(clip->cacher, SIGNAL(finished()), clip->cacher, SLOT(deleteLater())); - clip->cacher->start(QThread::LowPriority); + if (clip->track < 0) { + clip->cacher->start(QThread::LowPriority); + } else { + clip->cacher->start(QThread::TimeCriticalPriority); + } } } else { clip->finished_opening = false; diff --git a/ui/keyframeview.cpp b/ui/keyframeview.cpp index caac06c48..807ef34de 100644 --- a/ui/keyframeview.cpp +++ b/ui/keyframeview.cpp @@ -33,46 +33,48 @@ void KeyframeView::paintEvent(QPaintEvent*) { rowY.clear(); rows.clear(); - long effects_in = LONG_MAX; - long effects_out = 0; - for (int j=0;jselected_clips.size();j++) { - Clip* c = sequence->get_clip(panel_effect_controls->selected_clips.at(j)); - effects_in = qMin(effects_in, c->timeline_in); - effects_out = qMax(effects_out, c->timeline_out); - for (int i=0;ieffects.size();i++) { - Effect* e = c->effects.at(i); - if (e->container->is_expanded()) { - for (int j=0;jrow_count();j++) { - EffectRow* row = e->row(j); - QLabel* label = row->label; - QWidget* contents = e->container->contents; + if (panel_effect_controls->selected_clips.size() > 0) { + long effects_in = LONG_MAX; + long effects_out = 0; - int keyframe_y = label->y() + (label->height()>>1) + mapFrom(panel_effect_controls, contents->mapTo(panel_effect_controls, contents->pos())).y() - e->container->title_bar->height(); - for (int k=0;kkeyframe_times.size();k++) { - bool keyframe_selected = keyframeIsSelected(row, k); - long keyframe_frame = adjust_row_keyframe(row, row->keyframe_times.at(k)); - if (dragging && keyframe_selected) keyframe_frame += frame_diff; - draw_keyframe(p, getScreenPointFromFrame(panel_effect_controls->zoom, keyframe_frame), keyframe_y, keyframe_selected); + for (int j=0;jselected_clips.size();j++) { + Clip* c = sequence->get_clip(panel_effect_controls->selected_clips.at(j)); + effects_in = qMin(effects_in, c->timeline_in); + effects_out = qMax(effects_out, c->timeline_out); + for (int i=0;ieffects.size();i++) { + Effect* e = c->effects.at(i); + if (e->container->is_expanded()) { + for (int j=0;jrow_count();j++) { + EffectRow* row = e->row(j); + + QLabel* label = row->label; + QWidget* contents = e->container->contents; + + int keyframe_y = label->y() + (label->height()>>1) + mapFrom(panel_effect_controls, contents->mapTo(panel_effect_controls, contents->pos())).y() - e->container->title_bar->height(); + for (int k=0;kkeyframe_times.size();k++) { + bool keyframe_selected = keyframeIsSelected(row, k); + long keyframe_frame = adjust_row_keyframe(row, row->keyframe_times.at(k)); + if (dragging && keyframe_selected) keyframe_frame += frame_diff; + draw_keyframe(p, getScreenPointFromFrame(panel_effect_controls->zoom, keyframe_frame), keyframe_y, keyframe_selected); + } + + rows.append(row); + rowY.append(keyframe_y); } - - rows.append(row); - rowY.append(keyframe_y); } } } - } - visible_in = effects_in; - visible_out = effects_out; + visible_in = effects_in; + visible_out = effects_out; - int width = getScreenPointFromFrame(panel_effect_controls->zoom, visible_out - visible_in); - setMinimumWidth(width); - header->setMinimumWidth(width); - header->set_visible_in(effects_in); + int width = getScreenPointFromFrame(panel_effect_controls->zoom, visible_out - visible_in); + setMinimumWidth(width); + header->setMinimumWidth(width); + header->set_visible_in(effects_in); - if (rowY.size() > 0) { int playhead_x = getScreenPointFromFrame(panel_effect_controls->zoom, panel_timeline->playhead-visible_in); p.setPen(Qt::red); p.drawLine(playhead_x, 0, playhead_x, height()); @@ -80,7 +82,7 @@ void KeyframeView::paintEvent(QPaintEvent*) { if (select_rect) { draw_selection_rectangle(p, QRect(rect_select_x, rect_select_y, rect_select_w, rect_select_h)); - } + } /*if (mouseover && mouseover_row < rowY.size()) { draw_keyframe(p, getScreenPointFromFrame(panel_effect_controls->zoom, mouseover_frame - visible_in), rowY.at(mouseover_row), true);