FFmpegfs Fuse Multi Media Filesystem 2.14
dvdio.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 2017-2023 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_LIBDVD
23
34#include "dvdio.h"
35#include "logging.h"
36
37#include <cstring>
38
39#include <dvdread/dvd_reader.h>
40#include <dvdread/nav_read.h>
41
43 : m_dvd(nullptr)
44 , m_dvd_title(nullptr)
45 , m_vmg_file(nullptr)
46 , m_vts_file(nullptr)
47 , m_cur_pgc(nullptr)
48 , m_start_cell(0)
49 , m_end_cell(0)
50 , m_cur_cell(0)
51 , m_next_cell(0)
52 , m_goto_next_cell(false)
53 , m_cur_block(0)
54 , m_is_eof(false)
55 , m_errno(0)
56 , m_rest_size(0)
57 , m_rest_pos(0)
58 , m_cur_pos(0)
59 , m_full_title(false)
60 , m_title_idx(0)
61 , m_chapter_idx(0)
62 , m_angle_idx(0)
63 , m_duration(AV_NOPTS_VALUE)
64 , m_size(0)
65{
66 std::memset(&m_data, 0, sizeof(m_data));
67 std::memset(&m_buffer, 0, sizeof(m_buffer));
68}
69
71{
72 pvt_close();
73}
74
76{
77 return VIRTUALTYPE_DVD;
78}
79
80size_t DvdIO::bufsize() const
81{
82 return sizeof(m_data);
83}
84
86{
87 int pgc_id;
88 int ttn;
89 int pgn;
90 tt_srpt_t *tt_srpt;
91 vts_ptt_srpt_t *vts_ptt_srpt;
92
94
95 if (virtualfile != nullptr)
96 {
102 }
103 else
104 {
105 m_full_title = false;
106 m_title_idx = 0;
107 m_chapter_idx = 0;
108 m_angle_idx = 0;
109 m_duration = AV_NOPTS_VALUE;
110 }
111
112 Logging::debug(path(), "Opening the input DVD.");
113
114 // Open the disc.
115 m_dvd = DVDOpen(path().c_str());
116 if (m_dvd == nullptr)
117 {
118 Logging::error(path(), "Couldn't open the DVD.");
119 return EINVAL;
120 }
121
122 // Load the video manager to find out the information about the titles on this disc.
123 m_vmg_file = ifoOpen(m_dvd, 0);
124 if (m_vmg_file == nullptr)
125 {
126 Logging::error(path(), "Can't open VMG info.");
127 DVDClose(m_dvd);
128 return EINVAL;
129 }
130 tt_srpt = m_vmg_file->tt_srpt;
131
132 // Make sure our title number is valid.
133 Logging::trace(path(), "There are %1 titles on this DVD.", static_cast<uint16_t>(tt_srpt->nr_of_srpts));
134
135 if (m_title_idx < 0 || m_title_idx >= tt_srpt->nr_of_srpts)
136 {
137 Logging::error(path(), "Invalid title %1.", m_title_idx + 1);
138 ifoClose(m_vmg_file);
139 DVDClose(m_dvd);
140 return EINVAL;
141 }
142
143 // Make sure the chapter number is valid for this title.
144 Logging::trace(nullptr, "There are %1 chapters in this title.", static_cast<uint16_t>(tt_srpt->title[m_title_idx].nr_of_ptts));
145
146 if (m_chapter_idx < 0 || m_chapter_idx >= tt_srpt->title[m_title_idx].nr_of_ptts)
147 {
148 Logging::error(path(), "Invalid chapter %1.", m_chapter_idx + 1);
149 ifoClose(m_vmg_file);
150 DVDClose(m_dvd);
151 return EINVAL;
152 }
153
154 // Make sure the angle number is valid for this title.
155 Logging::trace(path(), "There are %1 angles in this title.", tt_srpt->title[m_title_idx].nr_of_angles);
156
157 if (m_angle_idx < 0 || m_angle_idx >= tt_srpt->title[m_title_idx].nr_of_angles)
158 {
159 Logging::error(nullptr, "Invalid angle %1.", m_angle_idx + 1);
160 ifoClose(m_vmg_file);
161 DVDClose(m_dvd);
162 return EINVAL;
163 }
164
165 // Load the VTS information for the title set our title is in.
166 m_vts_file = ifoOpen(m_dvd, tt_srpt->title[m_title_idx].title_set_nr);
167 if (m_vts_file == nullptr)
168 {
169 Logging::error(path(), "Can't open the title %1 info file.", tt_srpt->title[m_title_idx].title_set_nr);
170 ifoClose(m_vmg_file);
171 DVDClose(m_dvd);
172 return EINVAL;
173 }
174
175 // Determine which program chain we want to watch. This is based on the chapter number.
176 ttn = tt_srpt->title[m_title_idx].vts_ttn;
177 vts_ptt_srpt = m_vts_file->vts_ptt_srpt;
178 pgc_id = vts_ptt_srpt->title[ttn - 1].ptt[m_chapter_idx].pgcn;
179 pgn = vts_ptt_srpt->title[ttn - 1].ptt[m_chapter_idx].pgn;
180 m_cur_pgc = m_vts_file->vts_pgcit->pgci_srp[pgc_id - 1].pgc;
181 m_start_cell = m_cur_pgc->program_map[pgn - 1] - 1;
182
183 if (pgn < m_cur_pgc->nr_of_programs)
184 {
185 m_end_cell = m_cur_pgc->program_map[pgn] - 1;
186 }
187 else
188 {
189 m_end_cell = m_cur_pgc->nr_of_cells;
190 }
191
192 // We've got enough info, time to open the title set data.
193 m_dvd_title = DVDOpenFile(m_dvd, tt_srpt->title[m_title_idx].title_set_nr, DVD_READ_TITLE_VOBS);
194 if (m_dvd_title == nullptr)
195 {
196 Logging::error(path(), "Can't open title VOBS (VTS_%<%02d>1_X.VOB).", tt_srpt->title[m_title_idx].title_set_nr);
197 ifoClose(m_vts_file);
198 ifoClose(m_vmg_file);
199 DVDClose(m_dvd);
200 return EINVAL;
201 }
202
203 rewind();
204
205 // Determine the net file size
206 m_size = 0;
207 size_t bytes_read;
208
209 while ((bytes_read = readio(nullptr, ULONG_MAX)) != 0 && !eof())
210 {
211 m_size += bytes_read;
212 }
213
214 rewind();
215
216 return 0;
217}
218
219// Demux and cell navigation nicked from https://www.videolan.org/vlc/download-sources.html
220// More details see http://stnsoft.com/DVD/vobov.html
221
222#define PS_STREAM_ID_END_STREAM 0xB9
223#define PS_STREAM_ID_PACK_HEADER 0xBA
224#define PS_STREAM_ID_SYSTEM_HEADER 0xBB
225#define PS_STREAM_ID_MAP 0xBC
226#define PS_STREAM_ID_PRIVATE_STREAM1 0xBD
227#define PS_STREAM_ID_PADDING 0xBE
228#define PS_STREAM_ID_PRIVATE 0xBF
229#define PS_STREAM_ID_AUDIO 0xC0
230#define PS_STREAM_ID_VIDEO 0xE0
231#define PS_STREAM_ID_EXTENDED 0xFD
232#define PS_STREAM_ID_DIRECTORY 0xFF
234#define PS_STREAM_ID 3
236bool DvdIO::get_packet_size(const uint8_t *p, size_t peek, size_t *size) const
237{
238 if (peek < 4)
239 {
240 return false; // Invalid size
241 }
242
243 switch (p[PS_STREAM_ID])
244 {
246 {
247 *size = 4;
248 return true;
249 }
251 {
252 // MPEG-2 pack header, see http://stnsoft.com/DVD/packhdr.html
253 if (peek > 4)
254 {
255 if (peek >= 14 && (p[4] >> 6) == 0x01)
256 {
257 *size = 14 + static_cast<size_t>(p[13] & 0x07); // Byte 13 Bit 0..2: Pack stuffing length
258 return true;
259 }
260 else if (peek >= 12 && (p[4] >> 4) == 0x02)
261 {
262 *size = 12; // unclear what this is for
263 return true;
264 }
265 }
266 break;
267 }
268 case PS_STREAM_ID_SYSTEM_HEADER: // http://stnsoft.com/DVD/sys_hdr.html, see http://stnsoft.com/DVD/sys_hdr.html
269 case PS_STREAM_ID_MAP: // ???
270 case PS_STREAM_ID_DIRECTORY: // ???
271 default:
272 {
273 if (peek >= 6)
274 {
275 *size = (6 + ((static_cast<unsigned int>(p[4]) << 8) | p[5])); // Byte 4/5: header length
276 return true;
277 }
278 break;
279 }
280 }
281 return false; // unknown ID
282}
283
284int DvdIO::get_pes_id(const uint8_t *buffer, size_t size) const
285{
287 {
288 uint8_t sub_id = 0;
289 if (size >= 9 && size >= static_cast<unsigned int>(9 + buffer[8]))
290 {
291 const size_t start = static_cast<size_t>(9 + buffer[8]);
292 sub_id = buffer[start];
293
294 if ((sub_id & 0xfe) == 0xa0 &&
295 size >= start + 7 &&
296 (buffer[start + 5] >= 0xc0 ||
297 buffer[start + 6] != 0x80))
298 {
299 // AOB LPCM/MLP extension
300 // XXX for MLP I think that the !=0x80 test is not good and
301 // will fail for some valid files
302 return (0xa000 | (sub_id & 0x01));
303 }
304 }
305
306 // VOB extension
307 return (0xbd00 | sub_id);
308 }
309 else if (buffer[PS_STREAM_ID] == PS_STREAM_ID_EXTENDED &&
310 size >= 9 &&
311 (buffer[6] & 0xC0) == 0x80 && // mpeg2
312 (buffer[7] & 0x01) == 0x01) // extension_flag
313 {
314 // ISO 13818 amendment 2 and SMPTE RP 227
315 const uint8_t flags = buffer[7];
316 size_t skip = 9;
317
318 // Find PES extension
319 if ((flags & 0x80))
320 {
321 skip += 5; // pts
322 if ((flags & 0x40))
323 {
324 skip += 5; // dts
325 }
326 }
327 if ((flags & 0x20))
328 {
329 skip += 6;
330 }
331 if ((flags & 0x10))
332 {
333 skip += 3;
334 }
335 if ((flags & 0x08))
336 {
337 skip += 1;
338 }
339 if ((flags & 0x04))
340 {
341 skip += 1;
342 }
343 if ((flags & 0x02))
344 {
345 skip += 2;
346 }
347
348 if (skip < size && (buffer[skip] & 0x01))
349 {
350 const uint8_t flags2 = buffer[skip];
351
352 // Find PES extension 2
353 skip += 1;
354 if (flags2 & 0x80)
355 {
356 skip += 16;
357 }
358 if ((flags2 & 0x40) && skip < size)
359 {
360 skip += static_cast<size_t>(1 + buffer[skip]);
361 }
362 if (flags2 & 0x20)
363 {
364 skip += 2;
365 }
366 if (flags2 & 0x10)
367 {
368 skip += 2;
369 }
370
371 if (skip + 1 < size)
372 {
373 const int i_extension_field_length = buffer[skip] & 0x7f;
374 if (i_extension_field_length >=1)
375 {
376 int i_stream_id_extension_flag = (buffer[skip+1] >> 7) & 0x1;
377 if (i_stream_id_extension_flag == 0)
378 {
379 return (0xfd00 | (buffer[skip+1] & 0x7f));
380 }
381 }
382 }
383 }
384 }
385 return buffer[PS_STREAM_ID];
386}
387
388size_t DvdIO::demux_pes(uint8_t *out, const uint8_t *in, size_t len) const
389{
390 size_t netsize = 0;
391 while (len > 0)
392 {
393 size_t pktsize = 0;
394 if (!get_packet_size(in, len, &pktsize) || pktsize > len)
395 {
396 break;
397 }
398
399 // Parse block and copy to buffer
400 switch (0x100 | in[PS_STREAM_ID])
401 {
402 // Ignore thesse...
403 case (0x100 | PS_STREAM_ID_END_STREAM):
404 case (0x100 | PS_STREAM_ID_SYSTEM_HEADER):
405 case (0x100 | PS_STREAM_ID_MAP):
406 {
407 break;
408 }
409 case (0x100 | PS_STREAM_ID_PACK_HEADER): // MPEG-2 Pack Header
410 {
411 std::memcpy(out, in, pktsize);
412 out += pktsize;
413 netsize += pktsize;
414 break;
415 }
416 default:
417 {
418 int id = get_pes_id(in, pktsize);
419 if (id >= PS_STREAM_ID_AUDIO) // Audio/Video/Extended or Directory
420 {
421 // Probably this is sufficient here:
422 // 110x xxxx 0xC0 - 0xDF MPEG-1 or MPEG-2 audio stream number x xxxx
423 // 1110 xxxx 0xE0 - 0xEF MPEG-1 or MPEG-2 video stream number xxxx
424 std::memcpy(out, in, pktsize);
425 out += pktsize;
426 netsize += pktsize;
427 }
428 break;
429 }
430 }
431
432 in += pktsize;
433 len -= pktsize;
434 }
435
436 return netsize;
437}
438
439DvdIO::DSITYPE DvdIO::handle_DSI(void *_dsi_pack, size_t * cur_output_size, unsigned int *next_block, uint8_t *data)
440{
441 dsi_t * dsi_pack = reinterpret_cast<dsi_t*>(_dsi_pack);
442 DSITYPE dsitype = DSITYPE_CONTINUE;
443 bool end_of_cell;
444
445 navRead_DSI(dsi_pack, &data[DSI_START_BYTE]);
446
447 // Determine where we go next. These values are the ones we mostly
448 // care about.
449 m_cur_block = dsi_pack->dsi_gi.nv_pck_lbn;
450 *cur_output_size = dsi_pack->dsi_gi.vobu_ea;
451
452 // If we're not at the end of this cell, we can determine the next
453 // VOBU to display using the VOBU_SRI information section of the
454 // DSI. Using this value correctly follows the current angle,
455 // avoiding the doubled scenes in The Matrix, and makes our life
456 // really happy.
457
458 *next_block = m_cur_block + (dsi_pack->vobu_sri.next_vobu & 0x7fffffff);
459 end_of_cell = (dsi_pack->vobu_sri.next_vobu == SRI_END_OF_CELL || *next_block >= m_cur_pgc->cell_playback[m_cur_cell].last_sector); // Double check end of cell: DVD transcoding stops in the middle of the chapter #48
460
461 if (!end_of_cell && m_angle_idx > 1)
462 {
463 switch ((dsi_pack->sml_pbi.category & 0xf000) >> 12)
464 {
465 case 0x4:
466 {
467 // Interleaved unit with no angle
468 // dsi_pack->sml_pbi.ilvu_sa
469 // relative offset to the next ILVU block (not VOBU) for this angle or scene.
470 // 00 00 00 00 for PREU and non-interleaved blocks
471 // ff ff ff ff for the last interleaved block, indicating the end of interleaving
472 if (dsi_pack->sml_pbi.ilvu_sa != 0 && dsi_pack->sml_pbi.ilvu_sa != 0xffffffff)
473 {
474 *next_block = m_cur_block + dsi_pack->sml_pbi.ilvu_sa;
475 *cur_output_size = dsi_pack->sml_pbi.ilvu_ea;
476 }
477 else
478 {
479 *next_block = m_cur_block + dsi_pack->dsi_gi.vobu_ea + 1;
480 }
481 break;
482 }
483 case 0x5:
484 {
485 // vobu is end of ilvu
486 if (dsi_pack->sml_agli.data[m_angle_idx].address)
487 {
488 *next_block = m_cur_block + dsi_pack->sml_agli.data[m_angle_idx].address;
489 *cur_output_size = dsi_pack->sml_pbi.ilvu_ea;
490 break;
491 }
492 }
493 // fall through
494 case 0x6: // vobu is beginning of ilvu
495 case 0x9: // next scr is 0
496 case 0xa: // entering interleaved section
497 case 0x8: // non interleaved cells in interleaved section
498 default:
499 {
500 *next_block = m_cur_block + (dsi_pack->vobu_sri.next_vobu & 0x7fffffff);
501 break;
502 }
503 }
504 }
505 else if (end_of_cell)
506 {
507 if (m_next_cell >= m_cur_pgc->nr_of_cells)
508 {
509 *next_block = 0;
510 dsitype = DSITYPE_EOF_TITLE;
511 }
512 else
513 {
515
516 next_cell();
517
518 if (m_cur_cell >= m_end_cell)
519 {
520 dsitype = DSITYPE_EOF_CHAPTER;
521 }
522
523 *next_block = m_cur_pgc->cell_playback[m_cur_cell].first_sector;
524 }
525 }
526
527 return dsitype;
528}
529
531{
532 // Check if we're entering an angle block
533 if (m_cur_pgc->cell_playback[m_cur_cell].block_type == static_cast<unsigned int>(BLOCK_TYPE_ANGLE_BLOCK))
534 {
536
537 for (int i = 0;; ++i)
538 {
539 if (m_cur_pgc->cell_playback[m_cur_cell + i].block_mode == static_cast<unsigned int>(BLOCK_MODE_LAST_CELL))
540 {
541 m_next_cell = m_cur_cell + i + 1;
542 break;
543 }
544 }
545 }
546 else
547 {
549 }
550}
551
552size_t DvdIO::readio(void * data, size_t size)
553{
554 size_t cur_output_size;
555 size_t result_len = 0;
556 DSITYPE dsitype;
557
558 if (m_rest_size)
559 {
560 size_t rest_size = m_rest_size;
561
562 if (m_rest_size > size)
563 {
564 errno = EINVAL;
565 return 0;
566 }
567
568 if (data != nullptr)
569 {
570 std::memcpy(data, &m_data[m_rest_pos], rest_size);
571 }
572
574
575 return rest_size;
576 }
577
578 // Playback by cell in this pgc, starting at the cell for our chapter.
579 //while (next_cell < last_cell)
580 {
582 {
583 m_goto_next_cell = false;
584
586
587 next_cell();
588
589 m_cur_block = m_cur_pgc->cell_playback[m_cur_cell].first_sector;
590 }
591
592 if (m_cur_block >= m_cur_pgc->cell_playback[m_cur_cell].last_sector)
593 {
594 m_is_eof = false;
595 return 0;
596 }
597
598 // We loop until we're out of this cell.
599 //for(cur_pack = cur_pgc->cell_playback[cur_cell].first_sector;
600 // cur_pack < cur_pgc->cell_playback[cur_cell].last_sector;)
601 {
602 dsi_t dsi_pack;
603 unsigned int next_block;
604 ssize_t maxlen;
605
606 // Read NAV packet.
607 maxlen = DVDReadBlocks(m_dvd_title, static_cast<int>(m_cur_block), 1, m_buffer);
608 if (maxlen != 1)
609 {
610 Logging::error(path(), "Read failed for block at %1.", m_cur_block);
611 m_errno = EIO;
612 return 0;
613 }
614
615 if (!is_nav_pack(m_buffer))
616 {
617 Logging::warning(path(), "Block at %1 is probably not a NAV packet. Transcode may fail.", m_cur_block);
618 }
619
620 // Parse the contained dsi packet.
621 dsitype = handle_DSI(&dsi_pack, &cur_output_size, &next_block, m_buffer);
622 if (m_cur_block != dsi_pack.dsi_gi.nv_pck_lbn)
623 {
624 Logging::error(path(), "Read failed at %1 because current block != dsi_pack.dsi_gi.nv_pck_lbn.", m_cur_block);
625 m_errno = EIO;
626 return 0;
627 }
628
629 if (cur_output_size >= 1024)
630 {
631 Logging::error(path(), "Read failed at %1 because current output size %2 >= 1024.", m_cur_block, cur_output_size);
632 m_errno = EIO;
633 return 0;
634 }
635
636 m_cur_block++;
637
638 // Read in and output cur_output_size packs.
639 maxlen = DVDReadBlocks(m_dvd_title, static_cast<int>(m_cur_block), cur_output_size, m_buffer);
640
641 if (maxlen != static_cast<int>(cur_output_size))
642 {
643 Logging::error(path(), "Read failed for %1 blocks at %2.", cur_output_size, m_cur_block);
644 m_errno = EIO;
645 return 0;
646 }
647
648 size_t netsize = cur_output_size * DVD_VIDEO_LB_LEN;
649
650 netsize = demux_pes(m_data, m_buffer, netsize);
651
652 if (data != nullptr)
653 {
654 if (netsize > size)
655 {
656 result_len = size;
657
658 std::memcpy(data, m_data, result_len);
659
660 m_rest_size = netsize - size;
662 }
663 else
664 {
665 result_len = netsize;
666
667 std::memcpy(data, m_data, result_len);
668 }
669 }
670 else
671 {
672 if (netsize > size)
673 {
674 result_len = size;
675 }
676 else
677 {
678 result_len = netsize;
679 }
680 }
681
682 m_cur_block = next_block;
683 }
684
685 //break;
686 }
687
688 // DSITYPE_EOF_TITLE - end of title
689 // DSITYPE_EOF_CHAPTER - end of chapter
690 if ((dsitype != DSITYPE_CONTINUE && !m_full_title) || // Stop at end of chapter/title
691 (dsitype == DSITYPE_EOF_TITLE)) // Stop at end of title
692 {
693 m_is_eof = true;
694 }
695
696 m_cur_pos += result_len;
697
698 return result_len;
699}
700
701int DvdIO::error() const
702{
703 return m_errno;
704}
705
706int64_t DvdIO::duration() const
707{
708 return m_duration;
709}
710
711size_t DvdIO::size() const
712{
713 return m_size;
714}
715
716size_t DvdIO::tell() const
717{
718 return m_cur_pos;
719}
720
722{
725
726 m_goto_next_cell = true;
727 m_is_eof = false;
728 m_errno = 0;
729 m_rest_size = 0;
730 m_rest_pos = 0;
731 m_cur_pos = 0;
732}
733
734int DvdIO::seek(int64_t offset, int whence)
735{
736 errno = 0;
737
738 if (whence == SEEK_SET && !offset)
739 {
740 // Only rewind (seek(0, SEEK_SET) is implemented yet
741 rewind();
742 return 0;
743 }
744 size_t cur_pos = tell();
745 size_t abs_offset = 0;
746
747 switch (whence)
748 {
749 case SEEK_SET:
750 abs_offset = static_cast<size_t>(offset);
751 break;
752 case SEEK_CUR:
753 abs_offset += cur_pos;
754 break;
755 case SEEK_END:
756 abs_offset = size() - abs_offset;
757 break;
758 default:
759 errno = EINVAL;
760 return (EOF);
761 }
762
763 if (cur_pos == abs_offset)
764 {
765 // Already at right position
766 return static_cast<int>(abs_offset);
767 }
768
769 if (cur_pos > abs_offset)
770 {
771 // Need to start from beginning to find byte position
772 rewind();
773 cur_pos = 0;
774 }
775
776 size_t total_read = 0;
777 size_t bytes_read;
778 while ((bytes_read = readio(nullptr, abs_offset - total_read - cur_pos)) != 0 && total_read < abs_offset && !eof())
779 {
780 total_read += bytes_read;
781 }
782
783 if (total_read)
784 {
785 return static_cast<int>(cur_pos + total_read);
786 }
787
788 errno = EPERM;
789 return (EOF);
790}
791
792bool DvdIO::eof() const
793{
794 return m_is_eof;
795}
796
798{
799 pvt_close();
800}
801
803{
804 ifo_handle_t * vts_file = m_vts_file;
805 if (vts_file != nullptr)
806 {
807 m_vts_file = nullptr;
808 ifoClose(vts_file);
809 }
810 ifo_handle_t * vmg_file = m_vmg_file;
811 if (vmg_file != nullptr)
812 {
813 m_vmg_file = nullptr;
814 ifoClose(vmg_file);
815 }
816 dvd_file_t * dvd_title = m_dvd_title;
817 if (dvd_title != nullptr)
818 {
819 m_dvd_title = nullptr;
820 DVDCloseFile(dvd_title);
821 }
822 dvd_reader_t * dvd = m_dvd;
823 if (dvd != nullptr)
824 {
825 m_dvd = nullptr;
826 DVDClose(dvd);
827 }
828}
829
830// Code nicked from Handbrake (https://github.com/HandBrake/HandBrake/blob/master/libhb/dvd.c)
831bool DvdIO::is_nav_pack(const unsigned char *buffer) const
832{
833 /*
834 * The NAV Pack is comprised of the PCI Packet and DSI Packet, both
835 * of these start at known offsets and start with a special identifier.
836 *
837 * NAV = {
838 * PCI = { 00 00 01 bf # private stream header
839 * ?? ?? # length
840 * 00 # substream
841 * ...
842 * }
843 * DSI = { 00 00 01 bf # private stream header
844 * ?? ?? # length
845 * 01 # substream
846 * ...
847 * }
848 *
849 * The PCI starts at offset 0x26 into the sector, and the DSI starts at 0x400
850 *
851 * This information from: http://dvd.sourceforge.net/dvdinfo/
852 */
853 if ((buffer[0x26] == 0x00 && // PCI
854 buffer[0x27] == 0x00 &&
855 buffer[0x28] == 0x01 &&
856 buffer[0x29] == 0xbf &&
857 buffer[0x2c] == 0x00) &&
858 (buffer[0x400] == 0x00 && // DSI
859 buffer[0x401] == 0x00 &&
860 buffer[0x402] == 0x01 &&
861 buffer[0x403] == 0xbf &&
862 buffer[0x406] == 0x01))
863 {
864 return true;
865 }
866 else
867 {
868 return false;
869 }
870}
871
872#endif // USE_LIBDVD
873
unsigned char m_data[1024 *DVD_VIDEO_LB_LEN]
Buffer for readio() data.
Definition: dvdio.h:225
bool m_is_eof
true if at "end of file", i.e, end of chapter or title
Definition: dvdio.h:214
bool get_packet_size(const uint8_t *p, size_t peek, size_t *size) const
return the size of the next packet
Definition: dvdio.cc:236
int m_cur_cell
Current cell.
Definition: dvdio.h:210
int m_errno
errno of last operation
Definition: dvdio.h:215
virtual VIRTUALTYPE type() const override
Get type of the virtual file.
Definition: dvdio.cc:75
bool m_goto_next_cell
If logc needs to go to next cell before next read.
Definition: dvdio.h:212
bool m_full_title
If true, ignore m_chapter_no and provide full track.
Definition: dvdio.h:220
void rewind()
Rewind to start of stream.
Definition: dvdio.cc:721
virtual int seek(int64_t offset, int whence) override
Seek to position in file.
Definition: dvdio.cc:734
virtual size_t size() const override
Get the file size.
Definition: dvdio.cc:711
size_t m_size
Size of virtual file.
Definition: dvdio.h:229
DSITYPE handle_DSI(void *_dsi_pack, size_t *cur_output_size, unsigned int *next_block, uint8_t *data)
Handle DSI (Data Search Information) packet.
Definition: dvdio.cc:439
void pvt_close()
Close virtual file. Non-virtual version to be safely called from constructor/destructor.
Definition: dvdio.cc:802
ifo_handle_t * m_vmg_file
DVD video manager handle.
Definition: dvdio.h:205
bool is_nav_pack(const unsigned char *buffer) const
Do a rough check if this is really a navigation packet.
Definition: dvdio.cc:831
size_t m_rest_size
Rest bytes in buffer.
Definition: dvdio.h:216
int m_title_idx
Track index (track number - 1)
Definition: dvdio.h:221
virtual void closeio() override
Close virtual file.
Definition: dvdio.cc:797
virtual size_t bufsize() const override
Get the ideal buffer size.
Definition: dvdio.cc:80
void next_cell()
Goto next DVD cell.
Definition: dvdio.cc:530
int64_t m_duration
Track/chapter duration, in AV_TIME_BASE fractional seconds.
Definition: dvdio.h:228
DSITYPE
Type of a DSI block.
Definition: dvdio.h:57
@ DSITYPE_EOF_CHAPTER
End of chapter.
Definition: dvdio.h:59
@ DSITYPE_EOF_TITLE
End of title.
Definition: dvdio.h:60
@ DSITYPE_CONTINUE
Chapter continues.
Definition: dvdio.h:58
DvdIO()
Create DvdIO object.
Definition: dvdio.cc:42
virtual int openio(LPVIRTUALFILE virtualfile) override
Open a virtual file.
Definition: dvdio.cc:85
int m_next_cell
Next cell to be processed.
Definition: dvdio.h:211
int get_pes_id(const uint8_t *buffer, size_t size) const
return the id of a Packetized Elementary Stream (PES) (should be valid)
Definition: dvdio.cc:284
virtual bool eof() const override
Check if at end of file.
Definition: dvdio.cc:792
virtual size_t readio(void *data, size_t size) override
Read data from file.
Definition: dvdio.cc:552
virtual int error() const override
Get last error.
Definition: dvdio.cc:701
int m_chapter_idx
Chapter index (chapter number - 1)
Definition: dvdio.h:222
size_t m_cur_pos
Current position in virtual file.
Definition: dvdio.h:218
ifo_handle_t * m_vts_file
DVD video title stream handle.
Definition: dvdio.h:206
dvd_reader_t * m_dvd
DVD reader handle.
Definition: dvdio.h:203
pgc_t * m_cur_pgc
Current program chain.
Definition: dvdio.h:207
dvd_file_t * m_dvd_title
DVD title handle.
Definition: dvdio.h:204
virtual ~DvdIO()
Free DvdIO object.
Definition: dvdio.cc:70
unsigned char m_buffer[1024 *DVD_VIDEO_LB_LEN]
Buffer for data extracted from VOB file.
Definition: dvdio.h:226
int m_angle_idx
Selected angle index (angle number -1)
Definition: dvdio.h:223
size_t m_rest_pos
Position in buffer.
Definition: dvdio.h:217
unsigned int m_cur_block
Current processing block.
Definition: dvdio.h:213
int m_end_cell
End cell (of title)
Definition: dvdio.h:209
int m_start_cell
Start cell.
Definition: dvdio.h:208
virtual size_t tell() const override
Get current read position.
Definition: dvdio.cc:716
size_t demux_pes(uint8_t *out, const uint8_t *in, size_t len) const
Extract only the interesting portion of the VOB input stream.
Definition: dvdio.cc:388
virtual int64_t duration() const override
Get the duration of the file, in AV_TIME_BASE fractional seconds.
Definition: dvdio.cc:706
const std::string & path() const
Path to source file (without file name)
Definition: fileio.cc:119
LPVIRTUALFILE virtualfile()
Get virtual file object.
Definition: fileio.cc:114
void set_virtualfile(LPVIRTUALFILE virtualfile)
Set the virtual file object.
Definition: fileio.cc:97
static void warning(const T filename, const std::string &format_string, Args &&...args)
Write warning level log entry.
Definition: logging.h:220
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
#define PS_STREAM_ID_MAP
???
Definition: dvdio.cc:225
#define PS_STREAM_ID_DIRECTORY
???
Definition: dvdio.cc:232
#define PS_STREAM_ID_AUDIO
0xDF MPEG-1 or MPEG-2 audio stream number (note: DVD allows only 8 audio streams)
Definition: dvdio.cc:229
#define PS_STREAM_ID_END_STREAM
???
Definition: dvdio.cc:222
#define PS_STREAM_ID_EXTENDED
???
Definition: dvdio.cc:231
#define PS_STREAM_ID_PRIVATE_STREAM1
Private stream 1 (non MPEG audio, subpictures)
Definition: dvdio.cc:226
#define PS_STREAM_ID_SYSTEM_HEADER
Program Stream System Header.
Definition: dvdio.cc:224
#define PS_STREAM_ID
???
Definition: dvdio.cc:234
#define PS_STREAM_ID_PACK_HEADER
MPEG-2 Pack Header.
Definition: dvdio.cc:223
DVD I/O.
VIRTUALTYPE
Virtual file types enum.
Definition: fileio.h:90
@ VIRTUALTYPE_DVD
DVD file.
Definition: fileio.h:98
Provide various log facilities to stderr, disk or syslog.
int m_angle_no
Selected angle number (1...n)
Definition: fileio.h:195
int m_title_no
Track number (1...n)
Definition: fileio.h:193
int m_chapter_no
Chapter number (1...n)
Definition: fileio.h:194
Virtual file definition.
Definition: fileio.h:121
struct VIRTUALFILE::DVD_CHAPTER m_dvd
DVD title/chapter info.
bool m_full_title
If true, ignore m_chapter_no and provide full track.
Definition: fileio.h:153
int64_t m_duration
Track/chapter duration, in AV_TIME_BASE fractional seconds.
Definition: fileio.h:154