diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 0b09a009c..5e45f77d7 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -29,7 +29,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) : QOpenGLWidget(parent) { format.setDepthBufferSize(24); setFormat(format); - // error handler - retries after 200ms if we couldn't get the entire image + // error handler - retries after 250ms if we couldn't get the entire image retry_timer.setInterval(250); connect(&retry_timer, SIGNAL(timeout()), this, SLOT(retry())); } @@ -76,6 +76,156 @@ void ViewerWidget::paintEvent(QPaintEvent *e) { if (enable_paint) QOpenGLWidget::paintEvent(e); } +void ViewerWidget::compose_sequence(Sequence *s, bool render_audio) { + QVector current_clips; + + for (int i=0;iclip_count();i++) { + Clip* c = s->get_clip(i); + + // if clip starts within one second and/or hasn't finished yet + if (c != NULL) { + if (c->media->ready + && c->media->get_stream_from_file_index(c->media_stream) != NULL + && is_clip_active(c, panel_timeline->playhead)) { + // 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) { + open_clip(c, multithreaded); + } + + bool added = false; + for (int j=0;jtrack < c->track) { + current_clips.insert(j, c); + added = true; + break; + } + } + if (!added) { + current_clips.append(c); + } + } else if (c->open) { + close_clip(c); + } + } + } + + for (int i=0;ifinished_opening) { + qDebug() << "[WARNING] Tried to display clip" << i << "but it's closed"; + texture_failed = true; + } else if (is_clip_active(c, panel_timeline->playhead)) { + if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + // start preparing cache + get_clip_frame(c, panel_timeline->playhead); + + if (c->texture == NULL) { + qDebug() << "[WARNING] Texture hasn't been created yet"; + texture_failed = true; + } else if (panel_timeline->playhead >= c->timeline_in) { + MediaStream* ms = c->media->get_stream_from_file_index(c->media_stream); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glColor4f(1.0, 1.0, 1.0, 1.0); + glLoadIdentity(); + + int half_width = s->width/2; + int half_height = s->height/2; + if (flip) { + glOrtho(-half_width, half_width, -half_height, half_height, -1, 1); + } else { + glOrtho(-half_width, half_width, half_height, -half_height, -1, 1); + } + int anchor_x = ms->video_width/2; + int anchor_y = ms->video_height/2; + + // perform all transform effects + for (int j=0;jeffects.size();j++) { + if (c->effects.at(j)->is_enabled()) c->effects.at(j)->process_gl(&anchor_x, &anchor_y); + } + + if (c->opening_transition != NULL) { + int transition_progress = panel_timeline->playhead-c->timeline_in; + if (transition_progress < c->opening_transition->length) { + c->opening_transition->process_transition((float)transition_progress/(float)c->opening_transition->length); + } + } + if (c->closing_transition != NULL) { + int transition_progress = c->closing_transition->length-(panel_timeline->playhead-c->timeline_in-c->getLength()+c->closing_transition->length); + if (transition_progress < c->closing_transition->length) { + c->closing_transition->process_transition((float)transition_progress/(float)c->closing_transition->length); + } + } + + int anchor_right = ms->video_width - anchor_x; + int anchor_bottom = ms->video_height - anchor_y; + + c->texture->bind(); + + glBegin(GL_QUADS); + glTexCoord2f(0.0, 0.0); + glVertex2f(-anchor_x, -anchor_y); + glTexCoord2f(1.0, 0.0); + glVertex2f(anchor_right, -anchor_y); + glTexCoord2f(1.0, 1.0); + glVertex2f(anchor_right, anchor_bottom); + glTexCoord2f(0.0, 1.0); + glVertex2f(-anchor_x, anchor_bottom); + glEnd(); + + c->texture->release(); + + // perform all transform effects + for (int j=0;jeffects.size();j++) { + if (c->effects.at(j)->is_enabled()) c->effects.at(j)->post_gl(); + } + } + } else if (render_audio && + c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && + c->lock.tryLock()) { + // clip is not caching, start caching audio + cache_clip(c, panel_timeline->playhead, false, false, c->reset_audio); + c->lock.unlock(); + } + } + } +} + +int ViewerWidget::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; + + // send samples to audio monitor cache + if (panel_timeline->ui->audio_monitor->sample_cache_offset == -1) { + panel_timeline->ui->audio_monitor->sample_cache_offset = panel_timeline->playhead; + } + long sample_cache_playhead = panel_timeline->ui->audio_monitor->sample_cache_offset + panel_timeline->ui->audio_monitor->sample_cache.size(); + int next_buffer_offset, buffer_offset_adjusted, i; + int buffer_offset = get_buffer_offset_from_frame(sample_cache_playhead); + samples.resize(av_get_channel_layout_nb_channels(sequence->audio_layout)); + samples.fill(0); + while (buffer_offset < audio_ibuffer_read) { + sample_cache_playhead++; + next_buffer_offset = qMin(get_buffer_offset_from_frame(sample_cache_playhead), audio_ibuffer_read); + while (buffer_offset < next_buffer_offset) { + for (i=0;iui->audio_monitor->sample_cache.append(samples); + buffer_offset = next_buffer_offset; + } + + memset(audio_ibuffer+offset, 0, actual_write); + + return actual_write; +} + void ViewerWidget::paintGL() { bool loop = true; while (loop) { @@ -86,160 +236,16 @@ void ViewerWidget::paintGL() { glClear(GL_COLOR_BUFFER_BIT); - current_clips.clear(); - - for (int i=0;iclip_count();i++) { - Clip* c = sequence->get_clip(i); - - // if clip starts within one second and/or hasn't finished yet - if (c != NULL) { - if (c->media->ready - && c->media->get_stream_from_file_index(c->media_stream) != NULL - && is_clip_active(c, panel_timeline->playhead)) { - // 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) { - open_clip(c, multithreaded); - } - - bool added = false; - for (int j=0;jtrack < c->track) { - current_clips.insert(j, c); - added = true; - break; - } - } - if (!added) { - current_clips.append(c); - } - } else if (c->open) { - close_clip(c); - } - } - } - - bool render_audio = (panel_timeline->playing || force_audio); - - for (int i=0;ifinished_opening) { - qDebug() << "[WARNING] Tried to display clip" << i << "but it's closed"; - texture_failed = true; - } else if (is_clip_active(c, panel_timeline->playhead)) { - if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - // start preparing cache - get_clip_frame(c, panel_timeline->playhead); - - if (c->texture == NULL) { - qDebug() << "[WARNING] Texture hasn't been created yet"; - texture_failed = true; - } else if (panel_timeline->playhead >= c->timeline_in) { - MediaStream* ms = c->media->get_stream_from_file_index(c->media_stream); - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor4f(1.0, 1.0, 1.0, 1.0); - glLoadIdentity(); - - int half_width = c->sequence->width/2; - int half_height = c->sequence->height/2; - if (flip) { - glOrtho(-half_width, half_width, -half_height, half_height, -1, 1); - } else { - glOrtho(-half_width, half_width, half_height, -half_height, -1, 1); - } - int anchor_x = ms->video_width/2; - int anchor_y = ms->video_height/2; - - // perform all transform effects - for (int j=0;jeffects.size();j++) { - if (c->effects.at(j)->is_enabled()) c->effects.at(j)->process_gl(&anchor_x, &anchor_y); - } - - if (c->opening_transition != NULL) { - int transition_progress = panel_timeline->playhead-c->timeline_in; - if (transition_progress < c->opening_transition->length) { - c->opening_transition->process_transition((float)transition_progress/(float)c->opening_transition->length); - } - } - if (c->closing_transition != NULL) { - int transition_progress = c->closing_transition->length-(panel_timeline->playhead-c->timeline_in-c->getLength()+c->closing_transition->length); - if (transition_progress < c->closing_transition->length) { - c->closing_transition->process_transition((float)transition_progress/(float)c->closing_transition->length); - } - } - - int anchor_right = ms->video_width - anchor_x; - int anchor_bottom = ms->video_height - anchor_y; - - c->texture->bind(); - - glBegin(GL_QUADS); - glTexCoord2f(0.0, 0.0); - glVertex2f(-anchor_x, -anchor_y); - glTexCoord2f(1.0, 0.0); - glVertex2f(anchor_right, -anchor_y); - glTexCoord2f(1.0, 1.0); - glVertex2f(anchor_right, anchor_bottom); - glTexCoord2f(0.0, 1.0); - glVertex2f(-anchor_x, anchor_bottom); - glEnd(); - - c->texture->release(); - - // perform all transform effects - for (int j=0;jeffects.size();j++) { - if (c->effects.at(j)->is_enabled()) c->effects.at(j)->post_gl(); - } - } - } else if (render_audio && - c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && - c->lock.tryLock()) { - // clip is not caching, start caching audio - cache_clip(c, panel_timeline->playhead, false, false, c->reset_audio); - c->lock.unlock(); - } - } - } + // compose video preview + compose_sequence(sequence, (panel_timeline->playing || force_audio)); + // send audio to IO device 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); - audio_ibuffer_read += actual_write; - - // send samples to audio monitor cache - if (panel_timeline->ui->audio_monitor->sample_cache_offset == -1) { - panel_timeline->ui->audio_monitor->sample_cache_offset = panel_timeline->playhead; - } - long sample_cache_playhead = panel_timeline->ui->audio_monitor->sample_cache_offset + panel_timeline->ui->audio_monitor->sample_cache.size(); - int next_buffer_offset, buffer_offset_adjusted, i; - int buffer_offset = get_buffer_offset_from_frame(sample_cache_playhead); - samples.resize(av_get_channel_layout_nb_channels(sequence->audio_layout)); - samples.fill(0); - while (buffer_offset < audio_ibuffer_read) { - sample_cache_playhead++; - next_buffer_offset = qMin(get_buffer_offset_from_frame(sample_cache_playhead), audio_ibuffer_read); - while (buffer_offset < next_buffer_offset) { - for (i=0;iui->audio_monitor->sample_cache.append(samples.at(i)); - } - buffer_offset = next_buffer_offset; - } - - memset(audio_ibuffer+adjusted_read_index, 0, actual_write); - if (actual_write == max_write) { + if (send_audio_to_output(adjusted_read_index, max_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; + send_audio_to_output(0, audio_ibuffer_size); } } diff --git a/ui/viewerwidget.h b/ui/viewerwidget.h index 3b4136203..2c29c461e 100644 --- a/ui/viewerwidget.h +++ b/ui/viewerwidget.h @@ -8,6 +8,7 @@ #include struct Clip; +struct Sequence; class Viewer; @@ -28,11 +29,12 @@ protected: // void resizeGL(int w, int h); private: QTimer retry_timer; - QVector current_clips; QVector samples; private slots: void retry(); void deleteFunction(); + void compose_sequence(Sequence* s, bool render_audio); + int send_audio_to_output(int offset, int max); }; #endif // VIEWERWIDGET_H