FFmpegfs Fuse Multi Media Filesystem 2.16
ffmpegfs.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 2006-2008 David Collett
3 * Copyright (C) 2008-2012 K. Henriksson
4 * Copyright (C) 2017-2024 FFmpeg support by Norbert Schlia (nschlia@oblivion-software.de)
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 *
20 * On Debian systems, the complete text of the GNU General Public License
21 * Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
22 */
23
36#ifdef __cplusplus
37extern "C" {
38#endif
39#pragma GCC diagnostic push
40#pragma GCC diagnostic ignored "-Wconversion"
41#pragma GCC diagnostic ignored "-Wsign-conversion"
42#include <libavcodec/avcodec.h>
43#include <libavformat/avformat.h>
44#include <libavfilter/avfilter.h>
45#pragma GCC diagnostic pop
46#ifdef __cplusplus
47}
48#endif
49
50#ifdef HAVE_CONFIG_H
51#include "config.h"
52#endif
53
54#include "ffmpegfs.h"
55#include "logging.h"
56#include "ffmpegfshelp.h"
57
58#include <sys/sysinfo.h>
59#include <sqlite3.h>
60#include <unistd.h>
61#include <fnmatch.h>
62#include <iostream>
63
64#ifdef USE_LIBBLURAY
65#include <libbluray/bluray-version.h>
66#endif
67
68#ifdef __clang__
69// Silence this in fuse API code for clang
70#pragma GCC diagnostic ignored "-Wimplicit-int-conversion"
71#endif
72
76FFMPEGFS_PARAMS::FFMPEGFS_PARAMS()
77 : m_basepath("") // required parameter
78 , m_mountpath("") // required parameter
79
80 , m_audio_codec(AV_CODEC_ID_NONE) // default: use predefined option
81 , m_video_codec(AV_CODEC_ID_NONE) // default: use predefined option
82
83 , m_autocopy(AUTOCOPY::OFF) // default: off
84 , m_recodesame(RECODESAME::NO) // default: off
85 , m_profile(PROFILE::DEFAULT) // default: no profile
86 , m_level(PRORESLEVEL::NONE) // default: no level
87
88 // Format
89 // Audio
90 , m_audiobitrate(128*1024) // default: 128 kBit
91 , m_audiosamplerate(44100) // default: 44.1 kHz
92 , m_audiochannels(2) // default: 2 channels
93 , m_sample_fmt(SAMPLE_FMT::FMT_DONTCARE) // default: use source format
94
95 // Video
96 , m_videobitrate(2*1024*1024) // default: 2 MBit
97 , m_videowidth(0) // default: do not change width
98 , m_videoheight(0) // default: do not change height
99 , m_deinterlace(0) // default: do not interlace video
100 , m_segment_duration(10 * AV_TIME_BASE) // default: 10 seconds
101 , m_min_seek_time_diff(30 * AV_TIME_BASE) // default: 30 seconds
102 // Hardware acceleration
103 , m_hwaccel_enc_API(HWACCELAPI::NONE) // default: Use software encoder
104 , m_hwaccel_enc_device_type(AV_HWDEVICE_TYPE_NONE) // default: Use software encoder
105 , m_hwaccel_dec_API(HWACCELAPI::NONE) // default: Use software encoder
106 , m_hwaccel_dec_device_type(AV_HWDEVICE_TYPE_NONE) // default: Use software decoder
107 , m_hwaccel_dec_blocked(nullptr) // default: No blocked encoders
108
109 // Subtitles
110 , m_no_subtitles(0) // default: enable subtitles
111
112 // Album arts
113 , m_noalbumarts(0) // default: copy album arts
114 // Virtual Script
115 , m_enablescript(0) // default: no virtual script
116 , m_scriptfile("index.php") // default name
117 , m_scriptsource("scripts/videotag.php") // default name
118 // Other
119 , m_debug(0) // default: no debug messages
120 , m_log_maxlevel("INFO") // default: INFO level
121 , m_log_stderr(0) // default: do not log to stderr
122 , m_log_syslog(0) // default: do not use syslog
123 , m_logfile("") // default: none
124 // Cache/recoding options
125 , m_expiry_time((60*60*24 /* d */) * 7) // default: 1 week)
126 , m_max_inactive_suspend(15) // default: 15 seconds
127 , m_max_inactive_abort(30) // default: 30 seconds
128 , m_prebuffer_time(0) // default: no prebuffer time
129 , m_prebuffer_size(100 /* KB */ * 1024) // default: 100 KB
130 , m_max_cache_size(0) // default: no limit
131 , m_min_diskspace(0) // default: no minimum
132 , m_cachepath("") // default: $XDG_CACHE_HOME/ffmpegfs
133 , m_disable_cache(0) // default: enabled
134 , m_cache_maintenance((60*60)) // default: prune every 60 minutes
135 , m_prune_cache(0) // default: Do not prune cache immediately
136 , m_clear_cache(0) // default: Do not clear cache on startup
137 , m_max_threads(0) // default: 16 * CPU cores (this value here is overwritten later)
138 , m_decoding_errors(0) // default: ignore errors
139 , m_min_dvd_chapter_duration(1) // default: 1 second
140 , m_oldnamescheme(0) // default: new scheme
141 , m_include_extensions(new (std::nothrow) MATCHVEC) // default: empty list
142 , m_hide_extensions(new (std::nothrow) MATCHVEC) // default: empty list
143 , m_win_smb_fix(1) // default: fix enabled
144{
145}
146
147FFMPEGFS_PARAMS::FFMPEGFS_PARAMS(const FFMPEGFS_PARAMS & other)
148{
149 *this = other;
150}
151
152FFMPEGFS_PARAMS::~FFMPEGFS_PARAMS()
153{
155}
156
158{
159 if (this != &other) // Self assignment check
160 {
161 m_basepath = other.m_basepath;
162 m_mountpath = other.m_mountpath;
163
164 m_audio_codec = other.m_audio_codec;
165 m_video_codec = other.m_video_codec;
166
167 m_autocopy = other.m_autocopy;
168 m_recodesame = other.m_recodesame;
169 m_profile = other.m_profile;
170 m_level = other.m_level;
171
172 m_audiobitrate = other.m_audiobitrate;
173 m_audiosamplerate = other.m_audiosamplerate;
174 m_audiochannels = other.m_audiochannels;
175 m_sample_fmt = other.m_sample_fmt;
176
177 m_videobitrate = other.m_videobitrate;
178 m_videowidth = other.m_videowidth;
179 m_videoheight = other.m_videoheight;
180 m_deinterlace = other.m_deinterlace;
181 m_segment_duration = other.m_segment_duration;
182 m_min_seek_time_diff = other.m_min_seek_time_diff;
183
184 m_hwaccel_enc_API = other.m_hwaccel_enc_API;
185 m_hwaccel_enc_device_type = other.m_hwaccel_enc_device_type;
186 m_hwaccel_enc_device = other.m_hwaccel_enc_device;
187 m_hwaccel_dec_API = other.m_hwaccel_dec_API;
188 m_hwaccel_dec_device_type = other.m_hwaccel_dec_device_type;
189 m_hwaccel_dec_device = other.m_hwaccel_dec_device;
190 m_hwaccel_dec_blocked = other.m_hwaccel_dec_blocked;
191
192 m_no_subtitles = other.m_no_subtitles;
193
194 m_noalbumarts = other.m_noalbumarts;
195
196 m_enablescript = other.m_enablescript;
197 m_scriptfile = other.m_scriptfile;
198 m_scriptsource = other.m_scriptsource;
199
200 m_debug = other.m_debug;
201 m_log_maxlevel = other.m_log_maxlevel;
202 m_log_stderr = other.m_log_stderr;
203 m_log_syslog = other.m_log_syslog;
204 m_logfile = other.m_logfile;
205
206 m_expiry_time = other.m_expiry_time;
207 m_max_inactive_suspend = other.m_max_inactive_suspend;
208 m_max_inactive_abort = other.m_max_inactive_abort;
209 m_prebuffer_time = other.m_prebuffer_time;
210 m_prebuffer_size = other.m_prebuffer_size;
211 m_max_cache_size = other.m_max_cache_size;
212 m_min_diskspace = other.m_min_diskspace;
213 m_cachepath = other.m_cachepath;
214 m_disable_cache = other.m_disable_cache;
215 m_cache_maintenance = other.m_cache_maintenance;
216 m_prune_cache = other.m_prune_cache;
217 m_clear_cache = other.m_clear_cache;
218 m_max_threads = other.m_max_threads;
219 m_decoding_errors = other.m_decoding_errors;
220 m_min_dvd_chapter_duration = other.m_min_dvd_chapter_duration;
221 m_oldnamescheme = other.m_oldnamescheme;
222 *m_include_extensions = *other.m_include_extensions;
223 *m_hide_extensions = *other.m_hide_extensions;
224 m_win_smb_fix = other.m_win_smb_fix;
225 }
226
227 return *this;
228}
229
231{
232 return (ffmpeg_format[FORMAT::AUDIO].filetype() != FILETYPE::UNKNOWN && ffmpeg_format[FORMAT::VIDEO].filetype() != ffmpeg_format[FORMAT::AUDIO].filetype());
233}
234
236{
237 if (virtualfile == nullptr || virtualfile->m_format_idx > 1)
238 {
239 return nullptr;
240 }
241 return &ffmpeg_format[virtualfile->m_format_idx];
242}
243
244enum // enum class or typedef here is not compatible with Fuse API
245{
246 KEY_HELP,
247 KEY_VERSION,
248 KEY_FFMPEG_CAPS,
249 KEY_KEEP_OPT,
250 // Intelligent parameters
251 KEY_DESTTYPE,
252 KEY_AUDIOCODEC,
253 KEY_VIDEOCODEC,
254 KEY_AUDIO_BITRATE,
255 KEY_AUDIO_SAMPLERATE,
256 KEY_AUDIO_CHANNELS,
257 KEY_AUDIO_SAMPLE_FMT,
258 KEY_VIDEO_BITRATE,
259 KEY_SEGMENT_DURATION,
260 KEY_MIN_SEEK_TIME_DIFF,
261 KEY_SCRIPTFILE,
262 KEY_SCRIPTSOURCE,
263 KEY_EXPIRY_TIME,
264 KEY_MAX_INACTIVE_SUSPEND_TIME,
265 KEY_MAX_INACTIVE_ABORT_TIME,
266 KEY_PREBUFFER_TIME,
267 KEY_PREBUFFER_SIZE,
268 KEY_MAX_CACHE_SIZE,
269 KEY_MIN_DISKSPACE_SIZE,
270 KEY_CACHEPATH,
271 KEY_CACHE_MAINTENANCE,
272 KEY_AUTOCOPY,
273 KEY_RECODESAME,
274 KEY_PROFILE,
275 KEY_LEVEL,
276 KEY_LOG_MAXLEVEL,
277 KEY_LOGFILE,
278 KEY_HWACCEL_ENCODER_API,
279 KEY_HWACCEL_ENCODER_DEVICE,
280 KEY_HWACCEL_DECODER_API,
281 KEY_HWACCEL_DECODER_DEVICE,
282 KEY_HWACCEL_DECODER_BLOCKED,
283 KEY_INCLUDE_EXTENSIONS,
284 KEY_HIDE_EXTENSIONS
285};
286
290#define FFMPEGFS_OPT(templ, param, value) { templ, offsetof(FFMPEGFS_PARAMS, param), value }
291
297#pragma GCC diagnostic push
298#pragma GCC diagnostic ignored "-Wnarrowing"
299#pragma GCC diagnostic ignored "-Wsign-conversion"
300static struct fuse_opt ffmpegfs_opts[] = // NOLINT(modernize-avoid-c-arrays)
301{
302 // Output type
303 FUSE_OPT_KEY("--desttype=%s", KEY_DESTTYPE),
304 FUSE_OPT_KEY("desttype=%s", KEY_DESTTYPE),
305 FUSE_OPT_KEY("--audiocodec=%s", KEY_AUDIOCODEC),
306 FUSE_OPT_KEY("audiocodec=%s", KEY_AUDIOCODEC),
307 FUSE_OPT_KEY("--videocodec=%s", KEY_VIDEOCODEC),
308 FUSE_OPT_KEY("videocodec=%s", KEY_VIDEOCODEC),
309 FUSE_OPT_KEY("--profile=%s", KEY_PROFILE),
310 FUSE_OPT_KEY("profile=%s", KEY_PROFILE),
311 FUSE_OPT_KEY("--autocopy=%s", KEY_AUTOCOPY),
312 FUSE_OPT_KEY("autocopy=%s", KEY_AUTOCOPY),
313 FUSE_OPT_KEY("--recodesame=%s", KEY_RECODESAME),
314 FUSE_OPT_KEY("recodesame=%s", KEY_RECODESAME),
315 FUSE_OPT_KEY("--level=%s", KEY_LEVEL),
316 FUSE_OPT_KEY("level=%s", KEY_LEVEL),
317
318 // Audio
319 FUSE_OPT_KEY("--audiobitrate=%s", KEY_AUDIO_BITRATE),
320 FUSE_OPT_KEY("audiobitrate=%s", KEY_AUDIO_BITRATE),
321 FUSE_OPT_KEY("--audiosamplerate=%s", KEY_AUDIO_SAMPLERATE),
322 FUSE_OPT_KEY("audiosamplerate=%s", KEY_AUDIO_SAMPLERATE),
323 FUSE_OPT_KEY("--audiochannels=%s", KEY_AUDIO_CHANNELS),
324 FUSE_OPT_KEY("audiochannels=%s", KEY_AUDIO_CHANNELS),
325 FUSE_OPT_KEY("--audiosamplefmt=%s", KEY_AUDIO_SAMPLE_FMT),
326 FUSE_OPT_KEY("audiosamplefmt=%s", KEY_AUDIO_SAMPLE_FMT),
327 // Video
328 FUSE_OPT_KEY("--videobitrate=%s", KEY_VIDEO_BITRATE),
329 FUSE_OPT_KEY("videobitrate=%s", KEY_VIDEO_BITRATE),
330 FFMPEGFS_OPT("--videoheight=%u", m_videoheight, 0),
331 FFMPEGFS_OPT("videoheight=%u", m_videoheight, 0),
332 FFMPEGFS_OPT("--videowidth=%u", m_videowidth, 0),
333 FFMPEGFS_OPT("videowidth=%u", m_videowidth, 0),
334 FFMPEGFS_OPT("--deinterlace", m_deinterlace, 1),
335 FFMPEGFS_OPT("deinterlace", m_deinterlace, 1),
336 // HLS
337 FUSE_OPT_KEY("--segment_duration=%s", KEY_SEGMENT_DURATION),
338 FUSE_OPT_KEY("segment_duration=%s", KEY_SEGMENT_DURATION),
339 FUSE_OPT_KEY("--min_seek_time_diff=%s", KEY_MIN_SEEK_TIME_DIFF),
340 FUSE_OPT_KEY("min_seek_time_diff=%s", KEY_MIN_SEEK_TIME_DIFF),
341 // Hardware acceleration
342 FUSE_OPT_KEY("--hwaccel_enc=%s", KEY_HWACCEL_ENCODER_API),
343 FUSE_OPT_KEY("hwaccel_enc=%s", KEY_HWACCEL_ENCODER_API),
344 FUSE_OPT_KEY("--hwaccel_enc_device=%s", KEY_HWACCEL_ENCODER_DEVICE),
345 FUSE_OPT_KEY("hwaccel_enc_device=%s", KEY_HWACCEL_ENCODER_DEVICE),
346 FUSE_OPT_KEY("--hwaccel_dec=%s", KEY_HWACCEL_DECODER_API),
347 FUSE_OPT_KEY("hwaccel_dec=%s", KEY_HWACCEL_DECODER_API),
348 FUSE_OPT_KEY("--hwaccel_dec_device=%s", KEY_HWACCEL_DECODER_DEVICE),
349 FUSE_OPT_KEY("hwaccel_dec_device=%s", KEY_HWACCEL_DECODER_DEVICE),
350 FUSE_OPT_KEY("--hwaccel_dec_blocked=%s", KEY_HWACCEL_DECODER_BLOCKED),
351 FUSE_OPT_KEY("hwaccel_dec_blocked=%s", KEY_HWACCEL_DECODER_BLOCKED),
352 // Subtitles
353 FFMPEGFS_OPT("--no_subtitles", m_no_subtitles, 1),
354 FFMPEGFS_OPT("no_subtitles", m_no_subtitles, 1),
355 // Album arts
356 FFMPEGFS_OPT("--noalbumarts", m_noalbumarts, 1),
357 FFMPEGFS_OPT("noalbumarts", m_noalbumarts, 1),
358 // Virtual script
359 FFMPEGFS_OPT("--enablescript", m_enablescript, 1),
360 FFMPEGFS_OPT("enablescript", m_enablescript, 1),
361 FUSE_OPT_KEY("--scriptfile=%s", KEY_SCRIPTFILE),
362 FUSE_OPT_KEY("scriptfile=%s", KEY_SCRIPTFILE),
363 FUSE_OPT_KEY("--scriptsource=%s", KEY_SCRIPTSOURCE),
364 FUSE_OPT_KEY("scriptsource=%s", KEY_SCRIPTSOURCE),
365 // Background recoding/caching
366 // Cache
367 FUSE_OPT_KEY("--expiry_time=%s", KEY_EXPIRY_TIME),
368 FUSE_OPT_KEY("expiry_time=%s", KEY_EXPIRY_TIME),
369 FUSE_OPT_KEY("--max_inactive_suspend=%s", KEY_MAX_INACTIVE_SUSPEND_TIME),
370 FUSE_OPT_KEY("max_inactive_suspend=%s", KEY_MAX_INACTIVE_SUSPEND_TIME),
371 FUSE_OPT_KEY("--max_inactive_abort=%s", KEY_MAX_INACTIVE_ABORT_TIME),
372 FUSE_OPT_KEY("max_inactive_abort=%s", KEY_MAX_INACTIVE_ABORT_TIME),
373 FUSE_OPT_KEY("--prebuffer_time=%s", KEY_PREBUFFER_TIME),
374 FUSE_OPT_KEY("prebuffer_time=%s", KEY_PREBUFFER_TIME),
375 FUSE_OPT_KEY("--prebuffer_size=%s", KEY_PREBUFFER_SIZE),
376 FUSE_OPT_KEY("prebuffer_size=%s", KEY_PREBUFFER_SIZE),
377 FUSE_OPT_KEY("--max_cache_size=%s", KEY_MAX_CACHE_SIZE),
378 FUSE_OPT_KEY("max_cache_size=%s", KEY_MAX_CACHE_SIZE),
379 FUSE_OPT_KEY("--min_diskspace=%s", KEY_MIN_DISKSPACE_SIZE),
380 FUSE_OPT_KEY("min_diskspace=%s", KEY_MIN_DISKSPACE_SIZE),
381 FUSE_OPT_KEY("--cachepath=%s", KEY_CACHEPATH),
382 FUSE_OPT_KEY("cachepath=%s", KEY_CACHEPATH),
383 FFMPEGFS_OPT("--disable_cache", m_disable_cache, 1),
384 FFMPEGFS_OPT("disable_cache", m_disable_cache, 1),
385 FUSE_OPT_KEY("--cache_maintenance=%s", KEY_CACHE_MAINTENANCE),
386 FUSE_OPT_KEY("cache_maintenance=%s", KEY_CACHE_MAINTENANCE),
387 FFMPEGFS_OPT("--prune_cache", m_prune_cache, 1),
388 FFMPEGFS_OPT("--clear_cache", m_clear_cache, 1),
389 FFMPEGFS_OPT("clear_cache", m_clear_cache, 1),
390
391 // Other
392 FFMPEGFS_OPT("--max_threads=%u", m_max_threads, 0),
393 FFMPEGFS_OPT("max_threads=%u", m_max_threads, 0),
394 FFMPEGFS_OPT("--decoding_errors=%u", m_decoding_errors, 0),
395 FFMPEGFS_OPT("decoding_errors=%u", m_decoding_errors, 0),
396 FFMPEGFS_OPT("--min_dvd_chapter_duration=%u", m_min_dvd_chapter_duration, 0),
397 FFMPEGFS_OPT("min_dvd_chapter_duration=%u", m_min_dvd_chapter_duration, 0),
398 FFMPEGFS_OPT("--oldnamescheme=%u", m_oldnamescheme, 0),
399 FFMPEGFS_OPT("oldnamescheme=%u", m_oldnamescheme, 0),
400 FUSE_OPT_KEY("--include_extensions=%s", KEY_INCLUDE_EXTENSIONS),
401 FUSE_OPT_KEY("include_extensions=%s", KEY_INCLUDE_EXTENSIONS),
402 FUSE_OPT_KEY("--hide_extensions=%u", KEY_HIDE_EXTENSIONS),
403 FUSE_OPT_KEY("hide_extensions=%u", KEY_HIDE_EXTENSIONS),
404 // Experimental
405 FFMPEGFS_OPT("--win_smb_fix=%u", m_win_smb_fix, 1),
406 FFMPEGFS_OPT("win_smb_fix=%u", m_win_smb_fix, 1),
407 // FFmpegfs options
408 FFMPEGFS_OPT("-d", m_debug, 1),
409 FFMPEGFS_OPT("debug", m_debug, 1),
410 FUSE_OPT_KEY("--log_maxlevel=%s", KEY_LOG_MAXLEVEL),
411 FUSE_OPT_KEY("log_maxlevel=%s", KEY_LOG_MAXLEVEL),
412 FFMPEGFS_OPT("--log_stderr", m_log_stderr, 1),
413 FFMPEGFS_OPT("log_stderr", m_log_stderr, 1),
414 FFMPEGFS_OPT("--log_syslog", m_log_syslog, 1),
415 FFMPEGFS_OPT("log_syslog", m_log_syslog, 1),
416 FUSE_OPT_KEY("--logfile=%s", KEY_LOGFILE),
417 FUSE_OPT_KEY("logfile=%s", KEY_LOGFILE),
418
419 FUSE_OPT_KEY("-h", KEY_HELP),
420 FUSE_OPT_KEY("--help", KEY_HELP),
421 FUSE_OPT_KEY("-V", KEY_VERSION),
422 FUSE_OPT_KEY("--version", KEY_VERSION),
423 FUSE_OPT_KEY("-c", KEY_FFMPEG_CAPS),
424 FUSE_OPT_KEY("--capabilities", KEY_FFMPEG_CAPS),
425 FUSE_OPT_KEY("-d", KEY_KEEP_OPT),
426 FUSE_OPT_KEY("debug", KEY_KEEP_OPT),
427 FUSE_OPT_END
428};
429#pragma GCC diagnostic pop
430
431typedef std::map<const std::string, const AUTOCOPY, comp> AUTOCOPY_MAP;
432typedef std::map<const std::string, const PROFILE, comp> PROFILE_MAP;
433typedef std::map<const std::string, const PRORESLEVEL, comp> LEVEL_MAP;
434typedef std::map<const std::string, const RECODESAME, comp> RECODESAME_MAP;
436typedef struct HWACCEL
437{
440 AVHWDeviceType m_hwaccel_device_type;
442
443typedef std::map<const std::string, HWACCEL, comp> HWACCEL_MAP;
444typedef std::map<const std::string, const AVCodecID, comp> CODEC_MAP;
445typedef std::map<const std::string, const SAMPLE_FMT, comp> SAMPLE_FMT_MAP;
447typedef std::map<const std::string, const AVCodecID, comp> AUDIOCODEC_MAP;
448typedef std::map<const std::string, const AVCodecID, comp> VIDEOCODEC_MAP;
454{
455 { "AAC", AV_CODEC_ID_AAC }, // TS, MP4, MOV, MKV
456 { "AC3", AV_CODEC_ID_AC3 }, // MP4, MOV, MKV
457 { "MP3", AV_CODEC_ID_MP3 }, // TS, MP4, MOV, MKV
458 { "OPUS", AV_CODEC_ID_OPUS }, // webm
459
460 { "VORBIS", AV_CODEC_ID_VORBIS },
461 { "DTS", AV_CODEC_ID_DTS },
462 { "PCM16", AV_CODEC_ID_PCM_S16LE },
463 { "PCM24", AV_CODEC_ID_PCM_S24LE },
464 { "PCM32", AV_CODEC_ID_PCM_S32LE },
465};
466
471{
472 { "MPEG1", AV_CODEC_ID_MPEG1VIDEO }, // TS, MP4, MKV
473 { "MPEG2", AV_CODEC_ID_MPEG2VIDEO }, // TS, MP4, MKV
474 { "H264", AV_CODEC_ID_H264 }, // TS, MP4, MKV
475 { "H265", AV_CODEC_ID_H265 }, // TS, MP4, MKV
476 { "VP8", AV_CODEC_ID_VP8 }, // WebM
477 { "VP9", AV_CODEC_ID_VP9 }, // WebM
478
479 //{ "AV1", AV_CODEC_ID_AV1 }, /** @todo WebM ends with "Could not write video frame (error 'Invalid data found when processing input')." */
480};
481
486{
487 { "OFF", AUTOCOPY::OFF },
488 { "MATCH", AUTOCOPY::MATCH },
489 { "MATCHLIMIT", AUTOCOPY::MATCHLIMIT },
490 { "STRICT", AUTOCOPY::STRICT },
491 { "STRICTLIMIT", AUTOCOPY::STRICTLIMIT },
492};
493
498{
499 { "NONE", PROFILE::DEFAULT },
500
501 // MP4
502
503 { "FF", PROFILE::MP4_FF },
504 { "EDGE", PROFILE::MP4_EDGE },
505 { "IE", PROFILE::MP4_IE },
506 { "CHROME", PROFILE::MP4_CHROME },
507 { "SAFARI", PROFILE::MP4_SAFARI },
508 { "OPERA", PROFILE::MP4_OPERA },
509 { "MAXTHON", PROFILE::MP4_MAXTHON },
510
511 // WEBM
512};
513
518{
519 // ProRes
520 { "PROXY", PRORESLEVEL::PRORES_PROXY },
521 { "LT", PRORESLEVEL::PRORES_LT },
522 { "STANDARD", PRORESLEVEL::PRORES_STANDARD },
523 { "HQ", PRORESLEVEL::PRORES_HQ },
524};
525
530{
531 // Recode to same format
532 { "NO", RECODESAME::NO },
533 { "YES", RECODESAME::YES },
534};
535
545{
546 { "NONE", { true, HWACCELAPI::NONE, AV_HWDEVICE_TYPE_NONE } },
547
548 // **** Supported by Linux ****
549
550 { "VAAPI", { true, HWACCELAPI::VAAPI, AV_HWDEVICE_TYPE_NONE } }, // Video Acceleration API (VA-API), https://trac.ffmpeg.org/wiki/Hardware/VAAPI
551
552 // RaspberryPi
553
554 { "MMAL", { true, HWACCELAPI::MMAL, AV_HWDEVICE_TYPE_NONE } }, // Multimedia Abstraction Layer by Broadcom. Encoding only.
555 { "OMX", { true, HWACCELAPI::OMX, AV_HWDEVICE_TYPE_NONE } }, // OpenMAX (Open Media Acceleration). Decoding only.
556
557 #if 0
558 // Additional formats
559 { "CUDA", { false, HWACCELAPI::CUDA, AV_HWDEVICE_TYPE_NONE } }, // Compute Unified Device Architecture, see https://developer.nvidia.com/ffmpeg and https://en.wikipedia.org/wiki/CUDA
560 { "V4L2M2M", { false, HWACCELAPI::V4L2M2M, AV_HWDEVICE_TYPE_NONE } }, // v4l2 mem to mem (Video4linux)
561 { "VDPAU", { false, HWACCELAPI::VDPAU, AV_HWDEVICE_TYPE_NONE } }, // Video Decode and Presentation API for Unix, see https://en.wikipedia.org/wiki/VDPAU
562 { "QSV", { false, HWACCELAPI::QSV, AV_HWDEVICE_TYPE_NONE } }, // QuickSync, see https://trac.ffmpeg.org/wiki/Hardware/QuickSync
563 { "OPENCL", { false, HWACCELAPI::OPENCL, AV_HWDEVICE_TYPE_NONE } }, // Open Standard for Parallel Programming of Heterogeneous Systems, see https://trac.ffmpeg.org/wiki/HWAccelIntro#OpenCL
564 #if HAVE_VULKAN_HWACCEL
565 { "VULKAN", { false, HWACCELAPI::VULKAN, AV_HWDEVICE_TYPE_NONE } }, // Low-overhead, cross-platform 3D graphics and computing API, requires Libavutil >= 56.30.100, see https://en.wikipedia.org/wiki/Vulkan_(API)
566 #endif // HAVE_VULKAN_HWACCEL
567 #if __APPLE__
568 // MacOS, not supported
569 { "VIDEOTOOLBOX", { false, HWACCELAPI::VIDEOTOOLBOX, AV_HWDEVICE_TYPE_NONE } }, // https://trac.ffmpeg.org/wiki/HWAccelIntro#VideoToolbox
570 #endif
571 #if __ANDROID__
572 // Android
573 { "MEDIACODEC", { false, HWACCELAPI::MEDIACODEC, AV_HWDEVICE_TYPE_NONE } }, // See https://developer.android.com/reference/android/media/MediaCodec
574 #endif
575 #if _WIN32
576 // **** Not supported ****
577
578 // Digital Rights Management
579 { "DRM", { false, HWACCELAPI::DRM, AV_HWDEVICE_TYPE_NONE } },
580
581 // Windows only, not supported
582 { "DXVA2", { false, HWACCELAPI::DXVA2, AV_HWDEVICE_TYPE_NONE } }, // Direct3D 9 / DXVA2
583 { "D3D11VA", { false, HWACCELAPI::D3D11VA, AV_HWDEVICE_TYPE_NONE } }, // Direct3D 11
584 #endif
585 #endif
586};
587
592{
593 { "H263", AV_CODEC_ID_H263 },
594 { "H264", AV_CODEC_ID_H264 },
595 { "HEVC", AV_CODEC_ID_HEVC },
596 { "MPEG2", AV_CODEC_ID_MPEG2VIDEO },
597 { "MPEG4", AV_CODEC_ID_MPEG4 },
598 { "VC1", AV_CODEC_ID_VC1 },
599 { "VP8", AV_CODEC_ID_VP8 },
600 { "VP9", AV_CODEC_ID_VP9 },
601 { "WMV3", AV_CODEC_ID_WMV3 },
602};
603
608{
610 { "8", SAMPLE_FMT::FMT_8 },
611 { "16", SAMPLE_FMT::FMT_16 },
612 { "24", SAMPLE_FMT::FMT_24 },
613 { "32", SAMPLE_FMT::FMT_32 },
614 { "64", SAMPLE_FMT::FMT_64 },
615 { "F16", SAMPLE_FMT::FMT_F16 },
616 { "F24", SAMPLE_FMT::FMT_F24 },
617 { "F32", SAMPLE_FMT::FMT_F32 },
618 { "F64", SAMPLE_FMT::FMT_F64 },
619};
620
621static int get_bitrate(const std::string & arg, BITRATE *bitrate);
622static int get_samplerate(const std::string & arg, int * samplerate);
623static int get_sampleformat(const std::string & arg, SAMPLE_FMT * sample_fmt);
624static int get_time(const std::string & arg, time_t *time);
625static int get_size(const std::string & arg, size_t *size);
626static int get_desttype(const std::string & arg, FFMPEGFS_FORMAT_ARR & format);
627static int get_audiocodec(const std::string & arg, AVCodecID *audio_codec);
628static int get_videocodec(const std::string & arg, AVCodecID *video_codec);
629static int get_autocopy(const std::string & arg, AUTOCOPY *autocopy);
630static int get_recodesame(const std::string & arg, RECODESAME *recode);
631static int get_profile(const std::string & arg, PROFILE *profile);
632static int get_level(const std::string & arg, PRORESLEVEL *level);
633static int get_segment_duration(const std::string & arg, int64_t *value);
634static int get_seek_time_diff(const std::string & arg, int64_t *value);
635static int get_hwaccel(const std::string & arg, HWACCELAPI *hwaccel_API, AVHWDeviceType *hwaccel_device_type);
636static int get_codec(const std::string & codec, AVCodecID *codec_id);
637static int get_hwaccel_dec_blocked(const std::string & arg, HWACCEL_BLOCKED_MAP **hwaccel_dec_blocked);
638static int get_value(const std::string & arg, int *value);
639static int get_value(const std::string & arg, std::string *value);
640static int get_value(const std::string & arg, MATCHVEC *value);
641//static int get_value(const std::string & arg, std::optional<std::string> *value);
642static int get_value(const std::string & arg, double *value);
643
644static int ffmpegfs_opt_proc(__attribute__((unused)) void* data, const char* arg, int key, struct fuse_args *outargs);
645static bool set_defaults();
646static void build_device_type_list();
647static void print_params();
648static void usage();
649static void ffmpeg_log(void *ptr, int level, const char *fmt, va_list vl);
650static bool init_logging(const std::string &logfile, const std::string & max_level, bool to_stderr, bool to_syslog);
651
655static void usage()
656{
657 std::string help;
658 size_t pos;
659
660 help.assign(reinterpret_cast<const char*>(ffmpegfshelp), ffmpegfshelp_len);
661 pos = help.find("OPTIONS\n");
662
663 std::cout << help.substr(pos + sizeof("OPTIONS\n"));
664}
665
671template<typename T>
672static void list_options(const char * info, const T & map)
673{
674 std::string buffer;
675 for (typename T::const_iterator it = map.cbegin(); it != map.cend();)
676 {
677 buffer += it->first.c_str();
678
679 if (++it != map.cend())
680 {
681 buffer += ", ";
682 }
683 }
684
685 if (info != nullptr)
686 {
687 std::fprintf(stderr, "%s: %s\n", info, buffer.c_str());
688 }
689 else
690 {
691 std::fprintf(stderr, "%s\n", buffer.c_str());
692 }
693}
694
707static int get_bitrate(const std::string & arg, BITRATE *bitrate)
708{
709 size_t pos = arg.find('=');
710
711 if (pos != std::string::npos)
712 {
713 std::string param(arg.substr(0, pos));
714 std::string data(arg.substr(pos + 1));
715 int reti;
716
717 // Check for decimal number
718 reti = reg_compare(data, "^([1-9][0-9]*|0)?(bps)?$", std::regex::icase);
719
720 if (reti == -1)
721 {
722 return -1;
723 }
724 else if (!reti)
725 {
726 *bitrate = static_cast<BITRATE>(std::stol(data));
727 return 0; // OK
728 }
729
730 // Check for number with optional descimal point and K modifier
731 reti = reg_compare(data, "^[1-9][0-9]*(\\.[0-9]+)?K(bps)?$", std::regex::icase);
732
733 if (reti == -1)
734 {
735 return -1;
736 }
737 else if (!reti)
738 {
739 *bitrate = static_cast<BITRATE>(std::stof(data) * 1000);
740 return 0; // OK
741 }
742
743 // Check for number with optional descimal point and M modifier
744 reti = reg_compare(data, "^[1-9][0-9]*(\\.[0-9]+)?M(bps)?$", std::regex::icase);
745
746 if (reti == -1)
747 {
748 return -1;
749 }
750 else if (!reti)
751 {
752 *bitrate = static_cast<BITRATE>(std::stof(data) * 1000000);
753 return 0; // OK
754 }
755
756 std::fprintf(stderr, "INVALID PARAMETER (%s): Invalid bit rate '%s'\n", param.c_str(), data.c_str());
757 }
758
759 std::fprintf(stderr, "INVALID PARAMETER (%s): Missing argument\n", arg.c_str());
760
761 return -1;
762}
763
775static int get_samplerate(const std::string & arg, int * samplerate)
776{
777 size_t pos = arg.find('=');
778
779 if (pos != std::string::npos)
780 {
781 std::string param(arg.substr(0, pos));
782 std::string data(arg.substr(pos + 1));
783 int reti;
784
785 // Check for decimal number
786 reti = reg_compare(data, "^([1-9][0-9]*|0)(Hz)?$", std::regex::icase);
787
788 if (reti == -1)
789 {
790 return -1;
791 }
792 else if (!reti)
793 {
794 *samplerate = std::stoi(data);
795 return 0; // OK
796 }
797
798 // Check for number with optional descimal point and K modifier
799 reti = reg_compare(data, "^[1-9][0-9]*(\\.[0-9]+)?K(Hz)?$", std::regex::icase);
800
801 if (reti == -1)
802 {
803 return -1;
804 }
805 else if (!reti)
806 {
807 *samplerate = static_cast<int>(std::stof(data) * 1000);
808 return 0; // OK
809 }
810
811 std::fprintf(stderr, "INVALID PARAMETER (%s): Invalid sample rate '%s'\n", param.c_str(), data.c_str());
812 }
813 else
814 {
815 std::fprintf(stderr, "INVALID PARAMETER (%s): Missing argument\n", arg.c_str());
816 }
817
818 return -1;
819}
820
827static int get_sampleformat(const std::string & arg, SAMPLE_FMT * sample_fmt)
828{
829 size_t pos = arg.find('=');
830
831 *sample_fmt = SAMPLE_FMT::FMT_DONTCARE;
832
833 if (pos != std::string::npos)
834 {
835 std::string param(arg.substr(0, pos));
836 std::string data(arg.substr(pos + 1));
837
838 SAMPLE_FMT_MAP::const_iterator it = sample_fmt_map.find(data);
839
840 if (it == sample_fmt_map.cend())
841 {
842 std::fprintf(stderr, "INVALID PARAMETER (%s): Invalid sample format option: %s\n", param.c_str(), data.c_str());
843
844 list_options("Valid sample formats are", sample_fmt_map);
845
846 return -1;
847 }
848
849 // May fail later: Can only be checked when destination format is known.
850 *sample_fmt = it->second;
851
852 return 0;
853 }
854
855 std::fprintf(stderr, "INVALID PARAMETER (%s): Missing argument\n", arg.c_str());
856
857 return -1;
858
859}
860
861std::string get_sampleformat_text(SAMPLE_FMT sample_fmt)
862{
863 SAMPLE_FMT_MAP::const_iterator it = search_by_value(sample_fmt_map, sample_fmt);
864 if (it != sample_fmt_map.cend())
865 {
866 return it->first;
867 }
868 return "INVALID";
869}
870
885static int get_time(const std::string & arg, time_t *time)
886{
887 size_t pos = arg.find('=');
888
889 if (pos != std::string::npos)
890 {
891 std::string param(arg.substr(0, pos));
892 std::string data(arg.substr(pos + 1));
893 int reti;
894
895 // Check for decimal number
896 reti = reg_compare(data, "^([1-9][0-9]*|0)?s?$", std::regex::icase);
897
898 if (reti == -1)
899 {
900 return -1;
901 }
902 else if (!reti)
903 {
904 *time = static_cast<time_t>(std::stol(data));
905 return 0; // OK
906 }
907
908 // Check for number with optional descimal point and m modifier
909 reti = reg_compare(data, "^[1-9][0-9]*(\\.[0-9]+)?m$", std::regex::icase);
910
911 if (reti == -1)
912 {
913 return -1;
914 }
915 else if (!reti)
916 {
917 *time = static_cast<time_t>(std::stof(data) * 60);
918 return 0; // OK
919 }
920
921 // Check for number with optional descimal point and h modifier
922 reti = reg_compare(data, "^[1-9][0-9]*(\\.[0-9]+)?h$", std::regex::icase);
923
924 if (reti == -1)
925 {
926 return -1;
927 }
928 else if (!reti)
929 {
930 *time = static_cast<time_t>(std::stof(data) * 60 * 60);
931 return 0; // OK
932 }
933
934 // Check for number with optional descimal point and d modifier
935 reti = reg_compare(data, "^[1-9][0-9]*(\\.[0-9]+)?d$", std::regex::icase);
936
937 if (reti == -1)
938 {
939 return -1;
940 }
941 else if (!reti)
942 {
943 *time = static_cast<time_t>(std::stof(data) * 60 * 60 * 24);
944 return 0; // OK
945 }
946
947 // Check for number with optional descimal point and w modifier
948 reti = reg_compare(data, "^[1-9][0-9]*(\\.[0-9]+)?w$", std::regex::icase);
949
950 if (reti == -1)
951 {
952 return -1;
953 }
954 else if (!reti)
955 {
956 *time = static_cast<time_t>(std::stof(data) * 60 * 60 * 24 * 7);
957 return 0; // OK
958 }
959
960 std::fprintf(stderr, "INVALID PARAMETER (%s): Invalid time format '%s'\n", param.c_str(), data.c_str());
961 }
962 else
963 {
964 std::fprintf(stderr, "INVALID PARAMETER (%s): Invalid time format\n", arg.c_str());
965 }
966
967 return -1;
968}
969
984static int get_size(const std::string & arg, size_t *size)
985{
986 size_t pos = arg.find('=');
987
988 if (pos != std::string::npos)
989 {
990 std::string param(arg.substr(0, pos));
991 std::string data(arg.substr(pos + 1));
992 int reti;
993
994 // Check for decimal number
995 reti = reg_compare(data, "^([1-9][0-9]*|0)?B?$", std::regex::icase);
996
997 if (reti == -1)
998 {
999 return -1;
1000 }
1001 else if (!reti)
1002 {
1003 *size = static_cast<size_t>(std::stol(data));
1004 return 0; // OK
1005 }
1006
1007 // Check for number with optional descimal point and K/KB modifier
1008 reti = reg_compare(data, "^[1-9][0-9]*(\\.[0-9]+)?KB?$", std::regex::icase);
1009
1010 if (reti == -1)
1011 {
1012 return -1;
1013 }
1014 else if (!reti)
1015 {
1016 *size = static_cast<size_t>(std::stof(data) * 1024);
1017 return 0; // OK
1018 }
1019
1020 // Check for number with optional descimal point and M/MB modifier
1021 reti = reg_compare(data, "^[1-9][0-9]*(\\.[0-9]+)?MB?$", std::regex::icase);
1022
1023 if (reti == -1)
1024 {
1025 return -1;
1026 }
1027 else if (!reti)
1028 {
1029 *size = static_cast<size_t>(std::stof(data) * 1024 * 1024);
1030 return 0; // OK
1031 }
1032
1033 // Check for number with optional descimal point and G/GB modifier
1034 reti = reg_compare(data, "^[1-9][0-9]*(\\.[0-9]+)?GB?$", std::regex::icase);
1035
1036 if (reti == -1)
1037 {
1038 return -1;
1039 }
1040 else if (!reti)
1041 {
1042 *size = static_cast<size_t>(std::stof(data) * 1024 * 1024 * 1024);
1043 return 0; // OK
1044 }
1045
1046 // Check for number with optional descimal point and T/TB modifier
1047 reti = reg_compare(data, "^[1-9][0-9]*(\\.[0-9]+)?TB?$", std::regex::icase);
1048
1049 if (reti == -1)
1050 {
1051 return -1;
1052 }
1053 else if (!reti)
1054 {
1055 *size = static_cast<size_t>(std::stof(data) * 1024 * 1024 * 1024 * 1024);
1056 return 0; // OK
1057 }
1058
1059 std::fprintf(stderr, "INVALID PARAMETER (%s): Invalid size '%s'\n", param.c_str(), data.c_str());
1060 }
1061 else
1062 {
1063 std::fprintf(stderr, "INVALID PARAMETER (%s): Invalid size\n", arg.c_str());
1064 }
1065
1066 return -1;
1067}
1068
1076static int get_desttype(const std::string & arg, FFMPEGFS_FORMAT_ARR & format)
1077{
1078 size_t pos = arg.find('=');
1079
1080 if (pos != std::string::npos)
1081 {
1082 std::string param(arg.substr(0, pos));
1083 std::vector<std::string> results = split(arg.substr(pos + 1), "\\+");
1084
1085 if (results.size() > 0 && results.size() < 3)
1086 {
1087 // Check for valid destination type and obtain codecs and file type.
1088 if (!format[0].init(results[0]))
1089 {
1090 std::fprintf(stderr, "INVALID PARAMETER (%s): No codecs available for desttype: %s\n", param.c_str(), results[0].c_str());
1091 return 1;
1092 }
1093
1094 if (results.size() == 2)
1095 {
1096 if (format[0].video_codec() == AV_CODEC_ID_NONE)
1097 {
1098 std::fprintf(stderr, "INVALID PARAMETER (%s): First format %s does not support video\n", param.c_str(), results[0].c_str());
1099 return 1;
1100 }
1101
1102 if (!format[1].init(results[1]))
1103 {
1104 std::fprintf(stderr, "INVALID PARAMETER (%s): No codecs available for desttype: %s\n", param.c_str(), results[1].c_str());
1105 return 1;
1106 }
1107
1108 if (format[1].video_codec() != AV_CODEC_ID_NONE)
1109 {
1110 std::fprintf(stderr, "INVALID PARAMETER (%s): Second format %s should be audio only\n", param.c_str(), results[1].c_str());
1111 return 1;
1112 }
1113 }
1114
1115 return 0;
1116 }
1117 }
1118
1119 std::fprintf(stderr, "INVALID PARAMETER (%s): Missing argument\n", arg.c_str());
1120
1121 return -1;
1122}
1123
1130static int get_audiocodec(const std::string & arg, AVCodecID *audio_codec)
1131{
1132 *audio_codec = AV_CODEC_ID_NONE;
1133
1134 size_t pos = arg.find('=');
1135
1136 if (pos != std::string::npos)
1137 {
1138 std::string param(arg.substr(0, pos));
1139 std::string data(arg.substr(pos + 1));
1140
1141 AUDIOCODEC_MAP::const_iterator it = audiocodec_map.find(data);
1142
1143 if (it == audiocodec_map.cend())
1144 {
1145 std::fprintf(stderr, "INVALID PARAMETER (%s): Invalid videocodec option: %s\n", param.c_str(), data.c_str());
1146
1147 list_options("Valid audio codecs", audiocodec_map);
1148
1149 return -1;
1150 }
1151
1152 *audio_codec = it->second;
1153
1154 return 0;
1155 }
1156
1157 std::fprintf(stderr, "INVALID PARAMETER (%s): Missing argument\n", arg.c_str());
1158
1159 return -1;
1160}
1161
1168static int get_videocodec(const std::string & arg, AVCodecID *video_codec)
1169{
1170 *video_codec = AV_CODEC_ID_NONE;
1171
1172 size_t pos = arg.find('=');
1173
1174 if (pos != std::string::npos)
1175 {
1176 std::string param(arg.substr(0, pos));
1177 std::string data(arg.substr(pos + 1));
1178
1179 VIDEOCODEC_MAP::const_iterator it = videocodec_map.find(data);
1180
1181 if (it == videocodec_map.cend())
1182 {
1183 std::fprintf(stderr, "INVALID PARAMETER (%s): Invalid videocodec option: %s\n", param.c_str(), data.c_str());
1184
1185 list_options("Valid video codecs", videocodec_map);
1186
1187 return -1;
1188 }
1189
1190 *video_codec = it->second;
1191
1192 return 0;
1193 }
1194
1195 std::fprintf(stderr, "INVALID PARAMETER (%s): Missing argument\n", arg.c_str());
1196
1197 return -1;
1198}
1199
1206static int get_autocopy(const std::string & arg, AUTOCOPY *autocopy)
1207{
1208 size_t pos = arg.find('=');
1209
1210 if (pos != std::string::npos)
1211 {
1212 std::string param(arg.substr(0, pos));
1213 std::string data(arg.substr(pos + 1));
1214
1215 AUTOCOPY_MAP::const_iterator it = autocopy_map.find(data);
1216
1217 if (it == autocopy_map.cend())
1218 {
1219 std::fprintf(stderr, "INVALID PARAMETER (%s): Invalid autocopy option: %s\n", param.c_str(), data.c_str());
1220
1221 list_options("Valid autocopy options are", autocopy_map);
1222
1223 return -1;
1224 }
1225
1226 *autocopy = it->second;
1227
1228 return 0;
1229 }
1230
1231 std::fprintf(stderr, "INVALID PARAMETER (%s): Missing argument\n", arg.c_str());
1232
1233 return -1;
1234}
1235
1236std::string get_audio_codec_text(AVCodecID audio_codec)
1237{
1238 AUDIOCODEC_MAP::const_iterator it = search_by_value(audiocodec_map, audio_codec);
1239 if (it != audiocodec_map.cend())
1240 {
1241 return it->first;
1242 }
1243 return "INVALID";
1244}
1245
1246std::string get_video_codec_text(AVCodecID video_codec)
1247{
1248 AUDIOCODEC_MAP::const_iterator it = search_by_value(videocodec_map, video_codec);
1249 if (it != videocodec_map.cend())
1250 {
1251 return it->first;
1252 }
1253 return "INVALID";
1254}
1255
1256std::string get_autocopy_text(AUTOCOPY autocopy)
1257{
1258 AUTOCOPY_MAP::const_iterator it = search_by_value(autocopy_map, autocopy);
1259 if (it != autocopy_map.cend())
1260 {
1261 return it->first;
1262 }
1263 return "INVALID";
1264}
1265
1272static int get_recodesame(const std::string & arg, RECODESAME *recode)
1273{
1274 size_t pos = arg.find('=');
1275
1276 if (pos != std::string::npos)
1277 {
1278 std::string param(arg.substr(0, pos));
1279 std::string data(arg.substr(pos + 1));
1280
1281 RECODESAME_MAP::const_iterator it = recode_map.find(data);
1282
1283 if (it == recode_map.cend())
1284 {
1285 std::fprintf(stderr, "INVALID PARAMETER (%s): Invalid recode option: %s\n", param.c_str(), data.c_str());
1286
1287 list_options("Valid recode options are", recode_map);
1288
1289 return -1;
1290 }
1291
1292 *recode = it->second;
1293
1294 return 0;
1295 }
1296
1297 std::fprintf(stderr, "INVALID PARAMETER (%s): Missing argument\n", arg.c_str());
1298
1299 return -1;
1300}
1301
1303{
1304 RECODESAME_MAP::const_iterator it = search_by_value(recode_map, recode);
1305 if (it != recode_map.cend())
1306 {
1307 return it->first;
1308 }
1309 return "INVALID";
1310}
1311
1318static int get_profile(const std::string & arg, PROFILE *profile)
1319{
1320 size_t pos = arg.find('=');
1321
1322 if (pos != std::string::npos)
1323 {
1324 std::string param(arg.substr(0, pos));
1325 std::string data(arg.substr(pos + 1));
1326
1327 PROFILE_MAP::const_iterator it = profile_map.find(data);
1328
1329 if (it == profile_map.cend())
1330 {
1331 std::fprintf(stderr, "INVALID PARAMETER (%s): Invalid profile: %s\n", param.c_str(), data.c_str());
1332
1333 list_options("Valid profiles are", profile_map);
1334
1335 return -1;
1336 }
1337
1338 *profile = it->second;
1339
1340 return 0;
1341 }
1342
1343 std::fprintf(stderr, "INVALID PARAMETER (%s): Missing argument\n", arg.c_str());
1344
1345 return -1;
1346}
1347
1348std::string get_profile_text(PROFILE profile)
1349{
1350 PROFILE_MAP::const_iterator it = search_by_value(profile_map, profile);
1351 if (it != profile_map.cend())
1352 {
1353 return it->first;
1354 }
1355 return "INVALID";
1356}
1357
1358// Read level
1365static int get_level(const std::string & arg, PRORESLEVEL *level)
1366{
1367 size_t pos = arg.find('=');
1368
1369 if (pos != std::string::npos)
1370 {
1371 std::string param(arg.substr(0, pos));
1372 std::string data(arg.substr(pos + 1));
1373
1374 LEVEL_MAP::const_iterator it = prores_level_map.find(data);
1375
1376 if (it == prores_level_map.cend())
1377 {
1378 std::fprintf(stderr, "INVALID PARAMETER (%s): Invalid level: %s\n", param.c_str(), data.c_str());
1379
1380 list_options("Valid levels are", prores_level_map);
1381
1382 return -1;
1383 }
1384
1385 *level = it->second;
1386
1387 return 0;
1388 }
1389
1390 std::fprintf(stderr, "INVALID PARAMETER (%s): Missing argument\n", arg.c_str());
1391
1392 return -1;
1393}
1394
1395// Get level text
1396std::string get_level_text(PRORESLEVEL level)
1397{
1398 LEVEL_MAP::const_iterator it = search_by_value(prores_level_map, level);
1399 if (it != prores_level_map.cend())
1400 {
1401 return it->first;
1402 }
1403 return "INVALID";
1404}
1405
1412static int get_segment_duration(const std::string & arg, int64_t *value)
1413{
1414 double duration;
1415 if (get_value(arg, &duration) < 0)
1416 {
1417 return -1;
1418 }
1419
1420 if (*value <= 0)
1421 {
1422 std::fprintf(stderr, "INVALID PARAMETER: segment_duration %.1f is out of range. For obvious reasons this must be greater than zero.\n", duration);
1423 return -1;
1424 }
1425
1426 *value = static_cast<int>(duration * AV_TIME_BASE);
1427
1428 return 0;
1429}
1430
1437static int get_seek_time_diff(const std::string & arg, int64_t *value)
1438{
1439 double duration;
1440 if (get_value(arg, &duration) < 0)
1441 {
1442 return -1;
1443 }
1444
1445 if (*value <= 0)
1446 {
1447 std::fprintf(stderr, "INVALID PARAMETER: seek time %.1f is out of range. For obvious reasons this must be greater than or equal zero.\n", duration);
1448 return -1;
1449 }
1450
1451 *value = static_cast<int>(duration * AV_TIME_BASE);
1452
1453 return 0;
1454}
1455
1465static int get_hwaccel(const std::string & arg, HWACCELAPI *hwaccel_API, AVHWDeviceType *hwaccel_device_type)
1466{
1467 size_t pos = arg.find('=');
1468
1469 if (pos != std::string::npos)
1470 {
1471 std::string param(arg.substr(0, pos));
1472 std::string data(arg.substr(pos + 1));
1473
1474 HWACCEL_MAP::const_iterator it = hwaccel_map.find(data);
1475
1476 if (it == hwaccel_map.cend())
1477 {
1478 std::fprintf(stderr, "INVALID PARAMETER (%s): Invalid hardware acceleration API: %s\n", param.c_str(), data.c_str());
1479
1480 list_options("Valid hardware acceleration APIs are", hwaccel_map);
1481
1482 return -1;
1483 }
1484
1485 const HWACCEL & hwaccel = it->second;
1486
1487 if (!hwaccel.m_supported)
1488 {
1489 std::fprintf(stderr, "INVALID PARAMETER (%s): Unsupported hardware acceleration API: %s\n", param.c_str(), data.c_str());
1490 return -1;
1491 }
1492
1493 *hwaccel_API = hwaccel.m_hwaccel_API;
1494 *hwaccel_device_type = hwaccel.m_hwaccel_device_type;
1495 return 0;
1496 }
1497
1498 std::fprintf(stderr, "INVALID PARAMETER (%s): Missing argument\n", arg.c_str());
1499
1500 return -1;
1501}
1502
1509static int get_codec(const std::string & codec, AVCodecID *codec_id)
1510{
1511 CODEC_MAP::const_iterator it = hwaccel_codec_map.find(codec);
1512
1513 if (it == hwaccel_codec_map.cend())
1514 {
1515 std::fprintf(stderr, "INVALID PARAMETER: Unknown codec '%s'.\n", codec.c_str());
1516
1517 list_options("Valid hardware acceleration APIs are", hwaccel_codec_map);
1518
1519 *codec_id = AV_CODEC_ID_NONE;
1520 return -1;
1521 }
1522
1523 *codec_id = it->second;
1524
1525 return 0;
1526}
1527
1534static int get_hwaccel_dec_blocked(const std::string & arg, HWACCEL_BLOCKED_MAP **hwaccel_dec_blocked)
1535{
1536 size_t pos = arg.find('=');
1537
1538 if (pos != std::string::npos)
1539 {
1540 std::string param(arg.substr(0, pos));
1541 std::stringstream data(arg.substr(pos + 1));
1542 std::string codec;
1543
1544 if (*hwaccel_dec_blocked == nullptr)
1545 {
1546 *hwaccel_dec_blocked = new (std::nothrow) HWACCEL_BLOCKED_MAP;
1547 }
1548
1549 if (!std::getline(data, codec, ':'))
1550 {
1551 std::fprintf(stderr, "INVALID PARAMETER (%s): Missing argument\n", param.c_str());
1552 return -1;
1553 }
1554
1555 AVCodecID codec_id;
1556
1557 if (get_codec(codec, &codec_id))
1558 {
1559 std::fprintf(stderr, "INVALID PARAMETER (%s): Unknown codec '%s'\n", param.c_str(), codec.c_str());
1560 return -1;
1561 }
1562
1563 int nProfilesFound = 0;
1564 for (std::string profile; std::getline(data, profile, ':');)
1565 {
1566 nProfilesFound++;
1567 // Block codec and profile
1568 (*hwaccel_dec_blocked)->insert(std::pair<AVCodecID, int>(codec_id, std::stoi(profile)));
1569 }
1570
1571 if (!nProfilesFound)
1572 {
1573 // No profile
1574 (*hwaccel_dec_blocked)->insert(std::pair<AVCodecID, int>(codec_id, FF_PROFILE_UNKNOWN));
1575 }
1576
1577 return 0;
1578 }
1579
1580 std::fprintf(stderr, "INVALID PARAMETER (%s): Missing argument\n", arg.c_str());
1581
1582 return -1;
1583}
1584
1585bool check_hwaccel_dec_blocked(AVCodecID codec_id, int profile)
1586{
1587 if (params.m_hwaccel_dec_blocked == nullptr)
1588 {
1589 return false; // Nothing blocked
1590 }
1591
1592 for (HWACCEL_BLOCKED_MAP::const_iterator it = params.m_hwaccel_dec_blocked->find(codec_id); it != params.m_hwaccel_dec_blocked->cend(); ++it)
1593 {
1594 if (it->first == codec_id && (it->second == profile || it->second == FF_PROFILE_UNKNOWN))
1595 {
1596 return true;
1597 }
1598 }
1599
1600 return false;
1601}
1602
1603std::string get_hwaccel_API_text(HWACCELAPI hwaccel_API)
1604{
1605 HWACCEL_MAP::const_iterator it = hwaccel_map.cbegin();
1606 while (it != hwaccel_map.cend())
1607 {
1608 if (it->second.m_hwaccel_API == hwaccel_API)
1609 {
1610 return it->first;
1611 }
1612 ++it;
1613 }
1614
1615 return "INVALID";
1616}
1617
1625static int get_value(const std::string & arg, int *value)
1626{
1627 size_t pos = arg.find('=');
1628
1629 if (pos != std::string::npos)
1630 {
1631 *value = std::stoi(arg.substr(pos + 1));
1632
1633 return 0;
1634 }
1635
1636 std::fprintf(stderr, "INVALID PARAMETER (%s): Missing argument\n", arg.c_str());
1637
1638 return -1;
1639}
1640
1648static int get_value(const std::string & arg, std::string *value)
1649{
1650 size_t pos = arg.find('=');
1651
1652 if (pos != std::string::npos)
1653 {
1654 *value = arg.substr(pos + 1);
1655
1656 return 0;
1657 }
1658
1659 std::fprintf(stderr, "INVALID PARAMETER (%s): Missing argument\n", arg.c_str());
1660
1661 return -1;
1662}
1663
1671static int get_value(const std::string & arg, MATCHVEC *value)
1672{
1673 size_t pos = arg.find('=');
1674
1675 if (pos != std::string::npos)
1676 {
1677 std::vector<std::string> v = split(arg.substr(pos + 1), ",");
1678
1679 for (const std::string & str : v)
1680 {
1681 int res = fnmatch(str.c_str(), "", 0);
1682
1683 if (res != 0 && res != FNM_NOMATCH)
1684 {
1685 std::fprintf(stderr, "INVALID PARAMETER (%s): Error in wildcard pattern\n", str.c_str());
1686
1687 return -1;
1688 }
1689 }
1690
1691 value->insert(value->end(), v.begin(), v.end());
1692
1693 return 0;
1694 }
1695
1696 std::fprintf(stderr, "INVALID PARAMETER (%s): Missing argument\n", arg.c_str());
1697
1698 return -1;
1699}
1700
1701#if 0
1709static int get_value(const std::string & arg, std::optional<std::string> *value)
1710{
1711 size_t pos = arg.find('=');
1712
1713 if (pos != std::string::npos)
1714 {
1715 *value = arg.substr(pos + 1);
1716
1717 return 0;
1718 }
1719
1720 std::fprintf(stderr, "INVALID PARAMETER (%s): Missing argument\n", arg.c_str());
1721
1722 return -1;
1723}
1724#endif
1725
1733static int get_value(const std::string & arg, double *value)
1734{
1735 size_t pos = arg.find('=');
1736
1737 if (pos != std::string::npos)
1738 {
1739 *value = std::stof(arg.substr(pos + 1));
1740
1741 return 0;
1742 }
1743
1744 std::fprintf(stderr, "INVALID PARAMETER (%s): Missing argument\n", arg.c_str());
1745
1746 return -1;
1747}
1748
1757static int ffmpegfs_opt_proc(__attribute__((unused)) void* data, const char* arg, int key, struct fuse_args *outargs)
1758{
1759 switch (key)
1760 {
1761 case FUSE_OPT_KEY_NONOPT:
1762 {
1763 static int n;
1764
1765 // check for basepath and bitrate parameters
1766 if (n == 0 && params.m_basepath.empty())
1767 {
1771 n++;
1772 return 0;
1773 }
1774 else if (n == 1 && params.m_mountpath.empty())
1775 {
1779 if (!docker_client)
1780 {
1781 switch (is_mount(params.m_mountpath))
1782 {
1783 case 1:
1784 {
1785 std::fprintf(stderr, "%-25s: already mounted\n", params.m_mountpath.c_str());
1786 exit(1);
1787 }
1788 //case -1:
1789 //{
1790 // // Error already reported
1791 // exit(1);
1792 //}
1793 }
1794 }
1795
1796 n++;
1797 return 1;
1798 }
1799
1800 break;
1801 }
1802 case KEY_HELP:
1803 {
1804 usage();
1805 fuse_opt_add_arg(outargs, "-ho");
1806 fuse_main(outargs->argc, outargs->argv, &ffmpegfs_ops, nullptr);
1807 exit(1);
1808 }
1809 case KEY_VERSION:
1810 {
1811 std::printf("-------------------------------------------------------------------------------------------\n");
1812
1813#ifdef __GNUC__
1814#ifndef __clang_version__
1815 std::printf("%-20s: %s (%s)\n", "Built with", "gcc " __VERSION__, HOST_OS);
1816#else
1817 std::printf("%-20s: %s (%s)\n", "Built with", "clang " __clang_version__, HOST_OS);
1818#endif
1819#endif
1820 std::printf("%-20s: %s\n\n", "configuration", CONFIGURE_ARGS);
1821
1822 std::printf("%-20s: %s\n", PACKAGE_NAME " Version", FFMPEFS_VERSION);
1823
1824 std::printf("%s", ffmpeg_libinfo().c_str());
1825
1826#ifdef USE_LIBVCD
1827 std::printf("%-20s: %s\n", "Video CD Library", "enabled");
1828#endif // USE_LIBVCD
1829#ifdef USE_LIBDVD
1830 std::printf("%-20s: %s\n", "DVD Library", "enabled");
1831#endif // USE_LIBDVD
1832#ifdef USE_LIBBLURAY
1833 std::printf("%-20s: %s\n", "Blu-ray Library", BLURAY_VERSION_STRING);
1834#endif // USE_LIBBLURAY
1835
1836 fuse_opt_add_arg(outargs, "--version");
1837 fuse_main(outargs->argc, outargs->argv, &ffmpegfs_ops, nullptr);
1838
1839 exit(0);
1840 }
1841 case KEY_FFMPEG_CAPS:
1842 {
1843 std::printf("-------------------------------------------------------------------------------------------\n\n");
1844
1845 std::printf("%-20s: %s\n", PACKAGE_NAME " Version", FFMPEFS_VERSION);
1846 std::printf("%s", ffmpeg_libinfo().c_str());
1847
1848 std::printf("\nFFMpeg Capabilities\n\n");
1849
1850 show_caps(0);
1851
1852 exit(0);
1853 }
1854 case KEY_DESTTYPE:
1855 {
1856 return get_desttype(arg, ffmpeg_format);
1857 }
1858 case KEY_AUDIOCODEC:
1859 {
1860 return get_audiocodec(arg, &params.m_audio_codec);
1861 }
1862 case KEY_VIDEOCODEC:
1863 {
1864 return get_videocodec(arg, &params.m_video_codec);
1865 }
1866 case KEY_AUTOCOPY:
1867 {
1868 return get_autocopy(arg, &params.m_autocopy);
1869 }
1870 case KEY_RECODESAME:
1871 {
1872 return get_recodesame(arg, &params.m_recodesame);
1873 }
1874 case KEY_PROFILE:
1875 {
1876 return get_profile(arg, &params.m_profile);
1877 }
1878 case KEY_LEVEL:
1879 {
1880 return get_level(arg, &params.m_level);
1881 }
1882 case KEY_AUDIO_BITRATE:
1883 {
1884 return get_bitrate(arg, &params.m_audiobitrate);
1885 }
1886 case KEY_AUDIO_SAMPLERATE:
1887 {
1889 }
1890 case KEY_AUDIO_CHANNELS:
1891 {
1892 return get_value(arg, &params.m_audiochannels);
1893 }
1894 case KEY_AUDIO_SAMPLE_FMT:
1895 {
1896 return get_sampleformat(arg, &params.m_sample_fmt);
1897 }
1898 case KEY_SCRIPTFILE:
1899 {
1900 return get_value(arg, &params.m_scriptfile);
1901 }
1902 case KEY_SCRIPTSOURCE:
1903 {
1904 return get_value(arg, &params.m_scriptsource);
1905 }
1906 case KEY_VIDEO_BITRATE:
1907 {
1908 return get_bitrate(arg, &params.m_videobitrate);
1909 }
1910 case KEY_SEGMENT_DURATION:
1911 {
1913 }
1914 case KEY_MIN_SEEK_TIME_DIFF:
1915 {
1917 }
1918 case KEY_HWACCEL_ENCODER_API:
1919 {
1921 }
1922 case KEY_HWACCEL_ENCODER_DEVICE:
1923 {
1925 }
1926 case KEY_HWACCEL_DECODER_API:
1927 {
1929 }
1930 case KEY_HWACCEL_DECODER_DEVICE:
1931 {
1933 }
1934 case KEY_HWACCEL_DECODER_BLOCKED:
1935 {
1937 }
1938 case KEY_EXPIRY_TIME:
1939 {
1940 return get_time(arg, &params.m_expiry_time);
1941 }
1942 case KEY_MAX_INACTIVE_SUSPEND_TIME:
1943 {
1945 }
1946 case KEY_MAX_INACTIVE_ABORT_TIME:
1947 {
1948 return get_time(arg, &params.m_max_inactive_abort);
1949 }
1950 case KEY_PREBUFFER_TIME:
1951 {
1952 return get_time(arg, &params.m_prebuffer_time);
1953 }
1954 case KEY_PREBUFFER_SIZE:
1955 {
1956 return get_size(arg, &params.m_prebuffer_size);
1957 }
1958 case KEY_MAX_CACHE_SIZE:
1959 {
1960 return get_size(arg, &params.m_max_cache_size);
1961 }
1962 case KEY_MIN_DISKSPACE_SIZE:
1963 {
1964 return get_size(arg, &params.m_min_diskspace);
1965 }
1966 case KEY_CACHEPATH:
1967 {
1968 return get_value(arg, &params.m_cachepath);
1969 }
1970 case KEY_CACHE_MAINTENANCE:
1971 {
1972 return get_time(arg, &params.m_cache_maintenance);
1973 }
1974 case KEY_LOG_MAXLEVEL:
1975 {
1976 return get_value(arg, &params.m_log_maxlevel);
1977 }
1978 case KEY_LOGFILE:
1979 {
1980 std::string logfile;
1981 int res = get_value(arg, &logfile);
1982
1983 if (res)
1984 {
1985 return res;
1986 }
1987
1988 expand_path(&params.m_logfile, logfile);
1990
1991 return 0;
1992 }
1993 case KEY_INCLUDE_EXTENSIONS:
1994 {
1995 return get_value(arg, params.m_include_extensions.get());
1996 }
1997 case KEY_HIDE_EXTENSIONS:
1998 {
1999 return get_value(arg, params.m_hide_extensions.get());
2000 }
2001 }
2002
2003 return 1;
2004}
2005
2010static bool set_defaults()
2011{
2012 if (ffmpeg_format[FORMAT::VIDEO].video_codec() == AV_CODEC_ID_PRORES)
2013 {
2015 {
2017 }
2018 }
2019
2020 return true;
2021}
2022
2029{
2030 for (AVHWDeviceType device_type = AV_HWDEVICE_TYPE_NONE; (device_type = av_hwdevice_iterate_types(device_type)) != AV_HWDEVICE_TYPE_NONE;)
2031 {
2032 HWACCEL_MAP::iterator it = hwaccel_map.find(av_hwdevice_get_type_name(device_type));
2033
2034 if (it == hwaccel_map.end())
2035 {
2036 continue;
2037 }
2038
2039 it->second.m_hwaccel_device_type = device_type;
2040 }
2041}
2042
2046static void print_params()
2047{
2048 std::string cachepath;
2049
2050 transcoder_cache_path(&cachepath);
2051
2052 Logging::trace(nullptr, "********* " PACKAGE_NAME " Options *********");
2053 Logging::trace(nullptr, "Base Path : %1", params.m_basepath.c_str());
2054 Logging::trace(nullptr, "Mount Path : %1", params.m_mountpath.c_str());
2055 Logging::trace(nullptr, "--------- Format ---------");
2056 if (ffmpeg_format[FORMAT::AUDIO].filetype() != FILETYPE::UNKNOWN)
2057 {
2058 Logging::trace(nullptr, "Audio File Type : %1", ffmpeg_format[FORMAT::AUDIO].desttype().c_str());
2059 if (ffmpeg_format[FORMAT::AUDIO].audio_codec() != AV_CODEC_ID_NONE)
2060 {
2061 Logging::trace(nullptr, "Audio Codec : %1 (%2)", get_codec_name(ffmpeg_format[FORMAT::AUDIO].audio_codec(), false), get_codec_name(ffmpeg_format[FORMAT::AUDIO].audio_codec(), true));
2062 }
2063 Logging::trace(nullptr, "Video File Type : %1", ffmpeg_format[FORMAT::VIDEO].desttype().c_str());
2064 if (ffmpeg_format[FORMAT::VIDEO].audio_codec() != AV_CODEC_ID_NONE)
2065 {
2066 Logging::trace(nullptr, "Audio Codec : %1 (%2)", get_codec_name(ffmpeg_format[FORMAT::VIDEO].audio_codec(), false), get_codec_name(ffmpeg_format[FORMAT::VIDEO].audio_codec(), true));
2067 }
2068 if (ffmpeg_format[FORMAT::VIDEO].video_codec() != AV_CODEC_ID_NONE)
2069 {
2070 Logging::trace(nullptr, "Video Codec : %1 (%2)", get_codec_name(ffmpeg_format[FORMAT::VIDEO].video_codec(), false), get_codec_name(ffmpeg_format[FORMAT::VIDEO].video_codec(), true));
2071 }
2072 }
2073 else
2074 {
2075 Logging::trace(nullptr, "File Type : %1", ffmpeg_format[FORMAT::VIDEO].desttype().c_str());
2076 if (ffmpeg_format[FORMAT::VIDEO].audio_codec() != AV_CODEC_ID_NONE)
2077 {
2078 Logging::trace(nullptr, "Audio Codec : %1 (%2)", get_codec_name(ffmpeg_format[FORMAT::VIDEO].audio_codec(), false), get_codec_name(ffmpeg_format[FORMAT::VIDEO].audio_codec(), true));
2079 }
2080 if (ffmpeg_format[FORMAT::VIDEO].video_codec() != AV_CODEC_ID_NONE)
2081 {
2082 Logging::trace(nullptr, "Video Codec : %1 (%2)", get_codec_name(ffmpeg_format[FORMAT::VIDEO].video_codec(), false), get_codec_name(ffmpeg_format[FORMAT::VIDEO].video_codec(), true));
2083 }
2084 }
2085 Logging::trace(nullptr, "Smart Transcode : %1", params.smart_transcode() ? "yes" : "no");
2086 Logging::trace(nullptr, "Auto Copy : %1", get_autocopy_text(params.m_autocopy).c_str());
2087 Logging::trace(nullptr, "Recode to same fmt: %1", get_recodesame_text(params.m_recodesame).c_str());
2088 Logging::trace(nullptr, "Profile : %1", get_profile_text(params.m_profile).c_str());
2089 Logging::trace(nullptr, "Level : %1", get_level_text(params.m_level).c_str());
2090 Logging::trace(nullptr, "Include Extensions: %1", implode(*params.m_include_extensions).c_str());
2091 Logging::trace(nullptr, "Hide Extensions : %1", implode(*params.m_hide_extensions).c_str());
2092 Logging::trace(nullptr, "--------- Audio ---------");
2093 Logging::trace(nullptr, "Codecs : %1+%2", get_codec_name(ffmpeg_format[FORMAT::VIDEO].audio_codec(), true), get_codec_name(ffmpeg_format[FORMAT::AUDIO].audio_codec(), true));
2094 Logging::trace(nullptr, "Bitrate : %1", format_bitrate(params.m_audiobitrate).c_str());
2095 Logging::trace(nullptr, "Sample Rate : %1", format_samplerate(params.m_audiosamplerate).c_str());
2096 Logging::trace(nullptr, "Max. Channels : %1", params.m_audiochannels);
2098 {
2099 Logging::trace(nullptr, "Sample Format : %1", get_sampleformat_text(params.m_sample_fmt).c_str());
2100 }
2101 Logging::trace(nullptr, "--------- Video ---------");
2102 Logging::trace(nullptr, "Codec : %1", get_codec_name(ffmpeg_format[FORMAT::VIDEO].video_codec(), true));
2103 Logging::trace(nullptr, "Bitrate : %1", format_bitrate(params.m_videobitrate).c_str());
2104 Logging::trace(nullptr, "Dimension : width=%1 height=%2", format_number(params.m_videowidth).c_str(), format_number(params.m_videoheight).c_str());
2105 Logging::trace(nullptr, "Deinterlace : %1", params.m_deinterlace ? "yes" : "no");
2106 Logging::trace(nullptr, "--------- HLS Options ---------");
2107 Logging::trace(nullptr, "Segment Duration : %1", format_time(static_cast<time_t>(params.m_segment_duration / AV_TIME_BASE)).c_str());
2108 Logging::trace(nullptr, "Seek Time Diff : %1", format_time(static_cast<time_t>(params.m_min_seek_time_diff / AV_TIME_BASE)).c_str());
2109 Logging::trace(nullptr, "---- Hardware Acceleration ----");
2110 Logging::trace(nullptr, "Hardware Decoder:");
2111 Logging::trace(nullptr, "API : %1", get_hwaccel_API_text(params.m_hwaccel_dec_API).c_str());
2112 Logging::trace(nullptr, "Frame Buffering : %1", av_hwdevice_get_type_name(params.m_hwaccel_dec_device_type));
2113 Logging::trace(nullptr, "Device : %1", params.m_hwaccel_dec_device.c_str());
2114 Logging::trace(nullptr, "Hardware Encoder:");
2115 Logging::trace(nullptr, "API : %1", get_hwaccel_API_text(params.m_hwaccel_enc_API).c_str());
2116 Logging::trace(nullptr, "Frame Buffering : %1", av_hwdevice_get_type_name(params.m_hwaccel_enc_device_type));
2117 Logging::trace(nullptr, "Device : %1", params.m_hwaccel_enc_device.c_str());
2118 Logging::trace(nullptr, "--------- Subtitles ---------");
2119 Logging::trace(nullptr, "No subtitles : %1", params.m_no_subtitles ? "yes" : "no");
2120 Logging::trace(nullptr, "--------- Virtual Script ---------");
2121 Logging::trace(nullptr, "Create script : %1", params.m_enablescript ? "yes" : "no");
2122 Logging::trace(nullptr, "Script file name : %1", params.m_scriptfile.c_str());
2123 Logging::trace(nullptr, "Input file : %1", params.m_scriptsource.c_str());
2124 Logging::trace(nullptr, "--------- Logging ---------");
2125 Logging::trace(nullptr, "Max. Log Level : %1", params.m_log_maxlevel.c_str());
2126 Logging::trace(nullptr, "Log to stderr : %1", params.m_log_stderr ? "yes" : "no");
2127 Logging::trace(nullptr, "Log to syslog : %1", params.m_log_syslog ? "yes" : "no");
2128 Logging::trace(nullptr, "Logfile : %1", !params.m_logfile.empty() ? params.m_logfile.c_str() : "none");
2129 Logging::trace(nullptr, "--------- Cache Settings ---------");
2130 Logging::trace(nullptr, "Expiry Time : %1", format_time(params.m_expiry_time).c_str());
2131 Logging::trace(nullptr, "Inactivity Suspend: %1", format_time(params.m_max_inactive_suspend).c_str());
2132 Logging::trace(nullptr, "Inactivity Abort : %1", format_time(params.m_max_inactive_abort).c_str());
2133 Logging::trace(nullptr, "Pre-buffer Time : %1", format_time(params.m_prebuffer_time).c_str());
2134 Logging::trace(nullptr, "Pre-buffer Size : %1", format_size(params.m_prebuffer_size).c_str());
2135 Logging::trace(nullptr, "Max. Cache Size : %1", format_size(params.m_max_cache_size).c_str());
2136 Logging::trace(nullptr, "Min. Disk Space : %1", format_size(params.m_min_diskspace).c_str());
2137 Logging::trace(nullptr, "Cache Path : %1", cachepath.c_str());
2138 Logging::trace(nullptr, "Disable Cache : %1", params.m_disable_cache ? "yes" : "no");
2139 Logging::trace(nullptr, "Maintenance Timer : %1", params.m_cache_maintenance ? format_time(params.m_cache_maintenance).c_str() : "inactive");
2140 Logging::trace(nullptr, "Clear Cache : %1", params.m_clear_cache ? "yes" : "no");
2141 Logging::trace(nullptr, "--------- Various Options ---------");
2142 Logging::trace(nullptr, "Remove Album Arts : %1", params.m_noalbumarts ? "yes" : "no");
2143 Logging::trace(nullptr, "Max. Threads : %1", format_number(params.m_max_threads).c_str());
2144 Logging::trace(nullptr, "Decoding Errors : %1", params.m_decoding_errors ? "break transcode" : "ignore");
2145 Logging::trace(nullptr, "Min. DVD Chapter : %1", format_duration(params.m_min_dvd_chapter_duration * AV_TIME_BASE).c_str());
2146 Logging::trace(nullptr, "Old Name Scheme : %1", params.m_oldnamescheme ? "yes" : "no");
2147 Logging::trace(nullptr, "--------- Experimental Options ---------");
2148 Logging::trace(nullptr, "Windows 10 Fix : %1", params.m_win_smb_fix ? "SMB Lockup Fix Active" : "inactive");
2149}
2150
2158static void ffmpeg_log(void *ptr, int level, const char *fmt, va_list vl)
2159{
2160 Logging::LOGLEVEL ffmpegfs_level;
2161
2162 // Map log level
2163 // AV_LOG_PANIC 0
2164 // AV_LOG_FATAL 8
2165 // AV_LOG_ERROR 16
2166 if (level <= AV_LOG_ERROR)
2167 {
2168 ffmpegfs_level = LOGERROR;
2169 }
2170 // AV_LOG_WARNING 24
2171 else if (level <= AV_LOG_WARNING)
2172 {
2173 ffmpegfs_level = LOGWARN;
2174 }
2175#ifdef AV_LOG_TRACE
2176 // AV_LOG_INFO 32
2177 //else if (level <= AV_LOG_INFO)
2178 //{
2179 // ffmpegfs_level = LOGINFO;
2180 //}
2181 // AV_LOG_VERBOSE 40
2182 // AV_LOG_DEBUG 48
2183 else if (level < AV_LOG_DEBUG)
2184 {
2185 ffmpegfs_level = LOGDEBUG;
2186 }
2187 // AV_LOG_TRACE 56
2188 else // if (level <= AV_LOG_TRACE)
2189 {
2190 ffmpegfs_level = LOGTRACE;
2191 }
2192#else
2193 // AV_LOG_INFO 32
2194 else // if (level <= AV_LOG_INFO)
2195 {
2196 ffmpegfs_level = DEBUG;
2197 }
2198#endif
2199
2200 if (!Logging::show(ffmpegfs_level))
2201 {
2202 return;
2203 }
2204
2205 va_list vl2;
2206 static int print_prefix = 1;
2207
2208#if (LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 23, 0))
2209 char * line;
2210 int line_size;
2211 std::string category;
2212
2213 if (ptr != nullptr)
2214 {
2215 AVClass* avc = *(AVClass **)ptr;
2216
2217 switch (avc->category)
2218 {
2219 case AV_CLASS_CATEGORY_NA:
2220 {
2221 break;
2222 }
2223 case AV_CLASS_CATEGORY_INPUT:
2224 {
2225 category = "INPUT ";
2226 break;
2227 }
2228 case AV_CLASS_CATEGORY_OUTPUT:
2229 {
2230 category = "OUTPUT ";
2231 break;
2232 }
2233 case AV_CLASS_CATEGORY_MUXER:
2234 {
2235 category = "MUXER ";
2236 break;
2237 }
2238 case AV_CLASS_CATEGORY_DEMUXER:
2239 {
2240 category = "DEMUXER ";
2241 break;
2242 }
2243 case AV_CLASS_CATEGORY_ENCODER:
2244 {
2245 category = "ENCODER ";
2246 break;
2247 }
2248 case AV_CLASS_CATEGORY_DECODER:
2249 {
2250 category = "DECODER ";
2251 break;
2252 }
2253 case AV_CLASS_CATEGORY_FILTER:
2254 {
2255 category = "FILTER ";
2256 break;
2257 }
2258 case AV_CLASS_CATEGORY_BITSTREAM_FILTER:
2259 {
2260 category = "BITFILT ";
2261 break;
2262 }
2263 case AV_CLASS_CATEGORY_SWSCALER:
2264 {
2265 category = "SWSCALE ";
2266 break;
2267 }
2268 case AV_CLASS_CATEGORY_SWRESAMPLER:
2269 {
2270 category = "SWRESAM ";
2271 break;
2272 }
2273 default:
2274 {
2275 strsprintf(&category, "CAT %3i ", static_cast<int>(avc->category));
2276 break;
2277 }
2278 }
2279 }
2280
2281 va_copy(vl2, vl);
2282 av_log_default_callback(ptr, level, fmt, vl);
2283 line_size = av_log_format_line2(ptr, level, fmt, vl2, nullptr, 0, &print_prefix);
2284 if (line_size < 0)
2285 {
2286 va_end(vl2);
2287 return;
2288 }
2289 line = static_cast<char *>(av_malloc(static_cast<size_t>(line_size)));
2290 if (line == nullptr)
2291 {
2292 return;
2293 }
2294 av_log_format_line2(ptr, level, fmt, vl2, line, line_size, &print_prefix);
2295 va_end(vl2);
2296#else
2297 char line[1024];
2298
2299 va_copy(vl2, vl);
2300 av_log_default_callback(ptr, level, fmt, vl);
2301 av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix);
2302 va_end(vl2);
2303#endif
2304
2305 Logging::log_with_level(ffmpegfs_level, "", category + line);
2306
2307#if (LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 23, 0))
2308 av_free(line);
2309#endif
2310}
2311
2320static bool init_logging(const std::string &logfile, const std::string & max_level, bool to_stderr, bool to_syslog)
2321{
2322 static const std::map<const std::string, const Logging::LOGLEVEL, comp> log_level_map =
2323 {
2324 { "ERROR", LOGERROR },
2325 { "WARNING", LOGWARN },
2326 { "INFO", LOGINFO },
2327 { "DEBUG", LOGDEBUG },
2328 { "TRACE", LOGTRACE },
2329 };
2330
2331 std::map<const std::string, const Logging::LOGLEVEL, comp>::const_iterator it = log_level_map.find(max_level);
2332
2333 if (it == log_level_map.cend())
2334 {
2335 std::fprintf(stderr, "Invalid logging level string: %s\n", max_level.c_str());
2336 return false;
2337 }
2338
2339 return Logging::init_logging(logfile, it->second, to_stderr, to_syslog);
2340}
2341
2349int main(int argc, char *argv[])
2350{
2351 int ret;
2352
2353 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
2354
2355 // Check if run from other process group like mount and if so, inhibit startup message
2356 if (getppid() == getpgid(0))
2357 {
2358 std::printf("%s V%s\n", PACKAGE_NAME, FFMPEFS_VERSION);
2359 std::printf("Copyright (C) 2017-2024 Norbert Schlia (nschlia@oblivion-software.de)\n"
2360 "David Collett (2006-2008) and K. Henriksson (2008-2012)\n\n");
2361 }
2362
2363 // Check if run under Docker
2365
2366 init_fuse_ops();
2367
2368 // Redirect FFmpeg logs
2369 av_log_set_callback(ffmpeg_log);
2370
2371 // Set default
2372 params.m_max_threads = static_cast<unsigned int>(get_nprocs() * 16);
2373
2374 // Build list of supported device types
2376
2377 if (fuse_opt_parse(&args, &params, ffmpegfs_opts, ffmpegfs_opt_proc))
2378 {
2379 std::fprintf(stderr, "\nError parsing command line options.\n\n");
2380 //usage(argv[0]);
2381 return 1;
2382 }
2383
2384 // Expand cache path
2385 if (!params.m_cachepath.empty())
2386 {
2389 }
2390
2391 // Log to the screen, and enable debug messages, if debug is enabled.
2392 if (params.m_debug)
2393 {
2394 params.m_log_stderr = 1;
2395 params.m_log_maxlevel = "DEBUG";
2396 av_log_set_level(AV_LOG_INFO); // Do not use AV_LOG_DEBUG; AV_LOG_INFO is chatty enough
2397 }
2398 else
2399 {
2400 av_log_set_level(AV_LOG_QUIET);
2401 }
2402
2404 {
2405 std::fprintf(stderr, "ERROR: Failed to initialise logging module.\n");
2406 std::fprintf(stderr, "Maybe log file couldn't be opened for writing?\n\n");
2407 return 1;
2408 }
2409
2411 {
2412 if (args.argc > 1)
2413 {
2414 std::fprintf(stderr, "INVALID PARAMETER: Invalid additional parameters for --prune_cache:\n");
2415 for (int n = 1; n < args.argc; n++)
2416 {
2417 std::fprintf(stderr, "Invalid: '%s'\n", args.argv[n]);
2418 }
2419 return 1;
2420 }
2421
2422 // Prune cache and exit
2423 if (!transcoder_init())
2424 {
2425 return 1;
2426 }
2428 return 0;
2429 }
2430
2431 if (params.m_basepath.empty())
2432 {
2433 std::fprintf(stderr, "INVALID PARAMETER: No valid basepath specified.\n\n");
2434 return 1;
2435 }
2436
2437 if (params.m_basepath.front() != '/')
2438 {
2439 std::fprintf(stderr, "INVALID PARAMETER: basepath must be an absolute path.\n\n");
2440 return 1;
2441 }
2442
2443 struct stat stbuf;
2444 if (stat(params.m_basepath.c_str(), &stbuf) != 0 || !S_ISDIR(stbuf.st_mode))
2445 {
2446 std::fprintf(stderr, "INVALID PARAMETER: basepath is not a valid directory: %s\n\n", params.m_basepath.c_str());
2447 return 1;
2448 }
2449
2450 if (params.m_mountpath.empty())
2451 {
2452 std::fprintf(stderr, "INVALID PARAMETER: No valid mountpath specified.\n\n");
2453 return 1;
2454 }
2455
2456 if (params.m_mountpath.front() != '/')
2457 {
2458 std::fprintf(stderr, "INVALID PARAMETER: mountpath must be an absolute path.\n\n");
2459 return 1;
2460 }
2461
2462 if (stat(params.m_mountpath.c_str(), &stbuf) != 0 || !S_ISDIR(stbuf.st_mode))
2463 {
2464 std::fprintf(stderr, "INVALID PARAMETER: mountpath is not a valid directory: %s\n\n", params.m_mountpath.c_str());
2465 return 1;
2466 }
2467
2468 // Check if sample format is supported
2469 for (const FFmpegfs_Format & fmt : ffmpeg_format)
2470 {
2471 if (fmt.filetype() != FILETYPE::UNKNOWN && !fmt.is_sample_fmt_supported())
2472 {
2473 std::fprintf(stderr, "INVALID PARAMETER: %s does not support the sample format %s\n\n", fmt.desttype().c_str(), get_sampleformat_text(params.m_sample_fmt).c_str());
2474 std::fprintf(stderr, "Supported formats: %s\n\n", fmt.sample_fmt_list().c_str());
2475 return 1;
2476 }
2477 }
2478
2479 // Check if audio or video codec is supported
2480 for (const FFmpegfs_Format & fmt : ffmpeg_format)
2481 {
2482 if (fmt.filetype() != FILETYPE::UNKNOWN)
2483 {
2484 if (params.m_audio_codec != AV_CODEC_ID_NONE && !fmt.is_audio_codec_supported(params.m_audio_codec))
2485 {
2486 std::fprintf(stderr, "INVALID PARAMETER: %s does not support audio codec %s\n\n", fmt.desttype().c_str(), get_audio_codec_text(params.m_audio_codec).c_str());
2487 std::fprintf(stderr, "Supported formats: %s\n\n", fmt.audio_codec_list().c_str());
2488 return 1;
2489 }
2490
2491 if (params.m_video_codec != AV_CODEC_ID_NONE && !fmt.is_video_codec_supported(params.m_video_codec))
2492 {
2493 std::fprintf(stderr, "INVALID PARAMETER: %s does not support video codec %s\n\n", fmt.desttype().c_str(), get_video_codec_text(params.m_video_codec).c_str());
2494 std::fprintf(stderr, "Supported formats: %s\n\n", fmt.video_codec_list().c_str());
2495 return 1;
2496 }
2497 }
2498 }
2499
2500 if (!set_defaults())
2501 {
2502 return 1;
2503 }
2504
2505 if (!transcoder_init())
2506 {
2507 return 1;
2508 }
2509
2510 print_params();
2511
2513 {
2514 // Prune cache and exit
2516 {
2517 return 1;
2518 }
2519 }
2520
2521 // start FUSE
2522 ret = fuse_main(args.argc, args.argv, &ffmpegfs_ops, nullptr);
2523
2524 fuse_opt_free_args(&args);
2525
2526 return ret;
2527}
@ NONE
No result code available.
The FFmpegfs_Format class.
Definition: ffmpeg_utils.h:388
static void log_with_level(LOGLEVEL loglevel, const char *filename, const std::string &message)
Write log entry.
Definition: logging.cc:226
static bool init_logging(const std::string &logfile, LOGLEVEL max_level, bool to_stderr, bool to_syslog)
Initialise the logging facility.
Definition: logging.cc:210
static void trace(const T filename, const std::string &format_string, Args &&...args)
Write trace level log entry.
Definition: logging.h:163
static bool show(LOGLEVEL loglevel)
Check if log entry should be displayed at the current log level.
Definition: logging.h:272
LOGLEVEL
Logging level types enum.
Definition: logging.h:85
const char * get_codec_name(AVCodecID codec_id, bool long_name)
Safe way to get the codec name. Function never fails, will return "unknown" on error.
std::string format_duration(int64_t value, uint32_t fracs)
Format a time in format HH:MM:SS.fract.
int is_mount(const std::string &path)
Check if path is a mount.
std::string sanitise_filepath(std::string *filepath)
Sanitise file name. Calls realpath() to remove duplicate // or resolve ../.. etc. Changes the path in...
int reg_compare(const std::string &value, const std::string &pattern, std::regex::flag_type flag)
Compare value with pattern.
int show_caps(int device_only)
Lists all supported codecs and devices.
std::string format_time(time_t value)
Format a time in format "w d m s".
std::string format_samplerate(int value)
Format a samplerate.
std::string format_bitrate(BITRATE value)
Format a bit rate.
bool detect_docker()
Detect if we are running under Docker.
static std::string ffmpeg_libinfo(bool lib_exists, __attribute__((unused)) unsigned int version, __attribute__((unused)) const char *cfg, int version_minor, int version_major, int version_micro, const char *libname)
Get FFmpeg library info.
const std::string & append_sep(std::string *path)
Add / to the path if required.
const std::string & expand_path(std::string *tgt, const std::string &src)
Expand path, e.g., expand ~/ to home directory.
std::string format_size(uint64_t value)
Format size.
std::vector< std::string > split(const std::string &input, const std::string &regex)
Split string into an array delimited by a regular expression.
std::string format_number(int64_t value)
Format numeric value.
PRORESLEVEL
Definition: ffmpeg_utils.h:210
@ PRORES_STANDARD
Prores Level: STANDARD.
@ NONE
No level.
@ PRORES_PROXY
Prores Level: PROXY.
@ PRORES_HQ
Prores Level: HQ.
@ PRORES_LT
Prores Level: LT.
std::array< FFmpegfs_Format, 2 > FFMPEGFS_FORMAT_ARR
Array of FFmpegfs formats. There are two, for audio and video.
Definition: ffmpeg_utils.h:521
RECODESAME
Definition: ffmpeg_utils.h:235
@ YES
Always recode to same format.
@ NO
Never recode to same format.
#define BITRATE
For FFmpeg bit rate is an int.
Definition: ffmpeg_utils.h:145
std::string implode(const T &s)
Combine array of strings into comma separated list.
PROFILE
Definition: ffmpeg_utils.h:179
@ MP4_MAXTHON
Maxthon.
@ MP4_CHROME
Google Chrome.
@ MP4_OPERA
Opera.
@ MP4_EDGE
MS Edge.
@ MP4_IE
MS Internet Explorer.
@ DEFAULT
No specific profile/Don't care.
@ MP4_SAFARI
Apple Safari.
@ MP4_FF
Firefox.
#define FFMPEFS_VERSION
FFmpegfs version number.
Definition: ffmpeg_utils.h:42
std::map< conststd::string, constT, comp >::const_iterator search_by_value(const std::map< const std::string, const T, comp > &mapOfWords, T value)
Iterate through all elements in map and search for the passed element.
AUTOCOPY
Definition: ffmpeg_utils.h:223
@ STRICT
Copy stream if codec matches desired target, transcode otherwise.
@ MATCH
Copy stream if target supports codec.
@ MATCHLIMIT
Same as MATCH, only copy if target not larger transcode otherwise.
@ OFF
Never copy streams, transcode always.
@ STRICTLIMIT
Same as STRICT, only copy if target not larger, transcode otherwise.
const std::string & strsprintf(std::string *str, const std::string &format, Args ... args)
Format a std::string sprintf-like.
Definition: ffmpeg_utils.h:737
@ VIDEO
FFmpegfs_Format info, 0: video file.
Definition: ffmpeg_utils.h:517
@ AUDIO
FFmpegfs_Format info, 1: audio file.
Definition: ffmpeg_utils.h:518
std::vector< std::string > MATCHVEC
Array of strings, sorted/search case insensitive.
SAMPLE_FMT
Definition: ffmpeg_utils.h:245
@ FMT_F16
16 bit floating point
@ FMT_F32
32 bit floating point
@ FMT_F24
24 bit floating point
@ FMT_8
8 bit integer
@ FMT_32
32 bit integer
@ FMT_16
16 bit integer
@ FMT_DONTCARE
Don't care, leave to FFmpegfs to choose.
@ FMT_F64
64 bit floating point
@ FMT_24
24 bit integer
@ FMT_64
64 bit integer
static const AUDIOCODEC_MAP audiocodec_map
List of audio codecs.
Definition: ffmpegfs.cc:454
static int get_value(const std::string &arg, int *value)
Get value from command line string. Finds whatever is after the "=" sign.
Definition: ffmpegfs.cc:1625
int main(int argc, char *argv[])
Main program entry point.
Definition: ffmpegfs.cc:2349
static const VIDEOCODEC_MAP videocodec_map
List of video codecs.
Definition: ffmpegfs.cc:471
static int get_size(const std::string &arg, size_t *size)
Read size: .
Definition: ffmpegfs.cc:984
std::map< const std::string, HWACCEL, comp > HWACCEL_MAP
Map command line option to HWACCEL struct.
Definition: ffmpegfs.cc:443
std::string get_recodesame_text(RECODESAME recode)
Convert RECODESAME enum to human readable text.
Definition: ffmpegfs.cc:1302
std::map< const std::string, const AVCodecID, comp > VIDEOCODEC_MAP
Map command line option to video AVCodecID.
Definition: ffmpegfs.cc:448
static HWACCEL_MAP hwaccel_map
Definition: ffmpegfs.cc:545
#define FFMPEGFS_OPT(templ, param, value)
Definition: ffmpegfs.cc:290
static void ffmpeg_log(void *ptr, int level, const char *fmt, va_list vl)
Custom FFmpeg log function. Used with av_log_set_callback().
Definition: ffmpegfs.cc:2158
static const SAMPLE_FMT_MAP sample_fmt_map
Definition: ffmpegfs.cc:608
static int get_hwaccel(const std::string &arg, HWACCELAPI *hwaccel_API, AVHWDeviceType *hwaccel_device_type)
Get type of hardware acceleration. To keep it simple, currently all values are accepted.
Definition: ffmpegfs.cc:1465
static int get_seek_time_diff(const std::string &arg, int64_t *value)
Get seek time diff. Input value must be in seconds.
Definition: ffmpegfs.cc:1437
static int get_audiocodec(const std::string &arg, AVCodecID *audio_codec)
Get the audio codec.
Definition: ffmpegfs.cc:1130
FFMPEGFS_PARAMS params
FFmpegfs command line parameters.
Definition: ffmpegfs.cc:74
static bool init_logging(const std::string &logfile, const std::string &max_level, bool to_stderr, bool to_syslog)
Inititalise logging facility.
Definition: ffmpegfs.cc:2320
std::map< const std::string, const AUTOCOPY, comp > AUTOCOPY_MAP
Map command line option to AUTOCOPY enum.
Definition: ffmpegfs.cc:431
std::map< const std::string, const AVCodecID, comp > CODEC_MAP
Map command line option to AVCodecID.
Definition: ffmpegfs.cc:444
static int get_bitrate(const std::string &arg, BITRATE *bitrate)
Get formatted bitrate.
Definition: ffmpegfs.cc:707
std::map< const std::string, const SAMPLE_FMT, comp > SAMPLE_FMT_MAP
Map command line option to SAMPLE_FMT.
Definition: ffmpegfs.cc:445
std::map< const std::string, const AVCodecID, comp > AUDIOCODEC_MAP
Map command line option to audio AVCodecID.
Definition: ffmpegfs.cc:447
static void usage()
Print program usage info.
Definition: ffmpegfs.cc:655
static const LEVEL_MAP prores_level_map
Definition: ffmpegfs.cc:518
static const AUTOCOPY_MAP autocopy_map
Definition: ffmpegfs.cc:486
std::map< const std::string, const PRORESLEVEL, comp > LEVEL_MAP
Map command line option to LEVEL enum.
Definition: ffmpegfs.cc:433
static int get_videocodec(const std::string &arg, AVCodecID *video_codec)
Get the video codec.
Definition: ffmpegfs.cc:1168
static struct fuse_opt ffmpegfs_opts[]
Definition: ffmpegfs.cc:300
static const PROFILE_MAP profile_map
Definition: ffmpegfs.cc:498
static int get_profile(const std::string &arg, PROFILE *profile)
Get profile option.
Definition: ffmpegfs.cc:1318
static int get_desttype(const std::string &arg, FFMPEGFS_FORMAT_ARR &format)
Get destination type.
Definition: ffmpegfs.cc:1076
static int get_level(const std::string &arg, PRORESLEVEL *level)
Get ProRes level.
Definition: ffmpegfs.cc:1365
std::string get_profile_text(PROFILE profile)
Convert PROFILE enum to human readable text.
Definition: ffmpegfs.cc:1348
static int get_hwaccel_dec_blocked(const std::string &arg, HWACCEL_BLOCKED_MAP **hwaccel_dec_blocked)
Get list of codecs and optional profiles blocked for hardware accelerated decoding.
Definition: ffmpegfs.cc:1534
static void print_params()
Print currently selected parameters.
Definition: ffmpegfs.cc:2046
static const CODEC_MAP hwaccel_codec_map
Definition: ffmpegfs.cc:592
std::string get_level_text(PRORESLEVEL level)
Convert PRORESLEVEL enum to human readable text.
Definition: ffmpegfs.cc:1396
std::string get_sampleformat_text(SAMPLE_FMT sample_fmt)
Convert SAMPLE_FMT enum to human readable text.
Definition: ffmpegfs.cc:861
static int get_sampleformat(const std::string &arg, SAMPLE_FMT *sample_fmt)
Get sample format.
Definition: ffmpegfs.cc:827
static int ffmpegfs_opt_proc(__attribute__((unused)) void *data, const char *arg, int key, struct fuse_args *outargs)
FUSE option parsing function.
Definition: ffmpegfs.cc:1757
static int get_segment_duration(const std::string &arg, int64_t *value)
Get HLS segment duration. Input value must be in seconds.
Definition: ffmpegfs.cc:1412
static void build_device_type_list()
Build list of available device types. Builds a list of device types supported by the current FFmpeg l...
Definition: ffmpegfs.cc:2028
static int get_time(const std::string &arg, time_t *time)
Get formatted time,.
Definition: ffmpegfs.cc:885
std::string get_video_codec_text(AVCodecID video_codec)
Convert AVCodecID enum for video codec to human readable text.
Definition: ffmpegfs.cc:1246
std::map< const std::string, const PROFILE, comp > PROFILE_MAP
Map command line option to PROFILE enum.
Definition: ffmpegfs.cc:432
static int get_recodesame(const std::string &arg, RECODESAME *recode)
Get recode option.
Definition: ffmpegfs.cc:1272
static void list_options(const char *info, const T &map)
Iterate through all elements in map print all keys.
Definition: ffmpegfs.cc:672
static const RECODESAME_MAP recode_map
Definition: ffmpegfs.cc:530
FFMPEGFS_FORMAT_ARR ffmpeg_format
Two FFmpegfs_Format infos, 0: video file, 1: audio file.
Definition: ffmpegfs.cc:73
std::map< const std::string, const RECODESAME, comp > RECODESAME_MAP
Map command line option to RECODESAME enum.
Definition: ffmpegfs.cc:434
static int get_samplerate(const std::string &arg, int *samplerate)
Get formatted sample rate.
Definition: ffmpegfs.cc:775
std::string get_autocopy_text(AUTOCOPY autocopy)
Convert AUTOCOPY enum to human readable text.
Definition: ffmpegfs.cc:1256
std::string get_audio_codec_text(AVCodecID audio_codec)
Convert AVCodecID enum for audio codec to human readable text.
Definition: ffmpegfs.cc:1236
static int get_codec(const std::string &codec, AVCodecID *codec_id)
Get AVCodecID for codec string.
Definition: ffmpegfs.cc:1509
bool check_hwaccel_dec_blocked(AVCodecID codec_id, int profile)
Check if codec_id and the optional profile are in the block list.
Definition: ffmpegfs.cc:1585
std::string get_hwaccel_API_text(HWACCELAPI hwaccel_API)
Get the selected hardware acceleration as text.
Definition: ffmpegfs.cc:1603
struct HWACCEL HWACCEL
Hardware acceleration device and type.
static int get_autocopy(const std::string &arg, AUTOCOPY *autocopy)
Get autocopy option.
Definition: ffmpegfs.cc:1206
static bool set_defaults()
Set default values.
Definition: ffmpegfs.cc:2010
Main include for FFmpegfs project.
fuse_operations ffmpegfs_ops
Fuse operations struct.
Definition: fuseops.cc:100
void transcoder_cache_path(std::string *path)
Get transcoder cache path.
Definition: transcode.cc:195
bool docker_client
True if running inside a Docker container.
Definition: fuseops.cc:98
HWACCELAPI
Hardware acceleration types.
Definition: ffmpegfs.h:124
bool transcoder_init()
Initialise transcoder, create cache.
Definition: transcode.cc:229
std::multimap< AVCodecID, int > HWACCEL_BLOCKED_MAP
Map command line option to AVCodecID.
Definition: ffmpegfs.h:158
bool transcoder_cache_clear()
Clear transcoder cache.
Definition: transcode.cc:755
bool transcoder_cache_maintenance()
Run cache maintenance.
Definition: transcode.cc:743
void init_fuse_ops()
Initialise FUSE operation structure.
Definition: fuseops.cc:247
VIRTUALFILE const * LPCVIRTUALFILE
Pointer to const version of VIRTUALFILE.
Definition: fileio.h:254
Provide various log facilities to stderr, disk or syslog.
constexpr Logging::LOGLEVEL LOGDEBUG
Shorthand for log level DEBUG.
Definition: logging.h:459
constexpr Logging::LOGLEVEL LOGTRACE
Shorthand for log level TRACE.
Definition: logging.h:460
constexpr Logging::LOGLEVEL LOGWARN
Shorthand for log level WARNING.
Definition: logging.h:457
constexpr Logging::LOGLEVEL LOGERROR
Shorthand for log level ERROR.
Definition: logging.h:456
constexpr Logging::LOGLEVEL LOGINFO
Shorthand for log level INFO.
Definition: logging.h:458
Global program parameters.
Definition: ffmpegfs.h:166
std::string m_scriptsource
Source script.
Definition: ffmpegfs.h:234
std::string m_hwaccel_enc_device
Encoder device. May be AUTO to auto detect or empty.
Definition: ffmpegfs.h:222
int m_log_stderr
Log output to standard error.
Definition: ffmpegfs.h:238
time_t m_cache_maintenance
Prune timer interval.
Definition: ffmpegfs.h:251
bool smart_transcode() const
Check for smart transcode mode.
Definition: ffmpegfs.cc:230
AVHWDeviceType m_hwaccel_dec_device_type
Enable hardware acceleration buffering for decoder.
Definition: ffmpegfs.h:224
time_t m_max_inactive_suspend
Time (seconds) that must elapse without access until transcoding is suspended.
Definition: ffmpegfs.h:243
int m_deinterlace
1: deinterlace video, 0: no deinterlace
Definition: ffmpegfs.h:215
int m_decoding_errors
Break transcoding on decoding error.
Definition: ffmpegfs.h:256
int m_oldnamescheme
Use old output name scheme, can create duplicate filenames.
Definition: ffmpegfs.h:258
AVHWDeviceType m_hwaccel_enc_device_type
Enable hardware acceleration buffering for encoder.
Definition: ffmpegfs.h:221
time_t m_expiry_time
Time (seconds) after which an cache entry is deleted.
Definition: ffmpegfs.h:242
int m_no_subtitles
0: allow subtitles, 1: do no transcode subtitles
Definition: ffmpegfs.h:228
FFMPEGFS_PARAMS & operator=(const FFMPEGFS_PARAMS &other) noexcept
Make copy from other FFMPEGFS_PARAMS object.
Definition: ffmpegfs.cc:157
int m_clear_cache
Clear cache on start up.
Definition: ffmpegfs.h:253
std::string m_hwaccel_dec_device
Decoder device. May be AUTO to auto detect or empty.
Definition: ffmpegfs.h:225
const FFmpegfs_Format * current_format(LPCVIRTUALFILE virtualfile) const
Get FFmpegfs_Format for a virtual file.
Definition: ffmpegfs.cc:235
int m_audiochannels
Max. number of audio channels.
Definition: ffmpegfs.h:209
int64_t m_min_seek_time_diff
Minimum time diff from current to next requested segment to perform a seek, in AV_TIME_BASE fractiona...
Definition: ffmpegfs.h:218
int m_videowidth
Output video width.
Definition: ffmpegfs.h:213
BITRATE m_videobitrate
Output video bit rate (bits per second)
Definition: ffmpegfs.h:212
HWACCELAPI m_hwaccel_dec_API
Decoder API.
Definition: ffmpegfs.h:223
size_t m_prebuffer_size
Number of bytes that will be decoded before the output can be accessed.
Definition: ffmpegfs.h:246
int m_videoheight
Output video height.
Definition: ffmpegfs.h:214
time_t m_prebuffer_time
Playing time that will be decoded before the output can be accessed.
Definition: ffmpegfs.h:245
int64_t m_segment_duration
Duration of one HLS segment file, in AV_TIME_BASE fractional seconds.
Definition: ffmpegfs.h:217
BITRATE m_audiobitrate
Output audio bit rate (bits per second)
Definition: ffmpegfs.h:207
std::string m_cachepath
Disk cache path, defaults to $XDG_CACHE_HOME.
Definition: ffmpegfs.h:249
int m_prune_cache
Prune cache immediately.
Definition: ffmpegfs.h:252
RECODESAME m_recodesame
Recode to same format options.
Definition: ffmpegfs.h:203
SAMPLE_FMT m_sample_fmt
Sample format.
Definition: ffmpegfs.h:210
PROFILE m_profile
Target profile: Firefox, MS Edge/IE or other.
Definition: ffmpegfs.h:204
int m_audiosamplerate
Output audio sample rate (in Hz)
Definition: ffmpegfs.h:208
size_t m_max_cache_size
Max. cache size in MB. When exceeded, oldest entries will be pruned.
Definition: ffmpegfs.h:247
AVCodecID m_video_codec
Either AV_CODEC_ID_NONE for default, or a user selected codec.
Definition: ffmpegfs.h:201
unsigned int m_max_threads
Max. number of recoder threads.
Definition: ffmpegfs.h:254
int m_disable_cache
Disable cache.
Definition: ffmpegfs.h:250
std::unique_ptr< MATCHVEC > m_hide_extensions
Set of extensions to block/hide. Must be a pointer as the fuse API cannot handle advanced c++ objects...
Definition: ffmpegfs.h:260
time_t m_max_inactive_abort
Time (seconds) that must elapse without access until transcoding is aborted.
Definition: ffmpegfs.h:244
int m_min_dvd_chapter_duration
Min. DVD chapter duration. Shorter chapters will be ignored.
Definition: ffmpegfs.h:257
std::string m_logfile
Output filename if logging to file.
Definition: ffmpegfs.h:240
std::string m_log_maxlevel
Max. log level.
Definition: ffmpegfs.h:237
std::string m_mountpath
Mount path: Files from m_mountpath will be mapped to this directory.
Definition: ffmpegfs.h:197
AVCodecID m_audio_codec
Either AV_CODEC_ID_NONE for default, or a user selected codec.
Definition: ffmpegfs.h:200
PRORESLEVEL m_level
Level, currently proxy/hq/lt/HQ (ProRes only)
Definition: ffmpegfs.h:205
size_t m_min_diskspace
Min. diskspace required for cache.
Definition: ffmpegfs.h:248
int m_noalbumarts
Skip album arts.
Definition: ffmpegfs.h:230
int m_enablescript
Enable virtual script.
Definition: ffmpegfs.h:232
std::unique_ptr< MATCHVEC > m_include_extensions
Set of extensions to include. If empty, include all. Must be a pointer as the fuse API cannot handle ...
Definition: ffmpegfs.h:259
HWACCEL_BLOCKED_MAP * m_hwaccel_dec_blocked
List of blocked decoders and optional profiles.
Definition: ffmpegfs.h:226
int m_debug
Debug mode (stay in foreground.
Definition: ffmpegfs.h:236
std::string m_scriptfile
Script name.
Definition: ffmpegfs.h:233
int m_win_smb_fix
Experimental Windows fix for access to EOF at file open.
Definition: ffmpegfs.h:262
int m_log_syslog
Log output to system log.
Definition: ffmpegfs.h:239
std::string m_basepath
Base path: Files from this directory (including all sub directories) will be mapped to m_mountpath.
Definition: ffmpegfs.h:196
HWACCELAPI m_hwaccel_enc_API
Encoder API.
Definition: ffmpegfs.h:220
AUTOCOPY m_autocopy
Copy streams if codec matches.
Definition: ffmpegfs.h:202
Hardware acceleration device and type.
Definition: ffmpegfs.cc:437
HWACCELAPI m_hwaccel_API
Acceleration API, e.g VAAPI, MMAL or OMX.
Definition: ffmpegfs.cc:439
AVHWDeviceType m_hwaccel_device_type
Hardware buffering type, NONE if not used.
Definition: ffmpegfs.cc:440
bool m_supported
true if API supported, false if not
Definition: ffmpegfs.cc:438