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"
175 const char *msg, va_list msg_va)
181 vsnprintf(msg_buf,
sizeof(msg_buf), msg, msg_va);
183 if (
level == DVD_LOGGER_LEVEL_ERROR)
185 else if (
level == DVD_LOGGER_LEVEL_WARN)
188 av_log(
s, lavu_level,
"libdvdread: %s\n", msg_buf);
192 const char *msg, va_list msg_va)
198 vsnprintf(msg_buf,
sizeof(msg_buf), msg, msg_va);
200 if (
level == DVDNAV_LOGGER_LEVEL_ERROR)
206 av_log(
s, lavu_level,
"libdvdnav: %s\n", msg_buf);
214 ifoClose(
c->vts_ifo);
217 ifoClose(
c->vmg_ifo);
220 DVDClose(
c->dvdread);
227 dvd_logger_cb dvdread_log_cb;
228 title_info_t title_info;
231 c->dvdread = DVDOpen2(
s, &dvdread_log_cb,
s->url);
239 if (!(
c->vmg_ifo = ifoOpen(
c->dvdread, 0))) {
246 if (
c->opt_menu_vts > 0 && !(
c->vts_ifo = ifoOpen(
c->dvdread,
c->opt_menu_vts))) {
255 if (
c->opt_title >
c->vmg_ifo->tt_srpt->nr_of_srpts) {
261 title_info =
c->vmg_ifo->tt_srpt->title[
c->opt_title - 1];
262 if (
c->opt_angle > title_info.nr_of_angles) {
268 if (title_info.nr_of_ptts < 1) {
274 if (
c->opt_chapter_start > title_info.nr_of_ptts ||
275 (
c->opt_chapter_end > 0 &&
c->opt_chapter_end > title_info.nr_of_ptts)) {
277 c->opt_chapter_start,
c->opt_chapter_end);
282 if (!(
c->vts_ifo = ifoOpen(
c->dvdread, title_info.title_set_nr))) {
284 title_info.title_set_nr);
289 if (title_info.vts_ttn < 1 ||
290 title_info.vts_ttn > 99 ||
291 title_info.vts_ttn >
c->vts_ifo->vts_ptt_srpt->nr_of_srpts ||
292 c->vts_ifo->vtsi_mat->nr_of_vts_audio_streams > 8 ||
293 c->vts_ifo->vtsi_mat->nr_of_vts_subp_streams > 32) {
304 dvd_time_t cell_duration = pgc->cell_playback[celln - 1].playback_time;
306 return cell_duration.second >= 1 || cell_duration.minute >= 1 || cell_duration.hour >= 1;
311 for (
int i = 1;
i <= pgc->nr_of_cells;
i++)
321 DVDCloseFile(
state->vob_file);
329 pgci_ut =
c->opt_menu_vts ?
c->vts_ifo->pgci_ut :
c->vmg_ifo->pgci_ut;
332 c->opt_menu_lu,
c->opt_pgc);
337 if (
c->opt_pgc < 1 ||
338 c->opt_menu_lu < 1 ||
339 c->opt_menu_lu > pgci_ut->nr_of_lus ||
340 c->opt_pgc > pgci_ut->lu[
c->opt_menu_lu - 1].pgcit->nr_of_pgci_srp) {
348 state->pgcn =
c->opt_pgc - 1;
349 state->pgc = pgci_ut->lu[
c->opt_menu_lu - 1].pgcit->pgci_srp[
c->opt_pgc - 1].pgc;
350 if (!
state->pgc || !
state->pgc->program_map || !
state->pgc->cell_playback) {
352 c->opt_menu_lu,
c->opt_pgc);
358 state->entry_pgn =
c->opt_pg;
359 if (
state->entry_pgn < 1 ||
state->entry_pgn >
state->pgc->nr_of_programs) {
369 if (
state->celln_start >
state->pgc->nr_of_cells) {
375 state->sector_end =
state->pgc->cell_playback[
state->celln - 1].last_sector;
376 state->vobu_next =
state->pgc->cell_playback[
state->celln - 1].first_sector;
379 if (
c->opt_menu_vts > 0)
382 if (!(
state->vob_file = DVDOpenFile(
c->dvdread,
c->opt_menu_vts, DVD_READ_MENU_VOBS))) {
384 "Unable to open main menu VOB (VIDEO_TS.VOB)\n" :
385 "Unable to open menu VOBs for VTS %d\n",
c->opt_menu_vts);
394 uint8_t *buf,
int buf_size,
399 pci_t pci = (pci_t) {0};
400 dsi_t dsi = (dsi_t) {0};
410 if (!
state->vobu_remaining &&
state->in_pgc) {
411 if (
state->vobu_next == SRI_END_OF_CELL) {
416 state->sector_offset =
state->pgc->cell_playback[
state->celln - 1].first_sector;
417 state->sector_end =
state->pgc->cell_playback[
state->celln - 1].last_sector;
426 blocks_read = DVDReadBlocks(
state->vob_file,
state->sector_offset, 1, read_buf);
427 if (blocks_read != 1) {
429 state->sector_offset, blocks_read);
435 if (!
state->vobu_remaining) {
439 read_buf[DSI_START_BYTE - 1] != 0x01) {
442 state->sector_offset);
448 navRead_DSI(&dsi, &read_buf[DSI_START_BYTE]);
450 if (!pci.pci_gi.vobu_s_ptm ||
451 !pci.pci_gi.vobu_e_ptm ||
452 pci.pci_gi.vobu_s_ptm > pci.pci_gi.vobu_e_ptm) {
455 state->sector_offset);
460 state->vobu_remaining = dsi.dsi_gi.vobu_ea;
461 state->vobu_next = dsi.vobu_sri.next_vobu == SRI_END_OF_CELL ? SRI_END_OF_CELL :
462 dsi.dsi_gi.nv_pck_lbn + (dsi.vobu_sri.next_vobu & 0x7FFFFFFF);
463 state->sector_offset++;
466 if (
state->vobu_e_ptm != pci.pci_gi.vobu_s_ptm) {
470 state->ts_offset +=
state->vobu_e_ptm - pci.pci_gi.vobu_s_ptm;
477 state->vobu_e_ptm = pci.pci_gi.vobu_e_ptm;
480 "vobu_s_ptm=%d vobu_e_ptm=%d ts_offset=%" PRId64
"\n",
481 dsi.dsi_gi.nv_pck_lbn,
482 pci.pci_gi.vobu_s_ptm, pci.pci_gi.vobu_e_ptm,
state->ts_offset);
489 state->sector_offset++;
490 state->vobu_remaining--;
501 if (
state->pgc_pg_times_est)
502 free(
state->pgc_pg_times_est);
504 if (dvdnav_close(
state->dvdnav) != DVDNAV_STATUS_OK)
506 dvdnav_err_to_string(
state->dvdnav));
513 dvdnav_logger_cb dvdnav_log_cb;
514 dvdnav_status_t dvdnav_open_status;
517 int cur_title, cur_pgcn, cur_pgn;
521 dvdnav_open_status = dvdnav_open2(&
state->dvdnav,
s, &dvdnav_log_cb,
s->url);
523 if (!
state->dvdnav ||
524 dvdnav_open_status != DVDNAV_STATUS_OK ||
525 dvdnav_set_readahead_flag(
state->dvdnav, 0) != DVDNAV_STATUS_OK ||
526 dvdnav_set_PGC_positioning_flag(
state->dvdnav, 1) != DVDNAV_STATUS_OK ||
527 dvdnav_get_region_mask(
state->dvdnav, &disc_region_mask) != DVDNAV_STATUS_OK) {
530 goto end_dvdnav_error;
533 player_region_mask =
c->opt_region > 0 ? (1 << (
c->opt_region - 1)) : disc_region_mask;
534 if (dvdnav_set_region_mask(
state->dvdnav, player_region_mask) != DVDNAV_STATUS_OK) {
537 goto end_dvdnav_error;
540 if (
c->opt_pgc > 0 &&
c->opt_pg > 0) {
541 if (dvdnav_program_play(
state->dvdnav,
c->opt_title,
c->opt_pgc,
c->opt_pg) != DVDNAV_STATUS_OK) {
543 c->opt_title,
c->opt_pgc,
c->opt_pg);
545 goto end_dvdnav_error;
549 state->entry_pgn =
c->opt_pg;
551 if (dvdnav_part_play(
state->dvdnav,
c->opt_title,
c->opt_chapter_start) != DVDNAV_STATUS_OK ||
552 dvdnav_current_title_program(
state->dvdnav, &cur_title, &cur_pgcn, &cur_pgn) != DVDNAV_STATUS_OK) {
555 c->opt_title,
c->opt_chapter_start);
556 goto end_dvdnav_error;
559 state->pgcn = cur_pgcn;
560 state->entry_pgn = cur_pgn;
563 pgc =
c->vts_ifo->vts_pgcit->pgci_srp[
state->pgcn - 1].pgc;
565 if (pgc->pg_playback_mode != 0) {
573 "if you want to try anyway, disable the -trim option\n",
574 c->opt_title,
state->pgcn);
579 if (dvdnav_angle_change(
state->dvdnav,
c->opt_angle) != DVDNAV_STATUS_OK) {
582 goto end_dvdnav_error;
587 state->pgc_nb_pg_est = dvdnav_describe_title_chapters(
state->dvdnav,
c->opt_title,
588 &
state->pgc_pg_times_est,
589 &
state->pgc_duration_est);
592 if (!
state->pgc_nb_pg_est) {
595 goto end_dvdnav_error;
598 state->nav_pts = dvdnav_get_current_time(
state->dvdnav);
599 state->vtsn =
c->vmg_ifo->tt_srpt->title[
c->opt_title - 1].title_set_nr;
614 uint8_t *buf,
int buf_size,
624 dvdnav_vts_change_event_t *e_vts;
625 dvdnav_cell_change_event_t *e_cell;
626 int cur_title, cur_pgcn, cur_pgn, cur_angle, cur_title_unused, cur_ptt, cur_nb_angles;
627 int is_cell_promising = 0;
642 if (dvdnav_get_next_block(
state->dvdnav, nav_buf, &nav_event, &nav_len) != DVDNAV_STATUS_OK) {
645 goto end_dvdnav_error;
649 if (nav_event == DVDNAV_STOP)
659 if (dvdnav_current_title_info(
state->dvdnav, &cur_title, &cur_ptt) != DVDNAV_STATUS_OK) {
662 goto end_dvdnav_error;
666 if (cur_title == 0 || !dvdnav_is_domain_vts(
state->dvdnav))
669 if (dvdnav_current_title_program(
state->dvdnav, &cur_title_unused, &cur_pgcn, &cur_pgn) != DVDNAV_STATUS_OK) {
672 goto end_dvdnav_error;
679 if (dvdnav_get_angle_info(
state->dvdnav, &cur_angle, &cur_nb_angles) != DVDNAV_STATUS_OK) {
682 goto end_dvdnav_error;
686 "new block: i=%d nav_event=%d nav_len=%d cur_title=%d "
687 "cur_ptt=%d cur_angle=%d cur_celln=%d cur_pgcn=%d cur_pgn=%d "
688 "play_in_vts=%d play_in_pgc=%d play_in_ps=%d\n",
689 i, nav_event, nav_len, cur_title,
690 cur_ptt, cur_angle,
state->celln, cur_pgcn, cur_pgn,
694 case DVDNAV_VTS_CHANGE:
698 e_vts = (dvdnav_vts_change_event_t *) nav_buf;
700 if (e_vts->new_vtsN ==
state->vtsn && e_vts->new_domain == DVD_DOMAIN_VTSTitle)
704 case DVDNAV_CELL_CHANGE:
708 e_cell = (dvdnav_cell_change_event_t *) nav_buf;
712 state->celln, e_cell->cellN, is_cell_promising);
715 if (cur_title ==
c->opt_title &&
716 (
c->opt_pgc || cur_ptt ==
c->opt_chapter_start) &&
717 cur_pgcn ==
state->pgcn &&
718 cur_pgn ==
state->entry_pgn &&
724 if (
c->opt_trim && !is_cell_promising)
726 }
else if (
state->celln >= e_cell->cellN ||
state->pgn > cur_pgn) {
730 state->celln = e_cell->cellN;
731 state->ptt = cur_ptt;
732 state->pgn = cur_pgn;
733 state->nb_cells_played++;
736 case DVDNAV_NAV_PACKET:
740 if ((
state->ptt > 0 &&
state->ptt > cur_ptt) ||
741 (
c->opt_chapter_end > 0 && cur_ptt >
c->opt_chapter_end)) {
745 e_pci = dvdnav_get_current_nav_pci(
state->dvdnav);
746 e_dsi = dvdnav_get_current_nav_dsi(
state->dvdnav);
748 if (e_pci ==
NULL || e_dsi ==
NULL ||
749 e_pci->pci_gi.vobu_s_ptm > e_pci->pci_gi.vobu_e_ptm) {
755 state->vobu_duration = e_pci->pci_gi.vobu_e_ptm - e_pci->pci_gi.vobu_s_ptm;
757 state->nav_pts = dvdnav_get_current_time(
state->dvdnav);
758 state->ptt = cur_ptt;
759 state->pgn = cur_pgn;
762 "NAV packet: s_ptm=%d e_ptm=%d "
763 "scr=%d lbn=%d vobu_duration=%d nav_pts=%" PRId64
"\n",
764 e_pci->pci_gi.vobu_s_ptm, e_pci->pci_gi.vobu_e_ptm,
765 e_dsi->dsi_gi.nv_pck_scr,
766 e_pci->pci_gi.nv_pck_lbn,
state->vobu_duration,
state->nav_pts);
773 if (
state->vobu_e_ptm != e_pci->pci_gi.vobu_s_ptm) {
777 state->ts_offset +=
state->vobu_e_ptm - e_pci->pci_gi.vobu_s_ptm;
781 state->vobu_e_ptm = e_pci->pci_gi.vobu_e_ptm;
783 (*p_nav_event) = nav_event;
786 case DVDNAV_BLOCK_OK:
800 if (cur_angle !=
c->opt_angle) {
802 c->opt_angle, cur_angle);
807 memcpy(buf, &nav_buf, nav_len);
809 if (
state->pgn != cur_pgn)
811 "this could be due to a missed NAV packet\n",
812 state->pgn, cur_pgn);
814 (*p_nav_event) = nav_event;
817 case DVDNAV_STILL_FRAME:
819 case DVDNAV_HOP_CHANNEL:
820 case DVDNAV_HIGHLIGHT:
824 if (nav_event == DVDNAV_STILL_FRAME) {
825 if (dvdnav_still_skip(
state->dvdnav) != DVDNAV_STATUS_OK) {
828 goto end_dvdnav_error;
832 if (nav_event == DVDNAV_WAIT) {
833 if (dvdnav_wait_skip(
state->dvdnav) != DVDNAV_STATUS_OK) {
836 goto end_dvdnav_error;
852 cur_title, cur_pgcn, cur_pgn,
state->celln,
853 dvdnav_err_to_string(
state->dvdnav));
862 uint64_t time_prev = 0;
865 int chapter_start =
c->opt_chapter_start;
866 int chapter_end =
c->opt_chapter_end > 0 ?
c->opt_chapter_end :
c->play_state.pgc_nb_pg_est - 1;
869 if (chapter_start == chapter_end ||
870 c->play_state.pgc_nb_pg_est == 1 ||
871 chapter_start >
c->play_state.pgc_nb_pg_est ||
872 chapter_end >
c->play_state.pgc_nb_pg_est) {
879 for (
int i = chapter_start - 1;
i < chapter_end;
i++) {
880 uint64_t time_effective =
c->play_state.pgc_pg_times_est[
i] -
c->play_state.nav_pts;
885 time_prev = time_effective;
886 total_duration = time_effective;
889 if (
c->opt_chapter_start == 1 &&
c->opt_chapter_end == 0)
903 int ret = 0, interrupt = 0;
904 int nb_chapters = 0, last_ptt =
c->opt_chapter_start;
905 uint64_t cur_chapter_offset = 0, cur_chapter_duration = 0;
911 if (
c->opt_chapter_start ==
c->opt_chapter_end)
917 if (
state.pgc->nr_of_programs == 1)
921 "Indexing chapter markers, this will take a long time. Please wait...\n");
932 if (
state.ptt == last_ptt) {
933 cur_chapter_duration +=
state.vobu_duration;
940 cur_chapter_offset + cur_chapter_duration,
NULL)) {
946 cur_chapter_offset += cur_chapter_duration;
947 cur_chapter_duration =
state.vobu_duration;
948 last_ptt =
state.ptt;
979 int is_pal = video_attr.video_format == 1;
982 height = is_pal ? 576 : 480;
985 switch (video_attr.picture_size) {
1004 "this could be an authoring error or empty title "
1005 "(video_format=%d picture_size=%d)\n",
1006 video_attr.video_format, video_attr.picture_size);
1011 entry->startcode = 0x1E0;
1017 entry->has_cc = !is_pal && (video_attr.line21_cc_1 || video_attr.line21_cc_2);
1041 #if FF_API_R_FRAME_RATE
1063 video_attr_t video_attr;
1066 video_attr = !
c->opt_menu_vts ?
c->vmg_ifo->vmgi_mat->vmgm_video_attr :
1067 c->vts_ifo->vtsi_mat->vtsm_video_attr;
1069 video_attr =
c->vts_ifo->vtsi_mat->vts_video_attr;
1089 int nb_channels = 0;
1091 char lang_dvd[3] = {0};
1093 int position = (audio_control & 0x7F00) >> 8;
1096 switch (audio_attr.audio_format) {
1101 startcode = 0x80 + position;
1107 bit_depth = audio_attr.quantization ? 20 : 16;
1108 startcode = 0x1C0 + position;
1114 bit_depth = audio_attr.quantization ? 20 : 16;
1115 startcode = 0x1C0 + position;
1120 sample_rate = audio_attr.sample_frequency ? 96000 : 48000;
1121 bit_depth = audio_attr.quantization == 2 ? 24 : (audio_attr.quantization ? 20 : 16);
1122 startcode = 0xA0 + position;
1128 bit_depth = audio_attr.quantization == 2 ? 24 : (audio_attr.quantization ? 20 : 16);
1129 startcode = 0x88 + position;
1133 nb_channels = audio_attr.channels + 1;
1142 "this could be an authoring error or dummy title "
1143 "(stream position %d in IFO)\n", position);
1147 if (nb_channels == 1)
1149 else if (nb_channels == 2)
1151 else if (nb_channels == 6)
1153 else if (nb_channels == 7)
1155 else if (nb_channels == 8)
1159 if (audio_attr.application_mode == 1) {
1163 "(stream id=%d)\n", startcode);
1166 if (audio_attr.code_extension == 2)
1168 if (audio_attr.code_extension == 3 || audio_attr.code_extension == 4)
1171 AV_WB16(lang_dvd, audio_attr.lang_code);
1173 entry->startcode = startcode;
1177 entry->nb_channels = nb_channels;
1178 entry->ch_layout = ch_layout;
1205 if (
entry->lang_iso)
1226 nb_streams = !
c->opt_menu_vts ?
c->vmg_ifo->vmgi_mat->nr_of_vmgm_audio_streams :
1227 c->vts_ifo->vtsi_mat->nr_of_vtsm_audio_streams;
1229 nb_streams =
c->vts_ifo->vtsi_mat->nr_of_vts_audio_streams;
1233 audio_attr_t audio_attr;
1236 audio_attr = !
c->opt_menu_vts ?
c->vmg_ifo->vmgi_mat->vmgm_audio_attr :
1237 c->vts_ifo->vtsi_mat->vtsm_audio_attr;
1239 audio_attr =
c->vts_ifo->vtsi_mat->vts_audio_attr[
i];
1241 if (!(
c->play_state.pgc->audio_control[
i] & 0x8000))
1249 for (
int j = 0; j <
s->nb_streams; j++)
1250 if (
s->streams[j]->id ==
entry.startcode)
1271 char lang_dvd[3] = {0};
1275 if (subp_attr.lang_extension == 9)
1284 AV_WB16(lang_dvd, subp_attr.lang_code);
1308 if (
entry->lang_iso)
1326 subp_attr_t subp_attr,
1332 entry.viewport = viewport;
1338 for (
int i = 0;
i <
s->nb_streams;
i++)
1339 if (
s->streams[
i]->id ==
entry.startcode)
1359 nb_streams = !
c->opt_menu_vts ?
c->vmg_ifo->vmgi_mat->nr_of_vmgm_subp_streams :
1360 c->vts_ifo->vtsi_mat->nr_of_vtsm_subp_streams;
1362 nb_streams =
c->vts_ifo->vtsi_mat->nr_of_vts_subp_streams;
1367 uint32_t subp_control;
1368 subp_attr_t subp_attr;
1369 video_attr_t video_attr;
1371 subp_control =
c->play_state.pgc->subp_control[
i];
1372 if (!(subp_control & 0x80000000))
1378 video_attr = !
c->opt_menu_vts ?
c->vmg_ifo->vmgi_mat->vmgm_video_attr :
1379 c->vts_ifo->vtsi_mat->vtsm_video_attr;
1381 subp_attr = !
c->opt_menu_vts ?
c->vmg_ifo->vmgi_mat->vmgm_subp_attr :
1382 c->vts_ifo->vtsi_mat->vtsm_subp_attr;
1384 video_attr =
c->vts_ifo->vtsi_mat->vts_video_attr;
1385 subp_attr =
c->vts_ifo->vtsi_mat->vts_subp_attr[
i];
1389 if (!video_attr.display_aspect_ratio) {
1403 if (video_attr.permitted_df == 2 || video_attr.permitted_df == 0)
1409 if (video_attr.permitted_df == 1 || video_attr.permitted_df == 0)
1422 if (!
c->segment_started)
1428 c->segment_started = 0;
1450 c->mpeg_pb.pub.eof_reached = 1;
1456 if (
ret >= 0 && nav_event == DVDNAV_NAV_PACKET)
1481 c->mpeg_pb.pub.seekable = 0;
1495 c->mpeg_ctx->probesize = 0;
1496 c->mpeg_ctx->max_analyze_duration = 0;
1497 c->mpeg_ctx->interrupt_callback =
s->interrupt_callback;
1498 c->mpeg_ctx->pb = &
c->mpeg_pb.pub;
1499 c->mpeg_ctx->correct_ts_overflow = 0;
1500 c->mpeg_ctx->io_open =
NULL;
1512 if (
c->opt_region ||
1515 c->opt_chapter_start > 1 ||
1516 c->opt_chapter_end > 0) {
1518 "-preindex, or -chapter_start/-chapter_end options\n");
1528 if (!
c->opt_menu_lu) {
1530 "This is not always desirable, validation suggested.\n");
1537 "This is not always desirable, validation suggested.\n");
1552 if (
c->opt_title == 0) {
1554 "This is not always the main feature, validation suggested.\n");
1560 if (
c->opt_pg == 0) {
1564 }
else if (
c->opt_chapter_start > 1 ||
c->opt_chapter_end > 0 ||
c->opt_preindex) {
1566 "-chapter_start/-chapter_end options\n");
1584 if (!
c->opt_pgc && !
c->opt_preindex)
1596 int found_stream = 0;
1606 if (!
c->segment_started)
1607 c->segment_started = 1;
1612 for (
int i = 0;
i <
s->nb_streams;
i++) {
1620 if (!found_stream) {
1628 if (!
c->play_started) {
1632 "with unset PTS/DTS at start\n");
1637 c->play_started = 1;
1640 pkt->
pts +=
c->play_state.ts_offset -
c->first_pts;
1641 pkt->
dts +=
c->play_state.ts_offset -
c->first_pts;
1645 "this is OK at start of playback\n",
1656 "ts_offset=%" PRId64
" first_pts=%" PRId64
"\n",
1658 c->play_state.ts_offset,
c->first_pts);
1679 #define OFFSET(x) offsetof(DVDVideoDemuxContext, x)
1704 .
p.
name =
"dvdvideo",