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