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> </item>
</layout> </layout>
</widget> </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/> <resources/>
<connections/> <connections/>
</ui> </ui>
+10
View File
@@ -322,6 +322,16 @@
</item> </item>
</layout> </layout>
</widget> </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/> <resources/>
<connections> <connections>
<connection> <connection>
+1 -1
View File
@@ -17,7 +17,7 @@ VolumeEffect::VolumeEffect(Clip* c) : Effect(c) {
ui_layout->addWidget(new QLabel("Volume:"), 0, 0); ui_layout->addWidget(new QLabel("Volume:"), 0, 0);
volume_val = new QSpinBox(); volume_val = new QSpinBox();
volume_val->setMinimum(0); volume_val->setMinimum(0);
volume_val->setMaximum(100); volume_val->setMaximum(400);
ui_layout->addWidget(volume_val, 0, 1); ui_layout->addWidget(volume_val, 0, 1);
ui->setLayout(ui_layout); ui->setLayout(ui_layout);
+1 -1
View File
@@ -29,7 +29,7 @@ void load_config() {
#endif #endif
}*/ }*/
padding *= scale; // padding *= scale;
/*DIR* dir = opendir("conf"); /*DIR* dir = opendir("conf");
if (dir) { if (dir) {
+1 -1
View File
@@ -5,7 +5,7 @@ extern const char* version;
extern float scale; extern float scale;
extern bool vsync; extern bool vsync;
extern bool hwaccel; extern bool hwaccel;
extern int padding; //extern int padding;
extern bool custom_scale; extern bool custom_scale;
extern bool saved_layout; extern bool saved_layout;
extern bool show_track_lines; 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"; qDebug() << "[ERROR] Could not find allocate video encoding context";
fail = true; fail = true;
} else { } else {
vcodec_ctx->width = sequence->width; vcodec_ctx->width = video_width;
vcodec_ctx->height = sequence->height; vcodec_ctx->height = video_height;
vcodec_ctx->sample_aspect_ratio = av_d2q(sequence->width/sequence->height, INT_MAX); 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->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->bit_rate = video_bitrate * 1000000;
vcodec_ctx->time_base = av_inv_q(vcodec_ctx->framerate); vcodec_ctx->time_base = av_inv_q(vcodec_ctx->framerate);
@@ -266,15 +266,7 @@ void ExportThread::run() {
if (ret < 0) { if (ret < 0) {
qDebug() << "[ERROR] Could not write output file header." << ret; qDebug() << "[ERROR] Could not write output file header." << ret;
} else { } else {
panel_timeline->seek(0); panel_timeline->seek(start);
// 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);
}
}
QOpenGLFramebufferObject fbo(video_width, video_height, QOpenGLFramebufferObject::CombinedDepthStencil, GL_TEXTURE_RECTANGLE); QOpenGLFramebufferObject fbo(video_width, video_height, QOpenGLFramebufferObject::CombinedDepthStencil, GL_TEXTURE_RECTANGLE);
fbo.bind(); fbo.bind();
@@ -282,7 +274,6 @@ void ExportThread::run() {
QPainter painter(&fbo_dev); QPainter painter(&fbo_dev);
painter.beginNativePainting(); painter.beginNativePainting();
int written_frame_audio_bytes = 0;
long file_audio_samples = 0; long file_audio_samples = 0;
while (panel_timeline->playhead < end && !fail) { 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); memcpy(video_frame->data[0]+dst_index, flip_buffer+src_index, linesize);
} }
// change pixel format // change pixel format
sws_scale(sws_ctx, video_frame->data, video_frame->linesize, 0, video_frame->height, sws_frame->data, sws_frame->linesize); 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)); sws_frame->pts = round(timecode_secs/av_q2d(video_stream->time_base));
// send to encoder // send to encoder
@@ -310,23 +302,29 @@ void ExportThread::run() {
} }
if (audio_enabled && !fail) { if (audio_enabled && !fail) {
// do we need to encode more audio samples? // do we need to encode more audio samples?
if (file_audio_samples <= (timecode_secs*audio_sampling_rate)) { while (file_audio_samples <= (timecode_secs*audio_sampling_rate)) {
uint8_t* cache = (reading_audio_cache_A) ? audio_cache_A : audio_cache_B; int adjusted_read = audio_ibuffer_read%audio_ibuffer_size;
int copylen = qMin(aframe_bytes-written_frame_audio_bytes, audio_cache_size-audio_bytes_written); int copylen = qMin(aframe_bytes, audio_ibuffer_size-adjusted_read);
memcpy(audio_frame->data[0]+written_frame_audio_bytes, cache+audio_bytes_written, copylen); memcpy(audio_frame->data[0], audio_ibuffer+adjusted_read, copylen);
written_frame_audio_bytes += copylen; memset(audio_ibuffer+adjusted_read, 0, copylen);
audio_bytes_written += copylen; audio_ibuffer_read += 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;
// send to encoder if (copylen < aframe_bytes) {
if (!encode(fmt_ctx, acodec_ctx, swr_frame, &audio_pkt, audio_stream)) fail = true; // copy remainder
int remainder_len = aframe_bytes-copylen;
file_audio_samples += swr_frame->nb_samples; memcpy(audio_frame->data[0]+copylen, audio_ibuffer, remainder_len);
written_frame_audio_bytes = 0; 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); emit progress_changed(((float) panel_timeline->playhead / (float) end) * 100);
+2 -2
View File
@@ -69,7 +69,6 @@ HEADERS += \
playback/audio.h \ playback/audio.h \
effects/effects.h \ effects/effects.h \
io/config.h \ io/config.h \
ui/timeline-tools.h \
dialogs/newsequencedialog.h \ dialogs/newsequencedialog.h \
ui/viewerwidget.h \ ui/viewerwidget.h \
ui/viewercontainer.h \ ui/viewercontainer.h \
@@ -78,7 +77,8 @@ HEADERS += \
project/effect.h \ project/effect.h \
panels/panels.h \ panels/panels.h \
playback/cacher.h \ playback/cacher.h \
io/exportthread.h io/exportthread.h \
ui/timelinetools.h
FORMS += \ FORMS += \
mainwindow.ui \ mainwindow.ui \
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject> <!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> <qtcreator>
<data> <data>
<variable>EnvironmentId</variable> <variable>EnvironmentId</variable>
+4 -9
View File
@@ -69,11 +69,10 @@ void Timeline::seek(long p) {
Clip& c = sequence->get_clip(i); Clip& c = sequence->get_clip(i);
c.reset_audio = true; c.reset_audio = true;
c.frame_sample_index = 0; c.frame_sample_index = 0;
c.audio_buffer_write = 0;
} }
clear_cache(true, true); clear_audio_ibuffer();
audio_bytes_written = 0; audio_ibuffer_read = 0;
switch_audio_cache = true;
reading_audio_cache_A = false;
playhead = p; playhead = p;
} }
@@ -92,11 +91,7 @@ void Timeline::play() {
playback_timer.start(); playback_timer.start();
start_msecs = QDateTime::currentMSecsSinceEpoch(); start_msecs = QDateTime::currentMSecsSinceEpoch();
playback_updater.start(); playback_updater.start();
playing = true; playing = true;
if (switch_audio_cache) {
// add something to pre-cache audio
}
} }
void Timeline::pause() { void Timeline::pause() {
+1 -1
View File
@@ -1,7 +1,7 @@
#ifndef TIMELINE_H #ifndef TIMELINE_H
#define TIMELINE_H #define TIMELINE_H
#include "ui/timeline-tools.h" #include "ui/timelinetools.h"
#include <QDockWidget> #include <QDockWidget>
#include <QVector> #include <QVector>
#include <QTime> #include <QTime>
+3 -8
View File
@@ -29,10 +29,6 @@ Viewer::~Viewer()
delete ui; delete ui;
} }
void Viewer::receiver() {
qDebug() << "callback?";
}
void Viewer::set_sequence(Sequence* s) { void Viewer::set_sequence(Sequence* s) {
bool null_sequence = (s == NULL); bool null_sequence = (s == NULL);
sequence = s; sequence = s;
@@ -45,14 +41,13 @@ void Viewer::set_sequence(Sequence* s) {
ui->pushButton_4->setEnabled(!null_sequence); ui->pushButton_4->setEnabled(!null_sequence);
ui->pushButton_5->setEnabled(!null_sequence); ui->pushButton_5->setEnabled(!null_sequence);
init_audio(s);
if (!null_sequence) { if (!null_sequence) {
ui->glViewerPane->aspect_ratio = (float) sequence->width / (float) sequence->height; 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(); update();
} }
+1 -3
View File
@@ -33,9 +33,7 @@ private slots:
void on_pushButton_4_clicked(); void on_pushButton_4_clicked();
void on_pushButton_3_clicked(); void on_pushButton_3_clicked();
void receiver();
private: private:
Ui::Viewer *ui; Ui::Viewer *ui;
+6 -27
View File
@@ -13,24 +13,11 @@ QAudioOutput* audio_output;
QIODevice* audio_io_device; QIODevice* audio_io_device;
bool audio_device_set = false; bool audio_device_set = false;
uint8_t* audio_cache_A = NULL; qint8 audio_ibuffer[audio_ibuffer_size];
uint8_t* audio_cache_B = NULL; int audio_ibuffer_read = 0;
int audio_cache_size = 0; QVector<int> audio_ibuffer_write;
bool switch_audio_cache = true;
bool reading_audio_cache_A = false;
int audio_bytes_written = 0;
void init_audio(Sequence* s) { 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) { if (audio_device_set) {
audio_output->stop(); audio_output->stop();
delete audio_output; delete audio_output;
@@ -55,19 +42,11 @@ void init_audio(Sequence* s) {
audio_io_device = audio_output->start(); audio_io_device = audio_output->start();
audio_device_set = true; 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); clear_audio_ibuffer();
audio_cache_A = new uint8_t[audio_cache_size];
audio_cache_B = new uint8_t[audio_cache_size];
clear_cache(true, true);
} }
} }
} }
void clear_cache(bool clear_A, bool clear_B) { void clear_audio_ibuffer() {
if (clear_A) { memset(audio_ibuffer, 0, audio_ibuffer_size);
memset(audio_cache_A, 0, audio_cache_size);
}
if (clear_B) {
memset(audio_cache_B, 0, audio_cache_size);
}
} }
+7 -8
View File
@@ -1,7 +1,7 @@
#ifndef AUDIO_H #ifndef AUDIO_H
#define AUDIO_H #define AUDIO_H
#include <stdint.h> #include <QVector>
class QAudioOutput; class QAudioOutput;
class QIODevice; class QIODevice;
@@ -11,13 +11,12 @@ struct Sequence;
extern QAudioOutput* audio_output; extern QAudioOutput* audio_output;
extern QIODevice* audio_io_device; extern QIODevice* audio_io_device;
extern uint8_t* audio_cache_A; #define audio_ibuffer_size 192000
extern uint8_t* audio_cache_B; extern qint8 audio_ibuffer[audio_ibuffer_size];
extern int audio_cache_size; extern int audio_ibuffer_read;
extern int audio_bytes_written; //extern QVector<int> audio_ibuffer_write;
extern bool switch_audio_cache; void clear_audio_ibuffer();
extern bool reading_audio_cache_A;
void init_audio(Sequence* s); void init_audio(Sequence* s);
void clear_cache(bool clear_A, bool clear_B);
#endif // AUDIO_H #endif // AUDIO_H
+61 -45
View File
@@ -16,46 +16,67 @@ extern "C" {
#include <QDebug> #include <QDebug>
void cache_audio_worker(Clip* c, bool write_A) { void cache_audio_worker(Clip* c) {
// gets one frame worth of audio and sends it to the audio buffer int written = 0;
AVFrame* frame = c->cache_A.frames[0]; int max_write = 16384;
uint8_t* cache = (write_A) ? audio_cache_A : audio_cache_B; 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; if (c->frame_sample_index == 0) {
int j = 0; // no more audio left in frame, get a new one
while (bytes_written < audio_cache_size && !c->reached_end) { if (!c->reached_end) {
// is there audio left in the frame retrieve_next_frame_raw_data(c, frame);
if (c->frame_sample_index == 0) { } else {
// no more audio left in frame, get a new one // set by retrieve_next_frame_raw_data indicating no more frames in file,
retrieve_next_frame_raw_data(c, frame); // but there still may be samples in swresample
} swr_convert_frame(c->swr_ctx, frame, NULL);
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 (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++) { for (int j=0;j<c->effects.size();j++) {
c->effects.at(j)->process_audio(frame->data[0], limit); c->effects.at(j)->process_audio(frame->data[0], nb_bytes);
} }
// mix audio into cache
for (int i=c->frame_sample_index;i<limit;i++) { if (c->audio_buffer_write == 0) c->audio_buffer_write = audio_ibuffer_read + 1024;
cache[j] += frame->data[0][i]; while (c->frame_sample_index < nb_bytes) {
j++; if (c->audio_buffer_write >= audio_ibuffer_read+(audio_ibuffer_size/2)) {
} written = max_write;
bytes_written += limit - c->frame_sample_index; break;
c->frame_sample_index = (limit == nb_bytes) ? 0 : limit; } 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) { void cache_video_worker(Clip* c, long playhead, ClipCache* cache) {
cache->mutex.lock(); cache->mutex.lock();
cache->offset = playhead; cache->offset = playhead;
for (size_t i=0;i<c->cache_size;i++) { if (!c->reached_end) {
retrieve_next_frame_raw_data(c, cache->frames[i]); for (size_t i=0;i<c->cache_size;i++) {
} retrieve_next_frame_raw_data(c, cache->frames[i]);
cache->written = true; if (c->reached_end) break;
cache->unread = true; }
}
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(); cache->mutex.unlock();
} }
@@ -81,7 +102,7 @@ void reset_cache(Clip* c, long target_frame) {
// play up to the frame we actually want // play up to the frame we actually want
long retrieved_frame = 0; long retrieved_frame = 0;
AVFrame* temp = av_frame_alloc(); AVFrame* temp = av_frame_alloc();
do { do {
retrieve_next_frame(c, temp); retrieve_next_frame(c, temp);
if (retrieved_frame == 0) { if (retrieved_frame == 0) {
if (target_frame != 0) { if (target_frame != 0) {
@@ -223,7 +244,7 @@ void open_clip_worker(Clip* clip) {
clip->sequence->audio_layout, clip->sequence->audio_layout,
static_cast<AVSampleFormat>(sample_format), static_cast<AVSampleFormat>(sample_format),
clip->sequence->audio_frequency, clip->sequence->audio_frequency,
clip->stream->codecpar->channel_layout, clip->codecCtx->channel_layout,
static_cast<AVSampleFormat>(clip->stream->codecpar->format), static_cast<AVSampleFormat>(clip->stream->codecpar->format),
clip->stream->codecpar->sample_rate, clip->stream->codecpar->sample_rate,
0, 0,
@@ -266,13 +287,8 @@ void cache_clip_worker(Clip* clip, long playhead, bool write_A, bool write_B, bo
if (write_B) { if (write_B) {
cache_video_worker(clip, playhead, &clip->cache_B); cache_video_worker(clip, playhead, &clip->cache_B);
} }
} else if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { } else if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
if (write_A) { cache_audio_worker(clip);
cache_audio_worker(clip, true);
}
if (write_B) {
cache_audio_worker(clip, false);
}
} }
} }
@@ -323,8 +339,8 @@ void Cacher::run() {
caching = true; caching = true;
while (true) { while (true) {
clip->can_cache.wait(&clip->lock); clip->can_cache.wait(&clip->lock);
if (!caching) { if (!caching) {
break; break;
} else { } else {
cache_clip_worker(clip, playhead, write_A, write_B, reset); 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, // if thread is already working, we don't want to touch this,
// but we also don't want to hang the UI thread // but we also don't want to hang the UI thread
if (!c.open) { if (!c.open) {
if (c.lock.tryLock()) { if (c.lock.tryLock()) {
open_clip(&c, multithreaded); open_clip(&c, multithreaded);
// add to current_clips, (insertion) sorted by track so composite them in order // 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 retrieve_next_frame(Clip* c, AVFrame* f) {
int result = 0; int result = 0;
int receive_ret; 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
// do we need to retrieve a new packet for a new frame? // 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; int read_ret = 0;
do { do {
if (c->pkt_written) { 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); int send_ret = avcodec_send_packet(c->codecCtx, c->pkt);
if (send_ret < 0) { if (send_ret < 0) {
qDebug() << "[ERROR] Failed to send packet to decoder." << send_ret; qDebug() << "[ERROR] Failed to send packet to decoder." << send_ret;
result = send_ret; return send_ret;
break;
} }
} else { } else {
if (read_ret != AVERROR_EOF) qDebug() << "[ERROR] Could not read frame." << read_ret; if (read_ret != AVERROR_EOF) qDebug() << "[ERROR] Could not read frame." << read_ret;
return read_ret; // skips trying to find a frame at all 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) { void retrieve_next_frame_raw_data(Clip* c, AVFrame* output) {
int ret = retrieve_next_frame(c, c->frame); if (c->reached_end) {
if (ret >= 0) { qDebug() << "[WARNING] Attempted to retrieve frame of stream with no frames left";
if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { } else {
sws_scale(c->sws_ctx, c->frame->data, c->frame->linesize, 0, c->stream->codecpar->height, output->data, output->linesize); int ret = retrieve_next_frame(c, c->frame);
} else if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { if (ret >= 0) {
ret = swr_convert_frame(c->swr_ctx, output, c->frame); if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
if (ret < 0) { sws_scale(c->sws_ctx, c->frame->data, c->frame->linesize, 0, c->stream->codecpar->height, output->data, output->linesize);
qDebug() << "[ERROR] Failed to resample audio." << ret; } else if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
} ret = swr_convert_frame(c->swr_ctx, output, c->frame);
} if (ret < 0) {
} else if (ret == AVERROR_EOF) { qDebug() << "[ERROR] Failed to resample audio." << ret;
c->reached_end = true; }
} else { }
qDebug() << "[WARNING] Raw frame data could not be retrieved." << 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) { bool is_clip_active(Clip* c, long playhead) {
+1 -1
View File
@@ -52,7 +52,7 @@ void Clip::init() {
} }
void Clip::reset() { 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; texture_frame = -1;
formatCtx = NULL; formatCtx = NULL;
stream = NULL; stream = NULL;
+1
View File
@@ -89,6 +89,7 @@ struct Clip
// audio playback variables // audio playback variables
SwrContext* swr_ctx; SwrContext* swr_ctx;
int frame_sample_index; int frame_sample_index;
int audio_buffer_write;
bool reset_audio; bool reset_audio;
}; };
+2 -2
View File
@@ -21,5 +21,5 @@ Effect* Effect::copy() {
return e; return e;
} }
void Effect::process_gl(int* anchor_x, int* anchor_y) {} void Effect::process_gl(int*, int*) {}
void Effect::process_audio(uint8_t* samples, int nb_bytes) {} 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; bottom_align = false;
setMouseTracking(true); setMouseTracking(true);
track_height = 40; track_height = 40;
clip_pixmap = NULL;
setAcceptDrops(true); setAcceptDrops(true);
} }
@@ -35,6 +33,10 @@ bool same_sign(int a, int b) {
return (a < 0) == (b < 0); return (a < 0) == (b < 0);
} }
void TimelineWidget::resizeEvent(QResizeEvent*) {
if (panel_timeline->sequence != NULL) redraw_clips();
}
void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) { void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) {
if (static_cast<SourceTable*>(event->source()) == panel_project->source_table) { if (static_cast<SourceTable*>(event->source()) == panel_project->source_table) {
QPoint pos = event->pos(); 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) { if (panel_timeline->importing) {
panel_timeline->ghosts.clear(); panel_timeline->ghosts.clear();
panel_timeline->importing = false; 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) { void validate_snapping(Ghost& g, long* frame_diff) {
long validator;
panel_timeline->snapped = false; panel_timeline->snapped = false;
if (panel_timeline->snapping) { if (panel_timeline->snapping) {
if (!subvalidate_snapping(g, frame_diff, panel_timeline->playhead)) { 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() { void TimelineWidget::redraw_clips() {
// Draw clips // Draw clips
if (clip_pixmap != NULL) delete clip_pixmap;
int panel_width = getScreenPointFromFrame(panel_timeline->sequence->getEndFrame()) + 100; int panel_width = getScreenPointFromFrame(panel_timeline->sequence->getEndFrame()) + 100;
setMinimumWidth(panel_width); setMinimumWidth(panel_width);
clip_pixmap = new QPixmap(panel_width, height()); clip_pixmap = QPixmap(panel_width, height());
clip_pixmap->fill(Qt::transparent); clip_pixmap.fill(Qt::transparent);
QPainter clip_painter(clip_pixmap); QPainter clip_painter(&clip_pixmap);
int video_track_limit = 0; int video_track_limit = 0;
int audio_track_limit = 0; int audio_track_limit = 0;
for (int i=0;i<panel_timeline->sequence->clip_count();i++) { for (int i=0;i<panel_timeline->sequence->clip_count();i++) {
@@ -726,7 +725,7 @@ void TimelineWidget::paintEvent(QPaintEvent*) {
if (panel_timeline->sequence != NULL) { if (panel_timeline->sequence != NULL) {
QPainter p(this); 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 // Draw selections
for (int i=0;i<panel_timeline->selections.size();i++) { for (int i=0;i<panel_timeline->selections.size();i++) {
+7 -3
View File
@@ -2,7 +2,7 @@
#define TIMELINEWIDGET_H #define TIMELINEWIDGET_H
#include <QWidget> #include <QWidget>
#include "timeline-tools.h" #include "timelinetools.h"
#define GHOST_THICKNESS 2 // thiccccc #define GHOST_THICKNESS 2 // thiccccc
#define CLIP_TEXT_PADDING 3 #define CLIP_TEXT_PADDING 3
@@ -19,9 +19,10 @@ public:
bool bottom_align; bool bottom_align;
void redraw_clips(); void redraw_clips();
protected: protected:
void paintEvent(QPaintEvent*) override; void paintEvent(QPaintEvent*) override;
void resizeEvent(QResizeEvent*) override;
void mousePressEvent(QMouseEvent *event) override; void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override;
@@ -45,12 +46,15 @@ private:
QList<Clip*> pre_clips; QList<Clip*> pre_clips;
QList<Clip*> post_clips; QList<Clip*> post_clips;
QPixmap* clip_pixmap; QPixmap clip_pixmap;
// QPixmap selection_pixmap; // QPixmap selection_pixmap;
signals: signals:
public slots: public slots:
private slots:
}; };
#endif // TIMELINEWIDGET_H #endif // TIMELINEWIDGET_H
+21 -42
View File
@@ -17,12 +17,10 @@ extern "C" {
ViewerWidget::ViewerWidget(QWidget *parent) : QOpenGLWidget(parent) ViewerWidget::ViewerWidget(QWidget *parent) : QOpenGLWidget(parent)
{ {
multithreaded = true; multithreaded = true;
enable_paint = true; enable_paint = true;
force_audio = false; force_audio = false;
audio_bytes_written = 0;
QSurfaceFormat format; QSurfaceFormat format;
format.setDepthBufferSize(24); format.setDepthBufferSize(24);
setFormat(format); setFormat(format);
@@ -67,17 +65,6 @@ void ViewerWidget::paintGL()
bool render_audio = (panel_timeline->playing || force_audio); 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(); cc_lock.lock();
for (int i=0;i<current_clips.size();i++) { for (int i=0;i<current_clips.size();i++) {
Clip* c = current_clips.at(i); Clip* c = current_clips.at(i);
@@ -124,38 +111,30 @@ void ViewerWidget::paintGL()
c->texture->release(); c->texture->release();
} }
} else if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && } else if (render_audio &&
playhead >= c->timeline_in && c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
render_audio && playhead >= c->timeline_in &&
!c->reached_end && c->lock.tryLock()) {
(switch_audio_cache || c->reset_audio)) { // clip is not caching, start caching 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) c->lock.unlock();
cache_clip(c, playhead, false, false, c->reset_audio);
// 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) { if (panel_timeline->playing) {
switch_audio_cache = false; int adjusted_read_index = audio_ibuffer_read%audio_ibuffer_size;
int max_write = audio_ibuffer_size - adjusted_read_index;
if (audio_cache_A != NULL && audio_bytes_written < audio_cache_size) { int actual_write = audio_io_device->write((const char*) audio_ibuffer+adjusted_read_index, max_write);
// send cached/buffered audio to QIODevice/QAudioOutput memset(audio_ibuffer+adjusted_read_index, 0, actual_write);
uint8_t* cache = reading_audio_cache_A ? audio_cache_A : audio_cache_B; audio_ibuffer_read += actual_write;
if (panel_timeline->playing) { if (actual_write == max_write) {
int max_w = audio_cache_size-audio_bytes_written; // got all the bytes, write again
int w = audio_io_device->write((const char*) cache+audio_bytes_written, max_w); actual_write = audio_io_device->write((const char*) audio_ibuffer, audio_ibuffer_size);
qDebug() << w << max_w; memset(audio_ibuffer, 0, actual_write);
audio_bytes_written += w; audio_ibuffer_read += actual_write;
}
} }
} }
cc_lock.unlock(); cc_lock.unlock();