going with the simpler nested audio option
This commit is contained in:
+3
-9
@@ -86,18 +86,12 @@ void clear_audio_ibuffer() {
|
||||
}
|
||||
|
||||
int get_buffer_offset_from_frame(Sequence* s, long frame) {
|
||||
// currently debugging this function. since it has a high potential of failure and isn't actually fatal, we only assert on debug mode
|
||||
/*#ifdef QT_DEBUG
|
||||
Q_ASSERT(frame >= audio_ibuffer_frame);
|
||||
return qFloor(av_samples_get_buffer_size(NULL, av_get_channel_layout_nb_channels(s->audio_layout), qRound(((frame-audio_ibuffer_frame)/s->frame_rate)*s->audio_frequency), AV_SAMPLE_FMT_S16, 1)/4)*4;
|
||||
#else*/
|
||||
if (frame >= audio_ibuffer_frame) {
|
||||
return qFloor(av_samples_get_buffer_size(NULL, av_get_channel_layout_nb_channels(s->audio_layout), qRound(((frame-audio_ibuffer_frame)/s->frame_rate)*s->audio_frequency), AV_SAMPLE_FMT_S16, 1)/4)*4;
|
||||
return qFloor(((double) (frame - audio_ibuffer_frame)/s->frame_rate)*s->audio_frequency)*av_get_bytes_per_sample(AV_SAMPLE_FMT_S16)*av_get_channel_layout_nb_channels(s->audio_layout);
|
||||
} else {
|
||||
dout << "[WARNING] Invalid values passed to get_buffer_offset_from_frame";
|
||||
return 0;
|
||||
}
|
||||
//#endif
|
||||
}
|
||||
|
||||
AudioSenderThread::AudioSenderThread() : close(false) {
|
||||
@@ -163,14 +157,14 @@ int AudioSenderThread::send_audio_to_output(int offset, int max) {
|
||||
int channel_count = av_get_channel_layout_nb_channels(s->audio_layout);
|
||||
long sample_cache_playhead = panel_timeline->ui->audio_monitor->sample_cache_offset + (panel_timeline->ui->audio_monitor->sample_cache.size()/channel_count);
|
||||
int next_buffer_offset, buffer_offset_adjusted, i;
|
||||
int buffer_offset = get_buffer_offset_from_frame(s, sample_cache_playhead);
|
||||
int buffer_offset = get_buffer_offset_from_frame(s, sample_cache_playhead);
|
||||
if (samples.size() != channel_count) samples.resize(channel_count);
|
||||
samples.fill(0);
|
||||
|
||||
// TODO: I don't like this, but i'm not sure if there's a smarter way to do it
|
||||
while (buffer_offset < audio_ibuffer_limit) {
|
||||
sample_cache_playhead++;
|
||||
next_buffer_offset = qMin(get_buffer_offset_from_frame(s, sample_cache_playhead), audio_ibuffer_limit);
|
||||
next_buffer_offset = qMin(get_buffer_offset_from_frame(s, sample_cache_playhead), audio_ibuffer_limit);
|
||||
while (buffer_offset < next_buffer_offset) {
|
||||
for (i=0;i<samples.size();i++) {
|
||||
buffer_offset_adjusted = buffer_offset%audio_ibuffer_size;
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ void clear_audio_ibuffer();
|
||||
|
||||
void init_audio(Sequence *s);
|
||||
void stop_audio();
|
||||
int get_buffer_offset_from_frame(Sequence *s, long frame);
|
||||
int get_buffer_offset_from_frame(Sequence* s, long frame);
|
||||
|
||||
bool start_recording();
|
||||
void stop_recording();
|
||||
|
||||
+27
-13
@@ -8,6 +8,7 @@
|
||||
#include "effects/effect.h"
|
||||
#include "panels/timeline.h"
|
||||
#include "panels/project.h"
|
||||
#include "playback/audio.h"
|
||||
#include "debug.h"
|
||||
|
||||
extern "C" {
|
||||
@@ -23,6 +24,7 @@ extern "C" {
|
||||
|
||||
#include <QOpenGLFramebufferObject>
|
||||
#include <QtMath>
|
||||
#include <QAudioOutput>
|
||||
#include <math.h>
|
||||
|
||||
// temp debug shit
|
||||
@@ -71,12 +73,14 @@ void apply_audio_effects(Clip* c, double timecode_start, AVFrame* frame, int nb_
|
||||
|
||||
#define AUDIO_BUFFER_PADDING 2048
|
||||
|
||||
void cache_audio_worker(Clip* c, bool scrubbing, Clip* nest) {
|
||||
void cache_audio_worker(Clip* c, bool scrubbing, QVector<Clip*>& nests) {
|
||||
long timeline_in = c->timeline_in;
|
||||
long timeline_out = c->timeline_out;
|
||||
if (nest != NULL) {
|
||||
timeline_in = refactor_frame_number(timeline_in, c->sequence->frame_rate, sequence->frame_rate) + nest->timeline_in;
|
||||
timeline_out = refactor_frame_number(timeline_out, c->sequence->frame_rate, sequence->frame_rate) + nest->timeline_in;
|
||||
if (!nests.isEmpty()) {
|
||||
for (int i=nests.size()-1;i>=0;i--) {
|
||||
timeline_in = refactor_frame_number(timeline_in, c->sequence->frame_rate, nests.at(i)->sequence->frame_rate) + nests.at(i)->timeline_in;
|
||||
timeline_out = refactor_frame_number(timeline_out, c->sequence->frame_rate, nests.at(i)->sequence->frame_rate) + nests.at(i)->timeline_in;
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
@@ -269,7 +273,7 @@ void cache_audio_worker(Clip* c, bool scrubbing, Clip* nest) {
|
||||
#ifdef AUDIOWARNINGS
|
||||
dout << "fsi-post-post:" << c->frame_sample_index;
|
||||
#endif
|
||||
if (c->audio_buffer_write == 0) c->audio_buffer_write = get_buffer_offset_from_frame(c->sequence, qMax(timeline_in, c->audio_target_frame));
|
||||
if (c->audio_buffer_write == 0) c->audio_buffer_write = get_buffer_offset_from_frame(sequence, qMax(timeline_in, c->audio_target_frame));
|
||||
|
||||
int offset = (audio_ibuffer_read + AUDIO_BUFFER_PADDING) - c->audio_buffer_write;
|
||||
if (offset > 0) {
|
||||
@@ -306,7 +310,7 @@ void cache_audio_worker(Clip* c, bool scrubbing, Clip* nest) {
|
||||
apply_audio_effects(c, bytes_to_seconds(frame->pts, frame->channels, frame->sample_rate), frame, nb_bytes);
|
||||
c->frame->pts += nb_bytes;
|
||||
c->frame_sample_index = 0;
|
||||
if (c->audio_buffer_write == 0) c->audio_buffer_write = get_buffer_offset_from_frame(c->sequence, qMax(timeline_in, c->audio_target_frame));
|
||||
if (c->audio_buffer_write == 0) c->audio_buffer_write = get_buffer_offset_from_frame(sequence, qMax(timeline_in, c->audio_target_frame));
|
||||
int offset = audio_ibuffer_read - c->audio_buffer_write;
|
||||
if (offset > 0) {
|
||||
c->audio_buffer_write += offset;
|
||||
@@ -323,8 +327,14 @@ void cache_audio_worker(Clip* c, bool scrubbing, Clip* nest) {
|
||||
if (frame->nb_samples == 0) {
|
||||
break;
|
||||
} else {
|
||||
long buffer_timeline_out = get_buffer_offset_from_frame(c->sequence, timeline_out);
|
||||
long buffer_timeline_out = get_buffer_offset_from_frame(sequence, timeline_out);
|
||||
audio_write_lock.lock();
|
||||
|
||||
dout << c->name << "says" << c->frame_sample_index << nb_bytes
|
||||
<< c->audio_buffer_write << audio_ibuffer_read+(audio_ibuffer_size>>1)
|
||||
<< c->audio_buffer_write << buffer_timeline_out;
|
||||
dout << c->name << "also says" << timeline_in << c->audio_target_frame;
|
||||
int written = 0;
|
||||
while (c->frame_sample_index < nb_bytes
|
||||
&& c->audio_buffer_write < audio_ibuffer_read+(audio_ibuffer_size>>1)
|
||||
&& c->audio_buffer_write < buffer_timeline_out) {
|
||||
@@ -339,7 +349,11 @@ void cache_audio_worker(Clip* c, bool scrubbing, Clip* nest) {
|
||||
|
||||
c->audio_buffer_write+=2;
|
||||
c->frame_sample_index+=2;
|
||||
|
||||
written += 2;
|
||||
}
|
||||
dout << c->name << "wrote" << written;
|
||||
|
||||
#ifdef AUDIOWARNINGS
|
||||
if (c->audio_buffer_write >= buffer_timeline_out) dout << "timeline out at fsi" << c->frame_sample_index << "of frame ts" << c->frame->pts;
|
||||
#endif
|
||||
@@ -744,7 +758,7 @@ void open_clip_worker(Clip* clip) {
|
||||
dout << "[ERROR] Could not set output sample format";
|
||||
}
|
||||
|
||||
int target_sample_rate = clip->sequence->audio_frequency;
|
||||
int target_sample_rate = sequence->audio_frequency;
|
||||
|
||||
if (qFuzzyCompare(clip->speed, 1.0)) {
|
||||
avfilter_link(clip->buffersrc_ctx, 0, clip->buffersink_ctx, 0);
|
||||
@@ -779,7 +793,7 @@ void open_clip_worker(Clip* clip) {
|
||||
|
||||
avfilter_link(last_filter, 0, clip->buffersink_ctx, 0);
|
||||
} else {
|
||||
target_sample_rate = qRound64(clip->sequence->audio_frequency / clip->speed);
|
||||
target_sample_rate = qRound64(target_sample_rate / clip->speed);
|
||||
avfilter_link(clip->buffersrc_ctx, 0, clip->buffersink_ctx, 0);
|
||||
}
|
||||
|
||||
@@ -820,7 +834,7 @@ void open_clip_worker(Clip* clip) {
|
||||
dout << "[INFO] Clip opened on track" << clip->track;
|
||||
}
|
||||
|
||||
void cache_clip_worker(Clip* clip, long playhead, bool reset, bool scrubbing, Clip* nest) {
|
||||
void cache_clip_worker(Clip* clip, long playhead, bool reset, bool scrubbing, QVector<Clip*> nests) {
|
||||
if (reset) {
|
||||
// note: for video, playhead is in "internal clip" frames - for audio, it's the timeline playhead
|
||||
reset_cache(clip, playhead);
|
||||
@@ -832,11 +846,11 @@ void cache_clip_worker(Clip* clip, long playhead, bool reset, bool scrubbing, Cl
|
||||
if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||
cache_video_worker(clip, playhead);
|
||||
} else if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
|
||||
cache_audio_worker(clip, scrubbing, nest);
|
||||
cache_audio_worker(clip, scrubbing, nests);
|
||||
}
|
||||
break;
|
||||
case MEDIA_TYPE_TONE:
|
||||
cache_audio_worker(clip, scrubbing, nest);
|
||||
cache_audio_worker(clip, scrubbing, nests);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -875,7 +889,7 @@ void Cacher::run() {
|
||||
if (!caching) {
|
||||
break;
|
||||
} else {
|
||||
cache_clip_worker(clip, playhead, reset, scrubbing, nest);
|
||||
cache_clip_worker(clip, playhead, reset, scrubbing, nests);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -2,6 +2,7 @@
|
||||
#define CACHER_H
|
||||
|
||||
#include <QThread>
|
||||
#include <QVector>
|
||||
|
||||
struct Clip;
|
||||
|
||||
@@ -18,14 +19,14 @@ public:
|
||||
long playhead;
|
||||
bool reset;
|
||||
bool scrubbing;
|
||||
Clip* nest;
|
||||
QVector<Clip*> nests;
|
||||
|
||||
private:
|
||||
Clip* clip;
|
||||
};
|
||||
|
||||
void open_clip_worker(Clip* clip);
|
||||
void cache_clip_worker(Clip* clip, long playhead, bool reset, bool scrubbing, Clip *nest);
|
||||
void cache_clip_worker(Clip* clip, long playhead, bool reset, bool scrubbing, QVector<Clip *> nest);
|
||||
void close_clip_worker(Clip* clip);
|
||||
|
||||
#endif // CACHER_H
|
||||
|
||||
@@ -26,7 +26,7 @@ extern "C" {
|
||||
#include <QOpenGLFramebufferObject>
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
#define GCF_DEBUG
|
||||
//#define GCF_DEBUG
|
||||
#endif
|
||||
|
||||
bool texture_failed = false;
|
||||
@@ -95,17 +95,17 @@ void close_clip(Clip* clip) {
|
||||
}
|
||||
}
|
||||
|
||||
void cache_clip(Clip* clip, long playhead, bool reset, bool scrubbing, Clip* nest) {
|
||||
void cache_clip(Clip* clip, long playhead, bool reset, bool scrubbing, QVector<Clip*>& nests) {
|
||||
if (clip->media_type == MEDIA_TYPE_FOOTAGE || clip->media_type == MEDIA_TYPE_TONE) {
|
||||
if (clip->multithreaded) {
|
||||
clip->cacher->playhead = playhead;
|
||||
clip->cacher->reset = reset;
|
||||
clip->cacher->nest = nest;
|
||||
clip->cacher->nests = nests;
|
||||
clip->cacher->scrubbing = scrubbing;
|
||||
|
||||
clip->can_cache.wakeAll();
|
||||
} else {
|
||||
cache_clip_worker(clip, playhead, reset, scrubbing, nest);
|
||||
cache_clip_worker(clip, playhead, reset, scrubbing, nests);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -225,7 +225,7 @@ void get_clip_frame(Clip* c, long playhead) {
|
||||
c->queue_lock.unlock();
|
||||
|
||||
// get more frames
|
||||
if (cache) cache_clip(c, playhead, reset, false, NULL);
|
||||
if (cache) cache_clip(c, playhead, reset, false, QVector<Clip*>());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ extern bool texture_failed;
|
||||
extern bool rendering;
|
||||
|
||||
void open_clip(Clip* clip, bool multithreaded);
|
||||
void cache_clip(Clip* clip, long playhead, bool reset, bool scrubbing, Clip *nest);
|
||||
void cache_clip(Clip* clip, long playhead, bool reset, bool scrubbing, QVector<Clip *> &nests);
|
||||
void close_clip(Clip* clip);
|
||||
void cache_audio_worker(Clip* c, bool write_A);
|
||||
void cache_video_worker(Clip* c, long playhead);
|
||||
|
||||
+32
-17
@@ -217,14 +217,22 @@ void ViewerWidget::process_effect(Clip* c, Effect* e, double timecode, GLTexture
|
||||
}
|
||||
}
|
||||
|
||||
GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
|
||||
GLuint ViewerWidget::compose_sequence(QVector<Clip*>& nests, bool render_audio) {
|
||||
Sequence* s = viewer->seq;
|
||||
long playhead = s->playhead;
|
||||
|
||||
if (nest != NULL) {
|
||||
s = static_cast<Sequence*>(nest->media);
|
||||
playhead += nest->clip_in - nest->timeline_in;
|
||||
playhead = refactor_frame_number(playhead, nest->sequence->frame_rate, s->frame_rate);
|
||||
if (!nests.isEmpty()) {
|
||||
for (int i=0;i<nests.size();i++) {
|
||||
s = static_cast<Sequence*>(nests.at(i)->media);
|
||||
playhead += nests.at(i)->clip_in - nests.at(i)->timeline_in;
|
||||
playhead = refactor_frame_number(playhead, nests.at(i)->sequence->frame_rate, s->frame_rate);
|
||||
}
|
||||
|
||||
if (nests.last()->fbo != NULL) {
|
||||
nests.last()->fbo[0]->bind();
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
nests.last()->fbo[0]->release();
|
||||
}
|
||||
}
|
||||
|
||||
QVector<Clip*> current_clips;
|
||||
@@ -234,7 +242,7 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
|
||||
|
||||
// if clip starts within one second and/or hasn't finished yet
|
||||
if (c != NULL) {
|
||||
if (!(nest != NULL && !same_sign(c->track, nest->track))) {
|
||||
if (!(!nests.isEmpty() && !same_sign(c->track, nests.last()->track))) {
|
||||
bool clip_is_active = false;
|
||||
|
||||
switch (c->media_type) {
|
||||
@@ -288,7 +296,7 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
|
||||
|
||||
int half_width = s->width/2;
|
||||
int half_height = s->height/2;
|
||||
if (rendering || nest != NULL) half_height = -half_height; // invert vertical
|
||||
if (rendering || !nests.isEmpty()) half_height = -half_height; // invert vertical
|
||||
glPushMatrix();
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glColor4f(1.0, 1.0, 1.0, 1.0);
|
||||
@@ -349,7 +357,9 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
|
||||
|
||||
// for nested sequences
|
||||
if (c->media_type == MEDIA_TYPE_SEQUENCE) {
|
||||
textureID = compose_sequence(c, render_audio);
|
||||
nests.append(c);
|
||||
textureID = compose_sequence(nests, render_audio);
|
||||
nests.removeLast();
|
||||
fbo_switcher = true;
|
||||
}
|
||||
|
||||
@@ -406,8 +416,8 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
|
||||
}
|
||||
// EFFECT CODE END
|
||||
|
||||
if (nest != NULL) {
|
||||
nest->fbo[0]->bind();
|
||||
if (!nests.isEmpty()) {
|
||||
nests.last()->fbo[0]->bind();
|
||||
glViewport(0, 0, s->width, s->height);
|
||||
} else if (rendering) {
|
||||
glViewport(0, 0, s->width, s->height);
|
||||
@@ -433,8 +443,8 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
if (nest != NULL) {
|
||||
nest->fbo[0]->release();
|
||||
if (!nests.isEmpty()) {
|
||||
nests.last()->fbo[0]->release();
|
||||
if (default_fbo != NULL) default_fbo->bind();
|
||||
}
|
||||
|
||||
@@ -447,12 +457,14 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
|
||||
case MEDIA_TYPE_TONE:
|
||||
if (c->lock.tryLock()) {
|
||||
// clip is not caching, start caching audio
|
||||
cache_clip(c, playhead, c->audio_reset, !render_audio, nest);
|
||||
cache_clip(c, playhead, c->audio_reset, !render_audio, nests);
|
||||
c->lock.unlock();
|
||||
}
|
||||
break;
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
compose_sequence(c, render_audio);
|
||||
nests.append(c);
|
||||
compose_sequence(nests, render_audio);
|
||||
nests.removeLast();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -474,9 +486,9 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
if (nest != NULL && nest->fbo != NULL) {
|
||||
if (!nests.isEmpty() && nests.last()->fbo != NULL) {
|
||||
// returns nested clip's texture
|
||||
return nest->fbo[0]->texture();
|
||||
return nests.last()->fbo[0]->texture();
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -501,7 +513,10 @@ void ViewerWidget::paintGL() {
|
||||
|
||||
// compose video preview
|
||||
glClearColor(0, 0, 0, 0);
|
||||
compose_sequence(NULL, render_audio);
|
||||
|
||||
QVector<Clip*> nests;
|
||||
|
||||
compose_sequence(nests, render_audio);
|
||||
|
||||
if (waveform) {
|
||||
double waveform_zoom = (double) waveform_ms->audio_preview.size() / (double) width();
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ private:
|
||||
void drawTitleSafeArea();
|
||||
bool dragging;
|
||||
void seek_from_click(int x);
|
||||
GLuint compose_sequence(Clip *nest, bool render_audio);
|
||||
GLuint compose_sequence(QVector<Clip *> &nests, bool render_audio);
|
||||
GLuint draw_clip(QOpenGLFramebufferObject *clip, GLuint texture);
|
||||
void process_effect(Clip* c, Effect* e, double timecode, GLTextureCoords& coords, GLuint& composite_texture, bool& fbo_switcher);
|
||||
private slots:
|
||||
|
||||
Reference in New Issue
Block a user