MythTV master
mythbdinfo.cpp
Go to the documentation of this file.
1// Qt
2#include <QDir>
3#include <QCryptographicHash>
4
5// MythTV
9
10#include "io/mythiowrapper.h"
12#include "Bluray/mythbdinfo.h"
13
14// Std
15#include <fcntl.h>
16
17// BluRay
18#ifdef HAVE_LIBBLURAY
19#include <libbluray/bluray.h>
20#include <libbluray/log_control.h>
21#include <libbluray/meta_data.h>
22#else
23#include "libbluray/bluray.h"
24#include "util/log_control.h"
25#include "libbluray/bdnav/meta_data.h"
26#endif
27
28#define LOC QString("BDInfo: ")
29
30MythBDInfo::MythBDInfo(const QString &Filename)
31{
32 LOG(VB_PLAYBACK, LOG_INFO, QString("BDInfo: Trying %1").arg(Filename));
33 QString name = Filename;
34
35 if (name.startsWith("bd:"))
36 {
37 name.remove(0,3);
38 while (name.startsWith("//"))
39 name.remove(0,1);
40 }
41
42 // clean path filename
43 name = QDir(QDir::cleanPath(name)).canonicalPath();
44 if (name.isEmpty())
45 {
46 LOG(VB_GENERAL, LOG_ERR, LOC + QString("'%1' nonexistent").arg(name));
47 name = Filename;
48 }
49
50 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Opened MythBDBuffer device at '%1'").arg(name));
51
52 // Make sure log messages from the Bluray library appear in our logs
53 bd_set_debug_handler([](const char *Message) { LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString(Message).trimmed()); });
54 bd_set_debug_mask(DBG_CRIT | DBG_NAV | DBG_BLURAY);
55
56 // Use our own wrappers for file and directory access
58
59 int bdhandle = -1;
60 BLURAY* bdnav = nullptr;
61 if (Filename.startsWith("myth:") && MythCDROM::inspectImage(Filename) != MythCDROM::kUnknown)
62 {
63 // Use streaming for remote images.
64 // Streaming encrypted images causes a SIGSEGV in aacs code when
65 // using the makemkv libraries due to the missing "device" name.
66 // Since a local device (which is likely to be encrypted) can be
67 // opened directly, only use streaming for remote images, which
68 // presumably won't be encrypted.
69 bdhandle = MythFileOpen(Filename.toLocal8Bit().data(), O_RDONLY);
70 if (bdhandle >= 0)
71 {
72 bdnav = bd_init();
73 if (bdnav)
74 {
75 bd_open_stream(bdnav, &bdhandle,
76 [](void *Handle, void *Buf, int LBA, int NumBlocks) {
77 if (MythFileSeek(*(static_cast<int*>(Handle)), LBA * 2048LL, SEEK_SET) != -1)
78 return static_cast<int>(MythFileRead(*(static_cast<int*>(Handle)), Buf,
79 static_cast<size_t>(NumBlocks) * 2048) / 2048);
80 return -1;
81 });
82 }
83 }
84 }
85 else
86 {
87 QByteArray keyfile = QString("%1/KEYDB.cfg").arg(GetConfDir()).toLatin1();
88 bdnav = bd_open(name.toLocal8Bit().data(), keyfile.constData());
89 }
90
91 if (!bdnav)
92 {
93 m_lastError = tr("Could not open Blu-ray device: %1").arg(name);
94 LOG(VB_GENERAL, LOG_ERR, LOC + m_lastError);
95 m_isValid = false;
96 }
97 else
98 {
99 GetNameAndSerialNum(bdnav, m_name, m_serialnumber, name, QString("BDInfo: "));
100 bd_close(bdnav);
101 }
102
103 if (bdhandle >= 0)
104 MythfileClose(bdhandle);
105
106 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Done");
107}
108
109void MythBDInfo::GetNameAndSerialNum(BLURAY* BluRay, QString &Name,
110 QString &SerialNum, const QString &Filename,
111 const QString &LogPrefix)
112{
113 const meta_dl *metaDiscLibrary = bd_get_meta(BluRay);
114
115 if (metaDiscLibrary)
116 {
117 Name = QString(metaDiscLibrary->di_name);
118 }
119 else
120 {
121 // Use the directory name for the Bluray name
122 QDir dir(Filename);
123 Name = dir.dirName();
124 LOG(VB_PLAYBACK, LOG_DEBUG, LogPrefix + QString("Generated bd name '%1'")
125 .arg(Name));
126 }
127
128 SerialNum.clear();
129
130 // Try to find the first clip info file and
131 // use its SHA1 hash as a serial number.
132 for (uint32_t idx = 0; idx < 200; idx++)
133 {
134 QString clip = QString("BDMV/CLIPINF/%1.clpi").arg(idx, 5, 10, QChar('0'));
135 void* buffer = nullptr;
136 int64_t buffersize = 0;
137 if (bd_read_file(BluRay, clip.toLocal8Bit().data(), &buffer, &buffersize) != 0)
138 {
139 QCryptographicHash crypto(QCryptographicHash::Sha1);
140 // Add the clip number to the hash
141 QByteArray ba = QByteArray::fromRawData(reinterpret_cast<const char*>(&idx), sizeof(idx));
142 crypto.addData(ba);
143 // then the length of the file
144 ba = QByteArray::fromRawData(reinterpret_cast<const char*>(&buffersize), sizeof(buffersize));
145 crypto.addData(ba);
146 // and then the contents
147 ba = QByteArray::fromRawData(reinterpret_cast<const char*>(buffer), buffersize);
148 crypto.addData(ba);
149 SerialNum = QString("%1__gen").arg(QString(crypto.result().toBase64()));
150 free(buffer);
151 LOG(VB_PLAYBACK, LOG_DEBUG, LogPrefix + QString("Generated serial number '%1'")
152 .arg(SerialNum));
153 break;
154 }
155 }
156
157 if (SerialNum.isEmpty())
158 LOG(VB_GENERAL, LOG_ERR, LogPrefix + "Unable to generate serial number");
159}
160
161bool MythBDInfo::IsValid(void) const
162{
163 return m_isValid;
164}
165
166bool MythBDInfo::GetNameAndSerialNum(QString &Name, QString &SerialNum)
167{
168 Name = m_name;
169 SerialNum = m_serialnumber;
170 return !(Name.isEmpty() && SerialNum.isEmpty());
171}
172
173QString MythBDInfo::GetLastError(void) const
174{
175 return m_lastError;
176}
bool m_isValid
Definition: mythbdinfo.h:35
QString GetLastError(void) const
Definition: mythbdinfo.cpp:173
bool GetNameAndSerialNum(QString &Name, QString &SerialNum)
Definition: mythbdinfo.cpp:166
QString m_serialnumber
Definition: mythbdinfo.h:33
QString m_name
Definition: mythbdinfo.h:32
MythBDInfo(const QString &Filename)
Definition: mythbdinfo.cpp:30
QString m_lastError
Definition: mythbdinfo.h:34
bool IsValid(void) const
Definition: mythbdinfo.cpp:161
@ kUnknown
Definition: mythcdrom.h:28
static ImageType inspectImage(const QString &path)
Definition: mythcdrom.cpp:188
IFSPoint * Buf
Definition: ifs.cpp:105
#define LOC
Definition: mythbdinfo.cpp:28
void MythBDIORedirect(void)
QString GetConfDir(void)
Definition: mythdirs.cpp:263
ssize_t MythFileRead(int FileID, void *Buffer, size_t Count)
off_t MythFileSeek(int FileID, off_t Offset, int Whence)
int MythfileClose(int FileID)
int MythFileOpen(const char *Pathname, int Flags)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39