7 #include <QCoreApplication>
15 #include "libmythbase/mythconfig.h"
25 #define LOC QString("DVDRB: ")
27 #define IncrementButtonVersion if (++m_buttonVersion > 1024) m_buttonVersion = 1;
30 static const std::array<const std::string,8>
DVDMenuTable
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 : qAsConst(
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)
138 .arg((Whence == SEEK_SET) ?
"SEEK_SET" :
139 ((Whence == SEEK_CUR) ?
"SEEK_CUR" :
"SEEK_END"));
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 "http://code.mythtv.org/trac");
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());
379 std::copy(chapters.cbegin(), chapters.cend(), std::back_inserter(Times));
388 uint64_t duration = 0;
389 uint64_t *times =
nullptr;
390 uint32_t num = dvdnav_describe_title_chapters(
m_dvdnav, Title, ×, &duration);
394 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to retrieve chapter data");
398 QList<std::chrono::seconds> chapters;
403 for (
uint i = 0; i < num - 1; i++)
421 if (dvdnav_get_position(
m_dvdnav, &pos, &length) == DVDNAV_STATUS_ERR)
424 dvdnav_get_position(
m_dvdnav, &pos, &length);
462 return duration_cast<std::chrono::seconds>(
m_pgLength);
473 uint32_t newTimestamp = Timestamp;
481 int64_t newTimestamp = Timestamp;
482 if ((newTimestamp != AV_NOPTS_VALUE) && (newTimestamp >=
m_timeDiff))
504 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Waiting for player's buffers to drain");
511 std::this_thread::sleep_for(10ms);
518 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Player wait state was not cleared");
526 uint8_t* blockBuf =
nullptr;
528 int needed =
static_cast<int>(Size);
531 bool waiting =
false;
535 LOG(VB_GENERAL, LOG_ERR,
LOC +
"safe_read: called after DVDNAV_STOP");
541 LOG(VB_GENERAL, LOG_ERR,
LOC +
"read ahead thread running.");
545 bool reprocessing {
false };
556 reprocessing =
false;
561 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to read block: %1")
562 .arg(dvdnav_err_to_string(
m_dvdnav)));
570 case DVDNAV_BLOCK_OK:
581 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
584 LOG(VB_PLAYBACK|VB_FILE, LOG_DEBUG,
LOC +
"DVDNAV_BLOCK_OK");
589 case DVDNAV_CELL_CHANGE:
592 auto *cell_event =
reinterpret_cast<dvdnav_cell_change_event_t*
>(blockBuf);
609 uint32_t stillTimer = dvdnav_get_next_still_flag(
m_dvdnav);
614 dvdnav_get_position(
m_dvdnav, &pos, &length);
628 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
629 QString(
"---- DVDNAV_CELL_CHANGE - Cell #%1 Menu %2 Length %3")
630 .arg(cell_event->cellN).arg(
m_inMenu ?
"Yes" :
"No")
631 .arg(
static_cast<double>(cell_event->cell_length) / 90000.0, 0,
'f', 1));
632 QString still = stillTimer ? ((stillTimer < 0xff) ?
633 QString(
"Stillframe: %1 seconds").arg(stillTimer) :
634 QString(
"Infinite stillframe")) :
635 QString(
"Length: %1 seconds")
636 .arg(duration_cast<std::chrono::seconds>(
m_pgcLength).count());
639 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Menu #%1 %2")
644 LOG(VB_PLAYBACK, LOG_INFO,
645 LOC + QString(
"Title #%1: %2 Part %3 of %4")
675 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
680 case DVDNAV_SPU_CLUT_CHANGE:
683 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_SPU_CLUT_CHANGE");
687 std::copy(blockBuf, blockBuf + 16 *
sizeof(uint32_t),
688 reinterpret_cast<uint8_t*
>(
m_clut.data()));
691 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
696 case DVDNAV_SPU_STREAM_CHANGE:
699 auto* spu =
reinterpret_cast<dvdnav_spu_stream_change_event_t*
>(blockBuf);
709 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
710 QString(
"DVDNAV_SPU_STREAM_CHANGE: "
711 "physicalwide %1, physicalletterbox %2, "
712 "physicalpanscan %3, currenttrack %4")
713 .arg(spu->physical_wide).arg(spu->physical_letterbox)
718 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
723 case DVDNAV_AUDIO_STREAM_CHANGE:
726 auto* audio =
reinterpret_cast<dvdnav_audio_stream_change_event_t*
>(blockBuf);
732 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
733 QString(
"DVDNAV_AUDIO_STREAM_CHANGE: old %1 new %2, physical %3, logical %4")
735 .arg(audio->physical).arg(audio->logical));
746 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
751 case DVDNAV_NAV_PACKET:
759 dsi_t *dsi = dvdnav_get_current_nav_dsi(
m_dvdnav);
761 if (
pci ==
nullptr || dsi ==
nullptr)
764 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"DVDNAV_NAV_PACKET - Error retrieving DVD data structures - dsi 0x%1, pci 0x%2")
765 .arg(
reinterpret_cast<uint64_t
>(dsi), 0, 16)
766 .arg(
reinterpret_cast<uint64_t
>(
pci), 0, 16));
773 int64_t diff =
static_cast<int64_t
>(
pci->pci_gi.vobu_s_ptm) -
m_endPts;
778 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"PTS discontinuity - waiting for decoder: this %1, last %2, diff %3")
779 .arg(
pci->pci_gi.vobu_s_ptm).arg(
m_endPts).arg(diff));
793 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"Jumped into middle of menu: lba %1, dest %2")
794 .arg(
pci->pci_gi.nv_pck_lbn)
795 .arg(
pci->pci_gi.nv_pck_lbn - (dsi->synci.sp_synca[0] & 0x7fffffff)));
803 dvdnav_sector_search(
m_dvdnav,
pci->pci_gi.nv_pck_lbn - (dsi->synci.sp_synca[0] & 0x7fffffff), SEEK_SET);
807 pci_t pci_copy = *
pci;
812 if (
pci->pci_gi.vobu_se_e_ptm != 0)
836 m_vobid = dsi->dsi_gi.vobu_vob_idn;
851 if (abs(relativetime) <= 1s)
858 dvdnav_relative_time_search(
m_dvdnav, relativetime.count() * 2);
864 if ( (
pci->hli.hl_gi.hli_ss & 0x03) == 0x01 )
867 int aspect = dvdnav_get_video_aspect(
m_dvdnav);
872 int8_t spustream = dvdnav_get_active_spu_stream(
m_dvdnav) & 0x7f;
874 if (aspect != 0 && spustream > 0)
881 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"DVDNAV_NAV_PACKET - time:%1, lba:%2, vob:%3, cell:%4, seeking:%5, seektime:%6")
898 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
902 case DVDNAV_HOP_CHANNEL:
906 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_HOP_CHANNEL - waiting");
912 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_HOP_CHANNEL");
922 case DVDNAV_VTS_CHANGE:
925 auto* vts =
reinterpret_cast<dvdnav_vts_change_event_t*
>(blockBuf);
928 int aspect = dvdnav_get_video_aspect(
m_dvdnav);
931 else if (aspect == 3)
935 int permission = dvdnav_get_video_scale_permission(
m_dvdnav);
938 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
939 QString(
"DVDNAV_VTS_CHANGE: old_vtsN %1, new_vtsN %2, "
940 "aspect %3, perm %4")
941 .arg(vts->old_vtsN).arg(vts->new_vtsN)
942 .arg(aspect).arg(permission));
945 if ((vts->old_vtsN != vts->new_vtsN) ||(vts->old_domain != vts->new_domain))
956 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
961 case DVDNAV_HIGHLIGHT:
964 auto* highlight =
reinterpret_cast<dvdnav_highlight_event_t*
>(blockBuf);
973 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
974 QString(
"DVDNAV_HIGHLIGHT: display %1, palette %2, "
975 "sx %3, sy %4, ex %5, ey %6, pts %7, buttonN %8")
976 .arg(highlight->display).arg(highlight->palette)
977 .arg(highlight->sx).arg(highlight->sy)
978 .arg(highlight->ex).arg(highlight->ey)
979 .arg(highlight->pts).arg(highlight->buttonN));
983 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
988 case DVDNAV_STILL_FRAME:
991 auto* still =
reinterpret_cast<dvdnav_still_event_t*
>(blockBuf);
995 if (
m_still != std::chrono::seconds(still->length))
997 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"DVDNAV_STILL_FRAME (%1) - waiting")
998 .arg(still->length));
1008 std::this_thread::sleep_for(10ms);
1015 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"Skipping DVDNAV_STILL_FRAME (%1)")
1016 .arg(still->length));
1022 if (
m_still != std::chrono::seconds(still->length))
1024 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"DVDNAV_STILL_FRAME (%1)")
1025 .arg(still->length));
1028 m_still = std::chrono::seconds(still->length);
1035 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
1045 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_WAIT - waiting");
1053 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"DVDNAV_WAIT");
1064 std::this_thread::sleep_for(10ms);
1070 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
1078 LOG(VB_GENERAL, LOG_INFO,
LOC +
"DVDNAV_STOP");
1084 dvdnav_free_cache_block(
m_dvdnav, blockBuf);
1090 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Unknown DVD event: %1").arg(
m_dvdEvent));
1094 needed =
static_cast<int>(Size - tot);
1095 offset =
static_cast<int>(tot);
1103 return static_cast<int>(tot);
1121 int newPart =
m_part + 1;
1135 int newPart =
m_part - 1;
1150 return duration_cast<std::chrono::seconds>(
m_pgcLength);
1162 return duration_cast<std::chrono::seconds>(
m_cellStart);
1176 return dvdnav_get_next_still_flag(
m_dvdnav) > 0;
1206 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Skipping still frame.");
1221 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Exiting DVDNAV_WAIT status");
1243 DVDMenuID_t menuid = DVD_MENU_Escape;
1246 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"DVDRingBuf: GoToMenu %1").arg(str));
1248 if (str.compare(
"chapter") == 0)
1249 menuid = DVD_MENU_Part;
1250 else if (str.compare(
"root") == 0)
1251 menuid = DVD_MENU_Root;
1252 else if (str.compare(
"title") == 0)
1253 menuid = DVD_MENU_Title;
1257 dvdnav_status_t ret = dvdnav_menu_call(
m_dvdnav, menuid);
1258 return ret == DVDNAV_STATUS_OK;
1267 bool success =
false;
1274 if (dvdnav_go_up(
m_dvdnav) == DVDNAV_STATUS_OK)
1279 else if (dvdnav_menu_call(
m_dvdnav, DVD_MENU_Root) == DVDNAV_STATUS_OK)
1284 else if (dvdnav_menu_call(
m_dvdnav, DVD_MENU_Title) == DVDNAV_STATUS_OK)
1291 target =
"Nothing available";
1296 target = QString(
"No jump, %1 menu").arg(
m_inMenu ?
"in" :
"not in");
1299 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"DVDRingBuf: GoBack - %1").arg(target));
1351 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
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);
1389 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1406 auto *spu_pkt =
reinterpret_cast<uint8_t*
>(av_malloc(
static_cast<size_t>(Size)));
1407 memcpy(spu_pkt,
Buffer,
static_cast<size_t>(Size));
1418 int32_t gotbutton = 0;
1449 QRect rect(0,0,0,0);
1460 const uint8_t *SpuPkt,
int BufSize, uint32_t StartTime)
1471 bool force_subtitle_display =
false;
1472 Subtitle->rects =
nullptr;
1473 Subtitle->num_rects = 0;
1474 Subtitle->start_display_time = StartTime;
1475 Subtitle->end_display_time = StartTime;
1477 int cmd_pos = qFromBigEndian<qint16>(SpuPkt + 2);
1478 while ((cmd_pos + 4) < BufSize)
1482 int date = qFromBigEndian<qint16>(SpuPkt + cmd_pos);
1483 int next_cmd_pos = qFromBigEndian<qint16>(SpuPkt + cmd_pos + 2);
1484 int pos = cmd_pos + 4;
1489 while (pos < BufSize)
1491 int cmd = SpuPkt[pos++];
1495 force_subtitle_display =
true;
1498 Subtitle->start_display_time = ((
static_cast<uint>(date) << 10) / 90) + StartTime;
1501 Subtitle->end_display_time = ((
static_cast<uint>(date) << 10) / 90) + StartTime;
1505 if ((BufSize - pos) < 2)
1508 palette[3] = SpuPkt[pos] >> 4;
1509 palette[2] = SpuPkt[pos] & 0x0f;
1510 palette[1] = SpuPkt[pos + 1] >> 4;
1511 palette[0] = SpuPkt[pos + 1] & 0x0f;
1517 if ((BufSize - pos) < 2)
1519 alpha[3] = SpuPkt[pos] >> 4;
1520 alpha[2] = SpuPkt[pos] & 0x0f;
1521 alpha[1] = SpuPkt[pos + 1] >> 4;
1522 alpha[0] = SpuPkt[pos + 1] & 0x0f;
1528 if ((BufSize - pos) < 6)
1530 x1 = (SpuPkt[pos] << 4) | (SpuPkt[pos + 1] >> 4);
1531 x2 = ((SpuPkt[pos + 1] & 0x0f) << 8) | SpuPkt[pos + 2];
1532 y1 = (SpuPkt[pos + 3] << 4) | (SpuPkt[pos + 4] >> 4);
1533 y2 = ((SpuPkt[pos + 4] & 0x0f) << 8) | SpuPkt[pos + 5];
1539 if ((BufSize - pos) < 4)
1541 offset1 = qFromBigEndian<qint16>(SpuPkt + pos);
1542 offset2 = qFromBigEndian<qint16>(SpuPkt + pos + 2);
1548 if ((BufSize - pos) < 2)
1551 pos += qFromBigEndian<qint16>(SpuPkt + pos);
1562 int width =
x2 -
x1 + 1;
1565 int height = y2 - y1 + 1;
1568 if (width > 0 && height > 0)
1570 if (Subtitle->rects !=
nullptr)
1572 for (
uint i = 0; i < Subtitle->num_rects; i++)
1574 av_free(Subtitle->rects[i]->data[0]);
1575 av_free(Subtitle->rects[i]->data[1]);
1576 av_freep(&Subtitle->rects[i]);
1578 av_freep(&Subtitle->rects);
1579 Subtitle->num_rects = 0;
1582 auto *bitmap =
static_cast<uint8_t*
>(av_malloc(
static_cast<size_t>(width) * height));
1584 Subtitle->rects =
static_cast<AVSubtitleRect**
>(av_mallocz(
sizeof(AVSubtitleRect*) * Subtitle->num_rects));
1585 for (
uint i = 0; i < Subtitle->num_rects; i++)
1586 Subtitle->rects[i] =
static_cast<AVSubtitleRect*
>(av_mallocz(
sizeof(AVSubtitleRect)));
1587 Subtitle->rects[0]->data[1] =
static_cast<uint8_t*
>(av_mallocz(4_UZ * 4_UZ));
1588 DecodeRLE(bitmap, width * 2, width, (height + 1) / 2,
1589 SpuPkt, offset1 * 2, BufSize);
1590 DecodeRLE(bitmap + width, width * 2, width, height / 2,
1591 SpuPkt, offset2 * 2, BufSize);
1592 GuessPalette(
reinterpret_cast<uint32_t*
>(Subtitle->rects[0]->data[1]), palette, alpha);
1593 Subtitle->rects[0]->data[0] = bitmap;
1594 Subtitle->rects[0]->x =
x1;
1595 Subtitle->rects[0]->y = y1;
1596 Subtitle->rects[0]->w = width;
1597 Subtitle->rects[0]->h = height;
1598 Subtitle->rects[0]->type = SUBTITLE_BITMAP;
1599 Subtitle->rects[0]->nb_colors = 4;
1600 Subtitle->rects[0]->linesize[0] = width;
1603 Subtitle->rects[1]->type = SUBTITLE_BITMAP;
1604 Subtitle->rects[1]->data[1] =
static_cast<uint8_t*
>(av_malloc(4_UZ * 4_UZ));
1605 GuessPalette(
reinterpret_cast<uint32_t*
>(Subtitle->rects[1]->data[1]),
1613 if (next_cmd_pos == cmd_pos)
1615 cmd_pos = next_cmd_pos;
1617 if (Subtitle->num_rects > 0)
1619 if (force_subtitle_display)
1621 for (
unsigned i = 0; i < Subtitle->num_rects; i++)
1623 Subtitle->rects[i]->flags |= AV_SUBTITLE_FLAG_FORCED;
1625 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Decoded forced subtitle");
1642 int videoheight = videodispdim.height();
1643 int videowidth = videodispdim.width();
1646 dvdnav_highlight_area_t highlight;
1647 dvdnav_get_current_highlight(
m_dvdnav, &button);
1648 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1649 dvdnav_status_t dvdRet =
1650 dvdnav_get_highlight_area_from_group(
pci, DVD_BTN_GRP_Wide, button,
1651 static_cast<int32_t
>(ButtonMode), &highlight);
1653 if (dvdRet == DVDNAV_STATUS_ERR)
1656 for (
uint i = 0 ; i < 4 ; i++)
1659 m_buttonColor[i] = 0xf & (highlight.palette >> (16 + 4 * i));
1670 m_hlButton.setCoords(highlight.sx, highlight.sy, highlight.ex, highlight.ey);
1671 return ((highlight.sx + highlight.sy) > 0) &&
1672 (highlight.sx < videowidth && highlight.sy < videoheight);
1684 av_free(rect->data[0]);
1685 av_free(rect->data[1]);
1703 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Clearing Menu SPU Packet" );
1714 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1715 int numButtons =
pci->hli.hl_gi.btn_ns;
1716 if (numButtons > 0 && numButtons < 36)
1726 int8_t physicalStreamId = dvdnav_get_audio_logical_stream(
m_dvdnav,
static_cast<uint8_t
>(Index));
1728 if (physicalStreamId >= 0)
1730 uint16_t lang = dvdnav_audio_stream_to_lang(
m_dvdnav,
static_cast<uint8_t
>(physicalStreamId));
1731 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Audio StreamID: %1; lang: %2").arg(Index).arg(lang));
1736 LOG(VB_PLAYBACK, LOG_WARNING,
LOC + QString(
"Audio StreamID: %1 - not found!").arg(Index));
1749 const uint AC3_OFFSET = 0x0080;
1750 const uint DTS_OFFSET = 0x0088;
1751 const uint LPCM_OFFSET = 0x00A0;
1752 const uint MP2_OFFSET = 0x01C0;
1754 if (StreamId >= MP2_OFFSET)
1755 StreamId -= MP2_OFFSET;
1756 else if (StreamId >= LPCM_OFFSET)
1757 StreamId -= LPCM_OFFSET;
1758 else if (StreamId >= DTS_OFFSET)
1759 StreamId -= DTS_OFFSET;
1760 else if (StreamId >= AC3_OFFSET)
1761 StreamId -= AC3_OFFSET;
1764 for (uint8_t i = 0; i < 8; i++)
1768 int8_t phys = dvdnav_get_audio_logical_stream(
m_dvdnav, i);
1769 if (
static_cast<uint>(phys) == StreamId)
1782 int8_t physicalStreamId = dvdnav_get_audio_logical_stream(
m_dvdnav,
static_cast<uint8_t
>(Index));
1783 if (physicalStreamId < 0)
1786 audio_attr_t attributes;
1787 if (dvdnav_get_audio_attr(
m_dvdnav,
static_cast<uint8_t
>(physicalStreamId), &attributes) == DVDNAV_STATUS_OK)
1789 LOG(VB_AUDIO, LOG_INFO, QString(
"DVD Audio Track #%1 Language Extension Code - %2")
1790 .arg(Index).arg(attributes.code_extension));
1791 return attributes.code_extension;
1800 uint16_t lang = dvdnav_spu_stream_to_lang(
m_dvdnav,
static_cast<uint8_t
>(Id));
1801 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"StreamID: %1; lang: %2").arg(Id).arg(lang));
1810 int8_t logstream = -1;
1816 if (dvdnav_is_domain_vts(
m_dvdnav) || (StreamId == 0))
1817 logstream = dvdnav_get_spu_logical_stream(
m_dvdnav,
static_cast<uint8_t
>(StreamId));
1828 std::array<QChar,2> str2 { QChar(Code >> 8), QChar(Code & 0xff) };
1831 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"code: %1; iso639: %2").arg(Code).arg(str3));
1833 if (!str3.isEmpty())
1843 pci_t *
pci = dvdnav_get_current_nav_pci(
m_dvdnav);
1844 int32_t button =
pci->hli.hl_gi.fosl_btnn;
1850 dvdnav_get_current_highlight(
m_dvdnav,&button);
1871 dvdnav_set_active_audio_stream(
m_dvdnav,
static_cast<int8_t
>(TrackNo));
1891 int8_t physical = dvdnav_get_audio_logical_stream(
m_dvdnav,
static_cast<uint8_t
>(Index));
1894 uint16_t channels = dvdnav_audio_stream_channels(
m_dvdnav,
static_cast<uint8_t
>(physical));
1895 if (channels != 0xFFFf)
1912 return !(
Name.isEmpty() && SerialNumber.isEmpty());
1920 char* dvdstate = dvdnav_get_state(
m_dvdnav);
1928 return (!
State.isEmpty());
1935 QByteArray state =
State.toUtf8();
1936 return (dvdnav_set_state(
m_dvdnav, state.constData()) == DVDNAV_STATUS_OK);
1946 int format = dvdnav_get_video_format(
m_dvdnav);
1947 double dvdfps = (format == 1) ? 25.00 : 29.97;
1948 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"DVD Frame Rate %1").arg(dvdfps));
1964 dvdnav_part_play(
m_dvdnav, Title, Part);
1995 memset(RGBAPalette, 0, 16);
1996 for (
int i = 0 ; i < 4 ; i++)
1998 uint32_t yuv =
m_clut[Palette[i]];
1999 uint y = (yuv >> 16) & 0xff;
2000 uint cr = (yuv >> 8) & 0xff;
2001 uint cb = (yuv >> 0) & 0xff;
2002 uint r = std::clamp(
uint(y + 1.4022 * (cr - 128)), 0U, 0xFFU);
2003 uint b = std::clamp(
uint(y + 1.7710 * (cb - 128)), 0U, 0xFFU);
2004 uint g = std::clamp(
uint(1.7047 * y - (0.1952 * b) - (0.5647 * r)), 0U, 0xFFU);
2005 RGBAPalette[i] = ((Alpha[i] * 17U) << 24) | (r << 16 )| (g << 8) | b;
2013 const uint8_t *
Buffer,
int NibbleOffset,
int BufferSize)
2015 int nibbleEnd = BufferSize * 2;
2021 if (NibbleOffset >= nibbleEnd)
2034 v |=
static_cast<uint>(Width - x) << 2;
2039 if (len > (Width - x))
2041 int color = v & 0x03;
2042 memset(data + x, color,
static_cast<size_t>(len));
2051 NibbleOffset += (NibbleOffset & 1);
2061 return (
Buffer[NibbleOffset >> 1] >> ((1 - (NibbleOffset & 1)) << 2)) & 0xf;
2070 for (
int i = 0; i < Num; i++)
2087 if (Subtitle->num_rects == 0 || Subtitle->rects ==
nullptr ||
2088 Subtitle->rects[0]->w <= 0 || Subtitle->rects[0]->h <= 0)
2093 for (
int i = 0; i < Subtitle->rects[0]->nb_colors; i++)
2094 if (((
reinterpret_cast<uint32_t*
>(Subtitle->rects[0]->data[1])[i] >> 24)) == 0)
2097 ptrdiff_t bottom = 0;
2098 while (bottom < Subtitle->rects[0]->h &&
2099 IsTransparent(Subtitle->rects[0]->data[0] + bottom * Subtitle->rects[0]->linesize[0],
2100 1, Subtitle->rects[0]->w, colors))
2105 if (bottom == Subtitle->rects[0]->h)
2107 av_freep(&Subtitle->rects[0]->data[0]);
2108 Subtitle->rects[0]->w = Subtitle->rects[0]->h = 0;
2112 ptrdiff_t top = Subtitle->rects[0]->h - 1;
2114 IsTransparent(Subtitle->rects[0]->data[0] + top * Subtitle->rects[0]->linesize[0], 1,
2115 Subtitle->rects[0]->w, colors))
2121 while (left < (Subtitle->rects[0]->w - 1) &&
2122 IsTransparent(Subtitle->rects[0]->data[0] + left, Subtitle->rects[0]->linesize[0],
2123 Subtitle->rects[0]->h, colors))
2128 int right = Subtitle->rects[0]->w - 1;
2130 IsTransparent(Subtitle->rects[0]->data[0] + right, Subtitle->rects[0]->linesize[0],
2131 Subtitle->rects[0]->h, colors))
2136 int width = right - left + 1;
2137 int height = top - bottom + 1;
2138 auto *bitmap =
static_cast<uint8_t*
>(av_malloc(
static_cast<size_t>(width) * height));
2142 for (
int y = 0; y < height; y++)
2144 memcpy(bitmap +
static_cast<ptrdiff_t
>(width) * y, Subtitle->rects[0]->data[0] + left +
2145 (bottom + y) * Subtitle->rects[0]->linesize[0],
static_cast<size_t>(width));
2148 av_freep(&Subtitle->rects[0]->data[0]);
2149 Subtitle->rects[0]->data[0] = bitmap;
2150 Subtitle->rects[0]->linesize[0] = width;
2151 Subtitle->rects[0]->w = width;
2152 Subtitle->rects[0]->h = height;
2153 Subtitle->rects[0]->x += left;
2154 Subtitle->rects[0]->y += bottom;
2163 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Switching to Angle %1...").arg(Angle));
2164 dvdnav_status_t status = dvdnav_angle_change(
m_dvdnav,
static_cast<int32_t
>(Angle));
2165 if (status == DVDNAV_STATUS_OK)