37#define VCD_SECTOR_SIZE 2352
38#define VCD_SECTOR_OFFS 24
39#define VCD_SECTOR_DATA 2324
44const std::array<char, 12>
SYNC = {
'\x00',
'\xFF',
'\xFF',
'\xFF',
'\xFF',
'\xFF',
'\xFF',
'\xFF',
'\xFF',
'\xFF',
'\xFF',
'\x00' };
89 uint32_t num_entries = 0;
91 fpi = fopen(fullname.c_str(),
"rb");
94 throw static_cast<int>(errno);
97 if (fstat(fileno(fpi), &stbuf) != 0)
99 throw static_cast<int>(ferror(fpi));
104 std::memset(&vcdentry, 0,
sizeof(vcdentry));
106 if (fread(
reinterpret_cast<char *
>(&vcdentry), 1,
sizeof(vcdentry), fpi) !=
sizeof(vcdentry))
108 throw static_cast<int>(ferror(fpi));
118 for (uint32_t chapter_no = 0, total = num_entries; chapter_no < total; chapter_no++)
134 for (
size_t chapter_no = 0; chapter_no <
m_chapters.size() - 1; chapter_no++)
162 FILE * fpi =
nullptr;
165 std::memset(&stbuf, 0,
sizeof(stbuf));
174 int last_track_no = -1;
175 int64_t first_sync = -1;
178 for (
size_t chapter_no = 0; chapter_no <
m_chapters.size(); chapter_no++)
180 if (last_track_no !=
m_chapters[chapter_no].get_track_no())
182 std::string fullname;
184 last_track_no =
m_chapters[chapter_no].get_track_no();
189 throw static_cast<int>(orgerrno);
194 m_chapters[chapter_no - 1].m_end_pos =
static_cast<uint64_t
>(stbuf.st_size);
202 fpi = fopen(fullname.c_str(),
"rb");
206 throw static_cast<int>(errno);
209 if (fstat(fileno(fpi), &stbuf) != 0)
211 throw static_cast<int>(ferror(fpi));
219 throw static_cast<int>(EIO);
222 first_sync = ftell(fpi) -
static_cast<int64_t
>(
SYNC.size());
227 int64_t last = total_chunks - 1;
228 int64_t middle = (first + last) / 2;
231 while (first <= last)
234 long int file_pos =
static_cast<long int>(first_sync + middle *
VCD_SECTOR_SIZE);
236 if (fseek(fpi, file_pos, SEEK_SET))
238 throw static_cast<int>(ferror(fpi));
241 int orgerrno = buffer.
readio(fpi, last_track_no);
244 throw static_cast<int>(orgerrno);
253 m_chapters[chapter_no].m_start_pos =
static_cast<uint64_t
>(file_pos);
257 m_chapters[chapter_no - 1].m_end_pos =
static_cast<uint64_t
>(file_pos);
266 middle = (first + last) / 2;
275 if (fseek(fpi,
static_cast<long int>(first_sync + (total_chunks - 1) *
VCD_SECTOR_SIZE), SEEK_SET))
277 throw static_cast<int>(ferror(fpi));
280 int orgerrno = buffer.
readio(fpi, last_track_no);
283 throw static_cast<int>(orgerrno);
320 if (fread(&ch, 1, 1, fpi) != 1)
325 for (
size_t n = 1; n <= sync.size(); n++)
327 if (ch != sync[n - 1])
339 if (n == sync.size())
345 if (fread(&ch, 1, 1, fpi) != 1)
395 return &
m_chapters[
static_cast<size_t>(chapter_idx)];
int64_t m_duration
Chapter duration, in AV_TIME_BASE fractional seconds.
int64_t get_start_time() const
Get start position of chapter in AV_TIME_BASE units.
int readio(FILE *fpi, int track_no)
Read file from disk.
VcdEntries()
Construct VcdEntries object.
time_t m_file_date
File date.
std::string m_disk_path
Path to this disk.
VCDTYPE get_type() const
Get disk type.
SEEKRES seek_sync(FILE *fpi, const std::array< char, 12 > &sync) const
Seek for sync bytes.
uint64_t get_size() const
Get disk size (DAT/MPEG only).
std::string m_id
ID of CD.
int get_number_of_chapters() const
Get number of chapters on this disk.
void clear()
Reset this object.
time_t get_file_date() const
Get date of disk (taken from INFO.VCD or SVD).
const std::string & get_disk_path() const
Get disk directory.
VCDPROFILETAG m_profile_tag
System profile tag.
VCDTYPE m_type
Type of CD.
int scan_chapters()
Scan the disk for chapters.
std::vector< VcdChapter > m_chapters
VCD chapters.
int load_file(const std::string &path)
Load VCD from path.
const VcdChapter * get_chapter(int chapter_idx) const
Get chapter object.
int64_t m_duration
Total disk duration, in AV_TIME_BASE fractional seconds.
@ NOTFOUND
Sync not found.
std::string get_type_str() const
Get disk type as string.
std::string get_profile_tag_str() const
Get disk profile tag as string.
int64_t get_duration() const
Get the total disk duration in AV_TIME_BASE fractional seconds.
const std::string & get_id() const
Get disk ID.
VCDPROFILETAG get_profile_tag() const
Get disk profile tag.
bool locate_file(const std::string &path, const std::string &filename, std::string &fullname, bool &is_vcd)
Check if path is a S/VCD.
int locate_video(const std::string &path, int track_no, std::string &fullname)
Locate AVSEQ*DAT/MPEG video file for track_no.
std::string convert_txt2string(const char *txt, int size, bool trimmed)
Non-zero terminated text is converted to std::string.
void get_directory(const std::string &fullname, std::string *directory)
Check if fullname is a directory. Remove the filename if necessary.
std::string get_type_str(VCDTYPE type)
Return disk type as a human readable string.
std::string get_profile_tag_str(VCDPROFILETAG tag)
Profile as a human readable string.
uint16_t m_num_entries
2 Bytes: 1 <= tracks <= 500
std::array< VCDCHAPTER, VCD_MAX_CHAPTERS > m_chapter
Chapters.
uint8_t m_type
1 Byte: CD type
std::array< char, 8 > m_ID
8 Bytes: ID "ENTRYVCD" or "ENTRYSVD"
uint8_t m_profile_tag
1 Byte: System Profile Tag.
@ UNKNOWN
unknown file tag
const std::array< char, 12 > SYNC
Chapter synchronisation in S/VCD mpeg/dat files (12 byte: 0x00FFFFFFFFFFFFFFFFFFFF00)
#define VCD_SECTOR_SIZE
Video CD sector size.