1/*
2 * Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de>
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify,
8 * merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26#include <fcntl.h>
27#include <malloc.h>
28#include <math.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <sys/uio.h>
33#include <unistd.h>
34
35#include <MediaRoster.h>
36#include <Buffer.h>
37#include <BufferGroup.h>
38#include <ParameterWeb.h>
39#include <TimeSource.h>
40#include <String.h>
41#include <Autolock.h>
42#include <Debug.h>
43
44#include <Directory.h>
45#include <Entry.h>
46#include <Path.h>
47
48#include "MediaFormat.h"
49#include "Packet.h"
50#include "PacketQueue.h"
51#include "pes.h"
52#include "media_header_ex.h"
53#include "config.h"
54
55//#define DUMP_VIDEO
56//#define DUMP_AUDIO
57//#define DUMP_RAW_AUDIO
58
59
60#include "DVBMediaNode.h"
61
62#define ENABLE_TRACE
63//#define ENABLE_TRACE_TIMING
64
65#undef TRACE
66
67#ifdef ENABLE_TRACE
68	#define TRACE printf
69#else
70	#define TRACE(a...)
71#endif
72
73#ifdef ENABLE_TRACE_TIMING
74	#define TRACE_TIMING printf
75#else
76	#define TRACE_TIMING(a...)
77#endif
78
79#define RETURN_IF_ERROR(expr) { status_t e = (expr); if (e != B_OK) return e; }
80
81#define ID_RAW_VIDEO	0
82#define ID_RAW_AUDIO	1
83#define ID_ENC_VIDEO	2
84#define ID_ENC_AUDIO	3
85#define ID_TS			4
86
87// Timeouts for requesting buffers, if the system is busy,
88// the output buffer queue is full, requesting a buffer will
89// timeout, and we need to drop the current data
90#define VIDEO_BUFFER_REQUEST_TIMEOUT	20000
91#define AUDIO_BUFFER_REQUEST_TIMEOUT	10000
92
93// DVB data arrives early and with a timestamp, this is used to validate
94// that the timestamp is correct and we don't get stuck
95#define VIDEO_MAX_EARLY					3000000	// up to 3 seconds too early
96#define VIDEO_MAX_LATE					50000	// no more than 50 ms too late
97#define AUDIO_MAX_EARLY					3000000	// up to 3 seconds too early
98#define AUDIO_MAX_LATE					50000	// no more than 50 ms too late
99
100#define PROCESSING_LATENCY				1500	// assumed latency for sending the buffer
101
102#define STOP_CAPTURE_WHILE_TUNING		1
103
104#define MPEG2_VIDEO_DECODER_PATH		"/boot/home/config/add-ons/media/dvb/video_decoder_addon"
105#define MPEG2_AUDIO_DECODER_PATH		"/boot/home/config/add-ons/media/dvb/audio_decoder_addon"
106#define AC3_AUDIO_DECODER_PATH			"/boot/home/config/add-ons/media/dvb/ac3_decoder_addon"
107#define DEINTERLACE_FILTER_PATH			"/boot/home/config/add-ons/media/dvb/deinterlace_filter_addon"
108
109
110#define M_REFRESH_PARAMETER_WEB 		(BTimedEventQueue::B_USER_EVENT + 1)
111
112
113DVBMediaNode::DVBMediaNode(
114	BMediaAddOn *addon, const char *name,
115	int32 internal_id, DVBCard *card)
116 :	BMediaNode(name)
117 ,	BBufferProducer(B_MEDIA_RAW_VIDEO)
118 ,	BControllable()
119 ,	BMediaEventLooper()
120 ,	fStopDisabled(false)
121 ,	fOutputEnabledRawVideo(false)
122 ,	fOutputEnabledRawAudio(false)
123 ,	fOutputEnabledEncVideo(false)
124 ,	fOutputEnabledEncAudio(false)
125 ,	fOutputEnabledTS(false)
126 ,	fCardDataQueue(new PacketQueue(6))
127 ,	fRawVideoQueue(new PacketQueue(56))
128 ,	fRawAudioQueue(new PacketQueue(56))
129 ,	fEncVideoQueue(new PacketQueue(56))
130 ,	fEncAudioQueue(new PacketQueue(56))
131 ,	fMpegTsQueue(new PacketQueue(16))
132 ,	fCard(card)
133 ,	fCaptureThreadsActive(false)
134 ,	fThreadIdCardReader(-1)
135 ,	fThreadIdMpegDemux(-1)
136 ,	fThreadIdRawAudio(-1)
137 ,	fThreadIdRawVideo(-1)
138 ,	fThreadIdEncAudio(-1)
139 ,	fThreadIdEncVideo(-1)
140 ,	fThreadIdMpegTS(-1)
141 ,	fTerminateThreads(false)
142 ,	fDemux(new TransportStreamDemux(fRawVideoQueue, fRawAudioQueue,
143 		fEncVideoQueue, fEncAudioQueue, fMpegTsQueue))
144 ,	fBufferGroupRawVideo(0)
145 ,	fBufferGroupRawAudio(0)
146 ,	fInterfaceType(DVB_TYPE_UNKNOWN)
147 ,	fAudioPid(-1)
148 ,	fVideoPid(-1)
149 ,	fPcrPid(-1)
150 ,	fTuningSuccess(false)
151 ,	fCaptureActive(false)
152 ,	fVideoDelaySem(create_sem(0, "video delay sem"))
153 ,	fAudioDelaySem(create_sem(0, "audio delay sem"))
154 ,	fSelectedState(-1)
155 ,	fSelectedRegion(-1)
156 ,	fSelectedChannel(-1)
157 ,	fSelectedAudio(-1)
158 ,	fStateList(new StringList)
159 ,	fRegionList(new StringList)
160 ,	fChannelList(new StringList)
161 ,	fAudioList(new StringList)
162 ,	fVideoDecoder(0)
163 ,	fAudioDecoder(0)
164 ,	fCurrentVideoPacket(0)
165 ,	fCurrentAudioPacket(0)
166{
167	TRACE("DVBMediaNode::DVBMediaNode\n");
168
169	AddNodeKind(B_PHYSICAL_INPUT);
170
171	fInternalID = internal_id;
172	fAddOn = addon;
173
174	fInitStatus = B_OK;
175
176	InitDefaultFormats();
177
178	// in the beginning, the required formats are the same as the defaults
179	fRequiredFormatRawVideo = fDefaultFormatRawVideo;
180	fRequiredFormatRawAudio = fDefaultFormatRawAudio;
181	fRequiredFormatEncVideo = fDefaultFormatEncVideo;
182	fRequiredFormatEncAudio = fDefaultFormatEncAudio;
183	fRequiredFormatTS = fDefaultFormatTS;
184
185	// start the BMediaEventLooper control loop running
186	Run();
187
188	TRACE("current RunMode = %d\n", RunMode());
189
190#ifdef DUMP_VIDEO
191	fVideoFile = open("/boot/home/dvb-video.mpg", O_RDWR | O_CREAT | O_TRUNC);
192#endif
193#ifdef DUMP_AUDIO
194	fAudioFile = open("/boot/home/dvb-audio.mpg", O_RDWR | O_CREAT | O_TRUNC);
195#endif
196#ifdef DUMP_RAW_AUDIO
197	fRawAudioFile = open("/boot/home/dvb-audio.raw", O_RDWR | O_CREAT | O_TRUNC);
198#endif
199}
200
201
202DVBMediaNode::~DVBMediaNode()
203{
204	TRACE("DVBMediaNode::~DVBMediaNode\n");
205
206	StopCapture();
207
208	delete_sem(fVideoDelaySem);
209	delete_sem(fAudioDelaySem);
210
211	// fCard is owned by the media addon
212	delete fCardDataQueue;
213	delete fRawVideoQueue;
214	delete fRawAudioQueue;
215	delete fEncVideoQueue;
216	delete fEncAudioQueue;
217	delete fMpegTsQueue;
218
219	delete fDemux;
220
221	delete fBufferGroupRawVideo;
222	delete fBufferGroupRawAudio;
223
224	delete fStateList;
225	delete fRegionList;
226	delete fChannelList;
227	delete fAudioList;
228
229#ifdef DUMP_VIDEO
230	close(fVideoFile);
231#endif
232#ifdef DUMP_AUDIO
233	close(fAudioFile);
234#endif
235#ifdef DUMP_RAW_AUDIO
236	close(fRawAudioFile);
237#endif
238
239}
240
241
242/* BMediaNode */
243
244
245BMediaAddOn *
246DVBMediaNode::AddOn(int32 *internal_id) const
247{
248	if (internal_id)
249		*internal_id = fInternalID;
250	return fAddOn;
251}
252
253
254status_t
255DVBMediaNode::HandleMessage(int32 message, const void *data, size_t size)
256{
257	return B_ERROR;
258}
259
260
261void
262DVBMediaNode::Preroll()
263{
264	/* This hook may be called before the node is started to give the hardware
265	 * a chance to start. */
266}
267
268
269void
270DVBMediaNode::SetTimeSource(BTimeSource *time_source)
271{
272	TRACE("DVBMediaNode::SetTimeSource\n");
273	//printf("current RunMode = %d\n", RunMode());
274	//printf("_m_recordDelay = %Ld\n", _m_recordDelay);
275}
276
277
278void
279DVBMediaNode::SetRunMode(run_mode mode)
280{
281	TRACE("DVBMediaNode::SetRunMode: %d\n", mode);
282	TRACE("current RunMode = %d\n", RunMode());
283	//printf("_m_recordDelay = %Ld\n", _m_recordDelay);
284}
285
286
287/* BMediaEventLooper */
288
289
290void
291DVBMediaNode::NodeRegistered()
292{
293	TRACE("DVBMediaNode::NodeRegistered\n");
294
295	fOutputRawVideo.node = Node();
296	fOutputRawVideo.source.port = ControlPort();
297	fOutputRawVideo.source.id = ID_RAW_VIDEO;
298	fOutputRawVideo.destination = media_destination::null;
299	fOutputRawVideo.format = fDefaultFormatRawVideo;
300	strcpy(fOutputRawVideo.name, SourceDefaultName(fOutputRawVideo.source));
301
302	fOutputRawAudio.node = Node();
303	fOutputRawAudio.source.port = ControlPort();
304	fOutputRawAudio.source.id = ID_RAW_AUDIO;
305	fOutputRawAudio.destination = media_destination::null;
306	fOutputRawAudio.format = fDefaultFormatRawAudio;
307	strcpy(fOutputRawAudio.name, SourceDefaultName(fOutputRawAudio.source));
308
309	fOutputEncVideo.node = Node();
310	fOutputEncVideo.source.port = ControlPort();
311	fOutputEncVideo.source.id = ID_ENC_VIDEO;
312	fOutputEncVideo.destination = media_destination::null;
313	fOutputEncVideo.format = fDefaultFormatEncVideo;
314	strcpy(fOutputEncVideo.name, SourceDefaultName(fOutputEncVideo.source));
315
316	fOutputEncAudio.node = Node();
317	fOutputEncAudio.source.port = ControlPort();
318	fOutputEncAudio.source.id = ID_ENC_AUDIO;
319	fOutputEncAudio.destination = media_destination::null;
320	fOutputEncAudio.format = fDefaultFormatEncAudio;
321	strcpy(fOutputEncAudio.name, SourceDefaultName(fOutputEncAudio.source));
322
323	fOutputTS.node = Node();
324	fOutputTS.source.port = ControlPort();
325	fOutputTS.source.id = ID_TS;
326	fOutputTS.destination = media_destination::null;
327	fOutputTS.format = fDefaultFormatTS;
328	strcpy(fOutputTS.name, SourceDefaultName(fOutputTS.source));
329
330	fCard->GetCardType(&fInterfaceType);
331
332	// set control thread priority
333	SetPriority(110);
334
335	LoadSettings();
336
337	RefreshParameterWeb();
338
339	// this nodes operates in recording mode, so set it (will be done asynchronously)
340	BMediaRoster::Roster()->SetRunModeNode(Node(), B_RECORDING);
341	// as it's a notification hook, calling this doesn't work: SetRunMode(B_RECORDING);
342
343	//printf("RunMode = %d\n", RunMode());
344	//printf("_m_recordDelay = %Ld\n", _m_recordDelay);
345}
346
347
348void
349DVBMediaNode::Stop(bigtime_t performance_time, bool immediate)
350{
351	if (fStopDisabled)
352		return;
353	else
354		BMediaEventLooper::Stop(performance_time, immediate);
355}
356
357
358void
359DVBMediaNode::HandleEvent(const media_timed_event *event,
360		bigtime_t lateness, bool realTimeEvent)
361{
362
363	switch(event->type)
364	{
365		case M_REFRESH_PARAMETER_WEB:
366			RefreshParameterWeb();
367			break;
368		case BTimedEventQueue::B_START:
369			HandleStart(event->event_time);
370			break;
371		case BTimedEventQueue::B_STOP:
372			HandleStop();
373			break;
374		case BTimedEventQueue::B_WARP:
375			HandleTimeWarp(event->bigdata);
376			break;
377		case BTimedEventQueue::B_SEEK:
378			HandleSeek(event->bigdata);
379			break;
380		case BTimedEventQueue::B_HANDLE_BUFFER:
381		case BTimedEventQueue::B_DATA_STATUS:
382		case BTimedEventQueue::B_PARAMETER:
383		default:
384			TRACE("DVBMediaNode::HandleEvent: Unhandled event -- %lx\n", event->type);
385			break;
386	}
387}
388
389
390/* BBufferProducer */
391
392
393status_t
394DVBMediaNode::FormatChangeRequested(const media_source &source,
395		const media_destination &destination, media_format *io_format,
396		int32 *_deprecated_)
397{
398	TRACE("DVBMediaNode::FormatChangeRequested denied: %s\n", SourceDefaultName(source));
399	return B_ERROR;
400}
401
402
403status_t
404DVBMediaNode::GetNextOutput(int32 *cookie, media_output *out_output)
405{
406	switch (*cookie) {
407		case 0: *out_output = fOutputRawVideo;	break;
408		case 1: *out_output = fOutputRawAudio;	break;
409		case 2: *out_output = fOutputEncVideo;	break;
410		case 3: *out_output = fOutputEncAudio;	break;
411		case 4: *out_output = fOutputTS;		break;
412		default:								return B_BAD_INDEX;
413	}
414
415	(*cookie) += 1;
416	return B_OK;
417}
418
419
420status_t
421DVBMediaNode::DisposeOutputCookie(int32 cookie)
422{
423	return B_OK;
424}
425
426
427status_t
428DVBMediaNode::SetBufferGroup(const media_source &source, BBufferGroup *group)
429{
430	TRACE("DVBMediaNode::SetBufferGroup denied: %s\n", SourceDefaultName(source));
431	return B_ERROR;
432}
433
434
435status_t
436DVBMediaNode::VideoClippingChanged(const media_source &for_source,
437		int16 num_shorts, int16 *clip_data,
438		const media_video_display_info &display, int32 *_deprecated_)
439{
440	return B_ERROR;
441}
442
443
444status_t
445DVBMediaNode::GetLatency(bigtime_t *out_latency)
446{
447	if (B_OK != BBufferProducer::GetLatency(out_latency))
448		*out_latency = 50000;
449
450	printf("DVBMediaNode::GetLatency: %Ld\n", *out_latency);
451	*out_latency += PROCESSING_LATENCY;
452	return B_OK;
453}
454
455
456status_t
457DVBMediaNode::FormatSuggestionRequested(
458		media_type type, int32 quality, media_format *format)
459{
460	TRACE("DVBMediaNode::FormatSuggestionRequested\n");
461
462	switch (type) {
463		case B_MEDIA_RAW_VIDEO: 	*format = fDefaultFormatRawVideo; break;
464		case B_MEDIA_RAW_AUDIO: 	*format = fDefaultFormatRawAudio; break;
465		case B_MEDIA_ENCODED_VIDEO:	*format = fDefaultFormatEncVideo; break;
466		case B_MEDIA_ENCODED_AUDIO:	*format = fDefaultFormatEncAudio; break;
467		case B_MEDIA_MULTISTREAM:	*format = fDefaultFormatTS;		  break;
468		default: TRACE("Bad type!\n");								  return B_MEDIA_BAD_FORMAT;
469	}
470
471	#ifdef DEBUG
472		TRACE("suggested format: ");
473		PrintFormat(*format);
474	#endif
475
476	return B_OK;
477}
478
479
480status_t
481DVBMediaNode::FormatProposal(const media_source &source, media_format *format)
482{
483	TRACE("DVBMediaNode::FormatProposal: %s\n", SourceDefaultName(source));
484
485	/* The connection process:
486	 * we are here => BBufferProducer::FormatProposal
487	 *                BBufferConsumer::AcceptFormat
488	 *                BBufferProducer::PrepareToConnect
489	 *                BBufferConsumer::Connected
490	 *                BBufferProducer::Connect
491	 *
492	 * What we need to do:
493	 * - if the format contains a wildcard AND we have a requirement for that
494	 *   field, set it to the value we need.
495	 * - if a field has a value that is not wildcard and not supported by us,
496	 *   we don't change it, and return B_MEDIA_BAD_FORMAT
497	 * - after we are done, the format may still contain wildcards.
498	 */
499
500	if (source.port != ControlPort())
501		goto _bad_source;
502
503	#ifdef DEBUG
504		TRACE("proposed format: ");
505		PrintFormat(*format);
506		TRACE("required format: ");
507		switch (source.id) {
508			case ID_RAW_VIDEO: PrintFormat(fRequiredFormatRawVideo); break;
509			case ID_RAW_AUDIO: PrintFormat(fRequiredFormatRawAudio); break;
510			case ID_ENC_VIDEO: PrintFormat(fRequiredFormatEncVideo); break;
511			case ID_ENC_AUDIO: PrintFormat(fRequiredFormatEncAudio); break;
512			case ID_TS:        PrintFormat(fRequiredFormatTS); break;
513		}
514	#endif
515
516	switch (source.id) {
517		case ID_RAW_VIDEO:
518			// check if destination still available
519			if (fOutputRawVideo.destination != media_destination::null)
520				goto _bad_source;
521			// set requirements and check if compatible
522			color_space c;
523			c = format->u.raw_video.display.format;
524			format->SpecializeTo(&fRequiredFormatRawVideo);
525			format->u.raw_video.display.format = c;
526//			if (!format->Matches(&fRequiredFormatRawVideo))
527//				goto _bad_format_1;
528			if (!VerifyFormatRawVideo(format->u.raw_video))
529				goto _bad_format_2;
530			break;
531
532		case ID_RAW_AUDIO:
533			// check if destination still available
534			if (fOutputRawAudio.destination != media_destination::null)
535				goto _bad_source;
536			// set requirements and check if compatible
537			format->SpecializeTo(&fRequiredFormatRawAudio);
538			if (!format->Matches(&fRequiredFormatRawAudio))
539				goto _bad_format_1;
540			if (!VerifyFormatRawAudio(format->u.raw_audio))
541				goto _bad_format_2;
542			break;
543
544		case ID_ENC_VIDEO:
545			// check if destination still available
546			if (fOutputEncVideo.destination != media_destination::null)
547				goto _bad_source;
548			// set requirements and check if compatible
549			format->SpecializeTo(&fRequiredFormatEncVideo);
550			if (!format->Matches(&fRequiredFormatEncVideo))
551				goto _bad_format_1;
552			break;
553
554		case ID_ENC_AUDIO:
555			// check if destination still available
556			if (fOutputEncAudio.destination != media_destination::null)
557				goto _bad_source;
558			// set requirements and check if compatible
559			format->SpecializeTo(&fRequiredFormatEncAudio);
560			if (!format->Matches(&fRequiredFormatEncAudio))
561				goto _bad_format_1;
562			break;
563
564		case ID_TS:
565			// check if destination still available
566			if (fOutputTS.destination != media_destination::null)
567				goto _bad_source;
568			// set requirements and check if compatible
569			format->SpecializeTo(&fRequiredFormatTS);
570			if (!format->Matches(&fRequiredFormatTS))
571				goto _bad_format_1;
572			break;
573
574		default:
575			goto _bad_source;
576	}
577
578	#ifdef DEBUG
579		TRACE("final format: ");
580		PrintFormat(*format);
581	#endif
582
583	return B_OK;
584
585_bad_source:
586	TRACE("Error: bad source!\n");
587	return B_MEDIA_BAD_SOURCE;
588
589_bad_format_1:
590	TRACE("Error, bad format (1): ");
591	goto _bad_format;
592
593_bad_format_2:
594	TRACE("Error, bad format (2): ");
595	goto _bad_format;
596
597_bad_format:
598	#ifdef DEBUG
599		PrintFormat(*format);
600	#endif
601	return B_MEDIA_BAD_FORMAT;
602}
603
604
605status_t
606DVBMediaNode::PrepareToConnect(const media_source &source,
607		const media_destination &destination, media_format *format,
608		media_source *out_source, char *out_name)
609{
610	/* The connection process:
611	 *                BBufferProducer::FormatProposal
612	 *                BBufferConsumer::AcceptFormat
613	 * we are here => BBufferProducer::PrepareToConnect
614	 *                BBufferConsumer::Connected
615	 *                BBufferProducer::Connect
616	 *
617	 * At this point, the consumer's AcceptFormat() method has been called,
618	 * and that node has potentially changed the proposed format. It may
619	 * also have left wildcards in the format. PrepareToConnect()
620	 * *must* fully specialize the format before returning!
621	 */
622
623	TRACE("DVBMediaNode::PrepareToConnect: %s\n", SourceDefaultName(source));
624
625	#ifdef DEBUG
626		TRACE("connecting format: ");
627		PrintFormat(*format);
628		TRACE("required format: ");
629		switch (source.id) {
630			case ID_RAW_VIDEO: PrintFormat(fRequiredFormatRawVideo); break;
631			case ID_RAW_AUDIO: PrintFormat(fRequiredFormatRawAudio); break;
632			case ID_ENC_VIDEO: PrintFormat(fRequiredFormatEncVideo); break;
633			case ID_ENC_AUDIO: PrintFormat(fRequiredFormatEncAudio); break;
634			case ID_TS:        PrintFormat(fRequiredFormatTS); break;
635		}
636	#endif
637
638	// is the source valid?
639	if (source.port != ControlPort())
640		goto _bad_source;
641
642	// 1) check if the output is still available,
643	// 2) specialize and verify the format
644	switch (source.id) {
645		case ID_RAW_VIDEO:
646			if (fOutputRawVideo.destination != media_destination::null)
647				goto _already_connected;
648			SpecializeFormatRawVideo(&format->u.raw_video);
649//			if (!format->Matches(&fRequiredFormatRawVideo))
650//				goto _bad_format;
651			if (!VerifyFormatRawVideo(format->u.raw_video))
652				goto _bad_format;
653			break;
654
655		case ID_RAW_AUDIO:
656			if (fOutputRawAudio.destination != media_destination::null)
657				goto _already_connected;
658			SpecializeFormatRawAudio(&format->u.raw_audio);
659			if (!format->Matches(&fRequiredFormatRawAudio))
660				goto _bad_format;
661			if (!VerifyFormatRawAudio(format->u.raw_audio))
662				goto _bad_format;
663			break;
664
665		case ID_ENC_VIDEO:
666			if (fOutputEncVideo.destination != media_destination::null)
667				goto _already_connected;
668			SpecializeFormatEncVideo(&format->u.encoded_video);
669			if (!format->Matches(&fRequiredFormatEncVideo))
670				goto _bad_format;
671			break;
672
673		case ID_ENC_AUDIO:
674			if (fOutputEncAudio.destination != media_destination::null)
675				goto _already_connected;
676			SpecializeFormatEncAudio(&format->u.encoded_audio);
677			if (!format->Matches(&fRequiredFormatRawVideo))
678				goto _bad_format;
679			break;
680
681		case ID_TS:
682			if (fOutputTS.destination != media_destination::null)
683				goto _already_connected;
684			SpecializeFormatTS(&format->u.multistream);
685			if (!format->Matches(&fRequiredFormatTS))
686				goto _bad_format;
687			break;
688
689		default:
690			goto _bad_source;
691	}
692
693	#ifdef DEBUG
694		TRACE("final format: ");
695		PrintFormat(*format);
696	#endif
697
698	// reserve the connection by setting destination
699	// set the output's format to the new format
700	SetOutput(source, destination, *format);
701
702	// set source and suggest a name
703	*out_source = source;
704	strcpy(out_name, SourceDefaultName(source));
705
706	return B_OK;
707
708_bad_source:
709	TRACE("Error: bad source!\n");
710	return B_MEDIA_BAD_SOURCE;
711
712_bad_format:
713	#ifdef DEBUG
714		TRACE("Error, bad format: ");
715		PrintFormat(*format);
716	#endif
717	return B_MEDIA_BAD_FORMAT;
718
719_already_connected:
720	TRACE("Error: already connected!\n");
721	return B_MEDIA_ALREADY_CONNECTED;
722}
723
724
725void
726DVBMediaNode::Connect(status_t error, const media_source &source,
727		const media_destination &destination, const media_format &format,
728		char *io_name)
729{
730	/* The connection process:
731	 *                BBufferProducer::FormatProposal
732	 *                BBufferConsumer::AcceptFormat
733	 *                BBufferProducer::PrepareToConnect
734	 *                BBufferConsumer::Connected
735	 * we are here => BBufferProducer::Connect
736	 */
737
738	TRACE("DVBMediaNode::Connect: %s\n", SourceDefaultName(source));
739
740	if (error != B_OK) {
741		TRACE("Error during connecting\n");
742		// if an error occured, unreserve the connection
743		ResetOutput(source);
744		return;
745	}
746
747	#ifdef DEBUG
748		TRACE("connected format: ");
749		PrintFormat(format);
750	#endif
751
752	// Since the destination is allowed to be changed by the
753	// consumer, the one we got in PrepareToConnect() is no
754	// longer correct, and must be updated here.
755	SetOutput(source, destination, format);
756
757	// Set output as connected
758	switch (source.id) {
759		case ID_RAW_VIDEO:	fOutputEnabledRawVideo = true; break;
760		case ID_RAW_AUDIO:	fOutputEnabledRawAudio = true; break;
761		case ID_ENC_VIDEO:	fOutputEnabledEncVideo = true; break;
762		case ID_ENC_AUDIO:	fOutputEnabledEncAudio = true; break;
763		case ID_TS:			fOutputEnabledTS = true; break;
764		default:			break;
765	}
766
767	// if the connection has no name, we set it now
768	if (strlen(io_name) == 0)
769		strcpy(io_name, SourceDefaultName(source));
770
771	#ifdef DEBUG
772		bigtime_t latency;
773		media_node_id ts;
774		if (B_OK != FindLatencyFor(destination, &latency, &ts))
775			TRACE("FindLatencyFor failed\n");
776		else
777			TRACE("downstream latency %Ld\n", latency);
778	#endif
779}
780
781
782void
783DVBMediaNode::Disconnect(const media_source &source,
784		const media_destination &destination)
785{
786	TRACE("DVBMediaNode::Disconnect: %s\n", SourceDefaultName(source));
787
788	// unreserve the connection
789	ResetOutput(source);
790
791	// Set output to disconnected
792	switch (source.id) {
793		case ID_RAW_VIDEO:	fOutputEnabledRawVideo = false; break;
794		case ID_RAW_AUDIO:	fOutputEnabledRawAudio = false; break;
795		case ID_ENC_VIDEO:	fOutputEnabledEncVideo = false; break;
796		case ID_ENC_AUDIO:	fOutputEnabledEncAudio = false; break;
797		case ID_TS:			fOutputEnabledTS = false; break;
798		default:			break;
799	}
800}
801
802
803void
804DVBMediaNode::LateNoticeReceived(const media_source &source,
805		bigtime_t how_much, bigtime_t performance_time)
806{
807	TRACE("DVBMediaNode::LateNoticeReceived %Ld late at %Ld\n", how_much, performance_time);
808}
809
810
811void
812DVBMediaNode::EnableOutput(const media_source &source, bool enabled,
813		int32 *_deprecated_)
814{
815	TRACE("DVBMediaNode::EnableOutput id = %ld, enabled = %d\n", source.id, enabled);
816	/* not used yet
817	switch (source.id) {
818		case ID_RAW_VIDEO:	fOutputEnabledRawVideo = enabled; break;
819		case ID_RAW_AUDIO:	fOutputEnabledRawAudio = enabled; break;
820		case ID_ENC_VIDEO:	fOutputEnabledEncVideo = enabled; break;
821		case ID_ENC_AUDIO:	fOutputEnabledEncAudio = enabled; break;
822		case ID_TS:			fOutputEnabledTS = enabled; break;
823		default:			break;
824	}
825	*/
826}
827
828
829status_t
830DVBMediaNode::SetPlayRate(int32 numer, int32 denom)
831{
832
833	return B_ERROR;
834}
835
836
837void
838DVBMediaNode::AdditionalBufferRequested(const media_source &source,
839		media_buffer_id prev_buffer, bigtime_t prev_time,
840		const media_seek_tag *prev_tag)
841{
842	TRACE("DVBMediaNode::AdditionalBufferRequested: %s\n", SourceDefaultName(source));
843}
844
845
846void
847DVBMediaNode::LatencyChanged(const media_source &source,
848		const media_destination &destination, bigtime_t new_latency,
849		uint32 flags)
850{
851	TRACE("DVBMediaNode::LatencyChanged to %Ld\n", new_latency);
852}
853
854/* DVBMediaNode */
855
856
857void
858DVBMediaNode::HandleTimeWarp(bigtime_t performance_time)
859{
860	TRACE("DVBMediaNode::HandleTimeWarp at %Ld\n", performance_time);
861}
862
863
864void
865DVBMediaNode::HandleSeek(bigtime_t performance_time)
866{
867	TRACE("DVBMediaNode::HandleSeek at %Ld\n", performance_time);
868}
869
870
871void
872DVBMediaNode::InitDefaultFormats()
873{
874	// 720 * 576
875	fDefaultFormatRawVideo.type = B_MEDIA_RAW_VIDEO;
876	fDefaultFormatRawVideo.u.raw_video.display.format = B_RGB32;
877	fDefaultFormatRawVideo.u.raw_video.display.line_width = 720;
878	fDefaultFormatRawVideo.u.raw_video.display.line_count = 576;
879	fDefaultFormatRawVideo.u.raw_video.last_active = fDefaultFormatRawVideo.u.raw_video.display.line_count - 1;
880	fDefaultFormatRawVideo.u.raw_video.display.bytes_per_row = fDefaultFormatRawVideo.u.raw_video.display.line_width * 4;
881	fDefaultFormatRawVideo.u.raw_video.field_rate = 0; // wildcard
882	fDefaultFormatRawVideo.u.raw_video.interlace = 1;
883	fDefaultFormatRawVideo.u.raw_video.first_active = 0;
884	fDefaultFormatRawVideo.u.raw_video.orientation = B_VIDEO_TOP_LEFT_RIGHT;
885	fDefaultFormatRawVideo.u.raw_video.pixel_width_aspect = 1;
886	fDefaultFormatRawVideo.u.raw_video.pixel_height_aspect = 1;
887	fDefaultFormatRawVideo.u.raw_video.display.pixel_offset = 0;
888	fDefaultFormatRawVideo.u.raw_video.display.line_offset = 0;
889	fDefaultFormatRawVideo.u.raw_video.display.flags = 0;
890
891	fDefaultFormatRawAudio.type = B_MEDIA_RAW_AUDIO;
892	fDefaultFormatRawAudio.u.raw_audio.frame_rate = 48000;
893	fDefaultFormatRawAudio.u.raw_audio.channel_count = 2;
894//  XXX broken in Haiku...
895//	fDefaultFormatRawAudio.u.raw_audio.format = 0; // wildcard
896	fDefaultFormatRawAudio.u.raw_audio.format = media_raw_audio_format::B_AUDIO_SHORT;
897//  when set to 0, haiku mixer has problems when diung a format change
898//  set to short and debug the buffer_size problem first!
899	fDefaultFormatRawAudio.u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN;
900//	fDefaultFormatRawAudio.u.raw_audio.buffer_size = 0; // wildcard
901//	fDefaultFormatRawAudio.u.raw_audio.buffer_size = 0x1200;
902//	fDefaultFormatRawAudio.u.raw_audio.buffer_size = 0x1000;
903	fDefaultFormatRawAudio.u.raw_audio.buffer_size = 32768;
904//	fDefaultFormatRawAudio.u.raw_audio.buffer_size = 333 * 8;
905//	fDefaultFormatRawAudio.u.raw_audio.buffer_size = 512;
906//  when set to anything different from 32768 haiku mixer has problems
907
908	fDefaultFormatEncVideo.type = B_MEDIA_ENCODED_VIDEO;
909	fDefaultFormatEncAudio.type = B_MEDIA_ENCODED_AUDIO;
910	fDefaultFormatTS.type = B_MEDIA_MULTISTREAM;
911}
912
913
914bool
915DVBMediaNode::VerifyFormatRawVideo(const media_raw_video_format &format)
916{
917	if (format.display.format != 0 &&
918		format.display.format != B_RGB32 &&
919		format.display.format != B_YCbCr422)
920		return false;
921
922	return true;
923}
924
925
926bool
927DVBMediaNode::VerifyFormatRawAudio(const media_multi_audio_format &format)
928{
929	if (format.format != 0 &&
930		format.format != media_raw_audio_format::B_AUDIO_FLOAT &&
931		format.format != media_raw_audio_format::B_AUDIO_SHORT)
932		return false;
933
934	return true;
935}
936
937
938void
939DVBMediaNode::SpecializeFormatRawVideo(media_raw_video_format *format)
940{
941	// Here we need to specialize *all* remaining wildcard
942	// fields that the consumer didn't set
943	if (format->field_rate == 0.0)
944		format->field_rate = 25;
945
946	// XXX a lot is missing here...
947}
948
949
950void
951DVBMediaNode::SpecializeFormatRawAudio(media_multi_audio_format *format)
952{
953	// Here we need to specialize *all* remaining wildcard
954	// fields that the consumer didn't set
955	if (format->format == 0)
956		format->format = media_raw_audio_format::B_AUDIO_SHORT;
957
958	if (format->buffer_size == 0)
959		format->buffer_size = 333 * 8;
960
961	// XXX a lot is missing here...
962}
963
964
965void
966DVBMediaNode::SpecializeFormatEncVideo(media_encoded_video_format *format)
967{
968	// Here we need to specialize *all* remaining wildcard
969	// fields that the consumer didn't set
970}
971
972
973void
974DVBMediaNode::SpecializeFormatEncAudio(media_encoded_audio_format *format)
975{
976	// Here we need to specialize *all* remaining wildcard
977	// fields that the consumer didn't set
978}
979
980
981void
982DVBMediaNode::SpecializeFormatTS(media_multistream_format *format)
983{
984	// Here we need to specialize *all* remaining wildcard
985	// fields that the consumer didn't set
986}
987
988
989status_t
990DVBMediaNode::SetOutput(const media_source &source,
991						const media_destination &destination,
992						const media_format &format)
993{
994	switch (source.id) {
995		case ID_RAW_VIDEO:
996			fOutputRawVideo.destination = destination;
997			fOutputRawVideo.format = format;
998			break;
999
1000		case ID_RAW_AUDIO:
1001			fOutputRawAudio.destination = destination;
1002			fOutputRawAudio.format = format;
1003			break;
1004
1005		case ID_ENC_VIDEO:
1006			fOutputEncVideo.destination = destination;
1007			fOutputEncVideo.format = format;
1008			break;
1009
1010		case ID_ENC_AUDIO:
1011			fOutputEncAudio.destination = destination;
1012			fOutputEncAudio.format = format;
1013			break;
1014
1015		case ID_TS:
1016			fOutputTS.destination = destination;
1017			fOutputTS.format = format;
1018			break;
1019
1020		default:
1021			return B_MEDIA_BAD_SOURCE;
1022	}
1023	return B_OK;
1024}
1025
1026
1027status_t
1028DVBMediaNode::ResetOutput(const media_source &source)
1029{
1030	switch (source.id) {
1031		case ID_RAW_VIDEO:
1032			fOutputRawVideo.destination = media_destination::null;
1033			fOutputRawVideo.format = fDefaultFormatRawVideo;
1034			break;
1035
1036		case ID_RAW_AUDIO:
1037			fOutputRawAudio.destination = media_destination::null;
1038			fOutputRawAudio.format = fDefaultFormatRawAudio;
1039			break;
1040
1041		case ID_ENC_VIDEO:
1042			fOutputEncVideo.destination = media_destination::null;
1043			fOutputEncVideo.format = fDefaultFormatEncVideo;
1044			break;
1045
1046		case ID_ENC_AUDIO:
1047			fOutputEncAudio.destination = media_destination::null;
1048			fOutputEncAudio.format = fDefaultFormatEncAudio;
1049			break;
1050
1051		case ID_TS:
1052			fOutputTS.destination = media_destination::null;
1053			fOutputTS.format = fDefaultFormatTS;
1054			break;
1055
1056		default:
1057			return B_MEDIA_BAD_SOURCE;
1058	}
1059	return B_OK;
1060}
1061
1062
1063const char *
1064DVBMediaNode::SourceDefaultName(const media_source &source)
1065{
1066	switch (source.id) {
1067		case ID_RAW_VIDEO:	return "raw video";
1068		case ID_RAW_AUDIO:	return "raw audio";
1069		case ID_ENC_VIDEO:	return "encoded video";
1070		case ID_ENC_AUDIO:	return "encoded audio";
1071		case ID_TS:			return "MPEG2 TS";
1072		default:			return NULL;
1073	}
1074}
1075
1076
1077void
1078DVBMediaNode::HandleStart(bigtime_t performance_time)
1079{
1080	TRACE("DVBMediaNode::HandleStart\n");
1081	StartCapture();
1082}
1083
1084
1085void
1086DVBMediaNode::HandleStop(void)
1087{
1088	TRACE("DVBMediaNode::HandleStop\n");
1089	StopCapture();
1090}
1091
1092
1093status_t
1094DVBMediaNode::Tune()
1095{
1096	TRACE("DVBMediaNode::Tune enter\n");
1097
1098	TRACE("state %d, region %d, channel %d, audio %d\n",
1099		fSelectedState, fSelectedRegion, fSelectedChannel, fSelectedAudio);
1100
1101	status_t err;
1102	bool needs_tuning = false;
1103
1104	if (fSelectedChannel < 0 || fSelectedAudio < 0) {
1105		printf("DVBMediaNode::Tune: invalid tuning info\n");
1106		StopCapture();
1107		err = B_ERROR;
1108		goto end;
1109//		return B_ERROR;
1110	}
1111
1112	const char *desc;
1113
1114	dvb_tuning_parameters_t new_params;
1115	int new_video_pid;
1116	int new_audio_pid;
1117	int new_pcr_pid;
1118
1119	desc = fChannelList->ItemAt(fSelectedChannel);
1120	err = ExtractTuningParams(desc, fSelectedAudio, &new_params, &new_video_pid, &new_audio_pid, &new_pcr_pid);
1121
1122	if (err != B_OK) {
1123		printf("DVBMediaNode::Tune: getting tuning info failed\n");
1124		StopCapture();
1125		err = B_ERROR;
1126		goto end;
1127//		return B_ERROR;
1128	}
1129/*
1130	if (fTuningParam.frequency == new_params.frequency) {
1131		printf("DVBMediaNode::Tune: frequency not changed\n");
1132		fVideoPid = new_video_pid;
1133		fAudioPid = new_audio_pid;
1134		fPcrPid = new_pcr_pid;
1135		fDemux->SetPIDs(fVideoPid, fAudioPid, fPcrPid);
1136		return B_OK;
1137	}
1138*/
1139	switch (fInterfaceType) {
1140		case DVB_TYPE_DVB_T:
1141			needs_tuning = (fTuningParam.u.dvb_t.frequency != new_params.u.dvb_t.frequency) || !fTuningSuccess;
1142			needs_tuning = true;
1143			break;
1144		case DVB_TYPE_DVB_S:
1145			printf("needs_tuning = %d, forcing tuning for DVB-S\n", needs_tuning);
1146			needs_tuning = true;
1147			break;
1148		default:
1149			needs_tuning = true;
1150			break;
1151	}
1152
1153	fTuningParam = new_params;
1154	fVideoPid = new_video_pid;
1155	fAudioPid = new_audio_pid;
1156	fPcrPid = new_pcr_pid;
1157
1158	if (needs_tuning) {
1159printf("about to stop capture 1\n");
1160#if STOP_CAPTURE_WHILE_TUNING
1161printf("about to stop capture 2\n");
1162		err = StopCapture();
1163		if (err) {
1164			printf("Tune: StopCapture failed\n");
1165			goto end;
1166		}
1167#endif
1168	} else {
1169#if STOP_CAPTURE_WHILE_TUNING
1170		StopCaptureThreads();
1171#endif
1172	}
1173
1174	if (needs_tuning) {
1175		err = fCard->SetTuningParameter(fTuningParam);
1176		fTuningSuccess = err == B_OK;
1177	}
1178
1179	fDemux->SetPIDs(fVideoPid, fAudioPid, fPcrPid);
1180
1181	if (needs_tuning) {
1182		if (fTuningSuccess) {
1183			fCard->GetTuningParameter(&fTuningParam);
1184			err = StartCapture();
1185		}
1186	} else {
1187#if STOP_CAPTURE_WHILE_TUNING
1188		StartCaptureThreads();
1189#endif
1190	}
1191
1192end:
1193	EventQueue()->AddEvent(media_timed_event(0, M_REFRESH_PARAMETER_WEB));
1194//	RefreshParameterWeb();
1195
1196	TRACE("DVBMediaNode::Tune finished\n");
1197	return err;
1198}
1199
1200
1201status_t
1202DVBMediaNode::StartCapture()
1203{
1204	TRACE("DVBMediaNode::StartCapture\n");
1205
1206	if (fCaptureActive)
1207		return B_OK;
1208
1209	RETURN_IF_ERROR(StopCaptureThreads());
1210
1211	if (!fTuningSuccess) {
1212		RETURN_IF_ERROR(Tune());
1213	}
1214
1215	RETURN_IF_ERROR(StartCaptureThreads());
1216
1217	fCard->CaptureStart();
1218
1219	fCaptureActive = true;
1220
1221	RefreshParameterWeb();
1222
1223	return B_OK;
1224}
1225
1226
1227status_t
1228DVBMediaNode::StopCapture()
1229{
1230	TRACE("DVBMediaNode::StopCapture\n");
1231	if (!fCaptureActive)
1232		return B_OK;
1233
1234	StopCaptureThreads();
1235
1236	fCard->CaptureStop();
1237
1238	fCaptureActive = false;
1239	return B_OK;
1240}
1241
1242
1243status_t
1244DVBMediaNode::StartCaptureThreads()
1245{
1246	TRACE("DVBMediaNode::StartCaptureThreads\n");
1247
1248	if (fCaptureThreadsActive)
1249		return B_OK;
1250
1251	fTerminateThreads = false;
1252
1253	fThreadIdCardReader = spawn_thread(_card_reader_thread_, "DVB card reader", 120, this);
1254	fThreadIdMpegDemux = spawn_thread(_mpeg_demux_thread_, "DVB MPEG demux", 110, this);
1255	fThreadIdEncAudio = spawn_thread(_enc_audio_thread_, "DVB audio streaming", 110, this);
1256	fThreadIdEncVideo = spawn_thread(_enc_video_thread_, "DVB video streaming", 110, this);
1257	fThreadIdMpegTS = spawn_thread(_mpeg_ts_thread_, "DVB MPEG TS streaming", 110, this);
1258	fThreadIdRawAudio = spawn_thread(_raw_audio_thread_, "DVB audio decode", 100, this);
1259	fThreadIdRawVideo = spawn_thread(_raw_video_thread_, "DVB video decode", 85, this);
1260	resume_thread(fThreadIdCardReader);
1261	resume_thread(fThreadIdMpegDemux);
1262	resume_thread(fThreadIdEncAudio);
1263	resume_thread(fThreadIdEncVideo);
1264	resume_thread(fThreadIdMpegTS);
1265	resume_thread(fThreadIdRawAudio);
1266	resume_thread(fThreadIdRawVideo);
1267
1268	fCaptureThreadsActive = true;
1269	return B_OK;
1270}
1271
1272
1273status_t
1274DVBMediaNode::StopCaptureThreads()
1275{
1276	TRACE("DVBMediaNode::StopCaptureThreads\n");
1277
1278	if (!fCaptureThreadsActive)
1279		return B_OK;
1280
1281	fTerminateThreads = true;
1282
1283	fCardDataQueue->Terminate();
1284	fEncVideoQueue->Terminate();
1285	fEncAudioQueue->Terminate();
1286	fMpegTsQueue->Terminate();
1287	fRawVideoQueue->Terminate();
1288	fRawAudioQueue->Terminate();
1289
1290	status_t dummy; // NULL as parameter does not work
1291	wait_for_thread(fThreadIdCardReader, &dummy);
1292	wait_for_thread(fThreadIdMpegDemux, &dummy);
1293	wait_for_thread(fThreadIdEncAudio, &dummy);
1294	wait_for_thread(fThreadIdEncVideo, &dummy);
1295	wait_for_thread(fThreadIdMpegTS, &dummy);
1296	wait_for_thread(fThreadIdRawAudio, &dummy);
1297	wait_for_thread(fThreadIdRawVideo, &dummy);
1298
1299	fCardDataQueue->Restart();
1300	fEncVideoQueue->Restart();
1301	fEncAudioQueue->Restart();
1302	fMpegTsQueue->Restart();
1303	fRawVideoQueue->Restart();
1304	fRawAudioQueue->Restart();
1305
1306	fCaptureThreadsActive = false;
1307	return B_OK;
1308}
1309
1310
1311int32
1312DVBMediaNode::_card_reader_thread_(void *arg)
1313{
1314	static_cast<DVBMediaNode *>(arg)->card_reader_thread();
1315	return 0;
1316}
1317
1318
1319int32
1320DVBMediaNode::_mpeg_demux_thread_(void *arg)
1321{
1322	static_cast<DVBMediaNode *>(arg)->mpeg_demux_thread();
1323	return 0;
1324}
1325
1326
1327int32
1328DVBMediaNode::_raw_audio_thread_(void *arg)
1329{
1330	static_cast<DVBMediaNode *>(arg)->raw_audio_thread();
1331	return 0;
1332}
1333
1334
1335int32
1336DVBMediaNode::_raw_video_thread_(void *arg)
1337{
1338	static_cast<DVBMediaNode *>(arg)->raw_video_thread();
1339	return 0;
1340}
1341
1342
1343int32
1344DVBMediaNode::_enc_audio_thread_(void *arg)
1345{
1346	static_cast<DVBMediaNode *>(arg)->enc_audio_thread();
1347	return 0;
1348}
1349
1350
1351int32
1352DVBMediaNode::_enc_video_thread_(void *arg)
1353{
1354	static_cast<DVBMediaNode *>(arg)->enc_video_thread();
1355	return 0;
1356}
1357
1358
1359int32
1360DVBMediaNode::_mpeg_ts_thread_(void *arg)
1361{
1362	static_cast<DVBMediaNode *>(arg)->mpeg_ts_thread();
1363	return 0;
1364}
1365
1366
1367void
1368DVBMediaNode::card_reader_thread()
1369{
1370	while (!fTerminateThreads) {
1371		void *data;
1372		size_t size;
1373		status_t err;
1374		bigtime_t end_time;
1375		err = fCard->Capture(&data, &size, &end_time);
1376		if (err != B_OK) {
1377			TRACE("fCard->Capture failed, error %lx (%s)\n", err, strerror(err));
1378			continue;
1379		}
1380
1381//		TRACE("captured %ld bytes\n", size);
1382
1383		Packet *packet = new Packet(data, size, end_time);
1384
1385		err = fCardDataQueue->Insert(packet);
1386		if (err != B_OK) {
1387			delete packet;
1388			TRACE("fCardDataQueue->Insert failed, error %lx\n", err);
1389			continue;
1390		}
1391	}
1392}
1393
1394
1395void
1396DVBMediaNode::mpeg_demux_thread()
1397{
1398	while (!fTerminateThreads) {
1399		status_t err;
1400		Packet *packet;
1401		err = fCardDataQueue->Remove(&packet);
1402		if (err != B_OK) {
1403			TRACE("fCardDataQueue->Remove failed, error %lx\n", err);
1404			continue;
1405		}
1406
1407		// packet->TimeStamp() is the end time of the capture
1408		fDemux->AddData(packet);
1409	}
1410}
1411
1412
1413void
1414DVBMediaNode::mpeg_ts_thread()
1415{
1416	while (!fTerminateThreads) {
1417		status_t err;
1418		Packet *packet;
1419		err = fMpegTsQueue->Remove(&packet);
1420		if (err != B_OK) {
1421			TRACE("fMpegTsQueue->Remove failed, error %lx\n", err);
1422			continue;
1423		}
1424
1425//		TRACE("mpeg ts   packet, size %6ld, start_time %14Ld\n", packet->Size(), packet->TimeStamp());
1426
1427		delete packet;
1428	}
1429}
1430
1431
1432void
1433DVBMediaNode::enc_audio_thread()
1434{
1435	while (!fTerminateThreads) {
1436		status_t err;
1437		Packet *packet;
1438		err = fEncAudioQueue->Remove(&packet);
1439		if (err != B_OK) {
1440			TRACE("fEncAudioQueue->Remove failed, error %lx\n", err);
1441			continue;
1442		}
1443//		TRACE("enc audio packet, size %6ld, start_time %14Ld\n", packet->Size(), packet->TimeStamp());
1444
1445#ifdef DUMP_AUDIO
1446		const uint8 *data;
1447		size_t size;
1448		if (B_OK != pes_extract(packet->Data(), packet->Size(), &data, &size)) {
1449			TRACE("audio pes_extract failed\n");
1450			delete packet;
1451			return;
1452		}
1453		lock.Lock();
1454		write(fAudioFile, data, size);
1455		lock.Unlock();
1456#endif
1457
1458		if (!fOutputEnabledEncAudio) {
1459			delete packet;
1460			continue;
1461		}
1462
1463		// send encoded audio buffer
1464
1465
1466		delete packet;
1467	}
1468}
1469
1470
1471void
1472DVBMediaNode::enc_video_thread()
1473{
1474	while (!fTerminateThreads) {
1475		status_t err;
1476		Packet *packet;
1477		err = fEncVideoQueue->Remove(&packet);
1478		if (err != B_OK) {
1479			TRACE("fEncVideoQueue->Remove failed, error %lx\n", err);
1480			continue;
1481		}
1482
1483//		TRACE("enc video packet, size %6ld, start_time %14Ld\n", packet->Size(), packet->TimeStamp());
1484
1485
1486#ifdef DUMP_VIDEO
1487		const uint8 *data;
1488		size_t size;
1489		if (B_OK != pes_extract(packet->Data(), packet->Size(), &data, &size)) {
1490			TRACE("video pes_extract failed\n");
1491			delete packet;
1492			return;
1493		}
1494		lock.Lock();
1495		write(fVideoFile, data, size);
1496		lock.Unlock();
1497#endif
1498
1499		if (!fOutputEnabledEncVideo) {
1500			delete packet;
1501			continue;
1502		}
1503
1504		// send encoded video buffer
1505
1506		delete packet;
1507	}
1508}
1509
1510
1511void
1512DVBMediaNode::raw_audio_thread()
1513{
1514	media_format format;
1515	status_t err;
1516	err = GetStreamFormat(fRawAudioQueue, &format);
1517	if (err) {
1518		printf("fAudioDecoder init error %s\n", strerror(err));
1519		return;
1520	}
1521
1522	// create decoder interface
1523
1524	fAudioDecoder = new MediaStreamDecoder(&_GetNextAudioChunk, this);
1525
1526	err = fAudioDecoder->SetInputFormat(format);
1527	if (err) {
1528		printf("fAudioDecoder SetInputFormat error %s\n", strerror(err));
1529		return;
1530	}
1531
1532	TRACE("requested audio decoder format: ");
1533	PrintFormat(fOutputRawAudio);
1534
1535	media_format fmt = fOutputRawAudio.format;
1536	err = fAudioDecoder->SetOutputFormat(&fmt);
1537	if (err) {
1538		printf("fAudioDecoder SetOutputFormat error %s\n", strerror(err));
1539		return;
1540	}
1541
1542	TRACE("final audio decoder format: ");
1543	PrintFormat(fmt);
1544
1545	// change format of connection
1546	if (format_is_compatible(fmt, fOutputRawAudio.format)) {
1547		printf("audio formats are compatible\n");
1548		fOutputRawAudio.format = fmt;
1549	} else {
1550		printf("audio formats NOT compatible\n");
1551		lock.Lock();
1552		err = ChangeFormat(fOutputRawAudio.source,
1553						   fOutputRawAudio.destination,
1554						   &fmt);
1555		lock.Unlock();
1556		printf("format change result %lx (%s)\n", err, strerror(err));
1557		PrintFormat(fmt);
1558		fOutputRawAudio.format = fmt;
1559		if (err)
1560			return;
1561	}
1562
1563	// decode data and send buffers
1564
1565	delete fBufferGroupRawAudio;
1566	fBufferGroupRawAudio = new BBufferGroup(fOutputRawAudio.format.u.raw_audio.buffer_size * 3, 25);
1567
1568	while (!fTerminateThreads) {
1569		int64 frameCount;
1570		media_header mh;
1571		media_header_ex *mhe = (media_header_ex *)&mh;
1572
1573		if (!fOutputEnabledRawAudio) {
1574			fRawAudioQueue->Flush(40000);
1575			continue;
1576		}
1577
1578		BBuffer* buf;
1579		buf = fBufferGroupRawAudio->RequestBuffer(fOutputRawAudio.format.u.raw_audio.buffer_size, AUDIO_BUFFER_REQUEST_TIMEOUT);
1580		if (!buf) {
1581			TRACE("audio: request buffer timout\n");
1582			continue;
1583		}
1584
1585		err = fAudioDecoder->Decode(buf->Data(), &frameCount, &mh, NULL);
1586		if (err) {
1587			buf->Recycle();
1588			printf("fAudioDecoder Decode error %s\n", strerror(err));
1589			continue;
1590		}
1591
1592#ifdef DUMP_RAW_AUDIO
1593		lock.Lock();
1594		write(fRawAudioFile, buf->Data(), mhe->size_used);
1595		lock.Unlock();
1596#endif
1597
1598		if (	fOutputRawAudio.format.u.raw_audio.buffer_size     != mhe->size_used
1599		 	||	int(fOutputRawAudio.format.u.raw_audio.frame_rate) != mhe->u.raw_audio.frame_rate
1600			||	fOutputRawAudio.format.u.raw_audio.channel_count   != mhe->u.raw_audio.channel_count
1601		 ) {
1602			TRACE("audio: decode format change: changed buffer_size from %ld to %ld\n", fOutputRawAudio.format.u.raw_audio.buffer_size, mhe->size_used);
1603			TRACE("audio: decode format change: changed channel_count from %ld to %ld\n", fOutputRawAudio.format.u.raw_audio.channel_count, mhe->u.raw_audio.channel_count);
1604			TRACE("audio: decode format change: changed frame_rate from %.0f to %.0f\n", fOutputRawAudio.format.u.raw_audio.frame_rate, mhe->u.raw_audio.frame_rate);
1605			fOutputRawAudio.format.u.raw_audio.buffer_size   = mhe->size_used;
1606			fOutputRawAudio.format.u.raw_audio.frame_rate    = mhe->u.raw_audio.frame_rate;
1607			fOutputRawAudio.format.u.raw_audio.channel_count = mhe->u.raw_audio.channel_count;
1608			lock.Lock();
1609			err = ChangeFormat(fOutputRawAudio.source,
1610							   fOutputRawAudio.destination,
1611							   &fOutputRawAudio.format);
1612			lock.Unlock();
1613			printf("format change result %lx (%s)\n", err, strerror(err));
1614			PrintFormat(fOutputRawAudio.format);
1615			if (err) {
1616				buf->Recycle();
1617				return; // we are dead!
1618			}
1619		}
1620
1621		bigtime_t ts_perf_time;
1622		bigtime_t ts_sys_time;
1623		bigtime_t ts_offset;
1624		bigtime_t aud_time;
1625		bigtime_t start_time;
1626
1627		// calculate start time of audio data
1628
1629		fDemux->TimesourceInfo(&ts_perf_time, &ts_sys_time);
1630		ts_offset = ts_sys_time - ts_perf_time;
1631		aud_time = mhe->start_time;	// measured in PCR time base
1632		start_time = TimeSource()->PerformanceTimeFor(aud_time + ts_offset);
1633
1634		// calculate delay and wait
1635
1636		bigtime_t delay;
1637		delay = start_time - TimeSource()->Now();
1638		TRACE_TIMING("audio delay is %Ld\n", delay);
1639		if (delay < -AUDIO_MAX_LATE) {
1640			printf("audio: decoded packet is %Ldms too late, dropped\n", -delay / 1000);
1641			buf->Recycle();
1642			continue;
1643		}
1644		if (delay < 0) {
1645//			printf("audio: decoded packet is %Ldms too late\n", -delay / 1000);
1646		}
1647		if (delay > AUDIO_MAX_EARLY) {
1648			printf("audio: decoded packet is %Ldms too early, dropped\n", delay / 1000);
1649			buf->Recycle();
1650			continue;
1651		}
1652		if (delay > 0) {
1653//			printf("audio: decoded packet is %Ldms too early\n", delay / 1000);
1654		}
1655		delay -= PROCESSING_LATENCY;
1656		if (delay > 0) {
1657			if (acquire_sem_etc(fAudioDelaySem, 1, B_RELATIVE_TIMEOUT, delay) != B_TIMED_OUT) {
1658				printf("audio: delay sem not timed out, dropped packet\n");
1659				buf->Recycle();
1660				continue;
1661			}
1662		}
1663
1664		TRACE_TIMING("audio playback delay %Ld\n", start_time - TimeSource()->Now());
1665
1666		media_header* hdr;
1667		hdr = buf->Header();
1668//		*hdr = mh;								// copy header from decoded frame
1669		hdr->type = B_MEDIA_RAW_AUDIO;
1670		hdr->size_used = mhe->size_used;
1671		hdr->time_source = TimeSource()->ID();	// set time source id
1672		hdr->start_time = start_time;			// set start time
1673		lock.Lock();
1674		if (SendBuffer(buf, fOutputRawAudio.source, fOutputRawAudio.destination)
1675				!= B_OK) {
1676			TRACE("audio: sending buffer failed\n");
1677			buf->Recycle();
1678		}
1679		lock.Unlock();
1680	}
1681
1682	delete fCurrentAudioPacket;
1683	fCurrentAudioPacket = 0;
1684}
1685
1686
1687void
1688DVBMediaNode::raw_video_thread()
1689{
1690	media_format format;
1691	status_t err;
1692	err = GetStreamFormat(fRawVideoQueue, &format);
1693	if (err) {
1694		printf("fVideoDecoder init error %s\n", strerror(err));
1695		return;
1696	}
1697
1698	// create decoder interface
1699
1700	fVideoDecoder = new MediaStreamDecoder(&_GetNextVideoChunk, this);
1701
1702	err = fVideoDecoder->SetInputFormat(format);
1703	if (err) {
1704		printf("fVideoDecoder SetInputFormat error %s\n", strerror(err));
1705		return;
1706	}
1707
1708	TRACE("requested video decoder format: ");
1709	PrintFormat(fOutputRawVideo);
1710
1711	media_format fmt = fOutputRawVideo.format;
1712	err = fVideoDecoder->SetOutputFormat(&fmt);
1713	if (err) {
1714		printf("fVideoDecoder SetOutputFormat error %s\n", strerror(err));
1715		return;
1716	}
1717
1718	TRACE("final video decoder format: ");
1719	PrintFormat(fmt);
1720
1721	// change format of connection
1722	if (format_is_compatible(fmt, fOutputRawVideo.format)) {
1723		printf("video formats are compatible\n");
1724		fOutputRawVideo.format = fmt;
1725	} else {
1726		printf("video formats NOT compatible\n");
1727		lock.Lock();
1728		err = ChangeFormat(fOutputRawVideo.source,
1729						   fOutputRawVideo.destination,
1730						   &fmt);
1731		lock.Unlock();
1732		printf("format change result %lx (%s)\n", err, strerror(err));
1733		PrintFormat(fmt);
1734		fOutputRawVideo.format = fmt;
1735		if (err) {
1736			printf("video format change failed\n");
1737			return;
1738		}
1739	}
1740
1741	// decode data and send buffers
1742
1743	uint32 video_buffer_size_max = 720 * 576 * 4;
1744	uint32 video_buffer_size
1745		= fOutputRawVideo.format.u.raw_video.display.line_count
1746			* fOutputRawVideo.format.u.raw_video.display.bytes_per_row;
1747
1748	delete fBufferGroupRawVideo;
1749	fBufferGroupRawVideo = new BBufferGroup(video_buffer_size_max, 4);
1750
1751	while (!fTerminateThreads) {
1752		int64 frameCount;
1753		media_header mh;
1754		media_header_ex *mhe = (media_header_ex *)&mh;
1755
1756		if (!fOutputEnabledRawVideo) {
1757			fRawVideoQueue->Flush(40000);
1758			continue;
1759		}
1760
1761		// fetch a new buffer (always of maximum size, as the stream may change)
1762
1763		BBuffer* buf;
1764		buf = fBufferGroupRawVideo->RequestBuffer(video_buffer_size_max,
1765			VIDEO_BUFFER_REQUEST_TIMEOUT);
1766		if (!buf) {
1767			TRACE("video: request buffer timout\n");
1768			continue;
1769		}
1770
1771		// decode one video frame into buffer
1772
1773		err = fVideoDecoder->Decode(buf->Data(), &frameCount, &mh, NULL);
1774		if (err) {
1775			buf->Recycle();
1776			printf("fVideoDecoder Decode error %s\n", strerror(err));
1777			continue;
1778		}
1779
1780		// check if the format of the stream has changed
1781
1782		if (	mhe->u.raw_video.display_line_width  != fOutputRawVideo.format.u.raw_video.display.line_width
1783			||	mhe->u.raw_video.display_line_count  != fOutputRawVideo.format.u.raw_video.display.line_count
1784			||	mhe->u.raw_video.bytes_per_row       != fOutputRawVideo.format.u.raw_video.display.bytes_per_row
1785			||	mhe->u.raw_video.pixel_width_aspect  != fOutputRawVideo.format.u.raw_video.pixel_width_aspect
1786			||	mhe->u.raw_video.pixel_height_aspect != fOutputRawVideo.format.u.raw_video.pixel_height_aspect
1787			||  mhe->size_used						 != video_buffer_size)
1788		{
1789			printf("video format changed:\n");
1790			printf(" line_width %ld => %ld\n", fOutputRawVideo.format.u.raw_video.display.line_width, mhe->u.raw_video.display_line_width);
1791			printf(" line_count %ld => %ld\n", fOutputRawVideo.format.u.raw_video.display.line_count, mhe->u.raw_video.display_line_count);
1792			printf(" bytes_per_row %ld => %ld\n", fOutputRawVideo.format.u.raw_video.display.bytes_per_row, mhe->u.raw_video.bytes_per_row);
1793			printf(" pixel_width_aspect %d => %d\n", fOutputRawVideo.format.u.raw_video.pixel_width_aspect, mhe->u.raw_video.pixel_width_aspect);
1794			printf(" pixel_height_aspect %d => %d\n", fOutputRawVideo.format.u.raw_video.pixel_width_aspect, mhe->u.raw_video.pixel_height_aspect);
1795			printf(" pixel_height_aspect %d => %d\n", fOutputRawVideo.format.u.raw_video.pixel_width_aspect, mhe->u.raw_video.pixel_height_aspect);
1796			printf(" video_buffer_size %ld => %ld\n", video_buffer_size, mhe->size_used);
1797
1798			// recalculate video buffer size
1799//			video_buffer_size = mhe->size_used;
1800			video_buffer_size = fOutputRawVideo.format.u.raw_video.display.line_count * fOutputRawVideo.format.u.raw_video.display.bytes_per_row;
1801
1802			// perform a video format change
1803
1804			fOutputRawVideo.format.u.raw_video.display.line_width    = mhe->u.raw_video.display_line_width;
1805			fOutputRawVideo.format.u.raw_video.display.line_count    = mhe->u.raw_video.display_line_count;
1806			fOutputRawVideo.format.u.raw_video.display.bytes_per_row = mhe->u.raw_video.bytes_per_row;
1807			fOutputRawVideo.format.u.raw_video.pixel_width_aspect    = mhe->u.raw_video.pixel_width_aspect;
1808			fOutputRawVideo.format.u.raw_video.pixel_width_aspect    = mhe->u.raw_video.pixel_height_aspect;
1809			fOutputRawVideo.format.u.raw_video.last_active           = mhe->u.raw_video.display_line_count - 1;
1810			lock.Lock();
1811			err = ChangeFormat(fOutputRawVideo.source,
1812							   fOutputRawVideo.destination,
1813							   &fOutputRawVideo.format);
1814			lock.Unlock();
1815			printf("format change result %lx (%s)\n", err, strerror(err));
1816			PrintFormat(fOutputRawVideo.format);
1817			if (err) {
1818				buf->Recycle();
1819				printf("video format change failed\n");
1820				return; // we are dead
1821			}
1822		}
1823
1824		// calculate start time for video
1825
1826		bigtime_t ts_perf_time;
1827		bigtime_t ts_sys_time;
1828		bigtime_t ts_offset;
1829		bigtime_t pic_time;
1830		bigtime_t start_time;
1831
1832		fDemux->TimesourceInfo(&ts_perf_time, &ts_sys_time);
1833		ts_offset = ts_sys_time - ts_perf_time;
1834		pic_time = mhe->start_time;	// measured in PCR time base
1835		start_time = TimeSource()->PerformanceTimeFor(pic_time + ts_offset);
1836
1837		// calculate delay and wait
1838
1839		bigtime_t delay;
1840		delay = start_time - TimeSource()->Now();
1841		TRACE_TIMING("video delay %Ld\n", delay);
1842		if (delay < -VIDEO_MAX_LATE) {
1843			printf("video: decoded packet is %Ldms too late, dropped\n", -delay / 1000);
1844			buf->Recycle();
1845			continue;
1846		}
1847		if (delay > VIDEO_MAX_EARLY) {
1848			printf("video: decoded packet is %Ldms too early, dropped\n", delay / 1000);
1849			buf->Recycle();
1850			continue;
1851		}
1852		delay -= PROCESSING_LATENCY;
1853		if (delay > 0) {
1854			if (acquire_sem_etc(fVideoDelaySem, 1, B_RELATIVE_TIMEOUT, delay) != B_TIMED_OUT) {
1855				printf("video: delay sem not timed out, dropped packet\n");
1856				buf->Recycle();
1857				continue;
1858			}
1859		}
1860
1861		TRACE_TIMING("video playback delay %Ld\n", start_time - TimeSource()->Now());
1862
1863		media_header* hdr;
1864		hdr = buf->Header();
1865//		*hdr = mh;								// copy header from decoded frame
1866		hdr->type = B_MEDIA_RAW_VIDEO;
1867		hdr->size_used = video_buffer_size;
1868		hdr->time_source = TimeSource()->ID();	// set time source id
1869		hdr->start_time = start_time;			// set start time
1870		lock.Lock();
1871		if (SendBuffer(buf, fOutputRawVideo.source, fOutputRawVideo.destination)
1872				!= B_OK) {
1873			TRACE("video: sending buffer failed\n");
1874			buf->Recycle();
1875		}
1876		lock.Unlock();
1877
1878	}
1879
1880	delete fCurrentVideoPacket;
1881	fCurrentVideoPacket = 0;
1882}
1883
1884
1885inline status_t
1886DVBMediaNode::GetNextVideoChunk(const void **chunkData, size_t *chunkLen, media_header *mh)
1887{
1888//	TRACE("DVBMediaNode::GetNextVideoChunk\n");
1889
1890	delete fCurrentVideoPacket;
1891
1892	status_t err;
1893	err = fRawVideoQueue->Remove(&fCurrentVideoPacket);
1894	if (err != B_OK) {
1895		TRACE("fRawVideoQueue->Remove failed, error %lx\n", err);
1896		fCurrentVideoPacket = 0;
1897		return B_ERROR;
1898	}
1899
1900	const uint8 *data;
1901	size_t size;
1902
1903	if (B_OK != pes_extract(fCurrentVideoPacket->Data(), fCurrentVideoPacket->Size(), &data, &size)) {
1904		TRACE("video pes_extract failed\n");
1905		return B_ERROR;
1906	}
1907
1908	*chunkData = data;
1909	*chunkLen = size;
1910	// measured in PCR time base
1911	mh->start_time = fCurrentVideoPacket->TimeStamp();
1912
1913	return B_OK;
1914}
1915
1916
1917inline status_t
1918DVBMediaNode::GetNextAudioChunk(const void **chunkData, size_t *chunkLen, media_header *mh)
1919{
1920//	TRACE("DVBMediaNode::GetNextAudioChunk\n");
1921
1922	delete fCurrentAudioPacket;
1923
1924	status_t err;
1925	err = fRawAudioQueue->Remove(&fCurrentAudioPacket);
1926	if (err != B_OK) {
1927		TRACE("fRawAudioQueue->Remove failed, error %lx\n", err);
1928		fCurrentAudioPacket = 0;
1929		return B_ERROR;
1930	}
1931
1932	const uint8 *data;
1933	size_t size;
1934
1935	if (B_OK != pes_extract(fCurrentAudioPacket->Data(), fCurrentAudioPacket->Size(), &data, &size)) {
1936		TRACE("audio pes_extract failed\n");
1937		return B_ERROR;
1938	}
1939
1940	*chunkData = data;
1941	*chunkLen = size;
1942	// measured in PCR time base
1943	mh->start_time = fCurrentAudioPacket->TimeStamp();
1944
1945//	printf("GetNextAudioChunk: done start_time %Ld\n", mh->start_time);
1946
1947	return B_OK;
1948}
1949
1950
1951status_t
1952DVBMediaNode::_GetNextVideoChunk(const void **chunkData, size_t *chunkLen, media_header *mh, void *cookie)
1953{
1954	return static_cast<DVBMediaNode *>(cookie)->GetNextVideoChunk(chunkData, chunkLen, mh);
1955}
1956
1957
1958status_t
1959DVBMediaNode::_GetNextAudioChunk(const void **chunkData, size_t *chunkLen, media_header *mh, void *cookie)
1960{
1961	return static_cast<DVBMediaNode *>(cookie)->GetNextAudioChunk(chunkData, chunkLen, mh);
1962}
1963
1964
1965status_t
1966DVBMediaNode::GetStreamFormat(PacketQueue *queue, media_format *format)
1967{
1968	status_t status;
1969	Packet *packet;
1970	const uint8 *data;
1971	size_t size;
1972	int stream_id;
1973
1974	// get copy of the first packet from queue, and determine format
1975
1976	if ((status = queue->Peek(&packet)) != B_OK) {
1977		TRACE("queue->Peek failed, error %lx\n", status);
1978		return status;
1979	}
1980
1981	if ((status = pes_extract(packet->Data(), packet->Size(), &data, &size)) != B_OK) {
1982		TRACE("pes_extract failed\n");
1983		goto done;
1984	}
1985
1986	if ((status = pes_stream_id(packet->Data(), packet->Size(), &stream_id)) != B_OK) {
1987		TRACE("pes_stream_id failed\n");
1988		goto done;
1989	}
1990
1991	if ((status = GetHeaderFormat(format, data, size, stream_id)) != B_OK) {
1992		TRACE("GetHeaderFormat failed, error %lx\n", status);
1993		goto done;
1994	}
1995
1996done:
1997	delete packet;
1998	return status;
1999}
2000
2001
2002enum {
2003	ID_STATE	= 11,
2004	ID_REGION	= 12,
2005	ID_CHANNEL	= 13,
2006	ID_AUDIO	= 14,
2007};
2008
2009
2010void
2011DVBMediaNode::RefreshParameterWeb()
2012{
2013	TRACE("DVBMediaNode::RefreshParameterWeb enter\n");
2014	fWeb = CreateParameterWeb();
2015	SetParameterWeb(fWeb);
2016	TRACE("DVBMediaNode::RefreshParameterWeb finished\n");
2017}
2018
2019
2020void
2021DVBMediaNode::SetAboutInfo(BParameterGroup *about)
2022{
2023	about->MakeNullParameter(0, B_MEDIA_NO_TYPE, "DVB media_addon info:", B_GENERIC);
2024	about->MakeNullParameter(0, B_MEDIA_NO_TYPE, "Version " VERSION, B_GENERIC);
2025	about->MakeNullParameter(0, B_MEDIA_NO_TYPE, "Revision " REVISION, B_GENERIC);
2026	about->MakeNullParameter(0, B_MEDIA_NO_TYPE, "Build " BUILD, B_GENERIC);
2027
2028	about->MakeNullParameter(0, B_MEDIA_NO_TYPE, "", B_GENERIC);
2029	about->MakeNullParameter(0, B_MEDIA_NO_TYPE, "Driver info:", B_GENERIC);
2030
2031	dvb_type_t type;
2032	char name[200];
2033	char info[200];
2034
2035	fCard->GetCardType(&type);
2036	fCard->GetCardInfo(name, sizeof(name), info, sizeof(info));
2037
2038	about->MakeNullParameter(0, B_MEDIA_NO_TYPE, name, B_GENERIC);
2039	about->MakeNullParameter(0, B_MEDIA_NO_TYPE, info, B_GENERIC);
2040}
2041
2042
2043BParameterWeb *
2044DVBMediaNode::CreateParameterWeb()
2045{
2046	/* Set up the parameter web */
2047	BParameterWeb *web = new BParameterWeb();
2048
2049	char n[200], i[200];
2050	fCard->GetCardInfo(n, sizeof(n), i, sizeof(i));
2051
2052	BString name;
2053	name << Name() << " - " << i;
2054
2055	BParameterGroup *main = web->MakeGroup(name.String());
2056
2057	BParameterGroup *ctrl = main->MakeGroup("Channel Selection");
2058	ctrl->MakeNullParameter(0, B_MEDIA_NO_TYPE, ctrl->Name(), B_GENERIC);
2059
2060	BParameterGroup *pref = main->MakeGroup("Preferences");
2061	pref->MakeNullParameter(0, B_MEDIA_NO_TYPE, pref->Name(), B_GENERIC);
2062
2063	BDiscreteParameter *state = pref->MakeDiscreteParameter(
2064			ID_STATE, B_MEDIA_RAW_VIDEO, "State", B_GENERIC);
2065
2066	BDiscreteParameter *region = pref->MakeDiscreteParameter(
2067			ID_REGION, B_MEDIA_RAW_VIDEO, "Region", B_GENERIC);
2068
2069	BDiscreteParameter *chan = ctrl->MakeDiscreteParameter(
2070			ID_CHANNEL, B_MEDIA_RAW_VIDEO, "Channel", /* B_TUNER_CHANNEL */ B_GENERIC);
2071
2072	BDiscreteParameter *aud = ctrl->MakeDiscreteParameter(
2073			ID_AUDIO, B_MEDIA_RAW_VIDEO, "Audio", B_GENERIC);
2074
2075	AddStateItems(state);
2076	AddRegionItems(region);
2077	AddChannelItems(chan);
2078	AddAudioItems(aud);
2079
2080
2081	if (!fTuningSuccess || !fCaptureActive) {
2082		BParameterGroup *info = main->MakeGroup("Info");
2083		info->MakeNullParameter(0, B_MEDIA_NO_TYPE, info->Name(), B_GENERIC);
2084		BParameterGroup *about = main->MakeGroup("About");
2085		about->MakeNullParameter(0, B_MEDIA_NO_TYPE, about->Name(), B_GENERIC);
2086		SetAboutInfo(about);
2087//		info->MakeNullParameter(0, B_MEDIA_NO_TYPE, fCaptureActive ? "Tuning failed" : "Node stopped", B_GENERIC);
2088		info->MakeNullParameter(0, B_MEDIA_NO_TYPE, "Node is stopped", B_GENERIC);
2089		info->MakeNullParameter(0, B_MEDIA_NO_TYPE, "or tuning failed.", B_GENERIC);
2090		return web;
2091	}
2092
2093	BParameterGroup *info1 = main->MakeGroup("Info");
2094	info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, info1->Name(), B_GENERIC);
2095	BParameterGroup *info2 = main->MakeGroup("Info");
2096	info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, info2->Name(), B_GENERIC);
2097	BParameterGroup *about = main->MakeGroup("About");
2098	about->MakeNullParameter(0, B_MEDIA_NO_TYPE, about->Name(), B_GENERIC);
2099	SetAboutInfo(about);
2100
2101	BString sInterfaceType = "Interface Type: ";
2102	BString sFrequency = "Frequency: ";
2103	BString sAudioPid = "Audio PID: ";
2104	BString sVideoPid = "Video PID: ";
2105	BString sPcrPid = "PCR PID: ";
2106	BString sInversion = "Inversion: ";
2107	BString sBandwidth = "Bandwith: ";
2108	BString sModulation = "Modulation: ";
2109	BString sHierarchy = "Hierarchy: ";
2110	BString sCodeRateHP = "Code Rate HP: ";
2111	BString sCodeRateLP = "Code Rate LP: ";
2112	BString sTransmissionMode = "Transmission Mode: ";
2113	BString sGuardInterval = "Guard Interval: ";
2114
2115	BString sSymbolRate = "Symbol Rate: ";
2116	BString sPolarity = "Polarity: ";
2117	BString sAgcInversion = "AGC Inversion: ";
2118
2119	switch (fInterfaceType) {
2120		case DVB_TYPE_DVB_C: sInterfaceType << "DVB-C"; break;
2121		case DVB_TYPE_DVB_H: sInterfaceType << "DVB-H"; break;
2122		case DVB_TYPE_DVB_S: sInterfaceType << "DVB-S"; break;
2123		case DVB_TYPE_DVB_T: sInterfaceType << "DVB-T"; break;
2124		default: sInterfaceType << "unknown"; break;
2125	}
2126
2127	sAudioPid << fAudioPid;
2128	sVideoPid << fVideoPid;
2129	sPcrPid << fPcrPid;
2130
2131	if (fInterfaceType == DVB_TYPE_DVB_T) {
2132
2133		sFrequency << fTuningParam.u.dvb_t.frequency / 1000000 << " MHz";
2134
2135		switch (fTuningParam.u.dvb_t.inversion) {
2136			case DVB_INVERSION_AUTO: sInversion << "auto"; break;
2137			case DVB_INVERSION_ON: sInversion << "on"; break;
2138			case DVB_INVERSION_OFF: sInversion << "off"; break;
2139			default: sInversion << "unknown"; break;
2140		}
2141
2142		switch (fTuningParam.u.dvb_t.bandwidth) {
2143			case DVB_BANDWIDTH_AUTO: sBandwidth << "auto"; break;
2144			case DVB_BANDWIDTH_6_MHZ: sBandwidth << "6 MHz"; break;
2145			case DVB_BANDWIDTH_7_MHZ: sBandwidth << "7 MHz"; break;
2146			case DVB_BANDWIDTH_8_MHZ: sBandwidth << "8 MHz"; break;
2147			default: sBandwidth << "unknown"; break;
2148		}
2149
2150		switch (fTuningParam.u.dvb_t.modulation) {
2151			case DVB_MODULATION_AUTO: sModulation << "auto"; break;
2152			case DVB_MODULATION_QPSK: sModulation << "QPSK"; break;
2153			case DVB_MODULATION_16_QAM: sModulation << "16 QAM"; break;
2154			case DVB_MODULATION_32_QAM: sModulation << "32 QAM"; break;
2155			case DVB_MODULATION_64_QAM: sModulation << "64 QAM"; break;
2156			case DVB_MODULATION_128_QAM: sModulation << "128 QAM"; break;
2157			case DVB_MODULATION_256_QAM: sModulation << "256 QAM"; break;
2158			default: sModulation << "unknown"; break;
2159		}
2160
2161		switch (fTuningParam.u.dvb_t.hierarchy) {
2162			case DVB_HIERARCHY_AUTO: sHierarchy << "auto"; break;
2163			case DVB_HIERARCHY_NONE: sHierarchy << "none"; break;
2164			case DVB_HIERARCHY_1: sHierarchy << "1"; break;
2165			case DVB_HIERARCHY_2: sHierarchy << "2"; break;
2166			case DVB_HIERARCHY_4: sHierarchy << "4"; break;
2167			default: sHierarchy << "unknown"; break;
2168		}
2169
2170		switch (fTuningParam.u.dvb_t.code_rate_hp) {
2171			case DVB_FEC_AUTO: sCodeRateHP << "auto"; break;
2172			case DVB_FEC_NONE: sCodeRateHP << "none"; break;
2173			case DVB_FEC_1_2: sCodeRateHP << "FEC 1/2"; break;
2174			case DVB_FEC_2_3: sCodeRateHP << "FEC 2/3"; break;
2175			case DVB_FEC_3_4: sCodeRateHP << "FEC 3/4"; break;
2176			case DVB_FEC_4_5: sCodeRateHP << "FEC 4/5"; break;
2177			case DVB_FEC_5_6: sCodeRateHP << "FEC 5/6"; break;
2178			case DVB_FEC_6_7: sCodeRateHP << "FEC 6/7"; break;
2179			case DVB_FEC_7_8: sCodeRateHP << "FEC 7/8"; break;
2180			case DVB_FEC_8_9: sCodeRateHP << "FEC 8/9"; break;
2181			default: sCodeRateHP << "unknown"; break;
2182		}
2183
2184		switch (fTuningParam.u.dvb_t.code_rate_lp) {
2185			case DVB_FEC_AUTO: sCodeRateLP << "auto"; break;
2186			case DVB_FEC_NONE: sCodeRateLP << "none"; break;
2187			case DVB_FEC_1_2: sCodeRateLP << "FEC 1/2"; break;
2188			case DVB_FEC_2_3: sCodeRateLP << "FEC 2/3"; break;
2189			case DVB_FEC_3_4: sCodeRateLP << "FEC 3/4"; break;
2190			case DVB_FEC_4_5: sCodeRateLP << "FEC 4/5"; break;
2191			case DVB_FEC_5_6: sCodeRateLP << "FEC 5/6"; break;
2192			case DVB_FEC_6_7: sCodeRateLP << "FEC 6/7"; break;
2193			case DVB_FEC_7_8: sCodeRateLP << "FEC 7/8"; break;
2194			case DVB_FEC_8_9: sCodeRateLP << "FEC 8/9"; break;
2195			default: sCodeRateLP << "unknown"; break;
2196		}
2197
2198		switch (fTuningParam.u.dvb_t.transmission_mode) {
2199			case DVB_TRANSMISSION_MODE_AUTO: sTransmissionMode << "auto"; break;
2200			case DVB_TRANSMISSION_MODE_2K: sTransmissionMode << "2K"; break;
2201			case DVB_TRANSMISSION_MODE_4K: sTransmissionMode << "4K"; break;
2202			case DVB_TRANSMISSION_MODE_8K: sTransmissionMode << "8K"; break;
2203			default: sTransmissionMode << "unknown"; break;
2204		}
2205
2206		switch (fTuningParam.u.dvb_t.guard_interval) {
2207			case DVB_GUARD_INTERVAL_AUTO: sGuardInterval << "auto"; break;
2208			case DVB_GUARD_INTERVAL_1_4: sGuardInterval << "1/4"; break;
2209			case DVB_GUARD_INTERVAL_1_8: sGuardInterval << "1/8"; break;
2210			case DVB_GUARD_INTERVAL_1_16: sGuardInterval << "1/16"; break;
2211			case DVB_GUARD_INTERVAL_1_32: sGuardInterval << "1/32"; break;
2212			default: sGuardInterval << "unknown"; break;
2213		}
2214
2215		info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, sInterfaceType.String(), B_GENERIC);
2216		info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, sFrequency.String(), B_GENERIC);
2217		info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, sBandwidth.String(), B_GENERIC);
2218		info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, sVideoPid.String(), B_GENERIC);
2219		info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, sAudioPid.String(), B_GENERIC);
2220		info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, sPcrPid.String(), B_GENERIC);
2221
2222		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sModulation.String(), B_GENERIC);
2223		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sTransmissionMode.String(), B_GENERIC);
2224		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sGuardInterval.String(), B_GENERIC);
2225		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sCodeRateHP.String(), B_GENERIC);
2226		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sCodeRateLP.String(), B_GENERIC);
2227		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sInversion.String(), B_GENERIC);
2228		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sHierarchy.String(), B_GENERIC);
2229	}
2230
2231	if (fInterfaceType == DVB_TYPE_DVB_S) {
2232
2233		sFrequency << fTuningParam.u.dvb_s.frequency / 1000000 << " MHz";
2234		sSymbolRate << fTuningParam.u.dvb_s.symbolrate;
2235
2236		switch (fTuningParam.u.dvb_s.inversion) {
2237			case DVB_INVERSION_AUTO: sInversion << "auto"; break;
2238			case DVB_INVERSION_ON: sInversion << "on"; break;
2239			case DVB_INVERSION_OFF: sInversion << "off"; break;
2240			default: sInversion << "unknown"; break;
2241		}
2242
2243		switch (fTuningParam.u.dvb_s.polarity) {
2244			case DVB_POLARITY_VERTICAL: sPolarity << "vertical"; break;
2245			case DVB_POLARITY_HORIZONTAL: sPolarity << "horizontal"; break;
2246			default: sPolarity << "unknown"; break;
2247		}
2248
2249		info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, sInterfaceType.String(), B_GENERIC);
2250		info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, sVideoPid.String(), B_GENERIC);
2251		info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, sAudioPid.String(), B_GENERIC);
2252		info1->MakeNullParameter(0, B_MEDIA_NO_TYPE, sPcrPid.String(), B_GENERIC);
2253
2254		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sFrequency.String(), B_GENERIC);
2255		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sPolarity.String(), B_GENERIC);
2256		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sSymbolRate.String(), B_GENERIC);
2257		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sInversion.String(), B_GENERIC);
2258		info2->MakeNullParameter(0, B_MEDIA_NO_TYPE, sAgcInversion.String(), B_GENERIC);
2259	}
2260
2261	return web;
2262}
2263
2264
2265void
2266DVBMediaNode::LoadSettings()
2267{
2268	TRACE("DVBMediaNode::LoadSettings\n");
2269	RefreshStateList();
2270	fSelectedState = 0;
2271	RefreshRegionList();
2272	fSelectedRegion = 0;
2273	RefreshChannelList();
2274	fSelectedChannel = 0;
2275	RefreshAudioList();
2276	fSelectedAudio = 0;
2277}
2278
2279
2280void
2281DVBMediaNode::RefreshStateList()
2282{
2283	TRACE("DVBMediaNode::RefreshStateList\n");
2284
2285	fStateList->MakeEmpty();
2286	fSelectedState = -1;
2287
2288	const char *dir;
2289	switch (fInterfaceType) {
2290		case DVB_TYPE_DVB_C: dir = "/boot/home/config/settings/Media/dvb/dvb-c channels"; break;
2291		case DVB_TYPE_DVB_H: dir = "/boot/home/config/settings/Media/dvb/dvb-h channels"; break;
2292		case DVB_TYPE_DVB_S: dir = "/boot/home/config/settings/Media/dvb/dvb-s channels"; break;
2293		case DVB_TYPE_DVB_T: dir = "/boot/home/config/settings/Media/dvb/dvb-t channels"; break;
2294		default:
2295			printf("DVBMediaNode::RefreshStateList unknown interface type\n");
2296			return;
2297	}
2298
2299	TRACE("loading channel lists from dir = %s\n", dir);
2300
2301	BDirectory d(dir);
2302	BEntry e;
2303	BPath p;
2304	while (B_OK == d.GetNextEntry(&e, false)) {
2305		if (B_OK != e.GetPath(&p))
2306			continue;
2307		fStateList->AddItem(p.Path());
2308	}
2309
2310	if (fStateList->ItemAt(0))
2311		fSelectedState = 0;
2312}
2313
2314
2315void
2316DVBMediaNode::RefreshRegionList()
2317{
2318	TRACE("DVBMediaNode::RefreshRegionList\n");
2319
2320	fRegionList->MakeEmpty();
2321	fSelectedRegion = -1;
2322
2323	const char *dir = fStateList->ItemAt(fSelectedState);
2324	if (!dir)
2325		return;
2326
2327	BDirectory d(dir);
2328	BEntry e;
2329	BPath p;
2330	while (B_OK == d.GetNextEntry(&e, false)) {
2331		if (B_OK != e.GetPath(&p))
2332			continue;
2333		fRegionList->AddItem(p.Path());
2334	}
2335
2336	if (fRegionList->ItemAt(0))
2337		fSelectedRegion = 0;
2338}
2339
2340
2341void
2342DVBMediaNode::RefreshChannelList()
2343{
2344	TRACE("DVBMediaNode::RefreshChannelList\n");
2345
2346	fChannelList->MakeEmpty();
2347	fSelectedChannel = -1;
2348
2349	const char *path = fRegionList->ItemAt(fSelectedRegion);
2350	if (!path)
2351		return;
2352
2353	TRACE("opening channel list file = %s\n", path);
2354
2355	FILE *f = fopen(path, "r");
2356	if (!f)
2357		return;
2358
2359	char line[1024];
2360	while (fgets(line, sizeof(line), f)) {
2361		if (line[0] == ':') // skip comments
2362			continue;
2363		if (strchr(line, ':') == NULL)	// skip empty lines
2364			continue;
2365		fChannelList->AddItem(line);
2366	}
2367
2368	fclose(f);
2369
2370	if (fChannelList->ItemAt(0))
2371		fSelectedChannel = 0;
2372}
2373
2374
2375void
2376DVBMediaNode::RefreshAudioList()
2377{
2378	TRACE("DVBMediaNode::RefreshAudioList\n");
2379
2380	fAudioList->MakeEmpty();
2381	fSelectedAudio = -1;
2382
2383	fAudioList->AddItem("default"); // XXX test
2384
2385	if (fAudioList->ItemAt(0))
2386		fSelectedAudio = 0;
2387}
2388
2389
2390void
2391DVBMediaNode::AddStateItems(BDiscreteParameter *param)
2392{
2393	TRACE("DVBMediaNode::AddStateItems\n");
2394
2395	const char *str;
2396	for (int i = 0; (str = fStateList->ItemAt(i)); i++) {
2397		str = strrchr(str, '/');
2398		if (!str)
2399			continue;
2400		str++;
2401		param->AddItem(i, str);
2402	}
2403	if (param->CountItems() == 0)
2404		param->AddItem(-1, "none");
2405}
2406
2407
2408void
2409DVBMediaNode::AddRegionItems(BDiscreteParameter *param)
2410{
2411	TRACE("DVBMediaNode::AddRegionItems\n");
2412
2413	const char *str;
2414	for (int i = 0; (str = fRegionList->ItemAt(i)); i++) {
2415		str = strrchr(str, '/');
2416		if (!str)
2417			continue;
2418		str++;
2419		param->AddItem(i, str);
2420	}
2421	if (param->CountItems() == 0)
2422		param->AddItem(-1, "none");
2423}
2424
2425
2426void
2427DVBMediaNode::AddChannelItems(BDiscreteParameter *param)
2428{
2429	TRACE("DVBMediaNode::AddChannelItems\n");
2430
2431	const char *str;
2432	for (int i = 0; (str = fChannelList->ItemAt(i)); i++) {
2433		char name[256];
2434//		sscanf(str, "%s:", name);
2435		sscanf(str, "%[^:]", name);
2436		param->AddItem(i, name);
2437
2438	}
2439	if (param->CountItems() == 0)
2440		param->AddItem(-1, "none");
2441}
2442
2443
2444void
2445DVBMediaNode::AddAudioItems(BDiscreteParameter *param)
2446{
2447	TRACE("DVBMediaNode::AddAudioItems\n");
2448
2449	if (param->CountItems() == 0)
2450		param->AddItem(-1, "default");
2451}
2452
2453
2454status_t
2455DVBMediaNode::GetParameterValue(int32 id, bigtime_t *last_change, void *value, size_t *size)
2456{
2457//	TRACE("DVBMediaNode::GetParameterValue, id 0x%lx\n", id);
2458
2459	switch (id) {
2460		case ID_STATE:   *size = 4; *(int32 *)value = fSelectedState; break;
2461		case ID_REGION:  *size = 4; *(int32 *)value = fSelectedRegion; break;
2462		case ID_CHANNEL: *size = 4; *(int32 *)value = fSelectedChannel; break;
2463		case ID_AUDIO:   *size = 4; *(int32 *)value = fSelectedAudio; break;
2464		default: 		 return B_ERROR;
2465	}
2466	return B_OK;
2467}
2468
2469
2470void
2471DVBMediaNode::SetParameterValue(int32 id, bigtime_t when, const void *value, size_t size)
2472{
2473	TRACE("DVBMediaNode::SetParameterValue, id 0x%lx, size %ld, value 0x%lx\n", id, size, *(const int32 *)value);
2474
2475	switch (id) {
2476		case ID_STATE:
2477			fSelectedState = *(const int32 *)value;
2478			StopCapture();
2479			RefreshRegionList();
2480			RefreshChannelList();
2481			RefreshAudioList();
2482			EventQueue()->AddEvent(media_timed_event(0, M_REFRESH_PARAMETER_WEB));
2483//			Tune();
2484			break;
2485
2486		case ID_REGION:
2487			fSelectedRegion = *(const int32 *)value;
2488			StopCapture();
2489			RefreshChannelList();
2490			RefreshAudioList();
2491			EventQueue()->AddEvent(media_timed_event(0, M_REFRESH_PARAMETER_WEB));
2492//			Tune();
2493			break;
2494
2495		case ID_CHANNEL:
2496			fSelectedChannel = *(const int32 *)value;
2497			RefreshAudioList();
2498//			EventQueue()->AddEvent(media_timed_event(0, M_REFRESH_PARAMETER_WEB));
2499			Tune();
2500			break;
2501
2502		case ID_AUDIO:
2503			fSelectedAudio = *(const int32 *)value;
2504			Tune();
2505			break;
2506
2507		default:
2508			break;
2509	}
2510	TRACE("DVBMediaNode::SetParameterValue finished\n");
2511}
2512
2513
2514status_t
2515DVBMediaNode::ExtractTuningParams(const char *description, int audio_pid_index,
2516								  dvb_tuning_parameters_t *tuning_param,
2517								  int *video_pid, int *audio_pid, int *pcr_pid)
2518{
2519	if (!description)
2520		return B_ERROR;
2521
2522	printf("ExtractTuningParams: \"%s\"\n", description);
2523
2524	char name[50];
2525	char freq[50];
2526	char para[100];
2527	char src[50];
2528	char srate[50];
2529	char vpid[50];
2530	char apid[50];
2531	char tpid[50];
2532	char ca[50];
2533	char sid[50];
2534	char nid[50];
2535	char tid[50];
2536	char rid[50];
2537
2538	sscanf(description, " %[^:] : %[^:] : %[^:] : %[^:] : %[^:] : %[^:] : %[^:] : %[^:] : %[^:] : %[^:] : %[^:] : %[^:] : %[^:] ",
2539		name, freq, para, src, srate, vpid, apid, tpid, ca, sid, nid, tid, rid);
2540
2541	char *cpid = strchr(vpid, '+');
2542	if (cpid) cpid++;
2543
2544	int _vpid = strtol(vpid, 0, 0);
2545	int _apid = strtol(apid, 0, 0);
2546//	int _tpid = strtol(tpid, 0, 0);
2547	int _cpid = cpid ? strtol(cpid, 0, 0) : _vpid;
2548	int _srate = strtol(srate, 0, 0);
2549	int64 _freq = strtol(freq, 0, 0);
2550	while (_freq && _freq <= 1000000)
2551		_freq *= 1000;
2552
2553	if (fInterfaceType == DVB_TYPE_DVB_S && _freq < 950000000) {
2554		TRACE("workaround activated: type is DVB_S and frequency < 950 MHz, multiplying by 1000!\n");
2555		_freq *= 1000;
2556	}
2557
2558
2559	*video_pid = _vpid;
2560	*audio_pid = _apid;
2561	*pcr_pid   = _cpid;
2562
2563	TRACE("parsing result: params: '%s'\n", para);
2564
2565	TRACE("parsing result: video pid %d\n", _vpid);
2566	TRACE("parsing result: audio pid %d\n", _apid);
2567	TRACE("parsing result: PCR pid %d\n", _cpid);
2568	TRACE("parsing result: symbol rate %d\n", _srate);
2569	TRACE("parsing result: Frequency %Ld Hz, %Ld MHz\n", _freq, _freq / 1000000);
2570
2571	if (fInterfaceType == DVB_TYPE_DVB_T) {
2572
2573		dvb_t_tuning_parameters_t *param = &tuning_param->u.dvb_t;
2574
2575		TRACE("Interface is DVB-T\n");
2576		param->frequency = _freq;
2577		param->inversion = DVB_INVERSION_OFF;
2578		param->bandwidth = DVB_BANDWIDTH_8_MHZ;
2579		param->modulation = DVB_MODULATION_16_QAM;
2580		param->hierarchy = DVB_HIERARCHY_NONE;
2581		param->code_rate_hp = DVB_FEC_2_3;
2582		param->code_rate_lp = DVB_FEC_2_3;
2583		param->transmission_mode = DVB_TRANSMISSION_MODE_8K;
2584		param->guard_interval = DVB_GUARD_INTERVAL_1_4;
2585	}
2586
2587	if (fInterfaceType == DVB_TYPE_DVB_S) {
2588		dvb_s_tuning_parameters_t *param = &tuning_param->u.dvb_s;
2589
2590		TRACE("Interface is DVB-S\n");
2591
2592		const char *pInv = strchr(para, 'I');
2593		if (!pInv)
2594			pInv = strchr(para, 'i');
2595		if (pInv && pInv[1] == '0') {
2596			TRACE("DVB_INVERSION_OFF\n");
2597			param->inversion = DVB_INVERSION_OFF;
2598		} else if (pInv && pInv[1] == '1') {
2599			TRACE("DVB_INVERSION_ON\n");
2600			param->inversion = DVB_INVERSION_ON;
2601		} else {
2602			TRACE("parse error, assuming DVB_INVERSION_OFF\n");
2603			param->inversion = DVB_INVERSION_OFF;
2604		}
2605
2606		const char *pPolH = strchr(para, 'H');
2607		if (!pPolH)
2608			pPolH = strchr(para, 'h');
2609		const char *pPolV = strchr(para, 'V');
2610		if (!pPolV)
2611			pPolV = strchr(para, 'v');
2612		if (pPolH && !pPolV) {
2613			TRACE("DVB_POLARITY_HORIZONTAL\n");
2614			param->polarity = DVB_POLARITY_HORIZONTAL;
2615		} else if (!pPolH && pPolV) {
2616			TRACE("DVB_POLARITY_VERTICAL\n");
2617			param->polarity = DVB_POLARITY_VERTICAL;
2618		} else {
2619			TRACE("parse error, assuming DVB_POLARITY_HORIZONTAL\n");
2620			param->polarity = DVB_POLARITY_HORIZONTAL;
2621		}
2622
2623		param->frequency = _freq;
2624		param->symbolrate = _srate;
2625	}
2626
2627	return B_OK;
2628}
2629