added waveform support in footage viewer and fixed audio regression where sound stopped playing if it hit EOF

This commit is contained in:
itsmattkc
2018-10-19 21:23:15 +11:00
parent 8b0b33f431
commit 84347a0988
15 changed files with 223 additions and 154 deletions
+36 -38
View File
@@ -1777,7 +1777,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) {
}
}
void TimelineWidget::leaveEvent(QEvent *event) {
void TimelineWidget::leaveEvent(QEvent*) {
tooltip_timer.stop();
}
@@ -1785,6 +1785,37 @@ int color_brightness(int r, int g, int b) {
return (0.2126*r + 0.7152*g + 0.0722*b);
}
void draw_waveform(Clip* clip, MediaStream* ms, long media_length, QPainter *p, const QRect& clip_rect, int waveform_start, int waveform_limit, double zoom) {
int divider = ms->audio_channels*2;
int channel_height = clip_rect.height()/ms->audio_channels;
for (int i=waveform_start;i<waveform_limit;i++) {
int waveform_index = qFloor((((clip->clip_in + ((double) i/zoom))/media_length) * ms->audio_preview.size())/divider)*divider;
if (clip->reverse) {
waveform_index = ms->audio_preview.size() - waveform_index - (ms->audio_channels * 2);
}
for (int j=0;j<ms->audio_channels;j++) {
int mid = (config.rectified_waveforms) ? clip_rect.top()+channel_height*(j+1) : clip_rect.top()+channel_height*j+(channel_height/2);
int offset = waveform_index+(j*2);
if ((offset + 1) < ms->audio_preview.size()) {
qint8 min = (double)ms->audio_preview.at(offset) / 128.0 * (channel_height/2);
qint8 max = (double)ms->audio_preview.at(offset+1) / 128.0 * (channel_height/2);
if (config.rectified_waveforms) {
p->drawLine(clip_rect.left()+i, mid, clip_rect.left()+i, mid - (max - min));
} else {
p->drawLine(clip_rect.left()+i, mid+min, clip_rect.left()+i, mid+max);
}
}/* else {
qDebug() << "[WARNING] Tried to reach" << offset + 1 << ", limit:" << ms->audio_preview.size();
}*/
}
}
}
void TimelineWidget::paintEvent(QPaintEvent*) {
// Draw clips
if (sequence != NULL) {
@@ -1869,6 +1900,9 @@ void TimelineWidget::paintEvent(QPaintEvent*) {
}
}
} else if (clip_rect.height() > TRACK_MIN_HEIGHT) {
// draw waveform
p.setPen(QColor(80, 80, 80));
int waveform_start = -qMin(clip_rect.x(), 0);
int waveform_limit = qMin(clip_rect.width(), getScreenPointFromFrame(panel_timeline->zoom, media_length - clip->clip_in));
@@ -1879,43 +1913,7 @@ void TimelineWidget::paintEvent(QPaintEvent*) {
if (waveform_limit > 0) checkerboard_rect.setLeft(checkerboard_rect.left() + waveform_limit);
}
// draw waveform
p.setPen(QColor(80, 80, 80));
int divider = ms->audio_channels*2;
int channel_height = clip_rect.height()/ms->audio_channels;
for (int i=waveform_start;i<waveform_limit;i++) {
int waveform_index = qFloor((((clip->clip_in + ((double) i/panel_timeline->zoom))/media_length) * ms->audio_preview.size())/divider)*divider;
if (clip->reverse) {
waveform_index = ms->audio_preview.size() - waveform_index - (ms->audio_channels * 2);
}
int rectified_height = 0;
for (int j=0;j<ms->audio_channels;j++) {
int mid = clip_rect.top()+channel_height*j+(channel_height/2);
int offset = waveform_index+(j*2);
if ((offset + 1) < ms->audio_preview.size()) {
qint8 min = (double)ms->audio_preview.at(offset) / 128.0 * (channel_height/2);
qint8 max = (double)ms->audio_preview.at(offset+1) / 128.0 * (channel_height/2);
if (config.rectified_waveforms) {
rectified_height += (max - min);
} else {
p.drawLine(clip_rect.left()+i, mid+min, clip_rect.left()+i, mid+max);
}
} else {
qDebug() << "[WARNING] Tried to reach" << offset + 1 << ", limit:" << ms->audio_preview.size();
}
}
if (config.rectified_waveforms) {
p.drawLine(clip_rect.left()+i, clip_rect.height(), clip_rect.left()+i, clip_rect.height() - rectified_height);
}
}
draw_waveform(clip, ms, media_length, &p, clip_rect, waveform_start, waveform_limit, panel_timeline->zoom);
}
}
if (draw_checkerboard) {
+3
View File
@@ -13,12 +13,15 @@
struct Sequence;
struct Clip;
struct MediaStream;
class Timeline;
class TimelineAction;
class QScrollBar;
class SetSelectionsCommand;
class QPainter;
bool same_sign(int a, int b);
void draw_waveform(Clip* clip, MediaStream* ms, long media_length, QPainter* p, const QRect& clip_rect, int waveform_start, int waveform_limit, double zoom);
class TimelineWidget : public QWidget {
Q_OBJECT
+5 -4
View File
@@ -4,10 +4,11 @@
#include <QResizeEvent>
// enforces aspect ratio
ViewerContainer::ViewerContainer(QWidget *parent) : QWidget(parent) {
child = NULL;
aspect_ratio = 1;
}
ViewerContainer::ViewerContainer(QWidget *parent) :
QWidget(parent),
child(NULL),
aspect_ratio(1)
{}
void ViewerContainer::adjust() {
if (child != NULL) {
+1 -1
View File
@@ -13,7 +13,7 @@ public:
void adjust();
protected:
void resizeEvent(QResizeEvent *event);
void resizeEvent(QResizeEvent *event);
signals:
+80 -54
View File
@@ -27,10 +27,12 @@ extern "C" {
}
ViewerWidget::ViewerWidget(QWidget *parent) :
QOpenGLWidget(parent),
rendering(false),
default_fbo(NULL)
QOpenGLWidget(parent),
default_fbo(NULL),
waveform(false)
{
setFocusPolicy(Qt::ClickFocus);
QSurfaceFormat format;
format.setDepthBufferSize(24);
setFormat(format);
@@ -175,62 +177,71 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
QVector<Clip*> current_clips;
long endFrame = LONG_MIN;
for (int i=0;i<s->clips.size();i++) {
Clip* c = s->clips.at(i);
// if clip starts within one second and/or hasn't finished yet
if (c != NULL && !(nest != NULL && !same_sign(c->track, nest->track))) {
bool clip_is_active = false;
if (c != NULL) {
endFrame = qMax(endFrame, c->timeline_out);
switch (c->media_type) {
case MEDIA_TYPE_FOOTAGE:
{
Media* m = static_cast<Media*>(c->media);
if (m->ready) {
MediaStream* ms = m->get_stream_from_file_index(c->track < 0, c->media_stream);
if (ms != NULL && is_clip_active(c, 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, !rendering);
if (!(nest != NULL && !same_sign(c->track, nest->track))) {
bool clip_is_active = false;
switch (c->media_type) {
case MEDIA_TYPE_FOOTAGE:
{
Media* m = static_cast<Media*>(c->media);
if (m->ready) {
MediaStream* ms = m->get_stream_from_file_index(c->track < 0, c->media_stream);
if (ms != NULL && is_clip_active(c, 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, !rendering);
}
clip_is_active = true;
} else if (c->open) {
close_clip(c);
}
} else {
texture_failed = true;
}
}
break;
case MEDIA_TYPE_SEQUENCE:
case MEDIA_TYPE_SOLID:
case MEDIA_TYPE_TONE:
if (is_clip_active(c, playhead)) {
if (!c->open) open_clip(c, !rendering);
clip_is_active = true;
} else if (c->open) {
close_clip(c);
}
} else {
texture_failed = true;
break;
}
}
break;
case MEDIA_TYPE_SEQUENCE:
case MEDIA_TYPE_SOLID:
case MEDIA_TYPE_TONE:
if (is_clip_active(c, playhead)) {
if (!c->open) open_clip(c, !rendering);
clip_is_active = true;
} else if (c->open) {
close_clip(c);
}
break;
}
if (clip_is_active) {
bool added = false;
for (int j=0;j<current_clips.size();j++) {
if (current_clips.at(j)->track < c->track) {
current_clips.insert(j, c);
added = true;
break;
}
}
if (!added) {
current_clips.append(c);
}
}
}
if (clip_is_active) {
bool added = false;
for (int j=0;j<current_clips.size();j++) {
if (current_clips.at(j)->track < c->track) {
current_clips.insert(j, c);
added = true;
break;
}
}
if (!added) {
current_clips.append(c);
}
}
}
}
}
if (viewer->playing && s->playhead == endFrame) {
viewer->pause();
}
int half_width = s->width/2;
int half_height = s->height/2;
if (rendering || nest != NULL) half_height = -half_height;
@@ -444,28 +455,43 @@ void ViewerWidget::paintGL() {
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
texture_failed = false;
texture_failed = false;
if (!rendering) retry_timer.stop();
glClear(GL_COLOR_BUFFER_BIT);
glClear(GL_COLOR_BUFFER_BIT);
// compose video preview
glClearColor(0, 0, 0, 0);
compose_sequence(NULL, (viewer->playing || rendering));
if (texture_failed) {
if (waveform) {
double waveform_zoom = (double) waveform_ms->audio_preview.size() / (double) width();
double timeline_zoom = (double) width() / (double) waveform_clip->timeline_out;
QPainter p(this);
p.setPen(QColor(0, 255, 0));
if (viewer->seq->using_workarea) {
p.fillRect(QRect(getScreenPointFromFrame(timeline_zoom, viewer->seq->workarea_in), 0, getScreenPointFromFrame(timeline_zoom, viewer->seq->workarea_out-viewer->seq->workarea_in), height()), QColor(255, 255, 255, 64));
}
draw_waveform(waveform_clip, waveform_ms, waveform_clip->timeline_out, &p, rect(), 0, width(), waveform_zoom);
p.setPen(Qt::red);
int playhead_x = getScreenPointFromFrame(timeline_zoom, viewer->seq->playhead);
p.drawLine(playhead_x, 0, playhead_x, height());
}
if (texture_failed) {
if (rendering) {
qDebug() << "[INFO] Texture failed - looping";
loop = true;
} else {
} else {
retry_timer.start();
}
}
}
}
if (config.show_title_safe_area && !rendering) {
drawTitleSafeArea();
}
if (config.show_title_safe_area && !rendering) {
drawTitleSafeArea();
}
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
+5 -1
View File
@@ -11,6 +11,7 @@
class Viewer;
struct Clip;
struct MediaStream;
class QOpenGLFramebufferObject;
class ViewerWidget : public QOpenGLWidget
@@ -19,11 +20,14 @@ class ViewerWidget : public QOpenGLWidget
public:
ViewerWidget(QWidget *parent = 0);
bool rendering;
void paintGL();
void initializeGL();
Viewer* viewer;
bool waveform;
Clip* waveform_clip;
MediaStream* waveform_ms;
QOpenGLFramebufferObject* default_fbo;
protected:
void paintEvent(QPaintEvent *e);