diff --git a/dialogs/exportdialog.ui b/dialogs/exportdialog.ui index ce1b53b70..3434cb213 100644 --- a/dialogs/exportdialog.ui +++ b/dialogs/exportdialog.ui @@ -247,6 +247,22 @@ + + formatCombobox + videoGroupbox + vcodecCombobox + widthSpinbox + heightSpinbox + framerateSpinbox + videobitrateSpinbox + audioGroupbox + acodecCombobox + samplingRateSpinbox + audiobitrateSpinbox + renderCancel + pushButton + pushButton_2 + diff --git a/dialogs/newsequencedialog.ui b/dialogs/newsequencedialog.ui index de589f8ee..3a9663340 100644 --- a/dialogs/newsequencedialog.ui +++ b/dialogs/newsequencedialog.ui @@ -322,6 +322,16 @@ + + comboBox + width_numeric + height_numeric + frame_rate_combobox + par_combobox + interlacing_combobox + audio_frequency_combobox + lineEdit + diff --git a/effects/volumeeffect.cpp b/effects/volumeeffect.cpp index 0650d55a1..986a8c23c 100644 --- a/effects/volumeeffect.cpp +++ b/effects/volumeeffect.cpp @@ -17,7 +17,7 @@ VolumeEffect::VolumeEffect(Clip* c) : Effect(c) { ui_layout->addWidget(new QLabel("Volume:"), 0, 0); volume_val = new QSpinBox(); volume_val->setMinimum(0); - volume_val->setMaximum(100); + volume_val->setMaximum(400); ui_layout->addWidget(volume_val, 0, 1); ui->setLayout(ui_layout); diff --git a/io/config.cpp b/io/config.cpp index d751e595e..c655a45e4 100644 --- a/io/config.cpp +++ b/io/config.cpp @@ -29,7 +29,7 @@ void load_config() { #endif }*/ - padding *= scale; +// padding *= scale; /*DIR* dir = opendir("conf"); if (dir) { diff --git a/io/config.h b/io/config.h index 1bd410f1b..7a618c2ce 100644 --- a/io/config.h +++ b/io/config.h @@ -5,7 +5,7 @@ extern const char* version; extern float scale; extern bool vsync; extern bool hwaccel; -extern int padding; +//extern int padding; extern bool custom_scale; extern bool saved_layout; extern bool show_track_lines; diff --git a/io/exportthread.cpp b/io/exportthread.cpp index 91ac166d5..9a67eea81 100644 --- a/io/exportthread.cpp +++ b/io/exportthread.cpp @@ -110,11 +110,11 @@ void ExportThread::run() { qDebug() << "[ERROR] Could not find allocate video encoding context"; fail = true; } else { - vcodec_ctx->width = sequence->width; - vcodec_ctx->height = sequence->height; - vcodec_ctx->sample_aspect_ratio = av_d2q(sequence->width/sequence->height, INT_MAX); + vcodec_ctx->width = video_width; + vcodec_ctx->height = video_height; + vcodec_ctx->sample_aspect_ratio = av_d2q(video_width/video_height, INT_MAX); vcodec_ctx->pix_fmt = vcodec->pix_fmts[0]; // maybe be breakable code - vcodec_ctx->framerate = av_d2q(sequence->frame_rate, INT_MAX); + vcodec_ctx->framerate = av_d2q(video_frame_rate, INT_MAX); vcodec_ctx->bit_rate = video_bitrate * 1000000; vcodec_ctx->time_base = av_inv_q(vcodec_ctx->framerate); @@ -266,15 +266,7 @@ void ExportThread::run() { if (ret < 0) { qDebug() << "[ERROR] Could not write output file header." << ret; } else { - panel_timeline->seek(0); - - // clean up - close all open clips - for (int i=0;iclip_count();i++) { - Clip& c = sequence->get_clip(i); - if (c.open) { - close_clip(&c); - } - } + panel_timeline->seek(start); QOpenGLFramebufferObject fbo(video_width, video_height, QOpenGLFramebufferObject::CombinedDepthStencil, GL_TEXTURE_RECTANGLE); fbo.bind(); @@ -282,7 +274,6 @@ void ExportThread::run() { QPainter painter(&fbo_dev); painter.beginNativePainting(); - int written_frame_audio_bytes = 0; long file_audio_samples = 0; while (panel_timeline->playhead < end && !fail) { @@ -301,8 +292,9 @@ void ExportThread::run() { memcpy(video_frame->data[0]+dst_index, flip_buffer+src_index, linesize); } - // change pixel format - sws_scale(sws_ctx, video_frame->data, video_frame->linesize, 0, video_frame->height, sws_frame->data, sws_frame->linesize); + // change pixel format + sws_scale(sws_ctx, video_frame->data, video_frame->linesize, 0, video_frame->height, sws_frame->data, sws_frame->linesize); +// qDebug() << video_frame->linesize[0] << sws_frame->linesize[0]; sws_frame->pts = round(timecode_secs/av_q2d(video_stream->time_base)); // send to encoder @@ -310,23 +302,29 @@ void ExportThread::run() { } if (audio_enabled && !fail) { // do we need to encode more audio samples? - if (file_audio_samples <= (timecode_secs*audio_sampling_rate)) { - uint8_t* cache = (reading_audio_cache_A) ? audio_cache_A : audio_cache_B; - int copylen = qMin(aframe_bytes-written_frame_audio_bytes, audio_cache_size-audio_bytes_written); - memcpy(audio_frame->data[0]+written_frame_audio_bytes, cache+audio_bytes_written, copylen); - written_frame_audio_bytes += copylen; - audio_bytes_written += copylen; - if (written_frame_audio_bytes == aframe_bytes) { - // convert to export sample format - swr_convert_frame(swr_ctx, swr_frame, audio_frame); - swr_frame->pts = file_audio_samples; + while (file_audio_samples <= (timecode_secs*audio_sampling_rate)) { + int adjusted_read = audio_ibuffer_read%audio_ibuffer_size; + int copylen = qMin(aframe_bytes, audio_ibuffer_size-adjusted_read); + memcpy(audio_frame->data[0], audio_ibuffer+adjusted_read, copylen); + memset(audio_ibuffer+adjusted_read, 0, copylen); + audio_ibuffer_read += copylen; - // send to encoder - if (!encode(fmt_ctx, acodec_ctx, swr_frame, &audio_pkt, audio_stream)) fail = true; - - file_audio_samples += swr_frame->nb_samples; - written_frame_audio_bytes = 0; + if (copylen < aframe_bytes) { + // copy remainder + int remainder_len = aframe_bytes-copylen; + memcpy(audio_frame->data[0]+copylen, audio_ibuffer, remainder_len); + memset(audio_ibuffer, 0, remainder_len); + audio_ibuffer_read += remainder_len; } + + // convert to export sample format + swr_convert_frame(swr_ctx, swr_frame, audio_frame); + swr_frame->pts = file_audio_samples; + + // send to encoder + if (!encode(fmt_ctx, acodec_ctx, swr_frame, &audio_pkt, audio_stream)) fail = true; + + file_audio_samples += swr_frame->nb_samples; } } emit progress_changed(((float) panel_timeline->playhead / (float) end) * 100); diff --git a/olive.pro b/olive.pro index a2cb46ce7..4a98ac142 100644 --- a/olive.pro +++ b/olive.pro @@ -69,7 +69,6 @@ HEADERS += \ playback/audio.h \ effects/effects.h \ io/config.h \ - ui/timeline-tools.h \ dialogs/newsequencedialog.h \ ui/viewerwidget.h \ ui/viewercontainer.h \ @@ -78,7 +77,8 @@ HEADERS += \ project/effect.h \ panels/panels.h \ playback/cacher.h \ - io/exportthread.h + io/exportthread.h \ + ui/timelinetools.h FORMS += \ mainwindow.ui \ diff --git a/olive.pro.user b/olive.pro.user index e57423a29..3a7b3e899 100644 --- a/olive.pro.user +++ b/olive.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 9c3056d6d..a9b3e15bc 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -69,11 +69,10 @@ void Timeline::seek(long p) { Clip& c = sequence->get_clip(i); c.reset_audio = true; c.frame_sample_index = 0; + c.audio_buffer_write = 0; } - clear_cache(true, true); - audio_bytes_written = 0; - switch_audio_cache = true; - reading_audio_cache_A = false; + clear_audio_ibuffer(); + audio_ibuffer_read = 0; playhead = p; } @@ -92,11 +91,7 @@ void Timeline::play() { playback_timer.start(); start_msecs = QDateTime::currentMSecsSinceEpoch(); playback_updater.start(); - playing = true; - - if (switch_audio_cache) { - // add something to pre-cache audio - } + playing = true; } void Timeline::pause() { diff --git a/panels/timeline.h b/panels/timeline.h index f7b6aa3b3..66939775f 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -1,7 +1,7 @@ #ifndef TIMELINE_H #define TIMELINE_H -#include "ui/timeline-tools.h" +#include "ui/timelinetools.h" #include #include #include diff --git a/panels/viewer.cpp b/panels/viewer.cpp index d2a8698b3..fb0c35aab 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -29,10 +29,6 @@ Viewer::~Viewer() delete ui; } -void Viewer::receiver() { - qDebug() << "callback?"; -} - void Viewer::set_sequence(Sequence* s) { bool null_sequence = (s == NULL); sequence = s; @@ -45,14 +41,13 @@ void Viewer::set_sequence(Sequence* s) { ui->pushButton_4->setEnabled(!null_sequence); ui->pushButton_5->setEnabled(!null_sequence); + init_audio(s); + if (!null_sequence) { ui->glViewerPane->aspect_ratio = (float) sequence->width / (float) sequence->height; - ui->glViewerPane->adjust(); + ui->glViewerPane->adjust(); } - init_audio(s); - connect(audio_output, SIGNAL(notify()), this, SLOT(receiver())); - update(); } diff --git a/panels/viewer.h b/panels/viewer.h index f1681d6ca..ffcad1f4f 100644 --- a/panels/viewer.h +++ b/panels/viewer.h @@ -33,9 +33,7 @@ private slots: void on_pushButton_4_clicked(); - void on_pushButton_3_clicked(); - - void receiver(); + void on_pushButton_3_clicked(); private: Ui::Viewer *ui; diff --git a/playback/audio.cpp b/playback/audio.cpp index 33fc9a820..7de4a562c 100644 --- a/playback/audio.cpp +++ b/playback/audio.cpp @@ -13,24 +13,11 @@ QAudioOutput* audio_output; QIODevice* audio_io_device; bool audio_device_set = false; -uint8_t* audio_cache_A = NULL; -uint8_t* audio_cache_B = NULL; -int audio_cache_size = 0; -bool switch_audio_cache = true; -bool reading_audio_cache_A = false; -int audio_bytes_written = 0; +qint8 audio_ibuffer[audio_ibuffer_size]; +int audio_ibuffer_read = 0; +QVector audio_ibuffer_write; void init_audio(Sequence* s) { - if (audio_cache_A != NULL) { - delete [] audio_cache_A; - audio_cache_A = NULL; - } - - if (audio_cache_B != NULL) { - delete [] audio_cache_B; - audio_cache_B = NULL; - } - if (audio_device_set) { audio_output->stop(); delete audio_output; @@ -55,19 +42,11 @@ void init_audio(Sequence* s) { audio_io_device = audio_output->start(); audio_device_set = true; - audio_cache_size = av_samples_get_buffer_size(NULL, av_get_channel_layout_nb_channels(s->audio_layout), s->audio_frequency/8, AV_SAMPLE_FMT_S16, 1); - audio_cache_A = new uint8_t[audio_cache_size]; - audio_cache_B = new uint8_t[audio_cache_size]; - clear_cache(true, true); + clear_audio_ibuffer(); } } } -void clear_cache(bool clear_A, bool clear_B) { - if (clear_A) { - memset(audio_cache_A, 0, audio_cache_size); - } - if (clear_B) { - memset(audio_cache_B, 0, audio_cache_size); - } +void clear_audio_ibuffer() { + memset(audio_ibuffer, 0, audio_ibuffer_size); } diff --git a/playback/audio.h b/playback/audio.h index 093b4f0a1..555bc44b5 100644 --- a/playback/audio.h +++ b/playback/audio.h @@ -1,7 +1,7 @@ #ifndef AUDIO_H #define AUDIO_H -#include +#include class QAudioOutput; class QIODevice; @@ -11,13 +11,12 @@ struct Sequence; extern QAudioOutput* audio_output; extern QIODevice* audio_io_device; -extern uint8_t* audio_cache_A; -extern uint8_t* audio_cache_B; -extern int audio_cache_size; -extern int audio_bytes_written; -extern bool switch_audio_cache; -extern bool reading_audio_cache_A; +#define audio_ibuffer_size 192000 +extern qint8 audio_ibuffer[audio_ibuffer_size]; +extern int audio_ibuffer_read; +//extern QVector audio_ibuffer_write; +void clear_audio_ibuffer(); + void init_audio(Sequence* s); -void clear_cache(bool clear_A, bool clear_B); #endif // AUDIO_H diff --git a/playback/cacher.cpp b/playback/cacher.cpp index 8d68216ed..a83e6aaa4 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -16,46 +16,67 @@ extern "C" { #include -void cache_audio_worker(Clip* c, bool write_A) { - // gets one frame worth of audio and sends it to the audio buffer - AVFrame* frame = c->cache_A.frames[0]; - uint8_t* cache = (write_A) ? audio_cache_A : audio_cache_B; +void cache_audio_worker(Clip* c) { + int written = 0; + int max_write = 16384; + while (written < max_write) { + // gets one frame worth of audio and sends it to the audio buffer + AVFrame* frame = c->cache_A.frames[0]; - int bytes_written = 0; - int j = 0; - while (bytes_written < audio_cache_size && !c->reached_end) { - // is there audio left in the frame - if (c->frame_sample_index == 0) { - // no more audio left in frame, get a new one - retrieve_next_frame_raw_data(c, frame); - } - if (!c->reached_end) { - int nb_bytes = av_samples_get_buffer_size(NULL, frame->channels, frame->nb_samples, static_cast(frame->format), 1); - int limit = std::min(c->frame_sample_index + audio_cache_size - bytes_written, nb_bytes); - // perform all audio effects + if (c->frame_sample_index == 0) { + // no more audio left in frame, get a new one + if (!c->reached_end) { + retrieve_next_frame_raw_data(c, frame); + } else { + // set by retrieve_next_frame_raw_data indicating no more frames in file, + // but there still may be samples in swresample + swr_convert_frame(c->swr_ctx, frame, NULL); + } + } + + if (frame->nb_samples == 0) { + written = max_write; + } else { + int nb_bytes = av_samples_get_buffer_size(NULL, frame->channels, frame->nb_samples, static_cast(frame->format), 1); + + // perform all audio effects for (int j=0;jeffects.size();j++) { - c->effects.at(j)->process_audio(frame->data[0], limit); - } - // mix audio into cache - for (int i=c->frame_sample_index;idata[0][i]; - j++; - } - bytes_written += limit - c->frame_sample_index; - c->frame_sample_index = (limit == nb_bytes) ? 0 : limit; - } - } + c->effects.at(j)->process_audio(frame->data[0], nb_bytes); + } + + if (c->audio_buffer_write == 0) c->audio_buffer_write = audio_ibuffer_read + 1024; + while (c->frame_sample_index < nb_bytes) { + if (c->audio_buffer_write >= audio_ibuffer_read+(audio_ibuffer_size/2)) { + written = max_write; + break; + } else { + audio_ibuffer[c->audio_buffer_write%audio_ibuffer_size] += frame->data[0][c->frame_sample_index]; + c->audio_buffer_write++; + c->frame_sample_index++; + } + } + written += c->frame_sample_index; + if (c->frame_sample_index == nb_bytes) { + c->frame_sample_index = 0; + } + } + } } void cache_video_worker(Clip* c, long playhead, ClipCache* cache) { - cache->mutex.lock(); + cache->mutex.lock(); - cache->offset = playhead; - for (size_t i=0;icache_size;i++) { - retrieve_next_frame_raw_data(c, cache->frames[i]); - } - cache->written = true; - cache->unread = true; + cache->offset = playhead; + if (!c->reached_end) { + for (size_t i=0;icache_size;i++) { + retrieve_next_frame_raw_data(c, cache->frames[i]); + if (c->reached_end) break; + } + } + cache->written = true; + cache->unread = true; + // setting the cache to written even if it hasn't reached_end prevents playback from + // signaling a seek/reset because it wasn't able to find the frame cache->mutex.unlock(); } @@ -81,7 +102,7 @@ void reset_cache(Clip* c, long target_frame) { // play up to the frame we actually want long retrieved_frame = 0; AVFrame* temp = av_frame_alloc(); - do { + do { retrieve_next_frame(c, temp); if (retrieved_frame == 0) { if (target_frame != 0) { @@ -223,7 +244,7 @@ void open_clip_worker(Clip* clip) { clip->sequence->audio_layout, static_cast(sample_format), clip->sequence->audio_frequency, - clip->stream->codecpar->channel_layout, + clip->codecCtx->channel_layout, static_cast(clip->stream->codecpar->format), clip->stream->codecpar->sample_rate, 0, @@ -266,13 +287,8 @@ void cache_clip_worker(Clip* clip, long playhead, bool write_A, bool write_B, bo if (write_B) { cache_video_worker(clip, playhead, &clip->cache_B); } - } else if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - if (write_A) { - cache_audio_worker(clip, true); - } - if (write_B) { - cache_audio_worker(clip, false); - } + } else if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { + cache_audio_worker(clip); } } @@ -323,8 +339,8 @@ void Cacher::run() { caching = true; while (true) { - clip->can_cache.wait(&clip->lock); - if (!caching) { + clip->can_cache.wait(&clip->lock); + if (!caching) { break; } else { cache_clip_worker(clip, playhead, write_A, write_B, reset); diff --git a/playback/playback.cpp b/playback/playback.cpp index b58725a77..070e9a4d3 100644 --- a/playback/playback.cpp +++ b/playback/playback.cpp @@ -34,7 +34,7 @@ void handle_media(Sequence* sequence, long playhead, bool multithreaded) { // if thread is already working, we don't want to touch this, // but we also don't want to hang the UI thread if (!c.open) { - if (c.lock.tryLock()) { + if (c.lock.tryLock()) { open_clip(&c, multithreaded); // add to current_clips, (insertion) sorted by track so composite them in order @@ -229,13 +229,10 @@ float clip_frame_to_seconds(Clip* c, long clip_frame) { int retrieve_next_frame(Clip* c, AVFrame* f) { int result = 0; - int receive_ret; - - // could be optimized if "linked stream" shares timeline_in and clip_in, only use one read_frame? - // depends how much time av_read_frame needs, the decoding is probably far more consuming anyway + int receive_ret; // do we need to retrieve a new packet for a new frame? - while ((receive_ret = avcodec_receive_frame(c->codecCtx, f)) == AVERROR(EAGAIN)) { + while ((receive_ret = avcodec_receive_frame(c->codecCtx, f)) == AVERROR(EAGAIN)) { int read_ret = 0; do { if (c->pkt_written) { @@ -249,10 +246,9 @@ int retrieve_next_frame(Clip* c, AVFrame* f) { int send_ret = avcodec_send_packet(c->codecCtx, c->pkt); if (send_ret < 0) { qDebug() << "[ERROR] Failed to send packet to decoder." << send_ret; - result = send_ret; - break; + return send_ret; } - } else { + } else { if (read_ret != AVERROR_EOF) qDebug() << "[ERROR] Could not read frame." << read_ret; return read_ret; // skips trying to find a frame at all } @@ -266,21 +262,26 @@ int retrieve_next_frame(Clip* c, AVFrame* f) { } void retrieve_next_frame_raw_data(Clip* c, AVFrame* output) { - int ret = retrieve_next_frame(c, c->frame); - if (ret >= 0) { - if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - sws_scale(c->sws_ctx, c->frame->data, c->frame->linesize, 0, c->stream->codecpar->height, output->data, output->linesize); - } else if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - ret = swr_convert_frame(c->swr_ctx, output, c->frame); - if (ret < 0) { - qDebug() << "[ERROR] Failed to resample audio." << ret; - } - } - } else if (ret == AVERROR_EOF) { - c->reached_end = true; - } else { - qDebug() << "[WARNING] Raw frame data could not be retrieved." << ret; - } + if (c->reached_end) { + qDebug() << "[WARNING] Attempted to retrieve frame of stream with no frames left"; + } else { + int ret = retrieve_next_frame(c, c->frame); + if (ret >= 0) { + if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + sws_scale(c->sws_ctx, c->frame->data, c->frame->linesize, 0, c->stream->codecpar->height, output->data, output->linesize); + } else if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { + ret = swr_convert_frame(c->swr_ctx, output, c->frame); + if (ret < 0) { + qDebug() << "[ERROR] Failed to resample audio." << ret; + } + } + } else if (ret == AVERROR_EOF) { +// qDebug() << "reached end triggered" << c->track; + c->reached_end = true; + } else { + qDebug() << "[WARNING] Raw frame data could not be retrieved." << ret; + } + } } bool is_clip_active(Clip* c, long playhead) { diff --git a/project/clip.cpp b/project/clip.cpp index 650513f43..93d0878c5 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -52,7 +52,7 @@ void Clip::init() { } void Clip::reset() { - cache_size = cache_A.offset = cache_B.offset = open = pkt_written = cache_A.written = cache_B.written = cache_A.unread = cache_B.unread = reached_end = reset_audio = frame_sample_index = 0; + cache_size = cache_A.offset = cache_B.offset = open = pkt_written = cache_A.written = cache_B.written = cache_A.unread = cache_B.unread = reached_end = reset_audio = frame_sample_index = audio_buffer_write = 0; texture_frame = -1; formatCtx = NULL; stream = NULL; diff --git a/project/clip.h b/project/clip.h index 50708e357..bd0f1dc35 100644 --- a/project/clip.h +++ b/project/clip.h @@ -89,6 +89,7 @@ struct Clip // audio playback variables SwrContext* swr_ctx; int frame_sample_index; + int audio_buffer_write; bool reset_audio; }; diff --git a/project/effect.cpp b/project/effect.cpp index cacad5fee..0d505e3b1 100644 --- a/project/effect.cpp +++ b/project/effect.cpp @@ -21,5 +21,5 @@ Effect* Effect::copy() { return e; } -void Effect::process_gl(int* anchor_x, int* anchor_y) {} -void Effect::process_audio(uint8_t* samples, int nb_bytes) {} +void Effect::process_gl(int*, int*) {} +void Effect::process_audio(uint8_t*, int) {} diff --git a/ui/timeline-tools.h b/ui/timeline-tools.h deleted file mode 100644 index 28cdb10da..000000000 --- a/ui/timeline-tools.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef TIMELINETOOLS_H -#define TIMELINETOOLS_H - -enum TimelineTools { - TIMELINE_TOOL_POINTER, - TIMELINE_TOOL_EDIT, - TIMELINE_TOOL_RAZOR, - TIMELINE_TOOL_RIPPLE, - TIMELINE_TOOL_ROLLING, - TIMELINE_TOOL_SLIP, - TIMELINE_TOOL_HAND, - TIMELINE_TOOL_ZOOM -}; - -#endif // TIMELINETOOLS_H diff --git a/ui/timelinetools.h b/ui/timelinetools.h new file mode 100644 index 000000000..74f54fb9a --- /dev/null +++ b/ui/timelinetools.h @@ -0,0 +1,13 @@ +#ifndef TIMELINETOOLS_H +#define TIMELINETOOLS_H + +#define TIMELINE_TOOL_POINTER 0 +#define TIMELINE_TOOL_EDIT 1 +#define TIMELINE_TOOL_RAZOR 2 +#define TIMELINE_TOOL_RIPPLE 3 +#define TIMELINE_TOOL_ROLLING 4 +#define TIMELINE_TOOL_SLIP 5 +#define TIMELINE_TOOL_HAND 6 +#define TIMELINE_TOOL_ZOOM 7 + +#endif // TIMELINETOOLS_H diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 03ece55ad..743aae638 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -24,9 +24,7 @@ TimelineWidget::TimelineWidget(QWidget *parent) : QWidget(parent) { bottom_align = false; setMouseTracking(true); - track_height = 40; - - clip_pixmap = NULL; + track_height = 40; setAcceptDrops(true); } @@ -35,6 +33,10 @@ bool same_sign(int a, int b) { return (a < 0) == (b < 0); } +void TimelineWidget::resizeEvent(QResizeEvent*) { + if (panel_timeline->sequence != NULL) redraw_clips(); +} + void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) { if (static_cast(event->source()) == panel_project->source_table) { QPoint pos = event->pos(); @@ -77,7 +79,7 @@ void TimelineWidget::dragMoveEvent(QDragMoveEvent *event) { } } -void TimelineWidget::dragLeaveEvent(QDragLeaveEvent *event) { +void TimelineWidget::dragLeaveEvent(QDragLeaveEvent*) { if (panel_timeline->importing) { panel_timeline->ghosts.clear(); panel_timeline->importing = false; @@ -324,7 +326,6 @@ bool subvalidate_snapping(Ghost& g, long* frame_diff, long snap_point) { } void validate_snapping(Ghost& g, long* frame_diff) { - long validator; panel_timeline->snapped = false; if (panel_timeline->snapping) { if (!subvalidate_snapping(g, frame_diff, panel_timeline->playhead)) { @@ -659,15 +660,13 @@ int color_brightness(int r, int g, int b) { } void TimelineWidget::redraw_clips() { - // Draw clips - if (clip_pixmap != NULL) delete clip_pixmap; - + // Draw clips int panel_width = getScreenPointFromFrame(panel_timeline->sequence->getEndFrame()) + 100; setMinimumWidth(panel_width); - clip_pixmap = new QPixmap(panel_width, height()); - clip_pixmap->fill(Qt::transparent); - QPainter clip_painter(clip_pixmap); + clip_pixmap = QPixmap(panel_width, height()); + clip_pixmap.fill(Qt::transparent); + QPainter clip_painter(&clip_pixmap); int video_track_limit = 0; int audio_track_limit = 0; for (int i=0;isequence->clip_count();i++) { @@ -726,7 +725,7 @@ void TimelineWidget::paintEvent(QPaintEvent*) { if (panel_timeline->sequence != NULL) { QPainter p(this); - if (clip_pixmap != NULL) p.drawPixmap(0, 0, minimumWidth(), height(), *clip_pixmap); + p.drawPixmap(0, 0, minimumWidth(), height(), clip_pixmap); // Draw selections for (int i=0;iselections.size();i++) { diff --git a/ui/timelinewidget.h b/ui/timelinewidget.h index fb14a3bb6..a743884ff 100644 --- a/ui/timelinewidget.h +++ b/ui/timelinewidget.h @@ -2,7 +2,7 @@ #define TIMELINEWIDGET_H #include -#include "timeline-tools.h" +#include "timelinetools.h" #define GHOST_THICKNESS 2 // thiccccc #define CLIP_TEXT_PADDING 3 @@ -19,9 +19,10 @@ public: bool bottom_align; - void redraw_clips(); + void redraw_clips(); protected: void paintEvent(QPaintEvent*) override; + void resizeEvent(QResizeEvent*) override; void mousePressEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; @@ -45,12 +46,15 @@ private: QList pre_clips; QList post_clips; - QPixmap* clip_pixmap; + QPixmap clip_pixmap; // QPixmap selection_pixmap; signals: public slots: + +private slots: + }; #endif // TIMELINEWIDGET_H diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 270145d50..27d8e7f89 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -17,12 +17,10 @@ extern "C" { ViewerWidget::ViewerWidget(QWidget *parent) : QOpenGLWidget(parent) { - multithreaded = true; + multithreaded = true; enable_paint = true; force_audio = false; - audio_bytes_written = 0; - QSurfaceFormat format; format.setDepthBufferSize(24); setFormat(format); @@ -67,17 +65,6 @@ void ViewerWidget::paintGL() bool render_audio = (panel_timeline->playing || force_audio); - // switch_cache - if (render_audio && audio_bytes_written == audio_cache_size) { - switch_audio_cache = true; - - reading_audio_cache_A = !reading_audio_cache_A; - audio_bytes_written = 0; - clear_cache(!reading_audio_cache_A, reading_audio_cache_A); - } - -// qDebug() << audio_bytes_written << "/" << audio_cache_size; - cc_lock.lock(); for (int i=0;itexture->release(); } - } else if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && - playhead >= c->timeline_in && - render_audio && - !c->reached_end && - (switch_audio_cache || c->reset_audio)) { - // TODO doesn't affect new clips appearing in the timeline (they'll ALWAYS end up in the other cache with a 1/8 sec delay) - - // cache audio - if (c->lock.tryLock()) { - // clip is not caching, start cache - c->lock.unlock(); - - cache_clip(c, playhead, !reading_audio_cache_A, reading_audio_cache_A, c->reset_audio); - } + } else if (render_audio && + c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && + playhead >= c->timeline_in && + c->lock.tryLock()) { + // clip is not caching, start caching audio + c->lock.unlock(); + cache_clip(c, playhead, false, false, c->reset_audio); } } - } + } - if (render_audio) { - switch_audio_cache = false; - - if (audio_cache_A != NULL && audio_bytes_written < audio_cache_size) { - // send cached/buffered audio to QIODevice/QAudioOutput - uint8_t* cache = reading_audio_cache_A ? audio_cache_A : audio_cache_B; - if (panel_timeline->playing) { - int max_w = audio_cache_size-audio_bytes_written; - int w = audio_io_device->write((const char*) cache+audio_bytes_written, max_w); - qDebug() << w << max_w; - audio_bytes_written += w; - } + if (panel_timeline->playing) { + int adjusted_read_index = audio_ibuffer_read%audio_ibuffer_size; + int max_write = audio_ibuffer_size - adjusted_read_index; + int actual_write = audio_io_device->write((const char*) audio_ibuffer+adjusted_read_index, max_write); + memset(audio_ibuffer+adjusted_read_index, 0, actual_write); + audio_ibuffer_read += actual_write; + if (actual_write == max_write) { + // got all the bytes, write again + actual_write = audio_io_device->write((const char*) audio_ibuffer, audio_ibuffer_size); + memset(audio_ibuffer, 0, actual_write); + audio_ibuffer_read += actual_write; } - } + } cc_lock.unlock();