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