FFmpegfs Fuse Multi Media Filesystem 2.16
vcdparser.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 2017-2024 Norbert Schlia (nschlia@oblivion-software.de)
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 * On Debian systems, the complete text of the GNU General Public License
19 * Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
20 */
21
22#ifdef USE_LIBVCD
23
34#include "ffmpegfs.h"
35#include "vcdparser.h"
36#include "logging.h"
37
38#include "vcd/vcdentries.h"
39
40extern "C" {
41#include <libavutil/rational.h>
42}
43
44static int parse_vcd(const std::string & path, const struct stat * statbuf, void * buf, fuse_fill_dir_t filler);
45static bool create_vcd_virtualfile(const VcdEntries &vcd, const struct stat * statbuf, void * buf, fuse_fill_dir_t filler, bool full_title, int chapter_no);
46
57static bool create_vcd_virtualfile(const VcdEntries & vcd, const struct stat * statbuf, void * buf, fuse_fill_dir_t filler, bool full_title, int chapter_no)
58{
59 const VcdChapter * chapter1 = vcd.get_chapter(chapter_no);
60 std::string title_buf;
61 size_t size;
62 int64_t duration;
63
64 if (!full_title)
65 {
66 size = static_cast<size_t>(chapter1->get_size());
67 duration = chapter1->get_duration();
68 strsprintf(&title_buf, "%02d. Chapter %03d [%s].%s", chapter1->get_track_no(), chapter_no + 1, replace_all(format_duration(duration), ":", "-").c_str(), ffmpeg_format[FORMAT::VIDEO].fileext().c_str()); // can safely assume this a video
69 }
70 else
71 {
72 size = static_cast<size_t>(vcd.get_size());
73 duration = vcd.get_duration();
74 strsprintf(&title_buf, "%02d. Title [%s].%s", chapter1->get_track_no(), replace_all(format_duration(duration), ":", "-").c_str(), ffmpeg_format[FORMAT::VIDEO].fileext().c_str()); // can safely assume this a video
75 }
76
77 LPVIRTUALFILE virtualfile = nullptr;
78 if (!ffmpeg_format[FORMAT::VIDEO].is_multiformat())
79 {
80 virtualfile = insert_file(VIRTUALTYPE::VCD, vcd.get_disk_path() + title_buf, statbuf);
81 }
82 else
83 {
84 virtualfile = insert_dir(VIRTUALTYPE::VCD, vcd.get_disk_path() + title_buf, statbuf);
85 }
86
87 if (virtualfile == nullptr)
88 {
89 Logging::error(vcd.get_disk_path(), "Failed to create virtual path: %1", (vcd.get_disk_path() + title_buf).c_str());
90 errno = EIO;
91 return false;
92 }
93
94 if (add_fuse_entry(buf, filler, title_buf, &virtualfile->m_st, 0))
95 {
96 // break;
97 }
98
99 // Video CD is video format anyway
100 virtualfile->m_format_idx = 0;
101 // Mark title/chapter/angle
102 virtualfile->m_full_title = full_title;
103 virtualfile->m_vcd.m_track_no = chapter1->get_track_no();
104 virtualfile->m_vcd.m_chapter_no = chapter_no;
105 virtualfile->m_vcd.m_start_pos = chapter1->get_start_pos();
106 if (!full_title)
107 {
108 virtualfile->m_vcd.m_end_pos = chapter1->get_end_pos();
109 }
110 else
111 {
112 virtualfile->m_vcd.m_end_pos = size;
113 }
114 virtualfile->m_duration = duration;
115 AVRational framerate = av_make_q(25000, 1000); //*** @todo check disk which framerate is correct, can be 25 or 29.996 fps!
116 virtualfile->m_video_frame_count = static_cast<uint32_t>(av_rescale_q(duration, av_get_time_base_q(), av_inv_q(framerate)));
117 virtualfile->m_predicted_size = size;
118
119 return true;
120}
121
130static int parse_vcd(const std::string & path, const struct stat * statbuf, void * buf, fuse_fill_dir_t filler)
131{
132 VcdEntries vcd;
133 bool success = true;
134
135 vcd.load_file(path);
136
137 Logging::debug(path, "Parsing the Video CD.");
138
139 for (int chapter_no = 0; chapter_no < vcd.get_number_of_chapters() && success; chapter_no++)
140 {
141 success = create_vcd_virtualfile(vcd, statbuf, buf, filler, false, chapter_no);
142 }
143
144 if (success && vcd.get_number_of_chapters() > 1)
145 {
146 success = create_vcd_virtualfile(vcd, statbuf, buf, filler, true, 0);
147 }
148
149 if (success)
150 {
151 return vcd.get_number_of_chapters();
152 }
153 else
154 {
155 return -errno;
156 }
157}
158
159int check_vcd(const std::string & path, void *buf, fuse_fill_dir_t filler)
160{
161 std::string _path(path);
162 struct stat stbuf;
163 int res = 0;
164
165 append_sep(&_path);
166
167 if (stat((_path + "SVCD/INFO.SVD").c_str(), &stbuf) == 0)
168 {
169 if (!check_path(_path))
170 {
171 Logging::trace(_path, "SVCD detected.");
172 res = parse_vcd(_path, &stbuf, buf, filler);
173 Logging::trace(nullptr, "%1 titles were discovered.", res);
174 }
175 else
176 {
177 res = load_path(_path, &stbuf, buf, filler);
178 }
179
180 add_dotdot(buf, filler, &stbuf, 0);
181 }
182 else if (stat((_path + "VCD/INFO.VCD").c_str(), &stbuf) == 0)
183 {
184 if (!check_path(_path))
185 {
186 Logging::trace(_path, "VCD detected.");
187 res = parse_vcd(_path, &stbuf, buf, filler);
188 Logging::trace(nullptr, "%1 titles were discovered.", res);
189 }
190 else
191 {
192 res = load_path(_path, &stbuf, buf, filler);
193 }
194
195 add_dotdot(buf, filler, &stbuf, 0);
196 }
197 return res;
198}
199
200#endif // USE_LIBVCD
static void debug(const T filename, const std::string &format_string, Args &&...args)
Write debug level log entry.
Definition: logging.h:182
static void trace(const T filename, const std::string &format_string, Args &&...args)
Write trace level log entry.
Definition: logging.h:163
static void error(const T filename, const std::string &format_string, Args &&...args)
Write error level log entry.
Definition: logging.h:239
Video CD chapter.
Definition: vcdchapter.h:62
int get_track_no() const
Get the track number of this chapter.
Definition: vcdchapter.cc:114
uint64_t get_size() const
Get the size of this chapter in bytes.
Definition: vcdchapter.cc:164
uint64_t get_start_pos() const
Get file position of chapter in bytes.
Definition: vcdchapter.cc:154
uint64_t get_end_pos() const
Get end position of chapter in bytes.
Definition: vcdchapter.cc:159
int64_t get_duration() const
Get chapter duration, in AV_TIME_BASE fractional seconds.
Definition: vcdchapter.cc:134
Video CD entries.
Definition: vcdentries.h:41
uint64_t get_size() const
Get disk size (DAT/MPEG only).
Definition: vcdentries.cc:403
int get_number_of_chapters() const
Get number of chapters on this disk.
Definition: vcdentries.cc:384
const std::string & get_disk_path() const
Get disk directory.
Definition: vcdentries.cc:415
int load_file(const std::string &path)
Load VCD from path.
Definition: vcdentries.cc:70
const VcdChapter * get_chapter(int chapter_idx) const
Get chapter object.
Definition: vcdentries.cc:389
int64_t get_duration() const
Get the total disk duration in AV_TIME_BASE fractional seconds.
Definition: vcdentries.cc:398
std::string format_duration(int64_t value, uint32_t fracs)
Format a time in format HH:MM:SS.fract.
const std::string & append_sep(std::string *path)
Add / to the path if required.
std::string replace_all(std::string str, const std::string &from, const std::string &to)
Same as std::string replace(), but replaces all occurrences.
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
FFMPEGFS_FORMAT_ARR ffmpeg_format
Two FFmpegfs_Format infos, 0: video file, 1: audio file.
Definition: ffmpegfs.cc:73
Main include for FFmpegfs project.
int add_dotdot(void *buf, fuse_fill_dir_t filler, const struct stat *stbuf, off_t off)
Make dot and double dot entries for a virtual directory.
Definition: fuseops.cc:2416
LPVIRTUALFILE insert_dir(VIRTUALTYPE type, const std::string &virtdir, const struct stat *stbuf, int flags=VIRTUALFLAG_NONE)
Add new virtual directory to the internal list. If the file already exists, it will be updated.
Definition: fuseops.cc:1717
int add_fuse_entry(void *buf, fuse_fill_dir_t filler, const std::string &name, const struct stat *stbuf, off_t off)
Wrapper to the Fuse filler function.
Definition: fuseops.cc:2406
int load_path(const std::string &path, const struct stat *statbuf, void *buf, fuse_fill_dir_t filler)
Load a path with virtual files for FUSE.
Definition: fuseops.cc:1759
bool check_path(const std::string &path)
Check if the path has already been parsed. Only useful if for DVD, Blu-ray or VCD where it is guarant...
Definition: fuseops.cc:1752
LPVIRTUALFILE insert_file(VIRTUALTYPE type, const std::string &virtfile, const struct stat *stbuf, int flags=VIRTUALFLAG_NONE)
Add new virtual file to internal list.
Definition: fuseops.cc:1638
@ VCD
Video CD file.
Provide various log facilities to stderr, disk or syslog.
int m_chapter_no
Chapter number (1..)
Definition: fileio.h:179
uint64_t m_start_pos
Start offset in bytes.
Definition: fileio.h:180
uint64_t m_end_pos
End offset in bytes (not including this byte)
Definition: fileio.h:181
int m_track_no
Track number (1..)
Definition: fileio.h:178
Virtual file definition.
Definition: fileio.h:123
bool m_full_title
If true, ignore m_chapter_no and provide full track.
Definition: fileio.h:155
size_t m_predicted_size
Use this as the size instead of computing it over and over.
Definition: fileio.h:157
struct stat m_st
stat structure with size etc.
Definition: fileio.h:153
size_t m_format_idx
Index into params.format[] array.
Definition: fileio.h:149
struct VIRTUALFILE::VCD_CHAPTER m_vcd
S/VCD track/chapter info.
uint32_t m_video_frame_count
Number of frames in video or 0 if not a video.
Definition: fileio.h:158
int64_t m_duration
Track/chapter duration, in AV_TIME_BASE fractional seconds.
Definition: fileio.h:156
S/VCD VcdEntries class.
int check_vcd(const std::string &path, void *buf, fuse_fill_dir_t filler)
Get number of chapters on S/VCD.
Definition: vcdparser.cc:159
static int parse_vcd(const std::string &path, const struct stat *statbuf, void *buf, fuse_fill_dir_t filler)
Parse VCD directory and get all VCD chapters as virtual files.
Definition: vcdparser.cc:130
static bool create_vcd_virtualfile(const VcdEntries &vcd, const struct stat *statbuf, void *buf, fuse_fill_dir_t filler, bool full_title, int chapter_no)
Create a virtual file for a video CD.
Definition: vcdparser.cc:57
Video CD and Super Video CD parser.