fixed various audio issues

This commit is contained in:
itsmattkc
2018-06-07 03:30:54 -07:00
parent b2b3f5a14e
commit 35e03bd91b
24 changed files with 225 additions and 237 deletions
+16
View File
@@ -247,6 +247,22 @@
</item>
</layout>
</widget>
<tabstops>
<tabstop>formatCombobox</tabstop>
<tabstop>videoGroupbox</tabstop>
<tabstop>vcodecCombobox</tabstop>
<tabstop>widthSpinbox</tabstop>
<tabstop>heightSpinbox</tabstop>
<tabstop>framerateSpinbox</tabstop>
<tabstop>videobitrateSpinbox</tabstop>
<tabstop>audioGroupbox</tabstop>
<tabstop>acodecCombobox</tabstop>
<tabstop>samplingRateSpinbox</tabstop>
<tabstop>audiobitrateSpinbox</tabstop>
<tabstop>renderCancel</tabstop>
<tabstop>pushButton</tabstop>
<tabstop>pushButton_2</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
+10
View File
@@ -322,6 +322,16 @@
</item>
</layout>
</widget>
<tabstops>
<tabstop>comboBox</tabstop>
<tabstop>width_numeric</tabstop>
<tabstop>height_numeric</tabstop>
<tabstop>frame_rate_combobox</tabstop>
<tabstop>par_combobox</tabstop>
<tabstop>interlacing_combobox</tabstop>
<tabstop>audio_frequency_combobox</tabstop>
<tabstop>lineEdit</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -29,7 +29,7 @@ void load_config() {
#endif
}*/
padding *= scale;
// padding *= scale;
/*DIR* dir = opendir("conf");
if (dir) {
+1 -1
View File
@@ -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;
+29 -31
View File
@@ -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;i<sequence->clip_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);
+2 -2
View File
@@ -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 \
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.6.1, 2018-06-06T05:46:13. -->
<!-- Written by QtCreator 4.6.1, 2018-06-06T18:33:45. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
+4 -9
View File
@@ -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() {
+1 -1
View File
@@ -1,7 +1,7 @@
#ifndef TIMELINE_H
#define TIMELINE_H
#include "ui/timeline-tools.h"
#include "ui/timelinetools.h"
#include <QDockWidget>
#include <QVector>
#include <QTime>
+3 -8
View File
@@ -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();
}
+1 -3
View File
@@ -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;
+6 -27
View File
@@ -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<int> 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);
}
+7 -8
View File
@@ -1,7 +1,7 @@
#ifndef AUDIO_H
#define AUDIO_H
#include <stdint.h>
#include <QVector>
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<int> audio_ibuffer_write;
void clear_audio_ibuffer();
void init_audio(Sequence* s);
void clear_cache(bool clear_A, bool clear_B);
#endif // AUDIO_H
+61 -45
View File
@@ -16,46 +16,67 @@ extern "C" {
#include <QDebug>
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<AVSampleFormat>(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<AVSampleFormat>(frame->format), 1);
// perform all audio effects
for (int j=0;j<c->effects.size();j++) {
c->effects.at(j)->process_audio(frame->data[0], limit);
}
// mix audio into cache
for (int i=c->frame_sample_index;i<limit;i++) {
cache[j] += frame->data[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;i<c->cache_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;i<c->cache_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<AVSampleFormat>(sample_format),
clip->sequence->audio_frequency,
clip->stream->codecpar->channel_layout,
clip->codecCtx->channel_layout,
static_cast<AVSampleFormat>(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);
+25 -24
View File
@@ -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) {
+1 -1
View File
@@ -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;
+1
View File
@@ -89,6 +89,7 @@ struct Clip
// audio playback variables
SwrContext* swr_ctx;
int frame_sample_index;
int audio_buffer_write;
bool reset_audio;
};
+2 -2
View File
@@ -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) {}
-15
View File
@@ -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
+13
View File
@@ -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
+11 -12
View File
@@ -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<SourceTable*>(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;i<panel_timeline->sequence->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;i<panel_timeline->selections.size();i++) {
+7 -3
View File
@@ -2,7 +2,7 @@
#define TIMELINEWIDGET_H
#include <QWidget>
#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<Clip*> pre_clips;
QList<Clip*> post_clips;
QPixmap* clip_pixmap;
QPixmap clip_pixmap;
// QPixmap selection_pixmap;
signals:
public slots:
private slots:
};
#endif // TIMELINEWIDGET_H
+21 -42
View File
@@ -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;i<current_clips.size();i++) {
Clip* c = current_clips.at(i);
@@ -124,38 +111,30 @@ void ViewerWidget::paintGL()
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 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();