FFmpegfs Fuse Multi Media Filesystem 2.19
Loading...
Searching...
No Matches
cache_entry.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 2017-2026 Norbert Schlia (nschlia@oblivion-software.de)
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 3 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 * On Debian systems, the complete text of the GNU General Public License
19 * Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
20 */
21
32#include "cache_entry.h"
33#include "ffmpegfs.h"
34#include "buffer.h"
35#include "logging.h"
36
37#include <cstring>
38
40 : m_owner(owner)
41 , m_ref_count(0)
42 , m_virtualfile(virtualfile)
43 , m_is_decoding(false)
44 , m_suspend_timeout(false)
45 , m_seek_to_no(0)
46{
49
50 m_cache_info.m_desttype[0] = '\0';
52
53 m_buffer = std::make_unique<Buffer>();
54
55 if (m_buffer != nullptr)
56 {
57 m_buffer->openio(virtualfile);
58 }
59
60 clear();
61
62 Logging::trace(filename(), "Created a new cache entry.");
63}
64
66{
67 std::unique_lock<std::recursive_mutex> lock_active_mutex(m_active_mutex);
68
69 unlock();
70
71 Logging::trace(filename(), "Deleted buffer.");
72}
73
75{
76 return new(std::nothrow) Cache_Entry(owner, virtualfile);
77}
78
80{
81 delete this;
82 return true;
83}
84
85void Cache_Entry::clear(bool fetch_file_time /*= true*/)
86{
87 // Do not touch m_is_decoding here. clear() is also used by an already
88 // running transcoder to remove stale cache contents before a full recode;
89 // resetting the flag in that window allows a second reader to start a
90 // second transcoder for the same cache entry.
91
92 // Initialise ID3v1.1 tag structure
94
95 //m_cache_info.m_enable_ismv = params.m_enable_ismv;
106 m_cache_info.m_error = false;
111
112 if (fetch_file_time)
113 {
114 struct stat sb;
115
116 if (stat(filename(), &sb) == -1)
117 {
120 }
121 else
122 {
123 m_cache_info.m_file_time = sb.st_mtime;
124 m_cache_info.m_file_size = static_cast<size_t>(sb.st_size);
125 }
126 }
127
128 if (m_buffer != nullptr)
129 {
130 m_buffer->clear();
131 }
132}
133
135{
137}
138
143
148
149bool Cache_Entry::update_access(bool update_database /*= false*/)
150{
151 m_cache_info.m_access_time = time(nullptr);
152
153 if (update_database)
154 {
156 }
157 else
158 {
159 return true;
160 }
161}
162
163bool Cache_Entry::openio(bool create_cache /*= true*/)
164{
165 if (m_buffer == nullptr)
166 {
167 errno = EINVAL;
168 return false;
169 }
170
171 if (m_ref_count++ > 0) // fetch_and_add
172 {
173 // Already open. This can happen when an entry was first opened only
174 // for metadata (create_cache == false) and the actual HLS/frame-set
175 // buffer is created later when the requested segment is known.
176 if (create_cache && m_buffer->segment_count() == 0)
177 {
178 bool erase_cache = !is_finished();
179
180 Logging::trace(filename(), "Initialising cache buffer for an already referenced entry. Result %1 Erasing cache: %2.", static_cast<int>(m_cache_info.m_result), erase_cache);
181
182 update_access(true);
183
184 if (m_buffer->init(erase_cache))
185 {
186 return true;
187 }
188 else
189 {
190 clear(false);
191 return false;
192 }
193 }
194
195 // Already open
196 return true;
197 }
198
199 bool erase_cache = !read_info(); // If read_info fails, rebuild cache entry
200
201 if (!create_cache)
202 {
203 return true;
204 }
205
206 if (!is_finished())
207 {
208 // If no database entry found (database is not consistent),
209 // or file was not completely transcoded last time,
210 // simply create a new file.
211 erase_cache = true;
212 }
213
214 Logging::trace(filename(), "The last transcode was completed. Result %1 Erasing cache: %2.", static_cast<int>(m_cache_info.m_result), erase_cache);
215
216 // Store access time
217 update_access(true);
218
219 // Open the cache
220 if (m_buffer->init(erase_cache))
221 {
222 return true;
223 }
224 else
225 {
226 clear(false);
227 return false;
228 }
229}
230
232{
233 if (m_buffer->release(flags))
234 {
235 if (flags)
236 {
237 delete_info();
238 }
239 }
240}
241
242bool Cache_Entry::closeio(int flags)
243{
244 write_info();
245
246 if (m_buffer == nullptr)
247 {
248 errno = EINVAL;
249 return false;
250 }
251
252 if (!m_ref_count)
253 {
254 close_buffer(flags);
255
256 return true;
257 }
258
259 if (--m_ref_count > 0) // sub_and_fetch
260 {
261 // Just flush to disk
262 flush();
263 return false;
264 }
265
266 close_buffer(flags);
267
268 return true;
269}
270
272{
273 if (m_buffer == nullptr)
274 {
275 errno = EINVAL;
276 return false;
277 }
278
279 m_buffer->flush();
280 //write_info();
281
282 return true;
283}
284
285size_t Cache_Entry::size() const
286{
288 {
290 }
291 else
292 {
293 if (m_buffer == nullptr)
294 {
296 }
297 else
298 {
299 size_t current_size = m_buffer->buffer_watermark();
300
301 return std::max(current_size, m_cache_info.m_predicted_filesize);
302 }
303 }
304}
305
310
311time_t Cache_Entry::age() const
312{
313 return (time(nullptr) - m_cache_info.m_creation_time);
314}
315
317{
319}
320
322{
323 return (age() > params.m_expiry_time);
324}
325
327{
328 return (((time(nullptr) - m_cache_info.m_access_time) >= params.m_max_inactive_suspend) && m_ref_count <= 1);
329}
330
332{
333 return (((time(nullptr) - m_cache_info.m_access_time) >= params.m_max_inactive_abort) && m_ref_count <= 1);
334}
335
336const char * Cache_Entry::filename() const
337{
338 return (m_virtualfile != nullptr ? m_virtualfile->m_origfile.c_str() : "");
339}
340
341const char *Cache_Entry::destname() const
342{
343 return (m_virtualfile != nullptr ? m_virtualfile->m_destfile.c_str() : "");
344}
345
346const char * Cache_Entry::virtname() const
347{
348 return (m_virtualfile != nullptr ? m_virtualfile->m_virtfile.c_str() : "");
349}
350
352{
353 m_mutex.lock();
354}
355
357{
358 m_mutex.unlock();
359}
360
362{
363 return m_ref_count;
364}
365
367{
368 return m_ref_count++; // fetch_and_add
369}
370
372{
373 return --m_ref_count; // sub_and_fetch
374}
375
377{
378 struct stat sb;
379
381 {
383 {
384 // Report if old rate is known
385 Logging::debug(filename(), "Triggering re-transcode: Selected audio bitrate changed from %1 to %2.", m_cache_info.m_audiobitrate, params.m_audiobitrate);
386 }
387 return true;
388 }
389
391 {
393 {
394 // Report if old rate is known
395 Logging::debug(filename(), "Triggering re-transcode: Selected audio samplerate changed from %1 to %2.", m_cache_info.m_audiosamplerate, params.m_audiosamplerate);
396 }
397 return true;
398 }
399
401 {
403 {
404 // Report if old rate is known
405 Logging::debug(filename(), "Triggering re-transcode: Selected video bitrate changed from %1 to %2.", m_cache_info.m_audiobitrate, params.m_audiobitrate);
406 }
407 return true;
408 }
409
411 {
413 {
414 // Report if old dimensions is known
415 Logging::debug(filename(), "Triggering re-transcode: Selected video width/height changed from %1/%2 to %3/%4.", m_cache_info.m_videowidth, m_cache_info.m_videoheight, params.m_videowidth, params.m_videoheight);
416 }
417 return true;
418 }
419
420 if (m_cache_info.m_deinterlace != (params.m_deinterlace ? true : false))
421 {
422 Logging::debug(filename(), "Triggering re-transcode: Selected video deinterlace changed from %1 to %2.", m_cache_info.m_deinterlace, params.m_deinterlace);
423 return true;
424 }
425
426 if (stat(filename(), &sb) != -1)
427 {
428 // If source file exists, check file date/size
429 if (m_cache_info.m_file_time < sb.st_mtime)
430 {
431 Logging::debug(filename(), "Triggering re-transcode: File time has gone forward.");
432 return true;
433 }
434
435 if (m_cache_info.m_file_size != static_cast<size_t>(sb.st_size))
436 {
437 Logging::debug(filename(), "Triggering re-transcode: File size has changed.");
438 return true;
439 }
440 }
441
442 return false;
443}
444
449
454
455unsigned int Cache_Entry::read_count() const
456{
458}
459
461{
463}
464
469
474
Buffer class.
@ FINISHED_ERROR
Transcode finished with error.
@ FINISHED_INCOMPLETE
Transcode finished, but incomplete.
@ NONE
No result code available.
@ FINISHED_SUCCESS
Transcode finished successfully.
Cache entry
The Cache_Entry class.
Definition cache_entry.h:49
size_t size() const
Return size of output file, as computed by encoder.
CACHE_INFO m_cache_info
Info about cached object.
bool update_access(bool update_database=false)
Update last access time.
bool is_finished_error() const
Get if cache has been finished and with an error.
static Cache_Entry * create(Cache *owner, LPVIRTUALFILE virtualfile)
Create a new Cache_Entry object.
time_t age() const
Get the age of the cache entry.
bool is_finished() const
Get if cache has been finished.
std::recursive_mutex m_mutex
Access mutex.
bool suspend_timeout() const
Check for decode suspend timeout.
Cache * m_owner
Owner cache object.
int ref_count() const
Get the current reference counter.
void lock()
Lock the access mutex.
void close_buffer(int flags)
Close buffer object.
const char * virtname() const
Return virtual filename. Same as destination filename, but with virtual (mount) path....
LPVIRTUALFILE m_virtualfile
Underlying virtual file object.
void clear(bool fetch_file_time=true)
Clear the cache entry.
const char * destname() const
Return destination filename.
LPVIRTUALFILE virtualfile()
Get the underlying VIRTUALFILE object.
bool write_info()
Write cache info.
bool destroy()
Destroy this Cache_Entry object.
bool openio(bool create_cache=true)
Open the cache file.
Cache_Entry(Cache *owner, LPVIRTUALFILE virtualfile)
Create Cache_Entry object.
void update_read_count()
Update read counter.
std::atomic_int m_ref_count
Reference counter.
const char * filename() const
Return source filename.
int decr_refcount()
Decrement the current reference counter.
time_t last_access() const
Get last access time.
std::recursive_mutex m_active_mutex
Mutex while thread is active.
ID3v1 m_id3v1
ID3v1 structure which is used to send to clients.
uint32_t video_frame_count() const
Get the video frame count.
bool closeio(int flags)
Close the cache entry.
unsigned int read_count() const
Get read counter.
int inc_refcount()
Increment the current reference counter.
bool flush()
Flush current memory cache to disk.
bool decode_timeout() const
Check for decode timeout.
void unlock()
Unlock the access mutex.
bool is_finished_incomplete() const
Get if cache has been finished, but not completely filled.
bool is_finished_success() const
Get if cache has been finished and filled successfully.
bool outdated() const
Check if cache entry needs to be recoded.
std::unique_ptr< Buffer > m_buffer
Buffer object.
bool delete_info()
Delete cache info.
virtual ~Cache_Entry()
Destroy Cache_Entry object.
bool read_info()
Read cache info.
bool expired() const
Check if cache entry expired.
The Cache class.
Definition cache.h:105
bool delete_info(const std::string &filename, const std::string &desttype)
Delete cache file info.
Definition cache.cc:978
bool write_info(LPCCACHE_INFO cache_info)
Write cache file info.
Definition cache.cc:912
bool read_info(LPCACHE_INFO cache_info)
Read cache file info.
Definition cache.cc:785
const std::string & desttype() const
Get destination type.
static void debug(const T filename, const std::string &format_string, Args &&...args)
Write debug level log entry.
Definition logging.h:182
static void trace(const T filename, const std::string &format_string, Args &&...args)
Write trace level log entry.
Definition logging.h:163
void init_id3v1(ID3v1 *id3v1)
Initialise ID3v1 tag.
FFMPEGFS_PARAMS params
FFmpegfs command line parameters.
Definition ffmpegfs.cc:81
Main include for FFmpegfs project.
Provide various log facilities to stderr, disk or syslog.
uint32_t m_video_frame_count
Number of frames in video or 0 if not a video.
Definition cache.h:84
int64_t m_audiobitrate
Audio bitrate in bit/s.
Definition cache.h:75
size_t m_file_size
Source file file size.
Definition cache.h:93
time_t m_access_time
Source file last access time.
Definition cache.h:91
RESULTCODE m_result
Result code:
Definition cache.h:86
bool m_deinterlace
true if video was deinterlaced
Definition cache.h:80
size_t m_encoded_filesize
Actual file size after encode.
Definition cache.h:83
int m_audiosamplerate
Audio sample rate in Hz.
Definition cache.h:76
bool m_error
true if encode failed
Definition cache.h:87
size_t m_predicted_filesize
Predicted file size.
Definition cache.h:82
std::string m_destfile
Destination filename after transcode.
Definition cache.h:73
int m_averror
FFmpeg error code if encode failed.
Definition cache.h:89
std::string m_origfile
Original filename before transcode.
Definition cache.h:72
time_t m_file_time
Source file file time.
Definition cache.h:92
std::array< char, 11 > m_desttype
Destination type.
Definition cache.h:74
int m_videowidth
Video width.
Definition cache.h:78
int m_videoheight
Video height.
Definition cache.h:79
int64_t m_videobitrate
Video bitrate in bit/s.
Definition cache.h:77
unsigned int m_access_count
Read access counter.
Definition cache.h:94
int m_errno
errno if encode failed
Definition cache.h:88
time_t m_creation_time
Source file creation time.
Definition cache.h:90
time_t m_max_inactive_suspend
Time (seconds) that must elapse without access until transcoding is suspended.
Definition ffmpegfs.h:239
int m_deinterlace
1: deinterlace video, 0: no deinterlace
Definition ffmpegfs.h:211
time_t m_expiry_time
Time (seconds) after which an cache entry is deleted.
Definition ffmpegfs.h:238
const FFmpegfs_Format * current_format(LPCVIRTUALFILE virtualfile) const
Get FFmpegfs_Format for a virtual file.
Definition ffmpegfs.cc:242
int m_videowidth
Output video width.
Definition ffmpegfs.h:209
BITRATE m_videobitrate
Output video bit rate (bits per second)
Definition ffmpegfs.h:208
int m_videoheight
Output video height.
Definition ffmpegfs.h:210
BITRATE m_audiobitrate
Output audio bit rate (bits per second)
Definition ffmpegfs.h:203
int m_audiosamplerate
Output audio sample rate (in Hz)
Definition ffmpegfs.h:204
time_t m_max_inactive_abort
Time (seconds) that must elapse without access until transcoding is aborted.
Definition ffmpegfs.h:240
Virtual file definition.
Definition fileio.h:123
std::string m_destfile
Name and path of destination file.
Definition fileio.h:150
std::string m_origfile
Sanitised name and path of original file.
Definition fileio.h:152
std::string m_virtfile
Name and path of virtual file.
Definition fileio.h:151