158 lines
4.2 KiB
C++
158 lines
4.2 KiB
C++
#include "viewerwidget.h"
|
|
|
|
#include "panels/panels.h"
|
|
#include "panels/viewer.h"
|
|
#include "panels/timeline.h"
|
|
#include "project/sequence.h"
|
|
#include "project/effect.h"
|
|
#include "playback/playback.h"
|
|
#include "playback/audio.h"
|
|
#include "io/media.h"
|
|
|
|
#include <QDebug>
|
|
|
|
extern "C" {
|
|
#include <libavformat/avformat.h>
|
|
}
|
|
|
|
ViewerWidget::ViewerWidget(QWidget *parent) : QOpenGLWidget(parent)
|
|
{
|
|
multithreaded = true;
|
|
|
|
QSurfaceFormat format;
|
|
format.setDepthBufferSize(24);
|
|
setFormat(format);
|
|
|
|
// error handler - retries after 200ms if we couldn't get the entire image
|
|
retry_timer.setInterval(200);
|
|
connect(&retry_timer, SIGNAL(timeout()), this, SLOT(retry()));
|
|
}
|
|
|
|
void ViewerWidget::retry() {
|
|
update();
|
|
}
|
|
|
|
void ViewerWidget::initializeGL() {
|
|
initializeOpenGLFunctions();
|
|
|
|
glClearColor(0, 0, 0, 1);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
}
|
|
|
|
//void ViewerWidget::resizeGL(int w, int h)
|
|
//{
|
|
//}
|
|
|
|
int audio_bytes_written = 0;
|
|
|
|
void ViewerWidget::paintGL()
|
|
{
|
|
if (multithreaded) retry_timer.stop();
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
long playhead = panel_timeline->playhead;
|
|
|
|
handle_media(panel_viewer->sequence, playhead, multithreaded);
|
|
texture_failed = false;
|
|
|
|
bool render_audio = (panel_timeline->playing);
|
|
|
|
if (render_audio && switch_audio_cache) {
|
|
reading_audio_cache_A = !reading_audio_cache_A;
|
|
audio_bytes_written = 0;
|
|
clear_cache(!reading_audio_cache_A, reading_audio_cache_A);
|
|
}
|
|
|
|
cc_lock.lock();
|
|
for (int i=0;i<current_clips.size();i++) {
|
|
Clip* c = current_clips.at(i);
|
|
|
|
if (!c->open) {
|
|
qDebug() << "[WARNING] Tried to display clip" << i << "but it's closed";
|
|
texture_failed = true;
|
|
} else if (is_clip_active(c, playhead)) {
|
|
if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
|
|
// start preparing cache
|
|
get_clip_frame(c, playhead);
|
|
|
|
if (c->texture == NULL) {
|
|
qDebug() << "[WARNING] Texture hasn't been created yet";
|
|
texture_failed = true;
|
|
} else if (playhead >= c->timeline_in) {
|
|
glLoadIdentity();
|
|
int half_width = c->sequence->width/2;
|
|
int half_height = c->sequence->height/2;
|
|
glOrtho(-half_width, half_width, half_height,- half_height, -1, 1);
|
|
int anchor_x = 0;
|
|
int anchor_y = 0;
|
|
|
|
// perform all transform effects
|
|
for (unsigned int j=0;j<c->effects.size();j++) {
|
|
c->effects.at(j)->process_gl(&anchor_x, &anchor_y);
|
|
}
|
|
|
|
int anchor_right = c->media_stream->video_width - anchor_x;
|
|
int anchor_bottom = c->media_stream->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();
|
|
}
|
|
} 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 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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
audio_bytes_written += audio_io_device->write((const char*) cache+audio_bytes_written, audio_cache_size-audio_bytes_written);
|
|
}
|
|
|
|
if (audio_bytes_written == audio_cache_size) {
|
|
// switch_cache
|
|
switch_audio_cache = true;
|
|
}
|
|
}
|
|
|
|
cc_lock.unlock();
|
|
|
|
if (texture_failed) {
|
|
if (multithreaded) {
|
|
retry_timer.start();
|
|
} else {
|
|
paintGL();
|
|
}
|
|
}
|
|
}
|