7#include <QCoreApplication>
13#include "libmythbase/mythconfig.h"
25#define LOC QString("DVDRB: ")
27#define IncrementButtonVersion if (++m_buttonVersion > 1024) m_buttonVersion = 1;
34 QT_TRANSLATE_NOOP(
"(DVD menu)",
"Title Menu"),
35 QT_TRANSLATE_NOOP(
"(DVD menu)",
"Root Menu"),
36 QT_TRANSLATE_NOOP(
"(DVD menu)",
"Subpicture Menu"),
37 QT_TRANSLATE_NOOP(
"(DVD menu)",
"Audio Menu"),
38 QT_TRANSLATE_NOOP(
"(DVD menu)",
"Angle Menu"),
40 QT_TRANSLATE_NOOP(
"(DVD menu)",
"Part Menu")
44{ { 3, 1 }, { 5, 2 }, { 10, 4 }, { 20, 8 },
45 { 30, 10 }, { 60, 15 }, { 120, 20 }, { 180, 60 } };
89 for (QList<std::chrono::seconds> chapters : std::as_const(
m_chapterMap))
103 ((Whence == SEEK_SET && Position ==
m_readPos) || (Whence == SEEK_CUR && Position == 0)))
111 long long new_pos = (SEEK_SET==Whence) ? Position :
m_readPos + Position;
116 if ((SEEK_END == Whence) || ((SEEK_CUR == Whence) && new_pos != 0))
137 QString cmd = QString(
"Seek(%1, %2)").arg(Position)
139 LOG(VB_GENERAL, LOG_ERR,
LOC + cmd +
" Failed" +
ENO);
155 dvdnav_status_t dvdRet = DVDNAV_STATUS_OK;
159 dvdRet = dvdnav_sector_search(
m_dvdnav,
static_cast<int64_t
>(Sector), SEEK_SET);
161 if (dvdRet == DVDNAV_STATUS_ERR)
163 LOG(VB_PLAYBACK, LOG_ERR,
LOC + QString(
"SectorSeek() to sector %1 failed").arg(Sector));
166 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"DVD Playback SectorSeek() sector: %1").arg(Sector));
172 dvdnav_status_t dvdRet = DVDNAV_STATUS_OK;
179 if (ffrewSkip != 1 && ffrewSkip != 0 && Time != 0)
181 auto it =
kSeekSpeedMap.lowerBound(
static_cast<int>(std::abs(Time)));
187 seekSpeed = -seekSpeed;
188 dvdRet = dvdnav_relative_time_search(
m_dvdnav, seekSpeed);
196 LOG(VB_PLAYBACK, LOG_DEBUG, QString(
"DVD Playback Seek() time: %1; seekSpeed: %2")
197 .arg(Time).arg(seekSpeed));
199 if (dvdRet == DVDNAV_STATUS_ERR)
201 LOG(VB_PLAYBACK, LOG_ERR,
LOC + QString(
"Seek() to time %1 failed").arg(Time));
208 if (Time > 0 && ffrewSkip == 1)
245 Description = QCoreApplication::translate(
"(DVD menu)",
DVDMenuTable[
m_part].c_str());
249 Description = tr(
"Title %1 chapter %2").arg(
m_title).arg(
m_part);
274 if (res == DVDNAV_STATUS_ERR)
277 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to open DVD device at '%1'").arg(
m_filename));
282 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Opened DVD device at '%1'").arg(
m_filename));
293 dvdnav_menu_language_select(
m_dvdnav, lang.toLatin1().data());
294 dvdnav_audio_language_select(
m_dvdnav, lang.toLatin1().data());
295 dvdnav_spu_language_select(
m_dvdnav, lang.toLatin1().data());
297 dvdnav_set_readahead_flag(
m_dvdnav, 0);
298 dvdnav_set_PGC_positioning_flag(
m_dvdnav, 1);
302 if (dvdnav_get_next_still_flag(
m_dvdnav))
304 LOG(VB_GENERAL, LOG_NOTICE,
305 LOC +
"The selected title is a still frame. "
306 "Playback is likely to fail - please raise a bug report at "
307 "https://github.com/MythTV/mythtv/issues");
329 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Resetting DVD device.");
335 LOG(VB_GENERAL, LOG_ERR,
LOC +
336 "DVD errored after initial scan - trying again");
340 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to re-open DVD.");
347 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Setting DVD languages to %1")
352 dvdnav_menu_language_select(
m_dvdnav, lang.toLatin1().data());
353 dvdnav_audio_language_select(
m_dvdnav, lang.toLatin1().data());
354 dvdnav_spu_language_select(
m_dvdnav, lang.toLatin1().data());
378 std::copy(chapters.cbegin(), chapters.cend(), std::back_inserter(Times));
387 uint64_t duration = 0;
388 uint64_t *times =
nullptr;
389 uint32_t num = dvdnav_describe_title_chapters(
m_dvdnav, Title, ×, &duration);
393 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to retrieve chapter data");
397 QList<std::chrono::seconds> chapters;
402 for (
uint i = 0; i < num - 1; i++)
420 if (dvdnav_get_position(
m_dvdnav, &pos, &length) == DVDNAV_STATUS_ERR)
423 dvdnav_get_position(
m_dvdnav, &pos, &length);
461 return duration_cast<std::chrono::seconds>(
m_pgLength);
472 uint32_t newTimestamp = Timestamp;
480 int64_t newTimestamp = Timestamp;
481 if ((newTimestamp != AV_NOPTS_VALUE) && (newTimestamp >=
m_timeDiff))
503 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Waiting for player's buffers to drain");
510 std::this_thread::sleep_for(10ms);
517 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Player wait state was not cleared");
525 uint8_t* blockBuf =
nullptr;
527 int needed =
static_cast<int>(Size);
530 bool waiting =
false;
534 LOG(VB_GENERAL, LOG_ERR,
LOC +
"safe_read: called after DVDNAV_STOP");
540 LOG(VB_GENERAL, LOG_ERR,
LOC +
"read ahead thread running.");
544 bool reprocessing {
false };
555 reprocessing =
false;
560 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to read block: %1")
561 .arg(dvdnav_err_to_string(
m_dvdnav)));
569 case DVDNAV_BLOCK_OK:
580 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
583 LOG(VB_PLAYBACK|VB_FILE, LOG_DEBUG,
LOC +
"DVDNAV_BLOCK_OK");
588 case DVDNAV_CELL_CHANGE:
591 auto *cell_event =
reinterpret_cast<dvdnav_cell_change_event_t*
>(blockBuf);
608 uint32_t stillTimer = dvdnav_get_next_still_flag(
m_dvdnav);
613 dvdnav_get_position(
m_dvdnav, &pos, &length);
627 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
628 QString(
"---- DVDNAV_CELL_CHANGE - Cell #%1 Menu %2 Length %3")
629 .arg(cell_event->cellN).arg(
m_inMenu ?
"Yes" :
"No")
630 .arg(
static_cast<double>(cell_event->cell_length) / 90000.0, 0,
'f', 1));
634 still = QString(
"Length: %1 seconds")
635 .arg(duration_cast<std::chrono::seconds>(
m_pgcLength).count());
637 else if (stillTimer < 0xff)
639 still = QString(
"Stillframe: %1 seconds").arg(stillTimer);
643 still = QString(
"Infinite stillframe");
648 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Menu #%1 %2")
653 LOG(VB_PLAYBACK, LOG_INFO,
654 LOC + QString(
"Title #%1: %2 Part %3 of %4")
684 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
689 case DVDNAV_SPU_CLUT_CHANGE:
692 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_SPU_CLUT_CHANGE");
696 std::copy(blockBuf, blockBuf + (16 *
sizeof(uint32_t)),
697 reinterpret_cast<uint8_t*
>(
m_clut.data()));
700 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
705 case DVDNAV_SPU_STREAM_CHANGE:
708 auto* spu =
reinterpret_cast<dvdnav_spu_stream_change_event_t*
>(blockBuf);
718 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
719 QString(
"DVDNAV_SPU_STREAM_CHANGE: "
720 "physicalwide %1, physicalletterbox %2, "
721 "physicalpanscan %3, currenttrack %4")
722 .arg(spu->physical_wide).arg(spu->physical_letterbox)
727 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
732 case DVDNAV_AUDIO_STREAM_CHANGE:
735 auto* audio =
reinterpret_cast<dvdnav_audio_stream_change_event_t*
>(blockBuf);
741 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
742 QString(
"DVDNAV_AUDIO_STREAM_CHANGE: old %1 new %2, physical %3, logical %4")
744 .arg(audio->physical).arg(audio->logical));
755 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
760 case DVDNAV_NAV_PACKET:
768 dsi_t *dsi = dvdnav_get_current_nav_dsi(
m_dvdnav);
770 if (
pci ==
nullptr || dsi ==
nullptr)
773 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"DVDNAV_NAV_PACKET - Error retrieving DVD data structures - dsi 0x%1, pci 0x%2")
774 .arg(
reinterpret_cast<uint64_t
>(dsi), 0, 16)
775 .arg(
reinterpret_cast<uint64_t
>(
pci), 0, 16));
782 int64_t diff =
static_cast<int64_t
>(
pci->pci_gi.vobu_s_ptm) -
m_endPts;
787 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"PTS discontinuity - waiting for decoder: this %1, last %2, diff %3")
788 .arg(
pci->pci_gi.vobu_s_ptm).arg(
m_endPts).arg(diff));
802 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"Jumped into middle of menu: lba %1, dest %2")
803 .arg(
pci->pci_gi.nv_pck_lbn)
804 .arg(
pci->pci_gi.nv_pck_lbn - (dsi->synci.sp_synca[0] & 0x7fffffff)));
812 dvdnav_sector_search(
m_dvdnav,
pci->pci_gi.nv_pck_lbn - (dsi->synci.sp_synca[0] & 0x7fffffff), SEEK_SET);
816 pci_t pci_copy = *
pci;
821 if (
pci->pci_gi.vobu_se_e_ptm != 0)
845 m_vobid = dsi->dsi_gi.vobu_vob_idn;
860 if (abs(relativetime) <= 1s)
867 dvdnav_relative_time_search(
m_dvdnav, relativetime.count() * 2);
873 if ( (
pci->hli.hl_gi.hli_ss & 0x03) == 0x01 )
876 int aspect = dvdnav_get_video_aspect(
m_dvdnav);
881 int8_t spustream = dvdnav_get_active_spu_stream(
m_dvdnav) & 0x7f;
883 if (aspect != 0 && spustream > 0)
890 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"DVDNAV_NAV_PACKET - time:%1, lba:%2, vob:%3, cell:%4, seeking:%5, seektime:%6")
907 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
911 case DVDNAV_HOP_CHANNEL:
915 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_HOP_CHANNEL - waiting");
921 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_HOP_CHANNEL");
931 case DVDNAV_VTS_CHANGE:
934 auto* vts =
reinterpret_cast<dvdnav_vts_change_event_t*
>(blockBuf);
937 int aspect = dvdnav_get_video_aspect(
m_dvdnav);
940 else if (aspect == 3)
944 int permission = dvdnav_get_video_scale_permission(
m_dvdnav);
947 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
948 QString(
"DVDNAV_VTS_CHANGE: old_vtsN %1, new_vtsN %2, "
949 "aspect %3, perm %4")
950 .arg(vts->old_vtsN).arg(vts->new_vtsN)
951 .arg(aspect).arg(permission));
954 if ((vts->old_vtsN != vts->new_vtsN) ||(vts->old_domain != vts->new_domain))
965 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
970 case DVDNAV_HIGHLIGHT:
973 auto* highlight =
reinterpret_cast<dvdnav_highlight_event_t*
>(blockBuf);
982 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
983 QString(
"DVDNAV_HIGHLIGHT: display %1, palette %2, "
984 "sx %3, sy %4, ex %5, ey %6, pts %7, buttonN %8")
985 .arg(highlight->display).arg(highlight->palette)
986 .arg(highlight->sx).arg(highlight->sy)
987 .arg(highlight->ex).arg(highlight->ey)
988 .arg(highlight->pts).arg(highlight->buttonN));
992 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
997 case DVDNAV_STILL_FRAME:
1000 auto* still =
reinterpret_cast<dvdnav_still_event_t*
>(blockBuf);
1004 if (
m_still != std::chrono::seconds(still->length))
1006 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"DVDNAV_STILL_FRAME (%1) - waiting")
1007 .arg(still->length));
1017 std::this_thread::sleep_for(10ms);
1024 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"Skipping DVDNAV_STILL_FRAME (%1)")
1025 .arg(still->length));
1031 if (
m_still != std::chrono::seconds(still->length))
1033 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"DVDNAV_STILL_FRAME (%1)")
1034 .arg(still->length));
1037 m_still = std::chrono::seconds(still->length);
1044 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
1054 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_WAIT - waiting");
1062 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_WAIT");
1073 std::this_thread::sleep_for(10ms);
1079 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
1087 LOG(VB_GENERAL, LOG_INFO,
LOC +
"DVDNAV_STOP");
1093 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
1099 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Unknown DVD event: %1").arg(
m_dvdEvent));
1103 needed =
static_cast<int>(Size - tot);
1104 offset =
static_cast<int>(tot);
1112 return static_cast<int>(tot);
1130 int newPart =
m_part + 1;
1144 int newPart =
m_part - 1;
1159 return duration_cast<std::chrono::seconds>(
m_pgcLength);
1171 return duration_cast<std::chrono::seconds>(
m_cellStart);
1185 return dvdnav_get_next_still_flag(
m_dvdnav) > 0;
1215 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Skipping still frame.");
1230 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Exiting DVDNAV_WAIT status");
1252 DVDMenuID_t menuid = DVD_MENU_Escape;
1255 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"DVDRingBuf: GoToMenu %1").arg(str));
1257 if (str.compare(
"chapter") == 0)
1258 menuid = DVD_MENU_Part;
1259 else if (str.compare(
"root") == 0)
1260 menuid = DVD_MENU_Root;
1261 else if (str.compare(
"title") == 0)
1262 menuid = DVD_MENU_Title;
1266 dvdnav_status_t ret = dvdnav_menu_call(
m_dvdnav, menuid);
1267 return ret == DVDNAV_STATUS_OK;
1276 bool success =
false;
1283 if (dvdnav_go_up(
m_dvdnav) == DVDNAV_STATUS_OK)
1288 else if (dvdnav_menu_call(
m_dvdnav, DVD_MENU_Root) == DVDNAV_STATUS_OK)
1293 else if (dvdnav_menu_call(
m_dvdnav, DVD_MENU_Title) == DVDNAV_STATUS_OK)
1300 target =
"Nothing available";
1305 target = QString(
"No jump, %1 menu").arg(
m_inMenu ?
"in" :
"not in");
1308 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"DVDRingBuf: GoBack - %1").arg(target));
1360 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1369 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1378 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1387 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1398 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1415 auto *spu_pkt =
reinterpret_cast<uint8_t*
>(av_malloc(
static_cast<size_t>(Size)));
1416 memcpy(spu_pkt,
Buffer,
static_cast<size_t>(Size));
1427 int32_t gotbutton = 0;
1458 QRect rect(0,0,0,0);
1469 const uint8_t *SpuPkt,
int BufSize, uint32_t StartTime)
1480 bool force_subtitle_display =
false;
1481 Subtitle->rects =
nullptr;
1482 Subtitle->num_rects = 0;
1483 Subtitle->start_display_time = StartTime;
1484 Subtitle->end_display_time = StartTime;
1486 int cmd_pos = qFromBigEndian<qint16>(SpuPkt + 2);
1487 while ((cmd_pos + 4) < BufSize)
1491 int date = qFromBigEndian<qint16>(SpuPkt + cmd_pos);
1492 int next_cmd_pos = qFromBigEndian<qint16>(SpuPkt + cmd_pos + 2);
1493 int pos = cmd_pos + 4;
1498 while (pos < BufSize)
1500 int cmd = SpuPkt[pos++];
1504 force_subtitle_display =
true;
1507 Subtitle->start_display_time = ((
static_cast<uint>(date) << 10) / 90) + StartTime;
1510 Subtitle->end_display_time = ((
static_cast<uint>(date) << 10) / 90) + StartTime;
1514 if ((BufSize - pos) < 2)
1517 palette[3] = SpuPkt[pos] >> 4;
1518 palette[2] = SpuPkt[pos] & 0x0f;
1519 palette[1] = SpuPkt[pos + 1] >> 4;
1520 palette[0] = SpuPkt[pos + 1] & 0x0f;
1526 if ((BufSize - pos) < 2)
1528 alpha[3] = SpuPkt[pos] >> 4;
1529 alpha[2] = SpuPkt[pos] & 0x0f;
1530 alpha[1] = SpuPkt[pos + 1] >> 4;
1531 alpha[0] = SpuPkt[pos + 1] & 0x0f;
1537 if ((BufSize - pos) < 6)
1539 x1 = (SpuPkt[pos] << 4) | (SpuPkt[pos + 1] >> 4);
1540 x2 = ((SpuPkt[pos + 1] & 0x0f) << 8) | SpuPkt[pos + 2];
1541 y1 = (SpuPkt[pos + 3] << 4) | (SpuPkt[pos + 4] >> 4);
1542 y2 = ((SpuPkt[pos + 4] & 0x0f) << 8) | SpuPkt[pos + 5];
1548 if ((BufSize - pos) < 4)
1550 offset1 = qFromBigEndian<qint16>(SpuPkt + pos);
1551 offset2 = qFromBigEndian<qint16>(SpuPkt + pos + 2);
1557 if ((BufSize - pos) < 2)
1560 pos += qFromBigEndian<qint16>(SpuPkt + pos);
1571 int width =
x2 -
x1 + 1;
1572 width = std::max(width, 0);
1573 int height = y2 - y1 + 1;
1574 height = std::max(height, 0);
1575 if (width > 0 && height > 0)
1577 if (Subtitle->rects !=
nullptr)
1579 for (
uint i = 0; i < Subtitle->num_rects; i++)
1581 av_free(Subtitle->rects[i]->data[0]);
1582 av_free(Subtitle->rects[i]->data[1]);
1583 av_freep(
reinterpret_cast<void*
>(&Subtitle->rects[i]));
1585 av_freep(
reinterpret_cast<void*
>(&Subtitle->rects));
1586 Subtitle->num_rects = 0;
1589 auto *bitmap =
static_cast<uint8_t*
>(av_malloc(
static_cast<size_t>(width) * height));
1591 Subtitle->rects =
static_cast<AVSubtitleRect**
>(av_mallocz(
sizeof(AVSubtitleRect*) * Subtitle->num_rects));
1592 for (
uint i = 0; i < Subtitle->num_rects; i++)
1593 Subtitle->rects[i] =
static_cast<AVSubtitleRect*
>(av_mallocz(
sizeof(AVSubtitleRect)));
1594 Subtitle->rects[0]->data[1] =
static_cast<uint8_t*
>(av_mallocz(4_UZ * 4_UZ));
1595 DecodeRLE(bitmap, width * 2, width, (height + 1) / 2,
1596 SpuPkt, offset1 * 2, BufSize);
1597 DecodeRLE(bitmap + width, width * 2, width, height / 2,
1598 SpuPkt, offset2 * 2, BufSize);
1599 GuessPalette(
reinterpret_cast<uint32_t*
>(Subtitle->rects[0]->data[1]), palette, alpha);
1600 Subtitle->rects[0]->data[0] = bitmap;
1601 Subtitle->rects[0]->x =
x1;
1602 Subtitle->rects[0]->y = y1;
1603 Subtitle->rects[0]->w = width;
1604 Subtitle->rects[0]->h = height;
1605 Subtitle->rects[0]->type = SUBTITLE_BITMAP;
1606 Subtitle->rects[0]->nb_colors = 4;
1607 Subtitle->rects[0]->linesize[0] = width;
1610 Subtitle->rects[1]->type = SUBTITLE_BITMAP;
1611 Subtitle->rects[1]->data[1] =
static_cast<uint8_t*
>(av_malloc(4_UZ * 4_UZ));
1612 GuessPalette(
reinterpret_cast<uint32_t*
>(Subtitle->rects[1]->data[1]),
1622 if (next_cmd_pos == cmd_pos)
1624 cmd_pos = next_cmd_pos;
1626 if (Subtitle->num_rects > 0)
1628 if (force_subtitle_display)
1630 for (
unsigned i = 0; i < Subtitle->num_rects; i++)
1632 Subtitle->rects[i]->flags |= AV_SUBTITLE_FLAG_FORCED;
1634 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Decoded forced subtitle");
1651 int videoheight = videodispdim.height();
1652 int videowidth = videodispdim.width();
1655 dvdnav_highlight_area_t highlight;
1656 dvdnav_get_current_highlight(
m_dvdnav, &button);
1657 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1658 dvdnav_status_t dvdRet =
1659 dvdnav_get_highlight_area_from_group(
pci, DVD_BTN_GRP_Wide, button,
1660 static_cast<int32_t
>(ButtonMode), &highlight);
1662 if (dvdRet == DVDNAV_STATUS_ERR)
1665 for (
uint i = 0 ; i < 4 ; i++)
1668 m_buttonColor[i] = 0xf & (highlight.palette >> (16 + 4 * i));
1679 m_hlButton.setCoords(highlight.sx, highlight.sy, highlight.ex, highlight.ey);
1680 return ((highlight.sx + highlight.sy) > 0) &&
1681 (highlight.sx < videowidth && highlight.sy < videoheight);
1693 av_free(rect->data[0]);
1694 av_free(rect->data[1]);
1712 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Clearing Menu SPU Packet" );
1723 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1724 int numButtons =
pci->hli.hl_gi.btn_ns;
1725 if (numButtons > 0 && numButtons < 36)
1735 int8_t physicalStreamId = dvdnav_get_audio_logical_stream(
m_dvdnav,
static_cast<uint8_t
>(Index));
1737 if (physicalStreamId >= 0)
1739 uint16_t lang = dvdnav_audio_stream_to_lang(
m_dvdnav,
static_cast<uint8_t
>(physicalStreamId));
1740 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Audio StreamID: %1; lang: %2").arg(Index).arg(lang));
1745 LOG(VB_PLAYBACK, LOG_WARNING,
LOC + QString(
"Audio StreamID: %1 - not found!").arg(Index));
1758 const uint AC3_OFFSET = 0x0080;
1759 const uint DTS_OFFSET = 0x0088;
1760 const uint LPCM_OFFSET = 0x00A0;
1761 const uint MP2_OFFSET = 0x01C0;
1763 if (StreamId >= MP2_OFFSET)
1764 StreamId -= MP2_OFFSET;
1765 else if (StreamId >= LPCM_OFFSET)
1766 StreamId -= LPCM_OFFSET;
1767 else if (StreamId >= DTS_OFFSET)
1768 StreamId -= DTS_OFFSET;
1769 else if (StreamId >= AC3_OFFSET)
1770 StreamId -= AC3_OFFSET;
1773 for (uint8_t i = 0; i < 8; i++)
1777 int8_t phys = dvdnav_get_audio_logical_stream(
m_dvdnav, i);
1778 if (
static_cast<uint>(phys) == StreamId)
1791 int8_t physicalStreamId = dvdnav_get_audio_logical_stream(
m_dvdnav,
static_cast<uint8_t
>(Index));
1792 if (physicalStreamId < 0)
1795 audio_attr_t attributes;
1796 if (dvdnav_get_audio_attr(
m_dvdnav,
static_cast<uint8_t
>(physicalStreamId), &attributes) == DVDNAV_STATUS_OK)
1798 LOG(VB_AUDIO, LOG_INFO, QString(
"DVD Audio Track #%1 Language Extension Code - %2")
1799 .arg(Index).arg(attributes.code_extension));
1800 return attributes.code_extension;
1809 uint16_t lang = dvdnav_spu_stream_to_lang(
m_dvdnav,
static_cast<uint8_t
>(Id));
1810 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"StreamID: %1; lang: %2").arg(Id).arg(lang));
1819 int8_t logstream = -1;
1825 if (dvdnav_is_domain_vts(
m_dvdnav) || (StreamId == 0))
1826 logstream = dvdnav_get_spu_logical_stream(
m_dvdnav,
static_cast<uint8_t
>(StreamId));
1837 std::array<QChar,2> str2 { QChar(Code >> 8), QChar(Code & 0xff) };
1840 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"code: %1; iso639: %2").arg(Code).arg(str3));
1842 if (!str3.isEmpty())
1852 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1853 int32_t button =
pci->hli.hl_gi.fosl_btnn;
1859 dvdnav_get_current_highlight(
m_dvdnav,&button);
1880 dvdnav_set_active_audio_stream(
m_dvdnav,
static_cast<int8_t
>(TrackNo));
1900 int8_t physical = dvdnav_get_audio_logical_stream(
m_dvdnav,
static_cast<uint8_t
>(Index));
1903 uint16_t channels = dvdnav_audio_stream_channels(
m_dvdnav,
static_cast<uint8_t
>(physical));
1904 if (channels != 0xFFFf)
1921 return !(
Name.isEmpty() && SerialNumber.isEmpty());
1929 char* dvdstate = dvdnav_get_state(
m_dvdnav);
1937 return (!
State.isEmpty());
1944 QByteArray state =
State.toUtf8();
1945 return (dvdnav_set_state(
m_dvdnav, state.constData()) == DVDNAV_STATUS_OK);
1955 int format = dvdnav_get_video_format(
m_dvdnav);
1956 double dvdfps = (format == 1) ? 25.00 : 29.97;
1957 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"DVD Frame Rate %1").arg(dvdfps));
1973 dvdnav_part_play(
m_dvdnav, Title, Part);
2004 memset(RGBAPalette, 0, 16);
2005 for (
int i = 0 ; i < 4 ; i++)
2007 uint32_t yuv =
m_clut[Palette[i]];
2008 uint y = (yuv >> 16) & 0xff;
2009 uint cr = (yuv >> 8) & 0xff;
2010 uint cb = (yuv >> 0) & 0xff;
2014 RGBAPalette[i] = ((Alpha[i] * 17U) << 24) | (r << 16 )| (g << 8) | b;
2022 const uint8_t *
Buffer,
int NibbleOffset,
int BufferSize)
2024 int nibbleEnd = BufferSize * 2;
2030 if (NibbleOffset >= nibbleEnd)
2043 v |=
static_cast<uint>(Width - x) << 2;
2048 len = std::min(len, Width - x);
2049 int color = v & 0x03;
2050 memset(data + x, color,
static_cast<size_t>(len));
2059 NibbleOffset += (NibbleOffset & 1);
2069 return (
Buffer[NibbleOffset >> 1] >> ((1 - (NibbleOffset & 1)) << 2)) & 0xf;
2078 for (
int i = 0; i < Num; i++)
2095 if (Subtitle->num_rects == 0 || Subtitle->rects ==
nullptr ||
2096 Subtitle->rects[0]->w <= 0 || Subtitle->rects[0]->h <= 0)
2101 for (
int i = 0; i < Subtitle->rects[0]->nb_colors; i++)
2102 if (((
reinterpret_cast<uint32_t*
>(Subtitle->rects[0]->data[1])[i] >> 24)) == 0)
2105 ptrdiff_t bottom = 0;
2106 while (bottom < Subtitle->rects[0]->h &&
2107 IsTransparent(Subtitle->rects[0]->data[0] + (bottom * Subtitle->rects[0]->linesize[0]),
2108 1, Subtitle->rects[0]->w, colors))
2113 if (bottom == Subtitle->rects[0]->h)
2115 av_freep(
reinterpret_cast<void*
>(&Subtitle->rects[0]->data[0]));
2116 Subtitle->rects[0]->w = Subtitle->rects[0]->h = 0;
2120 ptrdiff_t top = Subtitle->rects[0]->h - 1;
2122 IsTransparent(Subtitle->rects[0]->data[0] + (top * Subtitle->rects[0]->linesize[0]), 1,
2123 Subtitle->rects[0]->w, colors))
2129 while (left < (Subtitle->rects[0]->w - 1) &&
2130 IsTransparent(Subtitle->rects[0]->data[0] + left, Subtitle->rects[0]->linesize[0],
2131 Subtitle->rects[0]->h, colors))
2136 int right = Subtitle->rects[0]->w - 1;
2138 IsTransparent(Subtitle->rects[0]->data[0] + right, Subtitle->rects[0]->linesize[0],
2139 Subtitle->rects[0]->h, colors))
2144 int width = right - left + 1;
2145 int height = top - bottom + 1;
2146 auto *bitmap =
static_cast<uint8_t*
>(av_malloc(
static_cast<size_t>(width) * height));
2150 for (
int y = 0; y < height; y++)
2152 memcpy(bitmap + (
static_cast<ptrdiff_t
>(width) * y), Subtitle->rects[0]->data[0] + left +
2153 ((bottom + y) * Subtitle->rects[0]->linesize[0]),
static_cast<size_t>(width));
2156 av_freep(
reinterpret_cast<void*
>(&Subtitle->rects[0]->data[0]));
2157 Subtitle->rects[0]->data[0] = bitmap;
2158 Subtitle->rects[0]->linesize[0] = width;
2159 Subtitle->rects[0]->w = width;
2160 Subtitle->rects[0]->h = height;
2161 Subtitle->rects[0]->x += left;
2162 Subtitle->rects[0]->y += bottom;
2171 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Switching to Angle %1...").arg(Angle));
2172 dvdnav_status_t status = dvdnav_angle_change(
m_dvdnav,
static_cast<int32_t
>(Angle));
2173 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