35 #include <dvdnav/dvdnav.h>
36 #include <dvdread/dvd_reader.h>
37 #include <dvdread/ifo_read.h>
38 #include <dvdread/ifo_types.h>
39 #include <dvdread/nav_read.h>
58 #define DVDVIDEO_MAX_PS_SEARCH_BLOCKS 128
59 #define DVDVIDEO_BLOCK_SIZE 2048
60 #define DVDVIDEO_TIME_BASE_Q (AVRational) { 1, 90000 }
61 #define DVDVIDEO_PTS_WRAP_BITS 64
62 #define DVDVIDEO_LIBDVDX_LOG_BUFFER_SIZE 1024
64 #define PCI_START_BYTE 45
74 "Fullscreen",
"Widescreen",
"Letterbox",
"Pan and Scan"
174 const char *msg, va_list msg_va)
180 vsnprintf(msg_buf,
sizeof(msg_buf), msg, msg_va);
182 if (
level == DVD_LOGGER_LEVEL_ERROR)
184 else if (
level == DVD_LOGGER_LEVEL_WARN)
187 av_log(
s, lavu_level,
"libdvdread: %s\n", msg_buf);
191 const char *msg, va_list msg_va)
197 vsnprintf(msg_buf,
sizeof(msg_buf), msg, msg_va);
199 if (
level == DVDNAV_LOGGER_LEVEL_ERROR)
205 av_log(
s, lavu_level,
"libdvdnav: %s\n", msg_buf);
213 ifoClose(
c->vts_ifo);
216 ifoClose(
c->vmg_ifo);
219 DVDClose(
c->dvdread);
226 dvd_logger_cb dvdread_log_cb;
227 title_info_t title_info;
230 c->dvdread = DVDOpen2(
s, &dvdread_log_cb,
s->url);
238 if (!(
c->vmg_ifo = ifoOpen(
c->dvdread, 0))) {
245 if (
c->opt_menu_vts > 0 && !(
c->vts_ifo = ifoOpen(
c->dvdread,
c->opt_menu_vts))) {
254 if (
c->opt_title >
c->vmg_ifo->tt_srpt->nr_of_srpts) {
260 title_info =
c->vmg_ifo->tt_srpt->title[
c->opt_title - 1];
261 if (
c->opt_angle > title_info.nr_of_angles) {
267 if (title_info.nr_of_ptts < 1) {
273 if (
c->opt_chapter_start > title_info.nr_of_ptts ||
274 (
c->opt_chapter_end > 0 &&
c->opt_chapter_end > title_info.nr_of_ptts)) {
276 c->opt_chapter_start,
c->opt_chapter_end);
281 if (!(
c->vts_ifo = ifoOpen(
c->dvdread, title_info.title_set_nr))) {
283 title_info.title_set_nr);
288 if (title_info.vts_ttn < 1 ||
289 title_info.vts_ttn > 99 ||
290 title_info.vts_ttn >
c->vts_ifo->vts_ptt_srpt->nr_of_srpts ||
291 c->vts_ifo->vtsi_mat->nr_of_vts_audio_streams > 8 ||
292 c->vts_ifo->vtsi_mat->nr_of_vts_subp_streams > 32) {
303 dvd_time_t cell_duration = pgc->cell_playback[celln - 1].playback_time;
305 return cell_duration.second >= 1 || cell_duration.minute >= 1 || cell_duration.hour >= 1;
310 for (
int i = 1;
i <= pgc->nr_of_cells;
i++)
320 DVDCloseFile(
state->vob_file);
328 pgci_ut =
c->opt_menu_vts ?
c->vts_ifo->pgci_ut :
c->vmg_ifo->pgci_ut;
331 c->opt_menu_lu,
c->opt_pgc);
336 if (
c->opt_pgc < 1 ||
337 c->opt_menu_lu < 1 ||
338 c->opt_menu_lu > pgci_ut->nr_of_lus ||
339 c->opt_pgc > pgci_ut->lu[
c->opt_menu_lu - 1].pgcit->nr_of_pgci_srp) {
347 state->pgcn =
c->opt_pgc - 1;
348 state->pgc = pgci_ut->lu[
c->opt_menu_lu - 1].pgcit->pgci_srp[
c->opt_pgc - 1].pgc;
349 if (!
state->pgc || !
state->pgc->program_map || !
state->pgc->cell_playback) {
351 c->opt_menu_lu,
c->opt_pgc);
357 state->entry_pgn =
c->opt_pg;
358 if (
state->entry_pgn < 1 ||
state->entry_pgn >
state->pgc->nr_of_programs) {
368 if (
state->celln_start >
state->pgc->nr_of_cells) {
374 state->sector_end =
state->pgc->cell_playback[
state->celln - 1].last_sector;
375 state->vobu_next =
state->pgc->cell_playback[
state->celln - 1].first_sector;
378 if (
c->opt_menu_vts > 0)
381 if (!(
state->vob_file = DVDOpenFile(
c->dvdread,
c->opt_menu_vts, DVD_READ_MENU_VOBS))) {
383 "Unable to open main menu VOB (VIDEO_TS.VOB)\n" :
384 "Unable to open menu VOBs for VTS %d\n",
c->opt_menu_vts);
393 uint8_t *buf,
int buf_size,
398 pci_t pci = (pci_t) {0};
399 dsi_t dsi = (dsi_t) {0};
409 if (!
state->vobu_remaining &&
state->in_pgc) {
410 if (
state->vobu_next == SRI_END_OF_CELL) {
415 state->sector_offset =
state->pgc->cell_playback[
state->celln - 1].first_sector;
416 state->sector_end =
state->pgc->cell_playback[
state->celln - 1].last_sector;
425 blocks_read = DVDReadBlocks(
state->vob_file,
state->sector_offset, 1, read_buf);
426 if (blocks_read != 1) {
428 state->sector_offset, blocks_read);
434 if (!
state->vobu_remaining) {
438 read_buf[DSI_START_BYTE - 1] != 0x01) {
441 state->sector_offset);
447 navRead_DSI(&dsi, &read_buf[DSI_START_BYTE]);
449 if (!pci.pci_gi.vobu_s_ptm ||
450 !pci.pci_gi.vobu_e_ptm ||
451 pci.pci_gi.vobu_s_ptm > pci.pci_gi.vobu_e_ptm) {
454 state->sector_offset);
459 state->vobu_remaining = dsi.dsi_gi.vobu_ea;
460 state->vobu_next = dsi.vobu_sri.next_vobu == SRI_END_OF_CELL ? SRI_END_OF_CELL :
461 dsi.dsi_gi.nv_pck_lbn + (dsi.vobu_sri.next_vobu & 0x7FFFFFFF);
462 state->sector_offset++;
465 if (
state->vobu_e_ptm != pci.pci_gi.vobu_s_ptm) {
469 state->ts_offset +=
state->vobu_e_ptm - pci.pci_gi.vobu_s_ptm;
476 state->vobu_e_ptm = pci.pci_gi.vobu_e_ptm;
479 "vobu_s_ptm=%d vobu_e_ptm=%d ts_offset=%" PRId64
"\n",
480 dsi.dsi_gi.nv_pck_lbn,
481 pci.pci_gi.vobu_s_ptm, pci.pci_gi.vobu_e_ptm,
state->ts_offset);
488 state->sector_offset++;
489 state->vobu_remaining--;
500 if (
state->pgc_pg_times_est)
501 free(
state->pgc_pg_times_est);
503 if (dvdnav_close(
state->dvdnav) != DVDNAV_STATUS_OK)
505 dvdnav_err_to_string(
state->dvdnav));
512 dvdnav_logger_cb dvdnav_log_cb;
513 dvdnav_status_t dvdnav_open_status;
516 int cur_title, cur_pgcn, cur_pgn;
520 dvdnav_open_status = dvdnav_open2(&
state->dvdnav,
s, &dvdnav_log_cb,
s->url);
522 if (!
state->dvdnav ||
523 dvdnav_open_status != DVDNAV_STATUS_OK ||
524 dvdnav_set_readahead_flag(
state->dvdnav, 0) != DVDNAV_STATUS_OK ||
525 dvdnav_set_PGC_positioning_flag(
state->dvdnav, 1) != DVDNAV_STATUS_OK ||
526 dvdnav_get_region_mask(
state->dvdnav, &disc_region_mask) != DVDNAV_STATUS_OK) {
529 goto end_dvdnav_error;
532 player_region_mask =
c->opt_region > 0 ? (1 << (
c->opt_region - 1)) : disc_region_mask;
533 if (dvdnav_set_region_mask(
state->dvdnav, player_region_mask) != DVDNAV_STATUS_OK) {
536 goto end_dvdnav_error;
539 if (
c->opt_pgc > 0 &&
c->opt_pg > 0) {
540 if (dvdnav_program_play(
state->dvdnav,
c->opt_title,
c->opt_pgc,
c->opt_pg) != DVDNAV_STATUS_OK) {
542 c->opt_title,
c->opt_pgc,
c->opt_pg);
544 goto end_dvdnav_error;
548 state->entry_pgn =
c->opt_pg;
550 if (dvdnav_part_play(
state->dvdnav,
c->opt_title,
c->opt_chapter_start) != DVDNAV_STATUS_OK ||
551 dvdnav_current_title_program(
state->dvdnav, &cur_title, &cur_pgcn, &cur_pgn) != DVDNAV_STATUS_OK) {
554 c->opt_title,
c->opt_chapter_start);
555 goto end_dvdnav_error;
558 state->pgcn = cur_pgcn;
559 state->entry_pgn = cur_pgn;
562 pgc =
c->vts_ifo->vts_pgcit->pgci_srp[
state->pgcn - 1].pgc;
564 if (pgc->pg_playback_mode != 0) {
572 "if you want to try anyway, disable the -trim option\n",
573 c->opt_title,
state->pgcn);
578 if (dvdnav_angle_change(
state->dvdnav,
c->opt_angle) != DVDNAV_STATUS_OK) {
581 goto end_dvdnav_error;
586 state->pgc_nb_pg_est = dvdnav_describe_title_chapters(
state->dvdnav,
c->opt_title,
587 &
state->pgc_pg_times_est,
588 &
state->pgc_duration_est);
591 if (!
state->pgc_nb_pg_est) {
594 goto end_dvdnav_error;
597 state->nav_pts = dvdnav_get_current_time(
state->dvdnav);
598 state->vtsn =
c->vmg_ifo->tt_srpt->title[
c->opt_title - 1].title_set_nr;
613 uint8_t *buf,
int buf_size,
623 dvdnav_vts_change_event_t *e_vts;
624 dvdnav_cell_change_event_t *e_cell;
625 int cur_title, cur_pgcn, cur_pgn, cur_angle, cur_title_unused, cur_ptt, cur_nb_angles;
640 if (dvdnav_get_next_block(
state->dvdnav, nav_buf, &nav_event, &nav_len) != DVDNAV_STATUS_OK) {
643 goto end_dvdnav_error;
647 if (nav_event == DVDNAV_STOP)
657 if (dvdnav_current_title_info(
state->dvdnav, &cur_title, &cur_ptt) != DVDNAV_STATUS_OK) {
660 goto end_dvdnav_error;
664 if (cur_title == 0 || !dvdnav_is_domain_vts(
state->dvdnav))
667 if (dvdnav_current_title_program(
state->dvdnav, &cur_title_unused, &cur_pgcn, &cur_pgn) != DVDNAV_STATUS_OK) {
670 goto end_dvdnav_error;
677 if (dvdnav_get_angle_info(
state->dvdnav, &cur_angle, &cur_nb_angles) != DVDNAV_STATUS_OK) {
680 goto end_dvdnav_error;
684 "new block: i=%d nav_event=%d nav_len=%d cur_title=%d "
685 "cur_ptt=%d cur_angle=%d cur_celln=%d cur_pgcn=%d cur_pgn=%d "
686 "play_in_vts=%d play_in_pgc=%d play_in_ps=%d\n",
687 i, nav_event, nav_len, cur_title,
688 cur_ptt, cur_angle,
state->celln, cur_pgcn, cur_pgn,
692 case DVDNAV_VTS_CHANGE:
696 e_vts = (dvdnav_vts_change_event_t *) nav_buf;
698 if (e_vts->new_vtsN ==
state->vtsn && e_vts->new_domain == DVD_DOMAIN_VTSTitle)
702 case DVDNAV_CELL_CHANGE:
706 e_cell = (dvdnav_cell_change_event_t *) nav_buf;
711 if (cur_title ==
c->opt_title &&
712 (
c->opt_pgc || cur_ptt ==
c->opt_chapter_start) &&
713 cur_pgcn ==
state->pgcn &&
714 cur_pgn ==
state->entry_pgn) {
718 }
else if (
state->celln >= e_cell->cellN ||
state->pgn > cur_pgn) {
722 state->celln = e_cell->cellN;
723 state->ptt = cur_ptt;
724 state->pgn = cur_pgn;
727 case DVDNAV_NAV_PACKET:
731 if ((
state->ptt > 0 &&
state->ptt > cur_ptt) ||
732 (
c->opt_chapter_end > 0 && cur_ptt >
c->opt_chapter_end)) {
736 e_pci = dvdnav_get_current_nav_pci(
state->dvdnav);
737 e_dsi = dvdnav_get_current_nav_dsi(
state->dvdnav);
739 if (e_pci ==
NULL || e_dsi ==
NULL ||
740 e_pci->pci_gi.vobu_s_ptm > e_pci->pci_gi.vobu_e_ptm) {
746 state->vobu_duration = e_pci->pci_gi.vobu_e_ptm - e_pci->pci_gi.vobu_s_ptm;
748 state->nav_pts = dvdnav_get_current_time(
state->dvdnav);
749 state->ptt = cur_ptt;
750 state->pgn = cur_pgn;
753 "NAV packet: s_ptm=%d e_ptm=%d "
754 "scr=%d lbn=%d vobu_duration=%d nav_pts=%" PRId64
"\n",
755 e_pci->pci_gi.vobu_s_ptm, e_pci->pci_gi.vobu_e_ptm,
756 e_dsi->dsi_gi.nv_pck_scr,
757 e_pci->pci_gi.nv_pck_lbn,
state->vobu_duration,
state->nav_pts);
771 if (
state->vobu_e_ptm != e_pci->pci_gi.vobu_s_ptm) {
775 state->ts_offset +=
state->vobu_e_ptm - e_pci->pci_gi.vobu_s_ptm;
779 state->vobu_e_ptm = e_pci->pci_gi.vobu_e_ptm;
781 (*p_nav_event) = nav_event;
784 case DVDNAV_BLOCK_OK:
798 if (cur_angle !=
c->opt_angle) {
800 c->opt_angle, cur_angle);
805 memcpy(buf, &nav_buf, nav_len);
807 if (
state->pgn != cur_pgn)
809 "this could be due to a missed NAV packet\n",
810 state->pgn, cur_pgn);
812 (*p_nav_event) = nav_event;
816 if (dvdnav_wait_skip(
state->dvdnav) != DVDNAV_STATUS_OK) {
819 goto end_dvdnav_error;
823 case DVDNAV_STILL_FRAME:
824 case DVDNAV_HOP_CHANNEL:
825 case DVDNAV_HIGHLIGHT:
829 if (nav_event == DVDNAV_STILL_FRAME) {
830 if (dvdnav_still_skip(
state->dvdnav) != DVDNAV_STATUS_OK) {
833 goto end_dvdnav_error;
849 cur_title, cur_pgcn, cur_pgn,
state->celln,
850 dvdnav_err_to_string(
state->dvdnav));
859 uint64_t time_prev = 0;
862 int chapter_start =
c->opt_chapter_start;
863 int chapter_end =
c->opt_chapter_end > 0 ?
c->opt_chapter_end :
c->play_state.pgc_nb_pg_est - 1;
866 if (
c->play_state.pgc_nb_pg_est == 1 ||
867 chapter_start >
c->play_state.pgc_nb_pg_est ||
868 chapter_end >
c->play_state.pgc_nb_pg_est) {
875 for (
int i = chapter_start - 1;
i < chapter_end;
i++) {
876 uint64_t time_effective =
c->play_state.pgc_pg_times_est[
i] -
c->play_state.nav_pts;
878 if (time_effective - time_prev == 0)
881 if (chapter_start != chapter_end &&
887 time_prev = time_effective;
888 total_duration = time_effective;
891 if (
c->opt_chapter_start == 1 &&
c->opt_chapter_end == 0)
905 int ret = 0, interrupt = 0;
906 int nb_chapters = 0, last_ptt =
c->opt_chapter_start;
907 uint64_t cur_chapter_offset = 0, cur_chapter_duration = 0;
913 if (
c->opt_chapter_start ==
c->opt_chapter_end)
919 if (
state.pgc->nr_of_programs == 1)
923 "Indexing chapter markers, this will take a long time. Please wait...\n");
934 if (
state.ptt == last_ptt) {
935 cur_chapter_duration +=
state.vobu_duration;
941 if (cur_chapter_duration > 0) {
943 cur_chapter_offset + cur_chapter_duration,
NULL)) {
951 cur_chapter_offset += cur_chapter_duration;
952 cur_chapter_duration =
state.vobu_duration;
953 last_ptt =
state.ptt;
984 int is_pal = video_attr.video_format == 1;
987 height = is_pal ? 576 : 480;
990 switch (video_attr.picture_size) {
1009 "this could be an authoring error or empty title "
1010 "(video_format=%d picture_size=%d)\n",
1011 video_attr.video_format, video_attr.picture_size);
1016 entry->startcode = 0x1E0;
1022 entry->has_cc = !is_pal && (video_attr.line21_cc_1 || video_attr.line21_cc_2);
1046 #if FF_API_R_FRAME_RATE
1068 video_attr_t video_attr;
1071 video_attr = !
c->opt_menu_vts ?
c->vmg_ifo->vmgi_mat->vmgm_video_attr :
1072 c->vts_ifo->vtsi_mat->vtsm_video_attr;
1074 video_attr =
c->vts_ifo->vtsi_mat->vts_video_attr;
1092 int sample_rate = 0;
1094 int nb_channels = 0;
1096 char lang_dvd[3] = {0};
1098 int position = (audio_control & 0x7F00) >> 8;
1101 switch (audio_attr.audio_format) {
1105 sample_rate = 48000;
1106 startcode = 0x80 + position;
1111 sample_rate = 48000;
1112 bit_depth = audio_attr.quantization ? 20 : 16;
1113 startcode = 0x1C0 + position;
1118 sample_rate = 48000;
1119 bit_depth = audio_attr.quantization ? 20 : 16;
1120 startcode = 0x1C0 + position;
1125 sample_rate = audio_attr.sample_frequency ? 96000 : 48000;
1126 bit_depth = audio_attr.quantization == 2 ? 24 : (audio_attr.quantization ? 20 : 16);
1127 startcode = 0xA0 + position;
1132 sample_rate = 48000;
1133 bit_depth = audio_attr.quantization == 2 ? 24 : (audio_attr.quantization ? 20 : 16);
1134 startcode = 0x88 + position;
1138 nb_channels = audio_attr.channels + 1;
1147 "this could be an authoring error or dummy title "
1148 "(stream position %d in IFO)\n", position);
1152 if (nb_channels == 1)
1154 else if (nb_channels == 2)
1156 else if (nb_channels == 6)
1158 else if (nb_channels == 7)
1160 else if (nb_channels == 8)
1164 if (audio_attr.application_mode == 1) {
1168 "(stream id=%d)\n", startcode);
1171 if (audio_attr.code_extension == 2)
1173 if (audio_attr.code_extension == 3 || audio_attr.code_extension == 4)
1176 AV_WB16(lang_dvd, audio_attr.lang_code);
1178 entry->startcode = startcode;
1180 entry->sample_rate = sample_rate;
1182 entry->nb_channels = nb_channels;
1183 entry->ch_layout = ch_layout;
1210 if (
entry->lang_iso)
1231 nb_streams = !
c->opt_menu_vts ?
c->vmg_ifo->vmgi_mat->nr_of_vmgm_audio_streams :
1232 c->vts_ifo->vtsi_mat->nr_of_vtsm_audio_streams;
1234 nb_streams =
c->vts_ifo->vtsi_mat->nr_of_vts_audio_streams;
1238 audio_attr_t audio_attr;
1241 audio_attr = !
c->opt_menu_vts ?
c->vmg_ifo->vmgi_mat->vmgm_audio_attr :
1242 c->vts_ifo->vtsi_mat->vtsm_audio_attr;
1244 audio_attr =
c->vts_ifo->vtsi_mat->vts_audio_attr[
i];
1246 if (!(
c->play_state.pgc->audio_control[
i] & 0x8000))
1254 for (
int j = 0; j <
s->nb_streams; j++)
1255 if (
s->streams[j]->id ==
entry.startcode)
1276 char lang_dvd[3] = {0};
1280 if (subp_attr.lang_extension == 9)
1289 AV_WB16(lang_dvd, subp_attr.lang_code);
1313 if (
entry->lang_iso)
1331 subp_attr_t subp_attr,
1337 entry.viewport = viewport;
1343 for (
int i = 0;
i <
s->nb_streams;
i++)
1344 if (
s->streams[
i]->id ==
entry.startcode)
1364 nb_streams = !
c->opt_menu_vts ?
c->vmg_ifo->vmgi_mat->nr_of_vmgm_subp_streams :
1365 c->vts_ifo->vtsi_mat->nr_of_vtsm_subp_streams;
1367 nb_streams =
c->vts_ifo->vtsi_mat->nr_of_vts_subp_streams;
1372 uint32_t subp_control;
1373 subp_attr_t subp_attr;
1374 video_attr_t video_attr;
1376 subp_control =
c->play_state.pgc->subp_control[
i];
1377 if (!(subp_control & 0x80000000))
1383 video_attr = !
c->opt_menu_vts ?
c->vmg_ifo->vmgi_mat->vmgm_video_attr :
1384 c->vts_ifo->vtsi_mat->vtsm_video_attr;
1386 subp_attr = !
c->opt_menu_vts ?
c->vmg_ifo->vmgi_mat->vmgm_subp_attr :
1387 c->vts_ifo->vtsi_mat->vtsm_subp_attr;
1389 video_attr =
c->vts_ifo->vtsi_mat->vts_video_attr;
1390 subp_attr =
c->vts_ifo->vtsi_mat->vts_subp_attr[
i];
1394 if (!video_attr.display_aspect_ratio) {
1408 if (video_attr.permitted_df == 2 || video_attr.permitted_df == 0)
1414 if (video_attr.permitted_df == 1 || video_attr.permitted_df == 0)
1427 if (!
c->segment_started)
1433 c->segment_started = 0;
1455 c->mpeg_pb.pub.eof_reached = 1;
1461 if (
ret >= 0 && nav_event == DVDNAV_NAV_PACKET)
1486 c->mpeg_pb.pub.seekable = 0;
1500 c->mpeg_ctx->probesize = 0;
1501 c->mpeg_ctx->max_analyze_duration = 0;
1502 c->mpeg_ctx->interrupt_callback =
s->interrupt_callback;
1503 c->mpeg_ctx->pb = &
c->mpeg_pb.pub;
1504 c->mpeg_ctx->correct_ts_overflow = 0;
1505 c->mpeg_ctx->io_open =
NULL;
1517 if (
c->opt_region ||
1520 c->opt_chapter_start > 1 ||
1521 c->opt_chapter_end > 0) {
1523 "-preindex, or -chapter_start/-chapter_end options\n");
1533 if (!
c->opt_menu_lu) {
1535 "This is not always desirable, validation suggested.\n");
1542 "This is not always desirable, validation suggested.\n");
1557 if (
c->opt_chapter_end != 0 &&
c->opt_chapter_start >
c->opt_chapter_end) {
1559 c->opt_chapter_start,
c->opt_chapter_end);
1564 if (
c->opt_title == 0) {
1566 "This is not always the main feature, validation suggested.\n");
1572 if (
c->opt_pg == 0) {
1576 }
else if (
c->opt_chapter_start > 1 ||
c->opt_chapter_end > 0 ||
c->opt_preindex) {
1578 "-chapter_start/-chapter_end options\n");
1596 if (!
c->opt_pgc && !
c->opt_preindex)
1608 int found_stream = 0;
1618 if (!
c->segment_started)
1619 c->segment_started = 1;
1624 for (
int i = 0;
i <
s->nb_streams;
i++) {
1632 if (!found_stream) {
1640 if (!
c->play_started) {
1644 "with unset PTS/DTS at start\n");
1649 c->play_started = 1;
1652 pkt->
pts +=
c->play_state.ts_offset -
c->first_pts;
1653 pkt->
dts +=
c->play_state.ts_offset -
c->first_pts;
1657 "this is OK at start of playback\n",
1668 "ts_offset=%" PRId64
" first_pts=%" PRId64
"\n",
1670 c->play_state.ts_offset,
c->first_pts);
1691 #define OFFSET(x) offsetof(DVDVideoDemuxContext, x)
1716 .
p.
name =
"dvdvideo",