7#include <QCoreApplication>
24#define LOC QString("DVDRB: ")
26#define IncrementButtonVersion if (++m_buttonVersion > 1024) m_buttonVersion = 1;
33 QT_TRANSLATE_NOOP(
"(DVD menu)",
"Title Menu"),
34 QT_TRANSLATE_NOOP(
"(DVD menu)",
"Root Menu"),
35 QT_TRANSLATE_NOOP(
"(DVD menu)",
"Subpicture Menu"),
36 QT_TRANSLATE_NOOP(
"(DVD menu)",
"Audio Menu"),
37 QT_TRANSLATE_NOOP(
"(DVD menu)",
"Angle Menu"),
39 QT_TRANSLATE_NOOP(
"(DVD menu)",
"Part Menu")
43{ { 3, 1 }, { 5, 2 }, { 10, 4 }, { 20, 8 },
44 { 30, 10 }, { 60, 15 }, { 120, 20 }, { 180, 60 } };
88 for (QList<std::chrono::seconds> chapters : std::as_const(
m_chapterMap))
102 ((Whence == SEEK_SET && Position ==
m_readPos) || (Whence == SEEK_CUR && Position == 0)))
110 long long new_pos = (SEEK_SET==Whence) ? Position :
m_readPos + Position;
115 if ((SEEK_END == Whence) || ((SEEK_CUR == Whence) && new_pos != 0))
136 QString cmd = QString(
"Seek(%1, %2)").arg(Position)
138 LOG(VB_GENERAL, LOG_ERR,
LOC + cmd +
" Failed" +
ENO);
154 dvdnav_status_t dvdRet = DVDNAV_STATUS_OK;
158 dvdRet = dvdnav_sector_search(
m_dvdnav,
static_cast<int64_t
>(Sector), SEEK_SET);
160 if (dvdRet == DVDNAV_STATUS_ERR)
162 LOG(VB_PLAYBACK, LOG_ERR,
LOC + QString(
"SectorSeek() to sector %1 failed").arg(Sector));
165 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"DVD Playback SectorSeek() sector: %1").arg(Sector));
171 dvdnav_status_t dvdRet = DVDNAV_STATUS_OK;
178 if (ffrewSkip != 1 && ffrewSkip != 0 && Time != 0)
180 auto it =
kSeekSpeedMap.lowerBound(
static_cast<int>(std::abs(Time)));
186 seekSpeed = -seekSpeed;
187 dvdRet = dvdnav_relative_time_search(
m_dvdnav, seekSpeed);
195 LOG(VB_PLAYBACK, LOG_DEBUG, QString(
"DVD Playback Seek() time: %1; seekSpeed: %2")
196 .arg(Time).arg(seekSpeed));
198 if (dvdRet == DVDNAV_STATUS_ERR)
200 LOG(VB_PLAYBACK, LOG_ERR,
LOC + QString(
"Seek() to time %1 failed").arg(Time));
207 if (Time > 0 && ffrewSkip == 1)
244 Description = QCoreApplication::translate(
"(DVD menu)",
DVDMenuTable[
m_part].c_str());
248 Description = tr(
"Title %1 chapter %2").arg(
m_title).arg(
m_part);
273 if (res == DVDNAV_STATUS_ERR)
276 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to open DVD device at '%1'").arg(
m_filename));
281 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Opened DVD device at '%1'").arg(
m_filename));
292 dvdnav_menu_language_select(
m_dvdnav, lang.toLatin1().data());
293 dvdnav_audio_language_select(
m_dvdnav, lang.toLatin1().data());
294 dvdnav_spu_language_select(
m_dvdnav, lang.toLatin1().data());
296 dvdnav_set_readahead_flag(
m_dvdnav, 0);
297 dvdnav_set_PGC_positioning_flag(
m_dvdnav, 1);
301 if (dvdnav_get_next_still_flag(
m_dvdnav))
303 LOG(VB_GENERAL, LOG_NOTICE,
304 LOC +
"The selected title is a still frame. "
305 "Playback is likely to fail - please raise a bug report at "
306 "https://github.com/MythTV/mythtv/issues");
328 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Resetting DVD device.");
334 LOG(VB_GENERAL, LOG_ERR,
LOC +
335 "DVD errored after initial scan - trying again");
339 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to re-open DVD.");
346 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Setting DVD languages to %1")
351 dvdnav_menu_language_select(
m_dvdnav, lang.toLatin1().data());
352 dvdnav_audio_language_select(
m_dvdnav, lang.toLatin1().data());
353 dvdnav_spu_language_select(
m_dvdnav, lang.toLatin1().data());
377 std::copy(chapters.cbegin(), chapters.cend(), std::back_inserter(Times));
386 uint64_t duration = 0;
387 uint64_t *times =
nullptr;
388 uint32_t num = dvdnav_describe_title_chapters(
m_dvdnav, Title, ×, &duration);
392 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to retrieve chapter data");
396 QList<std::chrono::seconds> chapters;
401 for (
uint i = 0; i < num - 1; i++)
419 if (dvdnav_get_position(
m_dvdnav, &pos, &length) == DVDNAV_STATUS_ERR)
422 dvdnav_get_position(
m_dvdnav, &pos, &length);
460 return duration_cast<std::chrono::seconds>(
m_pgLength);
471 uint32_t newTimestamp = Timestamp;
479 int64_t newTimestamp = Timestamp;
480 if ((newTimestamp != AV_NOPTS_VALUE) && (newTimestamp >=
m_timeDiff))
502 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Waiting for player's buffers to drain");
509 std::this_thread::sleep_for(10ms);
516 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Player wait state was not cleared");
524 uint8_t* blockBuf =
nullptr;
526 int needed =
static_cast<int>(Size);
529 bool waiting =
false;
533 LOG(VB_GENERAL, LOG_ERR,
LOC +
"safe_read: called after DVDNAV_STOP");
539 LOG(VB_GENERAL, LOG_ERR,
LOC +
"read ahead thread running.");
543 bool reprocessing {
false };
554 reprocessing =
false;
559 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to read block: %1")
560 .arg(dvdnav_err_to_string(
m_dvdnav)));
568 case DVDNAV_BLOCK_OK:
579 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
582 LOG(VB_PLAYBACK|VB_FILE, LOG_DEBUG,
LOC +
"DVDNAV_BLOCK_OK");
587 case DVDNAV_CELL_CHANGE:
590 auto *cell_event =
reinterpret_cast<dvdnav_cell_change_event_t*
>(blockBuf);
607 uint32_t stillTimer = dvdnav_get_next_still_flag(
m_dvdnav);
612 dvdnav_get_position(
m_dvdnav, &pos, &length);
626 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
627 QString(
"---- DVDNAV_CELL_CHANGE - Cell #%1 Menu %2 Length %3")
628 .arg(cell_event->cellN).arg(
m_inMenu ?
"Yes" :
"No")
629 .arg(
static_cast<double>(cell_event->cell_length) / 90000.0, 0,
'f', 1));
633 still = QString(
"Length: %1 seconds")
634 .arg(duration_cast<std::chrono::seconds>(
m_pgcLength).count());
636 else if (stillTimer < 0xff)
638 still = QString(
"Stillframe: %1 seconds").arg(stillTimer);
642 still = QString(
"Infinite stillframe");
647 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Menu #%1 %2")
652 LOG(VB_PLAYBACK, LOG_INFO,
653 LOC + QString(
"Title #%1: %2 Part %3 of %4")
683 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
688 case DVDNAV_SPU_CLUT_CHANGE:
691 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_SPU_CLUT_CHANGE");
695 std::copy(blockBuf, blockBuf + (16 *
sizeof(uint32_t)),
696 reinterpret_cast<uint8_t*
>(
m_clut.data()));
699 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
704 case DVDNAV_SPU_STREAM_CHANGE:
707 auto* spu =
reinterpret_cast<dvdnav_spu_stream_change_event_t*
>(blockBuf);
717 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
718 QString(
"DVDNAV_SPU_STREAM_CHANGE: "
719 "physicalwide %1, physicalletterbox %2, "
720 "physicalpanscan %3, currenttrack %4")
721 .arg(spu->physical_wide).arg(spu->physical_letterbox)
726 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
731 case DVDNAV_AUDIO_STREAM_CHANGE:
734 auto* audio =
reinterpret_cast<dvdnav_audio_stream_change_event_t*
>(blockBuf);
740 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
741 QString(
"DVDNAV_AUDIO_STREAM_CHANGE: old %1 new %2, physical %3, logical %4")
743 .arg(audio->physical).arg(audio->logical));
754 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
759 case DVDNAV_NAV_PACKET:
767 dsi_t *dsi = dvdnav_get_current_nav_dsi(
m_dvdnav);
769 if (
pci ==
nullptr || dsi ==
nullptr)
772 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"DVDNAV_NAV_PACKET - Error retrieving DVD data structures - dsi 0x%1, pci 0x%2")
773 .arg(
reinterpret_cast<uint64_t
>(dsi), 0, 16)
774 .arg(
reinterpret_cast<uint64_t
>(
pci), 0, 16));
781 int64_t diff =
static_cast<int64_t
>(
pci->pci_gi.vobu_s_ptm) -
m_endPts;
786 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"PTS discontinuity - waiting for decoder: this %1, last %2, diff %3")
787 .arg(
pci->pci_gi.vobu_s_ptm).arg(
m_endPts).arg(diff));
801 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"Jumped into middle of menu: lba %1, dest %2")
802 .arg(
pci->pci_gi.nv_pck_lbn)
803 .arg(
pci->pci_gi.nv_pck_lbn - (dsi->synci.sp_synca[0] & 0x7fffffff)));
811 dvdnav_sector_search(
m_dvdnav,
pci->pci_gi.nv_pck_lbn - (dsi->synci.sp_synca[0] & 0x7fffffff), SEEK_SET);
815 pci_t pci_copy = *
pci;
820 if (
pci->pci_gi.vobu_se_e_ptm != 0)
844 m_vobid = dsi->dsi_gi.vobu_vob_idn;
859 if (abs(relativetime) <= 1s)
866 dvdnav_relative_time_search(
m_dvdnav, relativetime.count() * 2);
872 if ( (
pci->hli.hl_gi.hli_ss & 0x03) == 0x01 )
875 int aspect = dvdnav_get_video_aspect(
m_dvdnav);
880 int8_t spustream = dvdnav_get_active_spu_stream(
m_dvdnav) & 0x7f;
882 if (aspect != 0 && spustream > 0)
889 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"DVDNAV_NAV_PACKET - time:%1, lba:%2, vob:%3, cell:%4, seeking:%5, seektime:%6")
906 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
910 case DVDNAV_HOP_CHANNEL:
914 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_HOP_CHANNEL - waiting");
920 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_HOP_CHANNEL");
930 case DVDNAV_VTS_CHANGE:
933 auto* vts =
reinterpret_cast<dvdnav_vts_change_event_t*
>(blockBuf);
936 int aspect = dvdnav_get_video_aspect(
m_dvdnav);
939 else if (aspect == 3)
943 int permission = dvdnav_get_video_scale_permission(
m_dvdnav);
946 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
947 QString(
"DVDNAV_VTS_CHANGE: old_vtsN %1, new_vtsN %2, "
948 "aspect %3, perm %4")
949 .arg(vts->old_vtsN).arg(vts->new_vtsN)
950 .arg(aspect).arg(permission));
953 if ((vts->old_vtsN != vts->new_vtsN) ||(vts->old_domain != vts->new_domain))
964 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
969 case DVDNAV_HIGHLIGHT:
972 auto* highlight =
reinterpret_cast<dvdnav_highlight_event_t*
>(blockBuf);
981 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
982 QString(
"DVDNAV_HIGHLIGHT: display %1, palette %2, "
983 "sx %3, sy %4, ex %5, ey %6, pts %7, buttonN %8")
984 .arg(highlight->display).arg(highlight->palette)
985 .arg(highlight->sx).arg(highlight->sy)
986 .arg(highlight->ex).arg(highlight->ey)
987 .arg(highlight->pts).arg(highlight->buttonN));
991 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
996 case DVDNAV_STILL_FRAME:
999 auto* still =
reinterpret_cast<dvdnav_still_event_t*
>(blockBuf);
1003 if (
m_still != std::chrono::seconds(still->length))
1005 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"DVDNAV_STILL_FRAME (%1) - waiting")
1006 .arg(still->length));
1016 std::this_thread::sleep_for(10ms);
1023 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"Skipping DVDNAV_STILL_FRAME (%1)")
1024 .arg(still->length));
1030 if (
m_still != std::chrono::seconds(still->length))
1032 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"DVDNAV_STILL_FRAME (%1)")
1033 .arg(still->length));
1036 m_still = std::chrono::seconds(still->length);
1043 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
1053 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_WAIT - waiting");
1061 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_WAIT");
1072 std::this_thread::sleep_for(10ms);
1078 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
1086 LOG(VB_GENERAL, LOG_INFO,
LOC +
"DVDNAV_STOP");
1092 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
1098 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Unknown DVD event: %1").arg(
m_dvdEvent));
1102 needed =
static_cast<int>(Size - tot);
1103 offset =
static_cast<int>(tot);
1111 return static_cast<int>(tot);
1129 int newPart =
m_part + 1;
1143 int newPart =
m_part - 1;
1158 return duration_cast<std::chrono::seconds>(
m_pgcLength);
1170 return duration_cast<std::chrono::seconds>(
m_cellStart);
1184 return dvdnav_get_next_still_flag(
m_dvdnav) > 0;
1214 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Skipping still frame.");
1229 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Exiting DVDNAV_WAIT status");
1251 DVDMenuID_t menuid = DVD_MENU_Escape;
1254 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"DVDRingBuf: GoToMenu %1").arg(str));
1256 if (str.compare(
"chapter") == 0)
1257 menuid = DVD_MENU_Part;
1258 else if (str.compare(
"root") == 0)
1259 menuid = DVD_MENU_Root;
1260 else if (str.compare(
"title") == 0)
1261 menuid = DVD_MENU_Title;
1265 dvdnav_status_t ret = dvdnav_menu_call(
m_dvdnav, menuid);
1266 return ret == DVDNAV_STATUS_OK;
1275 bool success =
false;
1282 if (dvdnav_go_up(
m_dvdnav) == DVDNAV_STATUS_OK)
1287 else if (dvdnav_menu_call(
m_dvdnav, DVD_MENU_Root) == DVDNAV_STATUS_OK)
1292 else if (dvdnav_menu_call(
m_dvdnav, DVD_MENU_Title) == DVDNAV_STATUS_OK)
1299 target =
"Nothing available";
1304 target = QString(
"No jump, %1 menu").arg(
m_inMenu ?
"in" :
"not in");
1307 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"DVDRingBuf: GoBack - %1").arg(target));
1359 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1368 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1377 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1386 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1397 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1414 auto *spu_pkt =
reinterpret_cast<uint8_t*
>(av_malloc(
static_cast<size_t>(Size)));
1415 memcpy(spu_pkt,
Buffer,
static_cast<size_t>(Size));
1426 int32_t gotbutton = 0;
1457 QRect rect(0,0,0,0);
1468 const uint8_t *SpuPkt,
int BufSize, uint32_t StartTime)
1479 bool force_subtitle_display =
false;
1480 Subtitle->rects =
nullptr;
1481 Subtitle->num_rects = 0;
1482 Subtitle->start_display_time = StartTime;
1483 Subtitle->end_display_time = StartTime;
1485 int cmd_pos = qFromBigEndian<qint16>(SpuPkt + 2);
1486 while ((cmd_pos + 4) < BufSize)
1490 int date = qFromBigEndian<qint16>(SpuPkt + cmd_pos);
1491 int next_cmd_pos = qFromBigEndian<qint16>(SpuPkt + cmd_pos + 2);
1492 int pos = cmd_pos + 4;
1497 while (pos < BufSize)
1499 int cmd = SpuPkt[pos++];
1503 force_subtitle_display =
true;
1506 Subtitle->start_display_time = ((
static_cast<uint>(date) << 10) / 90) + StartTime;
1509 Subtitle->end_display_time = ((
static_cast<uint>(date) << 10) / 90) + StartTime;
1513 if ((BufSize - pos) < 2)
1516 palette[3] = SpuPkt[pos] >> 4;
1517 palette[2] = SpuPkt[pos] & 0x0f;
1518 palette[1] = SpuPkt[pos + 1] >> 4;
1519 palette[0] = SpuPkt[pos + 1] & 0x0f;
1525 if ((BufSize - pos) < 2)
1527 alpha[3] = SpuPkt[pos] >> 4;
1528 alpha[2] = SpuPkt[pos] & 0x0f;
1529 alpha[1] = SpuPkt[pos + 1] >> 4;
1530 alpha[0] = SpuPkt[pos + 1] & 0x0f;
1536 if ((BufSize - pos) < 6)
1538 x1 = (SpuPkt[pos] << 4) | (SpuPkt[pos + 1] >> 4);
1539 x2 = ((SpuPkt[pos + 1] & 0x0f) << 8) | SpuPkt[pos + 2];
1540 y1 = (SpuPkt[pos + 3] << 4) | (SpuPkt[pos + 4] >> 4);
1541 y2 = ((SpuPkt[pos + 4] & 0x0f) << 8) | SpuPkt[pos + 5];
1547 if ((BufSize - pos) < 4)
1549 offset1 = qFromBigEndian<qint16>(SpuPkt + pos);
1550 offset2 = qFromBigEndian<qint16>(SpuPkt + pos + 2);
1556 if ((BufSize - pos) < 2)
1559 pos += qFromBigEndian<qint16>(SpuPkt + pos);
1570 int width =
x2 -
x1 + 1;
1571 width = std::max(width, 0);
1572 int height = y2 - y1 + 1;
1573 height = std::max(height, 0);
1574 if (width > 0 && height > 0)
1576 if (Subtitle->rects !=
nullptr)
1578 for (
uint i = 0; i < Subtitle->num_rects; i++)
1580 av_free(Subtitle->rects[i]->data[0]);
1581 av_free(Subtitle->rects[i]->data[1]);
1582 av_freep(
reinterpret_cast<void*
>(&Subtitle->rects[i]));
1584 av_freep(
reinterpret_cast<void*
>(&Subtitle->rects));
1585 Subtitle->num_rects = 0;
1588 auto *bitmap =
static_cast<uint8_t*
>(av_malloc(
static_cast<size_t>(width) * height));
1590 Subtitle->rects =
static_cast<AVSubtitleRect**
>(av_mallocz(
sizeof(AVSubtitleRect*) * Subtitle->num_rects));
1591 for (
uint i = 0; i < Subtitle->num_rects; i++)
1592 Subtitle->rects[i] =
static_cast<AVSubtitleRect*
>(av_mallocz(
sizeof(AVSubtitleRect)));
1593 Subtitle->rects[0]->data[1] =
static_cast<uint8_t*
>(av_mallocz(4_UZ * 4_UZ));
1594 DecodeRLE(bitmap, width * 2, width, (height + 1) / 2,
1595 SpuPkt, offset1 * 2, BufSize);
1596 DecodeRLE(bitmap + width, width * 2, width, height / 2,
1597 SpuPkt, offset2 * 2, BufSize);
1598 GuessPalette(
reinterpret_cast<uint32_t*
>(Subtitle->rects[0]->data[1]), palette, alpha);
1599 Subtitle->rects[0]->data[0] = bitmap;
1600 Subtitle->rects[0]->x =
x1;
1601 Subtitle->rects[0]->y = y1;
1602 Subtitle->rects[0]->w = width;
1603 Subtitle->rects[0]->h = height;
1604 Subtitle->rects[0]->type = SUBTITLE_BITMAP;
1605 Subtitle->rects[0]->nb_colors = 4;
1606 Subtitle->rects[0]->linesize[0] = width;
1609 Subtitle->rects[1]->type = SUBTITLE_BITMAP;
1610 Subtitle->rects[1]->data[1] =
static_cast<uint8_t*
>(av_malloc(4_UZ * 4_UZ));
1611 GuessPalette(
reinterpret_cast<uint32_t*
>(Subtitle->rects[1]->data[1]),
1621 if (next_cmd_pos == cmd_pos)
1623 cmd_pos = next_cmd_pos;
1625 if (Subtitle->num_rects > 0)
1627 if (force_subtitle_display)
1629 for (
unsigned i = 0; i < Subtitle->num_rects; i++)
1631 Subtitle->rects[i]->flags |= AV_SUBTITLE_FLAG_FORCED;
1633 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Decoded forced subtitle");
1650 int videoheight = videodispdim.height();
1651 int videowidth = videodispdim.width();
1654 dvdnav_highlight_area_t highlight;
1655 dvdnav_get_current_highlight(
m_dvdnav, &button);
1656 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1657 dvdnav_status_t dvdRet =
1658 dvdnav_get_highlight_area_from_group(
pci, DVD_BTN_GRP_Wide, button,
1659 static_cast<int32_t
>(ButtonMode), &highlight);
1661 if (dvdRet == DVDNAV_STATUS_ERR)
1664 for (
uint i = 0 ; i < 4 ; i++)
1667 m_buttonColor[i] = 0xf & (highlight.palette >> (16 + 4 * i));
1678 m_hlButton.setCoords(highlight.sx, highlight.sy, highlight.ex, highlight.ey);
1679 return ((highlight.sx + highlight.sy) > 0) &&
1680 (highlight.sx < videowidth && highlight.sy < videoheight);
1692 av_free(rect->data[0]);
1693 av_free(rect->data[1]);
1711 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Clearing Menu SPU Packet" );
1722 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1723 int numButtons =
pci->hli.hl_gi.btn_ns;
1724 if (numButtons > 0 && numButtons < 36)
1734 int8_t physicalStreamId = dvdnav_get_audio_logical_stream(
m_dvdnav,
static_cast<uint8_t
>(Index));
1736 if (physicalStreamId >= 0)
1738 uint16_t lang = dvdnav_audio_stream_to_lang(
m_dvdnav,
static_cast<uint8_t
>(physicalStreamId));
1739 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Audio StreamID: %1; lang: %2").arg(Index).arg(lang));
1744 LOG(VB_PLAYBACK, LOG_WARNING,
LOC + QString(
"Audio StreamID: %1 - not found!").arg(Index));
1757 const uint AC3_OFFSET = 0x0080;
1758 const uint DTS_OFFSET = 0x0088;
1759 const uint LPCM_OFFSET = 0x00A0;
1760 const uint MP2_OFFSET = 0x01C0;
1762 if (StreamId >= MP2_OFFSET)
1763 StreamId -= MP2_OFFSET;
1764 else if (StreamId >= LPCM_OFFSET)
1765 StreamId -= LPCM_OFFSET;
1766 else if (StreamId >= DTS_OFFSET)
1767 StreamId -= DTS_OFFSET;
1768 else if (StreamId >= AC3_OFFSET)
1769 StreamId -= AC3_OFFSET;
1772 for (uint8_t i = 0; i < 8; i++)
1776 int8_t phys = dvdnav_get_audio_logical_stream(
m_dvdnav, i);
1777 if (
static_cast<uint>(phys) == StreamId)
1790 int8_t physicalStreamId = dvdnav_get_audio_logical_stream(
m_dvdnav,
static_cast<uint8_t
>(Index));
1791 if (physicalStreamId < 0)
1794 audio_attr_t attributes;
1795 if (dvdnav_get_audio_attr(
m_dvdnav,
static_cast<uint8_t
>(physicalStreamId), &attributes) == DVDNAV_STATUS_OK)
1797 LOG(VB_AUDIO, LOG_INFO, QString(
"DVD Audio Track #%1 Language Extension Code - %2")
1798 .arg(Index).arg(attributes.code_extension));
1799 return attributes.code_extension;
1808 uint16_t lang = dvdnav_spu_stream_to_lang(
m_dvdnav,
static_cast<uint8_t
>(Id));
1809 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"StreamID: %1; lang: %2").arg(Id).arg(lang));
1818 int8_t logstream = -1;
1824 if (dvdnav_is_domain_vts(
m_dvdnav) || (StreamId == 0))
1825 logstream = dvdnav_get_spu_logical_stream(
m_dvdnav,
static_cast<uint8_t
>(StreamId));
1836 std::array<QChar,2> str2 { QChar(Code >> 8), QChar(Code & 0xff) };
1839 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"code: %1; iso639: %2").arg(Code).arg(str3));
1841 if (!str3.isEmpty())
1851 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1852 int32_t button =
pci->hli.hl_gi.fosl_btnn;
1858 dvdnav_get_current_highlight(
m_dvdnav,&button);
1879 dvdnav_set_active_audio_stream(
m_dvdnav,
static_cast<int8_t
>(TrackNo));
1899 int8_t physical = dvdnav_get_audio_logical_stream(
m_dvdnav,
static_cast<uint8_t
>(Index));
1902 uint16_t channels = dvdnav_audio_stream_channels(
m_dvdnav,
static_cast<uint8_t
>(physical));
1903 if (channels != 0xFFFf)
1920 return !(
Name.isEmpty() && SerialNumber.isEmpty());
1928 char* dvdstate = dvdnav_get_state(
m_dvdnav);
1936 return (!
State.isEmpty());
1943 QByteArray state =
State.toUtf8();
1944 return (dvdnav_set_state(
m_dvdnav, state.constData()) == DVDNAV_STATUS_OK);
1954 int format = dvdnav_get_video_format(
m_dvdnav);
1955 double dvdfps = (format == 1) ? 25.00 : 29.97;
1956 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"DVD Frame Rate %1").arg(dvdfps));
1972 dvdnav_part_play(
m_dvdnav, Title, Part);
2003 memset(RGBAPalette, 0, 16);
2004 for (
int i = 0 ; i < 4 ; i++)
2006 uint32_t yuv =
m_clut[Palette[i]];
2007 uint y = (yuv >> 16) & 0xff;
2008 uint cr = (yuv >> 8) & 0xff;
2009 uint cb = (yuv >> 0) & 0xff;
2013 RGBAPalette[i] = ((Alpha[i] * 17U) << 24) | (r << 16 )| (g << 8) | b;
2021 const uint8_t *
Buffer,
int NibbleOffset,
int BufferSize)
2023 int nibbleEnd = BufferSize * 2;
2029 if (NibbleOffset >= nibbleEnd)
2042 v |=
static_cast<uint>(Width - x) << 2;
2047 len = std::min(len, Width - x);
2048 int color = v & 0x03;
2049 memset(data + x, color,
static_cast<size_t>(len));
2058 NibbleOffset += (NibbleOffset & 1);
2068 return (
Buffer[NibbleOffset >> 1] >> ((1 - (NibbleOffset & 1)) << 2)) & 0xf;
2077 for (
int i = 0; i < Num; i++)
2094 if (Subtitle->num_rects == 0 || Subtitle->rects ==
nullptr ||
2095 Subtitle->rects[0]->w <= 0 || Subtitle->rects[0]->h <= 0)
2100 for (
int i = 0; i < Subtitle->rects[0]->nb_colors; i++)
2101 if (((
reinterpret_cast<uint32_t*
>(Subtitle->rects[0]->data[1])[i] >> 24)) == 0)
2104 ptrdiff_t bottom = 0;
2105 while (bottom < Subtitle->rects[0]->h &&
2106 IsTransparent(Subtitle->rects[0]->data[0] + (bottom * Subtitle->rects[0]->linesize[0]),
2107 1, Subtitle->rects[0]->w, colors))
2112 if (bottom == Subtitle->rects[0]->h)
2114 av_freep(
reinterpret_cast<void*
>(&Subtitle->rects[0]->data[0]));
2115 Subtitle->rects[0]->w = Subtitle->rects[0]->h = 0;
2119 ptrdiff_t top = Subtitle->rects[0]->h - 1;
2121 IsTransparent(Subtitle->rects[0]->data[0] + (top * Subtitle->rects[0]->linesize[0]), 1,
2122 Subtitle->rects[0]->w, colors))
2128 while (left < (Subtitle->rects[0]->w - 1) &&
2129 IsTransparent(Subtitle->rects[0]->data[0] + left, Subtitle->rects[0]->linesize[0],
2130 Subtitle->rects[0]->h, colors))
2135 int right = Subtitle->rects[0]->w - 1;
2137 IsTransparent(Subtitle->rects[0]->data[0] + right, Subtitle->rects[0]->linesize[0],
2138 Subtitle->rects[0]->h, colors))
2143 int width = right - left + 1;
2144 int height = top - bottom + 1;
2145 auto *bitmap =
static_cast<uint8_t*
>(av_malloc(
static_cast<size_t>(width) * height));
2149 for (
int y = 0; y < height; y++)
2151 memcpy(bitmap + (
static_cast<ptrdiff_t
>(width) * y), Subtitle->rects[0]->data[0] + left +
2152 ((bottom + y) * Subtitle->rects[0]->linesize[0]),
static_cast<size_t>(width));
2155 av_freep(
reinterpret_cast<void*
>(&Subtitle->rects[0]->data[0]));
2156 Subtitle->rects[0]->data[0] = bitmap;
2157 Subtitle->rects[0]->linesize[0] = width;
2158 Subtitle->rects[0]->w = width;
2159 Subtitle->rects[0]->h = height;
2160 Subtitle->rects[0]->x += left;
2161 Subtitle->rects[0]->y += bottom;
2170 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Switching to Angle %1...").arg(Angle));
2171 dvdnav_status_t status = dvdnav_angle_change(
m_dvdnav,
static_cast<int32_t
>(Angle));
2172 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