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