OpenShot Library | libopenshot 1.1.1
AudioReaderSource.cpp
Go to the documentation of this file.
1
9// Copyright (c) 2008-2019 OpenShot Studios, LLC
10//
11// SPDX-License-Identifier: LGPL-3.0-or-later
12
13#include "AudioReaderSource.h"
14#include "Exceptions.h"
15#include "Frame.h"
16#include "CacheBase.h"
17#include "Settings.h"
18
19using namespace std;
20using namespace openshot;
21
22// Constructor that reads samples from a reader
23AudioReaderSource::AudioReaderSource(ReaderBase *audio_reader, int64_t starting_frame_number)
24 : reader(audio_reader), frame_position(starting_frame_number), videoCache(NULL), frame(NULL),
25 sample_position(0), speed(1), stream_position(0), requested_frame(starting_frame_number) {
26}
27
28// Destructor
30{
31}
32
33// Get the next block of audio samples
34void AudioReaderSource::getNextAudioBlock(const juce::AudioSourceChannelInfo& info)
35{
36 if (info.numSamples > 0) {
37 info.clearActiveBufferRegion();
38 const uint64_t generation = seek_generation.load();
39 if (generation & 1)
40 return;
41 const int64_t position = requested_frame.load();
42 if (seek_generation.load() != generation)
43 return;
44 if (applied_generation != generation) {
45 frame_position = position;
46 sample_position = 0;
47 applied_generation = generation;
48 }
49 const uint64_t speed_epoch = speed_generation.load();
50 // Commit the cursor only when this entire block is still current.
51 // A pause during decoding must not consume samples that were silenced.
52 int64_t next_frame = frame_position;
53 int64_t next_sample = sample_position;
54 std::shared_ptr<Frame> decoded_frame;
55 int remaining_samples = info.numSamples;
56 int remaining_position = info.startSample;
57
58 // Pause and fill buffer with silence (wait for pre-roll)
59 if (speed != 1 || (videoCache && !videoCache->isReady())) {
60 return;
61 }
62
63 while (remaining_samples > 0) {
64 const int previous_remaining = remaining_samples;
65 decoded_frame.reset();
66 try {
67 // Get current frame object
68 if (reader) {
69 // Shared pre-roll may fall back to a minimal buffer. A
70 // callback spanning more frames must never decode a slow
71 // missing Timeline frame. The next player hold seeks audio
72 // to its playhead before the shared gate opens again.
73 if (videoCache && videoCache->UsesCachedAudio()
75 decoded_frame = reader->GetCache()->GetFrame(next_frame);
76 if (!decoded_frame) videoCache->NotifyAudioCacheMiss();
77 } else {
78 decoded_frame = reader->GetFrame(next_frame);
79 }
80 }
81 }
82 catch (const ReaderClosed & e) { }
83 catch (const OutOfBoundsFrame & e) { }
84
85 // A control request never waits for GetFrame. Discard decoding that
86 // belongs to an older seek or playback state.
87 if (seek_generation.load() != generation || speed_generation.load() != speed_epoch || speed.load() != 1)
88 break;
89
90 // Get audio samples
91 if (reader && decoded_frame) {
92 const int frame_samples = decoded_frame->GetAudioSamplesCount();
93 const int frame_channels = decoded_frame->GetAudioChannelsCount();
94
95 // Corrupt/unsupported streams can yield frames without audio data.
96 // Avoid a tight loop that never consumes remaining_samples.
97 if (frame_samples <= 0 || frame_channels <= 0) {
98 info.buffer->clear(remaining_position, remaining_samples);
99 break;
100 }
101
102 if (next_sample + remaining_samples <= decoded_frame->GetAudioSamplesCount()) {
103 // Success, we have enough samples
104 for (int channel = 0; channel < frame_channels; channel++) {
105 if (channel < info.buffer->getNumChannels()) {
106 info.buffer->copyFrom(channel, remaining_position, *decoded_frame->GetAudioSampleBuffer(),
107 channel, next_sample, remaining_samples);
108 }
109 }
110 next_sample += remaining_samples;
111 remaining_position += remaining_samples;
112 remaining_samples = 0;
113
114 } else if (next_sample + remaining_samples > decoded_frame->GetAudioSamplesCount()) {
115 // Not enough samples, take what we can
116 int amount_to_copy = decoded_frame->GetAudioSamplesCount() - next_sample;
117 if (amount_to_copy <= 0) {
118 info.buffer->clear(remaining_position, remaining_samples);
119 break;
120 }
121
122 for (int channel = 0; channel < frame_channels; channel++) {
123 if (channel < info.buffer->getNumChannels()) {
124 info.buffer->copyFrom(channel, remaining_position, *decoded_frame->GetAudioSampleBuffer(), channel,
125 next_sample, amount_to_copy);
126 }
127 }
128 next_sample += amount_to_copy;
129 remaining_position += amount_to_copy;
130 remaining_samples -= amount_to_copy;
131 }
132
133 // Increment frame position (if samples are all used up)
134 if (next_sample == decoded_frame->GetAudioSamplesCount()) {
135 ++next_frame;
136 next_sample = 0; // reset for new frame
137 }
138 } else {
139 info.buffer->clear(remaining_position, remaining_samples);
140 break;
141 }
142
143 if (remaining_samples == previous_remaining) {
144 info.buffer->clear(remaining_position, remaining_samples);
145 break;
146 }
147 }
148 if (seek_generation.load() != generation || speed_generation.load() != speed_epoch || speed.load() != 1) {
149 info.clearActiveBufferRegion();
150 return;
151 }
152 frame_position = next_frame;
153 sample_position = next_sample;
154 std::atomic_store(&frame, decoded_frame);
155 published_generation.store(generation);
156 }
157}
158
159void AudioReaderSource::Seek(int64_t new_position)
160{
161 // Only control writers serialize. Cursor state belongs exclusively to the
162 // callback; no decoding, transport or device lock is taken here.
163 std::lock_guard<std::mutex> lock(seek_mutex);
164 ++seek_generation;
165 requested_frame.store(new_position);
166 ++seek_generation;
167}
168
169std::shared_ptr<Frame> AudioReaderSource::getFrame() const
170{
171 const auto generation = seek_generation.load();
172 auto result = std::atomic_load(&frame);
173 if ((generation & 1) || published_generation.load() != generation ||
174 seek_generation.load() != generation)
175 return {};
176 return result;
177}
178
179// Prepare to play this audio source
181
182// Release all resources
184
185// Get the total length (in samples) of this audio source
187{
188 // Get the length
189 if (reader)
190 return reader->info.sample_rate * reader->info.duration;
191 else
192 return 0;
193}
Header file for AudioReaderSource class.
Header file for CacheBase class.
#define int64
Definition: Clip.h:17
Header file for all Exception classes.
Header file for Frame class.
Header file for global Settings class.
std::shared_ptr< Frame > getFrame() const
Return the current frame object.
void releaseResources()
Release all resources.
juce::int64 getTotalLength() const
Get the total length (in samples) of this audio source.
void prepareToPlay(int, double)
Prepare to play this audio source.
void Seek(int64_t new_position)
Seek to a specific frame.
void getNextAudioBlock(const juce::AudioSourceChannelInfo &info)
Get the next block of audio samples.
virtual std::shared_ptr< openshot::Frame > GetFrame(int64_t frame_number)=0
Get a frame from the cache.
Exception for frames that are out of bounds.
Definition: Exceptions.h:307
This abstract class is the base class, used by all readers in libopenshot.
Definition: ReaderBase.h:76
openshot::ReaderInfo info
Information about the current media file.
Definition: ReaderBase.h:91
virtual std::shared_ptr< openshot::Frame > GetFrame(int64_t number)=0
virtual openshot::CacheBase * GetCache()=0
Get the cache object used by this reader (note: not all readers use cache)
Exception when a reader is closed, and a frame is requested.
Definition: Exceptions.h:370
static Settings * Instance()
Create or get an instance of this logger singleton (invoke the class with this method)
Definition: Settings.cpp:43
bool ENABLE_PLAYBACK_CACHING
Enable/Disable the cache thread to pre-fetch and cache video frames before we need them.
Definition: Settings.h:110
bool isReady()
Shared startup gate; bounded fallback resumes established video decoding.
bool UsesCachedAudio() const
Callback miss holds the shared gate until the player resynchronizes audio.
This namespace is the default namespace for all code in the openshot library.
Definition: AnimatedCurve.h:24
float duration
Length of time (in seconds)
Definition: ReaderBase.h:43
int sample_rate
The number of audio samples per second (44100 is a common sample rate)
Definition: ReaderBase.h:60