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;
399 chapters.reserve(num);
404 for (
uint i = 0; i < num - 1; i++)
422 if (dvdnav_get_position(
m_dvdnav, &pos, &length) == DVDNAV_STATUS_ERR)
425 dvdnav_get_position(
m_dvdnav, &pos, &length);
463 return duration_cast<std::chrono::seconds>(
m_pgLength);
474 uint32_t newTimestamp = Timestamp;
482 int64_t newTimestamp = Timestamp;
483 if ((newTimestamp != AV_NOPTS_VALUE) && (newTimestamp >=
m_timeDiff))
505 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Waiting for player's buffers to drain");
512 std::this_thread::sleep_for(10ms);
519 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Player wait state was not cleared");
527 uint8_t* blockBuf =
nullptr;
529 int needed =
static_cast<int>(Size);
532 bool waiting =
false;
536 LOG(VB_GENERAL, LOG_ERR,
LOC +
"safe_read: called after DVDNAV_STOP");
542 LOG(VB_GENERAL, LOG_ERR,
LOC +
"read ahead thread running.");
546 bool reprocessing {
false };
557 reprocessing =
false;
562 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to read block: %1")
563 .arg(dvdnav_err_to_string(
m_dvdnav)));
571 case DVDNAV_BLOCK_OK:
582 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
585 LOG(VB_PLAYBACK|VB_FILE, LOG_DEBUG,
LOC +
"DVDNAV_BLOCK_OK");
590 case DVDNAV_CELL_CHANGE:
593 auto *cell_event =
reinterpret_cast<dvdnav_cell_change_event_t*
>(blockBuf);
610 uint32_t stillTimer = dvdnav_get_next_still_flag(
m_dvdnav);
615 dvdnav_get_position(
m_dvdnav, &pos, &length);
629 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
630 QString(
"---- DVDNAV_CELL_CHANGE - Cell #%1 Menu %2 Length %3")
631 .arg(cell_event->cellN).arg(
m_inMenu ?
"Yes" :
"No")
632 .arg(
static_cast<double>(cell_event->cell_length) / 90000.0, 0,
'f', 1));
636 still = QString(
"Length: %1 seconds")
637 .arg(duration_cast<std::chrono::seconds>(
m_pgcLength).count());
639 else if (stillTimer < 0xff)
641 still = QString(
"Stillframe: %1 seconds").arg(stillTimer);
645 still = QString(
"Infinite stillframe");
650 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Menu #%1 %2")
655 LOG(VB_PLAYBACK, LOG_INFO,
656 LOC + QString(
"Title #%1: %2 Part %3 of %4")
686 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
691 case DVDNAV_SPU_CLUT_CHANGE:
694 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_SPU_CLUT_CHANGE");
698 std::copy(blockBuf, blockBuf + (16 *
sizeof(uint32_t)),
699 reinterpret_cast<uint8_t*
>(
m_clut.data()));
702 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
707 case DVDNAV_SPU_STREAM_CHANGE:
710 auto* spu =
reinterpret_cast<dvdnav_spu_stream_change_event_t*
>(blockBuf);
720 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
721 QString(
"DVDNAV_SPU_STREAM_CHANGE: "
722 "physicalwide %1, physicalletterbox %2, "
723 "physicalpanscan %3, currenttrack %4")
724 .arg(spu->physical_wide).arg(spu->physical_letterbox)
729 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
734 case DVDNAV_AUDIO_STREAM_CHANGE:
737 auto* audio =
reinterpret_cast<dvdnav_audio_stream_change_event_t*
>(blockBuf);
743 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
744 QString(
"DVDNAV_AUDIO_STREAM_CHANGE: old %1 new %2, physical %3, logical %4")
746 .arg(audio->physical).arg(audio->logical));
757 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
762 case DVDNAV_NAV_PACKET:
770 dsi_t *dsi = dvdnav_get_current_nav_dsi(
m_dvdnav);
772 if (
pci ==
nullptr || dsi ==
nullptr)
775 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"DVDNAV_NAV_PACKET - Error retrieving DVD data structures - dsi 0x%1, pci 0x%2")
776 .arg(
reinterpret_cast<uint64_t
>(dsi), 0, 16)
777 .arg(
reinterpret_cast<uint64_t
>(
pci), 0, 16));
784 int64_t diff =
static_cast<int64_t
>(
pci->pci_gi.vobu_s_ptm) -
m_endPts;
789 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"PTS discontinuity - waiting for decoder: this %1, last %2, diff %3")
790 .arg(
pci->pci_gi.vobu_s_ptm).arg(
m_endPts).arg(diff));
804 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"Jumped into middle of menu: lba %1, dest %2")
805 .arg(
pci->pci_gi.nv_pck_lbn)
806 .arg(
pci->pci_gi.nv_pck_lbn - (dsi->synci.sp_synca[0] & 0x7fffffff)));
814 dvdnav_sector_search(
m_dvdnav,
pci->pci_gi.nv_pck_lbn - (dsi->synci.sp_synca[0] & 0x7fffffff), SEEK_SET);
818 pci_t pci_copy = *
pci;
823 if (
pci->pci_gi.vobu_se_e_ptm != 0)
847 m_vobid = dsi->dsi_gi.vobu_vob_idn;
862 if (abs(relativetime) <= 1s)
869 dvdnav_relative_time_search(
m_dvdnav, relativetime.count() * 2);
875 if ( (
pci->hli.hl_gi.hli_ss & 0x03) == 0x01 )
878 int aspect = dvdnav_get_video_aspect(
m_dvdnav);
883 int8_t spustream = dvdnav_get_active_spu_stream(
m_dvdnav) & 0x7f;
885 if (aspect != 0 && spustream > 0)
892 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"DVDNAV_NAV_PACKET - time:%1, lba:%2, vob:%3, cell:%4, seeking:%5, seektime:%6")
909 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
913 case DVDNAV_HOP_CHANNEL:
917 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_HOP_CHANNEL - waiting");
923 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_HOP_CHANNEL");
933 case DVDNAV_VTS_CHANGE:
936 auto* vts =
reinterpret_cast<dvdnav_vts_change_event_t*
>(blockBuf);
939 int aspect = dvdnav_get_video_aspect(
m_dvdnav);
942 else if (aspect == 3)
946 int permission = dvdnav_get_video_scale_permission(
m_dvdnav);
949 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
950 QString(
"DVDNAV_VTS_CHANGE: old_vtsN %1, new_vtsN %2, "
951 "aspect %3, perm %4")
952 .arg(vts->old_vtsN).arg(vts->new_vtsN)
953 .arg(aspect).arg(permission));
956 if ((vts->old_vtsN != vts->new_vtsN) ||(vts->old_domain != vts->new_domain))
967 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
972 case DVDNAV_HIGHLIGHT:
975 auto* highlight =
reinterpret_cast<dvdnav_highlight_event_t*
>(blockBuf);
984 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
985 QString(
"DVDNAV_HIGHLIGHT: display %1, palette %2, "
986 "sx %3, sy %4, ex %5, ey %6, pts %7, buttonN %8")
987 .arg(highlight->display).arg(highlight->palette)
988 .arg(highlight->sx).arg(highlight->sy)
989 .arg(highlight->ex).arg(highlight->ey)
990 .arg(highlight->pts).arg(highlight->buttonN));
994 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
999 case DVDNAV_STILL_FRAME:
1002 auto* still =
reinterpret_cast<dvdnav_still_event_t*
>(blockBuf);
1006 if (
m_still != std::chrono::seconds(still->length))
1008 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"DVDNAV_STILL_FRAME (%1) - waiting")
1009 .arg(still->length));
1019 std::this_thread::sleep_for(10ms);
1026 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"Skipping DVDNAV_STILL_FRAME (%1)")
1027 .arg(still->length));
1033 if (
m_still != std::chrono::seconds(still->length))
1035 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"DVDNAV_STILL_FRAME (%1)")
1036 .arg(still->length));
1039 m_still = std::chrono::seconds(still->length);
1046 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
1056 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_WAIT - waiting");
1064 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_WAIT");
1075 std::this_thread::sleep_for(10ms);
1081 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
1089 LOG(VB_GENERAL, LOG_INFO,
LOC +
"DVDNAV_STOP");
1095 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
1101 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Unknown DVD event: %1").arg(
m_dvdEvent));
1105 needed =
static_cast<int>(Size - tot);
1106 offset =
static_cast<int>(tot);
1114 return static_cast<int>(tot);
1132 int newPart =
m_part + 1;
1146 int newPart =
m_part - 1;
1161 return duration_cast<std::chrono::seconds>(
m_pgcLength);
1173 return duration_cast<std::chrono::seconds>(
m_cellStart);
1187 return dvdnav_get_next_still_flag(
m_dvdnav) > 0;
1217 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Skipping still frame.");
1232 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Exiting DVDNAV_WAIT status");
1254 DVDMenuID_t menuid = DVD_MENU_Escape;
1257 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"DVDRingBuf: GoToMenu %1").arg(str));
1259 if (str.compare(
"chapter") == 0)
1260 menuid = DVD_MENU_Part;
1261 else if (str.compare(
"root") == 0)
1262 menuid = DVD_MENU_Root;
1263 else if (str.compare(
"title") == 0)
1264 menuid = DVD_MENU_Title;
1268 dvdnav_status_t ret = dvdnav_menu_call(
m_dvdnav, menuid);
1269 return ret == DVDNAV_STATUS_OK;
1278 bool success =
false;
1285 if (dvdnav_go_up(
m_dvdnav) == DVDNAV_STATUS_OK)
1290 else if (dvdnav_menu_call(
m_dvdnav, DVD_MENU_Root) == DVDNAV_STATUS_OK)
1295 else if (dvdnav_menu_call(
m_dvdnav, DVD_MENU_Title) == DVDNAV_STATUS_OK)
1302 target =
"Nothing available";
1307 target = QString(
"No jump, %1 menu").arg(
m_inMenu ?
"in" :
"not in");
1310 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"DVDRingBuf: GoBack - %1").arg(target));
1362 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1371 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1380 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1389 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1400 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1417 auto *spu_pkt =
reinterpret_cast<uint8_t*
>(av_malloc(
static_cast<size_t>(Size)));
1418 memcpy(spu_pkt,
Buffer,
static_cast<size_t>(Size));
1429 int32_t gotbutton = 0;
1460 QRect rect(0,0,0,0);
1471 const uint8_t *SpuPkt,
int BufSize, uint32_t StartTime)
1482 bool force_subtitle_display =
false;
1483 Subtitle->rects =
nullptr;
1484 Subtitle->num_rects = 0;
1485 Subtitle->start_display_time = StartTime;
1486 Subtitle->end_display_time = StartTime;
1488 int cmd_pos = qFromBigEndian<qint16>(SpuPkt + 2);
1489 while ((cmd_pos + 4) < BufSize)
1493 int date = qFromBigEndian<qint16>(SpuPkt + cmd_pos);
1494 int next_cmd_pos = qFromBigEndian<qint16>(SpuPkt + cmd_pos + 2);
1495 int pos = cmd_pos + 4;
1500 while (pos < BufSize)
1502 int cmd = SpuPkt[pos++];
1506 force_subtitle_display =
true;
1509 Subtitle->start_display_time = ((
static_cast<uint>(date) << 10) / 90) + StartTime;
1512 Subtitle->end_display_time = ((
static_cast<uint>(date) << 10) / 90) + StartTime;
1516 if ((BufSize - pos) < 2)
1519 palette[3] = SpuPkt[pos] >> 4;
1520 palette[2] = SpuPkt[pos] & 0x0f;
1521 palette[1] = SpuPkt[pos + 1] >> 4;
1522 palette[0] = SpuPkt[pos + 1] & 0x0f;
1528 if ((BufSize - pos) < 2)
1530 alpha[3] = SpuPkt[pos] >> 4;
1531 alpha[2] = SpuPkt[pos] & 0x0f;
1532 alpha[1] = SpuPkt[pos + 1] >> 4;
1533 alpha[0] = SpuPkt[pos + 1] & 0x0f;
1539 if ((BufSize - pos) < 6)
1541 x1 = (SpuPkt[pos] << 4) | (SpuPkt[pos + 1] >> 4);
1542 x2 = ((SpuPkt[pos + 1] & 0x0f) << 8) | SpuPkt[pos + 2];
1543 y1 = (SpuPkt[pos + 3] << 4) | (SpuPkt[pos + 4] >> 4);
1544 y2 = ((SpuPkt[pos + 4] & 0x0f) << 8) | SpuPkt[pos + 5];
1550 if ((BufSize - pos) < 4)
1552 offset1 = qFromBigEndian<qint16>(SpuPkt + pos);
1553 offset2 = qFromBigEndian<qint16>(SpuPkt + pos + 2);
1559 if ((BufSize - pos) < 2)
1562 pos += qFromBigEndian<qint16>(SpuPkt + pos);
1573 int width =
x2 -
x1 + 1;
1574 width = std::max(width, 0);
1575 int height = y2 - y1 + 1;
1576 height = std::max(height, 0);
1577 if (width > 0 && height > 0)
1579 if (Subtitle->rects !=
nullptr)
1581 for (
uint i = 0; i < Subtitle->num_rects; i++)
1583 av_free(Subtitle->rects[i]->data[0]);
1584 av_free(Subtitle->rects[i]->data[1]);
1585 av_freep(
reinterpret_cast<void*
>(&Subtitle->rects[i]));
1587 av_freep(
reinterpret_cast<void*
>(&Subtitle->rects));
1588 Subtitle->num_rects = 0;
1591 auto *bitmap =
static_cast<uint8_t*
>(av_malloc(
static_cast<size_t>(width) * height));
1593 Subtitle->rects =
static_cast<AVSubtitleRect**
>(av_mallocz(
sizeof(AVSubtitleRect*) * Subtitle->num_rects));
1594 for (
uint i = 0; i < Subtitle->num_rects; i++)
1595 Subtitle->rects[i] =
static_cast<AVSubtitleRect*
>(av_mallocz(
sizeof(AVSubtitleRect)));
1596#ifdef __cpp_size_t_suffix
1597 Subtitle->rects[0]->data[1] =
static_cast<uint8_t*
>(av_mallocz(4UZ * 4UZ));
1599 Subtitle->rects[0]->data[1] =
static_cast<uint8_t*
>(av_mallocz(4_UZ * 4_UZ));
1601 DecodeRLE(bitmap, width * 2, width, (height + 1) / 2,
1602 SpuPkt, offset1 * 2, BufSize);
1603 DecodeRLE(bitmap + width, width * 2, width, height / 2,
1604 SpuPkt, offset2 * 2, BufSize);
1605 GuessPalette(
reinterpret_cast<uint32_t*
>(Subtitle->rects[0]->data[1]), palette, alpha);
1606 Subtitle->rects[0]->data[0] = bitmap;
1607 Subtitle->rects[0]->x =
x1;
1608 Subtitle->rects[0]->y = y1;
1609 Subtitle->rects[0]->w = width;
1610 Subtitle->rects[0]->h = height;
1611 Subtitle->rects[0]->type = SUBTITLE_BITMAP;
1612 Subtitle->rects[0]->nb_colors = 4;
1613 Subtitle->rects[0]->linesize[0] = width;
1616 Subtitle->rects[1]->type = SUBTITLE_BITMAP;
1617#ifdef __cpp_size_t_suffix
1618 Subtitle->rects[1]->data[1] =
static_cast<uint8_t*
>(av_malloc(4UZ * 4UZ));
1620 Subtitle->rects[1]->data[1] =
static_cast<uint8_t*
>(av_malloc(4_UZ * 4_UZ));
1622 GuessPalette(
reinterpret_cast<uint32_t*
>(Subtitle->rects[1]->data[1]),
1632 if (next_cmd_pos == cmd_pos)
1634 cmd_pos = next_cmd_pos;
1636 if (Subtitle->num_rects > 0)
1638 if (force_subtitle_display)
1640 for (
unsigned i = 0; i < Subtitle->num_rects; i++)
1642 Subtitle->rects[i]->flags |= AV_SUBTITLE_FLAG_FORCED;
1644 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Decoded forced subtitle");
1661 int videoheight = videodispdim.height();
1662 int videowidth = videodispdim.width();
1665 dvdnav_highlight_area_t highlight;
1666 dvdnav_get_current_highlight(
m_dvdnav, &button);
1667 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1668 dvdnav_status_t dvdRet =
1669 dvdnav_get_highlight_area_from_group(
pci, DVD_BTN_GRP_Wide, button,
1670 static_cast<int32_t
>(ButtonMode), &highlight);
1672 if (dvdRet == DVDNAV_STATUS_ERR)
1675 for (
uint i = 0 ; i < 4 ; i++)
1678 m_buttonColor[i] = 0xf & (highlight.palette >> (16 + (4 * i)));
1689 m_hlButton.setCoords(highlight.sx, highlight.sy, highlight.ex, highlight.ey);
1690 return ((highlight.sx + highlight.sy) > 0) &&
1691 (highlight.sx < videowidth && highlight.sy < videoheight);
1703 av_free(rect->data[0]);
1704 av_free(rect->data[1]);
1722 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Clearing Menu SPU Packet" );
1733 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1734 int numButtons =
pci->hli.hl_gi.btn_ns;
1735 if (numButtons > 0 && numButtons < 36)
1745 int8_t physicalStreamId = dvdnav_get_audio_logical_stream(
m_dvdnav,
static_cast<uint8_t
>(Index));
1747 if (physicalStreamId >= 0)
1749 uint16_t lang = dvdnav_audio_stream_to_lang(
m_dvdnav,
static_cast<uint8_t
>(physicalStreamId));
1750 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Audio StreamID: %1; lang: %2").arg(Index).arg(lang));
1755 LOG(VB_PLAYBACK, LOG_WARNING,
LOC + QString(
"Audio StreamID: %1 - not found!").arg(Index));
1768 const uint AC3_OFFSET = 0x0080;
1769 const uint DTS_OFFSET = 0x0088;
1770 const uint LPCM_OFFSET = 0x00A0;
1771 const uint MP2_OFFSET = 0x01C0;
1773 if (StreamId >= MP2_OFFSET)
1774 StreamId -= MP2_OFFSET;
1775 else if (StreamId >= LPCM_OFFSET)
1776 StreamId -= LPCM_OFFSET;
1777 else if (StreamId >= DTS_OFFSET)
1778 StreamId -= DTS_OFFSET;
1779 else if (StreamId >= AC3_OFFSET)
1780 StreamId -= AC3_OFFSET;
1783 for (uint8_t i = 0; i < 8; i++)
1787 int8_t phys = dvdnav_get_audio_logical_stream(
m_dvdnav, i);
1788 if (
static_cast<uint>(phys) == StreamId)
1801 int8_t physicalStreamId = dvdnav_get_audio_logical_stream(
m_dvdnav,
static_cast<uint8_t
>(Index));
1802 if (physicalStreamId < 0)
1805 audio_attr_t attributes;
1806 if (dvdnav_get_audio_attr(
m_dvdnav,
static_cast<uint8_t
>(physicalStreamId), &attributes) == DVDNAV_STATUS_OK)
1808 LOG(VB_AUDIO, LOG_INFO, QString(
"DVD Audio Track #%1 Language Extension Code - %2")
1809 .arg(Index).arg(attributes.code_extension));
1810 return attributes.code_extension;
1819 uint16_t lang = dvdnav_spu_stream_to_lang(
m_dvdnav,
static_cast<uint8_t
>(Id));
1820 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"StreamID: %1; lang: %2").arg(Id).arg(lang));
1829 int8_t logstream = -1;
1835 if (dvdnav_is_domain_vts(
m_dvdnav) || (StreamId == 0))
1836 logstream = dvdnav_get_spu_logical_stream(
m_dvdnav,
static_cast<uint8_t
>(StreamId));
1847 std::array<QChar,2> str2 { QChar(Code >> 8), QChar(Code & 0xff) };
1850 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"code: %1; iso639: %2").arg(Code).arg(str3));
1852 if (!str3.isEmpty())
1862 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1863 int32_t button =
pci->hli.hl_gi.fosl_btnn;
1869 dvdnav_get_current_highlight(
m_dvdnav,&button);
1890 dvdnav_set_active_audio_stream(
m_dvdnav,
static_cast<int8_t
>(TrackNo));
1910 int8_t physical = dvdnav_get_audio_logical_stream(
m_dvdnav,
static_cast<uint8_t
>(Index));
1913 uint16_t channels = dvdnav_audio_stream_channels(
m_dvdnav,
static_cast<uint8_t
>(physical));
1914 if (channels != 0xFFFf)
1931 return !(
Name.isEmpty() && SerialNumber.isEmpty());
1939 char* dvdstate = dvdnav_get_state(
m_dvdnav);
1947 return (!
State.isEmpty());
1954 QByteArray state =
State.toUtf8();
1955 return (dvdnav_set_state(
m_dvdnav, state.constData()) == DVDNAV_STATUS_OK);
1965 int format = dvdnav_get_video_format(
m_dvdnav);
1966 double dvdfps = (format == 1) ? 25.00 : 29.97;
1967 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"DVD Frame Rate %1").arg(dvdfps));
1983 dvdnav_part_play(
m_dvdnav, Title, Part);
2014 memset(RGBAPalette, 0, 16);
2015 for (
int i = 0 ; i < 4 ; i++)
2017 uint32_t yuv =
m_clut[Palette[i]];
2018 uint y = (yuv >> 16) & 0xff;
2019 uint cr = (yuv >> 8) & 0xff;
2020 uint cb = (yuv >> 0) & 0xff;
2025 RGBAPalette[i] = ((Alpha[i] * 17U) << 24) | (r << 16 )| (g << 8) | b;
2033 const uint8_t *
Buffer,
int NibbleOffset,
int BufferSize)
2035 int nibbleEnd = BufferSize * 2;
2041 if (NibbleOffset >= nibbleEnd)
2054 v |=
static_cast<uint>(Width - x) << 2;
2059 len = std::min(len, Width - x);
2060 int color = v & 0x03;
2061 memset(data + x, color,
static_cast<size_t>(len));
2070 NibbleOffset += (NibbleOffset & 1);
2080 return (
Buffer[NibbleOffset >> 1] >> ((1 - (NibbleOffset & 1)) << 2)) & 0xf;
2089 for (
int i = 0; i < Num; i++)
2106 if (Subtitle->num_rects == 0 || Subtitle->rects ==
nullptr ||
2107 Subtitle->rects[0]->w <= 0 || Subtitle->rects[0]->h <= 0)
2112 for (
int i = 0; i < Subtitle->rects[0]->nb_colors; i++)
2113 if ((
reinterpret_cast<uint32_t*
>(Subtitle->rects[0]->data[1])[i] >> 24) == 0)
2116 ptrdiff_t bottom = 0;
2117 while (bottom < Subtitle->rects[0]->h &&
2118 IsTransparent(Subtitle->rects[0]->data[0] + (bottom * Subtitle->rects[0]->linesize[0]),
2119 1, Subtitle->rects[0]->w, colors))
2124 if (bottom == Subtitle->rects[0]->h)
2126 av_freep(
reinterpret_cast<void*
>(&Subtitle->rects[0]->data[0]));
2127 Subtitle->rects[0]->w = Subtitle->rects[0]->h = 0;
2131 ptrdiff_t top = Subtitle->rects[0]->h - 1;
2133 IsTransparent(Subtitle->rects[0]->data[0] + (top * Subtitle->rects[0]->linesize[0]), 1,
2134 Subtitle->rects[0]->w, colors))
2140 while (left < (Subtitle->rects[0]->w - 1) &&
2141 IsTransparent(Subtitle->rects[0]->data[0] + left, Subtitle->rects[0]->linesize[0],
2142 Subtitle->rects[0]->h, colors))
2147 int right = Subtitle->rects[0]->w - 1;
2149 IsTransparent(Subtitle->rects[0]->data[0] + right, Subtitle->rects[0]->linesize[0],
2150 Subtitle->rects[0]->h, colors))
2155 int width = right - left + 1;
2156 int height = top - bottom + 1;
2157 auto *bitmap =
static_cast<uint8_t*
>(av_malloc(
static_cast<size_t>(width) * height));
2161 for (
int y = 0; y < height; y++)
2163 memcpy(bitmap + (
static_cast<ptrdiff_t
>(width) * y), Subtitle->rects[0]->data[0] + left +
2164 ((bottom + y) * Subtitle->rects[0]->linesize[0]),
static_cast<size_t>(width));
2167 av_freep(
reinterpret_cast<void*
>(&Subtitle->rects[0]->data[0]));
2168 Subtitle->rects[0]->data[0] = bitmap;
2169 Subtitle->rects[0]->linesize[0] = width;
2170 Subtitle->rects[0]->w = width;
2171 Subtitle->rects[0]->h = height;
2172 Subtitle->rects[0]->x += left;
2173 Subtitle->rects[0]->y += bottom;
2182 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Switching to Angle %1...").arg(Angle));
2183 dvdnav_status_t status = dvdnav_angle_change(
m_dvdnav,
static_cast<int32_t
>(Angle));
2184 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