MythTV
master
libs
libmythtv
DVD
mythdvdstream.cpp
Go to the documentation of this file.
1
/* MythDVDStream
2
* Copyright 2011 Lawrence Rust <lvr at softsystem dot co dot uk>
3
*/
4
5
// Qt
6
#include <QMutexLocker>
7
#include <QtGlobal>
8
#include <QtAlgorithms>
9
10
// MythTV
11
#include "
mythlogging.h
"
12
#include "
mythdvdstream.h
"
13
14
// Std
15
#include <algorithm>
16
#include <cstdio>
17
18
// DVD
19
#include "dvdread/dvd_reader.h"
20
#include "dvdread/dvd_udf.h"
21
extern
"C"
{
22
#include "dvd_input.h"
23
}
24
25
#define LOC QString("DVDStream: ")
26
28
class
MythDVDStream::BlockRange
29
{
30
public
:
31
BlockRange
(uint32_t
Start
, uint32_t Count,
int
Title
)
32
:
m_start
(
Start
),
33
m_end
(
Start
+ Count),
34
m_title
(
Title
)
35
{
36
}
37
38
bool
operator <
(
const
BlockRange
rhs)
const
39
{
40
return
m_end
<= rhs.
m_start
;
41
}
42
43
uint32_t
Start
(
void
)
const
{
return
m_start
; }
44
uint32_t
End
(
void
)
const
{
return
m_end
; }
45
int
Title
(
void
)
const
{
return
m_title
; }
46
47
private
:
48
uint32_t
m_start
{ 0 };
49
uint32_t
m_end
{ 0 };
50
int
m_title
{ 0 };
51
};
52
53
54
// Private but located in/shared with dvd_reader.c
55
extern
"C"
int
InternalUDFReadBlocksRaw
(
dvd_reader_t
*device, uint32_t lb_number,
56
size_t
block_count,
unsigned
char
*data,
57
int
encrypted);
58
60
inline
uint32_t
Len2Blocks
(uint32_t Length)
61
{
62
return
(Length + (DVD_VIDEO_LB_LEN - 1)) / DVD_VIDEO_LB_LEN;
63
}
64
66
MythDVDStream::MythDVDStream
(
const
QString& Filename)
67
:
MythMediaBuffer
(
kMythBufferFile
)
68
{
69
MythDVDStream::OpenFile
(Filename);
70
}
71
72
MythDVDStream::~MythDVDStream
()
73
{
74
KillReadAheadThread
();
75
m_rwLock
.lockForWrite();
76
if
(
m_reader
)
77
DVDClose(
m_reader
);
78
m_rwLock
.unlock();
79
}
80
87
bool
MythDVDStream::OpenFile
(
const
QString &Filename,
uint
/*Retry*/
)
88
{
89
m_rwLock
.lockForWrite();
90
91
const
QString
root
= Filename.section(
"/VIDEO_TS/"
, 0, 0);
92
const
QString path = Filename.section(
root
, 1);
93
94
if
(
m_reader
)
95
DVDClose(
m_reader
);
96
97
m_reader
= DVDOpen(qPrintable(
root
));
98
if
(!
m_reader
)
99
{
100
LOG
(VB_GENERAL, LOG_ERR,
LOC
+ QString(
"DVDOpen(%1) failed"
).
arg
(Filename));
101
m_rwLock
.unlock();
102
return
false
;
103
}
104
105
if
(!path.isEmpty())
106
{
107
// Locate the start block of the requested title
108
uint32_t len = 0;
109
m_start
= UDFFindFile(
m_reader
, qPrintable(path), &len);
110
if
(
m_start
== 0)
111
{
112
LOG
(VB_GENERAL, LOG_ERR,
LOC
+ QString(
"(%1) UDFFindFile(%2) failed"
).
113
arg
(
root
).
arg
(path));
114
DVDClose(
m_reader
);
115
m_reader
=
nullptr
;
116
m_rwLock
.unlock();
117
return
false
;
118
}
119
m_blocks
.append(
BlockRange
(0,
Len2Blocks
(len), 0));
120
}
121
else
122
{
123
// Create a list of the possibly encrypted files
124
uint32_t len = 0;
125
126
// Root menu
127
QString name {
"VIDEO_TS/VIDEO_TS.VOB"
};
128
uint32_t
start
= UDFFindFile(
m_reader
, qPrintable(name), &len);
129
if
(
start
!= 0 && len != 0 )
130
m_blocks
.append(
BlockRange
(
start
,
Len2Blocks
(len), 0));
131
132
const
int
kTitles = 100;
133
for
(
int
title
= 1;
title
< kTitles; ++
title
)
134
{
135
// Menu
136
name = QString(
"/VIDEO_TS/VTS_%1_0.VOB"
).arg(
title
,2,10,QChar(
'0'
));
137
start
= UDFFindFile(
m_reader
, qPrintable(name), &len);
138
if
(
start
!= 0 && len != 0 )
139
m_blocks
.append(
BlockRange
(
start
,
Len2Blocks
(len),
title
));
140
141
for
(
int
part = 1; part < 10; ++part)
142
{
143
// A/V track
144
name = QString(
"/VIDEO_TS/VTS_%1_%2.VOB"
).arg(
title
,2,10,QChar(
'0'
)).arg(part);
145
start
= UDFFindFile(
m_reader
, qPrintable(name), &len);
146
if
(
start
!= 0 && len != 0 )
147
m_blocks
.append(
BlockRange
(
start
,
Len2Blocks
(len),
title
+ part * kTitles));
148
}
149
}
150
151
std::sort(
m_blocks
.begin(),
m_blocks
.end());
152
153
// Open the root menu so that CSS keys are generated now
154
dvd_file_t *
file
= DVDOpenFile(
m_reader
, 0, DVD_READ_MENU_VOBS);
155
if
(
file
)
156
DVDCloseFile(
file
);
157
else
158
LOG
(VB_GENERAL, LOG_ERR,
LOC
+
"DVDOpenFile(VOBS_1) failed"
);
159
}
160
161
m_rwLock
.unlock();
162
return
true
;
163
}
164
165
bool
MythDVDStream::IsOpen
(
void
)
const
166
{
167
m_rwLock
.lockForRead();
168
bool
ret =
m_reader
!=
nullptr
;
169
m_rwLock
.unlock();
170
return
ret;
171
}
172
173
int
MythDVDStream::SafeRead
(
void
*
Buffer
,
uint
Size)
174
{
175
uint32_t block = Size / DVD_VIDEO_LB_LEN;
176
if
(block < 1)
177
{
178
LOG
(VB_GENERAL, LOG_ERR,
LOC
+
"SafeRead too small"
);
179
return
-1;
180
}
181
182
if
(!
m_reader
)
183
return
-1;
184
185
int
ret = 0;
186
187
// Are any blocks in the range encrypted?
188
auto
it = std::lower_bound(
m_blocks
.begin(),
m_blocks
.end(),
BlockRange
(
m_pos
, block, -1));
189
uint32_t b = (it ==
m_blocks
.end()) ? block : (m_pos < it->
Start
() ? it->Start() -
m_pos
: 0);
190
if
(b)
191
{
192
// Read the beginning unencrypted blocks
193
ret =
InternalUDFReadBlocksRaw
(
m_reader
,
m_pos
, b,
static_cast<
unsigned
char
*
>
(
Buffer
), DVDINPUT_NOFLAGS);
194
if
(ret == -1)
195
{
196
LOG
(VB_GENERAL, LOG_ERR,
LOC
+
"SafeRead DVDReadBlocks error"
);
197
return
ret;
198
}
199
200
m_pos
+=
static_cast<
uint
>
(ret);
201
block -=
static_cast<
uint
>
(ret);
202
if
(it ==
m_blocks
.end())
203
return
ret * DVD_VIDEO_LB_LEN;
204
205
Buffer
=
static_cast<
unsigned
char
*
>
(
Buffer
) + ret * DVD_VIDEO_LB_LEN;
206
}
207
208
b = it->End() -
m_pos
;
209
if
(b > block)
210
b = block;
211
212
// Request new key if change in title
213
int
flags = DVDINPUT_READ_DECRYPT;
214
if
(it->Title() !=
m_title
)
215
{
216
m_title
= it->Title();
217
flags |= DVDCSS_SEEK_KEY;
218
}
219
220
// Read the encrypted blocks
221
int
ret2 =
InternalUDFReadBlocksRaw
(
m_reader
,
m_pos
+
m_start
, b,
static_cast<
unsigned
char
*
>
(
Buffer
), flags);
222
if
(ret2 == -1)
223
{
224
LOG
(VB_GENERAL, LOG_ERR,
LOC
+
"SafeRead DVDReadBlocks error"
);
225
m_title
= -1;
226
return
-1;
227
}
228
229
m_pos
+=
static_cast<
uint
>
(ret2);
230
ret += ret2;
231
block -=
static_cast<
uint
>
(ret2);
232
Buffer
=
static_cast<
unsigned
char
*
>
(
Buffer
) + ret2 * DVD_VIDEO_LB_LEN;
233
234
if
(block > 0 &&
m_start
== 0)
235
{
236
// Read the last unencrypted blocks
237
ret2 =
InternalUDFReadBlocksRaw
(
m_reader
,
m_pos
, block,
static_cast<
unsigned
char
*
>
(
Buffer
), DVDINPUT_NOFLAGS);
238
if
(ret2 == -1)
239
{
240
LOG
(VB_GENERAL, LOG_ERR,
LOC
+
"SafeRead DVDReadBlocks error"
);
241
return
-1;
242
}
243
244
m_pos
+=
static_cast<
uint
>
(ret2);
245
ret += ret2;
246
}
247
248
return
ret * DVD_VIDEO_LB_LEN;
249
}
250
251
long
long
MythDVDStream::SeekInternal
(
long
long
Position,
int
Whence)
252
{
253
if
(!
m_reader
)
254
return
-1;
255
256
if
(SEEK_END == Whence)
257
{
258
errno = EINVAL;
259
return
-1;
260
}
261
262
auto
block =
static_cast<
uint32_t
>
(Position / DVD_VIDEO_LB_LEN);
263
if
(
static_cast<
int64_t
>
(block) * DVD_VIDEO_LB_LEN != Position)
264
{
265
LOG
(VB_GENERAL, LOG_ERR,
LOC
+
"Seek not block aligned"
);
266
return
-1;
267
}
268
269
m_posLock
.lockForWrite();
270
m_pos
= block;
271
m_posLock
.unlock();
272
m_generalWait
.wakeAll();
273
return
Position;
274
}
275
276
long
long
MythDVDStream::GetReadPosition
(
void
)
const
277
{
278
m_posLock
.lockForRead();
279
long
long
ret =
static_cast<
long
long
>
(
m_pos
) * DVD_VIDEO_LB_LEN;
280
m_posLock
.unlock();
281
return
ret;
282
}
mythdvdstream.h
MythDVDStream::BlockRange
Definition:
mythdvdstream.cpp:28
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition:
mthread.cpp:288
root
QDomElement root
Definition:
mythplugins/mytharchive/mytharchivehelper/main.cpp:656
MythDVDStream::SeekInternal
long long SeekInternal(long long Position, int Whence) override
Definition:
mythdvdstream.cpp:251
MythDVDStream::m_title
int m_title
Definition:
mythdvdstream.h:42
title
QString title
Definition:
mythplugins/mytharchive/mytharchivehelper/main.cpp:636
MythDVDStream::~MythDVDStream
~MythDVDStream() override
Definition:
mythdvdstream.cpp:72
Len2Blocks
uint32_t Len2Blocks(uint32_t Length)
Roundup bytes to DVD blocks.
Definition:
mythdvdstream.cpp:60
arg
arg(title).arg(filename).arg(doDelete))
MythMediaBuffer
Definition:
mythmediabuffer.h:49
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition:
mythlogging.h:23
MythMediaBuffer::m_generalWait
QWaitCondition m_generalWait
Condition to signal that the read ahead thread is running.
Definition:
mythmediabuffer.h:236
build_compdb.file
file
Definition:
build_compdb.py:55
MythDVDStream::SafeRead
int SafeRead(void *Buffer, uint Size) override
Definition:
mythdvdstream.cpp:173
MythDVDStream::IsOpen
bool IsOpen(void) const override
Definition:
mythdvdstream.cpp:165
MythDVDStream::BlockRange::m_end
uint32_t m_end
Definition:
mythdvdstream.cpp:49
MythDVDStream::m_reader
dvd_reader_t * m_reader
Definition:
mythdvdstream.h:38
MythDVDStream::m_start
uint32_t m_start
Definition:
mythdvdstream.h:39
InternalUDFReadBlocksRaw
int InternalUDFReadBlocksRaw(dvd_reader_t *device, uint32_t lb_number, size_t block_count, unsigned char *data, int encrypted)
mythlogging.h
MythDVDStream::MythDVDStream
MythDVDStream(const QString &Filename)
Definition:
mythdvdstream.cpp:66
MythDVDStream::BlockRange::BlockRange
BlockRange(uint32_t Start, uint32_t Count, int Title)
Definition:
mythdvdstream.cpp:31
MythDVDStream::BlockRange::m_start
uint32_t m_start
Definition:
mythdvdstream.cpp:48
uint
unsigned int uint
Definition:
compat.h:141
dvd_reader_t
struct dvd_reader_s dvd_reader_t
Definition:
mythdvdstream.h:17
LOC
#define LOC
Definition:
mythdvdstream.cpp:25
MythDVDStream::GetReadPosition
long long GetReadPosition(void) const override
Definition:
mythdvdstream.cpp:276
MythMediaBuffer::KillReadAheadThread
void KillReadAheadThread(void)
Stops the read-ahead thread, and waits for it to stop.
Definition:
mythmediabuffer.cpp:649
Buffer
Definition:
MythExternControl.h:36
MythDVDStream::BlockRange::Title
int Title(void) const
Definition:
mythdvdstream.cpp:45
MythDVDStream::m_pos
uint32_t m_pos
Definition:
mythdvdstream.h:41
MythDVDStream::BlockRange::m_title
int m_title
Definition:
mythdvdstream.cpp:50
MythDVDStream::BlockRange::Start
uint32_t Start(void) const
Definition:
mythdvdstream.cpp:43
MythMediaBuffer::Start
void Start(void)
Starts the read-ahead thread.
Definition:
mythmediabuffer.cpp:613
MythDVDStream::m_blocks
QList< BlockRange > m_blocks
Definition:
mythdvdstream.h:40
kMythBufferFile
@ kMythBufferFile
Definition:
mythmediabuffer.h:41
MythDVDStream::OpenFile
bool OpenFile(const QString &Filename, uint Retry=0) override
Definition:
mythdvdstream.cpp:87
MythMediaBuffer::m_posLock
QReadWriteLock m_posLock
Definition:
mythmediabuffer.h:163
MythDVDStream::BlockRange::End
uint32_t End(void) const
Definition:
mythdvdstream.cpp:44
MythMediaBuffer::m_rwLock
QReadWriteLock m_rwLock
Definition:
mythmediabuffer.h:182
MythDVDStream::BlockRange::operator<
bool operator<(const BlockRange rhs) const
Definition:
mythdvdstream.cpp:38
Generated on Wed Jan 20 2021 03:17:41 for MythTV by
1.8.17