63static std::unique_ptr<Cache>
cache;
83 size_t end = offset + len;
86 if (cache_entry->
is_finished() || cache_entry->
m_buffer->is_segment_finished(segment_no) || cache_entry->
m_buffer->tell(segment_no) >= end)
96 bool reported =
false;
99 if (fuse_interrupted())
121 Logging::trace(cache_entry->
virtname(),
"Cache miss at offset %1 with length %2 for segment no. %3.", offset, len, segment_no);
136 Logging::trace(cache_entry->
virtname(),
"Cache hit at offset %1 with length %2 for segment no. %3.", offset, len, segment_no);
142 catch (
bool _success)
190 cache_entry->
flush();
206 *path =
"/var/cache";
211 if (
const char* cache_home = std::getenv(
"XDG_CACHE_HOME"))
231 if (
cache ==
nullptr)
234 cache = std::make_unique<Cache>();
235 if (
cache ==
nullptr)
237 Logging::error(
nullptr,
"Unable to create new media file cache. Out of memory.");
238 std::fprintf(stderr,
"ERROR: Creating new media file cache. Out of memory.\n");
242 if (!
cache->load_index())
244 std::fprintf(stderr,
"ERROR: Creating media file cache failed.\n");
253 if (
cache !=
nullptr)
264 if (cache_entry ==
nullptr)
271 if (!encoded_filesize)
277 if (encoded_filesize)
288bool transcoder_set_filesize(
LPVIRTUALFILE virtualfile, int64_t duration,
BITRATE audio_bit_rate,
int channels,
int sample_rate, AVSampleFormat sample_format,
BITRATE video_bit_rate,
int width,
int height,
bool interleaved,
const AVRational &framerate)
291 if (cache_entry ==
nullptr)
298 if (current_format ==
nullptr)
331 bool success =
false;
335 if (cache_entry !=
nullptr)
357 if (cache_entry ==
nullptr)
368 if (!cache_entry->
openio(begin_transcode))
370 throw static_cast<int>(errno);
376 cache_entry->
clear();
380 cache_entry->
clear();
403 cache_entry->
clear();
408 std::shared_ptr<THREAD_DATA> thread_data = std::make_unique<THREAD_DATA>();
410 thread_data->m_initialised =
false;
411 thread_data->m_cache_entry = cache_entry;
412 thread_data->m_thread_running_lock_guard =
false;
415 std::unique_lock<std::mutex> lock_thread_running_mutex(thread_data->m_thread_running_mutex);
420 while (!thread_data->m_thread_running_lock_guard)
422 thread_data->m_thread_running_cond.wait(lock_thread_running_mutex);
446 throw static_cast<int>(errno);
450 else if (begin_transcode)
462 cache_entry =
nullptr;
475 Logging::trace(cache_entry->
virtname(),
"Reading %1 bytes from offset %2 to %3.", len, offset, len + offset);
479 Logging::trace(cache_entry->
virtname(),
"Reading %1 bytes from offset %2 to %3 for segment no. %4.", len, offset, len + offset, segment_no);
492 if (segment_no && !cache_entry->
m_buffer->segment_exists(segment_no))
513 if ((offset > cache_entry->
m_buffer->tell(segment_no)) &&
517 std::memset(buff, 0xFF, len);
541 if ((offset > cache_entry->
m_buffer->tell(segment_no)) &&
544 ((offset + len) > (cache_entry->
size())))
546 Logging::warning(cache_entry->
virtname(),
"Ignoring Windows' groundless access to the last 8K boundary of the file.");
566 if (cache_entry->
m_buffer->buffer_watermark(segment_no) < offset)
570 else if (cache_entry->
m_buffer->buffer_watermark(segment_no) < offset + len)
572 len = cache_entry->
m_buffer->buffer_watermark(segment_no) - offset;
577 if (!cache_entry->
m_buffer->copy(
reinterpret_cast<uint8_t*
>(buff), offset, len, segment_no))
593 catch (
bool _success)
598 *bytes_read =
static_cast<int>(len);
605 bool success =
false;
607 Logging::trace(cache_entry->
virtname(),
"Reading %1 bytes from offset %2 to %3 for frame no. %4.", len, offset, len + offset, frame_no);
623 std::vector<uint8_t> data;
629 if (!cache_entry->
m_buffer->read_frame(&data, frame_no))
631 bool reported =
false;
640 Logging::error(cache_entry->
virtname(),
"Reading image frame no. %1: (%2) %3", frame_no, errno, strerror(errno));
646 if (errno == EAGAIN && !--retries)
649 Logging::error(cache_entry->
virtname(),
"Timeout reading image frame no. %1: (%2) %3", frame_no, errno, strerror(errno));
667 Logging::trace(cache_entry->
virtname(),
"Frame no. %1: Cache miss at offset %<11zu>2 (length %<6u>3).", frame_no, offset, len);
675 Logging::trace(cache_entry->
virtname(),
"Frame no. %1: Cache hit at offset %<11zu>2 (length %<6u>3).", frame_no, offset, len);
681 success = cache_entry->
m_buffer->read_frame(&data, frame_no);
684 Logging::error(cache_entry->
virtname(),
"Reading image frame no. %1: (%2) %3", frame_no, errno, strerror(errno));
691 if (data.size() < offset)
695 else if (data.size() < offset + len)
697 len = data.size() - offset;
702 std::memcpy(buff, data.data() + offset, len);
707 *bytes_read =
static_cast<int>(len);
710 catch (
bool _success)
720 cache->closeio(&cache_entry);
725 return cache_entry->
size();
730 return cache_entry->
m_buffer->buffer_watermark(segment_no);
735 return cache_entry->
m_buffer->tell(segment_no);
745 if (
cache !=
nullptr)
747 return cache->maintenance();
757 if (
cache !=
nullptr)
759 return cache->clear();
782 cache_entry->
clear();
789 bool unlocked =
false;
793 if (!cache_entry->
openio())
795 throw (
static_cast<int>(errno));
801 throw (
static_cast<int>(errno));
826 throw (
static_cast<int>(errno));
832 throw (
static_cast<int>(errno));
837 thread_data->m_initialised =
true;
844 thread_data->m_thread_running_lock_guard =
true;
845 thread_data->m_thread_running_cond.notify_all();
881 throw (
static_cast<int>(errno));
885 else if (transcoder.
is_hls())
895 throw (
static_cast<int>(errno));
905 throw (
static_cast<int>(errno));
916 throw (
static_cast<int>(errno));
925 thread_data->m_thread_running_lock_guard =
true;
926 thread_data->m_thread_running_cond.notify_all();
934 thread_data->m_thread_running_lock_guard =
true;
935 thread_data->m_thread_running_cond.notify_all();
957 thread_data->m_thread_running_lock_guard =
true;
958 thread_data->m_thread_running_cond.notify_all();
961 catch (
int _syserror)
964 syserror = _syserror;
966 if (!syserror && averror > -512)
970 syserror = AVUNERROR(averror);
980 thread_data->m_thread_running_lock_guard =
true;
981 thread_data->m_thread_running_cond.notify_all();
1001 Cache_Entry * cache_entry = thread_data->m_cache_entry;
1003 bool timeout =
false;
1004 bool success =
true;
1006 std::unique_lock<std::recursive_mutex> lock_active_mutex(cache_entry->
m_active_mutex);
1007 std::unique_lock<std::recursive_mutex> lock_restart_mutex(cache_entry->
m_restart_mutex);
1009 uint32_t seek_frame = 0;
1015 Logging::error(transcoder.
virtname(),
"Transcoder completed with last seek frame to %1. Transcoder is being restarted.", seek_frame);
1018 success =
transcode(thread_data, cache_entry, transcoder, &timeout);
1082 if (
cache !=
nullptr)
1087 thread_data.reset();
#define CACHE_FLAG_RO
Mark cache file read-only.
#define CACHE_CLOSE_DELETE
Delete cache entry, will unlink cached file! Implies CACHE_CLOSE_FREE.
#define CACHE_CLOSE_NOOPT
Dummy, do nothing special.
@ FINISHED_INCOMPLETE
Transcode finished, but incomplete.
@ FINISHED_SUCCESS
Transcode finished successfully.
std::recursive_mutex m_restart_mutex
Mutex while thread is restarted.
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.
std::atomic_bool m_suspend_timeout
true to temporarly disable read_frame timeout
bool is_finished() const
Get if cache has been finished.
bool suspend_timeout() const
Check for decode suspend timeout.
int ref_count() const
Get the current reference counter.
void lock()
Lock the access mutex.
std::atomic_bool m_is_decoding
true while file is decoding
const char * virtname() const
Return virtual filename. Same as destination filename, but with virtual (mount) path....
void clear(bool fetch_file_time=true)
Clear the cache entry.
LPVIRTUALFILE virtualfile()
Get the underlying VIRTUALFILE object.
bool openio(bool create_cache=true)
Open the cache file.
void update_read_count()
Update read counter.
const char * filename() const
Return source filename.
std::recursive_mutex m_active_mutex
Mutex while thread is active.
ID3v1 m_id3v1
ID3v1 structure which is used to send to clients.
unsigned int read_count() const
Get read 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_success() const
Get if cache has been finished and filled successfully.
bool outdated() const
Check if cache entry needs to be recoded.
std::atomic_uint32_t m_seek_to_no
If not 0, seeks to specified frame.
std::unique_ptr< Buffer > m_buffer
Buffer object.
The FFmpeg_Transcoder class.
static bool video_size(size_t *filesize, AVCodecID codec_id, BITRATE bit_rate, int64_t duration, int width, int height, bool interleaved, const AVRational &framerate)
Predict video file size. This may (better will surely) be inaccurate.
int stack_seek_frame(uint32_t frame_no)
Seek to a specific frame. Does not actually perform the seek, this is done asynchronously by the tran...
virtual const char * filename() const override
Return source filename.
int process_single_fr(DECODER_STATUS *status)
static bool audio_size(size_t *filesize, AVCodecID codec_id, BITRATE bit_rate, int64_t duration, int channels, int sample_rate, AVSampleFormat sample_format)
Predict audio file size. This may (better will surely) be inaccurate.
bool have_seeked() const
Check if we made a seek operation.
void closeio()
Close transcoder, free all ressources.
uint32_t video_frame_count() const
Get the number of video frames in file.
bool is_hls() const
Check for HLS format.
size_t predicted_filesize() const
Try to predict the recoded file size. This may (better will surely) be inaccurate.
static bool total_overhead(size_t *filesize, FILETYPE filetype)
Predict overhead in file size. This may (better will surely) be inaccurate.
const ID3v1 * id3v1tag() const
Assemble an ID3v1 file tag.
uint32_t segment_count() const
Get the number of HLS segments of file.
bool is_multiformat() const
Check for an export frame format.
virtual const char * virtname() const override
Return virtual filename. Same as destination filename, but with virtual (mount) path....
uint32_t last_seek_frame_no() const
Current seek frame if available.
int open_output_file(Buffer *buffer)
Open output file. Data will actually be written to buffer and copied by FUSE when accessed.
int64_t duration() const
Get the file duration.
bool is_frameset() const
Check for an export frame format.
int64_t pts() const
Get PTS (presentation time stamp) of decoded audio/video so far.
int open_input_file(LPVIRTUALFILE virtualfile, std::shared_ptr< FileIO > fio=nullptr)
int stack_seek_segment(uint32_t segment_no)
Seek to a specific HLS segment. Does not actually perform the seek, this is done asynchronously by th...
static void warning(const T filename, const std::string &format_string, Args &&...args)
Write warning level log entry.
static void debug(const T filename, const std::string &format_string, Args &&...args)
Write debug level log entry.
static void trace(const T filename, const std::string &format_string, Args &&...args)
Write trace level log entry.
static void info(const T filename, const std::string &format_string, Args &&...args)
Write info level log entry.
static void error(const T filename, const std::string &format_string, Args &&...args)
Write error level log entry.
DECODER_STATUS
Decoder status codes. Can be error, success or end of file.
@ DEC_ERROR
Decoder error, see return code.
@ DEC_EOF
Read to end of file.
@ DEC_SUCCESS
Frame decoded successfully.
bool check_ignore(size_t size, size_t offset)
For use with win_smb_fix=1: Check if this an illegal access offset by Windows.
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 get_filetype_text(FILETYPE filetype)
Convert FILETYPE enum to human readable text.
std::string format_time(time_t value)
Format a time in format "w d m s".
std::string format_result_size_ex(size_t size_resulting, size_t size_predicted)
Format size of transcoded file including difference between predicted and resulting size.
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.
void mssleep(int milliseconds)
Sleep for specified time.
std::string format_size(uint64_t value)
Format size.
void stat_set_size(struct stat *st, size_t size)
Properly fill in all size related members in stat struct.
std::string format_size_ex(uint64_t value)
Format size.
std::string ffmpeg_geterror(int errnum)
Get FFmpeg error string for errnum. Internally calls av_strerror().
#define BITRATE
For FFmpeg bit rate is an int.
FFMPEGFS_PARAMS params
FFmpegfs command line parameters.
Main include for FFmpegfs project.
std::unique_ptr< thread_pool > tp
Thread pool object.
#define ID3V1_TAG_LENGTH
Fixed 128 bytes.
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.
RESULTCODE m_result
Result code:
int64_t m_duration
File duration, in AV_TIME_BASE fractional seconds.
uint32_t m_segment_count
Number of segments for HLS.
size_t m_encoded_filesize
Actual file size after encode.
bool m_error
true if encode failed
size_t m_predicted_filesize
Predicted file size.
int m_averror
FFmpeg error code if encode failed.
int m_errno
errno if encode failed
time_t m_max_inactive_suspend
Time (seconds) that must elapse without access until transcoding is suspended.
const FFmpegfs_Format * current_format(LPCVIRTUALFILE virtualfile) const
Get FFmpegfs_Format for a virtual file.
size_t m_prebuffer_size
Number of bytes that will be decoded before the output can be accessed.
time_t m_prebuffer_time
Playing time that will be decoded before the output can be accessed.
std::string m_cachepath
Disk cache path, defaults to $XDG_CACHE_HOME.
int m_disable_cache
Disable cache.
time_t m_max_inactive_abort
Time (seconds) that must elapse without access until transcoding is aborted.
int m_win_smb_fix
Experimental Windows fix for access to EOF at file open.
THREAD_DATA struct to pass data from parent to child thread.
std::mutex m_thread_running_mutex
Mutex when thread is running.
bool m_initialised
True when this object is completely initialised.
std::atomic_bool m_thread_running_lock_guard
Lock guard to avoid spurious or missed unlocks.
Cache_Entry * m_cache_entry
Cache entry object. Will not be freed by child thread.
std::condition_variable m_thread_running_cond
Condition when thread is running.
size_t m_predicted_size
Use this as the size instead of computing it over and over.
struct stat m_st
stat structure with size etc.
uint32_t m_video_frame_count
Number of frames in video or 0 if not a video.
int64_t m_duration
Track/chapter duration, in AV_TIME_BASE fractional seconds.
Thread pool class implementation.
static bool transcode_until(Cache_Entry *cache_entry, size_t offset, size_t len, uint32_t segment_no)
Transcode the buffer until the buffer has enough or until an error occurs. The buffer needs at least ...
static bool transcode(std::shared_ptr< THREAD_DATA > thread_data, Cache_Entry *cache_entry, FFmpeg_Transcoder &transcoder, bool *timeout)
Actually transcode file.
const int TOTAL_RETRIES
Number of retries.
struct THREAD_DATA THREAD_DATA
THREAD_DATA struct to pass data from parent to child thread.
bool transcoder_predict_filesize(LPVIRTUALFILE virtualfile, Cache_Entry *cache_entry)
Predict file size.
static std::atomic_bool thread_exit
Used for shutdown: if true, forcibly exit all threads.
void transcoder_cache_path(std::string *path)
Get transcoder cache path.
Cache_Entry * transcoder_new(LPVIRTUALFILE virtualfile, bool begin_transcode)
Allocate and initialise the transcoder.
bool transcoder_set_filesize(LPVIRTUALFILE virtualfile, int64_t duration, BITRATE audio_bit_rate, int channels, int sample_rate, AVSampleFormat sample_format, BITRATE video_bit_rate, int width, int height, bool interleaved, const AVRational &framerate)
Set the file size.
static std::unique_ptr< Cache > cache
Global cache manager object.
void transcoder_free()
Free transcoder.
const int GRANULARITY
Image frame conversion: ms between checks if a picture frame is available.
size_t transcoder_buffer_tell(Cache_Entry *cache_entry, uint32_t segment_no)
Return the current file position in the file.
bool transcoder_read(Cache_Entry *cache_entry, char *buff, size_t offset, size_t len, int *bytes_read, uint32_t segment_no)
Read some bytes from the internal buffer and into the given buffer.
static int transcode_finish(Cache_Entry *cache_entry, FFmpeg_Transcoder &transcoder)
Close the input file and free everything but the initial buffer.
void transcoder_exit()
Exit transcoding.
size_t transcoder_get_size(Cache_Entry *cache_entry)
Return size of output file, as computed by encoder.
bool transcoder_read_frame(Cache_Entry *cache_entry, char *buff, size_t offset, size_t len, uint32_t frame_no, int *bytes_read, LPVIRTUALFILE virtualfile)
Read one image frame from the internal buffer and into the given buffer.
bool transcoder_init()
Initialise transcoder, create cache.
size_t transcoder_buffer_watermark(Cache_Entry *cache_entry, uint32_t segment_no)
Return the current watermark of the file while transcoding.
bool transcoder_cache_clear()
Clear transcoder cache.
static int transcoder_thread(std::shared_ptr< THREAD_DATA > thread_data)
Transcoding thread.
bool transcoder_cached_filesize(LPVIRTUALFILE virtualfile, struct stat *stbuf)
Simply get encoded file size (do not create the whole encoder/decoder objects)
bool transcoder_cache_maintenance()
Run cache maintenance.
const int FRAME_TIMEOUT
Image frame conversion: timout seconds to wait if a picture frame is available.
void transcoder_delete(Cache_Entry *cache_entry)
Free the cache entry structure.
File transcoder interface (for use with by FUSE)