41 changes: 41 additions & 0 deletions mythtv/libs/libmythtv/DVD/mythdvdcontext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#ifndef MYTHDVDCONTEXT_H
#define MYTHDVDCONTEXT_H

// MythTV
#include "mythtvexp.h"
#include "referencecounter.h"

// libdvd
#include "dvdnav/dvdnav.h"

/** \class MythDVDContext
* \brief Encapsulates playback context at any given moment.
*
* This class mainly represents a single VOBU (video object unit) on a DVD
*/
class MTV_PUBLIC MythDVDContext : public ReferenceCounter
{
friend class DVDRingBuffer;

public:
MythDVDContext() = delete;
~MythDVDContext() override = default;

int64_t GetStartPTS (void) const;
int64_t GetEndPTS (void) const;
int64_t GetSeqEndPTS (void) const;
uint32_t GetLBA (void) const;
uint32_t GetLBAPrevVideoFrame (void) const;
int GetNumFrames (void) const;
int GetNumFramesPresent (void) const;
int GetFPS (void) const;

protected:
MythDVDContext(const dsi_t& DSI, const pci_t& PCI);

protected:
dsi_t m_dsi;
pci_t m_pci;
};

#endif // MYTHDVDCONTEXT_H
119 changes: 119 additions & 0 deletions mythtv/libs/libmythtv/DVD/mythdvdinfo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// Qt
#include <QDir>

// MythTV
#include "mythlogging.h"
#include "mythiowrapper.h"
#include "mythdvdinfo.h"

// Std
#include <fcntl.h>
#include <zlib.h>

#undef Z_NULL
#define Z_NULL nullptr

MythDVDInfo::MythDVDInfo(const QString &Filename)
{
LOG(VB_PLAYBACK, LOG_INFO, QString("DVDInfo: Trying %1").arg(Filename));
QString name = Filename;
if (name.startsWith("dvd:"))
{
name.remove(0,4);
while (name.startsWith("//"))
name.remove(0,1);
}

QByteArray fname = name.toLocal8Bit();
dvdnav_status_t res = dvdnav_open(&m_nav, fname.constData());
if (res == DVDNAV_STATUS_ERR)
{
m_lastError = tr("Failed to open device at %1").arg(fname.constData());
LOG(VB_GENERAL, LOG_ERR, QString("DVDInfo: ") + m_lastError);
return;
}

GetNameAndSerialNum(m_nav, m_name, m_serialnumber, name, QString("DVDInfo: "));
}

MythDVDInfo::~MythDVDInfo(void)
{
if (m_nav)
dvdnav_close(m_nav);
LOG(VB_PLAYBACK, LOG_INFO, QString("DVDInfo: Finishing."));
}

bool MythDVDInfo::IsValid(void) const
{
return m_nav != nullptr;
}

void MythDVDInfo::GetNameAndSerialNum(dvdnav_t* Nav,
QString &Name,
QString &Serialnum,
const QString &Filename,
const QString &LogPrefix)
{
const char* dvdname = nullptr;
const char* dvdserial = nullptr;

if (dvdnav_get_title_string(Nav, &dvdname) == DVDNAV_STATUS_ERR)
LOG(VB_GENERAL, LOG_ERR, LogPrefix + "Failed to get name.");
if (dvdnav_get_serial_string(Nav, &dvdserial) == DVDNAV_STATUS_ERR)
LOG(VB_GENERAL, LOG_ERR, LogPrefix + "Failed to get serial number.");

Name = QString(dvdname);
Serialnum = QString(dvdserial);

if (Name.isEmpty() && Serialnum.isEmpty())
{
struct stat stat {};
if ((mythfile_stat(Filename.toLocal8Bit(), &stat) == 0) && S_ISDIR(stat.st_mode))
{
// Name and serial number are empty because we're reading
// from a directory (and not a device or image).

// Use the directory name for the DVD name
QDir dir(Filename);
Name = dir.dirName();
LOG(VB_PLAYBACK, LOG_DEBUG, LogPrefix + QString("Generated dvd name '%1'")
.arg(Name));

// And use the CRC of VTS_01_0.IFO as a serial number
QString ifo = Filename + QString("/VIDEO_TS/VTS_01_0.IFO");
int fd = mythfile_open(ifo.toLocal8Bit(), O_RDONLY);

if (fd > 0)
{
uint8_t buf[2048];
ssize_t read = 0;
uint32_t crc = static_cast<uint32_t>(crc32(0L, Z_NULL, 0));

while((read = mythfile_read(fd, buf, sizeof(buf))) > 0)
crc = static_cast<uint32_t>(crc32(crc, buf, static_cast<uint>(read)));

mythfile_close(fd);
Serialnum = QString("%1__gen").arg(crc, 0, 16, QChar('0'));
LOG(VB_PLAYBACK, LOG_DEBUG, LogPrefix + QString("Generated serial number '%1'")
.arg(Serialnum));
}
else
{
LOG(VB_GENERAL, LOG_ERR, LogPrefix + QString("Unable to open %2 to generate serial number")
.arg(ifo));
}
}
}
}

bool MythDVDInfo::GetNameAndSerialNum(QString &Name, QString &SerialNumber)
{
Name = m_name;
SerialNumber = m_serialnumber;
return !(Name.isEmpty() && SerialNumber.isEmpty());
}

QString MythDVDInfo::GetLastError(void) const
{
return m_lastError;
}
37 changes: 37 additions & 0 deletions mythtv/libs/libmythtv/DVD/mythdvdinfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef MYTHDVDINFO_H
#define MYTHDVDINFO_H

// Qt
#include <QCoreApplication>

// MythTV
#include "mythtvexp.h"

// libdvd
#include "dvdnav/dvdnav.h"

class MTV_PUBLIC MythDVDInfo
{
friend class DVDRingBuffer;
Q_DECLARE_TR_FUNCTIONS(DVDInfo)

public:
explicit MythDVDInfo(const QString &Filename);
~MythDVDInfo(void);

bool IsValid (void) const;
bool GetNameAndSerialNum (QString &Name, QString &SerialNumber);
QString GetLastError (void) const;

protected:
static void GetNameAndSerialNum(dvdnav_t* Nav, QString &Name,
QString &Serialnum, const QString &Filename,
const QString &LogPrefix);

dvdnav_t *m_nav { nullptr };
QString m_name;
QString m_serialnumber;
QString m_lastError;
};

#endif // MYTHDVDINFO_H
4 changes: 4 additions & 0 deletions mythtv/libs/libmythtv/libmythtv.pro
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,11 @@ win32-msvc*|freebsd {
!win32-msvc*:POST_TARGETDEPS += ../../external/libmythdvdnav/libmythdvdnav-$${MYTH_LIB_EXT}

HEADERS += DVD/dvdringbuffer.h
HEADERS += DVD/mythdvdcontext.h
HEADERS += DVD/mythdvdinfo.h
SOURCES += DVD/dvdringbuffer.cpp
SOURCES += DVD/mythdvdcontext.cpp
SOURCES += DVD/mythdvdinfo.cpp
using_frontend {
HEADERS += DVD/mythdvdplayer.h
SOURCES += DVD/mythdvdplayer.cpp
Expand Down
2 changes: 1 addition & 1 deletion mythtv/programs/mythfrontend/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1304,7 +1304,7 @@ static int internal_play_media(const QString &mrl, const QString &plot,

if (pginfo->IsVideoDVD())
{
auto *dvd = new DVDInfo(pginfo->GetPlaybackURL());
auto *dvd = new MythDVDInfo(pginfo->GetPlaybackURL());
if (dvd->IsValid())
{
QString name;
Expand Down