36#pragma GCC diagnostic push
37#pragma GCC diagnostic ignored "-Wconversion"
38#pragma GCC diagnostic ignored "-Wsign-conversion"
39#include <libswscale/swscale.h>
40#include "libavutil/ffversion.h"
41#include <libavcodec/avcodec.h>
42#pragma GCC diagnostic pop
70#pragma GCC diagnostic push
71#pragma GCC diagnostic ignored "-Wpedantic"
73#pragma GCC diagnostic pop
81#pragma GCC diagnostic push
82#pragma GCC diagnostic ignored "-Wconversion"
83#pragma GCC diagnostic ignored "-Wsign-conversion"
84#include <libswresample/swresample.h>
85#pragma GCC diagnostic pop
90static int is_device(__attribute__((unused))
const AVClass *avclass);
91static 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);
93#ifndef AV_ERROR_MAX_STRING_SIZE
94#define AV_ERROR_MAX_STRING_SIZE 128
97typedef std::map<const std::string, const FILETYPE, comp>
FILETYPE_MAP;
104 {
"mp3", FILETYPE::MP3 },
105 {
"mp4", FILETYPE::MP4 },
106 {
"wav", FILETYPE::WAV },
107 {
"ogg", FILETYPE::OGG },
108 {
"webm", FILETYPE::WEBM },
109 {
"mov", FILETYPE::MOV },
110 {
"aiff", FILETYPE::AIFF },
111 {
"opus", FILETYPE::OPUS },
112 {
"prores", FILETYPE::PRORES },
113 {
"alac", FILETYPE::ALAC },
114 {
"png", FILETYPE::PNG },
115 {
"jpg", FILETYPE::JPG },
116 {
"bmp", FILETYPE::BMP },
117 {
"ts", FILETYPE::TS },
118 {
"hls", FILETYPE::HLS },
119 {
"flac", FILETYPE::FLAC },
120 {
"mkv", FILETYPE::MKV },
124 : m_format_map{ {
SAMPLE_FMT::FMT_DONTCARE, { { AV_CODEC_ID_NONE }, { AV_CODEC_ID_NONE }, { AV_CODEC_ID_NONE }, AV_SAMPLE_FMT_NONE }}}
125 , m_albumart_supported(
false)
130 std::string format_name,
133 bool albumart_supported
135 : m_format_name(std::move(format_name))
136 , m_fileext(std::move(fileext))
137 , m_format_map(std::move(format))
138 , m_albumart_supported(albumart_supported)
149 return AV_CODEC_ID_NONE;
154 return (it->second.m_video_codec[0]);
165 for (
const AVCodecID & video_codec_id : it->second.m_video_codec)
167 if (video_codec_id == codec_id)
182 for (
const AVCodecID & video_codec_id : it->second.m_video_codec)
202 return AV_CODEC_ID_NONE;
207 return (it->second.m_audio_codec[0]);
218 for (
const AVCodecID & audio_codec_id : it->second.m_audio_codec)
220 if (audio_codec_id == codec_id)
235 for (
const AVCodecID & audio_codec_id : it->second.m_audio_codec)
254 return AV_SAMPLE_FMT_NONE;
257 return (it->second.m_sample_format);
288 return AV_CODEC_ID_NONE;
292 for (
const AVCodecID & subtitle_codec_id : it->second.m_subtitle_codec)
295 if (subtitle_codec_id == codec_id || (codec_id == AV_CODEC_ID_DVD_SUBTITLE && subtitle_codec_id == AV_CODEC_ID_DVB_SUBTITLE))
297 return subtitle_codec_id;
305 for (
const AVCodecID & subtitle_codec_id : it->second.m_subtitle_codec)
309 return subtitle_codec_id;
316 for (
const AVCodecID & subtitle_codec_id : it->second.m_subtitle_codec)
320 return subtitle_codec_id;
326 return AV_CODEC_ID_NONE;
359 { AV_CODEC_ID_NONE },
361 { AV_CODEC_ID_NONE },
381 { AV_CODEC_ID_H264, AV_CODEC_ID_H265, AV_CODEC_ID_MPEG1VIDEO, AV_CODEC_ID_MPEG2VIDEO },
382 { AV_CODEC_ID_AAC, AV_CODEC_ID_MP3 },
383 { AV_CODEC_ID_MOV_TEXT },
403 { AV_CODEC_ID_NONE },
404 { AV_CODEC_ID_PCM_S16LE },
405 { AV_CODEC_ID_NONE },
412 { AV_CODEC_ID_NONE },
413 { AV_CODEC_ID_PCM_U8 },
414 { AV_CODEC_ID_NONE },
421 { AV_CODEC_ID_NONE },
422 { AV_CODEC_ID_PCM_S16LE },
423 { AV_CODEC_ID_NONE },
430 { AV_CODEC_ID_NONE },
431 { AV_CODEC_ID_PCM_S24LE },
432 { AV_CODEC_ID_NONE },
440 { AV_CODEC_ID_NONE },
441 { AV_CODEC_ID_PCM_S32LE },
442 { AV_CODEC_ID_NONE },
450 { AV_CODEC_ID_NONE },
451 { AV_CODEC_ID_PCM_S64LE },
452 { AV_CODEC_ID_NONE },
459 { AV_CODEC_ID_NONE },
460 { AV_CODEC_ID_PCM_F16LE },
461 { AV_CODEC_ID_NONE },
468 { AV_CODEC_ID_NONE },
469 { AV_CODEC_ID_PCM_F24LE },
470 { AV_CODEC_ID_NONE },
477 { AV_CODEC_ID_NONE },
478 { AV_CODEC_ID_PCM_F32LE },
479 { AV_CODEC_ID_NONE },
486 { AV_CODEC_ID_NONE },
487 { AV_CODEC_ID_PCM_F64LE },
488 { AV_CODEC_ID_NONE },
508 { AV_CODEC_ID_THEORA },
509 { AV_CODEC_ID_VORBIS },
510 { AV_CODEC_ID_NONE },
530 { AV_CODEC_ID_VP9, AV_CODEC_ID_VP8, AV_CODEC_ID_AV1 },
531 { AV_CODEC_ID_OPUS, AV_CODEC_ID_VORBIS },
532 { AV_CODEC_ID_WEBVTT },
552 { AV_CODEC_ID_H264, AV_CODEC_ID_H265, AV_CODEC_ID_MPEG1VIDEO, AV_CODEC_ID_MPEG2VIDEO },
553 { AV_CODEC_ID_AAC, AV_CODEC_ID_AC3, AV_CODEC_ID_MP3 },
554 { AV_CODEC_ID_MOV_TEXT },
574 { AV_CODEC_ID_NONE },
575 { AV_CODEC_ID_PCM_S16BE },
576 { AV_CODEC_ID_NONE },
583 { AV_CODEC_ID_NONE },
584 { AV_CODEC_ID_PCM_S16BE },
585 { AV_CODEC_ID_NONE },
592 { AV_CODEC_ID_NONE },
593 { AV_CODEC_ID_PCM_S32BE },
594 { AV_CODEC_ID_NONE },
614 { AV_CODEC_ID_NONE },
615 { AV_CODEC_ID_OPUS },
616 { AV_CODEC_ID_NONE },
636 { AV_CODEC_ID_PRORES },
637 { AV_CODEC_ID_PCM_S16LE },
638 { AV_CODEC_ID_MOV_TEXT },
658 { AV_CODEC_ID_NONE },
659 { AV_CODEC_ID_ALAC },
660 { AV_CODEC_ID_NONE },
667 { AV_CODEC_ID_NONE },
668 { AV_CODEC_ID_ALAC },
669 { AV_CODEC_ID_NONE },
676 { AV_CODEC_ID_NONE },
677 { AV_CODEC_ID_ALAC },
678 { AV_CODEC_ID_NONE },
699 { AV_CODEC_ID_NONE },
700 { AV_CODEC_ID_NONE },
720 { AV_CODEC_ID_MJPEG },
721 { AV_CODEC_ID_NONE },
722 { AV_CODEC_ID_NONE },
743 { AV_CODEC_ID_NONE },
744 { AV_CODEC_ID_NONE },
764 { AV_CODEC_ID_H264, AV_CODEC_ID_H265, AV_CODEC_ID_MPEG1VIDEO, AV_CODEC_ID_MPEG2VIDEO },
765 { AV_CODEC_ID_AAC, AV_CODEC_ID_AC3, AV_CODEC_ID_MP3 },
766 { AV_CODEC_ID_DVB_SUBTITLE },
787 { AV_CODEC_ID_H264, AV_CODEC_ID_H265, AV_CODEC_ID_MPEG1VIDEO, AV_CODEC_ID_MPEG2VIDEO },
788 { AV_CODEC_ID_AAC, AV_CODEC_ID_AC3, AV_CODEC_ID_MP3 },
789 { AV_CODEC_ID_DVB_SUBTITLE },
809 { AV_CODEC_ID_NONE },
810 { AV_CODEC_ID_FLAC },
811 { AV_CODEC_ID_NONE },
818 { AV_CODEC_ID_NONE },
819 { AV_CODEC_ID_FLAC },
820 { AV_CODEC_ID_NONE },
827 { AV_CODEC_ID_NONE },
828 { AV_CODEC_ID_FLAC },
829 { AV_CODEC_ID_NONE },
849 { AV_CODEC_ID_H264, AV_CODEC_ID_H265, AV_CODEC_ID_MPEG1VIDEO, AV_CODEC_ID_MPEG2VIDEO },
850 { AV_CODEC_ID_AAC, AV_CODEC_ID_AC3, AV_CODEC_ID_MP3 },
851 { AV_CODEC_ID_ASS, AV_CODEC_ID_SUBRIP, AV_CODEC_ID_WEBVTT, AV_CODEC_ID_DVB_SUBTITLE },
862 m_cur_opts(&m_empty_options),
984 if (path->back() !=
'/')
1003 if (path->back() ==
'/')
1013 std::shared_ptr<char[]> p =
new_strdup(*filepath);
1021 *filepath = dirname(p.get());
1029 std::shared_ptr<char[]> p =
new_strdup(*filepath);
1037 *filepath = basename(p.get());
1046 found = filepath->rfind(
'.');
1048 if (found != std::string::npos)
1051 filepath->resize(found);
1057bool find_ext(std::string * ext,
const std::string & filename)
1061 found = filename.rfind(
'.');
1063 if (found == std::string::npos)
1072 *ext = filename.substr(found + 1);
1077bool check_ext(
const std::string & ext,
const std::string & filename)
1080 return (
find_ext(&ext1, filename) && ext1 == ext);
1083const std::string &
replace_ext(std::string * filepath,
const std::string & ext)
1087 found = filepath->rfind(
'.');
1089 if (found == std::string::npos)
1097 filepath->resize(found + 1);
1105const std::string &
append_ext(std::string * filepath,
const std::string & ext)
1109 found = filepath->rfind(
'.');
1111 if (found == std::string::npos ||
strcasecmp(filepath->substr(found + 1), ext) != 0)
1114 *filepath +=
'.' + ext;
1122 size_t n = str.size() + 1;
1123 std::shared_ptr<char[]> p(
new (std::nothrow)
char[n]);
1131 memcpy(p.get(), str.data(), n - 1); p.get()[n - 1] =
'\0';
1140 std::array<char, AV_ERROR_MAX_STRING_SIZE + 1> error;
1141 av_strerror(errnum, error.data(), error.size() - 1);
1142 return error.data();
1147#if defined(__GLIBC__) || defined(_POSIX_C_SOURCE)
1150# if ((_POSIX_C_SOURCE >= 200112L) && ! _GNU_SOURCE)
1151 if (strerror_r(errnum, buf,
sizeof(buf)) == 0)
1153 return std::string(buf);
1157 return std::string(
"Unknown error: ") + std::to_string(errnum);
1161 char *msg = strerror_r(errnum, buf,
sizeof(buf));
1162 if (msg)
return std::string(msg);
1163 return std::string(
"Unknown error: ") + std::to_string(errnum);
1167 return std::string(strerror(errnum));
1172int64_t
ffmpeg_rescale_q(int64_t ts,
const AVRational & timebase_in,
const AVRational &timebase_out)
1174 if (ts == AV_NOPTS_VALUE)
1176 return AV_NOPTS_VALUE;
1184 return av_rescale_q(ts, timebase_in, timebase_out);
1189 if (ts == AV_NOPTS_VALUE)
1191 return AV_NOPTS_VALUE;
1199 return av_rescale_q_rnd(ts, timebase_in, timebase_out,
static_cast<AVRounding
>(AV_ROUND_UP |
AV_ROUND_PASS_MINMAX));
1202#if !HAVE_MEDIA_TYPE_STRING
1207 case AVMEDIA_TYPE_VIDEO:
1209 case AVMEDIA_TYPE_AUDIO:
1211 case AVMEDIA_TYPE_DATA:
1213 case AVMEDIA_TYPE_SUBTITLE:
1215 case AVMEDIA_TYPE_ATTACHMENT:
1216 return "attachment";
1234static 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)
1250#define PRINT_LIB_INFO(libname, LIBNAME) \
1251 ffmpeg_libinfo(true, libname##_version(), libname##_configuration(), \
1252 LIB##LIBNAME##_VERSION_MAJOR, LIB##LIBNAME##_VERSION_MINOR, LIB##LIBNAME##_VERSION_MICRO, #libname)
1258 info =
"FFmpeg Version : " FFMPEG_VERSION
"\n";
1279static int is_device(__attribute__((unused))
const AVClass *avclass)
1290 const AVInputFormat *ifmt =
nullptr;
1291 const AVOutputFormat *ofmt =
nullptr;
1292 const char *last_name;
1296 " D. = Demuxing supported\n"
1297 " .E = Muxing supported\n"
1298 " --\n", device_only ?
"Devices:" :
"File formats:");
1304 const char *name =
nullptr;
1305 const char *long_name =
nullptr;
1306 const char *extensions =
nullptr;
1308 void *ofmt_opaque =
nullptr;
1309 ofmt_opaque =
nullptr;
1310 while ((ofmt = av_muxer_iterate(&ofmt_opaque)))
1313 if (!is_dev && device_only)
1318 if ((!name || strcmp(ofmt->name, name) < 0) &&
1319 strcmp(ofmt->name, last_name) > 0)
1322 long_name = ofmt->long_name;
1327 void *ifmt_opaque =
nullptr;
1328 ifmt_opaque =
nullptr;
1329 while ((ifmt = av_demuxer_iterate(&ifmt_opaque)) !=
nullptr)
1332 if (!is_dev && device_only)
1337 if ((!name || strcmp(ifmt->name, name) < 0) &&
1338 strcmp(ifmt->name, last_name) > 0)
1341 long_name = ifmt->long_name;
1342 extensions = ifmt->extensions;
1345 if (name && strcmp(ifmt->name, name) == 0)
1351 if (name ==
nullptr)
1357 if (extensions ==
nullptr)
1362 std::printf(
" %s%s %-15s %-15s %s\n",
1367 (long_name !=
nullptr) ? long_name :
" ");
1374 const AVCodecDescriptor * pCodecDescriptor;
1375 const char * psz =
"unknown";
1377 pCodecDescriptor = avcodec_descriptor_get(codec_id);
1379 if (pCodecDescriptor !=
nullptr)
1381 if (pCodecDescriptor->long_name !=
nullptr && long_name)
1383 psz = pCodecDescriptor->long_name;
1388 psz = pCodecDescriptor->name;
1395int mktree(
const std::string & path, mode_t mode)
1399 if (buffer ==
nullptr)
1406 char *p = strtok_r(buffer.get(),
"/", &saveptr);
1409 while (p !=
nullptr)
1418 newstat = mkdir(dir.c_str(), mode);
1420 if (!status && newstat && errno != EEXIST)
1428 p = strtok_r(
nullptr,
"/", &saveptr);
1434void tempdir(std::string & path)
1436 const char *temp = getenv(
"TMPDIR");
1438 if (temp !=
nullptr)
1457 return (filetype == FILETYPE::MP3 || filetype == FILETYPE::MP4);
1466 catch (
const std::out_of_range& )
1469 return FILETYPE::UNKNOWN;
1486 std::vector<std::string> desttype =
split(desttypelist,
",");
1487 FILETYPE filetype = FILETYPE::UNKNOWN;
1490 for (
size_t n = 0; n < desttype.size() && filetype != FILETYPE::UNKNOWN; n++)
1500 std::memset(id3v1,
' ',
sizeof(
ID3v1));
1501 std::memcpy(&id3v1->
m_tag,
"TAG", 3);
1514 if (value == AV_NOPTS_VALUE)
1520 return strsprintf(&buffer,
"%" PRId64, value);
1525 if (value ==
static_cast<BITRATE>(AV_NOPTS_VALUE))
1530 if (value > 1000000)
1533 return strsprintf(&buffer,
"%.2f Mbps",
static_cast<double>(value) / 1000000);
1535 else if (value > 1000)
1538 return strsprintf(&buffer,
"%.1f kbps",
static_cast<double>(value) / 1000);
1543 return strsprintf(&buffer,
"%" PRId64
" bps", value);
1549 if (value ==
static_cast<int>(AV_NOPTS_VALUE))
1562 return strsprintf(&buffer,
"%.3f kHz",
static_cast<double>(value) / 1000);
1566#define STR_VALUE(arg) #arg
1567#define X(name) STR_VALUE(name)
1571 if (value == AV_NOPTS_VALUE)
1577 std::string duration;
1578 unsigned hours =
static_cast<unsigned>((value / AV_TIME_BASE) / (3600));
1579 unsigned mins =
static_cast<unsigned>(((value / AV_TIME_BASE) % 3600) / 60);
1580 unsigned secs =
static_cast<unsigned>((value / AV_TIME_BASE) % 60);
1584 duration =
strsprintf(&buffer,
"%02u:", hours);
1587 duration +=
strsprintf(&buffer,
"%02u:%02u", mins, secs);
1590 unsigned decimals =
static_cast<unsigned>(value % AV_TIME_BASE);
1591 duration +=
strsprintf(&buffer,
".%0*u",
sizeof(
X(AV_TIME_BASE)) - 2, decimals).substr(0, fracs + 1);
1603 if (value ==
static_cast<time_t
>(AV_NOPTS_VALUE))
1616 weeks =
static_cast<int>(value / (60*60*24*7));
1617 value -= weeks * (60*60*24*7);
1618 days =
static_cast<int>(value / (60*60*24));
1619 value -= days * (60*60*24);
1620 hours =
static_cast<int>(value / (60*60));
1621 value -= hours * (60*60);
1622 mins =
static_cast<int>(value / (60));
1623 value -= mins * (60);
1624 secs =
static_cast<int>(value);
1656 if (value ==
static_cast<uint64_t
>(AV_NOPTS_VALUE))
1661 if (value > 1024*1024*1024*1024LL)
1664 return strsprintf(&buffer,
"%.3f TB",
static_cast<double>(value) / (1024*1024*1024*1024LL));
1666 else if (value > 1024*1024*1024)
1669 return strsprintf(&buffer,
"%.2f GB",
static_cast<double>(value) / (1024*1024*1024));
1671 else if (value > 1024*1024)
1674 return strsprintf(&buffer,
"%.1f MB",
static_cast<double>(value) / (1024*1024));
1676 else if (value > 1024)
1679 return strsprintf(&buffer,
"%.1f KB",
static_cast<double>(value) / (1024));
1684 return strsprintf(&buffer,
"%" PRIu64
" bytes", value);
1696 if (size_resulting >= size_predicted)
1698 size_t value = size_resulting - size_predicted;
1703 size_t value = size_predicted - size_resulting;
1710 if (size_resulting >= size_predicted)
1713 size_t value = size_resulting - size_predicted;
1719 size_t value = size_predicted - size_resulting;
1729static void print_fps(
double d,
const char *postfix)
1731 long v = lrint(d * 100);
1734 std::printf(
"%1.4f %s\n", d, postfix);
1738 std::printf(
"%3.2f %s\n", d, postfix);
1740 else if (v % (100 * 1000))
1742 std::printf(
"%1.0f %s\n", d, postfix);
1746 std::printf(
"%1.0fk %s\n", d / 1000, postfix);
1754 AVCodecContext *avctx = avcodec_alloc_context3(
nullptr);
1755 if (avctx ==
nullptr)
1757 return AVERROR(ENOMEM);
1760 ret = avcodec_parameters_to_context(avctx, stream->codecpar);
1763 avcodec_free_context(&avctx);
1774 int fps = stream->avg_frame_rate.den && stream->avg_frame_rate.num;
1775 int tbr = stream->r_frame_rate.den && stream->r_frame_rate.num;
1776 int tbn = stream->time_base.den && stream->time_base.num;
1777 int tbc = avctx->time_base.den && avctx->time_base.num;
1780 print_fps(av_q2d(stream->avg_frame_rate),
"avg fps");
1782 print_fps(av_q2d(stream->r_frame_rate),
"Real base framerate (tbr)");
1784 print_fps(1 / av_q2d(stream->time_base),
"stream timebase (tbn)");
1786 print_fps(1 / av_q2d(avctx->time_base),
"codec timebase (tbc)");
1788 avcodec_free_context(&avctx);
1795 std::string fourcc2str(AV_FOURCC_MAX_STRING_SIZE,
'\0');
1796 av_fourcc_make_string(&fourcc2str[0], fourcc);
1797 fourcc2str.resize(std::strlen(fourcc2str.c_str()));
1802void exepath(std::string * path)
1804 std::array<char, PATH_MAX + 1> result;
1805 ssize_t count = readlink(
"/proc/self/exe", result.data(), result.size() - 1);
1808 *path = dirname(result.data());
1817std::string &
ltrim(std::string &s)
1819 s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not_fn(std::function<
int(
int)>(isspace))));
1823std::string &
rtrim(std::string &s)
1825 s.erase(std::find_if(s.rbegin(), s.rend(), std::not_fn(std::function<
int(
int)>(isspace))).base(), s.end());
1829std::string &
trim(std::string &s)
1834std::string
replace_all(std::string str,
const std::string& from,
const std::string& to)
1839std::string
replace_all(std::string *str,
const std::string& from,
const std::string& to)
1841 size_t start_pos = 0;
1842 while ((start_pos = str->find(from, start_pos)) != std::string::npos)
1844 str->replace(start_pos, from.length(), to);
1845 start_pos += to.length();
1850bool replace_start(std::string *str,
const std::string& from,
const std::string& to)
1852#if __cplusplus >= 202002L
1854 if (str->starts_with(from) == 0)
1856 if (str->find(from, 0) == 0)
1859 str->replace(0, from.length(), to);
1866int strcasecmp(
const std::string & s1,
const std::string & s2)
1868 return ::strcasecmp(s1.c_str(), s2.c_str());
1871int reg_compare(
const std::string & value,
const std::string & pattern, std::regex::flag_type flag)
1877 std::regex rgx(pattern, flag);
1879 reti = (std::regex_search(value, rgx) ==
true) ? 0 : 1;
1881 catch(
const std::regex_error& e)
1883 std::cerr <<
"regex_error caught: " << e.what() << std::endl;
1884 if(e.code() == std::regex_constants::error_brack)
1885 std::cerr <<
"The code was error_brack" << std::endl;
1893const std::string &
expand_path(std::string *tgt,
const std::string & src)
1895 wordexp_t exp_result;
1896 if (!wordexp(
replace_all(src,
" ",
"\\ ").c_str(), &exp_result, 0))
1898 *tgt = exp_result.we_wordv[0];
1899 wordfree(&exp_result);
1909int is_mount(
const std::string & path)
1915 std::shared_ptr<char[]> orig_name;
1916 struct stat file_stat;
1917 struct stat parent_stat;
1918 char * parent_name =
nullptr;
1922 if (orig_name ==
nullptr)
1924 std::fprintf(stderr,
"is_mount(): Out of memory\n");
1930 parent_name = dirname(orig_name.get());
1933 if (-1 == stat(path.c_str(), &file_stat))
1935 std::fprintf(stderr,
"is_mount(): (%i) %s\n", errno, strerror(errno));
1941 if (!(file_stat.st_mode & S_IFDIR))
1943 std::fprintf(stderr,
"is_mount(): %s is not a directory.\n", path.c_str());
1948 if (-1 == stat(parent_name, &parent_stat))
1950 std::fprintf(stderr,
"is_mount(): (%i) %s\n", errno, strerror(errno));
1964 if (file_stat.st_dev != parent_stat.st_dev || file_stat.st_ino == parent_stat.st_ino)
1983std::vector<std::string>
split(
const std::string& input,
const std::string & regex)
1986 std::regex re(regex);
1987 std::sregex_token_iterator first{input.cbegin(), input.cend(), re, -1},
1989 return {first, last};
1994 std::array<char, PATH_MAX + 1> resolved_name;
1996 if (realpath(filepath->c_str(), resolved_name.data()) !=
nullptr)
1998 *filepath = resolved_name.data();
2004 std::string _filepath(*filepath);
2011 std::string buffer(filepath);
2027bool is_album_art(AVCodecID codec_id,
const AVRational * frame_rate)
2029 if (codec_id == AV_CODEC_ID_PNG || codec_id == AV_CODEC_ID_BMP)
2035 if (codec_id != AV_CODEC_ID_MJPEG)
2041 if (frame_rate !=
nullptr && frame_rate->den)
2043 double dbFrameRate =
static_cast<double>(frame_rate->num) / frame_rate->den;
2046 if (dbFrameRate < 300)
2056int nocasecompare(
const std::string & lhs,
const std::string &rhs)
2065 if (statvfs(path.c_str(), &buf))
2070 return static_cast<size_t>(buf.f_bfree * buf.f_bsize);
2075 std::array<size_t, 3> blocksize_arr = { 0x2000, 0x8000, 0x10000 };
2076 bool ignore =
false;
2078 for (
const size_t & blocksize: blocksize_arr)
2083 match = !(offset % blocksize);
2089 rest = size % offset;
2090 ignore = match && (rest < blocksize);
2101std::string
make_filename(uint32_t file_no,
const std::string & fileext)
2104 return strsprintf(&buffer,
"%06u.%s", file_no, fileext.c_str());
2109 return (access(filename.c_str(), F_OK) != -1);
2114 std::for_each(std::begin(*input), std::end(*input), [](
char& c) {
2115 c =
static_cast<char>(std::toupper(
static_cast<unsigned char>(c)));
2121 std::for_each(std::begin(*input), std::end(*input), [](
char& c) {
2122 c =
static_cast<char>(std::tolower(
static_cast<unsigned char>(c)));
2128 const char *type_name = av_hwdevice_get_type_name(dev_type);
2129 return (type_name !=
nullptr ? type_name :
"unknown");
2132int to_utf8(std::string & text,
const std::string & encoding)
2134 iconv_t conv = iconv_open(
"UTF-8", encoding.c_str());
2135 if (conv == (iconv_t) -1)
2137 int open_err = errno;
2139 const char *fallback =
nullptr;
2140 if (open_err == EINVAL)
2142 if (encoding ==
"UTF-32LE") fallback =
"UCS-4LE";
2143 else if (encoding ==
"UTF-32BE") fallback =
"UCS-4BE";
2144 else if (encoding ==
"UTF-16LE") fallback =
"UCS-2LE";
2145 else if (encoding ==
"UTF-16BE") fallback =
"UCS-2BE";
2147 if (fallback !=
nullptr)
2149 conv = iconv_open(
"UTF-8", fallback);
2150 if (conv == (iconv_t) -1)
2167 std::vector<char> src;
2168 std::vector<char> dst;
2169 size_t srclen = text.size();
2170 size_t dstlen = 2 * srclen;
2172 src.resize(srclen + 1);
2173 dst.resize(dstlen + 2);
2175 char * pIn = src.data();
2176 char * pOut = dst.data();
2178 memcpy(pIn, text.data(), srclen); pIn[srclen] =
'\0';
2180 size_t len = iconv(conv, &pIn, &srclen, &pOut, &dstlen);
2181 if (len != (
size_t) -1)
2193 int orgerrno = errno;
2202int get_encoding (
const char * str, std::string & encoding)
2204 DetectObj *obj = detect_obj_init();
2212#ifndef CHARDET_BINARY_SAFE
2214 switch (detect (str, &obj))
2217 switch (detect_r (str, strlen (str), &obj))
2220 case CHARDET_OUT_OF_MEMORY :
2222 detect_obj_free (&obj);
2224 case CHARDET_NULL_OBJECT :
2238 encoding = obj->encoding;
2239 detect_obj_free (&obj);
2244int read_file(
const std::string & path, std::string & result)
2246 constexpr std::array<char, 3> UTF_8_BOM = {
'\xEF',
'\xBB',
'\xBF' };
2247 constexpr std::array<char, 2> UTF_16_BE_BOM = {
'\xFE',
'\xFF' };
2248 constexpr std::array<char, 2> UTF_16_LE_BOM = {
'\xFF',
'\xFE' };
2249 constexpr std::array<char, 4> UTF_32_BE_BOM = {
'\x00',
'\x00',
'\xFE',
'\xFF' };
2250 constexpr std::array<char, 4> UTF_32_LE_BOM = {
'\xFF',
'\xFE',
'\x00',
'\x00' };
2258 ifs.open(path, std::ios::binary);
2275 std::array<char, 4> BOM;
2276 ifs.read(BOM.data(), BOM.size());
2281 if (!memcmp(BOM.data(), UTF_32_LE_BOM.data(), UTF_32_LE_BOM.size()))
2285 ifs.seekg(UTF_32_LE_BOM.size());
2287 else if (!memcmp(BOM.data(), UTF_32_BE_BOM.data(), UTF_32_BE_BOM.size()))
2291 ifs.seekg(UTF_32_BE_BOM.size());
2293 else if (!memcmp(BOM.data(), UTF_16_LE_BOM.data(), UTF_16_LE_BOM.size()))
2297 ifs.seekg(UTF_16_LE_BOM.size());
2299 else if (!memcmp(BOM.data(), UTF_16_BE_BOM.data(), UTF_16_BE_BOM.size()))
2303 ifs.seekg(UTF_16_BE_BOM.size());
2305 else if (!memcmp(BOM.data(), UTF_8_BOM.data(), UTF_8_BOM.size()))
2309 ifs.seekg(UTF_8_BOM.size());
2322 std::stringstream ss;
2325 res =
to_utf8(result,
"UTF-16LE");
2326 if (res) {
throw res; }
2331 std::stringstream ss;
2334 res =
to_utf8(result,
"UTF-16BE");
2335 if (res) {
throw res; }
2340 std::stringstream ss;
2343 res =
to_utf8(result,
"UTF-32LE");
2344 if (res) {
throw res; }
2349 std::stringstream ss;
2352 res =
to_utf8(result,
"UTF-32BE");
2353 if (res) {
throw res; }
2359 std::stringstream ss;
2367 std::stringstream ss;
2372 std::string encoding_name;
2379 if (encoding_name !=
"UTF-8")
2382 res =
to_utf8(result, encoding_name);
2391 res =
static_cast<int>(encoding);
2393 catch (
const std::system_error& e)
2406#if defined __x86_64__ || !defined __USE_FILE_OFFSET64
2407 st->st_size =
static_cast<__off_t
>(size);
2409 st->st_size =
static_cast<__off64_t
>(size);
2411 st->st_blocks = (st->st_size + 512 - 1) / 512;
2418 std::ifstream
const in_stream(
"/proc/self/cgroup");
2419 std::stringstream buffer;
2420 buffer << in_stream.rdbuf();
2421 auto const& content_as_string = buffer.str();
2422 return std::string::npos != content_as_string.find(
"/docker");
2424 catch (std::exception
const& ex)
2426 std::fprintf(stderr,
"detect_docker(): Unable check if running in docker or not, exception: %s.", ex.what());
2460 return (codec_id != AV_CODEC_ID_DVD_SUBTITLE && codec_id != AV_CODEC_ID_DVB_SUBTITLE && codec_id != AV_CODEC_ID_HDMV_PGS_SUBTITLE);
2463int get_audio_props(AVFormatContext *format_ctx,
int *channels,
int *samplerate)
2470#if LAVU_DEP_OLD_CHANNEL_LAYOUT
2471 *channels = format_ctx->streams[ret]->codecpar->ch_layout.nb_channels;
2473 *channels = format_ctx->streams[ret]->codecpar->channels;
2475 *samplerate = format_ctx->streams[ret]->codecpar->sample_rate;
2485 const std::vector<std::string> charlist {
"\\",
"+",
"*",
"?",
"^",
"$",
"(",
")",
"[",
"]",
"{",
"}",
"|"};
2487 for (
const std::string & ch : charlist)
2505 auto is_match = [ext](
const std::string & regex_string) {
return (fnmatch(regex_string.c_str(), ext.c_str(), 0) == 0); };
2527 auto is_match = [ext](
const std::string & regex_string) {
return (fnmatch(regex_string.c_str(), ext.c_str(), 0) == 0); };
2535 void * tmp = __atomic_exchange_n(p,
nullptr, __ATOMIC_RELEASE);
2544 std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
2549 std::this_thread::sleep_for(std::chrono::microseconds(microseconds));
2554 std::this_thread::sleep_for(std::chrono::nanoseconds(nanoseconds));
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.
void nssleep(int nanoseconds)
Sleep for specified time.
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.
int get_encoding(const char *str, std::string &encoding)
Try to detect the encoding of str. This is relatively realiable, but may be wrong.
const std::string & remove_path(std::string *filepath)
Remove path from filename. Handy basename alternative.
std::string format_duration(int64_t value, uint32_t fracs)
Format a time in format HH:MM:SS.fract.
void exepath(std::string *path)
Path to FFmpegfs binary.
static int is_device(__attribute__((unused)) const AVClass *avclass)
Check if class is a FMmpeg device.
void ussleep(int microseconds)
Sleep for specified time.
int is_mount(const std::string &path)
Check if path is a mount.
std::string & trim(std::string &s)
trim from both ends
int mktree(const std::string &path, mode_t mode)
Make directory tree.
int nocasecompare(const std::string &lhs, const std::string &rhs)
nocasecompare to make std::string find operations case insensitive
void make_upper(std::string *input)
Convert string to upper case.
int read_file(const std::string &path, std::string &result)
Read text file and return in UTF-8 format, no matter in which encoding the input file is....
const std::string & append_filename(std::string *path, const std::string &filename)
Add filename to path, including / after the path if required.
const std::string & remove_filename(std::string *filepath)
Remove filename from path. Handy dirname alternative.
bool check_ext(const std::string &ext, const std::string &filename)
Check if filename has a certain extension. The check is case sensitive.
std::string ffmpeg_libinfo()
Get info about the FFmpeg libraries used.
std::string get_filetype_text(FILETYPE filetype)
Convert FILETYPE enum to human readable text.
bool is_blocked(const std::string &filename)
Check if filename should be hidden from output path.
std::map< const std::string, const FILETYPE, comp > FILETYPE_MAP
Map of file type. One entry per supported type.
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.
bool is_selected(const std::string &ext)
Find extension in include list, if existing.
int strcasecmp(const std::string &s1, const std::string &s2)
strcasecmp() equivalent for std::string.
void tempdir(std::string &path)
Get temporary directory.
bool is_album_art(AVCodecID codec_id, const AVRational *frame_rate)
Minimal check if codec is an album art. Requires frame_rate to decide whether this is a video stream ...
bool is_text_codec(AVCodecID codec_id)
Check if subtitle codec is a text or graphical codec.
const char * get_media_type_string(enum AVMediaType media_type)
av_get_media_type_string is missing, so we provide our own.
const std::string & regex_escape(std::string *str)
Escape characters that are meaningful to regexp.
std::string format_result_size(size_t size_resulting, size_t size_predicted)
Format size of transcoded file including difference between predicted and resulting size.
std::string & rtrim(std::string &s)
trim from end
const char * hwdevice_get_type_name(AVHWDeviceType dev_type)
int64_t ffmpeg_rescale_q_rnd(int64_t ts, const AVRational &timebase_in, const AVRational &timebase_out)
Convert a FFmpeg time from in timebase to out timebase with rounding.
int supports_albumart(FILETYPE filetype)
Check if file type supports album arts.
FILETYPE get_filetype(const std::string &desttype)
Get the FFmpegfs filetype, desttype must be one of FFmpeg's "official" short names for formats.
#define PRINT_LIB_INFO(libname, LIBNAME)
Print info about a FFmpeg library.
int show_caps(int device_only)
Lists all supported codecs and devices.
size_t get_disk_free(std::string &path)
Get free disk space.
#define X(name)
Convert macro to string.
std::string fourcc_make_string(std::string *buf, uint32_t fourcc)
static const FILETYPE_MAP filetype_map
std::shared_ptr< char[]> new_strdup(const std::string &str)
strdup() variant taking a std::string as input.
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 make_filename(uint32_t file_no, const std::string &fileext)
Make a file name from file number and file extension.
std::string format_bitrate(BITRATE value)
Format a bit rate.
std::string & ltrim(std::string &s)
trim from start
const std::string & replace_ext(std::string *filepath, const std::string &ext)
Replace extension in filename, taking into account that there might not be an extension already.
bool detect_docker()
Detect if we are running under Docker.
void make_lower(std::string *input)
Convert string to lower case.
const std::string & remove_sep(std::string *path)
Remove / from the path.
const std::string & remove_ext(std::string *filepath)
Remove extension from filename.
void save_free(void **p)
Savely free memory: Pointer will be set to nullptr before it is actually freed.
const std::string & append_ext(std::string *filepath, const std::string &ext)
Append extension to filename. If ext is the same as.
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.
void append_basepath(std::string *origpath, const char *path)
Translate file names from FUSE to the original absolute path.
bool file_exists(const std::string &filename)
Check if file exists.
static void print_fps(double d, const char *postfix)
Print frames per second.
int print_stream_info(const AVStream *stream)
Print info about an AVStream.
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::vector< std::string > split(const std::string &input, const std::string ®ex)
Split string into an array delimited by a regular expression.
void init_id3v1(ID3v1 *id3v1)
Initialise ID3v1 tag.
int get_audio_props(AVFormatContext *format_ctx, int *channels, int *samplerate)
Get first audio stream.
std::string replace_all(std::string str, const std::string &from, const std::string &to)
Same as std::string replace(), but replaces all occurrences.
std::string format_size_ex(uint64_t value)
Format size.
bool replace_start(std::string *str, const std::string &from, const std::string &to)
Replace start of string from "from" to "to".
bool find_ext(std::string *ext, const std::string &filename)
Find extension in filename, if existing.
int to_utf8(std::string &text, const std::string &encoding)
Convert almost any encoding to UTF-8. To get a list of all possible encodings run "iconv --list".
std::string format_number(int64_t value)
Format numeric value.
FILETYPE get_filetype_from_list(const std::string &desttypelist)
Get the FFmpegfs filetype, desttypelist must be a comma separated list of FFmpeg's "official" short n...
int64_t ffmpeg_rescale_q(int64_t ts, const AVRational &timebase_in, const AVRational &timebase_out)
Convert a FFmpeg time from in timebase to outtime base.
std::string ffmpeg_geterror(int errnum)
Get FFmpeg error string for errnum. Internally calls av_strerror().
Various FFmpegfs utility functions.
#define BITRATE
For FFmpeg bit rate is an int.
#define AV_ROUND_PASS_MINMAX
bool is_text_codec(AVCodecID codec_id)
Check if subtitle codec is a text or graphical codec.
@ UTF8_BOM
UTF-8 with bottom mark.
@ UTF32BE_BOM
UTF-16 big-endian with bottom mark.
@ UTF16BE_BOM
UTF-16 big-endian with bottom mark.
@ UTF32LE_BOM
UTF-16 little-endian with bottom mark.
@ ASCII
Some sort of ASCII encoding.
@ UTF16LE_BOM
UTF-16 little-endian with bottom mark.
FILETYPE get_filetype(const std::string &desttype)
Get the FFmpegfs filetype, desttype must be one of FFmpeg's "official" short names for formats.
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.
const std::string & strsprintf(std::string *str, const std::string &format, Args ... args)
Format a std::string sprintf-like.
@ FMT_F16
16 bit floating point
@ FMT_F32
32 bit floating point
@ FMT_F24
24 bit floating point
@ FMT_DONTCARE
Don't care, leave to FFmpegfs to choose.
@ FMT_F64
64 bit floating point
#define INVALID_STREAM
Denote an invalid stream.
FFMPEGFS_PARAMS params
FFmpegfs command line parameters.
std::string get_sampleformat_text(SAMPLE_FMT sample_fmt)
Convert SAMPLE_FMT enum to human readable text.
std::string get_video_codec_text(AVCodecID video_codec)
Convert AVCodecID enum for video codec to human readable text.
std::string get_audio_codec_text(AVCodecID audio_codec)
Convert AVCodecID enum for audio codec to human readable text.
Main include for FFmpegfs project.
SAMPLE_FMT m_sample_fmt
Sample format.
AVCodecID m_video_codec
Either AV_CODEC_ID_NONE for default, or a user selected codec.
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...
AVCodecID m_audio_codec
Either AV_CODEC_ID_NONE for default, or a user selected codec.
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 ...
std::string m_basepath
Base path: Files from this directory (including all sub directories) will be mapped to m_mountpath.
char m_title_no
Title number.
char m_padding
Padding byte, must be '\0'.
std::array< char, 3 > m_tag
Contains "TAG".
char m_genre
Type of music.