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 {
35  MHPresentable::Initialise(p, engine);
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  MHAudio *pAudio = new MHAudio;
47  m_Multiplex.Append(pAudio);
48  pAudio->Initialise(pItem, engine);
49  }
50  else if (pItem->GetTagNo() == C_VIDEO)
51  {
52  MHVideo *pVideo = new MHVideo;
53  m_Multiplex.Append(pVideo);
54  pVideo->Initialise(pItem, engine);
55  }
56  else if (pItem->GetTagNo() == C_RTGRAPHICS)
57  {
58  MHRTGraphics *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 
86 void 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());
234 }
235 
237 {
238  // StreamCounterUnits (mS)
239  pResult->SetVariableValue((int)engine->GetContext()->GetStreamMaxPos());
240 }
241 
243 {
244  // StreamCounterUnits (mS)
245  engine->GetContext()->SetStreamPos(pos);
246 }
247 
248 void MHStream::SetSpeed(int speed, MHEngine *engine)
249 {
250  engine->GetContext()->StreamPlay(speed != 0);
251 }
252 
254 {
255  MHPresentable::Initialise(p, engine);
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 
271 void 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 
302  if (m_fStreamPlaying)
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
317  if (m_fStreamPlaying)
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 
354 
355  if (pTerm)
356  {
357  m_Termination = (enum Termination)pTerm->GetArgN(0)->GetEnumValue();
358  }
359 }
360 
361 void 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.
395  engine->EventTriggered(this, EventContentAvailable);
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 
420 void 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.
435 void 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.
445 void 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 QRegion();
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);
475  if (m_fStreamPlaying)
477 }
478 
480 {
481  if (! m_fRunning)
482  {
483  return;
484  }
485 
486  MHVisible::Deactivation(engine);
487 
488  if (m_fStreamPlaying)
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 
518 void 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
531  ref.Copy(*m_RefObject.GetReference());
532  CallAction(engine, Target(engine), engine->FindObject(ref));
533 }
Storage
Definition: Stream.h:60
void Destruction(MHEngine *engine) override
Definition: Stream.cpp:138
virtual void StopAudio()=0
void Preparation(MHEngine *engine) override
void ContentPreparation(MHEngine *engine) override
Definition: Stream.cpp:178
MHOwnPtrSequence< MHPresentable > m_Multiplex
Definition: Stream.h:59
int m_nDecodeWidth
Definition: Stream.h:121
enum MHStream::Storage ST_Stream
#define C_RTGRAPHICS
Definition: ASN1Codes.h:130
void PrintMe(FILE *fd, int nTabs) const override
void Deactivation(MHEngine *engine) override
Definition: Stream.cpp:307
virtual long GetStreamMaxPos()=0
int m_nDecodeHeight
Definition: Stream.h:122
#define C_COMPONENT_TAG
Definition: ASN1Codes.h:131
void Preparation(MHEngine *engine) override
Definition: Stream.cpp:118
void Activation(MHEngine *engine) override
Definition: Stream.cpp:149
void Deactivation(MHEngine *engine) override
Definition: Stream.cpp:479
virtual void CallAction(MHEngine *engine, MHRoot *pTarget, MHRoot *pObj)=0
void Activation(MHEngine *engine) override
Definition: Stream.cpp:290
virtual void SetVariableValue(const MHUnion &)
Definition: Root.h:101
virtual MHRoot * FindByObjectNo(int n)
Definition: Root.cpp:115
void Display(MHEngine *) override
Definition: Stream.cpp:399
void Deactivation(MHEngine *engine) override
Definition: Visible.cpp:141
MHRoot * Target(MHEngine *engine)
Definition: BaseActions.cpp:46
void SetCounterPosition(int, MHEngine *) override
Definition: Stream.cpp:242
BASE GetAt(int i) const
Definition: BaseClasses.h:48
virtual void StopVideo()=0
void BeginPlaying(MHEngine *engine) override
Definition: Stream.cpp:325
#define C_ORIGINAL_VOLUME
Definition: ASN1Codes.h:132
void PrintMe(FILE *fd, int nTabs) const override
Definition: Visible.cpp:84
Definition: Stream.h:87
#define C_TERMINATION
Definition: ASN1Codes.h:133
virtual void Activation(MHEngine *engine)
Definition: Root.cpp:69
void Perform(MHEngine *engine) override
Definition: Stream.cpp:525
virtual bool InitiallyActive()
Definition: Ingredients.h:42
int m_nBoxWidth
Definition: Visible.h:79
#define C_VIDEO
Definition: ASN1Codes.h:129
int m_nYDecodeOffset
Definition: Stream.h:120
bool m_fAvailable
Definition: Root.h:207
int m_nOriginalVol
Definition: Stream.h:82
int m_nPosY
Definition: Visible.h:82
virtual void Deactivation(MHEngine *engine)
Definition: Root.cpp:85
void Preparation(MHEngine *engine) override
Definition: Stream.cpp:379
void Copy(const MHObjectRef &objr)
const unsigned char * Bytes() const
Definition: BaseClasses.h:122
void ContentPreparation(MHEngine *engine) override
Definition: Stream.cpp:392
virtual void DrawVideo(const QRect &videoRect, const QRect &displayRect)=0
void StopPlaying(MHEngine *engine) override
Definition: Stream.cpp:332
MHGenericObjectRef m_RefObject
Definition: BaseActions.h:156
MHContext * GetContext()
Definition: Engine.h:153
void StopPlaying(MHEngine *engine) override
Definition: Stream.cpp:501
#define C_AUDIO
Definition: ASN1Codes.h:128
void GetValue(MHObjectRef &ref, MHEngine *engine) const
virtual long GetStreamPos()=0
void Activation(MHEngine *engine) override
Definition: Stream.cpp:467
void Redraw(const QRegion &region)
Definition: Engine.cpp:901
virtual void EndStream()=0
#define C_LOOPING
Definition: ASN1Codes.h:127
void PrintMe(FILE *fd, int nTabs) const override
Definition: Stream.cpp:271
void PrintTabs(FILE *fd, int n)
Definition: ParseNode.cpp:34
void PrintMe(FILE *fd, int nTabs) const override
Definition: Stream.cpp:86
int Size() const
Definition: BaseClasses.h:117
int m_nPosX
Definition: Visible.h:81
void Initialise(MHParseNode *p, MHEngine *engine) override
Definition: Ingredients.cpp:49
void Initialise(MHParseNode *p, MHEngine *engine) override
Definition: Stream.cpp:512
Definition: Stream.h:65
virtual void StopPlaying(MHEngine *)
Definition: Presentable.h:47
int GetIntValue()
Definition: ParseNode.cpp:170
void Initialise(MHParseNode *p, MHEngine *engine) override
Definition: Stream.cpp:253
#define C_STORAGE
Definition: ASN1Codes.h:126
void EventTriggered(MHRoot *pSource, enum EventType ev)
Definition: Engine.h:93
void GetVideoDecodeOffset(MHRoot *pXOffset, MHRoot *pYOffset, MHEngine *) override
Definition: Stream.cpp:445
void Preparation(MHEngine *engine) override
Definition: Visible.cpp:105
MHParseNode * GetNamedArg(int nTag)
Definition: ParseNode.cpp:110
virtual void BeginPlaying(MHEngine *)
Definition: Presentable.h:46
#define C_MULTIPLEX
Definition: ASN1Codes.h:125
void ScaleVideo(int xScale, int yScale, MHEngine *) override
Definition: Stream.cpp:420
void Initialise(MHParseNode *p, MHEngine *engine) override
Definition: Visible.cpp:50
Definition: Root.h:43
void SetVideoDecodeOffset(int newXOffset, int newYOffset, MHEngine *) override
Definition: Stream.cpp:435
int m_nXDecodeOffset
Definition: Stream.h:119
bool m_fRunning
Definition: Root.h:208
MHObjectRef m_ObjectReference
Definition: Root.h:203
void StopPlaying(MHEngine *engine) override
Definition: Stream.cpp:221
int FILE
Definition: mythburn.py:110
int m_nLooping
Definition: Stream.h:61
virtual bool BeginStream(const QString &str, MHStream *notify=nullptr)=0
void Destruction(MHEngine *engine) override
Termination
Definition: Stream.h:117
void Initialise(MHParseNode *p, MHEngine *engine) override
Definition: Stream.cpp:343
bool m_fStreamPlaying
Definition: Stream.h:124
void PrintMe(FILE *fd, int nTabs) const override
Definition: Stream.cpp:518
MHRoot * FindObject(const MHObjectRef &oRef, bool failOnNotFound=true)
Definition: Engine.cpp:575
enum MHVideo::Termination VI_Disappear
int m_nComponentTag
Definition: Stream.h:116
int GetEnumValue()
Definition: ParseNode.cpp:181
#define MHLOG(__level, __text)
Definition: Logging.h:36
void BeginPlaying(MHEngine *engine) override
Definition: Stream.cpp:206
MHOctetString m_ContentRef
Definition: BaseClasses.h:186
int GetArgCount()
Definition: ParseNode.cpp:60
QRegion GetVisibleArea() override
Definition: Stream.cpp:452
void SetSpeed(int, MHEngine *engine) override
Definition: Stream.cpp:248
virtual bool BeginVideo(int tag)=0
void Deactivation(MHEngine *engine) override
Definition: Stream.cpp:165
MHRoot * FindByObjectNo(int n) override
Definition: Stream.cpp:186
void GetCounterMaxPosition(MHRoot *, MHEngine *) override
Definition: Stream.cpp:236
MHParseNode * GetArgN(int n)
Definition: ParseNode.cpp:78
int GetTagNo()
Definition: ParseNode.cpp:49
void Activation(MHEngine *engine) override
Definition: Visible.cpp:128
int m_nComponentTag
Definition: Stream.h:81
bool m_fStreamPlaying
Definition: Stream.h:84
void Append(BASE b)
Definition: BaseClasses.h:62
void Initialise(MHParseNode *p, MHEngine *engine) override
Definition: Stream.cpp:33
void GetCounterPosition(MHRoot *, MHEngine *) override
Definition: Stream.cpp:230
int m_nBoxHeight
Definition: Visible.h:80
int Size() const
Definition: BaseClasses.h:46
virtual long SetStreamPos(long)=0
void BeginPlaying(MHEngine *engine) override
Definition: Stream.cpp:494
virtual bool BeginAudio(int tag)=0
MHContentRef m_ContentRef
Definition: Ingredients.h:78
MHObjectRef * GetReference()
void PrintMe(FILE *fd, int nTabs) const override
Definition: Stream.cpp:361
virtual void StreamPlay(bool play=true)=0