From 8bca36368e7e9203e0a8aed1abfb8ea797e67632 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 20 Jun 2018 00:18:49 -0700 Subject: [PATCH] improved waveform display (#76) --- io/media.h | 7 +++--- io/previewgenerator.cpp | 47 ++++++++++++----------------------------- mainwindow.cpp | 4 ++-- panels/project.cpp | 1 + panels/timeline.cpp | 21 +++++++++--------- panels/timeline.h | 5 ++--- ui/timelinewidget.cpp | 37 ++++++++++++++++++++++++++------ 7 files changed, 65 insertions(+), 57 deletions(-) diff --git a/io/media.h b/io/media.h index b98ac9c23..d82870380 100644 --- a/io/media.h +++ b/io/media.h @@ -15,12 +15,13 @@ struct MediaStream { int video_width; int video_height; bool infinite_length; + int audio_channels; // preview thumbnail/waveform - bool preview_done; - QImage preview; // TODO change to QPixmap QMutex preview_lock; - int preview_audio_index; + bool preview_done; + QImage video_preview; // TODO change to QPixmap + QVector audio_preview; }; struct Media diff --git a/io/previewgenerator.cpp b/io/previewgenerator.cpp index 06ececab0..7b9994040 100644 --- a/io/previewgenerator.cpp +++ b/io/previewgenerator.cpp @@ -51,16 +51,6 @@ void PreviewGenerator::run() { codec_ctx[i] = avcodec_alloc_context3(codec); avcodec_parameters_to_context(codec_ctx[i], fmt_ctx->streams[i]->codecpar); avcodec_open2(codec_ctx[i], codec, NULL); - - if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - // initiate qimage - MediaStream* ms = get_stream_from_file_index(i); - int width = fmt_ctx->streams[i]->duration * av_q2d(fmt_ctx->streams[i]->time_base) * WAVEFORM_RESOLUTION; - if (width > 32767) qDebug() << "[WARNING] Due to limitations in Qt's painter, this waveform may not appear correctly (see issue #76)"; - ms->preview = QImage(width, 80, QImage::Format_RGBA8888); - ms->preview_audio_index = 0; - ms->preview.fill(Qt::transparent); - } } AVPacket packet; bool done = true; @@ -91,7 +81,7 @@ void PreviewGenerator::run() { linesize[0] = dstW*3; sws_scale(sws_ctx, temp_frame->data, temp_frame->linesize, 0, temp_frame->height, &data, linesize); - s->preview = QImage(data, dstW, dstH, linesize[0], QImage::Format_RGB888); + s->video_preview = QImage(data, dstW, dstH, linesize[0], QImage::Format_RGB888); // delete [] data; @@ -101,10 +91,16 @@ void PreviewGenerator::run() { sws_freeContext(sws_ctx); } else if (fmt_ctx->streams[packet.stream_index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { int interval = qFloor((temp_frame->sample_rate/WAVEFORM_RESOLUTION)/4)*4; + + AVFrame* swr_frame = av_frame_alloc(); + swr_frame->channel_layout = temp_frame->channel_layout; + swr_frame->sample_rate = temp_frame->sample_rate; + swr_frame->format = AV_SAMPLE_FMT_S16; + swr_ctx = swr_alloc_set_opts( NULL, temp_frame->channel_layout, - AV_SAMPLE_FMT_S16, + static_cast(swr_frame->format), temp_frame->sample_rate, temp_frame->channel_layout, static_cast(temp_frame->format), @@ -115,25 +111,14 @@ void PreviewGenerator::run() { swr_init(swr_ctx); - AVFrame* swr_frame = av_frame_alloc(); - swr_frame->channel_layout = temp_frame->channel_layout; - swr_frame->sample_rate = temp_frame->sample_rate; - swr_frame->format = AV_SAMPLE_FMT_S16; - swr_convert_frame(swr_ctx, swr_frame, temp_frame); - int channel_height = s->preview.height()/swr_frame->channels; - - QPainter p; - p.begin(&s->preview); - p.setPen(QColor(80, 80, 80)); - int channel_jump = swr_frame->channels * 2; - int divider = (32768.0/(s->preview.height()/2))*swr_frame->channels; + int channel_skip = swr_frame->channels * 2; for (int i=0;inb_samples;i+=interval) { for (int j=0;jchannels;j++) { qint16 min = 0; qint16 max = 0; - for (int k=j*2;kdata[0][i+k+1] << 8) | swr_frame->data[0][i+k]); if (sample > max) { max = sample; @@ -141,16 +126,12 @@ void PreviewGenerator::run() { min = sample; } } - min /= divider; - max /= divider; - - int mid = channel_height*j+(channel_height/2); - p.drawLine(s->preview_audio_index, mid+min, s->preview_audio_index, mid+max); - i += 2; + min /= 256; + max /= 256; + s->audio_preview.append(min); + s->audio_preview.append(max); } - s->preview_audio_index++; } - p.end(); swr_free(&swr_ctx); av_frame_free(&swr_frame); diff --git a/mainwindow.cpp b/mainwindow.cpp index 56eae5bea..33072e0f2 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -130,14 +130,14 @@ void MainWindow::on_actionSequence_triggered() void MainWindow::on_actionZoom_In_triggered() { if (panel_timeline->focused()) { - panel_timeline->zoom_in(); + panel_timeline->set_zoom(true); } } void MainWindow::on_actionZoom_out_triggered() { if (panel_timeline->focused()) { - panel_timeline->zoom_out(); + panel_timeline->set_zoom(false); } } diff --git a/panels/project.cpp b/panels/project.cpp index 59de614b4..797f24d03 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -125,6 +125,7 @@ Media* Project::import_file(QString file) { ms->infinite_length = infinite_length; m->video_tracks.append(ms); } else if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { + ms->audio_channels = pFormatCtx->streams[i]->codecpar->channels; m->audio_tracks.append(ms); } } diff --git a/panels/timeline.cpp b/panels/timeline.cpp index a50aed645..b5266fb1a 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -14,6 +14,7 @@ #include "playback/playback.h" #include +#include #include Timeline::Timeline(QWidget *parent) : @@ -224,14 +225,14 @@ void Timeline::delete_selection(bool ripple_delete) { } } -void Timeline::zoom_in() { - zoom *= 2; - redraw_all_clips(); -} - -void Timeline::zoom_out() { - zoom /= 2; - redraw_all_clips(); +void Timeline::set_zoom(bool in) { + if (in) { + zoom *= 2; + } else { + zoom /= 2; + } + ui->timeline_area->horizontalScrollBar()->setValue(getScreenPointFromFrame(playhead) - (ui->timeline_area->width()/2)); + redraw_all_clips(); } void Timeline::ripple(long ripple_point, long ripple_length) { @@ -288,12 +289,12 @@ void Timeline::on_toolRazorButton_toggled(bool checked) void Timeline::on_pushButton_4_clicked() { - zoom_in(); + set_zoom(true); } void Timeline::on_pushButton_5_clicked() { - zoom_out(); + set_zoom(false); } bool Timeline::is_clip_selected(Clip* clip) { diff --git a/panels/timeline.h b/panels/timeline.h index 9f5c3b82e..cebaa187a 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -58,9 +58,8 @@ public: explicit Timeline(QWidget *parent = 0); ~Timeline(); - bool focused(); - void zoom_in(); - void zoom_out(); + bool focused(); + void set_zoom(bool in); void undo(); void redo(); void copy(bool del); diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 59ffafea2..dab63191c 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -789,17 +789,42 @@ void TimelineWidget::redraw_clips() { if (clip->track < 0) { int thumb_y = clip_painter.fontMetrics().height()+CLIP_TEXT_PADDING+CLIP_TEXT_PADDING; int thumb_height = clip_rect.height()-thumb_y; - int thumb_width = (thumb_height*((float)clip->media_stream->preview.width()/(float)clip->media_stream->preview.height())); + int thumb_width = (thumb_height*((float)clip->media_stream->video_preview.width()/(float)clip->media_stream->video_preview.height())); if (thumb_height > thumb_y && clip_rect.width() > thumb_width) { // at small clip heights, don't even draw it QRect thumb_rect(clip_rect.x(), clip_rect.y()+thumb_y, thumb_width, thumb_height); - clip_painter.drawImage(thumb_rect, clip->media_stream->preview); + clip_painter.drawImage(thumb_rect, clip->media_stream->video_preview); } } else { long length = clip->media->get_length_in_frames(clip->sequence->frame_rate); - int waveform_x = ((float)clip->clip_in/(float)length) * clip->media_stream->preview.width(); - int waveform_width = (((float)clip->getLength()/(float)length) * clip->media_stream->preview.width()); - QRect source(waveform_x, 0, waveform_width, clip->media_stream->preview.height()); - clip_painter.drawImage(clip_rect, clip->media_stream->preview, source); + int waveform_x = ((float)clip->clip_in/(float)length) * clip->media_stream->audio_preview.size(); + int waveform_width = (((float)clip->getLength()/(float)length) * clip->media_stream->audio_preview.size()); + int divider = clip->media_stream->audio_channels*2; + int waveform_scaled_length = qFloor((clip->media_stream->audio_preview.size() / (length*panel_timeline->zoom))/divider)*divider; + + clip_painter.setPen(QColor(80, 80, 80)); + int draw_x = clip_rect.x(); + int channel_height = clip_rect.height()/clip->media_stream->audio_channels; + for (int i=0;imedia_stream->audio_preview.size())/divider)*divider; + for (int j=0;jmedia_stream->audio_channels;j++) { + int mid = channel_height*j+(channel_height/2); + int offset = waveform_index+(j*2); + qint8 min = (float)clip->media_stream->audio_preview[offset] / 128.0f * (channel_height/2); + qint8 max = (float)clip->media_stream->audio_preview[offset+1] / 128.0f * (channel_height/2); + clip_painter.drawLine(clip_rect.left()+i, mid+min, clip_rect.left()+i, mid+max); + } + } + +// for (int i=waveform_x;imedia_stream->audio_channels;j++) { +// int mid = channel_height*j+(channel_height/2); +// int offset = i+(j*2); +// qint8 min = (float)clip->media_stream->audio_preview[offset] / 128.0f * (channel_height/2); +// qint8 max = (float)clip->media_stream->audio_preview[offset+1] / 128.0f * (channel_height/2); +// clip_painter.drawLine(draw_x, mid+min, draw_x, mid+max); +// } +// draw_x++; +// } } }