MythTV master
Stream.cpp
Go to the documentation of this file.
1/* Stream.cpp
2
3 Copyright (C) David C. J. Matthews 2004 dm at prolingua.co.uk
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
18 Or, point your browser to http://www.gnu.org/copyleft/gpl.html
19
20*/
21
22#include "Presentable.h"
23#include "Ingredients.h"
24#include "Root.h"
25#include "BaseClasses.h"
26#include "ParseNode.h"
27#include "ASN1Codes.h"
28#include "Engine.h"
29#include "Stream.h"
30#include "freemheg.h"
31
32
34{
36 MHParseNode *pMultiplex = p->GetNamedArg(C_MULTIPLEX);
37
38 if (pMultiplex)
39 {
40 for (int i = 0; i < pMultiplex->GetArgCount(); i++)
41 {
42 MHParseNode *pItem = pMultiplex->GetArgN(i);
43
44 if (pItem->GetTagNo() == C_AUDIO)
45 {
46 auto *pAudio = new MHAudio;
47 m_multiplex.Append(pAudio);
48 pAudio->Initialise(pItem, engine);
49 }
50 else if (pItem->GetTagNo() == C_VIDEO)
51 {
52 auto *pVideo = new MHVideo;
53 m_multiplex.Append(pVideo);
54 pVideo->Initialise(pItem, engine);
55 }
56 else if (pItem->GetTagNo() == C_RTGRAPHICS)
57 {
58 auto *pRtGraph = new MHRTGraphics;
59 m_multiplex.Append(pRtGraph);
60 pRtGraph->Initialise(pItem, engine);
61 }
62 else
63 {
64 // Ignore unknown items
65 MHLOG(MHLogWarning, QString("WARN unknown stream type %1")
66 .arg(pItem->GetTagNo()));
67 }
68 }
69 }
70
71 MHParseNode *pStorage = p->GetNamedArg(C_STORAGE);
72
73 if (pStorage)
74 {
75 m_nStorage = (enum Storage) pStorage->GetArgN(0)->GetEnumValue();
76 }
77
78 MHParseNode *pLooping = p->GetNamedArg(C_LOOPING);
79
80 if (pLooping)
81 {
82 m_nLooping = pLooping->GetArgN(0)->GetIntValue();
83 }
84}
85
86void MHStream::PrintMe(FILE *fd, int nTabs) const
87{
88 PrintTabs(fd, nTabs);
89 fprintf(fd, "{:Stream ");
90 MHPresentable::PrintMe(fd, nTabs + 1);
91 PrintTabs(fd, nTabs + 1);
92 fprintf(fd, ":Multiplex (\n");
93
94 for (int i = 0; i < m_multiplex.Size(); i++)
95 {
96 m_multiplex.GetAt(i)->PrintMe(fd, nTabs + 2);
97 }
98
99 PrintTabs(fd, nTabs + 1);
100 fprintf(fd, " )\n");
101
102 if (m_nStorage != ST_Stream)
103 {
104 PrintTabs(fd, nTabs + 1);
105 fprintf(fd, ":Storage memory\n");
106 }
107
108 if (m_nLooping != 0)
109 {
110 PrintTabs(fd, nTabs + 1);
111 fprintf(fd, ":Looping %d\n", m_nLooping);
112 }
113
114 PrintTabs(fd, nTabs);
115 fprintf(fd, "}\n");
116}
117
119{
120 if (m_fAvailable)
121 {
122 return; // Already prepared
123 }
124
125 for (int i = 0; i < m_multiplex.Size(); i++)
126 {
127 MHPresentable *pItem = m_multiplex.GetAt(i);
128
129 if (pItem->InitiallyActive())
130 {
131 pItem->Activation(engine); // N.B. This will also call Preparation for the components.
132 }
133 }
134
136}
137
139{
140 // Apply Destruction in reverse order.
141 for (int j = m_multiplex.Size(); j > 0; j--)
142 {
143 m_multiplex.GetAt(j - 1)->Destruction(engine);
144 }
145
147}
148
150{
151 if (m_fRunning)
152 {
153 return;
154 }
155
157
158 // Start playing all active stream components.
159 BeginPlaying(engine);
160 // subclasses are responsible for setting m_fRunning and generating IsRunning.
161 m_fRunning = true;
162 engine->EventTriggered(this, EventIsRunning);
163}
164
166{
167 if (! m_fRunning)
168 {
169 return;
170 }
171
173 StopPlaying(engine);
174}
175
176// The MHEG corrigendum allows SetData to be targeted to a stream so
177// the content ref could change while the stream is playing.
179{
180 engine->EventTriggered(this, EventContentAvailable); // Perhaps test for the streams being available?
181 if (m_fRunning)
182 BeginPlaying(engine);
183}
184
185// Return an object if there is a matching component.
187{
189 {
190 return this;
191 }
192
193 for (int i = m_multiplex.Size(); i > 0; i--)
194 {
195 MHRoot *pResult = m_multiplex.GetAt(i - 1)->FindByObjectNo(n);
196
197 if (pResult)
198 {
199 return pResult;
200 }
201 }
202
203 return nullptr;
204}
205
207{
208 QString stream;
210 if (str.Size() != 0) stream = QString::fromUtf8((const char *)str.Bytes(), str.Size());
211 if ( !engine->GetContext()->BeginStream(stream, this))
212 engine->EventTriggered(this, EventEngineEvent, 204); // StreamRefError
213
214 // Start playing all active stream components.
215 for (int i = 0; i < m_multiplex.Size(); i++)
216 m_multiplex.GetAt(i)->BeginPlaying(engine);
217
218 //engine->EventTriggered(this, EventStreamPlaying);
219}
220
222{
223 // Stop playing all active Stream components
224 for (int i = 0; i < m_multiplex.Size(); i++)
225 m_multiplex.GetAt(i)->StopPlaying(engine);
226 engine->GetContext()->EndStream();
227 engine->EventTriggered(this, EventStreamStopped);
228}
229
231{
232 // StreamCounterUnits (mS)
233 pResult->SetVariableValue((int)engine->GetContext()->GetStreamPos().count());
234}
235
237{
238 // StreamCounterUnits (mS)
239 pResult->SetVariableValue((int)engine->GetContext()->GetStreamMaxPos().count());
240}
241
243{
244 // StreamCounterUnits (mS)
245 engine->GetContext()->SetStreamPos(std::chrono::milliseconds(pos));
246}
247
248void MHStream::SetSpeed(int speed, MHEngine *engine)
249{
250 engine->GetContext()->StreamPlay(speed != 0);
251}
252
254{
256 MHParseNode *pComponentTagNode = p->GetNamedArg(C_COMPONENT_TAG);
257
258 if (pComponentTagNode)
259 {
260 m_nComponentTag = pComponentTagNode->GetArgN(0)->GetIntValue();
261 }
262
263 MHParseNode *pOrigVol = p->GetNamedArg(C_ORIGINAL_VOLUME);
264
265 if (pOrigVol)
266 {
267 m_nOriginalVol = pOrigVol->GetIntValue();
268 }
269}
270
271void MHAudio::PrintMe(FILE *fd, int nTabs) const
272{
273 PrintTabs(fd, nTabs);
274 fprintf(fd, "{:Audio ");
275 MHPresentable::PrintMe(fd, nTabs + 1);
276 PrintTabs(fd, nTabs + 1);
277 fprintf(fd, ":ComponentTag %d\n", m_nComponentTag);
278
279 if (m_nOriginalVol != 0)
280 {
281 PrintTabs(fd, nTabs + 1);
282 fprintf(fd, "OriginalVolume %d ", m_nOriginalVol);
283 }
284
285 PrintTabs(fd, nTabs);
286 fprintf(fd, "}\n");
287}
288
289// Activation for Audio is defined in the corrigendum
291{
292 if (m_fRunning)
293 {
294 return;
295 }
296
298 // Beginning presentation is started by the Stream object.
299 m_fRunning = true;
300 engine->EventTriggered(this, EventIsRunning);
301
304}
305
306// Deactivation for Audio is defined in the corrigendum
308{
309 if (! m_fRunning)
310 {
311 return;
312 }
313
314 m_fRunning = false;
315
316 // Stop presenting the audio
318 {
319 engine->GetContext()->StopAudio();
320 }
321
323}
324
326{
327 m_fStreamPlaying = true;
328 if (m_fRunning)
330}
331
333{
334 m_fStreamPlaying = false;
335
336 if (m_fRunning)
337 {
338 engine->GetContext()->StopAudio();
339 }
340}
341
342
344{
345 MHVisible::Initialise(p, engine);
346 MHParseNode *pComponentTagNode = p->GetNamedArg(C_COMPONENT_TAG);
347
348 if (pComponentTagNode)
349 {
350 m_nComponentTag = pComponentTagNode->GetArgN(0)->GetIntValue();
351 }
352
353 MHParseNode *pTerm = p->GetNamedArg(C_TERMINATION);
354
355 if (pTerm)
356 {
357 m_termination = (enum Termination)pTerm->GetArgN(0)->GetEnumValue();
358 }
359}
360
361void MHVideo::PrintMe(FILE *fd, int nTabs) const
362{
363 PrintTabs(fd, nTabs);
364 fprintf(fd, "{:Video ");
365 MHVisible::PrintMe(fd, nTabs + 1);
366 PrintTabs(fd, nTabs + 1);
367 fprintf(fd, ":ComponentTag %d\n", m_nComponentTag);
368
369 if (m_termination != VI_Disappear)
370 {
371 PrintTabs(fd, nTabs + 1);
372 fprintf(fd, "Termination freeze ");
373 }
374
375 PrintTabs(fd, nTabs);
376 fprintf(fd, "}\n");
377}
378
380{
381 if (m_fAvailable)
382 {
383 return; // Already prepared
384 }
385
386 MHVisible::Preparation(engine); // Prepare the base class.
387 // Set up the internal attributes after MHVisible::Preparation.
390}
391
393{
394 // Pretend it's available.
396}
397
398// Display the video.
400{
401 if (! m_fRunning)
402 {
403 return;
404 }
405
406 if (m_nBoxWidth == 0 || m_nBoxHeight == 0)
407 {
408 return; // Can't draw zero sized boxes.
409 }
410
411 // The bounding box is assumed always to be True.
412 // The full screen video is displayed in this rectangle. It is therefore scaled to
413 // m_nDecodeWidth/720 by m_nDecodeHeight/576.
414 QRect videoRect = QRect(m_nPosX + m_nXDecodeOffset, m_nPosY + m_nYDecodeOffset,
416 QRect displayRect = videoRect.intersected(QRect(m_nPosX, m_nPosY, m_nBoxWidth, m_nBoxHeight));
417 engine->GetContext()->DrawVideo(videoRect, displayRect);
418}
419
420void MHVideo::ScaleVideo(int xScale, int yScale, MHEngine *engine)
421{
422 if (xScale == m_nDecodeWidth && yScale == m_nDecodeHeight)
423 {
424 return;
425 }
426
427 QRegion updateArea = GetVisibleArea(); // Redraw the area before the offset
428 m_nDecodeWidth = xScale;
429 m_nDecodeHeight = yScale;
430 updateArea += GetVisibleArea(); // Redraw this bitmap.
431 engine->Redraw(updateArea); // Mark for redrawing
432}
433
434// Added action in UK MHEG.
435void MHVideo::SetVideoDecodeOffset(int newXOffset, int newYOffset, MHEngine *engine)
436{
437 QRegion updateArea = GetVisibleArea(); // Redraw the area before the offset
438 m_nXDecodeOffset = newXOffset;
439 m_nYDecodeOffset = newYOffset;
440 updateArea += GetVisibleArea(); // Redraw the resulting area.
441 engine->Redraw(updateArea); // Mark for redrawing
442}
443
444// Added action in UK MHEG.
445void MHVideo::GetVideoDecodeOffset(MHRoot *pXOffset, MHRoot *pYOffset, MHEngine * /*engine*/)
446{
449}
450
451// Return the region drawn by the bitmap.
453{
454 if (! m_fRunning)
455 {
456 return {};
457 }
458
459 // The visible area is the intersection of the containing box with the, possibly offset,
460 // video.
461 QRegion boxRegion = QRegion(m_nPosX, m_nPosY, m_nBoxWidth, m_nBoxHeight);
462 QRegion videoRegion = QRegion(m_nPosX + m_nXDecodeOffset, m_nPosY + m_nYDecodeOffset,
464 return boxRegion & videoRegion;
465}
466
468{
469 if (m_fRunning)
470 {
471 return;
472 }
473
474 MHVisible::Activation(engine);
477}
478
480{
481 if (! m_fRunning)
482 {
483 return;
484 }
485
487
489 {
490 engine->GetContext()->StopVideo();
491 }
492}
493
495{
496 m_fStreamPlaying = true;
497 if (m_fRunning)
499}
500
502{
503 m_fStreamPlaying = false;
504
505 if (m_fRunning)
506 {
507 engine->GetContext()->StopVideo();
508 }
509}
510
511
513{
514 MHVisible::Initialise(p, engine);
515 //
516}
517
518void MHRTGraphics::PrintMe(FILE *fd, int nTabs) const
519{
520 MHVisible::PrintMe(fd, nTabs);
521 //
522}
523
524// Fix for MHActionGenericObjectRef
526{
527 MHObjectRef ref;
529 m_refObject.GetValue(ref, engine);
530 else
532 CallAction(engine, Target(engine), engine->FindObject(ref));
533}
@ C_COMPONENT_TAG
Definition: ASN1Codes.h:134
@ C_TERMINATION
Definition: ASN1Codes.h:136
@ C_STORAGE
Definition: ASN1Codes.h:129
@ C_ORIGINAL_VOLUME
Definition: ASN1Codes.h:135
@ C_MULTIPLEX
Definition: ASN1Codes.h:128
@ C_LOOPING
Definition: ASN1Codes.h:130
@ C_AUDIO
Definition: ASN1Codes.h:131
@ C_VIDEO
Definition: ASN1Codes.h:132
@ C_RTGRAPHICS
Definition: ASN1Codes.h:133
#define MHLOG(__level, __text)
Definition: Logging.h:36
void PrintTabs(FILE *fd, int n)
Definition: ParseNode.cpp:34
@ EventIsRunning
Definition: Root.h:34
@ EventStreamStopped
Definition: Root.h:36
@ EventEngineEvent
Definition: Root.h:40
@ EventContentAvailable
Definition: Root.h:34
void Perform(MHEngine *engine) override
Definition: Stream.cpp:525
virtual void CallAction(MHEngine *engine, MHRoot *pTarget, MHRoot *pObj)=0
MHGenericObjectRef m_refObject
Definition: BaseActions.h:156
Definition: Stream.h:67
int m_nOriginalVol
Definition: Stream.h:83
void BeginPlaying(MHEngine *engine) override
Definition: Stream.cpp:325
void Deactivation(MHEngine *engine) override
Definition: Stream.cpp:307
void Initialise(MHParseNode *p, MHEngine *engine) override
Definition: Stream.cpp:253
bool m_fStreamPlaying
Definition: Stream.h:85
void PrintMe(FILE *fd, int nTabs) const override
Definition: Stream.cpp:271
int m_nComponentTag
Definition: Stream.h:82
void StopPlaying(MHEngine *engine) override
Definition: Stream.cpp:332
void Activation(MHEngine *engine) override
Definition: Stream.cpp:290
MHOctetString m_contentRef
Definition: BaseClasses.h:189
virtual std::chrono::milliseconds GetStreamPos()=0
virtual void StopAudio()=0
virtual void DrawVideo(const QRect &videoRect, const QRect &displayRect)=0
virtual void StopVideo()=0
virtual std::chrono::milliseconds GetStreamMaxPos()=0
virtual bool BeginStream(const QString &str, MHStream *notify=nullptr)=0
virtual bool BeginAudio(int tag)=0
virtual bool BeginVideo(int tag)=0
virtual std::chrono::milliseconds SetStreamPos(std::chrono::milliseconds)=0
virtual void EndStream()=0
virtual void StreamPlay(bool play=true)=0
MHRoot * Target(MHEngine *engine)
Definition: BaseActions.cpp:46
void Redraw(const QRegion &region)
Definition: Engine.cpp:926
MHRoot * FindObject(const MHObjectRef &oRef, bool failOnNotFound=true)
Definition: Engine.cpp:574
MHContext * GetContext()
Definition: Engine.h:154
void EventTriggered(MHRoot *pSource, enum EventType ev)
Definition: Engine.h:94
MHObjectRef * GetReference()
void GetValue(MHObjectRef &ref, MHEngine *engine) const
void Destruction(MHEngine *engine) override
MHContentRef m_contentRef
Definition: Ingredients.h:78
void Preparation(MHEngine *engine) override
void Initialise(MHParseNode *p, MHEngine *engine) override
Definition: Ingredients.cpp:50
void PrintMe(FILE *fd, int nTabs) const override
virtual bool InitiallyActive()
Definition: Ingredients.h:42
void Copy(const MHObjectRef &objr)
const unsigned char * Bytes() const
Definition: BaseClasses.h:125
int Size() const
Definition: BaseClasses.h:120
MHParseNode * GetArgN(int n)
Definition: ParseNode.cpp:78
int GetEnumValue()
Definition: ParseNode.cpp:181
int GetArgCount()
Definition: ParseNode.cpp:60
int GetTagNo()
Definition: ParseNode.cpp:49
int GetIntValue()
Definition: ParseNode.cpp:170
virtual void StopPlaying(MHEngine *)
Definition: Presentable.h:47
virtual void BeginPlaying(MHEngine *)
Definition: Presentable.h:46
void Initialise(MHParseNode *p, MHEngine *engine) override
Definition: Stream.cpp:512
void PrintMe(FILE *fd, int nTabs) const override
Definition: Stream.cpp:518
Definition: Root.h:45
virtual void Activation(MHEngine *engine)
Definition: Root.cpp:70
MHObjectRef m_ObjectReference
Definition: Root.h:248
virtual void Deactivation(MHEngine *engine)
Definition: Root.cpp:86
bool m_fRunning
Definition: Root.h:253
bool m_fAvailable
Definition: Root.h:252
virtual MHRoot * FindByObjectNo(int n)
Definition: Root.cpp:116
virtual void SetVariableValue(const MHUnion &)
Definition: Root.h:109
int Size() const
Definition: BaseClasses.h:47
void Append(BASE b)
Definition: BaseClasses.h:64
BASE GetAt(int i) const
Definition: BaseClasses.h:49
void ContentPreparation(MHEngine *engine) override
Definition: Stream.cpp:178
void SetCounterPosition(int, MHEngine *engine) override
Definition: Stream.cpp:242
Storage
Definition: Stream.h:61
void SetSpeed(int speed, MHEngine *engine) override
Definition: Stream.cpp:248
void PrintMe(FILE *fd, int nTabs) const override
Definition: Stream.cpp:86
MHOwnPtrSequence< MHPresentable > m_multiplex
Definition: Stream.h:59
int m_nLooping
Definition: Stream.h:62
void Activation(MHEngine *engine) override
Definition: Stream.cpp:149
void GetCounterMaxPosition(MHRoot *pResult, MHEngine *engine) override
Definition: Stream.cpp:236
void Deactivation(MHEngine *engine) override
Definition: Stream.cpp:165
MHRoot * FindByObjectNo(int n) override
Definition: Stream.cpp:186
void Preparation(MHEngine *engine) override
Definition: Stream.cpp:118
enum MHStream::Storage ST_Stream
void Initialise(MHParseNode *p, MHEngine *engine) override
Definition: Stream.cpp:33
void Destruction(MHEngine *engine) override
Definition: Stream.cpp:138
void GetCounterPosition(MHRoot *pResult, MHEngine *engine) override
Definition: Stream.cpp:230
void StopPlaying(MHEngine *engine) override
Definition: Stream.cpp:221
void BeginPlaying(MHEngine *engine) override
Definition: Stream.cpp:206
Definition: Stream.h:89
enum MHVideo::Termination VI_Disappear
Termination
Definition: Stream.h:119
bool m_fStreamPlaying
Definition: Stream.h:126
void BeginPlaying(MHEngine *engine) override
Definition: Stream.cpp:494
void Deactivation(MHEngine *engine) override
Definition: Stream.cpp:479
int m_nDecodeHeight
Definition: Stream.h:124
void Display(MHEngine *engine) override
Definition: Stream.cpp:399
void Preparation(MHEngine *engine) override
Definition: Stream.cpp:379
int m_nYDecodeOffset
Definition: Stream.h:122
void Initialise(MHParseNode *p, MHEngine *engine) override
Definition: Stream.cpp:343
int m_nXDecodeOffset
Definition: Stream.h:121
void StopPlaying(MHEngine *engine) override
Definition: Stream.cpp:501
void PrintMe(FILE *fd, int nTabs) const override
Definition: Stream.cpp:361
int m_nComponentTag
Definition: Stream.h:117
QRegion GetVisibleArea() override
Definition: Stream.cpp:452
void Activation(MHEngine *engine) override
Definition: Stream.cpp:467
void SetVideoDecodeOffset(int newXOffset, int newYOffset, MHEngine *engine) override
Definition: Stream.cpp:435
int m_nDecodeWidth
Definition: Stream.h:123
void ScaleVideo(int xScale, int yScale, MHEngine *engine) override
Definition: Stream.cpp:420
void ContentPreparation(MHEngine *engine) override
Definition: Stream.cpp:392
void GetVideoDecodeOffset(MHRoot *pXOffset, MHRoot *pYOffset, MHEngine *engine) override
Definition: Stream.cpp:445
void Deactivation(MHEngine *engine) override
Definition: Visible.cpp:147
void PrintMe(FILE *fd, int nTabs) const override
Definition: Visible.cpp:90
int m_nBoxWidth
Definition: Visible.h:79
int m_nBoxHeight
Definition: Visible.h:80
void Activation(MHEngine *engine) override
Definition: Visible.cpp:134
void Initialise(MHParseNode *p, MHEngine *engine) override
Definition: Visible.cpp:56
int m_nPosY
Definition: Visible.h:82
void Preparation(MHEngine *engine) override
Definition: Visible.cpp:111
int m_nPosX
Definition: Visible.h:81
@ MHLogWarning
Definition: freemheg.h:78
int FILE
Definition: mythburn.py:137