GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 34.5% 135 / 0 / 391
Functions: 66.7% 16 / 0 / 24
Branches: 22.5% 103 / 0 / 457

core/cache.cpp
Line Branch Exec Source
1 // Avisynth v2.6. Copyright 2002-2009 Ben Rudiak-Gould et al.
2 // http://avisynth.nl
3
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
17 // http://www.gnu.org/copyleft/gpl.html .
18 //
19 // Linking Avisynth statically or dynamically with other modules is making a
20 // combined work based on Avisynth. Thus, the terms and conditions of the GNU
21 // General Public License cover the whole combination.
22 //
23 // As a special exception, the copyright holders of Avisynth give you
24 // permission to link Avisynth with independent modules that communicate with
25 // Avisynth solely through the interfaces defined in avisynth.h, regardless of the license
26 // terms of these independent modules, and to copy and distribute the
27 // resulting combined work under terms of your choice, provided that
28 // every copy of the combined work is accompanied by a complete copy of
29 // the source code of Avisynth (the version of Avisynth used to produce the
30 // combined work), being distributed under the terms of the GNU General
31 // Public License plus this exception. An independent module is a module
32 // which is not derived from or based on Avisynth, such as 3rd-party filters,
33 // import and export plugins, or graphical user interfaces.
34
35 #include "cache.h"
36 #include "internal.h"
37 #include "LruCache.h"
38 #include "InternalEnvironment.h"
39 #include "DeviceManager.h"
40 #include <cassert>
41 #include <chrono>
42 #include <cstdio>
43
44 #ifdef X86_32
45 #include <mmintrin.h>
46 #endif
47
48 #include <avs/config.h>
49 #ifdef AVS_WINDOWS
50 #include <avs/win.h>
51 #else
52 #include <avs/posix.h>
53 #endif
54
55
56 extern const AVSFunction Cache_filters[] = {
57 { "Cache", BUILTIN_FUNC_PREFIX, "c[name]s", CacheGuard::Create },
58 { "InternalCache", BUILTIN_FUNC_PREFIX, "c[name]s", CacheGuard::Create },
59 { 0 }
60 };
61
62 class CacheStack
63 {
64 InternalEnvironment* env;
65 bool retSupressCaching;
66 public:
67 5 CacheStack(InternalEnvironment* env)
68 5 : env(env)
69 5 , retSupressCaching(env->GetSupressCaching())
70 5 { }
71 5 ~CacheStack() {
72 5 env->GetSupressCaching() = retSupressCaching;
73 5 }
74 };
75
76 struct CachePimpl
77 {
78 PClip child;
79 VideoInfo vi;
80
81 // Video cache
82 std::shared_ptr<LruCache<size_t, PVideoFrame> > VideoCache;
83
84 // Audio cache
85 CachePolicyHint AudioPolicy;
86 char* AudioCache;
87 int SampleSize;
88 int64_t MaxSampleCount;
89 int64_t AudioCacheStart;
90 int64_t CacheCount;
91 int64_t ac_expected_next;
92 int ac_too_small_count;
93 long ac_currentscore;
94
95 5 CachePimpl(const PClip& _child, CacheMode mode) :
96 5 child(_child),
97
1/2
✓ Branch 4 → 5 taken 5 times.
✗ Branch 4 → 15 not taken.
5 vi(_child->GetVideoInfo()),
98
1/2
✓ Branch 5 → 6 taken 5 times.
✗ Branch 5 → 12 not taken.
5 VideoCache(std::make_shared<LruCache<size_t, PVideoFrame> >(0, mode)),
99
2/4
✓ Branch 6 → 7 taken 5 times.
✗ Branch 6 → 13 not taken.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 5 times.
5 AudioPolicy(vi.HasAudio() ? CACHE_AUDIO_AUTO_START_OFF : CACHE_AUDIO_NOTHING), // Don't cache audio per default, auto mode.
100 5 AudioCache(NULL),
101 5 SampleSize(0),
102 5 MaxSampleCount(0),
103 5 AudioCacheStart(0),
104 5 CacheCount(0),
105 5 ac_expected_next(0),
106 5 ac_too_small_count(0),
107 5 ac_currentscore(20)
108 {
109
1/2
✓ Branch 10 → 11 taken 5 times.
✗ Branch 10 → 13 not taken.
5 SampleSize = vi.BytesPerAudioSample();
110 5 }
111 5 ~CachePimpl()
112 {
113
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 5 times.
5 if (AudioCache)
114 free(AudioCache);
115 5 AudioCache = NULL;
116 5 }
117 };
118
119
120 5 AvsCache::AvsCache(const PClip& _child, Device* device, std::mutex& CacheGuardMutex, InternalEnvironment* env) :
121 5 Env(env),
122 5 _pimpl(NULL),
123 5 device(device),
124 5 CacheGuardMutex(CacheGuardMutex)
125 {
126
4/10
✓ Branch 3 → 4 taken 5 times.
✗ Branch 3 → 33 not taken.
✓ Branch 4 → 5 taken 5 times.
✗ Branch 4 → 30 not taken.
✓ Branch 5 → 6 taken 5 times.
✗ Branch 5 → 30 not taken.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 5 times.
✗ Branch 30 → 31 not taken.
✗ Branch 30 → 32 not taken.
5 _pimpl = new CachePimpl(_child, env->GetCacheMode());
127
1/2
✓ Branch 8 → 9 taken 5 times.
✗ Branch 8 → 33 not taken.
5 env->ManageCache(MC_RegisterCache, reinterpret_cast<void*>(this));
128 _RPT5(0, "AvsCache::AvsCache registered. cache_id=%p child=%p w=%d h=%d VideoCacheSize=%Iu\n", (void*)this, (void*)_child, _pimpl->vi.width, _pimpl->vi.height, _pimpl->VideoCache->size());
129
130 5 const int dummy = 0;
131 // child is usually MTGuard, which forwards this request to its child filter - the real one
132
1/2
✓ Branch 10 → 11 taken 5 times.
✗ Branch 10 → 33 not taken.
5 const bool overAvs25 = (_child->GetVersion() >= 5);
133
2/4
✓ Branch 11 → 12 taken 5 times.
✗ Branch 11 → 15 not taken.
✓ Branch 13 → 14 taken 5 times.
✗ Branch 13 → 33 not taken.
5 CachePolicyHint childAudioPolicy = (CachePolicyHint)(overAvs25 ? _child->SetCacheHints(CACHE_GETCHILD_AUDIO_MODE, dummy) : 0);
134 // if not set by the plugin, get default (set in CachePimpl ctor)
135
1/2
✓ Branch 16 → 17 taken 5 times.
✗ Branch 16 → 19 not taken.
5 if (childAudioPolicy == 0)
136
1/2
✓ Branch 17 → 18 taken 5 times.
✗ Branch 17 → 33 not taken.
5 childAudioPolicy = (CachePolicyHint)this->SetCacheHints(CACHE_GET_AUDIO_POLICY, dummy);
137
1/3
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 5 times.
✗ Branch 19 → 28 not taken.
5 switch (childAudioPolicy) {
138 case CachePolicyHint(0): break; // n/a
139 5 case CACHE_AUDIO: // Explicitly do cache audio, X byte cache.
140 case CACHE_AUDIO_NOTHING: // Explicitly do not cache audio.
141 case CACHE_AUDIO_AUTO_START_OFF: // Audio cache off (auto mode), X byte initial cache.
142 case CACHE_AUDIO_AUTO_START_ON: // Audio cache on (auto mode), X byte initial cache.
143 // ask child for desired audio cache size
144 // e.g. EnsureVBRMP3Sync explicitely requests CACHE_AUDIO and 1024*1024
145 // This will create cache only if clip has audio
146
3/6
✓ Branch 21 → 22 taken 5 times.
✗ Branch 21 → 25 not taken.
✓ Branch 23 → 24 taken 5 times.
✗ Branch 23 → 33 not taken.
✓ Branch 26 → 27 taken 5 times.
✗ Branch 26 → 33 not taken.
5 this->SetCacheHints(childAudioPolicy, overAvs25 ? _child->SetCacheHints(CACHE_GETCHILD_AUDIO_SIZE, dummy) : 0); // if size=0 remains the default
147 5 break;
148 default:
149 env->ThrowError("Cache: Filter returned invalid response to CACHE_GETCHILD_AUDIO_MODE. %d", childAudioPolicy);
150 }
151 5 }
152
153 10 AvsCache::~AvsCache()
154 {
155 _RPT5(0, "AvsCache::AvsCache unregister. cache_id=%p child=%p w=%d h=%d VideoCacheSize=%Iu\n", (void *)this, (void *)_pimpl->child, _pimpl->vi.width, _pimpl->vi.height, _pimpl->VideoCache->size()); // P.F.
156 5 Env->ManageCache(MC_UnRegisterCache, reinterpret_cast<void*>(this));
157
1/2
✓ Branch 3 → 4 taken 5 times.
✗ Branch 3 → 6 not taken.
5 delete _pimpl;
158 10 }
159
160 5 PVideoFrame __stdcall AvsCache::GetFrame(int n, IScriptEnvironment* env_)
161 {
162 #ifdef _DEBUG
163 constexpr auto BUFSIZE = 255;
164 std::unique_ptr<char[]> buf(new char[BUFSIZE+1]);
165
166 #endif
167
1/2
✓ Branch 2 → 3 taken 5 times.
✗ Branch 2 → 72 not taken.
5 InternalEnvironment* env = GetAndRevealCamouflagedEnv(env_);
168
169 // Protect plugins that cannot handle out-of-bounds frame indices
170
1/2
✓ Branch 3 → 4 taken 5 times.
✗ Branch 3 → 72 not taken.
5 n = clamp(n, 0, GetVideoInfo().num_frames-1);
171
172
3/6
✓ Branch 6 → 7 taken 5 times.
✗ Branch 6 → 72 not taken.
✓ Branch 8 → 9 taken 5 times.
✗ Branch 8 → 72 not taken.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 5 times.
5 if (_pimpl->VideoCache->requested_capacity() > _pimpl->VideoCache->capacity())
173 env->ManageCache(MC_NodAndExpandCache, reinterpret_cast<void*>(this));
174 else
175
1/2
✓ Branch 11 → 12 taken 5 times.
✗ Branch 11 → 72 not taken.
5 env->ManageCache(MC_NodCache, reinterpret_cast<void*>(this));
176
177
1/2
✓ Branch 12 → 13 taken 5 times.
✗ Branch 12 → 72 not taken.
5 PVideoFrame result;
178 5 LruCache<size_t, PVideoFrame>::handle cache_handle;
179
180
1/2
✓ Branch 13 → 14 taken 5 times.
✗ Branch 13 → 68 not taken.
5 CacheStack cache_stack(env);
181
182 #ifdef _DEBUG
183 std::chrono::time_point<std::chrono::high_resolution_clock> t_start, t_end;
184 t_start = std::chrono::high_resolution_clock::now(); // t_start starts in the constructor. Used in logging
185
186 LruLookupResult LruLookupRes = _pimpl->VideoCache->lookup(n, &cache_handle, true, result, &env->GetSupressCaching());
187 /*
188 std::string name = FuncName;
189 snprintf(buf.get(), BUFSIZE, "AvsCache::GetFrame lookup follows: [%s] n=%6d Thread=%zu", name.c_str(), n, env->GetEnvProperty(AEP_THREAD_ID));
190 _RPT0(0, buf.get());
191
192 snprintf(buf.get(), BUFSIZE, "AvsCache::GetFrame lookup ready: [%s] n=%6d Thread=%zu res=%d", name.c_str(), n, env->GetEnvProperty(AEP_THREAD_ID), (int)LruLookupRes);
193 _RPT0(0, buf.get());
194 */
195
196 #ifdef _DEBUG
197 std::string name = FuncName;
198 #endif
199
200 switch (LruLookupRes)
201 #else
202 // fill result in lookup before releasing cache handle lock
203
3/8
✓ Branch 15 → 16 taken 5 times.
✗ Branch 15 → 66 not taken.
✓ Branch 16 → 17 taken 5 times.
✗ Branch 16 → 49 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 38 not taken.
✓ Branch 17 → 39 taken 5 times.
✗ Branch 17 → 44 not taken.
5 switch(_pimpl->VideoCache->lookup(n, &cache_handle, true, result, &env->GetSupressCaching()))
204 #endif
205 {
206 case LRU_LOOKUP_NOT_FOUND:
207 {
208 try
209 {
210 #ifdef _DEBUG
211 snprintf(buf.get(), BUFSIZE, "AvsCache::GetFrame LRU_LOOKUP_NOT_FOUND Start: [%s] n=%6d child=%p\n", name.c_str(), n, (void*)_pimpl->child); // P.F.
212 _RPT0(0, buf.get());
213 #endif
214 //cache_handle.first->value = _pimpl->child->GetFrame(n, env);
215 result = _pimpl->child->GetFrame(n, env); // P.F. fill result immediately
216
217 // check device
218 if (result->GetFrameBuffer()->device != device) {
219 const char* error_msg = env->Sprintf("Frame device mismatch: Assumed: %s Actual: %s",
220 device->GetName(), result->GetFrameBuffer()->device->GetName());
221 result = env->NewVideoFrame(_pimpl->vi);
222 env->ApplyMessage(&result, _pimpl->vi, error_msg, _pimpl->vi.width / 5, 0xa0a0a0, 0, 0);
223 }
224
225 cache_handle.first->value = result; // not after commit!
226 #ifdef X86_32
227 _mm_empty();
228 #endif
229 _pimpl->VideoCache->commit_value(&cache_handle);
230 }
231 catch (...)
232 {
233 _pimpl->VideoCache->rollback(&cache_handle);
234 throw;
235 }
236 #ifdef _DEBUG
237 t_end = std::chrono::high_resolution_clock::now();
238 std::chrono::duration<double> elapsed_seconds = t_end - t_start;
239 std::string name = FuncName;
240 if (NULL == cache_handle.first->value) {
241 snprintf(buf.get(), BUFSIZE, "AvsCache::GetFrame LRU_LOOKUP_NOT_FOUND End: HEY! got nulled! [%s] n=%6d child=%p frame=%p framebefore=%p SeekTimeWithGetFrame:%f\n", name.c_str(), n, (void *)_pimpl->child, (void *)cache_handle.first->value, (void *)result, elapsed_seconds.count()); // P.F.
242 _RPT0(0, buf.get());
243 } else {
244 snprintf(buf.get(), BUFSIZE, "AvsCache::GetFrame LRU_LOOKUP_NOT_FOUND End: [%s] n=%6d child=%p frame=%p framebefore=%p videoCacheSize=%zu SeekTimeWithGetFrame:%f\n", name.c_str(), n, (void *)_pimpl->child, (void *)cache_handle.first->value, (void *)result, _pimpl->VideoCache->size(), elapsed_seconds.count()); // P.F.
245 _RPT0(0, buf.get());
246 }
247 #endif
248 // result = cache_handle.first->value; not here!
249 // its content may change after commit when the last lock is released
250 // (cache is being restructured by other threads, new frames, etc...)
251 break;
252 }
253 case LRU_LOOKUP_FOUND_AND_READY:
254 {
255 // theoretically cache_handle here may point to wrong entry,
256 // because the lock in lookup is released before this readout
257 // solution:
258 // when LRU_LOOKUP_FOUND_AND_READY, the cache_handle.first->value is copied and returned in result itself
259 // result = cache_handle.first->value; // old method not needed, result is filled already by lookup
260 #ifdef _DEBUG
261 t_end = std::chrono::high_resolution_clock::now();
262 std::chrono::duration<double> elapsed_seconds = t_end - t_start;
263 std::string name = FuncName;
264 snprintf(buf.get(), BUFSIZE, "AvsCache::GetFrame LRU_LOOKUP_FOUND_AND_READY: [%s] n=%6d child=%p frame=%p vfb=%p videoCacheSize=%zu SeekTime :%f\n", name.c_str(), n, (void *)_pimpl->child, (void *)result, (void *)result->GetFrameBuffer(), _pimpl->VideoCache->size(), elapsed_seconds.count());
265 _RPT0(0, buf.get());
266 assert(result != NULL);
267 #endif
268 break;
269 }
270 5 case LRU_LOOKUP_NO_CACHE:
271 {
272 #ifdef _DEBUG
273 snprintf(buf.get(), BUFSIZE, "AvsCache::GetFrame <Before GetFrame> LRU_LOOKUP_NO_CACHE: [%s] n=%6d child=%p\n", name.c_str(), n, (void*)_pimpl->child); // P.F.
274 _RPT0(0, buf.get());
275 #endif
276
3/4
✓ Branch 40 → 41 taken 4 times.
✓ Branch 40 → 65 taken 1 time.
✓ Branch 41 → 42 taken 4 times.
✗ Branch 41 → 63 not taken.
5 result = _pimpl->child->GetFrame(n, env);
277 #ifdef _DEBUG
278 t_end = std::chrono::high_resolution_clock::now();
279 std::chrono::duration<double> elapsed_seconds = t_end - t_start;
280 snprintf(buf.get(), BUFSIZE, "AvsCache::GetFrame <After GetFrame> LRU_LOOKUP_NO_CACHE: [%s] n=%6d child=%p frame=%p vfb=%p videoCacheSize=%zu SeekTime :%f\n", name.c_str(), n, (void *)_pimpl->child, (void *)result, (void *)result->GetFrameBuffer(), _pimpl->VideoCache->size(), elapsed_seconds.count()); // P.F.
281 _RPT0(0, buf.get());
282 #endif
283 4 break;
284 }
285 case LRU_LOOKUP_FOUND_BUT_NOTAVAIL: // Fall-through intentional
286 default:
287 {
288 assert(0);
289 break;
290 }
291 }
292
293 4 return result;
294 7 }
295
296 void AvsCache::FillAudioZeros(void* buf, size_t start_offset, size_t count) {
297 const int bps = _pimpl->vi.BytesPerAudioSample();
298 unsigned char* byte_buf = (unsigned char*)buf;
299 memset(byte_buf + start_offset * bps, 0, count * bps);
300 }
301
302 void __stdcall AvsCache::GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env)
303 {
304 if (count <= 0)
305 return;
306 if (count > 0 && static_cast<uint64_t>(count) > std::numeric_limits<size_t>::max())
307 env->ThrowError("GetAudio error: Count exceeds platform maximum buffer size limit.");
308
309 // -----------------------------------------------------------
310 // Enforce audio bounds
311 // -----------------------------------------------------------
312
313 VideoInfo * vi = &(_pimpl->vi);
314
315 if ((!vi->HasAudio()) || (start + count <= 0) || (start >= vi->num_audio_samples)) {
316 // Completely skip.
317 FillAudioZeros(buf, 0, (size_t)count);
318 count = 0;
319 return;
320 }
321
322 if (start < 0) { // Partial initial skip
323 FillAudioZeros(buf, 0, static_cast<size_t>(-start)); // Fill all samples before 0 with silence.
324 count += start; // Subtract start bytes from count.
325 buf = ((BYTE*)buf) - start * vi->BytesPerAudioSample();
326 start = 0;
327 }
328
329 if (start + count > vi->num_audio_samples) { // Partial ending skip
330 FillAudioZeros(buf, (size_t)(vi->num_audio_samples - start), (size_t)(count - (vi->num_audio_samples - start))); // Fill end samples
331 count = (vi->num_audio_samples - start);
332 }
333
334 // -----------------------------------------------------------
335 // Caching
336 // -----------------------------------------------------------
337
338 long _cs = _pimpl->ac_currentscore;
339 if (start < _pimpl->ac_expected_next)
340 _cs = InterlockedExchangeAdd(&_pimpl->ac_currentscore, -5) - 5; // revisiting old ground - a cache could help
341 else if (start > _pimpl->ac_expected_next)
342 _cs = InterlockedDecrement(&_pimpl->ac_currentscore); // skipping chunks - a cache might not help
343 else // (start == ac_expected_next)
344 _cs = InterlockedIncrement(&_pimpl->ac_currentscore); // strict linear reading - why bother with a cache
345
346 if (_cs < -2000000)
347 _pimpl->ac_currentscore = -2000000;
348 else if (_cs > 90)
349 _pimpl->ac_currentscore = 90;
350
351 // Change from AUTO_OFF to AUTO_ON
352 if (_pimpl->AudioPolicy == CACHE_AUDIO_AUTO_START_OFF && _pimpl->ac_currentscore <= 0) {
353 // align size to 8192 byte boundary
354 int64_t new_size = (_pimpl->vi.BytesFromAudioSamples(count) + 8191) & -8192;
355 new_size = min((int64_t)4096 * 1024, new_size);
356 _RPT2(0, "CA:%x: Automatically adding %d byte audiocache!\n", this, (int)new_size);
357 SetCacheHints(CACHE_AUDIO_AUTO_START_ON, (int)new_size);
358 }
359
360 // Change from AUTO_ON to AUTO_OFF
361 if (_pimpl->AudioPolicy == CACHE_AUDIO_AUTO_START_ON && (_pimpl->ac_currentscore > 80)) {
362 _RPT1(0, "CA:%x: Automatically deleting cache!\n", this);
363 SetCacheHints(CACHE_AUDIO_AUTO_START_OFF, 0);
364 }
365
366 _pimpl->ac_expected_next = start + count;
367
368 if (_pimpl->AudioPolicy == CACHE_AUDIO_AUTO_START_OFF || _pimpl->AudioPolicy == CACHE_AUDIO_NOTHING) {
369 _pimpl->child->GetAudio(buf, start, count, env);
370 return; // We are ok to return now!
371 }
372
373 std::unique_lock<std::mutex> global_lock(CacheGuardMutex);
374
375 while (count > _pimpl->MaxSampleCount) { //is cache big enough?
376 _RPT1(0, "CA:%x:Cache too small->caching last audio\n", this);
377 _pimpl->ac_too_small_count++;
378
379 // But the current cache might have 99% of what was requested??
380
381 if (_pimpl->ac_too_small_count > 2 && _pimpl->MaxSampleCount < _pimpl->vi.AudioSamplesFromBytes(8192 * 1024)) { // Max size = 8MB!
382 //automatically upsize cache!
383 int64_t new_size = (_pimpl->vi.BytesFromAudioSamples(std::max(count, _pimpl->AudioCacheStart + _pimpl->CacheCount - start)) + 8192) & -8192; // Yes +1 to +8192 bytes
384 new_size = std::min((int64_t)8192 * 1024, new_size);
385 _RPT2(0, "CA:%x: Autoupsizing buffer to %d bytes!\n", this, (int)new_size);
386 SetCacheHints(_pimpl->AudioPolicy, (int)new_size); // updates maxsamplecount!!
387 _pimpl->ac_too_small_count = 0;
388 }
389 else {
390 global_lock.unlock();
391 _pimpl->child->GetAudio(buf, start, count, env);
392 global_lock.lock();
393
394 _pimpl->CacheCount = std::min(count, _pimpl->MaxSampleCount); // Remember maxsamplecount gets updated
395 _pimpl->AudioCacheStart = start + count - _pimpl->CacheCount;
396 BYTE* buff = (BYTE*)buf;
397 buff += _pimpl->vi.BytesFromAudioSamples(_pimpl->AudioCacheStart - start);
398 memcpy(_pimpl->AudioCache, buff, (size_t)_pimpl->vi.BytesFromAudioSamples(_pimpl->CacheCount));
399
400 global_lock.unlock();
401
402 return;
403 }
404 }
405
406 if ((start < _pimpl->AudioCacheStart) || (start > _pimpl->AudioCacheStart + _pimpl->MaxSampleCount)) { //first sample is before cache or beyond linear reach -> restart cache
407 _RPT1(0, "CA:%x: Restart\n", this);
408
409 _pimpl->CacheCount = std::min(count, _pimpl->MaxSampleCount);
410 _pimpl->AudioCacheStart = start;
411 _pimpl->child->GetAudio(_pimpl->AudioCache, _pimpl->AudioCacheStart, _pimpl->CacheCount, env);
412 }
413 else {
414 if (start + count > _pimpl->AudioCacheStart + _pimpl->CacheCount) { // Does the cache fail to cover the request?
415 if (start + count > _pimpl->AudioCacheStart + _pimpl->MaxSampleCount) { // Is cache shifting necessary?
416 int shiftsamples = (int)((start + count) - (_pimpl->AudioCacheStart + _pimpl->MaxSampleCount)); // Align end of cache with end of request
417
418 if ((start - _pimpl->AudioCacheStart) / 2 > shiftsamples) { //shift half cache if possible
419 shiftsamples = (int)((start - _pimpl->AudioCacheStart) / 2);
420 }
421 if (shiftsamples >= (int)_pimpl->CacheCount) { // Can we save any existing data
422 _pimpl->AudioCacheStart = start + count - _pimpl->MaxSampleCount; // Maximise linear access
423 _pimpl->CacheCount = 0;
424 }
425 else {
426 memmove(_pimpl->AudioCache, _pimpl->AudioCache + shiftsamples * _pimpl->SampleSize, (size_t)((_pimpl->CacheCount - shiftsamples) * _pimpl->SampleSize));
427 _pimpl->AudioCacheStart = _pimpl->AudioCacheStart + shiftsamples;
428 _pimpl->CacheCount = _pimpl->CacheCount - shiftsamples;
429 }
430 }
431 // Read just enough to complete the current request, append it to the cache
432 _pimpl->child->GetAudio(_pimpl->AudioCache + _pimpl->CacheCount * _pimpl->SampleSize, _pimpl->AudioCacheStart + _pimpl->CacheCount, start + count - (_pimpl->AudioCacheStart + _pimpl->CacheCount), env);
433 _pimpl->CacheCount += (size_t)(start + count - (_pimpl->AudioCacheStart + _pimpl->CacheCount));
434 }
435 }
436
437 //copy cache to buf
438 memcpy(buf, _pimpl->AudioCache + (size_t)(start - _pimpl->AudioCacheStart) * _pimpl->SampleSize, (size_t)(count * _pimpl->SampleSize));
439
440 }
441
442 5 const VideoInfo& __stdcall AvsCache::GetVideoInfo()
443 {
444 5 return _pimpl->vi;
445 }
446
447 bool __stdcall AvsCache::GetParity(int n)
448 {
449 return _pimpl->child->GetParity(n);
450 }
451
452 10 int __stdcall AvsCache::SetCacheHints(int cachehints, int frame_range)
453 {
454 // _RPT3(0, "AvsCache::SetCacheHints called. cache=%p hint=%d frame_range=%d\n", (void *)this, cachehints, frame_range);
455
2/19
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
✗ Branch 2 → 5 not taken.
✗ Branch 2 → 6 not taken.
✗ Branch 2 → 7 not taken.
✗ Branch 2 → 13 not taken.
✗ Branch 2 → 19 not taken.
✗ Branch 2 → 22 not taken.
✗ Branch 2 → 25 not taken.
✗ Branch 2 → 28 not taken.
✗ Branch 2 → 31 not taken.
✗ Branch 2 → 34 not taken.
✗ Branch 2 → 35 not taken.
✗ Branch 2 → 36 not taken.
✓ Branch 2 → 53 taken 5 times.
✓ Branch 2 → 54 taken 5 times.
✗ Branch 2 → 55 not taken.
✗ Branch 2 → 56 not taken.
✗ Branch 2 → 57 not taken.
10 switch(cachehints)
456 {
457 /*********************************************
458 MISC
459 *********************************************/
460
461 // By returning IS_CACHE_ANS to IS_CACHE_REQ, we tell the caller we are a cache
462 case CACHE_IS_CACHE_REQ:
463 return CACHE_IS_CACHE_ANS;
464
465 case CACHE_GET_POLICY: // Get the current policy.
466 return CACHE_GENERIC;
467
468 case CACHE_DONT_CACHE_ME:
469 return 1;
470
471 case CACHE_GET_MTMODE:
472 return MT_NICE_FILTER;
473
474 /*********************************************
475 VIDEO
476 *********************************************/
477
478 case CACHE_SET_MIN_CAPACITY:
479 { // This is not atomic, but frankly, we don't care
480 size_t min, max;
481 _pimpl->VideoCache->limits(&min, &max);
482 min = frame_range;
483 _pimpl->VideoCache->set_limits(min, max);
484 break;
485 }
486
487 case CACHE_SET_MAX_CAPACITY:
488 { // This is not atomic, but frankly, we don't care
489 size_t min, max;
490 _pimpl->VideoCache->limits(&min, &max);
491 max = frame_range;
492 _pimpl->VideoCache->set_limits(min, max);
493 _RPT3(0, "AvsCache::SetCacheHints CACHE_SET_MAX_CAPACITY cache=%p hint=%d frame_range=%d\n", (void *)this, cachehints, frame_range);
494 break;
495 }
496
497 case CACHE_GET_MIN_CAPACITY:
498 {
499 size_t min, max;
500 _pimpl->VideoCache->limits(&min, &max);
501 return (int)min;
502 }
503
504 case CACHE_GET_MAX_CAPACITY:
505 {
506 size_t min, max;
507 _pimpl->VideoCache->limits(&min, &max);
508 return (int)max;
509 }
510
511 case CACHE_GET_SIZE:
512 return (int)_pimpl->VideoCache->size();
513
514 case CACHE_GET_REQUESTED_CAP:
515 return (int)_pimpl->VideoCache->requested_capacity();
516
517 case CACHE_GET_CAPACITY:
518 return (int)_pimpl->VideoCache->capacity();
519
520 case CACHE_GET_WINDOW: // Get the current window h_span.
521 case CACHE_GET_RANGE: // Get the current generic frame range.
522 return 2;
523 break;
524
525 case CACHE_GENERIC:
526 case CACHE_FORCE_GENERIC:
527 case CACHE_NOTHING:
528 case CACHE_WINDOW:
529 case CACHE_PREFETCH_FRAME: // Queue request to prefetch frame N.
530 case CACHE_PREFETCH_GO: // Action video prefetches.
531 break;
532
533 /*********************************************
534 AUDIO
535 *********************************************/
536
537 case CACHE_AUDIO:
538 case CACHE_AUDIO_AUTO_START_ON:
539 if (!_pimpl->vi.HasAudio())
540 break;
541
542 // Range means for audio.
543 // 0 == Create a default buffer (256kb).
544 // Positive. Allocate X bytes for cache.
545 if (frame_range == 0) {
546 if (_pimpl->AudioPolicy != CACHE_AUDIO_AUTO_START_OFF) // We already have a policy - no need for a default one.
547 break;
548
549 frame_range = 256 * 1024;
550 }
551
552 if (frame_range/_pimpl->SampleSize > _pimpl->MaxSampleCount) { // Only make bigger
553 const bool audio_cache_existed = _pimpl->AudioCache != nullptr;
554 // keep content, newly added bytes are undefined on increase
555 // but CacheCount keeps track on that fact
556 char * NewAudioCache = (char*)realloc(_pimpl->AudioCache, frame_range);
557 if (NewAudioCache == NULL)
558 {
559 throw std::bad_alloc();
560 }
561 _pimpl->AudioCache = NewAudioCache;
562
563 _pimpl->MaxSampleCount = frame_range/_pimpl->SampleSize;
564 if(audio_cache_existed)
565 _pimpl->CacheCount = std::min(_pimpl->CacheCount, _pimpl->MaxSampleCount);
566 else {
567 _pimpl->AudioCacheStart = 0;
568 _pimpl->CacheCount = 0;
569 }
570 }
571
572 _pimpl->AudioPolicy = (CachePolicyHint)cachehints;
573 break;
574
575 5 case CACHE_AUDIO_AUTO_START_OFF:
576 case CACHE_AUDIO_NOTHING:
577 5 free(_pimpl->AudioCache);
578 5 _pimpl->AudioCache = NULL;
579 5 _pimpl->MaxSampleCount = 0;
580 5 _pimpl->AudioCacheStart = 0;
581 5 _pimpl->CacheCount = 0;
582 5 _pimpl->AudioPolicy = (CachePolicyHint)cachehints;
583 5 break;
584
585 5 case CACHE_GET_AUDIO_POLICY: // Get the current audio policy.
586 5 return _pimpl->AudioPolicy;
587
588 case CACHE_GET_AUDIO_SIZE: // Get the current audio cache size.
589 return (int)(_pimpl->SampleSize * _pimpl->MaxSampleCount);
590
591 // n/a ignore them, not implemented even in 2.6
592 case CACHE_PREFETCH_AUDIO_BEGIN: // Begin queue request to prefetch audio (take critical section).
593 case CACHE_PREFETCH_AUDIO_STARTLO: // Set low 32 bits of start.
594 case CACHE_PREFETCH_AUDIO_STARTHI: // Set high 32 bits of start.
595 case CACHE_PREFETCH_AUDIO_COUNT: // Set low 32 bits of length.
596 case CACHE_PREFETCH_AUDIO_COMMIT: // Enqueue request transaction to prefetch audio (release critical section).
597 case CACHE_PREFETCH_AUDIO_GO: // Action audio prefetch
598 break;
599
600 default:
601 return 0;
602 }
603
604 5 return 0;
605 }
606
607 6 CacheGuard::CacheGuard(const PClip& child, const char *name, IScriptEnvironment* env) :
608 6 child(child),
609
1/2
✓ Branch 5 → 6 taken 6 times.
✗ Branch 5 → 21 not taken.
6 vi(child->GetVideoInfo()),
610
1/2
✓ Branch 3 → 4 taken 6 times.
✗ Branch 3 → 23 not taken.
12 globalEnv(env)
611 {
612
1/2
✓ Branch 10 → 11 taken 6 times.
✗ Branch 10 → 12 not taken.
6 if (name)
613
1/2
✓ Branch 11 → 12 taken 6 times.
✗ Branch 11 → 17 not taken.
6 this->name = name;
614
615 // other fields are set OK already
616
2/4
✓ Branch 12 → 13 taken 6 times.
✗ Branch 12 → 17 not taken.
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 6 times.
6 hints.AudioPolicy = vi.HasAudio() ? CACHE_AUDIO_AUTO_START_OFF : CACHE_AUDIO_NOTHING;
617 6 hints.default_AudioPolicy = hints.AudioPolicy;
618
619 6 }
620
621 12 CacheGuard::~CacheGuard()
622 12 { }
623
624 5 PClip CacheGuard::GetCache(IScriptEnvironment* env_, bool use_child_if_notfound)
625 {
626
1/2
✓ Branch 2 → 3 taken 5 times.
✗ Branch 2 → 57 not taken.
5 std::unique_lock<std::mutex> global_lock(mutex);
627
628
1/2
✓ Branch 3 → 4 taken 5 times.
✗ Branch 3 → 55 not taken.
5 InternalEnvironment* env = GetAndRevealCamouflagedEnv(env_);
629
630
1/2
✓ Branch 4 → 5 taken 5 times.
✗ Branch 4 → 55 not taken.
5 Device* device = env->GetCurrentDevice();
631
632
1/4
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 51 not taken.
✗ Branch 26 → 7 not taken.
✓ Branch 26 → 27 taken 5 times.
10 for (auto entry : deviceCaches) {
633 if (entry.first == device) {
634 return entry.second;
635 }
636 }
637
638 // not found for current device, creation may not be good (e.g. GetFrame(0) from an Invoke)
639
1/2
✗ Branch 27 → 29 not taken.
✓ Branch 27 → 31 taken 5 times.
5 if (use_child_if_notfound)
640 return child;
641
642 // not found for current device, create it
643
3/8
✓ Branch 31 → 32 taken 5 times.
✗ Branch 31 → 55 not taken.
✓ Branch 32 → 33 taken 5 times.
✗ Branch 32 → 52 not taken.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 35 taken 5 times.
✗ Branch 52 → 53 not taken.
✗ Branch 52 → 54 not taken.
5 AvsCache* cache = new AvsCache(child, device, /*ref*/mutex, static_cast<InternalEnvironment*>(globalEnv));
644
645 // apply cache hints if it is changed
646
1/2
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 37 taken 5 times.
5 if (hints.min != hints.default_min)
647 cache->SetCacheHints(CACHE_SET_MIN_CAPACITY, (int)hints.min);
648
1/2
✗ Branch 37 → 38 not taken.
✓ Branch 37 → 39 taken 5 times.
5 if (hints.max != hints.default_max)
649 cache->SetCacheHints(CACHE_SET_MAX_CAPACITY, (int)hints.max);
650
651
2/4
✓ Branch 39 → 40 taken 5 times.
✗ Branch 39 → 41 not taken.
✗ Branch 40 → 41 not taken.
✓ Branch 40 → 42 taken 5 times.
5 if (hints.AudioPolicy != hints.default_AudioPolicy || hints.AudioSize != hints.default_AudioSize)
652 cache->SetCacheHints(hints.AudioPolicy, hints.AudioSize);
653
654
1/2
✓ Branch 42 → 43 taken 5 times.
✗ Branch 42 → 55 not taken.
5 deviceCaches.emplace_back(device, cache);
655
1/2
✓ Branch 44 → 45 taken 5 times.
✗ Branch 44 → 55 not taken.
5 return deviceCaches.back().second;
656 5 }
657
658 void CacheGuard::ApplyHints(int cachehints, int frame_range)
659 {
660 std::unique_lock<std::mutex> global_lock(mutex);
661 for (auto entry : deviceCaches) {
662 entry.second->SetCacheHints(cachehints, frame_range);
663 }
664 }
665
666 int CacheGuard::GetOrDefault(int cachehints, int frame_range, int def)
667 {
668 std::unique_lock<std::mutex> global_lock(mutex);
669 for (auto entry : deviceCaches) {
670 return entry.second->SetCacheHints(cachehints, frame_range);
671 }
672 return def;
673 }
674
675 5 PVideoFrame __stdcall CacheGuard::GetFrame(int n, IScriptEnvironment* env_)
676 {
677
1/2
✓ Branch 2 → 3 taken 5 times.
✗ Branch 2 → 18 not taken.
5 InternalEnvironment* IEnv = GetAndRevealCamouflagedEnv(env_);
678 5 IScriptEnvironment* env = static_cast<IScriptEnvironment*>(IEnv);
679
680
1/2
✓ Branch 3 → 4 taken 5 times.
✗ Branch 3 → 18 not taken.
5 ScopedCounter getframe_counter(IEnv->GetFrameRecursiveCount());
681 /*
682 if (!name.empty())
683 _RPT2(0, "CacheGuard::GetFrame call further GetFrame: %s %d\n", name.c_str(), n);
684 */
685
686 // do not create cache from inside Invoke (e.g. when calling GetFrame(0) from constructor during instantation)
687 //const bool chainedCtor = IEnv->GetInvokeStackSize() > 0;
688 5 const bool chainedCtor = false;
689
690
3/4
✓ Branch 5 → 6 taken 5 times.
✗ Branch 5 → 15 not taken.
✓ Branch 7 → 8 taken 4 times.
✓ Branch 7 → 13 taken 1 time.
10 return GetCache(env, chainedCtor)->GetFrame(n, env);
691 5 }
692
693 void __stdcall CacheGuard::GetAudio(void* buf, int64_t start, int64_t count, IScriptEnvironment* env_)
694 {
695 InternalEnvironment* IEnv = GetAndRevealCamouflagedEnv(env_);
696 IScriptEnvironment* env = static_cast<IScriptEnvironment*>(IEnv);
697
698 ScopedCounter getframe_counter(IEnv->GetFrameRecursiveCount());
699
700 // do not create cache from inside Invoke (e.g. when calling GetFrame(0) from constructor during instantation)
701 //const bool chainedCtor = IEnv->GetInvokeStackSize() > 0;
702 const bool chainedCtor = false;
703
704 return GetCache(env, chainedCtor)->GetAudio(buf, start, count, env);
705 }
706
707 10 const VideoInfo& __stdcall CacheGuard::GetVideoInfo()
708 {
709 10 return vi;
710 }
711
712 bool __stdcall CacheGuard::GetParity(int n)
713 {
714 return child->GetParity(n);
715 }
716
717 20 int __stdcall CacheGuard::SetCacheHints(int cachehints, int frame_range)
718 {
719
720 #ifdef _DEBUG
721 std::string hintname;
722 switch (cachehints) {
723 case CACHE_DONT_CACHE_ME: hintname = "CACHE_DONT_CACHE_ME"; break;
724 case CACHE_SET_MIN_CAPACITY: hintname = "CACHE_SET_MIN_CAPACITY"; break;
725 case CACHE_SET_MAX_CAPACITY: hintname = "CACHE_SET_MAX_CAPACITY"; break;
726 case CACHE_GET_MIN_CAPACITY: hintname = "CACHE_GET_MIN_CAPACITY"; break;
727 case CACHE_GET_MAX_CAPACITY: hintname = "CACHE_GET_MAX_CAPACITY"; break;
728 case CACHE_GET_SIZE: hintname = "CACHE_GET_SIZE"; break;
729 case CACHE_GET_REQUESTED_CAP: hintname = "CACHE_GET_REQUESTED_CAP"; break;
730 case CACHE_GET_CAPACITY: hintname = "CACHE_GET_CAPACITY"; break;
731 case CACHE_GET_MTMODE: hintname = "CACHE_GET_MTMODE"; break;
732 case CACHE_IS_CACHE_REQ: hintname = "CACHE_IS_CACHE_REQ"; break;
733 case CACHE_IS_CACHE_ANS: hintname = "CACHE_IS_CACHE_ANS"; break;
734 case CACHE_IS_MTGUARD_REQ: hintname = "CACHE_IS_MTGUARD_REQ"; break;
735 case CACHE_IS_MTGUARD_ANS: hintname = "CACHE_IS_MTGUARD_ANS"; break;
736 case CACHE_INFORM_NUM_THREADS: hintname = "CACHE_INFORM_NUM_THREADS"; break;
737 case CACHE_GET_DEV_TYPE: hintname = "CACHE_GET_DEV_TYPE"; break;
738 case CACHE_GET_CHILD_DEV_TYPE: hintname = "CACHE_GET_CHILD_DEV_TYPE"; break;
739 }
740 if (cachehints != CACHE_GET_DEV_TYPE && cachehints != CACHE_GET_CHILD_DEV_TYPE) {
741 // dont't care for the above
742 if (hintname == "")
743 _RPT3(0, "CacheGuard::SetCacheHints called. cache=%p hint=%d frame_range=%d\n", (void*)this, cachehints, frame_range); // P.F.
744 else
745 _RPT4(0, "CacheGuard::SetCacheHints called. cache=%p hint=%d (%s) frame_range=%d\n", (void*)this, cachehints, hintname.c_str(), frame_range); // P.F.
746 }
747 #endif
748
3/25
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
✓ Branch 2 → 5 taken 1 time.
✓ Branch 2 → 6 taken 4 times.
✗ Branch 2 → 7 not taken.
✗ Branch 2 → 8 not taken.
✗ Branch 2 → 11 not taken.
✗ Branch 2 → 13 not taken.
✗ Branch 2 → 15 not taken.
✗ Branch 2 → 17 not taken.
✗ Branch 2 → 19 not taken.
✗ Branch 2 → 21 not taken.
✗ Branch 2 → 23 not taken.
✗ Branch 2 → 24 not taken.
✗ Branch 2 → 25 not taken.
✗ Branch 2 → 27 not taken.
✗ Branch 2 → 28 not taken.
✗ Branch 2 → 29 not taken.
✗ Branch 2 → 37 not taken.
✗ Branch 2 → 39 not taken.
✗ Branch 2 → 40 not taken.
✗ Branch 2 → 47 not taken.
✓ Branch 2 → 48 taken 15 times.
✗ Branch 2 → 56 not taken.
✗ Branch 2 → 64 not taken.
20 switch (cachehints)
749 {
750 /*********************************************
751 MISC
752 *********************************************/
753
754 // By returning IS_CACHE_ANS to IS_CACHE_REQ, we tell the caller we are a cache
755 case CACHE_IS_CACHE_REQ:
756 return CACHE_IS_CACHE_ANS;
757
758 case CACHE_GET_POLICY: // Get the current policy.
759 return CACHE_GENERIC;
760
761 1 case CACHE_DONT_CACHE_ME:
762 1 return 1;
763
764 4 case CACHE_GET_MTMODE:
765 4 return MT_NICE_FILTER;
766
767 /*********************************************
768 AVS 2.5 TRANSLATION
769 *********************************************/
770
771 // Ignore 2.5 CACHE_NOTHING requests
772 case CACHE_25_NOTHING:
773 break;
774
775 // Map 2.5 CACHE_RANGE calls to CACHE_WINDOW
776 // force minimum range to 2
777 case CACHE_25_RANGE:
778 if (frame_range < 2) frame_range = 2;
779 SetCacheHints(CACHE_WINDOW, frame_range);
780 break;
781
782 // Map 2.5 CACHE_ALL calls to CACHE_GENERIC
783 case CACHE_25_ALL:
784 SetCacheHints(CACHE_GENERIC, frame_range);
785 break;
786
787 // Map 2.5 CACHE_AUDIO calls to CACHE_AUDIO
788 case CACHE_25_AUDIO:
789 SetCacheHints(CACHE_AUDIO, frame_range);
790 break;
791
792 // Map 2.5 CACHE_AUDIO_NONE calls to CACHE_AUDIO_NONE
793 case CACHE_25_AUDIO_NONE:
794 SetCacheHints(CACHE_AUDIO_NONE, 0);
795 break;
796
797 // Map 2.5 CACHE_AUDIO_AUTO calls to CACHE_AUDIO_AUTO
798 case CACHE_25_AUDIO_AUTO:
799 SetCacheHints(CACHE_AUDIO_AUTO, frame_range);
800 break;
801
802 /*********************************************
803 VIDEO
804 *********************************************/
805
806 case CACHE_SET_MIN_CAPACITY:
807 hints.min = frame_range;
808 ApplyHints(cachehints, frame_range);
809 break;
810
811 case CACHE_SET_MAX_CAPACITY:
812 hints.max = frame_range;
813 ApplyHints(cachehints, frame_range);
814 break;
815
816 case CACHE_GET_MIN_CAPACITY:
817 return (int)hints.min;
818
819 case CACHE_GET_MAX_CAPACITY:
820 return (int)hints.max;
821
822 case CACHE_GET_SIZE:
823 case CACHE_GET_REQUESTED_CAP:
824 case CACHE_GET_CAPACITY:
825 return GetOrDefault(cachehints, frame_range, 0);
826
827 case CACHE_GET_WINDOW: // Get the current window h_span.
828 case CACHE_GET_RANGE: // Get the current generic frame range.
829 return 2;
830 break;
831
832 case CACHE_GENERIC:
833 case CACHE_FORCE_GENERIC:
834 case CACHE_NOTHING:
835 case CACHE_WINDOW:
836 case CACHE_PREFETCH_FRAME: // Queue request to prefetch frame N.
837 case CACHE_PREFETCH_GO: // Action video prefetches.
838 break;
839
840 /*********************************************
841 AUDIO
842 *********************************************/
843 case CACHE_GETCHILD_AUDIO_MODE:
844 case CACHE_GETCHILD_AUDIO_SIZE:
845 return (child->GetVersion() >= 5) ? child->SetCacheHints(cachehints, 0) : 0;
846
847 case CACHE_AUDIO:
848 case CACHE_AUDIO_AUTO_START_ON: // auto mode, initially cache
849 case CACHE_AUDIO_AUTO_START_OFF: // auto mode, initially don't cache
850 case CACHE_AUDIO_NOTHING:
851 hints.AudioPolicy = (CachePolicyHint)cachehints;
852 hints.AudioSize = frame_range;
853 ApplyHints(cachehints, frame_range);
854 break;
855
856 case CACHE_GET_AUDIO_POLICY: // Get the current audio policy.
857 return hints.AudioPolicy;
858
859 case CACHE_GET_AUDIO_SIZE: // Get the current audio cache size.
860 return (child->GetVersion() >= 5) ? GetOrDefault(cachehints, frame_range, 0) : 0;
861
862 case CACHE_PREFETCH_AUDIO_BEGIN: // Begin queue request to prefetch audio (take critical section).
863 case CACHE_PREFETCH_AUDIO_STARTLO: // Set low 32 bits of start.
864 case CACHE_PREFETCH_AUDIO_STARTHI: // Set high 32 bits of start.
865 case CACHE_PREFETCH_AUDIO_COUNT: // Set low 32 bits of length.
866 case CACHE_PREFETCH_AUDIO_COMMIT: // Enqueue request transaction to prefetch audio (release critical section).
867 case CACHE_PREFETCH_AUDIO_GO: // Action audio prefetch
868 break;
869
870 15 case CACHE_GET_DEV_TYPE:
871 case CACHE_GET_CHILD_DEV_TYPE:
872
1/2
✓ Branch 50 → 51 taken 15 times.
✗ Branch 50 → 54 not taken.
15 return (child->GetVersion() >= 5) ? child->SetCacheHints(cachehints, 0) : 0;
873
874
875 /*****************************************************
876 Passes actual number of threads after a Prefetch call
877 *****************************************************/
878 case CACHE_INFORM_NUM_THREADS:
879 // pass the request to the child
880 return (child->GetVersion() >= 5) ? child->SetCacheHints(cachehints, frame_range) : 0;
881
882 default:
883 return 0;
884 }
885
886 return 0;
887 }
888
889 7 AVSValue __cdecl CacheGuard::Create(AVSValue args, void*, IScriptEnvironment* env)
890 {
891
1/2
✓ Branch 2 → 3 taken 7 times.
✗ Branch 2 → 70 not taken.
7 PClip p = 0;
892
2/4
✓ Branch 3 → 4 taken 7 times.
✗ Branch 3 → 68 not taken.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 9 taken 7 times.
7 if (args.IsClip())
893 {
894 p = args.AsClip();
895 }
896
6/12
✓ Branch 9 → 10 taken 7 times.
✗ Branch 9 → 68 not taken.
✓ Branch 10 → 11 taken 7 times.
✗ Branch 10 → 15 not taken.
✓ Branch 11 → 12 taken 7 times.
✗ Branch 11 → 68 not taken.
✓ Branch 12 → 13 taken 7 times.
✗ Branch 12 → 68 not taken.
✓ Branch 13 → 14 taken 7 times.
✗ Branch 13 → 15 not taken.
✓ Branch 16 → 17 taken 7 times.
✗ Branch 16 → 22 not taken.
7 else if (args.IsArray() && args[0].IsClip())
897 {
898
3/6
✓ Branch 17 → 18 taken 7 times.
✗ Branch 17 → 64 not taken.
✓ Branch 18 → 19 taken 7 times.
✗ Branch 18 → 64 not taken.
✓ Branch 19 → 20 taken 7 times.
✗ Branch 19 → 62 not taken.
7 p = args[0].AsClip();
899 }
900 7 const char* name = nullptr;
901
10/16
✓ Branch 22 → 23 taken 7 times.
✗ Branch 22 → 68 not taken.
✓ Branch 23 → 24 taken 7 times.
✗ Branch 23 → 30 not taken.
✓ Branch 24 → 25 taken 7 times.
✗ Branch 24 → 68 not taken.
✓ Branch 25 → 26 taken 7 times.
✗ Branch 25 → 30 not taken.
✓ Branch 26 → 27 taken 7 times.
✗ Branch 26 → 68 not taken.
✓ Branch 27 → 28 taken 7 times.
✗ Branch 27 → 68 not taken.
✓ Branch 28 → 29 taken 6 times.
✓ Branch 28 → 30 taken 1 time.
✓ Branch 31 → 32 taken 6 times.
✓ Branch 31 → 35 taken 1 time.
7 if (args.IsArray() && args.ArraySize() >= 2 && args[1].IsString())
902
2/4
✓ Branch 32 → 33 taken 6 times.
✗ Branch 32 → 68 not taken.
✓ Branch 33 → 34 taken 6 times.
✗ Branch 33 → 68 not taken.
6 name = args[1].AsString();
903
904
1/2
✓ Branch 36 → 37 taken 7 times.
✗ Branch 36 → 54 not taken.
7 if (p) // If the child is a clip
905 {
906
1/2
✓ Branch 38 → 39 taken 7 times.
✗ Branch 38 → 68 not taken.
7 if ( (p->GetVersion() >= 5)
907
6/8
✓ Branch 39 → 40 taken 7 times.
✗ Branch 39 → 44 not taken.
✓ Branch 41 → 42 taken 7 times.
✗ Branch 41 → 68 not taken.
✓ Branch 42 → 43 taken 1 time.
✓ Branch 42 → 44 taken 6 times.
✓ Branch 45 → 46 taken 1 time.
✓ Branch 45 → 48 taken 6 times.
7 && (p->SetCacheHints(CACHE_DONT_CACHE_ME, 0) != 0) )
908 {
909 // Don't create cache instance if the child doesn't want to be cached
910 // DONT_CACHE_ME is disabling audio cache as well, even if filter
911 // would specify it by CACHE_GETCHILD_AUDIO_MODE
912
1/2
✓ Branch 46 → 47 taken 1 time.
✗ Branch 46 → 68 not taken.
1 return p; /* This is op, not args! */
913 }
914 else
915 {
916
4/10
✓ Branch 48 → 49 taken 6 times.
✗ Branch 48 → 68 not taken.
✓ Branch 49 → 50 taken 6 times.
✗ Branch 49 → 65 not taken.
✓ Branch 50 → 51 taken 6 times.
✗ Branch 50 → 65 not taken.
✗ Branch 51 → 52 not taken.
✓ Branch 51 → 53 taken 6 times.
✗ Branch 65 → 66 not taken.
✗ Branch 65 → 67 not taken.
6 return new CacheGuard(p, name, env);
917 }
918 }
919 else
920 {
921 return args;
922 }
923 7 }
924
925 bool __stdcall CacheGuard::IsCache(const PClip& p)
926 {
927 return ((p->GetVersion() >= 5) && (p->SetCacheHints(CACHE_IS_CACHE_REQ, 0) == CACHE_IS_CACHE_ANS));
928 }
929