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