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