Blender V5.0
sequencer_preview.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
10#include "DNA_sound_types.h"
11
12#include "BLI_listbase.h"
13#include "BLI_task.h"
14#include "BLI_threads.h"
15
16#include "BKE_context.hh"
17#include "BKE_global.hh"
18#include "BKE_sound.h"
19
20#include "WM_api.hh"
21#include "WM_types.hh"
22
23#include "ED_screen.hh"
24
25#include "MEM_guardedalloc.h"
26
27#include "sequencer_intern.hh"
28
29namespace blender::ed::vse {
30
40
45 int lr; /* Sample left or right. */
47 bool waveform; /* Reload sound or waveform. */
48};
49
55
56static void free_preview_job(void *data)
57{
58 PreviewJob *pj = static_cast<PreviewJob *>(data);
59
62 MEM_freeN(pj);
63}
64
66{
67 SpinLock *spinlock = static_cast<SpinLock *>(sound->spinlock);
68 BLI_spin_lock(spinlock);
70 BLI_spin_unlock(spinlock);
71}
72
74{
76
77 ReadSoundWaveformTask *task = static_cast<ReadSoundWaveformTask *>(data);
78
79 /* The job audio has already been removed from the list, now we just need to free it. */
81
83 task->wm_job->processed++;
85
87
88 MEM_freeN(task);
89}
90
91static void execute_read_sound_waveform_task(TaskPool *__restrict task_pool, void *task_data)
92{
93 ReadSoundWaveformTask *task = static_cast<ReadSoundWaveformTask *>(task_data);
94
97 return;
98 }
99
100 PreviewJobAudio *audio_job = task->preview_job_audio;
101 BKE_sound_read_waveform(audio_job->bmain, audio_job->sound, task->stop);
102}
103
104/* Only this runs inside thread. */
105static void preview_startjob(void *data, wmJobWorkerStatus *worker_status)
106{
108 PreviewJob *pj = static_cast<PreviewJob *>(data);
109
110 while (true) {
111 /* Wait until there's either a new audio job to process or one of the previously submitted jobs
112 * is done. */
114
115 while (BLI_listbase_is_empty(&pj->previews) && pj->processed != pj->total) {
116
117 float current_progress = (pj->total > 0) ? float(pj->processed) / float(pj->total) : 1.0f;
118
119 if (current_progress != worker_status->progress) {
120 worker_status->progress = current_progress;
121 worker_status->do_update = true;
122 }
123
125 }
126
127 if (pj->processed == pj->total) {
128 pj->running = false;
130 break;
131 }
132
133 if (worker_status->stop || G.is_break) {
135
136 LISTBASE_FOREACH (PreviewJobAudio *, previewjb, &pj->previews) {
137 clear_sound_waveform_loading_tag(previewjb->sound);
138 }
139
141 pj->processed = 0;
142 pj->total = 0;
143 pj->running = false;
144
146 break;
147 }
148
151 ReadSoundWaveformTask *task = MEM_callocN<ReadSoundWaveformTask>("read sound waveform task");
152 task->wm_job = pj;
153 task->preview_job_audio = previewjb;
154 task->stop = &worker_status->stop;
155 new_tasks.append(task);
156
157 BLI_remlink(&pj->previews, previewjb);
158 }
159
161
162 for (ReadSoundWaveformTask *task : new_tasks) {
165 }
166 }
167
170}
171
172static void preview_endjob(void *data)
173{
174 PreviewJob *pj = static_cast<PreviewJob *>(data);
175
177}
178
179void sequencer_preview_add_sound(const bContext *C, const Strip *strip)
180{
181 wmJob *wm_job;
182 PreviewJob *pj;
183 ScrArea *area = CTX_wm_area(C);
184
185 wm_job = WM_jobs_get(CTX_wm_manager(C),
188 "Generating strip previews...",
191
192 /* Get the preview job if it exists. */
193 pj = static_cast<PreviewJob *>(WM_jobs_customdata_get(wm_job));
194
195 if (pj) {
197
198 /* If the job exists but is not running, bail and try again on the next draw call. */
199 if (!pj->running) {
201
202 /* Clear the sound loading tag to that it can be reattempted. */
205 return;
206 }
207 }
208 else { /* There's no existing preview job. */
209 pj = MEM_callocN<PreviewJob>("preview rebuild job");
210
211 pj->mutex = BLI_mutex_alloc();
214 pj->running = true;
216
219 WM_jobs_callbacks(wm_job, preview_startjob, nullptr, nullptr, preview_endjob);
220 }
221
222 PreviewJobAudio *audiojob = MEM_callocN<PreviewJobAudio>("preview_audio");
223 audiojob->bmain = CTX_data_main(C);
224 audiojob->sound = strip->sound;
225
226 BLI_addtail(&pj->previews, audiojob);
227 pj->total++;
229
231
232 if (!WM_jobs_is_running(wm_job)) {
233 G.is_break = false;
235 }
236
237 ED_area_tag_redraw(area);
238}
239
240} // namespace blender::ed::vse
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Main * CTX_data_main(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
Scene * CTX_data_sequencer_scene(const bContext *C)
void BKE_sound_read_waveform(struct Main *bmain, struct bSound *sound, bool *stop)
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
@ TASK_PRIORITY_LOW
Definition BLI_task.h:52
bool BLI_task_pool_current_canceled(TaskPool *pool)
Definition task_pool.cc:545
void BLI_task_pool_work_and_wait(TaskPool *pool)
Definition task_pool.cc:535
void BLI_task_pool_cancel(TaskPool *pool)
Definition task_pool.cc:540
TaskPool * BLI_task_pool_create(void *userdata, eTaskPriority priority)
Definition task_pool.cc:484
void BLI_task_pool_free(TaskPool *pool)
Definition task_pool.cc:521
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
Definition task_pool.cc:526
pthread_spinlock_t SpinLock
void BLI_mutex_free(ThreadMutex *mutex)
Definition threads.cc:372
ThreadMutex * BLI_mutex_alloc(void)
Definition threads.cc:365
void BLI_condition_wait(ThreadCondition *cond, ThreadMutex *mutex)
Definition threads.cc:580
pthread_cond_t ThreadCondition
void BLI_condition_notify_one(ThreadCondition *cond)
Definition threads.cc:590
void BLI_condition_init(ThreadCondition *cond)
Definition threads.cc:575
void BLI_mutex_lock(ThreadMutex *mutex)
Definition threads.cc:345
void BLI_mutex_unlock(ThreadMutex *mutex)
Definition threads.cc:350
void BLI_spin_unlock(SpinLock *spin)
Definition threads.cc:430
void BLI_spin_lock(SpinLock *spin)
Definition threads.cc:405
pthread_mutex_t ThreadMutex
Definition BLI_threads.h:79
#define UNUSED_VARS(...)
@ SOUND_TAGS_WAVEFORM_LOADING
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:693
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
@ WM_JOB_TYPE_SEQ_BUILD_PREVIEW
Definition WM_api.hh:1793
@ WM_JOB_PROGRESS
Definition WM_api.hh:1766
#define ND_SEQUENCER
Definition WM_types.hh:437
#define ND_SPACE_SEQUENCER
Definition WM_types.hh:535
#define NC_SCENE
Definition WM_types.hh:378
BMesh const char void * data
void append(const T &value)
nullptr float
TaskPool * task_pool
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define G(x, y, z)
void sequencer_preview_add_sound(const bContext *C, const Strip *strip)
static void clear_sound_waveform_loading_tag(bSound *sound)
static void preview_startjob(void *data, wmJobWorkerStatus *worker_status)
static void free_preview_job(void *data)
static void preview_endjob(void *data)
static void free_read_sound_waveform_task(TaskPool *__restrict task_pool, void *data)
static void execute_read_sound_waveform_task(TaskPool *__restrict task_pool, void *task_data)
struct bSound * sound
void * spinlock
void WM_main_add_notifier(uint type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
bool WM_jobs_is_running(const wmJob *wm_job)
Definition wm_jobs.cc:341
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
Definition wm_jobs.cc:376
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:479
void * WM_jobs_customdata_get(wmJob *wm_job)
Definition wm_jobs.cc:352
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, const eWM_JobFlag flag, const eWM_JobType job_type)
Definition wm_jobs.cc:211
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
Definition wm_jobs.cc:388
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:360