From 2298e78c617de047c93dcf339b6789cae9ba14a1 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Thu, 14 Mar 2019 15:34:19 +1100 Subject: [PATCH] fixed various audio exporting bugs --- dialogs/exportdialog.cpp | 2 ++ io/exportthread.cpp | 30 ++++++++++++++++++++++++------ rendering/audio.cpp | 6 ++++-- rendering/audio.h | 21 +++++++++++---------- rendering/cacher.cpp | 15 ++++++++------- 5 files changed, 49 insertions(+), 25 deletions(-) diff --git a/dialogs/exportdialog.cpp b/dialogs/exportdialog.cpp index 97eae5b25..3a2714e61 100644 --- a/dialogs/exportdialog.cpp +++ b/dialogs/exportdialog.cpp @@ -35,6 +35,7 @@ #include "panels/panels.h" #include "ui/viewerwidget.h" #include "rendering/renderfunctions.h" +#include "rendering/audio.h" #include "io/exportthread.h" #include "mainwindow.h" @@ -341,6 +342,7 @@ void ExportDialog::render_thread_finished() { QMessageBox::Ok ); } + clear_audio_ibuffer(); prep_ui_for_render(false); panel_sequence_viewer->viewer_widget->makeCurrent(); panel_sequence_viewer->viewer_widget->initializeGL(); diff --git a/io/exportthread.cpp b/io/exportthread.cpp index ab2c689cc..1f7980d31 100644 --- a/io/exportthread.cpp +++ b/io/exportthread.cpp @@ -242,6 +242,9 @@ bool ExportThread::setupAudio() { return false; } + // set sample rate to use for project + audio_rendering_rate = params.audio_sampling_rate; + // setup context acodec_ctx->codec_id = static_cast(params.audio_codec); acodec_ctx->codec_type = AVMEDIA_TYPE_AUDIO; @@ -283,7 +286,7 @@ bool ExportThread::setupAudio() { acodec_ctx->sample_rate, olive::ActiveSequence->audio_layout, AV_SAMPLE_FMT_S16, - olive::ActiveSequence->audio_frequency, + acodec_ctx->sample_rate, 0, nullptr ); @@ -291,9 +294,14 @@ bool ExportThread::setupAudio() { // initialize raw audio frame audio_frame = av_frame_alloc(); - audio_frame->sample_rate = olive::ActiveSequence->audio_frequency; + audio_frame->sample_rate = acodec_ctx->sample_rate; audio_frame->nb_samples = acodec_ctx->frame_size; - if (audio_frame->nb_samples == 0) audio_frame->nb_samples = 256; // should possibly be smaller? + + if (audio_frame->nb_samples == 0) { + // FIXME: Magic number. I don't know what to put here and truthfully I don't even know if it matters. + audio_frame->nb_samples = 256; + } + audio_frame->format = AV_SAMPLE_FMT_S16; audio_frame->channel_layout = AV_CH_LAYOUT_STEREO; // change this to support surround/mono sound in the future (this is whatever format they're held in the internal buffer) audio_frame->channels = av_get_channel_layout_nb_channels(audio_frame->channel_layout); @@ -306,15 +314,18 @@ bool ExportThread::setupAudio() { } aframe_bytes = av_samples_get_buffer_size(nullptr, audio_frame->channels, audio_frame->nb_samples, static_cast(audio_frame->format), 0); + av_init_packet(&audio_pkt); + // init converted audio frame swr_frame = av_frame_alloc(); swr_frame->channel_layout = acodec_ctx->channel_layout; swr_frame->channels = acodec_ctx->channels; swr_frame->sample_rate = acodec_ctx->sample_rate; swr_frame->format = acodec_ctx->sample_fmt; - av_frame_make_writable(swr_frame); + swr_frame->nb_samples = acodec_ctx->frame_size; + av_frame_get_buffer(swr_frame, 0); - av_init_packet(&audio_pkt); + av_frame_make_writable(swr_frame); return true; } @@ -439,8 +450,11 @@ void ExportThread::run() { // convert to export sample format swr_convert_frame(swr_ctx, swr_frame, audio_frame); + swr_frame->pts = file_audio_samples; + qDebug() << swr_frame->nb_samples << acodec_ctx->frame_size; + // send to encoder if (!encode(fmt_ctx, acodec_ctx, swr_frame, &audio_pkt, audio_stream, true)) continueEncode = false; @@ -473,14 +487,18 @@ void ExportThread::run() { olive::Global->set_rendering_state(false); if (params.audio_enabled && continueEncode) { + // flush swresample do { + swr_convert_frame(swr_ctx, swr_frame, nullptr); if (swr_frame->nb_samples == 0) break; swr_frame->pts = file_audio_samples; if (!encode(fmt_ctx, acodec_ctx, swr_frame, &audio_pkt, audio_stream, true)) continueEncode = false; file_audio_samples += swr_frame->nb_samples; + } while (swr_frame->nb_samples > 0); + } bool continueVideo = true; @@ -526,8 +544,8 @@ void ExportThread::run() { sws_freeContext(sws_ctx); } if (swr_ctx != nullptr) { - swr_free(&swr_ctx); av_frame_free(&swr_frame); + swr_free(&swr_ctx); } delete [] c_filename; diff --git a/rendering/audio.cpp b/rendering/audio.cpp index a5e4b49a6..8b5fb945a 100644 --- a/rendering/audio.cpp +++ b/rendering/audio.cpp @@ -50,9 +50,11 @@ bool audio_scrub = false; QMutex audio_write_lock; QAudioInput* audio_input = nullptr; QFile output_recording; -bool audio_rendering = false; bool recording = false; +bool audio_rendering = false; +int audio_rendering_rate = 0; + qint8 audio_ibuffer[audio_ibuffer_size]; qint64 audio_ibuffer_read = 0; long audio_ibuffer_frame = 0; @@ -152,7 +154,7 @@ void clear_audio_ibuffer() { } int current_audio_freq() { - return audio_rendering ? olive::ActiveSequence->audio_frequency : audio_output->format().sampleRate(); + return audio_rendering ? audio_rendering_rate : audio_output->format().sampleRate(); } qint64 get_buffer_offset_from_frame(double framerate, long frame) { diff --git a/rendering/audio.h b/rendering/audio.h index ba6aba7b5..d784f3863 100644 --- a/rendering/audio.h +++ b/rendering/audio.h @@ -32,19 +32,19 @@ #include "project/sequence.h" class AudioSenderThread : public QThread { - Q_OBJECT + Q_OBJECT public: - AudioSenderThread(); - void run(); - void stop(); - QWaitCondition cond; - bool close; - QMutex lock; + AudioSenderThread(); + void run(); + void stop(); + QWaitCondition cond; + bool close; + QMutex lock; public slots: - void notifyReceiver(); + void notifyReceiver(); private: - QVector samples; - int send_audio_to_output(qint64 offset, int max); + QVector samples; + int send_audio_to_output(qint64 offset, int max); }; double log_volume(double linear); @@ -62,6 +62,7 @@ extern double audio_ibuffer_timecode; extern bool audio_scrub; extern bool recording; extern bool audio_rendering; +extern int audio_rendering_rate; void clear_audio_ibuffer(); int current_audio_freq(); diff --git a/rendering/cacher.cpp b/rendering/cacher.cpp index 380b1c996..d077f549b 100644 --- a/rendering/cacher.cpp +++ b/rendering/cacher.cpp @@ -180,6 +180,7 @@ void Cacher::CacheAudioWorker() { // retrieve frame bool new_frame = false; while ((frame_sample_index_ == -1 || frame_sample_index_ >= nb_bytes) && nb_bytes > 0) { + // no more audio left in frame, get a new one if (!reached_end) { int loop = 0; @@ -187,7 +188,8 @@ void Cacher::CacheAudioWorker() { if (reverse_audio && !audio_just_reset) { avcodec_flush_buffers(codecCtx); reached_end = false; - int64_t backtrack_seek = qMax(reverse_target_ - static_cast(av_q2d(av_inv_q(stream->time_base))), static_cast(0)); + int64_t backtrack_seek = qMax(reverse_target_ - static_cast(av_q2d(av_inv_q(stream->time_base))), + static_cast(0)); av_seek_frame(formatCtx, stream->index, backtrack_seek, AVSEEK_FLAG_BACKWARD); #ifdef AUDIOWARNINGS if (backtrack_seek == 0) { @@ -339,7 +341,10 @@ void Cacher::CacheAudioWorker() { if (audio_just_reset) { // get precise sample offset for the elected clip_in from this audio frame double target_sts = playhead_to_clip_seconds(clip, audio_target_frame); - double frame_sts = ((frame->pts - stream->start_time) * timebase); + + int64_t stream_start = qMax(static_cast(0), stream->start_time); + double frame_sts = ((frame->pts - stream_start) * timebase); + int nb_samples = qRound64((target_sts - frame_sts)*current_audio_freq()); frame_sample_index_ = nb_samples * 4; #ifdef AUDIOWARNINGS @@ -387,10 +392,6 @@ void Cacher::CacheAudioWorker() { if (new_frame) { apply_audio_effects(clip, bytes_to_seconds(audio_buffer_write, 2, current_audio_freq()) + audio_ibuffer_timecode + ((double)clip->clip_in(true)/clip->sequence->frame_rate) - ((double)timeline_in/last_fr), frame, nb_bytes, nests_); } - } else { - // shouldn't ever get here - qCritical() << "Tried to cache a non-footage/tone clip"; - return; } // mix audio into internal buffer @@ -957,7 +958,7 @@ void Cacher::OpenWorker() { // set up cache queue_.append(av_frame_alloc()); - // if (clip->reverse) { + if (true) { AVFrame* reverse_frame = av_frame_alloc();