7#include <QCoreApplication>
15#ifndef __cpp_size_t_suffix
26#define LOC QString("DVDRB: ")
28#define IncrementButtonVersion if (++m_buttonVersion > 1024) m_buttonVersion = 1;
35 QT_TRANSLATE_NOOP(
"(DVD menu)",
"Title Menu"),
36 QT_TRANSLATE_NOOP(
"(DVD menu)",
"Root Menu"),
37 QT_TRANSLATE_NOOP(
"(DVD menu)",
"Subpicture Menu"),
38 QT_TRANSLATE_NOOP(
"(DVD menu)",
"Audio Menu"),
39 QT_TRANSLATE_NOOP(
"(DVD menu)",
"Angle Menu"),
41 QT_TRANSLATE_NOOP(
"(DVD menu)",
"Part Menu")
45{ { 3, 1 }, { 5, 2 }, { 10, 4 }, { 20, 8 },
46 { 30, 10 }, { 60, 15 }, { 120, 20 }, { 180, 60 } };
90 for (QList<std::chrono::seconds> chapters : std::as_const(
m_chapterMap))
104 ((Whence == SEEK_SET && Position ==
m_readPos) || (Whence == SEEK_CUR && Position == 0)))
112 long long new_pos = (SEEK_SET==Whence) ? Position :
m_readPos + Position;
117 if ((SEEK_END == Whence) || ((SEEK_CUR == Whence) && new_pos != 0))
138 QString cmd = QString(
"Seek(%1, %2)").arg(Position)
140 LOG(VB_GENERAL, LOG_ERR,
LOC + cmd +
" Failed" +
ENO);
156 dvdnav_status_t dvdRet = DVDNAV_STATUS_OK;
160 dvdRet = dvdnav_sector_search(
m_dvdnav,
static_cast<int64_t
>(Sector), SEEK_SET);
162 if (dvdRet == DVDNAV_STATUS_ERR)
164 LOG(VB_PLAYBACK, LOG_ERR,
LOC + QString(
"SectorSeek() to sector %1 failed").arg(Sector));
167 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"DVD Playback SectorSeek() sector: %1").arg(Sector));
173 dvdnav_status_t dvdRet = DVDNAV_STATUS_OK;
180 if (ffrewSkip != 1 && ffrewSkip != 0 && Time != 0)
182 auto it =
kSeekSpeedMap.lowerBound(
static_cast<int>(std::abs(Time)));
188 seekSpeed = -seekSpeed;
189 dvdRet = dvdnav_relative_time_search(
m_dvdnav, seekSpeed);
197 LOG(VB_PLAYBACK, LOG_DEBUG, QString(
"DVD Playback Seek() time: %1; seekSpeed: %2")
198 .arg(Time).arg(seekSpeed));
200 if (dvdRet == DVDNAV_STATUS_ERR)
202 LOG(VB_PLAYBACK, LOG_ERR,
LOC + QString(
"Seek() to time %1 failed").arg(Time));
209 if (Time > 0 && ffrewSkip == 1)
246 Description = QCoreApplication::translate(
"(DVD menu)",
DVDMenuTable[
m_part].c_str());
250 Description = tr(
"Title %1 chapter %2").arg(
m_title).arg(
m_part);
275 if (res == DVDNAV_STATUS_ERR)
278 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to open DVD device at '%1'").arg(
m_filename));
283 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Opened DVD device at '%1'").arg(
m_filename));
294 dvdnav_menu_language_select(
m_dvdnav, lang.toLatin1().data());
295 dvdnav_audio_language_select(
m_dvdnav, lang.toLatin1().data());
296 dvdnav_spu_language_select(
m_dvdnav, lang.toLatin1().data());
298 dvdnav_set_readahead_flag(
m_dvdnav, 0);
299 dvdnav_set_PGC_positioning_flag(
m_dvdnav, 1);
303 if (dvdnav_get_next_still_flag(
m_dvdnav))
305 LOG(VB_GENERAL, LOG_NOTICE,
306 LOC +
"The selected title is a still frame. "
307 "Playback is likely to fail - please raise a bug report at "
308 "https://github.com/MythTV/mythtv/issues");
330 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Resetting DVD device.");
336 LOG(VB_GENERAL, LOG_ERR,
LOC +
337 "DVD errored after initial scan - trying again");
341 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to re-open DVD.");
348 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Setting DVD languages to %1")
353 dvdnav_menu_language_select(
m_dvdnav, lang.toLatin1().data());
354 dvdnav_audio_language_select(
m_dvdnav, lang.toLatin1().data());
355 dvdnav_spu_language_select(
m_dvdnav, lang.toLatin1().data());
388 uint64_t duration = 0;
389 uint64_t *times =
nullptr;
390 uint32_t num = dvdnav_describe_title_chapters(
m_dvdnav, Title, ×, &duration);
394 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to retrieve chapter data");
398 QList<std::chrono::seconds> chapters;
403 for (
uint i = 0; i < num - 1; i++)
421 if (dvdnav_get_position(
m_dvdnav, &pos, &length) == DVDNAV_STATUS_ERR)
424 dvdnav_get_position(
m_dvdnav, &pos, &length);
462 return duration_cast<std::chrono::seconds>(
m_pgLength);
473 uint32_t newTimestamp = Timestamp;
481 int64_t newTimestamp = Timestamp;
482 if ((newTimestamp != AV_NOPTS_VALUE) && (newTimestamp >=
m_timeDiff))
504 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Waiting for player's buffers to drain");
511 std::this_thread::sleep_for(10ms);
518 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Player wait state was not cleared");
526 uint8_t* blockBuf =
nullptr;
528 int needed =
static_cast<int>(Size);
531 bool waiting =
false;
535 LOG(VB_GENERAL, LOG_ERR,
LOC +
"safe_read: called after DVDNAV_STOP");
541 LOG(VB_GENERAL, LOG_ERR,
LOC +
"read ahead thread running.");
545 bool reprocessing {
false };
556 reprocessing =
false;
561 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to read block: %1")
562 .arg(dvdnav_err_to_string(
m_dvdnav)));
570 case DVDNAV_BLOCK_OK:
581 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
584 LOG(VB_PLAYBACK|VB_FILE, LOG_DEBUG,
LOC +
"DVDNAV_BLOCK_OK");
589 case DVDNAV_CELL_CHANGE:
592 auto *cell_event =
reinterpret_cast<dvdnav_cell_change_event_t*
>(blockBuf);
609 uint32_t stillTimer = dvdnav_get_next_still_flag(
m_dvdnav);
614 dvdnav_get_position(
m_dvdnav, &pos, &length);
628 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
629 QString(
"---- DVDNAV_CELL_CHANGE - Cell #%1 Menu %2 Length %3")
630 .arg(cell_event->cellN).arg(
m_inMenu ?
"Yes" :
"No")
631 .arg(
static_cast<double>(cell_event->cell_length) / 90000.0, 0,
'f', 1));
635 still = QString(
"Length: %1 seconds")
636 .arg(duration_cast<std::chrono::seconds>(
m_pgcLength).count());
638 else if (stillTimer < 0xff)
640 still = QString(
"Stillframe: %1 seconds").arg(stillTimer);
644 still = QString(
"Infinite stillframe");
649 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Menu #%1 %2")
654 LOG(VB_PLAYBACK, LOG_INFO,
655 LOC + QString(
"Title #%1: %2 Part %3 of %4")
685 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
690 case DVDNAV_SPU_CLUT_CHANGE:
693 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_SPU_CLUT_CHANGE");
697 std::copy(blockBuf, blockBuf + (16 *
sizeof(uint32_t)),
698 reinterpret_cast<uint8_t*
>(
m_clut.data()));
701 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
706 case DVDNAV_SPU_STREAM_CHANGE:
709 auto* spu =
reinterpret_cast<dvdnav_spu_stream_change_event_t*
>(blockBuf);
719 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
720 QString(
"DVDNAV_SPU_STREAM_CHANGE: "
721 "physicalwide %1, physicalletterbox %2, "
722 "physicalpanscan %3, currenttrack %4")
723 .arg(spu->physical_wide).arg(spu->physical_letterbox)
728 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
733 case DVDNAV_AUDIO_STREAM_CHANGE:
736 auto* audio =
reinterpret_cast<dvdnav_audio_stream_change_event_t*
>(blockBuf);
742 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
743 QString(
"DVDNAV_AUDIO_STREAM_CHANGE: old %1 new %2, physical %3, logical %4")
745 .arg(audio->physical).arg(audio->logical));
756 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
761 case DVDNAV_NAV_PACKET:
769 dsi_t *dsi = dvdnav_get_current_nav_dsi(
m_dvdnav);
771 if (
pci ==
nullptr || dsi ==
nullptr)
774 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"DVDNAV_NAV_PACKET - Error retrieving DVD data structures - dsi 0x%1, pci 0x%2")
775 .arg(
reinterpret_cast<uint64_t
>(dsi), 0, 16)
776 .arg(
reinterpret_cast<uint64_t
>(
pci), 0, 16));
783 int64_t diff =
static_cast<int64_t
>(
pci->pci_gi.vobu_s_ptm) -
m_endPts;
788 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"PTS discontinuity - waiting for decoder: this %1, last %2, diff %3")
789 .arg(
pci->pci_gi.vobu_s_ptm).arg(
m_endPts).arg(diff));
803 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"Jumped into middle of menu: lba %1, dest %2")
804 .arg(
pci->pci_gi.nv_pck_lbn)
805 .arg(
pci->pci_gi.nv_pck_lbn - (dsi->synci.sp_synca[0] & 0x7fffffff)));
813 dvdnav_sector_search(
m_dvdnav,
pci->pci_gi.nv_pck_lbn - (dsi->synci.sp_synca[0] & 0x7fffffff), SEEK_SET);
817 pci_t pci_copy = *
pci;
822 if (
pci->pci_gi.vobu_se_e_ptm != 0)
846 m_vobid = dsi->dsi_gi.vobu_vob_idn;
861 if (abs(relativetime) <= 1s)
868 dvdnav_relative_time_search(
m_dvdnav, relativetime.count() * 2);
874 if ( (
pci->hli.hl_gi.hli_ss & 0x03) == 0x01 )
877 int aspect = dvdnav_get_video_aspect(
m_dvdnav);
882 int8_t spustream = dvdnav_get_active_spu_stream(
m_dvdnav) & 0x7f;
884 if (aspect != 0 && spustream > 0)
891 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"DVDNAV_NAV_PACKET - time:%1, lba:%2, vob:%3, cell:%4, seeking:%5, seektime:%6")
908 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
912 case DVDNAV_HOP_CHANNEL:
916 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_HOP_CHANNEL - waiting");
922 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_HOP_CHANNEL");
932 case DVDNAV_VTS_CHANGE:
935 auto* vts =
reinterpret_cast<dvdnav_vts_change_event_t*
>(blockBuf);
938 int aspect = dvdnav_get_video_aspect(
m_dvdnav);
941 else if (aspect == 3)
945 int permission = dvdnav_get_video_scale_permission(
m_dvdnav);
948 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
949 QString(
"DVDNAV_VTS_CHANGE: old_vtsN %1, new_vtsN %2, "
950 "aspect %3, perm %4")
951 .arg(vts->old_vtsN).arg(vts->new_vtsN)
952 .arg(aspect).arg(permission));
955 if ((vts->old_vtsN != vts->new_vtsN) ||(vts->old_domain != vts->new_domain))
966 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
971 case DVDNAV_HIGHLIGHT:
974 auto* highlight =
reinterpret_cast<dvdnav_highlight_event_t*
>(blockBuf);
983 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
984 QString(
"DVDNAV_HIGHLIGHT: display %1, palette %2, "
985 "sx %3, sy %4, ex %5, ey %6, pts %7, buttonN %8")
986 .arg(highlight->display).arg(highlight->palette)
987 .arg(highlight->sx).arg(highlight->sy)
988 .arg(highlight->ex).arg(highlight->ey)
989 .arg(highlight->pts).arg(highlight->buttonN));
993 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
998 case DVDNAV_STILL_FRAME:
1001 auto* still =
reinterpret_cast<dvdnav_still_event_t*
>(blockBuf);
1005 if (
m_still != std::chrono::seconds(still->length))
1007 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"DVDNAV_STILL_FRAME (%1) - waiting")
1008 .arg(still->length));
1018 std::this_thread::sleep_for(10ms);
1025 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"Skipping DVDNAV_STILL_FRAME (%1)")
1026 .arg(still->length));
1032 if (
m_still != std::chrono::seconds(still->length))
1034 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"DVDNAV_STILL_FRAME (%1)")
1035 .arg(still->length));
1038 m_still = std::chrono::seconds(still->length);
1045 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
1055 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_WAIT - waiting");
1063 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_WAIT");
1074 std::this_thread::sleep_for(10ms);
1080 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
1088 LOG(VB_GENERAL, LOG_INFO,
LOC +
"DVDNAV_STOP");
1094 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
1100 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Unknown DVD event: %1").arg(
m_dvdEvent));
1104 needed =
static_cast<int>(Size - tot);
1105 offset =
static_cast<int>(tot);
1113 return static_cast<int>(tot);
1131 int newPart =
m_part + 1;
1145 int newPart =
m_part - 1;
1160 return duration_cast<std::chrono::seconds>(
m_pgcLength);
1172 return duration_cast<std::chrono::seconds>(
m_cellStart);
1186 return dvdnav_get_next_still_flag(
m_dvdnav) > 0;
1216 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Skipping still frame.");
1231 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Exiting DVDNAV_WAIT status");
1253 DVDMenuID_t menuid = DVD_MENU_Escape;
1256 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"DVDRingBuf: GoToMenu %1").arg(str));
1258 if (str.compare(
"chapter") == 0)
1259 menuid = DVD_MENU_Part;
1260 else if (str.compare(
"root") == 0)
1261 menuid = DVD_MENU_Root;
1262 else if (str.compare(
"title") == 0)
1263 menuid = DVD_MENU_Title;
1267 dvdnav_status_t ret = dvdnav_menu_call(
m_dvdnav, menuid);
1268 return ret == DVDNAV_STATUS_OK;
1277 bool success =
false;
1284 if (dvdnav_go_up(
m_dvdnav) == DVDNAV_STATUS_OK)
1289 else if (dvdnav_menu_call(
m_dvdnav, DVD_MENU_Root) == DVDNAV_STATUS_OK)
1294 else if (dvdnav_menu_call(
m_dvdnav, DVD_MENU_Title) == DVDNAV_STATUS_OK)
1301 target =
"Nothing available";
1306 target = QString(
"No jump, %1 menu").arg(
m_inMenu ?
"in" :
"not in");
1309 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"DVDRingBuf: GoBack - %1").arg(target));
1361 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1370 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1379 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1388 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1399 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1416 auto *spu_pkt =
reinterpret_cast<uint8_t*
>(av_malloc(
static_cast<size_t>(Size)));
1417 memcpy(spu_pkt,
Buffer,
static_cast<size_t>(Size));
1428 int32_t gotbutton = 0;
1459 QRect rect(0,0,0,0);
1470 const uint8_t *SpuPkt,
int BufSize, uint32_t StartTime)
1481 bool force_subtitle_display =
false;
1482 Subtitle->rects =
nullptr;
1483 Subtitle->num_rects = 0;
1484 Subtitle->start_display_time = StartTime;
1485 Subtitle->end_display_time = StartTime;
1487 int cmd_pos = qFromBigEndian<qint16>(SpuPkt + 2);
1488 while ((cmd_pos + 4) < BufSize)
1492 int date = qFromBigEndian<qint16>(SpuPkt + cmd_pos);
1493 int next_cmd_pos = qFromBigEndian<qint16>(SpuPkt + cmd_pos + 2);
1494 int pos = cmd_pos + 4;
1499 while (pos < BufSize)
1501 int cmd = SpuPkt[pos++];
1505 force_subtitle_display =
true;
1508 Subtitle->start_display_time = ((
static_cast<uint>(date) << 10) / 90) + StartTime;
1511 Subtitle->end_display_time = ((
static_cast<uint>(date) << 10) / 90) + StartTime;
1515 if ((BufSize - pos) < 2)
1518 palette[3] = SpuPkt[pos] >> 4;
1519 palette[2] = SpuPkt[pos] & 0x0f;
1520 palette[1] = SpuPkt[pos + 1] >> 4;
1521 palette[0] = SpuPkt[pos + 1] & 0x0f;
1527 if ((BufSize - pos) < 2)
1529 alpha[3] = SpuPkt[pos] >> 4;
1530 alpha[2] = SpuPkt[pos] & 0x0f;
1531 alpha[1] = SpuPkt[pos + 1] >> 4;
1532 alpha[0] = SpuPkt[pos + 1] & 0x0f;
1538 if ((BufSize - pos) < 6)
1540 x1 = (SpuPkt[pos] << 4) | (SpuPkt[pos + 1] >> 4);
1541 x2 = ((SpuPkt[pos + 1] & 0x0f) << 8) | SpuPkt[pos + 2];
1542 y1 = (SpuPkt[pos + 3] << 4) | (SpuPkt[pos + 4] >> 4);
1543 y2 = ((SpuPkt[pos + 4] & 0x0f) << 8) | SpuPkt[pos + 5];
1549 if ((BufSize - pos) < 4)
1551 offset1 = qFromBigEndian<qint16>(SpuPkt + pos);
1552 offset2 = qFromBigEndian<qint16>(SpuPkt + pos + 2);
1558 if ((BufSize - pos) < 2)
1561 pos += qFromBigEndian<qint16>(SpuPkt + pos);
1572 int width =
x2 -
x1 + 1;
1573 width = std::max(width, 0);
1574 int height = y2 - y1 + 1;
1575 height = std::max(height, 0);
1576 if (width > 0 && height > 0)
1578 if (Subtitle->rects !=
nullptr)
1580 for (
uint i = 0; i < Subtitle->num_rects; i++)
1582 av_free(Subtitle->rects[i]->data[0]);
1583 av_free(Subtitle->rects[i]->data[1]);
1584 av_freep(
reinterpret_cast<void*
>(&Subtitle->rects[i]));
1586 av_freep(
reinterpret_cast<void*
>(&Subtitle->rects));
1587 Subtitle->num_rects = 0;
1590 auto *bitmap =
static_cast<uint8_t*
>(av_malloc(
static_cast<size_t>(width) * height));
1592 Subtitle->rects =
static_cast<AVSubtitleRect**
>(av_mallocz(
sizeof(AVSubtitleRect*) * Subtitle->num_rects));
1593 for (
uint i = 0; i < Subtitle->num_rects; i++)
1594 Subtitle->rects[i] =
static_cast<AVSubtitleRect*
>(av_mallocz(
sizeof(AVSubtitleRect)));
1595#ifdef __cpp_size_t_suffix
1596 Subtitle->rects[0]->data[1] =
static_cast<uint8_t*
>(av_mallocz(4UZ * 4UZ));
1598 Subtitle->rects[0]->data[1] =
static_cast<uint8_t*
>(av_mallocz(4_UZ * 4_UZ));
1600 DecodeRLE(bitmap, width * 2, width, (height + 1) / 2,
1601 SpuPkt, offset1 * 2, BufSize);
1602 DecodeRLE(bitmap + width, width * 2, width, height / 2,
1603 SpuPkt, offset2 * 2, BufSize);
1604 GuessPalette(
reinterpret_cast<uint32_t*
>(Subtitle->rects[0]->data[1]), palette, alpha);
1605 Subtitle->rects[0]->data[0] = bitmap;
1606 Subtitle->rects[0]->x =
x1;
1607 Subtitle->rects[0]->y = y1;
1608 Subtitle->rects[0]->w = width;
1609 Subtitle->rects[0]->h = height;
1610 Subtitle->rects[0]->type = SUBTITLE_BITMAP;
1611 Subtitle->rects[0]->nb_colors = 4;
1612 Subtitle->rects[0]->linesize[0] = width;
1615 Subtitle->rects[1]->type = SUBTITLE_BITMAP;
1616#ifdef __cpp_size_t_suffix
1617 Subtitle->rects[1]->data[1] =
static_cast<uint8_t*
>(av_malloc(4UZ * 4UZ));
1619 Subtitle->rects[1]->data[1] =
static_cast<uint8_t*
>(av_malloc(4_UZ * 4_UZ));
1621 GuessPalette(
reinterpret_cast<uint32_t*
>(Subtitle->rects[1]->data[1]),
1631 if (next_cmd_pos == cmd_pos)
1633 cmd_pos = next_cmd_pos;
1635 if (Subtitle->num_rects > 0)
1637 if (force_subtitle_display)
1639 for (
unsigned i = 0; i < Subtitle->num_rects; i++)
1641 Subtitle->rects[i]->flags |= AV_SUBTITLE_FLAG_FORCED;
1643 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Decoded forced subtitle");
1660 int videoheight = videodispdim.height();
1661 int videowidth = videodispdim.width();
1664 dvdnav_highlight_area_t highlight;
1665 dvdnav_get_current_highlight(
m_dvdnav, &button);
1666 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1667 dvdnav_status_t dvdRet =
1668 dvdnav_get_highlight_area_from_group(
pci, DVD_BTN_GRP_Wide, button,
1669 static_cast<int32_t
>(ButtonMode), &highlight);
1671 if (dvdRet == DVDNAV_STATUS_ERR)
1674 for (
uint i = 0 ; i < 4 ; i++)
1677 m_buttonColor[i] = 0xf & (highlight.palette >> (16 + 4 * i));
1688 m_hlButton.setCoords(highlight.sx, highlight.sy, highlight.ex, highlight.ey);
1689 return ((highlight.sx + highlight.sy) > 0) &&
1690 (highlight.sx < videowidth && highlight.sy < videoheight);
1702 av_free(rect->data[0]);
1703 av_free(rect->data[1]);
1721 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Clearing Menu SPU Packet" );
1732 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1733 int numButtons =
pci->hli.hl_gi.btn_ns;
1734 if (numButtons > 0 && numButtons < 36)
1744 int8_t physicalStreamId = dvdnav_get_audio_logical_stream(
m_dvdnav,
static_cast<uint8_t
>(Index));
1746 if (physicalStreamId >= 0)
1748 uint16_t lang = dvdnav_audio_stream_to_lang(
m_dvdnav,
static_cast<uint8_t
>(physicalStreamId));
1749 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Audio StreamID: %1; lang: %2").arg(Index).arg(lang));
1754 LOG(VB_PLAYBACK, LOG_WARNING,
LOC + QString(
"Audio StreamID: %1 - not found!").arg(Index));
1767 const uint AC3_OFFSET = 0x0080;
1768 const uint DTS_OFFSET = 0x0088;
1769 const uint LPCM_OFFSET = 0x00A0;
1770 const uint MP2_OFFSET = 0x01C0;
1772 if (StreamId >= MP2_OFFSET)
1773 StreamId -= MP2_OFFSET;
1774 else if (StreamId >= LPCM_OFFSET)
1775 StreamId -= LPCM_OFFSET;
1776 else if (StreamId >= DTS_OFFSET)
1777 StreamId -= DTS_OFFSET;
1778 else if (StreamId >= AC3_OFFSET)
1779 StreamId -= AC3_OFFSET;
1782 for (uint8_t i = 0; i < 8; i++)
1786 int8_t phys = dvdnav_get_audio_logical_stream(
m_dvdnav, i);
1787 if (
static_cast<uint>(phys) == StreamId)
1800 int8_t physicalStreamId = dvdnav_get_audio_logical_stream(
m_dvdnav,
static_cast<uint8_t
>(Index));
1801 if (physicalStreamId < 0)
1804 audio_attr_t attributes;
1805 if (dvdnav_get_audio_attr(
m_dvdnav,
static_cast<uint8_t
>(physicalStreamId), &attributes) == DVDNAV_STATUS_OK)
1807 LOG(VB_AUDIO, LOG_INFO, QString(
"DVD Audio Track #%1 Language Extension Code - %2")
1808 .arg(Index).arg(attributes.code_extension));
1809 return attributes.code_extension;
1818 uint16_t lang = dvdnav_spu_stream_to_lang(
m_dvdnav,
static_cast<uint8_t
>(Id));
1819 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"StreamID: %1; lang: %2").arg(Id).arg(lang));
1828 int8_t logstream = -1;
1834 if (dvdnav_is_domain_vts(
m_dvdnav) || (StreamId == 0))
1835 logstream = dvdnav_get_spu_logical_stream(
m_dvdnav,
static_cast<uint8_t
>(StreamId));
1846 std::array<QChar,2> str2 { QChar(Code >> 8), QChar(Code & 0xff) };
1849 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"code: %1; iso639: %2").arg(Code).arg(str3));
1851 if (!str3.isEmpty())
1861 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1862 int32_t button =
pci->hli.hl_gi.fosl_btnn;
1868 dvdnav_get_current_highlight(
m_dvdnav,&button);
1889 dvdnav_set_active_audio_stream(
m_dvdnav,
static_cast<int8_t
>(TrackNo));
1909 int8_t physical = dvdnav_get_audio_logical_stream(
m_dvdnav,
static_cast<uint8_t
>(Index));
1912 uint16_t channels = dvdnav_audio_stream_channels(
m_dvdnav,
static_cast<uint8_t
>(physical));
1913 if (channels != 0xFFFf)
1930 return !(
Name.isEmpty() && SerialNumber.isEmpty());
1938 char* dvdstate = dvdnav_get_state(
m_dvdnav);
1946 return (!
State.isEmpty());
1953 QByteArray state =
State.toUtf8();
1954 return (dvdnav_set_state(
m_dvdnav, state.constData()) == DVDNAV_STATUS_OK);
1964 int format = dvdnav_get_video_format(
m_dvdnav);
1965 double dvdfps = (format == 1) ? 25.00 : 29.97;
1966 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"DVD Frame Rate %1").arg(dvdfps));
1982 dvdnav_part_play(
m_dvdnav, Title, Part);
2013 memset(RGBAPalette, 0, 16);
2014 for (
int i = 0 ; i < 4 ; i++)
2016 uint32_t yuv =
m_clut[Palette[i]];
2017 uint y = (yuv >> 16) & 0xff;
2018 uint cr = (yuv >> 8) & 0xff;
2019 uint cb = (yuv >> 0) & 0xff;
2024 RGBAPalette[i] = ((Alpha[i] * 17U) << 24) | (r << 16 )| (g << 8) | b;
2032 const uint8_t *
Buffer,
int NibbleOffset,
int BufferSize)
2034 int nibbleEnd = BufferSize * 2;
2040 if (NibbleOffset >= nibbleEnd)
2053 v |=
static_cast<uint>(Width - x) << 2;
2058 len = std::min(len, Width - x);
2059 int color = v & 0x03;
2060 memset(data + x, color,
static_cast<size_t>(len));
2069 NibbleOffset += (NibbleOffset & 1);
2079 return (
Buffer[NibbleOffset >> 1] >> ((1 - (NibbleOffset & 1)) << 2)) & 0xf;
2088 for (
int i = 0; i < Num; i++)
2105 if (Subtitle->num_rects == 0 || Subtitle->rects ==
nullptr ||
2106 Subtitle->rects[0]->w <= 0 || Subtitle->rects[0]->h <= 0)
2111 for (
int i = 0; i < Subtitle->rects[0]->nb_colors; i++)
2112 if (((
reinterpret_cast<uint32_t*
>(Subtitle->rects[0]->data[1])[i] >> 24)) == 0)
2115 ptrdiff_t bottom = 0;
2116 while (bottom < Subtitle->rects[0]->h &&
2117 IsTransparent(Subtitle->rects[0]->data[0] + (bottom * Subtitle->rects[0]->linesize[0]),
2118 1, Subtitle->rects[0]->w, colors))
2123 if (bottom == Subtitle->rects[0]->h)
2125 av_freep(
reinterpret_cast<void*
>(&Subtitle->rects[0]->data[0]));
2126 Subtitle->rects[0]->w = Subtitle->rects[0]->h = 0;
2130 ptrdiff_t top = Subtitle->rects[0]->h - 1;
2132 IsTransparent(Subtitle->rects[0]->data[0] + (top * Subtitle->rects[0]->linesize[0]), 1,
2133 Subtitle->rects[0]->w, colors))
2139 while (left < (Subtitle->rects[0]->w - 1) &&
2140 IsTransparent(Subtitle->rects[0]->data[0] + left, Subtitle->rects[0]->linesize[0],
2141 Subtitle->rects[0]->h, colors))
2146 int right = Subtitle->rects[0]->w - 1;
2148 IsTransparent(Subtitle->rects[0]->data[0] + right, Subtitle->rects[0]->linesize[0],
2149 Subtitle->rects[0]->h, colors))
2154 int width = right - left + 1;
2155 int height = top - bottom + 1;
2156 auto *bitmap =
static_cast<uint8_t*
>(av_malloc(
static_cast<size_t>(width) * height));
2160 for (
int y = 0; y < height; y++)
2162 memcpy(bitmap + (
static_cast<ptrdiff_t
>(width) * y), Subtitle->rects[0]->data[0] + left +
2163 ((bottom + y) * Subtitle->rects[0]->linesize[0]),
static_cast<size_t>(width));
2166 av_freep(
reinterpret_cast<void*
>(&Subtitle->rects[0]->data[0]));
2167 Subtitle->rects[0]->data[0] = bitmap;
2168 Subtitle->rects[0]->linesize[0] = width;
2169 Subtitle->rects[0]->w = width;
2170 Subtitle->rects[0]->h = height;
2171 Subtitle->rects[0]->x += left;
2172 Subtitle->rects[0]->y += bottom;
2181 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Switching to Angle %1...").arg(Angle));
2182 dvdnav_status_t status = dvdnav_angle_change(
m_dvdnav,
static_cast<int32_t
>(Angle));
2183 if (status == DVDNAV_STATUS_OK)
QString GetSetting(const QString &key, const QString &defaultval="")
long long SeekInternal(long long Position, int Whence) override
bool HandleAction(const QStringList &Actions, mpeg::chrono::pts Pts) override
void GetDescForPos(QString &Description) const
mpeg::chrono::pts m_pgLength
MythDVDContext * m_context
long long GetTotalReadPosition(void) const
static int DecodeRLE(uint8_t *Bitmap, int Linesize, int Width, int Height, const uint8_t *Buffer, int NibbleOffset, int BufferSize)
decodes the bitmap from the subtitle packet.
void IgnoreWaitStates(bool Ignore) override
int NumMenuButtons(void) const
bool PlayTrack(int Track)
dvdnav_status_t m_dvdStat
void ClearChapterCache(void)
AVSubtitle m_dvdMenuButton
void GetMenuSPUPkt(uint8_t *Buffer, int Size, int StreamID, uint32_t StartTime)
Get SPU pkt from dvd menu subtitle stream.
void SkipDVDWaitingForPlayer(void)
mpeg::chrono::pts m_currentTime
uint16_t GetNumAudioChannels(int Index)
void GoToNextProgram(void)
int NumPartsInTitle(void) const
long long NormalSeek(long long Time)
void MoveButtonRight(void)
bool GoBack(void)
Attempts to back-up by trying to jump to the 'Go up' PGC, the root menu or the title menu in turn.
bool EndOfTitle(void) const
std::chrono::seconds GetTotalTimeOfTitle(void) const
get the total time of the title in seconds 90000 ticks = 1 sec
void SetDVDSpeed(void)
set dvd speed. uses the constant DVD_DRIVE_SPEED table
bool GetDVDStateSnapshot(QString &State)
Get a snapshot of the current DVD VM state.
void PlayTitleAndPart(int Title, int Part)
int GetAudioTrackNum(uint StreamId)
get the logical track index (into PGC_AST_CTL) of the element that maps the given physical stream id.
bool SwitchAngle(int Angle)
QRecursiveMutex m_contextLock
DvdBuffer m_dvdBlockWriteBuf
uint GetSubtitleLanguage(int Id)
Get the subtitle language from the dvd.
MythDVDBuffer(const QString &Filename)
bool RestoreDVDStateSnapshot(const QString &State)
Restore a DVD VM from a snapshot.
bool DVDButtonUpdate(bool ButtonMode)
update the dvd menu button parameters when a user changes the dvd menu button position
int GetTrack(uint Type) const
get the track the dvd should be playing.
bool m_autoselectsubtitle
int32_t GetLastEvent(void) const
bool SectorSeek(uint64_t Sector)
void MoveButtonLeft(void)
bool DVDWaitingForPlayer(void) const
void GetChapterTimes(QList< std::chrono::seconds > &Times)
int GetNumAngles(void) const
bool IsStillFramePending(void) const
uint32_t AdjustTimestamp(uint32_t Timestamp) const
static const QMap< int, int > kSeekSpeedMap
QRect GetButtonCoords(void)
get coordinates of highlighted button
uint GetAudioLanguage(int Index)
get the audio language from the dvd
int8_t GetSubtitleTrackNum(uint StreamId)
get the logical subtitle track/stream number from the dvd
void ClearMenuSPUParameters(void)
clears the menu SPU pkt and parameters.
std::chrono::seconds TitleTimeLeft(void) const
returns seconds left in the title
std::chrono::seconds GetCellStart(void) const
get the start of the cell in seconds
mpeg::chrono::pts m_pgcLength
static int FindSmallestBoundingRectangle(AVSubtitle *Subtitle)
Obtained from ffmpeg dvdsubdec.c Used to find smallest bounded rect and helps prevent jerky picture d...
bool OpenFile(const QString &Filename, std::chrono::milliseconds Retry=kDefaultOpenTimeout) override
Opens a dvd device for reading.
bool m_audioStreamsChanged
double GetFrameRate(void)
used by DecoderBase for the total frame number calculation for position map support and ffw/rew.
void GuessPalette(uint32_t *RGBAPalette, PaletteArray Palette, AlphaArray Alpha)
converts palette values from YUV to RGB
std::chrono::seconds GetChapterLength(void) const
std::chrono::seconds GetCurrentTime(void) const
static uint ConvertLangCode(uint16_t Code)
converts the subtitle/audio lang code to iso639.
bool PGCLengthChanged(void)
check if pgc length has changed
bool AudioStreamsChanged(void) const
void SkipStillFrame(void)
~MythDVDBuffer() override
int GetAudioTrackType(uint Index)
void ActivateButton(void)
Action taken when a dvd menu button is selected.
bool IsSeekingAllowed(void) override
MythDVDContext * GetDVDContext(void)
void MoveButtonDown(void)
bool m_lastButtonSeenInCell
void UnblockReading(void)
long long Seek(long long Time)
void SelectDefaultButton(void)
determines the default dvd menu button to show when you initially access the dvd menu.
bool GoToMenu(const QString &str)
jump to a dvd root or chapter menu
int GetCurrentAngle(void) const
void ReleaseMenuButton(void)
QMap< int, QList< std::chrono::seconds > > m_chapterMap
int m_currentTitleAngleCount
bool DecodeSubtitles(AVSubtitle *Subtitle, int *GotSubtitles, const uint8_t *SpuPkt, int BufSize, uint32_t StartTime)
generate dvd subtitle bitmap or dvd menu bitmap.
mpeg::chrono::pts m_seektime
void SetTrack(uint Type, int TrackNo)
set the dvd subtitle/audio track used
std::chrono::seconds m_lastStill
AVSubtitle * GetMenuSubtitle(uint &Version)
returns dvd menu button information if available.
void GoToPreviousProgram(void)
bool IsOpen(void) const override
PaletteArray m_buttonAlpha
void SetParent(MythDVDPlayer *Parent)
bool IsInStillFrame(void) const override
bool GetNameAndSerialNum(QString &Name, QString &SerialNumber) override
Get the dvd title and serial num.
bool CellChanged(void)
check if dvd cell has changed
long long GetReadPosition(void) const override
returns current position in the PGC.
void ClearMenuButton(void)
clears the dvd menu button structures
bool IsWaiting(void) const
static uint GetNibble(const uint8_t *Buffer, int NibbleOffset)
copied from ffmpeg's dvdsubdec.c
void GetPartAndTitle(int &Part, int &Title) const
bool StartFromBeginning(void) override
std::chrono::seconds m_still
mpeg::chrono::pts m_cellStart
bool IsBookmarkAllowed(void) override
int8_t m_curSubtitleTrack
static int IsTransparent(const uint8_t *Buffer, int Pitch, int Num, const ColorArray &Colors)
Obtained from ffmpeg dvdsubdec.c Used to find smallest bounded rectangle.
int SafeRead(void *Buffer, uint Size) override
float GetAspectOverride(void) const
bool StartOfTitle(void) const
bool IsReadingBlocked(void)
Encapsulates playback context at any given moment.
uint32_t GetLBA(void) const
int64_t GetStartPTS(void) const
bool GetNameAndSerialNum(QString &Name, QString &SerialNumber)
void SetStillFrameTimeout(std::chrono::seconds Length)
static void DisableScreensaver()
static void RestoreScreensaver()
QString m_discSerialNumber
MythOpticalState m_processState
QSize GetVideoSize(void) const
int GetFFRewSkip(void) const
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
virtual int IncrRef(void)
Increments reference count.
Contains listing of PMT Stream ID's for various A/V Stream types.
QString iso639_str2_to_str3(const QString &str2)
ISO 639-1 and ISO 639-2 support functions.
static int iso639_str3_to_key(const unsigned char *iso639_2)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define IncrementButtonVersion
static const std::array< const std::string, 8 > DVDMenuTable
static constexpr mpeg::chrono::pts HALFSECOND
static constexpr int8_t DVD_DRIVE_SPEED
std::array< uint8_t, 256 > ColorArray
std::array< uint8_t, 4 > AlphaArray
static constexpr int32_t DVD_MENU_MAX
std::array< uint8_t, 4 > PaletteArray
static constexpr size_t DVD_BLOCK_SIZE
#define ENO
This can be appended to the LOG args with "+".
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
static constexpr const char * ACTION_LEFT
static constexpr const char * ACTION_DOWN
static constexpr const char * ACTION_RIGHT
static constexpr const char * ACTION_SELECT
static constexpr const char * ACTION_UP
MBASE_PUBLIC long long copy(QFile &dst, QFile &src, uint block_size=0)
Copies src file to dst file.
std::chrono::duration< CHRONO_TYPE, std::ratio< 1, 90000 > > pts
static eu8 clamp(eu8 value, eu8 low, eu8 high)
#define ACTION_CHANNELDOWN