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