diff --git a/app/decoder/decoder.h b/app/decoder/decoder.h index 0d463857f..033b26cd2 100644 --- a/app/decoder/decoder.h +++ b/app/decoder/decoder.h @@ -58,25 +58,7 @@ public: // Necessary for subclassing, it's empty virtual ~Decoder(); - /** - * @brief Deleted copy constructor - */ - Decoder(const Decoder& other) = delete; - - /** - * @brief Deleted move constructor - */ - Decoder(Decoder&& other) = delete; - - /** - * @brief Deleted copy assignment - */ - Decoder& operator=(const Decoder& other) = delete; - - /** - * @brief Deleted move assignment - */ - Decoder& operator=(Decoder&& other) = delete; + Q_DISABLE_COPY_MOVE(Decoder) virtual QString id() = 0; diff --git a/app/decoder/ffmpeg/ffmpegdecoder.cpp b/app/decoder/ffmpeg/ffmpegdecoder.cpp index 3e6c37ba8..5c555773b 100644 --- a/app/decoder/ffmpeg/ffmpegdecoder.cpp +++ b/app/decoder/ffmpeg/ffmpegdecoder.cpp @@ -249,7 +249,7 @@ FramePtr FFmpegDecoder::Retrieve(const rational &timecode, const rational &lengt FramePtr frame_container = Frame::Create(); frame_container->set_width(frame_->width); frame_container->set_height(frame_->height); - frame_container->set_format(output_fmt_); + frame_container->set_format(static_cast(output_fmt_)); frame_container->set_timestamp(rational(frame_->pts * avstream_->time_base.num, avstream_->time_base.den)); frame_container->set_native_timestamp(frame_->pts); frame_container->allocate(); diff --git a/app/decoder/frame.cpp b/app/decoder/frame.cpp index eaa6b1c29..8d419b94d 100644 --- a/app/decoder/frame.cpp +++ b/app/decoder/frame.cpp @@ -28,7 +28,8 @@ Frame::Frame() : width_(0), height_(0), - format_(-1), + format_(olive::PIX_FMT_INVALID), + sample_count_(0), timestamp_(0), native_timestamp_(0) { @@ -59,6 +60,16 @@ void Frame::set_height(const int &height) height_ = height; } +const AudioRenderingParams &Frame::audio_params() +{ + return audio_params_; +} + +void Frame::set_audio_params(const AudioRenderingParams ¶ms) +{ + audio_params_ = params; +} + const rational &Frame::timestamp() { return timestamp_; @@ -79,16 +90,26 @@ void Frame::set_native_timestamp(const int64_t ×tamp) native_timestamp_ = timestamp; } -const int &Frame::format() +const olive::PixelFormat &Frame::format() { return format_; } -void Frame::set_format(const int &format) +void Frame::set_format(const olive::PixelFormat &format) { format_ = format; } +const int &Frame::sample_count() +{ + return sample_count_; +} + +void Frame::set_sample_count(const int &audio_sample_count) +{ + sample_count_ = audio_sample_count; +} + uint8_t *Frame::data() { return data_.data(); @@ -104,9 +125,9 @@ void Frame::allocate() // Assume this frame is intended to be a video frame if (width_ > 0 && height_ > 0) { data_.resize(PixelService::GetBufferSize(static_cast(format_), width_, height_)); + } else if (sample_count_ > 0) { + data_.resize(audio_params_.samples_to_bytes(sample_count_)); } - - // FIXME: Audio sample allocation } void Frame::destroy() diff --git a/app/decoder/frame.h b/app/decoder/frame.h index e56fb6be5..8561908ec 100644 --- a/app/decoder/frame.h +++ b/app/decoder/frame.h @@ -25,6 +25,7 @@ #include #include "common/rational.h" +#include "render/audio/audioparams.h" #include "render/pixelformat.h" class Frame; @@ -57,6 +58,12 @@ public: const int& height(); void set_height(const int& height); + const AudioRenderingParams& audio_params(); + void set_audio_params(const AudioRenderingParams& params); + + const int &sample_count(); + void set_sample_count(const int &sample_count); + /** * @brief Get frame's timestamp. * @@ -75,8 +82,8 @@ public: * * Currently this will either be an olive::PixelFormat (video) or an olive::SampleFormat (audio). */ - const int& format(); - void set_format(const int& format); + const olive::PixelFormat& format(); + void set_format(const olive::PixelFormat& format); /** * @brief Get the data buffer of this frame @@ -107,7 +114,11 @@ private: int height_; - int format_; + olive::PixelFormat format_; + + AudioRenderingParams audio_params_; + + int sample_count_; QVector data_; diff --git a/app/decoder/wave.cpp b/app/decoder/wave.cpp index 85027f465..3310e1a26 100644 --- a/app/decoder/wave.cpp +++ b/app/decoder/wave.cpp @@ -61,12 +61,12 @@ bool WaveOutput::open() write_int(&file_, params_.sample_rate()); // Bytes per second - write_int(&file_, (params_.sample_rate() * params_.bits_per_sample() * params_.channel_count())/8); + write_int(&file_, params_.samples_to_bytes(params_.sample_rate())); // Bytes per sample - write_int(&file_, static_cast((params_.bits_per_sample() * params_.channel_count())/8)); + write_int(&file_, static_cast(params_.samples_to_bytes(1))); - // Bits per sample + // Bits per sample per channel write_int(&file_, static_cast(params_.bits_per_sample())); // Data chunk header diff --git a/app/node/input/media/audio/audio.cpp b/app/node/input/media/audio/audio.cpp index f9e430bfb..ac7dd6da9 100644 --- a/app/node/input/media/audio/audio.cpp +++ b/app/node/input/media/audio/audio.cpp @@ -2,7 +2,9 @@ AudioInput::AudioInput() { - + samples_output_ = new NodeOutput("samples_out"); + samples_output_->set_data_type(NodeInput::kSamples); + AddParameter(samples_output_); } QString AudioInput::Name() @@ -24,3 +26,23 @@ QString AudioInput::Description() { return tr("Import an audio footage stream."); } + +QVariant AudioInput::Value(NodeOutput *output, const rational &in, const rational &out) +{ + if (output == samples_output_) { + // Make sure decoder is set up + if (!SetupDecoder()) { + return 0; + } + + // Retrieve audio samples from decoder + frame_ = decoder_->Retrieve(in, out - in); + + QByteArray samples; + samples.resize(frame_->audio_params().samples_to_bytes(frame_->sample_count())); + memcpy(samples.data(), frame_->data(), static_cast(samples.size())); + return samples; + } + + return 0; +} diff --git a/app/node/input/media/audio/audio.h b/app/node/input/media/audio/audio.h index 1870facdb..1faa55d9d 100644 --- a/app/node/input/media/audio/audio.h +++ b/app/node/input/media/audio/audio.h @@ -12,6 +12,12 @@ public: virtual QString id() override; virtual QString Category() override; virtual QString Description() override; + +protected: + virtual QVariant Value(NodeOutput* output, const rational& in, const rational& out) override; + +private: + NodeOutput* samples_output_; }; #endif // AUDIOINPUT_H diff --git a/app/node/input/media/media.cpp b/app/node/input/media/media.cpp index 9669a84df..e698c756c 100644 --- a/app/node/input/media/media.cpp +++ b/app/node/input/media/media.cpp @@ -35,7 +35,7 @@ void MediaInput::Release() decoder_ = nullptr; } -StreamPtr MediaInput::Footage() +StreamPtr MediaInput::footage() { return footage_input_->get_value(0).value(); } @@ -52,7 +52,7 @@ bool MediaInput::SetupDecoder() } // Get currently selected Footage - StreamPtr stream = Footage(); + StreamPtr stream = footage(); // If no footage is selected, return nothing if (stream == nullptr) { diff --git a/app/node/input/media/media.h b/app/node/input/media/media.h index b9791adec..baae7f05d 100644 --- a/app/node/input/media/media.h +++ b/app/node/input/media/media.h @@ -35,7 +35,7 @@ public: virtual void Release() override; - StreamPtr Footage(); + StreamPtr footage(); void SetFootage(StreamPtr f); protected: diff --git a/app/node/input/media/video/video.cpp b/app/node/input/media/video/video.cpp index 74740d8d9..b869883ba 100644 --- a/app/node/input/media/video/video.cpp +++ b/app/node/input/media/video/video.cpp @@ -96,10 +96,15 @@ QVariant VideoInput::Value(NodeOutput *output, const rational &in, const rationa { Q_UNUSED(out) - // FIXME: Hardcoded value - bool alpha_is_associated = false; - if (output == texture_output_) { + if (footage() == nullptr + || (footage()->type() != Stream::kVideo && footage()->type() != Stream::kImage)) { + return 0; + } + + // FIXME: Hardcoded value + bool alpha_is_associated = false; + // Find the current Renderer instance RenderInstance* renderer = VideoRendererProcessor::CurrentInstance(); @@ -124,7 +129,7 @@ QVariant VideoInput::Value(NodeOutput *output, const rational &in, const rationa } if (color_processor_ == nullptr) { - QString colorspace = std::static_pointer_cast(Footage())->colorspace(); + QString colorspace = std::static_pointer_cast(footage())->colorspace(); if (colorspace.isEmpty()) { // FIXME: Should use Footage() to find the Project* it belongs to instead of this colorspace = olive::core.GetActiveProject()->default_input_colorspace(); diff --git a/app/render/audio/audioparams.cpp b/app/render/audio/audioparams.cpp index e3a3d59ec..660d3a16c 100644 --- a/app/render/audio/audioparams.cpp +++ b/app/render/audio/audioparams.cpp @@ -52,7 +52,14 @@ int AudioRenderingParams::time_to_bytes(const rational &time) const { Q_ASSERT(is_valid()); - return qFloor(time.toDouble() * sample_rate()) * channel_count() * bytes_per_sample(); + return qFloor(time.toDouble() * sample_rate()) * channel_count() * bytes_per_sample_per_channel(); +} + +int AudioRenderingParams::samples_to_bytes(const int &samples) const +{ + Q_ASSERT(is_valid()); + + return samples * channel_count() * bytes_per_sample_per_channel(); } int AudioRenderingParams::channel_count() const @@ -60,7 +67,7 @@ int AudioRenderingParams::channel_count() const return av_get_channel_layout_nb_channels(channel_layout()); } -int AudioRenderingParams::bytes_per_sample() const +int AudioRenderingParams::bytes_per_sample_per_channel() const { switch (format_) { case olive::SAMPLE_FMT_U8: @@ -83,7 +90,7 @@ int AudioRenderingParams::bytes_per_sample() const int AudioRenderingParams::bits_per_sample() const { - return bytes_per_sample() * 8; + return bytes_per_sample_per_channel() * 8; } bool AudioRenderingParams::is_valid() const diff --git a/app/render/audio/audioparams.h b/app/render/audio/audioparams.h index 447fe2317..a2fc1bbda 100644 --- a/app/render/audio/audioparams.h +++ b/app/render/audio/audioparams.h @@ -29,8 +29,9 @@ public: AudioRenderingParams(const AudioParams& params, const olive::SampleFormat& format); int time_to_bytes(const rational& time) const; + int samples_to_bytes(const int& samples) const; int channel_count() const; - int bytes_per_sample() const; + int bytes_per_sample_per_channel() const; int bits_per_sample() const; bool is_valid() const;