forked from JMS-1/DVB.NET---VCR.NET
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathAdaptor.cs
More file actions
558 lines (472 loc) · 18 KB
/
Adaptor.cs
File metadata and controls
558 lines (472 loc) · 18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
using System;
using System.Text;
using System.Windows.Forms;
using JMS.DVB.DirectShow;
using JMS.DVB.Favorites;
using JMS.DVB.TS.VideoText;
namespace JMS.DVB.Viewer
{
/// <summary>
/// Diese Basisklasse abstrahiert die Quelle eines Transport Streams.
/// </summary>
public abstract class Adaptor : IDisposable
{
/// <summary>
/// Zugehörige Anwendung.
/// </summary>
public readonly IViewerSite Parent;
/// <summary>
/// Gesetzt, während die gespeicherten Vorschlagswerte für Sender und
/// Tonspur geladen werden.
/// </summary>
private bool m_LoadingDefaults = false;
/// <summary>
/// Gesetzt, wenn beim nächsten Aufruf der Programmzeitschrift der aktuelle
/// Eintrag angezeigt werden soll.
/// </summary>
private bool m_ShowCurrentEntry = true;
/// <summary>
/// Aktuelle EPG Informationen.
/// </summary>
private EPG.EventEntry m_CurrentEntry = null;
/// <summary>
/// EPG Informationen zur nächsten Sendung.
/// </summary>
private EPG.EventEntry m_NextEntry = null;
/// <summary>
/// Synchronisiert den Zugriff auf die EPG Informationen.
/// </summary>
private object m_EITLock = new object();
/// <summary>
/// Das Zugriffmodul, über das der Transport Stream in die Anwendung gelenkt wird.
/// </summary>
private AccessModule m_Accessor;
/// <summary>
/// Verwaltet den Videotext.
/// </summary>
private PageManager m_TTX = new PageManager();
/// <summary>
/// Initialisiert eine Verwaltungsinstanz.
/// </summary>
/// <param name="main">Zugehörige Anwendung.</param>
protected Adaptor( IViewerSite main )
{
// Remember
Parent = main;
}
/// <summary>
/// Der Sender, der beim vorherigen Beenden der Anwendung aktiv war.
/// </summary>
protected abstract string DefaultStation { get; }
/// <summary>
/// Die Tonspur, die beim vorherigen Beenden der Anwendungs aktiv war.
/// </summary>
protected abstract string DefaultAudio { get; }
/// <summary>
/// Anzeigename des aktuellen Senders - bei Verwendung von NVOD Diensten
/// handelt es sich um den Namen des Portals.
/// </summary>
protected abstract string StationName { get; }
/// <summary>
/// Wird beim Beenden der zugehörigen Anwendung zur Freigabe aller Ressourcen aufgerufen.
/// </summary>
protected abstract void OnDispose();
/// <summary>
/// Startet eine neue Aufzeichnung.
/// </summary>
public abstract void StartRecording();
/// <summary>
/// Neuen NVOD Dienst auswählen.
/// </summary>
/// <param name="service"></param>
/// <returns>Anzeigename von Dienst und aktiver Tonspue oder <i>null</i>.</returns>
public abstract string SetService( ServiceItem service );
/// <summary>
/// Meldet die Anzahl der aufgezeichneten Bytes.
/// </summary>
public virtual long RecordedBytes { get { return 0; } }
/// <summary>
/// Meldet, ob gerade eine Aufzeichnung läuft.
/// </summary>
public virtual bool IsRecording { get { return false; } }
/// <summary>
/// Neuen Sender auswählen - Tonspur und NVOD Dienst werden auf die
/// Voreinstellung zurück gesetzt.
/// </summary>
/// <param name="context"></param>
/// <returns>Anzeigename von Sender und aktiver Tonspur oder <i>null</i>.</returns>
public abstract string SetStation( object context );
/// <summary>
/// Alle zum aktuellen Portal verfügbaren NVOD Dienste melden.
/// </summary>
public abstract ServiceItem[] Services { get; }
/// <summary>
/// Neue Tonspur auswählen.
/// </summary>
/// <param name="audio">Die gewünschte Tonspur.</param>
/// <returns>Anzeigename von Sender und aktiver Tonspur oder <i>null</i>.</returns>
public abstract string SetAudio( string audio );
/// <summary>
/// Lädt die Senderliste.
/// </summary>
public abstract void LoadStations();
/// <summary>
/// Lädt die Liste der Tonspuren.
/// </summary>
public virtual void LoadTracks()
{
}
/// <summary>
/// Periodischer Aufruf der Anwendung, der zur Prüfung der Funktionsfähigkeit der
/// Transport Stream Quelle genutzt werden kann.
/// </summary>
/// <param name="fine">Gesetzt für den Aufruf im Sekundenrythmus.</param>
public virtual void KeepAlive( bool fine )
{
}
/// <summary>
/// Ergänzt optional zusätzliche Konfigurationsmöglichkeiten.
/// </summary>
/// <remarks>
/// Jeder Eintrag ist von der Art <see cref="OptionDisplay"/>.
/// </remarks>
public virtual void FillOptions()
{
}
/// <summary>
/// Meldet, ob beim Ändern der Direct Show Filter ein Neustart des
/// Graphen unterstützt wird.
/// </summary>
public virtual bool CanRestartGraph { get { return true; } }
/// <summary>
/// Lädt beim Starten der Anwendung den zuletzt verwendeten Sender und die
/// zugehörige Tonspur.
/// </summary>
/// <param name="applicationStart">Gesetzt, wenn die Anwendung gerade startet.</param>
/// <returns>Aktueller Sender mit aktiver tonspur oder <i>null</i>.</returns>
public virtual string LoadDefaults( bool applicationStart )
{
// Load
var station = DefaultStation;
var audio = DefaultAudio;
// Validate
if (string.IsNullOrEmpty( station ))
return null;
// Starting to load defauls
m_LoadingDefaults = true;
try
{
// Select and forward
if (Favorites.SelectChannel( station ))
return SetAudio( audio );
}
finally
{
// Reset
m_LoadingDefaults = false;
}
// Nothing
return null;
}
/// <summary>
/// Meldet, ob die aktuelle Veränderung an Sender und Tonspur zum Laden der
/// Vorgabewerte dient.
/// </summary>
public bool LoadingDefaults { get { return m_LoadingDefaults; } }
/// <summary>
/// Verbindet ein Zugriffsmodul mit dieser Verwaltungsinstanz.
/// </summary>
/// <param name="accessor">Ein Transport Stream Zugriffsmodul.</param>
protected void SetAccessor( AccessModule accessor )
{
// Remember
m_Accessor = accessor;
}
/// <summary>
/// Meldet das aktuelle Zugriffsmodul.
/// </summary>
public AccessModule Accessor { get { return m_Accessor; } }
/// <summary>
/// Zeigt eine Meldung im OSD an.
/// </summary>
/// <param name="message">Die Meldung.</param>
/// <param name="headline">Die Überschrift zur Meldung.</param>
/// <param name="realOSD">Gesetzt, wenn das echte OSD verwendet werden soll.</param>
public void ShowMessage( string message, string headline, bool realOSD )
{
// Forward
Parent.ShowMessage( message, headline, realOSD );
}
/// <summary>
/// Meldet die ktuelle Senderverwaltung.
/// </summary>
public ChannelSelector Favorites { get { return Parent.FavoriteManager; } }
/// <summary>
/// Prüft, ob die EPG Informationen zum aktuellen Sender und der laufenden Sendung
/// gehören und vermerkt diese dann.
/// </summary>
/// <param name="section">Die EPG Informationen.</param>
/// <param name="current">Kennung des aktuellen Senders.</param>
protected void ProcessEPG( EPG.Section section, SourceIdentifier current )
{
// Test station
if (current == null)
return;
// Test section
if (section == null)
return;
if (!section.IsValid)
return;
// Test table
var eit = section.Table as EPG.Tables.EIT;
if (eit == null)
return;
if (!eit.IsValid)
return;
// Test identification
if (current.Service != eit.ServiceIdentifier)
return;
if (current.Network != eit.OriginalNetworkIdentifier)
return;
if (current.TransportStream != eit.TransportStreamIdentifier)
return;
// Check mode
bool gotCurrent = false, gotNext = false;
// Test state
foreach (var entry in eit.Entries)
{
// Check for current entry
if (!gotCurrent)
if (entry.Status == EPG.EventStatus.Running)
{
// Remember
CurrentEntry = entry;
gotCurrent = true;
// Done
if (gotNext)
break;
// Next
continue;
}
// Check for next entry
if (!gotNext)
if (entry.Status == EPG.EventStatus.NotRunning)
{
// Remember
NextEntry = entry;
gotNext = true;
// Done
if (gotCurrent)
break;
}
}
}
/// <summary>
/// Zeigt die aktuellen EPG Informationen an.
/// </summary>
public void ShowEPG()
{
// Try the active entry
var entry = m_ShowCurrentEntry ? CurrentEntry : NextEntry;
if (entry == null)
{
// Switch mode
m_ShowCurrentEntry = !m_ShowCurrentEntry;
// Try the alternate entry
entry = m_ShowCurrentEntry ? CurrentEntry : NextEntry;
if (entry == null)
return;
}
// Switch mode for next call
m_ShowCurrentEntry = !m_ShowCurrentEntry;
// Get data
var start = entry.StartTime.ToLocalTime();
var end = (entry.StartTime + entry.Duration).ToLocalTime();
// Full text
var fulltext = new StringBuilder();
// Title
string name = string.Format( "#{0}", entry.EventIdentifier ), shortText = null;
foreach (var descriptor in entry.Descriptors)
{
// Short
var test = descriptor as EPG.Descriptors.ShortEvent;
if (test != null)
{
// Replace
if (!string.IsNullOrEmpty( test.Name ))
name = test.Name;
if (!string.IsNullOrEmpty( test.Language ))
name = string.Format( "{0} ({1})", name, test.Language );
// Remember
shortText = test.Text;
// Next
continue;
}
// Long
var descr = descriptor as EPG.Descriptors.ExtendedEvent;
if (descr != null)
fulltext.Append( descr.Text );
}
// Create headline
var head = string.Format( "{3}{0:HH:mm}-{1:HH:mm} {2}", start, end, name, m_ShowCurrentEntry ? "* " : string.Empty );
// Get the scratch selection list
var scratch = Parent.ScratchComboBox;
// Clear it
scratch.Items.Clear();
// Show episode and separate
if (SendEPGToList( shortText, scratch ))
if (fulltext.Length > 0)
scratch.Items.Add( " " );
// Show description
SendEPGToList( fulltext.ToString(), scratch );
// Show
Parent.ShowList( head, 0, OSDShowMode.ProgramGuide );
}
/// <summary>
/// Zerlegt eine Zeichenkette in Worte und bildet diese dann auf eine Liste ab.
/// </summary>
/// <param name="data">Die zu zerlegenden Daten.</param>
/// <param name="list">Die Liste, die tatsächlich angezeigt wird.</param>
private bool SendEPGToList( string data, ComboBox list )
{
// Nothing to do
if (string.IsNullOrEmpty( data ))
return false;
// Check size
var count = list.Items.Count;
// Remove CRLF
data = data.Replace( "\r", string.Empty );
// Split in lines
foreach (var line in data.Split( '\n' ))
if (string.IsNullOrEmpty( line ))
list.Items.Add( " " );
else
for (var pos = 0; pos < line.Length; )
{
// Next position
var next = Math.Min( pos + 65, line.Length );
// Find separator backward if the rest doesn't fit
var sep = (next < line.Length) ? line.LastIndexOf( ' ', next - 1, next ) : next;
// Not in range
if (sep < pos)
{
// Find separator forward
sep = line.IndexOf( ' ', next );
// All of it
if (sep < 0)
sep = line.Length;
}
// Get part
if (sep > pos)
list.Items.Add( line.Substring( pos, sep - pos ) );
// Next to process
pos = sep + 1;
}
// At least added one
return (list.Items.Count > 0);
}
/// <summary>
/// Liest oder setzt den aktuellen EPG Eintrag.
/// </summary>
public virtual EPG.EventEntry CurrentEntry
{
get
{
// Report locked
lock (m_EITLock)
return m_CurrentEntry;
}
set
{
// Change locked
lock (m_EITLock)
m_CurrentEntry = value;
}
}
/// <summary>
/// Beim nächsten Aufruf der Programmzeitschrift wird der aktuelle Eintrag angezeigt.
/// </summary>
public void ShowCurrentEntry()
{
// Set flag
m_ShowCurrentEntry = true;
}
/// <summary>
/// Liest oder setzt den EPG Eintrag für die nächste Sendung.
/// </summary>
public virtual EPG.EventEntry NextEntry
{
get
{
// Report locked
lock (m_EITLock)
return m_NextEntry;
}
set
{
// Change locked
lock (m_EITLock)
m_NextEntry = value;
}
}
/// <summary>
/// Meldete die Taste, mit der die Senderliste angezeigt wird.
/// </summary>
public virtual Keys? StationListKey { get { return Keys.K; } }
/// <summary>
/// Meldete die Taste, mit der die Liste der Tonspuren angezeigt wird.
/// </summary>
public virtual Keys? TrackListKey { get { return Keys.L; } }
/// <summary>
/// Meldete die Taste, mit der die Liste der Dienste angezeigt wird.
/// </summary>
public virtual Keys? ServiceListKey { get { return Keys.M; } }
/// <summary>
/// Meldete die Taste, mit der eine Aufzeichnung gestartet oder beendet wird.
/// </summary>
public virtual Keys? RecordingKey { get { return (Keys) 191; } }
/// <summary>
/// Meldet den Text für die Aktion zum Starten und Beenden einer Aufzeichnung.
/// </summary>
public virtual string RecordingText { get { return Properties.Resources.Context_Record; } }
/// <summary>
/// Taste zum an- und abschalten des TimeShift Modus.
/// </summary>
public virtual Keys? TimeShiftKey { get { return null; } }
/// <summary>
/// Meldet die Verwaltungsinstanz der Videotext Seiten.
/// </summary>
public PageManager VideoText { get { return m_TTX; } }
/// <summary>
/// Meldet, ob ein Videotext Signal vorliegt.
/// </summary>
public abstract bool TTXAvailable { get; }
/// <summary>
/// Übermittelt Videotext Daten zur Analyse.
/// </summary>
/// <param name="isStart">Gesetzt, wenn der PES Kopf enthalten ist.</param>
/// <param name="buffer">Speicher für die Videotext Daten.</param>
/// <param name="offset">Position des ersten Bytes der Videotext Daten.</param>
/// <param name="length">Anzahl der Bytes an Videotext Daten.</param>
/// <param name="pts">Aktueller Zeitstempel.</param>
protected void AnalyseVideoText( bool isStart, byte[] buffer, int offset, int length, long pts )
{
// Forward
m_TTX.AddPayload( isStart, buffer, offset, length, pts );
}
#region IDisposable Members
/// <summary>
/// Beendet die Nutzung dieser Verwaltungsinstanz endgültig und gibt alle
/// verbundenen Ressourcen frei.
/// </summary>
public void Dispose()
{
// Cleanup self
using (m_Accessor)
m_Accessor = null;
// Forward
OnDispose();
}
#endregion
}
}