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