1 /* ------------------------------------------------------------------ 2 * Copyright (C) 1998-2009 PacketVideo 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 * express or implied. 14 * See the License for the specific language governing permissions 15 * and limitations under the License. 16 * ------------------------------------------------------------------- 17 */ 18 #include "pvmi_media_io_fileoutput.h" 19 #include "pvlogger.h" 20 #include "pv_mime_string_utils.h" 21 #include "oscl_snprintf.h" 22 #include "pvmf_timedtext.h" 23 #include "oscl_file_io.h" 24 25 #include "oscl_dll.h" 26 27 #include "pvmf_video.h" 28 #include "pvmf_common_audio_decnode.h" 29 30 #define LOG_OUTPUT_TO_FILE 1 31 32 // Define entry point for this DLL 33 OSCL_DLL_ENTRY_POINT_DEFAULT() 34 35 //The factory functions. 36 #include "pvmi_media_io_fileoutput_registry_factory.h" 37 #include "oscl_mem.h" 38 39 #define QUEUE_LIMIT 10 40 41 OSCL_EXPORT_REF PvmiMIOControl* PVMFMediaFileOutputRegistryFactory::CreateMediaIO(OsclAny* aParam) 42 { 43 PVRefFileOutput* ptr = OSCL_NEW 44 45 (PVRefFileOutput, ((oscl_wchar*)aParam)); 46 return ptr; 47 } 48 49 OSCL_EXPORT_REF void PVMFMediaFileOutputRegistryFactory::ReleaseMediaIO(PvmiMIOControl* aNode) 50 { 51 OSCL_DELETE(aNode); 52 } 53 54 // This class implements the reference media IO for file output 55 // This class constitutes the Media IO component 56 57 58 OSCL_EXPORT_REF PVRefFileOutput::PVRefFileOutput(const OSCL_wString& aFileName, bool logStrings) 59 : OsclTimerObject(OsclActiveObject::EPriorityNominal, "pvreffileoutput") 60 , iOutputFileName(aFileName) 61 #if (LOG_OUTPUT_TO_FILE) 62 , iLogOutputToFile(true) 63 #else 64 , iLogOutputToFile(false) 65 #endif 66 { 67 initData(); 68 iLogStrings = logStrings; 69 iMediaType = MEDIATYPE_UNKNOWN; 70 } 71 72 73 OSCL_EXPORT_REF PVRefFileOutput::PVRefFileOutput(const OSCL_wString& aFileName 74 , PVRefFileOutputTestObserver*aTestObs 75 , bool aSimTiming, uint32 aQueueLimit 76 , bool aSimFlowControl 77 , bool logStrings) 78 : OsclTimerObject(OsclActiveObject::EPriorityNominal, "pvreffileoutput") 79 , iOutputFileName(aFileName) 80 #if (LOG_OUTPUT_TO_FILE) 81 , iLogOutputToFile(true) 82 #else 83 , iLogOutputToFile(false) 84 #endif 85 { 86 initData(); 87 //test features... 88 iSimFlowControl = aSimFlowControl; 89 iTestObserver = aTestObs; 90 iActiveTiming = NULL; 91 iMediaType = MEDIATYPE_UNKNOWN; 92 if (aSimTiming) 93 { 94 OsclMemAllocator alloc; 95 OsclAny*ptr = alloc.allocate(sizeof(PVRefFileOutputActiveTimingSupport)); 96 if (ptr) 97 { 98 iActiveTiming = OSCL_PLACEMENT_NEW(ptr, PVRefFileOutputActiveTimingSupport(aQueueLimit)); 99 } 100 // For active MIO assuming it to be audio MIO. 101 iMediaType = MEDIATYPE_AUDIO; 102 } 103 iLogStrings = logStrings; 104 iParametersLogged = false; 105 } 106 107 OSCL_EXPORT_REF PVRefFileOutput::PVRefFileOutput(const oscl_wchar* aFileName 108 , bool aActiveTiming) 109 : OsclTimerObject(OsclActiveObject::EPriorityNominal, "pvreffileoutput") 110 , iOutputFileName(aFileName) 111 #if (LOG_OUTPUT_TO_FILE) 112 , iLogOutputToFile(true) 113 #else 114 , iLogOutputToFile(false) 115 #endif 116 { 117 initData(); 118 iActiveTiming = NULL; 119 iMediaType = MEDIATYPE_UNKNOWN; 120 if (aActiveTiming) 121 { 122 OsclMemAllocator alloc; 123 OsclAny*ptr = alloc.allocate(sizeof(PVRefFileOutputActiveTimingSupport)); 124 if (ptr) 125 { 126 iActiveTiming = OSCL_PLACEMENT_NEW(ptr, PVRefFileOutputActiveTimingSupport(QUEUE_LIMIT)); 127 } 128 // For active MIO assuming it to be audio MIO. 129 iMediaType = MEDIATYPE_AUDIO; 130 } 131 } 132 133 OSCL_EXPORT_REF PVRefFileOutput::PVRefFileOutput(const oscl_wchar* aFileName, 134 MediaType aMediaType, 135 bool aCompressedMedia) 136 : OsclTimerObject(OsclActiveObject::EPriorityNominal, "pvreffileoutput") 137 , iOutputFileName(aFileName) 138 , iMediaType(aMediaType) 139 , iCompressedMedia(aCompressedMedia) 140 #if (LOG_OUTPUT_TO_FILE) 141 , iLogOutputToFile(true) 142 #else 143 , iLogOutputToFile(false) 144 #endif 145 { 146 initData(); 147 } 148 149 void PVRefFileOutput::initData() 150 { 151 iAudioFormat = PVMF_MIME_FORMAT_UNKNOWN; 152 iAudioNumChannelsValid = false; 153 iAudioSamplingRateValid = false; 154 155 iVideoFormat = PVMF_MIME_FORMAT_UNKNOWN; 156 iVideoHeightValid = false; 157 iVideoWidthValid = false; 158 iVideoDisplayHeightValid = false; 159 iVideoDisplayWidthValid = false; 160 161 iCommandCounter = 0; 162 iLogger = NULL; 163 iFileOpened = false; 164 iFsConnected = false; 165 iCommandResponseQueue.reserve(5); 166 iWriteResponseQueue.reserve(5); 167 iObserver = NULL; 168 iLogger = NULL; 169 iPeer = NULL; 170 iState = STATE_IDLE; 171 iWriteBusy = false; 172 iWriteBusySeqNum = 0; 173 174 //test features... 175 iSimFlowControl = false; 176 iTestObserver = NULL; 177 iActiveTiming = NULL; 178 iLogStrings = false; 179 iParametersLogged = false; 180 iFormatMask = 0; 181 iTextFormat = PVMF_MIME_FORMAT_UNKNOWN; 182 iUseClockExtension = false; 183 iRIFFChunk.chunkID = FOURCC_RIFF;//0x46464952; //"RIFF" in ASCII form, big-endian form 184 iRIFFChunk.chunkSize = 0; 185 iRIFFChunk.format = FOURCC_WAVE;//0x45564157; //"WAVE" in ASCII form, big-endian form 186 187 iFmtSubchunk.subchunk1ID = FOURCC_fmt;//0x20746d66; //"fmt " in ASCII form, big-endian form 188 iFmtSubchunk.subchunk1Size = 16; //for PCM16 189 iFmtSubchunk.audioFormat = 1; //PCM = 1 190 iFmtSubchunk.numChannels = 0; 191 iFmtSubchunk.sampleRate = 0; 192 iFmtSubchunk.byteRate = 0; 193 iFmtSubchunk.blockAlign = 0; 194 iFmtSubchunk.bitsPerSample = 16; 195 196 iDataSubchunk.subchunk2ID = FOURCC_data;//0x61746164; //"data" in ASCII form, big-endian form 197 iDataSubchunk.subchunk2Size = 0; 198 199 iHeaderWritten = false; 200 iAudioFormat = 0; 201 iVideoFormat = 0; 202 iInitializeAVIDone = false; 203 iAVIChunkSize = 0; 204 iVideoLastTimeStamp = 0; 205 iVideoCount = 0; 206 iIsMIOConfigured = false; 207 iClock = NULL; 208 //Connect with file server. 209 if (!iFsConnected) 210 { 211 if (iFs.Connect() == 0) 212 { 213 iFsConnected = true; 214 } 215 else 216 { 217 OSCL_ASSERT(false); 218 } 219 } 220 } 221 222 void PVRefFileOutput::setUserClockExtnInterface(bool aEnable) 223 { 224 if (aEnable == true) 225 { 226 iUseClockExtension = true; 227 } 228 else 229 { 230 iUseClockExtension = false; 231 } 232 233 } 234 235 void PVRefFileOutput::ResetData() 236 //reset all data from this session. 237 { 238 if (iAudioFormat == PVMF_MIME_PCM16 || iAudioFormat == PVMF_MIME_PCM8) 239 { 240 UpdateWaveChunkSize(); 241 } 242 243 if (iVideoFormat == PVMF_MIME_YUV420) 244 { 245 UpdateVideoChunkHeaderIdx(); 246 } 247 Cleanup(); 248 249 //reset all the received media parameters. 250 251 iAudioFormatString = ""; 252 iAudioFormat = PVMF_MIME_FORMAT_UNKNOWN; 253 iAudioNumChannelsValid = false; 254 iAudioSamplingRateValid = false; 255 256 iVideoFormatString = ""; 257 iVideoFormat = PVMF_MIME_FORMAT_UNKNOWN; 258 iVideoHeightValid = false; 259 iVideoWidthValid = false; 260 iVideoDisplayHeightValid = false; 261 iVideoDisplayWidthValid = false; 262 iIsMIOConfigured = false; 263 264 iTextFormatString = ""; 265 iTextFormat = PVMF_MIME_FORMAT_UNKNOWN; 266 267 iParametersLogged = false; 268 } 269 270 void PVRefFileOutput::Cleanup() 271 //cleanup all allocated memory and release resources. 272 { 273 if (iFileOpened) 274 { 275 iOutputFile.Flush(); 276 iOutputFile.Close(); 277 } 278 iFileOpened = false; 279 280 while (!iCommandResponseQueue.empty()) 281 { 282 if (iObserver) 283 { 284 iObserver->RequestCompleted(PVMFCmdResp(iCommandResponseQueue[0].iCmdId, iCommandResponseQueue[0].iContext, iCommandResponseQueue[0].iStatus)); 285 } 286 iCommandResponseQueue.erase(&iCommandResponseQueue[0]); 287 } 288 while (!iWriteResponseQueue.empty()) 289 { 290 if (iPeer) 291 { 292 iPeer->writeComplete(iWriteResponseQueue[0].iStatus, iWriteResponseQueue[0].iCmdId, (OsclAny*)iWriteResponseQueue[0].iContext); 293 } 294 iWriteResponseQueue.erase(&iWriteResponseQueue[0]); 295 } 296 } 297 298 PVRefFileOutput::~PVRefFileOutput() 299 { 300 Cleanup(); 301 302 if (iActiveTiming) 303 { 304 iActiveTiming->~PVRefFileOutputActiveTimingSupport(); 305 OsclMemAllocator alloc; 306 alloc.deallocate(iActiveTiming); 307 iActiveTiming = NULL; 308 } 309 310 if (iFsConnected) 311 { 312 iFs.Close(); 313 } 314 iFsConnected = false; 315 } 316 317 318 PVMFStatus PVRefFileOutput::connect(PvmiMIOSession& aSession, PvmiMIOObserver* aObserver) 319 { 320 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::connect() called")); 321 // Each Session could have its own set of Comfiguration parametres 322 //in an array of structures and the session ID could be an index to that array. 323 324 OSCL_UNUSED_ARG(aSession); 325 //currently supports only one session 326 if (iObserver) 327 { 328 return PVMFFailure; 329 } 330 331 iObserver = aObserver; 332 return PVMFSuccess; 333 } 334 335 336 PVMFStatus PVRefFileOutput::disconnect(PvmiMIOSession aSession) 337 { 338 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::disconnect() called")); 339 OSCL_UNUSED_ARG(aSession); 340 341 // just set the observer to NULL, any command completes should be done before disconnect. 342 iObserver = NULL; 343 return PVMFSuccess; 344 } 345 346 347 PvmiMediaTransfer* PVRefFileOutput::createMediaTransfer(PvmiMIOSession& aSession, 348 PvmiKvp* read_formats, int32 read_flags, 349 PvmiKvp* write_formats, int32 write_flags) 350 { 351 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::createMediaTransfer() called")); 352 353 OSCL_UNUSED_ARG(aSession); 354 OSCL_UNUSED_ARG(read_formats); 355 OSCL_UNUSED_ARG(read_flags); 356 OSCL_UNUSED_ARG(write_formats); 357 OSCL_UNUSED_ARG(write_flags); 358 359 return (PvmiMediaTransfer*)this; 360 } 361 362 void PVRefFileOutput::QueueCommandResponse(CommandResponse& aResp) 363 { 364 //queue a command response and schedule processing. 365 366 iCommandResponseQueue.push_back(aResp); 367 368 //cancel any timer delay so the command response will happen ASAP. 369 if (IsBusy()) 370 { 371 Cancel(); 372 } 373 374 RunIfNotReady(); 375 } 376 377 PVMFCommandId PVRefFileOutput::QueryUUID(const PvmfMimeString& aMimeType, 378 Oscl_Vector<PVUuid, OsclMemAllocator>& aUuids, 379 bool aExactUuidsOnly, const OsclAny* aContext) 380 { 381 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::QueryUUID() called")); 382 383 OSCL_UNUSED_ARG(aMimeType); 384 OSCL_UNUSED_ARG(aExactUuidsOnly); 385 386 PVMFCommandId cmdid = iCommandCounter++; 387 388 PVMFStatus status = PVMFFailure; 389 int32 err ; 390 OSCL_TRY(err, 391 aUuids.push_back(PVMI_CAPABILITY_AND_CONFIG_PVUUID); 392 if (iActiveTiming) 393 { 394 PVUuid uuid; 395 iActiveTiming->queryUuid(uuid); 396 aUuids.push_back(uuid); 397 } 398 ); 399 if (err == OsclErrNone) 400 { 401 status = PVMFSuccess; 402 } 403 404 CommandResponse resp(status, cmdid, aContext); 405 QueueCommandResponse(resp); 406 return cmdid; 407 } 408 409 410 PVMFCommandId PVRefFileOutput::QueryInterface(const PVUuid& aUuid, PVInterface*& aInterfacePtr, const OsclAny* aContext) 411 { 412 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::QueryInterface() called")); 413 414 PVMFCommandId cmdid = iCommandCounter++; 415 416 PVMFStatus status = PVMFFailure; 417 if (aUuid == PVMI_CAPABILITY_AND_CONFIG_PVUUID) 418 { 419 PvmiCapabilityAndConfig* myInterface = OSCL_STATIC_CAST(PvmiCapabilityAndConfig*, this); 420 aInterfacePtr = OSCL_STATIC_CAST(PVInterface*, myInterface); 421 status = PVMFSuccess; 422 } 423 else if (aUuid == PvmiClockExtensionInterfaceUuid) 424 { 425 //the clock extension interface is present only when the component 426 //has active timing. 427 if (iActiveTiming) 428 { 429 PvmiClockExtensionInterface* myInterface = OSCL_STATIC_CAST(PvmiClockExtensionInterface*, iActiveTiming); 430 aInterfacePtr = OSCL_STATIC_CAST(PVInterface*, myInterface); 431 status = PVMFSuccess; 432 } 433 else if (iUseClockExtension == true) 434 { 435 PvmiClockExtensionInterface* myInterface = OSCL_STATIC_CAST(PvmiClockExtensionInterface*, this); 436 aInterfacePtr = OSCL_STATIC_CAST(PVInterface*, myInterface); 437 status = PVMFSuccess; 438 } 439 else 440 { 441 status = PVMFFailure; 442 } 443 } 444 else 445 { 446 status = PVMFFailure; 447 } 448 449 CommandResponse resp(status, cmdid, aContext); 450 QueueCommandResponse(resp); 451 return cmdid; 452 } 453 454 455 void PVRefFileOutput::deleteMediaTransfer(PvmiMIOSession& aSession, PvmiMediaTransfer* media_transfer) 456 { 457 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::deleteMediaTransfer() called")); 458 OSCL_UNUSED_ARG(aSession); 459 OSCL_UNUSED_ARG(media_transfer); 460 461 if (iWriteResponseQueue.empty() == false) 462 { 463 // All media transfer requests are not completed yet. Do a leave 464 OSCL_LEAVE(OsclErrBusy); 465 // return; This statement was removed to avoid compiler warning for Unreachable Code 466 } 467 468 if (iPeer) 469 { 470 // Since media transfer is gone, peer is gone as well 471 iPeer = NULL; 472 } 473 } 474 475 476 PVMFCommandId PVRefFileOutput:: Init(const OsclAny* aContext) 477 { 478 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::Init() called")); 479 480 PVMFCommandId cmdid = iCommandCounter++; 481 482 PVMFStatus status = PVMFFailure; 483 484 switch (iState) 485 { 486 case STATE_LOGGED_ON: 487 if (!iFileOpened) 488 { 489 if (iOutputFile.Open(iOutputFileName.get_cstr(), Oscl_File::MODE_READWRITE | Oscl_File::MODE_BINARY, iFs) != 0) 490 { 491 status = PVMFFailure; 492 } 493 else 494 { 495 status = PVMFSuccess; 496 iFileOpened = true; 497 } 498 } 499 else 500 { 501 status = PVMFSuccess; 502 iFileOpened = true; 503 } 504 if (status == PVMFSuccess) 505 { 506 iState = STATE_INITIALIZED; 507 } 508 break; 509 510 default: 511 status = PVMFErrInvalidState; 512 break; 513 } 514 515 CommandResponse resp(status, cmdid, aContext); 516 QueueCommandResponse(resp); 517 return cmdid; 518 } 519 520 PVMFCommandId PVRefFileOutput::Reset(const OsclAny* aContext) 521 { 522 // Reset all data from this session 523 ResetData(); 524 525 // TEMP to properly behave asynchronously 526 PVMFCommandId cmdid = iCommandCounter++; 527 CommandResponse resp(PVMFSuccess, cmdid, aContext); 528 QueueCommandResponse(resp); 529 return cmdid; 530 } 531 532 PVMFCommandId PVRefFileOutput::Start(const OsclAny* aContext) 533 { 534 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::Start() called")); 535 536 PVMFCommandId cmdid = iCommandCounter++; 537 538 PVMFStatus status = PVMFFailure; 539 540 switch (iState) 541 { 542 case STATE_INITIALIZED: 543 case STATE_PAUSED: 544 iState = STATE_STARTED; 545 status = PVMFSuccess; 546 547 break; 548 549 default: 550 status = PVMFErrInvalidState; 551 break; 552 } 553 554 CommandResponse resp(status, cmdid, aContext); 555 QueueCommandResponse(resp); 556 return cmdid; 557 } 558 559 560 PVMFCommandId PVRefFileOutput::Pause(const OsclAny* aContext) 561 { 562 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::Pause() called")); 563 564 PVMFCommandId cmdid = iCommandCounter++; 565 566 PVMFStatus status = PVMFFailure; 567 568 switch (iState) 569 { 570 case STATE_STARTED: 571 case STATE_INITIALIZED: 572 case STATE_PAUSED: 573 iState = STATE_PAUSED; 574 status = PVMFSuccess; 575 break; 576 577 default: 578 status = PVMFErrInvalidState; 579 break; 580 } 581 582 CommandResponse resp(status, cmdid, aContext); 583 QueueCommandResponse(resp); 584 return cmdid; 585 } 586 587 588 PVMFCommandId PVRefFileOutput::Flush(const OsclAny* aContext) 589 { 590 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::Flush() called")); 591 592 PVMFCommandId cmdid = iCommandCounter++; 593 594 PVMFStatus status = PVMFFailure; 595 596 switch (iState) 597 { 598 case STATE_STARTED: 599 iOutputFile.Flush(); 600 iState = STATE_INITIALIZED; 601 status = PVMFSuccess; 602 break; 603 604 default: 605 status = PVMFErrInvalidState; 606 break; 607 } 608 609 CommandResponse resp(status, cmdid, aContext); 610 QueueCommandResponse(resp); 611 return cmdid; 612 } 613 614 PVMFCommandId PVRefFileOutput::DiscardData(const OsclAny* aContext) 615 { 616 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::DiscardData() called")); 617 618 PVMFCommandId cmdid = iCommandCounter++; 619 620 //this component doesn't buffer data, so there's nothing 621 //needed here. 622 623 PVMFStatus status = PVMFSuccess; 624 625 CommandResponse resp(status, cmdid, aContext); 626 QueueCommandResponse(resp); 627 return cmdid; 628 } 629 630 PVMFCommandId PVRefFileOutput::DiscardData(PVMFTimestamp aTimestamp, const OsclAny* aContext) 631 { 632 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::DiscardData() called")); 633 634 PVMFCommandId cmdid = iCommandCounter++; 635 636 aTimestamp = 0; 637 638 //this component doesn't buffer data, so there's nothing 639 //needed here. 640 641 PVMFStatus status = PVMFSuccess; 642 643 CommandResponse resp(status, cmdid, aContext); 644 QueueCommandResponse(resp); 645 return cmdid; 646 } 647 648 PVMFCommandId PVRefFileOutput::Stop(const OsclAny* aContext) 649 { 650 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::Stop() called")); 651 652 PVMFCommandId cmdid = iCommandCounter++; 653 654 PVMFStatus status = PVMFFailure; 655 656 switch (iState) 657 { 658 case STATE_STARTED: 659 case STATE_PAUSED: 660 // Add this case because of the following problem: 661 // This mio component may delay its start until it does 662 // configuration based on the first fragment it receives. 663 // If the parent node is stopped before this fragment arrives 664 // it will issue a stop command to this component, which 665 // is still in the initialized state. returning 666 // PVMFErrInvalid state would be unnecessary here 667 // when the component is already in the proper post-stop() 668 // state. 669 case STATE_INITIALIZED: 670 iState = STATE_INITIALIZED; 671 status = PVMFSuccess; 672 break; 673 674 default: 675 status = PVMFErrInvalidState; 676 break; 677 } 678 679 CommandResponse resp(status, cmdid, aContext); 680 QueueCommandResponse(resp); 681 return cmdid; 682 } 683 684 PVMFCommandId PVRefFileOutput::CancelAllCommands(const OsclAny* aContext) 685 { 686 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::CancelAllCommands() called")); 687 688 PVMFCommandId cmdid = iCommandCounter++; 689 690 //commands are executed immediately upon being received, so 691 //it isn't really possible to cancel them. 692 693 PVMFStatus status = PVMFSuccess; 694 695 CommandResponse resp(status, cmdid, aContext); 696 QueueCommandResponse(resp); 697 return cmdid; 698 } 699 700 PVMFCommandId PVRefFileOutput::CancelCommand(PVMFCommandId aCmdId, const OsclAny* aContext) 701 { 702 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::CancelCommand() called")); 703 704 PVMFCommandId cmdid = iCommandCounter++; 705 706 //commands are executed immediately upon being received, so 707 //it isn't really possible to cancel them. 708 709 //see if the response is still queued. 710 PVMFStatus status = PVMFFailure; 711 for (uint32 i = 0; i < iCommandResponseQueue.size(); i++) 712 { 713 if (iCommandResponseQueue[i].iCmdId == aCmdId) 714 { 715 status = PVMFSuccess; 716 break; 717 } 718 } 719 720 CommandResponse resp(status, cmdid, aContext); 721 QueueCommandResponse(resp); 722 return cmdid; 723 } 724 725 void PVRefFileOutput::ThreadLogon() 726 { 727 if (iState == STATE_IDLE) 728 { 729 iLogger = PVLogger::GetLoggerObject("PVRefFileOutput"); 730 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::ThreadLogon() called")); 731 AddToScheduler(); 732 iState = STATE_LOGGED_ON; 733 } 734 } 735 736 737 void PVRefFileOutput::ThreadLogoff() 738 { 739 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::ThreadLogoff() called")); 740 if (iState != STATE_IDLE) 741 { 742 RemoveFromScheduler(); 743 iLogger = NULL; 744 iState = STATE_IDLE; 745 } 746 } 747 748 749 void PVRefFileOutput::setPeer(PvmiMediaTransfer* aPeer) 750 { 751 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::setPeer() called")); 752 // Set the observer 753 iPeer = aPeer; 754 } 755 756 757 void PVRefFileOutput::useMemoryAllocators(OsclMemAllocator* write_alloc) 758 { 759 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::useMemoryAllocators() called")); 760 //not supported. 761 OSCL_UNUSED_ARG(write_alloc); 762 } 763 764 bool PVRefFileOutput::CheckWriteBusy(uint32 aSeqNum) 765 //This routine will determine whether data can be accepted in a writeAsync 766 //call and if not, will return true; 767 { 768 //we don't expect another data transfer when we're already busy. 769 //but if it does occur, leave again. 770 if (iWriteBusy) 771 { 772 PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR, 773 (0, "PVRefFileOutput::LeaveIfBusy: Unexpected call from peer!")); 774 return true; 775 } 776 777 if (iActiveTiming) 778 { 779 //when doing active timing, impose a limit on the number 780 //of queued messages. otherwise the queue may grow without 781 //bound since the caller is sending data ASAP. 782 if (iWriteResponseQueue.size() >= iActiveTiming->iQueueLimit) 783 { 784 return true; 785 } 786 } 787 else 788 { 789 //"sim flow control" is a test feature that causes this component 790 //to simulate a busy condition on every 5th input buffer. 791 if (iSimFlowControl 792 && aSeqNum != iWriteBusySeqNum 793 && ((aSeqNum + 1) % 5 == 0)) 794 { 795 return true; 796 } 797 } 798 799 //for all other cases, accept data now. 800 return false; 801 } 802 803 void PVRefFileOutput::LogParameters() 804 { 805 iParametersLogged = true; 806 if (iLogOutputToFile) 807 { 808 char string[128]; 809 int32 len; 810 if (iVideoFormatString.get_size() > 0) 811 { 812 len = oscl_snprintf(string, 128, "Video Format %s ", iVideoFormatString.get_str()); 813 iOutputFile.Write(string, sizeof(uint8), len) ; 814 } 815 if (iVideoHeightValid) 816 { 817 len = oscl_snprintf(string, 128, "Video Height %d ", iVideoHeight); 818 iOutputFile.Write(string, sizeof(uint8), len) ; 819 } 820 if (iVideoWidthValid) 821 { 822 len = oscl_snprintf(string, 128, "Video Width %d ", iVideoWidth); 823 iOutputFile.Write(string, sizeof(uint8), len) ; 824 } 825 if (iVideoDisplayHeightValid) 826 { 827 len = oscl_snprintf(string, 128, "Video Display Height %d ", iVideoDisplayHeight); 828 iOutputFile.Write(string, sizeof(uint8), len) ; 829 } 830 if (iVideoDisplayWidthValid) 831 { 832 len = oscl_snprintf(string, 128, "Video Display Width %d ", iVideoDisplayWidth); 833 iOutputFile.Write(string, sizeof(uint8), len) ; 834 } 835 if (iAudioFormatString.get_size() > 0) 836 { 837 len = oscl_snprintf(string, 128, "Audio Format %s ", iAudioFormatString.get_str()); 838 iOutputFile.Write(string, sizeof(uint8), len) ; 839 } 840 if (iAudioNumChannelsValid) 841 { 842 len = oscl_snprintf(string, 128, "Audio Num Channels %d ", iAudioNumChannels); 843 iOutputFile.Write(string, sizeof(uint8), len) ; 844 } 845 if (iAudioSamplingRateValid) 846 { 847 len = oscl_snprintf(string, 128, "Audio Sampling Rate %d ", iAudioSamplingRate); 848 iOutputFile.Write(string, sizeof(uint8), len) ; 849 } 850 if (iTextFormatString.get_size() > 0) 851 { 852 len = oscl_snprintf(string, 128, "Text Format %s ", iTextFormatString.get_str()); 853 iOutputFile.Write(string, sizeof(uint8), len) ; 854 } 855 } 856 } 857 858 void PVRefFileOutput::LogCodecHeader(uint32 aSeqNum, const PVMFTimestamp& aTimestamp, uint32 datalen) 859 { 860 if (iLogOutputToFile) 861 { 862 if (iLogStrings) 863 { 864 char string[128]; 865 int32 len = oscl_snprintf(string, 128, "SeqNum %d Timestamp %d Len %d Codec Header", aSeqNum, aTimestamp, datalen); 866 iOutputFile.Write(string, sizeof(uint8), len) ; 867 } 868 else 869 { 870 if (iVideoFormat == PVMF_MIME_H264_VIDEO_MP4) 871 { 872 iOutputFile.Write(&datalen, sizeof(uint8), sizeof(uint32)); 873 } 874 } 875 } 876 } 877 878 void PVRefFileOutput::LogEndOfStream(uint32 aSeqNum, const PVMFTimestamp& aTimestamp) 879 { 880 if (iLogOutputToFile && iLogStrings) 881 { 882 char string[128]; 883 int32 len = oscl_snprintf(string, 128, "SeqNum %d Timestamp %d EOS", aSeqNum, aTimestamp); 884 iOutputFile.Write(string, sizeof(uint8), len) ; 885 } 886 } 887 888 void PVRefFileOutput::LogFrame(uint32 aSeqNum, const PVMFTimestamp& aTimestamp, uint32 datalen) 889 { 890 if (iLogOutputToFile) 891 { 892 if (iLogStrings) 893 { 894 char string[128]; 895 int32 len = oscl_snprintf(string, 128, "SeqNum %d Timestamp %d Len %d Frame", aSeqNum, aTimestamp, datalen); 896 iOutputFile.Write(string, sizeof(uint8), len) ; 897 } 898 else 899 { 900 if (iVideoFormat == PVMF_MIME_H264_VIDEO_MP4) 901 { 902 iOutputFile.Write(&datalen, sizeof(uint8), sizeof(uint32)); 903 } 904 } 905 } 906 } 907 908 PVMFCommandId PVRefFileOutput::writeAsync(uint8 aFormatType, int32 aFormatIndex, uint8* aData, uint32 aDataLen, 909 const PvmiMediaXferHeader& data_header_info, OsclAny* aContext) 910 { 911 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 912 (0, "PVRefFileOutput::writeAsync() seqnum %d ts %d context %d", 913 data_header_info.seq_num, data_header_info.timestamp, aContext)); 914 915 PVMFStatus status = PVMFFailure; 916 bool discard = false; 917 918 switch (aFormatType) 919 { 920 case PVMI_MEDIAXFER_FMT_TYPE_COMMAND : 921 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 922 (0, "PVRefFileOutput::writeAsync() called with Command info.")); 923 //ignore 924 status = PVMFSuccess; 925 break; 926 927 case PVMI_MEDIAXFER_FMT_TYPE_NOTIFICATION : 928 switch (aFormatIndex) 929 { 930 case PVMI_MEDIAXFER_FMT_INDEX_END_OF_STREAM: 931 { 932 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 933 (0, "PVRefFileOutput::writeAsync() called with Notification info - EOS.")); 934 if (iLogStrings) 935 { 936 LogEndOfStream(data_header_info.seq_num, data_header_info.timestamp); 937 } 938 status = PVMFSuccess; 939 } 940 break; 941 case PVMI_MEDIAXFER_FMT_INDEX_RE_CONFIG_NOTIFICATION: 942 { 943 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 944 (0, "PVRefFileOutput::writeAsync() called with Notification info - RECONFIG.")); 945 status = HandleReConfig(data_header_info.seq_num); 946 } 947 break; 948 default: 949 //ignore 950 status = PVMFSuccess; 951 break; 952 } 953 break; 954 955 case PVMI_MEDIAXFER_FMT_TYPE_DATA : 956 switch (aFormatIndex) 957 { 958 case PVMI_MEDIAXFER_FMT_INDEX_FMT_SPECIFIC_INFO: 959 //format-specific info contains codec headers. 960 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 961 (0, "PVRefFileOutput::writeAsync() called with format-specific info.")); 962 963 if (iState < STATE_INITIALIZED) 964 { 965 PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR, 966 (0, "PVRefFileOutput::writeAsync: Error - Invalid state")); 967 iWriteBusy = true; 968 OSCL_LEAVE(OsclErrInvalidState); 969 return -1; 970 } 971 else 972 { 973 // Just write out the passed in data to file 974 if (iLogStrings) 975 { 976 if (!iParametersLogged) 977 LogParameters(); 978 } 979 if (aDataLen > 0) 980 { 981 LogCodecHeader(data_header_info.seq_num, data_header_info.timestamp, aDataLen); 982 if (iLogOutputToFile && iOutputFile.Write(aData, sizeof(uint8), aDataLen) != aDataLen) 983 { 984 PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR, 985 (0, "PVRefFileOutput::writeAsync: Error - File write failed")); 986 status = PVMFFailure; 987 } 988 else 989 { 990 status = PVMFSuccess; 991 } 992 } 993 else 994 { 995 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_INFO, 996 (0, "PVRefFileOutput::writeAsync() called aDataLen==0.")); 997 status = PVMFSuccess; 998 } 999 } 1000 break; 1001 1002 case PVMI_MEDIAXFER_FMT_INDEX_DATA: 1003 //data contains the media bitstream. 1004 1005 //Verify the state 1006 if (iState != STATE_STARTED) 1007 { 1008 PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR, 1009 (0, "PVRefFileOutput::writeAsync: Error - Invalid state")); 1010 iWriteBusy = true; 1011 OSCL_LEAVE(OsclErrInvalidState); 1012 return -1; 1013 } 1014 //Check whether we can accept data now and leave if we can't. 1015 else if (CheckWriteBusy(data_header_info.seq_num)) 1016 { 1017 PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR, 1018 (0, "PVRefFileOutput::writeAsync: Entering busy state")); 1019 1020 //schedule an event to re-start the data flow. 1021 iWriteBusy = true; 1022 iWriteBusySeqNum = data_header_info.seq_num; 1023 RunIfNotReady(); 1024 1025 OSCL_LEAVE(OsclErrBusy); 1026 } 1027 else 1028 { 1029 // Just write out the passed in data to file 1030 if (iLogStrings) 1031 { 1032 if (!iParametersLogged) 1033 { 1034 LogParameters(); 1035 } 1036 } 1037 1038 if (aDataLen > 0) 1039 { 1040 //check whether the player clock is in frame-step mode. 1041 //do not render audio in frame-step mode. 1042 if (iAudioFormat != PVMF_MIME_FORMAT_UNKNOWN 1043 && iActiveTiming 1044 && iActiveTiming->FrameStepMode()) 1045 { 1046 discard = true; 1047 } 1048 1049 LogFrame(data_header_info.seq_num, data_header_info.timestamp, aDataLen); 1050 if (iTextFormat == PVMF_MIME_3GPP_TIMEDTEXT) 1051 { 1052 // Guard against somebody setting this MIO component for multiple data types 1053 OSCL_ASSERT(iVideoFormat == PVMF_MIME_FORMAT_UNKNOWN && iAudioFormat == PVMF_MIME_FORMAT_UNKNOWN); 1054 1055 PVMFTimedTextMediaData* textmediadata = (PVMFTimedTextMediaData*)aData; 1056 1057 // Write out the text sample entry 1058 if (textmediadata->iTextSampleEntry.GetRep() != NULL) 1059 { 1060 // @todo Write out the text sample entry in a better format 1061 if (iLogOutputToFile && iOutputFile.Write((OsclAny*)(textmediadata->iTextSampleEntry.GetRep()), sizeof(PVMFTimedTextSampleEntry), 1) != 1) 1062 { 1063 PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR, 1064 (0, "PVRefFileOutput::writeAsync: Error - File write failed for text sample entry")); 1065 status = PVMFFailure; 1066 break; 1067 } 1068 } 1069 1070 // Write out the raw text sample 1071 if (iLogOutputToFile && iOutputFile.Write(textmediadata->iTextSample, sizeof(uint8), textmediadata->iTextSampleLength) != textmediadata->iTextSampleLength) 1072 { 1073 PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR, 1074 (0, "PVRefFileOutput::writeAsync: Error - File write failed for text sample data")); 1075 status = PVMFFailure; 1076 } 1077 else 1078 { 1079 status = PVMFSuccess; 1080 } 1081 } 1082 else if (discard) 1083 { 1084 //do not render this frame. 1085 char string[128]; 1086 int32 len = oscl_snprintf(string, 128, "discard-- frame-step mode"); 1087 if (iLogOutputToFile && iOutputFile.Write(string, sizeof(uint8), len) != (uint32)len) 1088 { 1089 PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR, 1090 (0, "PVRefFileOutput::writeAsync: Error - File write failed")); 1091 status = PVMFFailure; 1092 } 1093 } 1094 else 1095 { 1096 if (iHeaderWritten != true && (iAudioFormat == PVMF_MIME_PCM16 || iAudioFormat == PVMF_MIME_PCM8)) 1097 { 1098 if (iLogOutputToFile) 1099 { 1100 iOutputFile.Write(&iRIFFChunk, sizeof(uint8), sizeof(RIFFChunk)); 1101 iOutputFile.Write(&iFmtSubchunk, sizeof(uint8), sizeof(fmtSubchunk)); 1102 iOutputFile.Write(&iDataSubchunk, sizeof(uint8), sizeof(dataSubchunk)); 1103 } 1104 iHeaderWritten = true; 1105 } 1106 if (iHeaderWritten != true && (iVideoFormat == PVMF_MIME_YUV420 || iVideoFormat == PVMF_MIME_YUV422)) 1107 { 1108 WriteHeaders(); 1109 iHeaderWritten = true; 1110 } 1111 1112 if (iAudioFormat == PVMF_MIME_AMR_IETF || 1113 iAudioFormat == PVMF_MIME_AMR_IF2 || 1114 iVideoFormat == PVMF_MIME_H2631998 || 1115 iVideoFormat == PVMF_MIME_H2632000 || 1116 iVideoFormat == PVMF_MIME_M4V) 1117 { 1118 if (iLogOutputToFile && iOutputFile.Write(aData, sizeof(uint8), aDataLen) != aDataLen) 1119 { 1120 PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR, 1121 (0, "PVRefFileOutput::writeAsync: Error - File write failed")); 1122 status = PVMFFailure; 1123 } 1124 else 1125 { 1126 status = PVMFSuccess; 1127 } 1128 } 1129 //'render' this frame 1130 if (iAudioFormat == PVMF_MIME_PCM16 || iAudioFormat == PVMF_MIME_PCM8) 1131 { 1132 if (iLogOutputToFile && iOutputFile.Write(aData, sizeof(uint8), aDataLen) != aDataLen) 1133 { 1134 PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR, 1135 (0, "PVRefFileOutput::writeAsync: Error - File write failed")); 1136 status = PVMFFailure; 1137 } 1138 else 1139 { 1140 if (iAudioFormat == PVMF_MIME_PCM16 || iAudioFormat == PVMF_MIME_PCM8) 1141 iDataSubchunk.subchunk2Size += aDataLen; 1142 status = PVMFSuccess; 1143 } 1144 } 1145 1146 if (iVideoFormat == PVMF_MIME_YUV420 || iVideoFormat == PVMF_MIME_YUV422) 1147 { 1148 #ifdef AVI_OUTPUT 1149 unsigned char *u, *v, ch; 1150 uint32 fsize = iVideoWidth * iVideoHeight; 1151 uint32 bsize = iVideoWidth * iVideoHeight * 3 / 2; 1152 u = aData + fsize; 1153 v = aData + fsize * 5 / 4; 1154 for (int j = 0; j < fsize / 4; j++) 1155 { 1156 ch = u[j]; 1157 u[j] = v[j]; 1158 v[j] = ch; 1159 } 1160 AddChunk(aData, bsize, videoChunkID); 1161 iVideoLastTimeStamp = data_header_info.timestamp; 1162 iAVIChunkSize += bsize + 4 + 4; 1163 status = PVMFSuccess; 1164 #else 1165 uint32 size = iVideoWidth * iVideoHeight * 3 / 2; 1166 if (iLogOutputToFile && iOutputFile.Write(aData, sizeof(uint8), size) != size) 1167 { 1168 PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR, 1169 (0, "PVRefFileOutput::writeAsync: Error - File write failed")); 1170 status = PVMFFailure; 1171 } 1172 else 1173 status = PVMFSuccess; 1174 #endif 1175 } 1176 } 1177 } 1178 else 1179 { 1180 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_INFO, 1181 (0, "PVRefFileOutput::writeAsync() called aDataLen==0.")); 1182 status = PVMFSuccess; 1183 } 1184 } 1185 break; 1186 1187 default: 1188 PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR, 1189 (0, "PVRefFileOutput::writeAsync: Error - unrecognized format index")); 1190 status = PVMFFailure; 1191 break; 1192 } 1193 break; 1194 1195 default: 1196 PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR, 1197 (0, "PVRefFileOutput::writeAsync: Error - unrecognized format type")); 1198 status = PVMFFailure; 1199 break; 1200 } 1201 1202 //Schedule asynchronous response 1203 PVMFCommandId cmdid = iCommandCounter++; 1204 WriteResponse resp(status, cmdid, aContext, data_header_info.timestamp, discard); 1205 iWriteResponseQueue.push_back(resp); 1206 RunIfNotReady(); 1207 return cmdid; 1208 1209 } 1210 1211 void PVRefFileOutput::writeComplete(PVMFStatus aStatus, PVMFCommandId write_cmd_id, OsclAny* aContext) 1212 { 1213 OSCL_UNUSED_ARG(aStatus); 1214 OSCL_UNUSED_ARG(write_cmd_id); 1215 OSCL_UNUSED_ARG(aContext); 1216 1217 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::writeComplete() called")); 1218 //won't be called since this component is a sink. 1219 1220 } 1221 1222 1223 PVMFCommandId PVRefFileOutput::readAsync(uint8* data, uint32 max_data_len, OsclAny* aContext, 1224 int32* formats, uint16 num_formats) 1225 { 1226 OSCL_UNUSED_ARG(data); 1227 OSCL_UNUSED_ARG(max_data_len); 1228 OSCL_UNUSED_ARG(aContext); 1229 OSCL_UNUSED_ARG(formats); 1230 OSCL_UNUSED_ARG(num_formats); 1231 1232 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::readAsync() called")); 1233 //read not supported. 1234 OsclError::Leave(OsclErrNotSupported); 1235 return 0; 1236 } 1237 1238 1239 void PVRefFileOutput::readComplete(PVMFStatus aStatus, PVMFCommandId read_cmd_id, int32 format_index, 1240 const PvmiMediaXferHeader& data_header_info, OsclAny* aContext) 1241 { 1242 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::readComplete() called")); 1243 //won't be called since this component is a sink. 1244 OSCL_UNUSED_ARG(aStatus); 1245 OSCL_UNUSED_ARG(read_cmd_id); 1246 OSCL_UNUSED_ARG(format_index); 1247 OSCL_UNUSED_ARG(data_header_info); 1248 OSCL_UNUSED_ARG(aContext); 1249 } 1250 1251 1252 void PVRefFileOutput::statusUpdate(uint32 status_flags) 1253 { 1254 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::statusUpdate() called")); 1255 //won't be called since this component is a sink. 1256 OSCL_UNUSED_ARG(status_flags); 1257 } 1258 1259 1260 void PVRefFileOutput::cancelCommand(PVMFCommandId command_id) 1261 { 1262 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::cancelCommand() called")); 1263 1264 //the purpose of this API is to cancel a writeAsync command and report 1265 //completion ASAP. 1266 1267 //in this implementation, the write commands are executed immediately 1268 //when received so it isn't really possible to cancel. 1269 //just report completion immediately. 1270 1271 for (uint32 i = 0; i < iWriteResponseQueue.size(); i++) 1272 { 1273 if (iWriteResponseQueue[i].iCmdId == command_id) 1274 { 1275 //report completion 1276 if (iPeer) 1277 { 1278 iPeer->writeComplete(iWriteResponseQueue[i].iStatus, iWriteResponseQueue[i].iCmdId, (OsclAny*)iWriteResponseQueue[i].iContext); 1279 } 1280 iWriteResponseQueue.erase(&iWriteResponseQueue[i]); 1281 break; 1282 } 1283 } 1284 } 1285 1286 void PVRefFileOutput::cancelAllCommands() 1287 { 1288 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVRefFileOutput::cancelAllCommands() called")); 1289 1290 //the purpose of this API is to cancel all writeAsync commands and report 1291 //completion ASAP. 1292 1293 //in this implementaiton, the write commands are executed immediately 1294 //when received so it isn't really possible to cancel. 1295 //just report completion immediately. 1296 1297 while (iWriteResponseQueue.size() > 0) 1298 { 1299 //report completion 1300 if (iPeer) 1301 { 1302 iPeer->writeComplete(iWriteResponseQueue[0].iStatus, iWriteResponseQueue[0].iCmdId, (OsclAny*)iWriteResponseQueue[0].iContext); 1303 } 1304 iWriteResponseQueue.erase(&iWriteResponseQueue[0]); 1305 } 1306 1307 } 1308 1309 void PVRefFileOutput::setObserver(PvmiConfigAndCapabilityCmdObserver* aObserver) 1310 { 1311 OSCL_UNUSED_ARG(aObserver); 1312 //not needed since this component only supports synchronous capability & config 1313 //APIs. 1314 } 1315 1316 PVMFStatus PVRefFileOutput::getParametersSync(PvmiMIOSession aSession, PvmiKeyType aIdentifier, 1317 PvmiKvp*& aParameters, int& num_parameter_elements, 1318 PvmiCapabilityContext aContext) 1319 { 1320 OSCL_UNUSED_ARG(aSession); 1321 OSCL_UNUSED_ARG(aContext); 1322 1323 if (pv_mime_strcmp(aIdentifier, INPUT_FORMATS_CAP_QUERY) == 0) 1324 { 1325 aParameters = NULL; 1326 num_parameter_elements = 0; 1327 1328 //This is a query for the list of supported formats. 1329 1330 //This component supports any audio or video format 1331 1332 //Generate a list of all the PVMF audio & video formats... 1333 int32 count = 0; 1334 if (iMediaType == MEDIATYPE_AUDIO) 1335 { 1336 if (iCompressedMedia) 1337 { 1338 count = PVMF_SUPPORTED_COMPRESSED_AUDIO_FORMATS_COUNT; 1339 } 1340 else 1341 { 1342 count = PVMF_SUPPORTED_UNCOMPRESSED_AUDIO_FORMATS_COUNT; 1343 } 1344 } 1345 else if (iMediaType == MEDIATYPE_VIDEO) 1346 { 1347 if (iCompressedMedia) 1348 { 1349 count = PVMF_SUPPORTED_COMPRESSED_VIDEO_FORMATS_COUNT; 1350 } 1351 else 1352 { 1353 count = PVMF_SUPPORTED_UNCOMPRESSED_VIDEO_FORMATS_COUNT; 1354 } 1355 } 1356 else if (iMediaType == MEDIATYPE_TEXT) 1357 { 1358 count = PVMF_SUPPORTED_TEXT_FORMAT_COUNT; 1359 } 1360 else 1361 { 1362 count = PVMF_SUPPORTED_UNCOMPRESSED_AUDIO_FORMATS_COUNT + 1363 PVMF_SUPPORTED_UNCOMPRESSED_VIDEO_FORMATS_COUNT + 1364 PVMF_SUPPORTED_COMPRESSED_AUDIO_FORMATS_COUNT + 1365 PVMF_SUPPORTED_COMPRESSED_VIDEO_FORMATS_COUNT + 1366 PVMF_SUPPORTED_TEXT_FORMAT_COUNT; 1367 } 1368 1369 aParameters = (PvmiKvp*)oscl_malloc(count * sizeof(PvmiKvp)); 1370 1371 if (aParameters) 1372 { 1373 PVMFFormatType fmt; 1374 if (iMediaType == MEDIATYPE_AUDIO || iMediaType == MEDIATYPE_UNKNOWN) 1375 { 1376 if (iCompressedMedia || iMediaType == MEDIATYPE_UNKNOWN) 1377 { 1378 int32 i = 0; 1379 if (iMediaType == MEDIATYPE_UNKNOWN) 1380 { 1381 i = num_parameter_elements; 1382 } 1383 1384 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_AMR; 1385 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_AMRWB; 1386 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_AMR_IETF; 1387 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_AMRWB_IETF; 1388 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_AMR_IF2; 1389 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_EVRC; 1390 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_MP3; 1391 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_ADIF; 1392 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_ADTS; 1393 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_LATM; 1394 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_MPEG4_AUDIO; 1395 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_G723; 1396 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_G726; 1397 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_WMA; 1398 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_ASF_AMR; 1399 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_REAL_AUDIO; 1400 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_ASF_MPEG4_AUDIO; 1401 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_3640; 1402 1403 while (i < count) 1404 { 1405 aParameters[i].key = (PvmiKeyType)oscl_malloc(oscl_strlen(MOUT_AUDIO_FORMAT_KEY) + 1); 1406 if (!aParameters[i].key) 1407 { 1408 return PVMFErrNoMemory; 1409 // (hope it's safe to leave array partially 1410 // allocated, caller will free?) 1411 } 1412 oscl_strncpy(aParameters[i++].key, MOUT_AUDIO_FORMAT_KEY, oscl_strlen(MOUT_AUDIO_FORMAT_KEY) + 1); 1413 } 1414 } 1415 1416 if (!iCompressedMedia || iMediaType == MEDIATYPE_UNKNOWN) 1417 { 1418 int32 i = 0; 1419 if (iMediaType == MEDIATYPE_UNKNOWN) 1420 { 1421 i = num_parameter_elements; 1422 } 1423 1424 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_PCM; 1425 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_PCM8; 1426 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_PCM16; 1427 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_PCM16_BE; 1428 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_ULAW; 1429 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_ALAW; 1430 1431 while (i < count) 1432 { 1433 aParameters[i].key = (PvmiKeyType)oscl_malloc(oscl_strlen(MOUT_AUDIO_FORMAT_KEY) + 1); 1434 if (!aParameters[i].key) 1435 { 1436 return PVMFErrNoMemory; 1437 // (hope it's safe to leave array partially 1438 // allocated, caller will free?) 1439 } 1440 oscl_strncpy(aParameters[i++].key, MOUT_AUDIO_FORMAT_KEY, oscl_strlen(MOUT_AUDIO_FORMAT_KEY) + 1); 1441 } 1442 } 1443 } 1444 if (iMediaType == MEDIATYPE_VIDEO || iMediaType == MEDIATYPE_UNKNOWN) 1445 { 1446 if (iCompressedMedia || iMediaType == MEDIATYPE_UNKNOWN) 1447 { 1448 int32 i = 0; 1449 if (iMediaType == MEDIATYPE_UNKNOWN) 1450 { 1451 i = num_parameter_elements; 1452 } 1453 1454 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_M4V; 1455 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_H2631998; 1456 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_H2632000; 1457 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_H264_VIDEO_RAW; 1458 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_H264_VIDEO_MP4; 1459 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_H264_VIDEO; 1460 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_WMV; 1461 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_REAL_VIDEO; 1462 1463 while (i < count) 1464 { 1465 aParameters[i].key = (PvmiKeyType)oscl_malloc(oscl_strlen(MOUT_VIDEO_FORMAT_KEY) + 1); 1466 if (!aParameters[i].key) 1467 { 1468 return PVMFErrNoMemory; 1469 // (hope it's safe to leave array partially 1470 // allocated, caller will free?) 1471 } 1472 oscl_strncpy(aParameters[i++].key, MOUT_VIDEO_FORMAT_KEY, oscl_strlen(MOUT_VIDEO_FORMAT_KEY) + 1); 1473 } 1474 } 1475 1476 if (!iCompressedMedia || iMediaType == MEDIATYPE_UNKNOWN) 1477 { 1478 int32 i = 0; 1479 if (iMediaType == MEDIATYPE_UNKNOWN) 1480 { 1481 i = num_parameter_elements; 1482 } 1483 1484 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_YUV420; 1485 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_YUV422; 1486 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_RGB8; 1487 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_RGB12; 1488 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_RGB16; 1489 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_RGB24; 1490 1491 while (i < count) 1492 { 1493 aParameters[i].key = (PvmiKeyType)oscl_malloc(oscl_strlen(MOUT_VIDEO_FORMAT_KEY) + 1); 1494 if (!aParameters[i].key) 1495 { 1496 return PVMFErrNoMemory; 1497 // (hope it's safe to leave array partially 1498 // allocated, caller will free?) 1499 } 1500 oscl_strncpy(aParameters[i++].key, MOUT_VIDEO_FORMAT_KEY, oscl_strlen(MOUT_VIDEO_FORMAT_KEY) + 1); 1501 } 1502 } 1503 } 1504 1505 if (iMediaType == MEDIATYPE_TEXT || iMediaType == MEDIATYPE_UNKNOWN) 1506 { 1507 int32 i = 0; 1508 if (iMediaType == MEDIATYPE_UNKNOWN) 1509 { 1510 i = num_parameter_elements; 1511 } 1512 1513 aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_3GPP_TIMEDTEXT; 1514 aParameters[i].key = (PvmiKeyType)oscl_malloc(oscl_strlen(MOUT_TEXT_FORMAT_KEY) + 1); 1515 if (!aParameters[i].key) 1516 { 1517 return PVMFErrNoMemory; 1518 // (hope it's safe to leave array partially 1519 // allocated, caller will free?) 1520 } 1521 oscl_strncpy(aParameters[i++].key, MOUT_TEXT_FORMAT_KEY, oscl_strlen(MOUT_TEXT_FORMAT_KEY) + 1); 1522 } 1523 return PVMFSuccess; 1524 } 1525 return PVMFErrNoMemory; 1526 } 1527 else if (pv_mime_strcmp(aIdentifier, PVMF_NUM_DECODED_FRAMES_CONFIG_KEY) == 0) 1528 { 1529 aParameters = (PvmiKvp*)oscl_malloc(sizeof(PvmiKvp)); 1530 if (!aParameters) 1531 { 1532 return PVMFErrNoMemory; 1533 } 1534 1535 aParameters[0].value.uint32_value = DEFAULT_NUM_DECODED_FRAMES_CAPABILITY; 1536 return PVMFSuccess; 1537 } 1538 #if TEST_BUFFER_ALLOCATOR 1539 else if (pv_mime_strcmp(aIdentifier, PVMF_BUFFER_ALLOCATOR_KEY) == 0) 1540 { 1541 int32 err; 1542 aParameters = (PvmiKvp*)oscl_malloc(sizeof(PvmiKvp)); 1543 if (!aParameters) 1544 { 1545 return PVMFErrNoMemory; 1546 } 1547 1548 OSCL_TRY(err, aParameters[0].value.key_specific_value = (PVInterface *)OSCL_NEW(PVRefBufferAlloc, (iBufferSize, iNumberOfBuffers)) ;); 1549 if (err || (NULL == aParameters[0].value.key_specific_value)) 1550 { 1551 return PVMFErrNoMemory; 1552 1553 } 1554 return PVMFSuccess; 1555 } 1556 #endif 1557 //other queries are not currently supported. 1558 1559 //unrecognized key. 1560 return PVMFFailure; 1561 } 1562 1563 PVMFStatus PVRefFileOutput::releaseParameters(PvmiMIOSession aSession, PvmiKvp* aParameters, int num_elements) 1564 { 1565 OSCL_UNUSED_ARG(aSession); 1566 1567 //release parameters that were allocated by this component. 1568 if (aParameters) 1569 { 1570 for (int i = 0; i < num_elements; i++) 1571 { 1572 oscl_free(aParameters[i].key); 1573 } 1574 oscl_free(aParameters); 1575 return PVMFSuccess; 1576 } 1577 return PVMFFailure; 1578 } 1579 1580 void PVRefFileOutput::createContext(PvmiMIOSession aSession, PvmiCapabilityContext& aContext) 1581 { 1582 OSCL_UNUSED_ARG(aSession); 1583 OSCL_UNUSED_ARG(aContext); 1584 1585 OsclError::Leave(OsclErrNotSupported); 1586 } 1587 1588 void PVRefFileOutput::setContextParameters(PvmiMIOSession aSession, PvmiCapabilityContext& aContext, 1589 PvmiKvp* aParameters, int num_parameter_elements) 1590 { 1591 OSCL_UNUSED_ARG(aSession); 1592 OSCL_UNUSED_ARG(aContext); 1593 OSCL_UNUSED_ARG(aParameters); 1594 OSCL_UNUSED_ARG(num_parameter_elements); 1595 1596 OsclError::Leave(OsclErrNotSupported); 1597 } 1598 1599 void PVRefFileOutput::DeleteContext(PvmiMIOSession aSession, PvmiCapabilityContext& aContext) 1600 { 1601 OSCL_UNUSED_ARG(aSession); 1602 OSCL_UNUSED_ARG(aContext); 1603 1604 OsclError::Leave(OsclErrNotSupported); 1605 } 1606 1607 1608 void PVRefFileOutput::setParametersSync(PvmiMIOSession aSession, 1609 PvmiKvp* aParameters, 1610 int num_elements, 1611 PvmiKvp * & aRet_kvp) 1612 { 1613 OSCL_UNUSED_ARG(aSession); 1614 aRet_kvp = NULL; 1615 1616 for (int32 i = 0; i < num_elements; i++) 1617 { 1618 //Check against known audio parameter keys... 1619 if (pv_mime_strcmp(aParameters[i].key, MOUT_AUDIO_FORMAT_KEY) == 0) 1620 { 1621 if (oscl_strncmp(aParameters[i].value.pChar_value, "audio/L16", sizeof("audio/L16")) == 0) 1622 iAudioFormat = PVMF_MIME_PCM16; 1623 else if (oscl_strncmp(aParameters[i].value.pChar_value, "audio/L8", sizeof("audio/L8")) == 0) 1624 iAudioFormat = PVMF_MIME_PCM8; 1625 else if (oscl_strncmp(aParameters[i].value.pChar_value, "X-AMR-IF2", sizeof("X-AMR-IF2")) == 0) 1626 iAudioFormat = PVMF_MIME_AMR_IF2; 1627 else if (oscl_strncmp(aParameters[i].value.pChar_value, "X-AMR-IETF-SEPARATE", sizeof("X-AMR-IETF-SEPARATE")) == 0) 1628 iAudioFormat = PVMF_MIME_AMR_IETF; 1629 1630 iAudioFormatString = iAudioFormat.getMIMEStrPtr(); 1631 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1632 (0, "PVRefFileOutput::setParametersSync() Audio Format Key, Value %s", iAudioFormatString.get_str())); 1633 } 1634 else if (pv_mime_strcmp(aParameters[i].key, MOUT_AUDIO_SAMPLING_RATE_KEY) == 0) 1635 { 1636 iAudioSamplingRate = (int32)aParameters[i].value.uint32_value; 1637 iAudioSamplingRateValid = true; 1638 iFmtSubchunk.sampleRate = iAudioSamplingRate; 1639 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1640 (0, "PVRefFileOutput::setParametersSync() Audio Sampling Rate Key, Value %d", iAudioSamplingRate)); 1641 } 1642 else if (pv_mime_strcmp(aParameters[i].key, MOUT_AUDIO_NUM_CHANNELS_KEY) == 0) 1643 { 1644 iAudioNumChannels = (int32)aParameters[i].value.uint32_value; 1645 iAudioNumChannelsValid = true; 1646 iFmtSubchunk.numChannels = iAudioNumChannels; 1647 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1648 (0, "PVRefFileOutput::setParametersSync() Audio Num Channels Key, Value %d", iAudioNumChannels)); 1649 } 1650 //Check against known video parameter keys... 1651 else if (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_FORMAT_KEY) == 0) 1652 { 1653 1654 if (oscl_strncmp(aParameters[i].value.pChar_value, "X-YUV-420", sizeof("X-YUV-420")) == 0) 1655 iVideoFormat = PVMF_MIME_YUV420; 1656 else if (oscl_strncmp(aParameters[i].value.pChar_value, "X-YUV-422", sizeof("X-YUV-422")) == 0) 1657 iVideoFormat = PVMF_MIME_YUV422; 1658 else if (oscl_strncmp(aParameters[i].value.pChar_value, "video/H263-2000", sizeof("video/H263-2000")) == 0) 1659 iVideoFormat = PVMF_MIME_H2632000; 1660 else if (oscl_strncmp(aParameters[i].value.pChar_value, "video/H263-1998", sizeof("video/H263-1998")) == 0) 1661 iVideoFormat = PVMF_MIME_H2631998; 1662 else if (oscl_strncmp(aParameters[i].value.pChar_value, "video/MP4V-ES", sizeof("video/MP4V-ES")) == 0) 1663 iVideoFormat = PVMF_MIME_M4V; 1664 1665 iVideoFormatString = iVideoFormat.getMIMEStrPtr(); 1666 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1667 (0, "PVRefFileOutput::setParametersSync() Video Format Key, Value %s", iVideoFormatString.get_str())); 1668 } 1669 else if (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_WIDTH_KEY) == 0) 1670 { 1671 iVideoWidth = (int32)aParameters[i].value.uint32_value; 1672 iVideoWidthValid = true; 1673 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1674 (0, "PVRefFileOutput::setParametersSync() Video Width Key, Value %d", iVideoWidth)); 1675 } 1676 else if (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_HEIGHT_KEY) == 0) 1677 { 1678 iVideoHeight = (int32)aParameters[i].value.uint32_value; 1679 iVideoHeightValid = true; 1680 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1681 (0, "PVRefFileOutput::setParametersSync() Video Height Key, Value %d", iVideoHeight)); 1682 } 1683 else if (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_DISPLAY_HEIGHT_KEY) == 0) 1684 { 1685 iVideoDisplayHeight = (int32)aParameters[i].value.uint32_value; 1686 iVideoDisplayHeightValid = true; 1687 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1688 (0, "PVRefFileOutput::setParametersSync() Video Display Height Key, Value %d", iVideoDisplayHeight)); 1689 } 1690 else if (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_DISPLAY_WIDTH_KEY) == 0) 1691 { 1692 iVideoDisplayWidth = (int32)aParameters[i].value.uint32_value; 1693 iVideoDisplayWidthValid = true; 1694 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1695 (0, "PVRefFileOutput::setParametersSync() Video Display Width Key, Value %d", iVideoDisplayWidth)); 1696 } 1697 //Check against known text parameter keys... 1698 else if (pv_mime_strcmp(aParameters[i].key, MOUT_TEXT_FORMAT_KEY) == 0) 1699 { 1700 iTextFormatString = aParameters[i].value.pChar_value; 1701 iTextFormat = iTextFormatString.get_str(); 1702 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1703 (0, "PVRefFileOutput::setParametersSync() Text Format Key, Value %s", iTextFormatString.get_str())); 1704 } 1705 // Change to output rate 1706 else if (pv_mime_strcmp(aParameters[i].key, MOUT_MEDIAXFER_OUTPUT_RATE) == 0) 1707 { 1708 // Do nothing, this setting is meaningless for file IO 1709 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1710 (0, "PVRefFileOutput::setParametersSync() MediaXFER Output Rate Key, Value %d", 1711 aParameters[i].value.int32_value)); 1712 } 1713 else if (pv_mime_strcmp(aParameters[i].key, PVMF_FORMAT_SPECIFIC_INFO_KEY) == 0) 1714 { 1715 if (!iFileOpened) 1716 { 1717 if (iOutputFile.Open(iOutputFileName.get_cstr(), Oscl_File::MODE_READWRITE | Oscl_File::MODE_BINARY, iFs) != 0) 1718 { 1719 PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR, 1720 (0, "PVRefFileOutput::setParametersSync: Error - File Open failed")); 1721 } 1722 else 1723 { 1724 iFileOpened = true; 1725 LogCodecHeader(0, 0, (int32)aParameters[i].capacity); 1726 if (aParameters[i].value.pChar_value != NULL) 1727 { 1728 if (iLogOutputToFile && iOutputFile.Write(aParameters[i].value.pChar_value, 1729 sizeof(uint8), 1730 (int32)aParameters[i].capacity) != (uint32)aParameters[i].length) 1731 { 1732 PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR, 1733 (0, "PVRefFileOutput::setParametersSync: Error - File write failed")); 1734 } 1735 } 1736 } 1737 } 1738 } 1739 //All FSI for video will be set here in one go 1740 else if (pv_mime_strcmp(aParameters[i].key, PVMF_FORMAT_SPECIFIC_INFO_KEY_YUV) == 0) 1741 { 1742 uint8* data = (uint8*)aParameters->value.key_specific_value; 1743 PVMFYuvFormatSpecificInfo0* yuvInfo = (PVMFYuvFormatSpecificInfo0*)data; 1744 1745 iVideoWidth = (int32)yuvInfo->width; 1746 iVideoWidthValid = true; 1747 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1748 (0, "PVRefFileOutput::setParametersSync() Video Width, Value %d", iVideoWidth)); 1749 1750 iVideoHeight = (int32)yuvInfo->height; 1751 iVideoHeightValid = true; 1752 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1753 (0, "PVRefFileOutput::setParametersSync() Video Height, Value %d", iVideoHeight)); 1754 1755 iVideoDisplayHeight = (int32)yuvInfo->display_height; 1756 iVideoDisplayHeightValid = true; 1757 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1758 (0, "PVRefFileOutput::setParametersSync() Video Display Height, Value %d", iVideoDisplayHeight)); 1759 1760 1761 iVideoDisplayWidth = (int32)yuvInfo->display_width; 1762 iVideoDisplayWidthValid = true; 1763 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1764 (0, "PVRefFileOutput::setParametersSync() Video Display Width, Value %d", iVideoDisplayWidth)); 1765 1766 iNumberOfBuffers = (int32)yuvInfo->num_buffers; 1767 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1768 (0, "PVRefFileOutput::setParametersSync() Number of Buffer, Value %d", iNumberOfBuffers)); 1769 1770 iBufferSize = (int32)yuvInfo->buffer_size; 1771 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1772 (0, "PVRefFileOutput::setParametersSync() Buffer Size, Value %d", iBufferSize)); 1773 1774 } 1775 //All FSI for audio will be set here in one go 1776 else if (pv_mime_strcmp(aParameters[i].key, PVMF_FORMAT_SPECIFIC_INFO_KEY_PCM) == 0) 1777 { 1778 uint8* data = (uint8*)aParameters->value.key_specific_value; 1779 channelSampleInfo* pcm16Info = (channelSampleInfo*)data; 1780 1781 iAudioSamplingRate = pcm16Info->samplingRate; 1782 iAudioSamplingRateValid = true; 1783 iFmtSubchunk.sampleRate = iAudioSamplingRate; 1784 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1785 (0, "PVRefFileOutput::setParametersSync() Audio Sampling Rate, Value %d", iAudioSamplingRate)); 1786 1787 1788 iAudioNumChannels = pcm16Info->desiredChannels; 1789 iAudioNumChannelsValid = true; 1790 iFmtSubchunk.numChannels = iAudioNumChannels; 1791 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1792 (0, "PVRefFileOutput::setParametersSync() Audio Num Channels, Value %d", iAudioNumChannels)); 1793 1794 1795 iFmtSubchunk.bitsPerSample = (int32)pcm16Info->bitsPerSample; 1796 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1797 (0, "PVRefFileOutput::setParametersSync() Audio Bits Per Sample, Value %d", iFmtSubchunk.bitsPerSample)); 1798 1799 iNumberOfBuffers = (int32)pcm16Info->num_buffers; 1800 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1801 (0, "PVRefFileOutput::setParametersSync() Number of Buffer, Value %d", iNumberOfBuffers)); 1802 1803 iBufferSize = (int32)pcm16Info->buffer_size; 1804 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1805 (0, "PVRefFileOutput::setParametersSync() Buffer Size, Value %d", iBufferSize)); 1806 1807 } 1808 else 1809 { 1810 //if we get here the key is unrecognized. 1811 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1812 (0, "PVRefFileOutput::setParametersSync() Error, unrecognized key ")); 1813 1814 //set the return value to indicate the unrecognized key 1815 //and return. 1816 aRet_kvp = &aParameters[i]; 1817 return; 1818 } 1819 } 1820 if (iAudioFormat == PVMF_MIME_PCM16) 1821 { 1822 iFmtSubchunk.bitsPerSample = 16; 1823 iFmtSubchunk.byteRate = iFmtSubchunk.sampleRate * iFmtSubchunk.numChannels * iFmtSubchunk.bitsPerSample / 8; 1824 iFmtSubchunk.blockAlign = iFmtSubchunk.numChannels * iFmtSubchunk.bitsPerSample / 8; 1825 } 1826 else 1827 { 1828 iFmtSubchunk.bitsPerSample = 8; 1829 iFmtSubchunk.byteRate = iFmtSubchunk.sampleRate * iFmtSubchunk.numChannels * iFmtSubchunk.bitsPerSample / 8; 1830 iFmtSubchunk.blockAlign = iFmtSubchunk.numChannels * iFmtSubchunk.bitsPerSample / 8; 1831 1832 } 1833 1834 if ((iVideoFormat == PVMF_MIME_YUV420 || iVideoFormat == PVMF_MIME_YUV422) && (iVideoHeightValid == true && iVideoHeightValid == true && iInitializeAVIDone == false)) 1835 { 1836 InitializeAVI(iVideoWidth, iVideoHeight); 1837 iInitializeAVIDone = true; 1838 } 1839 1840 //No configuration is required for this MIO to function. 1841 //So, send PVMFMIOConfigurationComplete() from Run() 1842 1843 //If MIO is configured, send PVMFMIOConfigurationComplete event to observer. 1844 if (!iIsMIOConfigured) 1845 { 1846 if (iObserver) 1847 { 1848 iObserver->ReportInfoEvent(PVMFMIOConfigurationComplete); 1849 iIsMIOConfigured = true; 1850 } 1851 } 1852 } 1853 1854 PVMFCommandId PVRefFileOutput::setParametersAsync(PvmiMIOSession aSession, PvmiKvp* aParameters, 1855 int num_elements, PvmiKvp*& aRet_kvp, OsclAny* context) 1856 { 1857 OSCL_UNUSED_ARG(aSession); 1858 OSCL_UNUSED_ARG(aParameters); 1859 OSCL_UNUSED_ARG(num_elements); 1860 OSCL_UNUSED_ARG(aRet_kvp); 1861 OSCL_UNUSED_ARG(context); 1862 1863 OsclError::Leave(OsclErrNotSupported); 1864 return 0; 1865 } 1866 1867 uint32 PVRefFileOutput::getCapabilityMetric(PvmiMIOSession aSession) 1868 { 1869 OSCL_UNUSED_ARG(aSession); 1870 1871 return 0; 1872 } 1873 1874 PVMFStatus PVRefFileOutput::verifyParametersSync(PvmiMIOSession aSession, 1875 PvmiKvp* aParameters, 1876 int num_elements) 1877 { 1878 OSCL_UNUSED_ARG(aSession); 1879 1880 // Go through each parameter 1881 for (int32 paramind = 0; paramind < num_elements; ++paramind) 1882 { 1883 // Retrieve the first component from the key string 1884 char* compstr = NULL; 1885 pv_mime_string_extract_type(0, aParameters[paramind].key, compstr); 1886 1887 if (pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf/media/format-type")) == 0) 1888 { 1889 if (iMediaType == MEDIATYPE_UNKNOWN) 1890 { 1891 // For an unknown media type return PVMFErrNotSupported always. 1892 return PVMFErrNotSupported; 1893 } 1894 1895 if (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_FORMAT_UNKNOWN) == 0) 1896 { 1897 return PVMFErrNotSupported; 1898 } 1899 1900 // The Sink will return success based on following conditions: 1901 // i) The MIME string is supported by the sink, Text Sink will support Text MIME, 1902 // Audio Sink - Audio MIME and Video Sink - Video MIME. 1903 // ii) For all compressed formats, if the sink itself is Compressed. If the sink 1904 // is UnCompressed here, Sink will send PVMFErrNotSupported. 1905 // iii) For all uncompressed formats, if the sink itself is Uncompressed. If the sink 1906 // is Compressed here, Sink will send PVMFErrNotSupported. 1907 if (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_3GPP_TIMEDTEXT) == 0) 1908 { 1909 if (iMediaType == MEDIATYPE_TEXT) 1910 { 1911 return PVMFSuccess; 1912 } 1913 else 1914 { 1915 return PVMFErrNotSupported; 1916 } 1917 } 1918 else if ((pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_YUV420) == 0) || 1919 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_YUV422) == 0) || 1920 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_RGB8) == 0) || 1921 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_RGB12) == 0) || 1922 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_RGB16) == 0) || 1923 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_RGB24) == 0)) 1924 { 1925 // Uncompressed Video formats 1926 if (iMediaType == MEDIATYPE_VIDEO) 1927 { 1928 if (iCompressedMedia) 1929 { 1930 return PVMFErrNotSupported; 1931 } 1932 else 1933 { 1934 return PVMFSuccess; 1935 } 1936 } 1937 else 1938 { 1939 return PVMFErrNotSupported; 1940 } 1941 } 1942 else if ((pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_M4V) == 0) || 1943 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_H2631998) == 0) || 1944 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_H2632000) == 0) || 1945 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_H264_VIDEO_RAW) == 0) || 1946 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_H264_VIDEO_MP4) == 0) || 1947 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_H264_VIDEO) == 0) || 1948 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_WMV) == 0) || 1949 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_REAL_VIDEO) == 0)) 1950 { 1951 // Compressed Video formats 1952 if (iMediaType == MEDIATYPE_VIDEO) 1953 { 1954 if (iCompressedMedia) 1955 { 1956 return PVMFSuccess; 1957 } 1958 else 1959 { 1960 return PVMFErrNotSupported; 1961 } 1962 } 1963 else 1964 { 1965 return PVMFErrNotSupported; 1966 } 1967 } 1968 else if ((pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_PCM) == 0) || 1969 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_PCM8) == 0) || 1970 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_PCM16) == 0) || 1971 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_PCM16_BE) == 0) || 1972 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_ULAW) == 0) || 1973 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_ALAW) == 0)) 1974 { 1975 // Uncompressed Audio formats 1976 if (iMediaType == MEDIATYPE_AUDIO) 1977 { 1978 if (iCompressedMedia) 1979 { 1980 return PVMFErrNotSupported; 1981 } 1982 else 1983 { 1984 return PVMFSuccess; 1985 } 1986 } 1987 else 1988 { 1989 return PVMFErrNotSupported; 1990 } 1991 } 1992 else if ((pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_AMR) == 0) || 1993 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_AMRWB) == 0) || 1994 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_AMR_IETF) == 0) || 1995 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_AMRWB_IETF) == 0) || 1996 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_AMR_IF2) == 0) || 1997 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_EVRC) == 0) || 1998 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_MP3) == 0) || 1999 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_ADIF) == 0) || 2000 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_ADTS) == 0) || 2001 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_LATM) == 0) || 2002 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_MPEG4_AUDIO) == 0) || 2003 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_G723) == 0) || 2004 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_G726) == 0) || 2005 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_WMA) == 0) || 2006 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_ASF_AMR) == 0) || 2007 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_REAL_AUDIO) == 0) || 2008 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_ASF_MPEG4_AUDIO) == 0) || 2009 (pv_mime_strcmp(aParameters[paramind].value.pChar_value, PVMF_MIME_3640) == 0)) 2010 { 2011 // Compressed audio formats 2012 if (iMediaType == MEDIATYPE_AUDIO) 2013 { 2014 if (iCompressedMedia) 2015 { 2016 return PVMFSuccess; 2017 } 2018 else 2019 { 2020 return PVMFErrNotSupported; 2021 } 2022 } 2023 else 2024 { 2025 return PVMFErrNotSupported; 2026 } 2027 } 2028 } 2029 } 2030 2031 // For all other parameters return a default success 2032 2033 return PVMFSuccess; 2034 } 2035 2036 void PVRefFileOutput::setFormatMask(uint32 mask) 2037 { 2038 iFormatMask = mask; 2039 } 2040 2041 OSCL_EXPORT_REF PVMFStatus PVRefFileOutput::SetClock(PVMFMediaClock *clockVal) 2042 { 2043 iClock = clockVal; 2044 return PVMFSuccess; 2045 } 2046 2047 OSCL_EXPORT_REF void PVRefFileOutput::addRef() 2048 { 2049 } 2050 2051 OSCL_EXPORT_REF void PVRefFileOutput::removeRef() 2052 { 2053 } 2054 2055 OSCL_EXPORT_REF bool PVRefFileOutput::queryInterface(const PVUuid& aUuid, PVInterface*& aInterface) 2056 { 2057 OSCL_UNUSED_ARG(aInterface); 2058 OSCL_UNUSED_ARG(aUuid); 2059 return true; 2060 } 2061 void PVRefFileOutput::queryUuid(PVUuid& uuid) 2062 { 2063 OSCL_UNUSED_ARG(uuid); 2064 } 2065 // 2066 // For active timing support 2067 // 2068 OSCL_EXPORT_REF PVMFStatus PVRefFileOutputActiveTimingSupport::SetClock(PVMFMediaClock *clockVal) 2069 { 2070 iClock = clockVal; 2071 return PVMFSuccess; 2072 } 2073 2074 OSCL_EXPORT_REF void PVRefFileOutputActiveTimingSupport::addRef() 2075 { 2076 } 2077 2078 OSCL_EXPORT_REF void PVRefFileOutputActiveTimingSupport::removeRef() 2079 { 2080 } 2081 2082 OSCL_EXPORT_REF bool PVRefFileOutputActiveTimingSupport::queryInterface(const PVUuid& aUuid, PVInterface*& aInterface) 2083 { 2084 aInterface = NULL; 2085 PVUuid uuid; 2086 queryUuid(uuid); 2087 if (uuid == aUuid) 2088 { 2089 PvmiClockExtensionInterface* myInterface = OSCL_STATIC_CAST(PvmiClockExtensionInterface*, this); 2090 aInterface = OSCL_STATIC_CAST(PVInterface*, myInterface); 2091 return true; 2092 } 2093 return false; 2094 } 2095 2096 void PVRefFileOutputActiveTimingSupport::queryUuid(PVUuid& uuid) 2097 { 2098 uuid = PvmiClockExtensionInterfaceUuid; 2099 } 2100 2101 bool PVRefFileOutputActiveTimingSupport::FrameStepMode() 2102 { 2103 if (iClock && iClock->GetCountTimebase()) 2104 { 2105 //frame-step mode detected! 2106 2107 //there will be a discontinuity in the rendering-- so reset the 2108 //simulated delay control now. 2109 if (iLastTimestampValid) 2110 { 2111 iLastTimestampValid = false; 2112 } 2113 return true; 2114 } 2115 return false; 2116 } 2117 2118 void PVRefFileOutputActiveTimingSupport::AdjustClock(PVMFTimestamp& aTs) 2119 { 2120 //Adjust player clock to match rendering time. 2121 //This is called at the time of simulated rendering. 2122 //On a real device, we would read the rendering position from the device. 2123 //In this simulation, we just assume that data is rendered ASAP and there 2124 //is no drift in the rendering device clock. 2125 //Therefore we just set the player clock to match the media timestamp at 2126 //the time of simulated rendering. 2127 //However, only adjust the clock ahead when in frame step mode 2128 2129 if (iClock) 2130 { 2131 uint32 clktime; 2132 uint32 tbtime; 2133 bool overflow = 0; 2134 iClock->GetCurrentTime32(clktime, overflow, PVMF_MEDIA_CLOCK_MSEC, tbtime); 2135 { 2136 // always adjust clock if not in frame step mode 2137 // if in framestep mode, only adjust clock if the timestamp is ahead 2138 bool frameStep = FrameStepMode(); 2139 if (!frameStep || (frameStep && (aTs > (PVMFTimestamp)clktime))) 2140 { 2141 if (!iLogger) 2142 { 2143 iLogger = PVLogger::GetLoggerObject("PVRefFileOutput"); 2144 } 2145 uint32 adjtime = aTs; 2146 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, 2147 (0, "PVRefFileOutputActiveTimingSupport::AdjustClock: from %d to %d", (uint32)clktime, (uint32)adjtime)); 2148 iClock->AdjustClockTime32(clktime, tbtime, adjtime, PVMF_MEDIA_CLOCK_MSEC, overflow); 2149 } 2150 } 2151 } 2152 } 2153 2154 //This routine does 2 things-- computes the delay before we can render this frame, 2155 //based on simulated rendering time for the prior frame, and adjusts the 2156 //player clock when it's time to render this frame. 2157 uint32 PVRefFileOutputActiveTimingSupport::GetDelayMsec(PVMFTimestamp& aTs) 2158 { 2159 //This routine can be called twice per frame. On the first call, if 2160 //a non-zero delay is returned, it will be called a second time after the delay 2161 //has elapsed. 2162 2163 if (iDelay > 0) 2164 { 2165 //already delayed this frame, so render now. 2166 iDelay = 0; 2167 } 2168 else //first call for this frame. 2169 { 2170 if (!iLastTimestampValid) 2171 { 2172 //this is the very first frame-- render it ASAP. 2173 //render first frame ASAP. 2174 iLastTimestampValid = true; 2175 iDelay = 0; 2176 } 2177 else 2178 { 2179 //not the first frame. 2180 //delay long enough to allow the prior data to render. 2181 iDelay = aTs - iLastTimestamp; 2182 } 2183 //save this timestamp for next delta computation. 2184 iLastTimestamp = aTs; 2185 } 2186 2187 //if delay is zero, it's time to render now. in this case, we 2188 //need to adjust the player clock with the device rendering time. 2189 if (iDelay == 0) 2190 { 2191 AdjustClock(aTs); 2192 } 2193 2194 return iDelay; 2195 } 2196 2197 // 2198 // Private section 2199 // 2200 PVMFStatus PVRefFileOutput::HandleReConfig(uint32 aReconfigSeqNum) 2201 { 2202 PVMFStatus status = PVMFFailure; 2203 /* Close the existing file and open a new one */ 2204 if (iFileOpened) 2205 { 2206 iOutputFile.Close(); 2207 } 2208 iFileOpened = false; 2209 2210 aReconfigSeqNum++; 2211 oscl_wchar append[8]; 2212 OSCL_wStackString<8> fmt(_STRLIT_WCHAR("%d")); 2213 oscl_snprintf(append, 8, fmt.get_cstr(), aReconfigSeqNum); 2214 append[7] = (oscl_wchar)'\0'; 2215 OSCL_wStackString<32> appendString(append); 2216 iOutputFileName += appendString.get_cstr(); 2217 if (iOutputFile.Open(iOutputFileName.get_cstr(), Oscl_File::MODE_READWRITE | Oscl_File::MODE_BINARY, iFs) == 0) 2218 { 2219 status = PVMFSuccess; 2220 iFileOpened = true; 2221 iParametersLogged = false; 2222 } 2223 return status; 2224 } 2225 2226 void PVRefFileOutput::Run() 2227 { 2228 //send async command responses 2229 while (!iCommandResponseQueue.empty()) 2230 { 2231 if (iObserver) 2232 { 2233 iObserver->RequestCompleted(PVMFCmdResp(iCommandResponseQueue[0].iCmdId, iCommandResponseQueue[0].iContext, iCommandResponseQueue[0].iStatus)); 2234 } 2235 iCommandResponseQueue.erase(&iCommandResponseQueue[0]); 2236 } 2237 2238 2239 //send async write completion 2240 while (!iWriteResponseQueue.empty()) 2241 { 2242 //for active timing mode, insert some delays to simulate 2243 //actual device rendering time. 2244 if (!iWriteResponseQueue[0].iDiscard 2245 && iActiveTiming) 2246 { 2247 uint32 delay = iActiveTiming->GetDelayMsec(iWriteResponseQueue[0].iTimestamp); 2248 if (delay > 0) 2249 { 2250 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 2251 (0, "PVRefFileOutput::Run() Re-scheduling in %d msec", delay)); 2252 RunIfNotReady(delay*1000); 2253 return; 2254 } 2255 } 2256 //report write complete 2257 if (iPeer) 2258 { 2259 iPeer->writeComplete(iWriteResponseQueue[0].iStatus, iWriteResponseQueue[0].iCmdId, (OsclAny*)iWriteResponseQueue[0].iContext); 2260 } 2261 //report playback position to the test observer. 2262 if (iTestObserver) 2263 { 2264 iTestObserver->Pos(iWriteResponseQueue[0].iTimestamp); 2265 } 2266 iWriteResponseQueue.erase(&iWriteResponseQueue[0]); 2267 } 2268 2269 //Re-start the data transfer if needed. 2270 if (iWriteBusy && iPeer) 2271 { 2272 iWriteBusy = false; 2273 iPeer->statusUpdate(PVMI_MEDIAXFER_STATUS_WRITE); 2274 } 2275 } 2276 2277 2278 int32 PVRefFileOutput::yuv2rgb(uint8 * pBufRGBRev, uint8 * pBufYUV, int32 width, int32 height) 2279 { 2280 int32 i, j, yi, yj; 2281 int32 w2 = width / 2; 2282 int32 rowoff, yrowoff, uvrowoff; 2283 uint8 *pBufY = pBufYUV; 2284 uint8 *pBufU = pBufYUV + width * height; 2285 uint8 *pBufV = pBufU + width * height / 4; 2286 2287 for (i = 0, yi = 0; i < height; i++, yi++) 2288 { 2289 rowoff = ((height - 1) - i) * width * 3; 2290 yrowoff = yi * width; 2291 uvrowoff = (yi / 2) * w2; 2292 for (j = 0, yj = 0; j < width*3; j += 3, yj++) 2293 { 2294 pBufRGBRev[rowoff+j] = (uint8)max(0, min(255, (1.164 * (pBufY[yrowoff+yj] - 16) + 2295 2.018 * (pBufU[uvrowoff+yj/2] - 128)))); // blue 2296 pBufRGBRev[rowoff+j+1] = (uint8)max(0, min(255, (1.164 * (pBufY[yrowoff+yj] - 16) - 2297 0.813 * (pBufV[uvrowoff+yj/2] - 128) - 2298 0.391 * (pBufU[uvrowoff+yj/2] - 128)))); // green 2299 pBufRGBRev[rowoff+j+2] = (uint8)max(0, min(255, (1.164 * (pBufY[yrowoff+yj] - 16) + 2300 1.596 * (pBufV[uvrowoff+yj/2] - 128)))); // red 2301 2302 } 2303 } 2304 return 0; 2305 } 2306 2307 2308 void PVRefFileOutput::InitializeAVI(int width, int height) 2309 { 2310 2311 uint32 fsize, bsize; 2312 fsize = width * height; // avi physical frame size 2313 bsize = width * height * 3; // frame buffer size 2314 2315 //Init the AVIMainHeader 2316 iAVIMainHeader.dwMicroSecPerFrame = 200000; 2317 iAVIMainHeader.dwMaxBytesPerSec = 5 * 3 * width * height; 2318 iAVIMainHeader.dwPaddingGranularity = 0; 2319 iAVIMainHeader.dwFlags = AVIF_TRUSTCKTYPE_FILE_OUT | AVIF_HASINDEX_FILE_OUT; 2320 iAVIMainHeader.dwTotalFrames = DEFAULT_COUNT; 2321 iAVIMainHeader.dwInitialFrames = 0; 2322 iAVIMainHeader.dwStreams = 1; 2323 iAVIMainHeader.dwSuggestedBufferSize = bsize; 2324 iAVIMainHeader.dwWidth = width; 2325 iAVIMainHeader.dwHeight = height; 2326 iAVIMainHeader.dwScale = 0; 2327 iAVIMainHeader.dwRate = 0; 2328 iAVIMainHeader.dwStart = 0; 2329 iAVIMainHeader.dwLength = 0; 2330 2331 // creating fourCC independent parameters 2332 iAVIStreamHeader.fccType = streamtypeVIDEO; 2333 /* support only YUV for now */ 2334 iAVIStreamHeader.fccHandler = mmioFOURCC('I', '4', '2', '0'); // BI_RGB 2335 iAVIStreamHeader.dwFlags = 0; // containing AVITF_ flags 2336 iAVIStreamHeader.wPriority = 0; 2337 iAVIStreamHeader.wLanguage = 0; 2338 iAVIStreamHeader.dwScale = 1000; 2339 iAVIStreamHeader.dwInitialFrames = 0; 2340 iAVIStreamHeader.dwRate = 5000; 2341 iAVIStreamHeader.dwStart = 0; 2342 iAVIStreamHeader.dwLength = DEFAULT_COUNT; /* will be changed later */ 2343 iAVIStreamHeader.dwSuggestedBufferSize = bsize; 2344 iAVIStreamHeader.dwQuality = 0; 2345 iAVIStreamHeader.dwSampleSize = 0; 2346 iAVIStreamHeader.rcFrame.left = 0; 2347 iAVIStreamHeader.rcFrame.top = 0; 2348 iAVIStreamHeader.rcFrame.right = width; 2349 iAVIStreamHeader.rcFrame.bottom = height; 2350 2351 bi_hdr.biSize = sizeof(bi_hdr); 2352 bi_hdr.biWidth = width; 2353 bi_hdr.biHeight = height; 2354 bi_hdr.biPlanes = 1; 2355 bi_hdr.biXPelsPerMeter = 0; 2356 bi_hdr.biYPelsPerMeter = 0; 2357 bi_hdr.biClrUsed = 0; 2358 bi_hdr.biClrImportant = 0; 2359 bi_hdr.biBitCount = 24; // every WORD a pixel 2360 bi_hdr.biSizeImage = bsize; 2361 bi_hdr.biCompression = iAVIStreamHeader.fccHandler; 2362 } 2363 2364 2365 void PVRefFileOutput::WriteHeaders() 2366 { 2367 if (iLogOutputToFile) 2368 { 2369 2370 uint32 tmp; 2371 2372 #ifndef AVI_OUTPUT 2373 return; 2374 #endif 2375 2376 tmp = FOURCC_RIFF; 2377 iOutputFile.Write(&tmp, sizeof(uint8), sizeof(uint32)); //"RIFF" 2378 tmp = 38016; 2379 iOutputFile.Write(&tmp, sizeof(uint8), sizeof(uint32)); //4-byte size til the end 2380 tmp = formtypeAVI; 2381 iOutputFile.Write(&tmp, sizeof(uint8), sizeof(uint32)); //"AVI " 2382 tmp = FOURCC_LIST; 2383 iOutputFile.Write(&tmp, sizeof(uint8), sizeof(uint32)); //"LIST" 2384 tmp = 4 + 4 + 4 + sizeof(AVIMainHeader) + 4 + 4 + 4 + 4 + 4 + 4 + 4 + sizeof(AVIStreamHeader) + sizeof(BitMapInfoHeader); 2385 iOutputFile.Write(&tmp, sizeof(uint8), sizeof(uint32)); //4-byte list chunk size (entire list including all streams) 2386 2387 // Write AVIMainHeader 2388 tmp = listtypeAVIHEADER; 2389 iOutputFile.Write(&tmp, sizeof(uint8), sizeof(uint32)); //"hdrl" 2390 tmp = ckidAVIMAINHDR; 2391 iOutputFile.Write(&tmp, sizeof(uint8), sizeof(uint32)); //"avih" 2392 tmp = sizeof(AVIMainHeader); 2393 iOutputFile.Write(&tmp, sizeof(uint8), sizeof(uint32)); //4-byte AVI Header size 2394 iAVIMainHeaderPosition = (TOsclFileOffsetInt32)iOutputFile.Tell(); 2395 iOutputFile.Write(&iAVIMainHeader, sizeof(uint8), sizeof(AVIMainHeader)); //AVI Header Data 2396 2397 tmp = FOURCC_LIST; 2398 iOutputFile.Write(&tmp, sizeof(uint8), sizeof(uint32)); //"LIST" 2399 tmp = 4 + 4 + 4 + 4 + 4 + sizeof(AVIStreamHeader) + sizeof(BitMapInfoHeader); 2400 iOutputFile.Write(&tmp, sizeof(uint8), sizeof(uint32)); //4-byte size of second LIST chunk (for the first stream) 2401 tmp = listtypeSTREAMHEADER; 2402 iOutputFile.Write(&tmp, sizeof(uint8), sizeof(uint32)); //"strl" 2403 tmp = ckidSTREAMHEADER; 2404 iOutputFile.Write(&tmp, sizeof(uint8), sizeof(uint32)); //"strh" 2405 tmp = sizeof(AVIStreamHeader); //size of strh 2406 iOutputFile.Write(&tmp, sizeof(uint8), sizeof(uint32)); //4-byte size of strh 2407 2408 iAVIStreamHeaderPosition = (TOsclFileOffsetInt32)iOutputFile.Tell(); 2409 iOutputFile.Write(&iAVIStreamHeader, sizeof(uint8), sizeof(AVIStreamHeader)); 2410 2411 2412 tmp = ckidSTREAMFORMAT; //same format as BITMAPINFO 2413 iOutputFile.Write(&tmp, sizeof(uint8), sizeof(uint32)); //"strf" 2414 tmp = sizeof(BitMapInfoHeader); 2415 iOutputFile.Write(&tmp, sizeof(uint8), sizeof(uint32)); //4-byte size of strf 2416 iOutputFile.Write(&bi_hdr, sizeof(uint8), sizeof(BitMapInfoHeader)); //stream format data 2417 2418 tmp = FOURCC_LIST; 2419 iOutputFile.Write(&tmp, sizeof(uint8), sizeof(uint32)); //"LIST" 2420 iVideoHeaderPosition = (TOsclFileOffsetInt32)iOutputFile.Tell(); 2421 tmp = 0; 2422 iOutputFile.Write(&tmp, sizeof(uint8), sizeof(uint32)); //4-byte size of movi chunk below 2423 tmp = listtypeAVIMOVIE; 2424 iOutputFile.Write(&tmp, sizeof(uint8), sizeof(uint32)); //"movi" 2425 } 2426 2427 uint32 tmp; 2428 tmp = ckidAVINEWINDEX; 2429 oscl_memcpy(&iIndexBuffer.indexBuffer[0], &tmp, sizeof(uint32)); 2430 iIndexBuffer.length = 4; 2431 tmp = 0; 2432 oscl_memcpy(&iIndexBuffer.indexBuffer[iIndexBuffer.length], &tmp, sizeof(uint32)); 2433 iIndexBuffer.length += 4; 2434 } 2435 2436 void PVRefFileOutput::AddChunk(uint8* chunk, uint32 size, uint32 ckid) 2437 { 2438 if (iLogOutputToFile) 2439 { 2440 iOutputFile.Write(&ckid, sizeof(uint8), sizeof(uint32)); 2441 iOutputFile.Write(&size, sizeof(uint8), sizeof(uint32)); 2442 iOutputFile.Write(chunk, sizeof(uint8), size); 2443 } 2444 2445 iAVIIndex.chunkID = videoChunkID; 2446 iAVIIndex.flags = 0x10; 2447 if (iVideoCount == 0) 2448 { 2449 iAVIIndex.offset = iIndexBuffer.length - 4; 2450 iVideoCount++; 2451 iPreviousOffset = iAVIIndex.offset; 2452 } 2453 else 2454 { 2455 iAVIIndex.offset = iPreviousOffset + size + 8; 2456 iPreviousOffset = iAVIIndex.offset; 2457 // iAVIIndex.offset = 4 + (size + 8) * iVideoCount; //iIndexBuffer.length + size * iVideoCount; 2458 iVideoCount++; 2459 } 2460 iAVIIndex.length = size; 2461 oscl_memcpy(&iIndexBuffer.indexBuffer[iIndexBuffer.length], &iAVIIndex, sizeof(AVIIndex)); 2462 iIndexBuffer.length += sizeof(AVIIndex); 2463 } 2464 2465 void PVRefFileOutput::UpdateWaveChunkSize() 2466 { 2467 if (iLogOutputToFile) 2468 { 2469 int32 ret = (TOsclFileOffsetInt32)iOutputFile.Tell(); 2470 iOutputFile.Seek(4, Oscl_File::SEEKSET); 2471 ret = (TOsclFileOffsetInt32)iOutputFile.Tell(); 2472 } 2473 iRIFFChunk.chunkSize = 36 + iDataSubchunk.subchunk2Size; 2474 if (iLogOutputToFile) 2475 { 2476 iOutputFile.Write(&iRIFFChunk.chunkSize, sizeof(uint8), 4); 2477 iOutputFile.Seek(40, Oscl_File::SEEKSET); 2478 iOutputFile.Write(&iDataSubchunk.subchunk2Size, sizeof(uint8), 4); 2479 iOutputFile.Flush(); 2480 } 2481 } 2482 2483 void PVRefFileOutput::UpdateVideoChunkHeaderIdx() 2484 { 2485 //update the AVI Main Header 2486 if (iVideoCount == 0 || iVideoLastTimeStamp == 0) return; 2487 iAVIMainHeader.dwMicroSecPerFrame = (uint32)((float)iVideoLastTimeStamp / (float)iVideoCount * 1000); 2488 iAVIMainHeader.dwMaxBytesPerSec = (uint32)((float)(iVideoCount * 3 * iVideoHeight * iVideoWidth) / (float)iVideoLastTimeStamp * 1000); 2489 iAVIMainHeader.dwTotalFrames = iVideoCount; 2490 2491 if (iLogOutputToFile) 2492 { 2493 iOutputFile.Seek(iAVIMainHeaderPosition, Oscl_File::SEEKSET); 2494 iOutputFile.Write(&iAVIMainHeader, sizeof(uint8), sizeof(AVIMainHeader)); 2495 } 2496 2497 iAVIStreamHeader.dwRate = (uint32)((float)(iVideoCount * 1000000) / (float)iVideoLastTimeStamp); 2498 iAVIStreamHeader.dwLength = iVideoCount; 2499 2500 if (iLogOutputToFile) 2501 { 2502 iOutputFile.Seek(iAVIStreamHeaderPosition, Oscl_File::SEEKSET); 2503 iOutputFile.Write(&iAVIStreamHeader, sizeof(uint8), sizeof(AVIStreamHeader)); 2504 iOutputFile.Seek(0, Oscl_File::SEEKEND); 2505 } 2506 2507 uint32 tmp = iIndexBuffer.length - 8; 2508 2509 //write the indexBuffer to the file 2510 oscl_memcpy(&iIndexBuffer.indexBuffer[4], &tmp, sizeof(uint32)); 2511 if (iLogOutputToFile) 2512 { 2513 iOutputFile.Write(iIndexBuffer.indexBuffer, sizeof(uint8), iIndexBuffer.length); 2514 iOutputFile.Seek(0, Oscl_File::SEEKEND); 2515 } 2516 uint32 iAVISize = (TOsclFileOffsetInt32)iOutputFile.Tell() - 8; 2517 if (iLogOutputToFile) 2518 { 2519 iOutputFile.Seek(4, Oscl_File::SEEKSET); 2520 iOutputFile.Write(&iAVISize, sizeof(uint8), 4); 2521 iOutputFile.Seek(iVideoHeaderPosition, Oscl_File::SEEKSET); 2522 } 2523 iAVIChunkSize += 4; 2524 if (iLogOutputToFile) 2525 { 2526 iOutputFile.Write(&iAVIChunkSize, sizeof(uint8), 4); 2527 } 2528 } 2529 2530 #if TEST_BUFFER_ALLOCATOR 2531 2532 PVRefBufferAlloc::PVRefBufferAlloc(uint32 size, uint32 buffers): refCount(0), bufferSize(size), maxBuffers(buffers), numAllocated(0) 2533 { 2534 } 2535 2536 PVRefBufferAlloc::~PVRefBufferAlloc() 2537 { 2538 2539 } 2540 2541 void PVRefBufferAlloc::addRef() 2542 { 2543 ++refCount; 2544 } 2545 2546 void PVRefBufferAlloc::removeRef() 2547 { 2548 --refCount; 2549 if (refCount <= 0) 2550 { 2551 this->~PVRefBufferAlloc(); 2552 OSCL_DELETE(this); 2553 } 2554 } 2555 2556 2557 OsclAny* PVRefBufferAlloc::allocate() 2558 { 2559 if (numAllocated < maxBuffers) 2560 { 2561 OsclAny* ptr = oscl_malloc(bufferSize); 2562 if (ptr) ++numAllocated; 2563 return ptr; 2564 } 2565 return NULL; 2566 } 2567 2568 void PVRefBufferAlloc::deallocate(OsclAny* ptr) 2569 { 2570 if (ptr) 2571 { 2572 oscl_free(ptr); 2573 --numAllocated; 2574 } 2575 } 2576 2577 uint32 PVRefBufferAlloc::getBufferSize() 2578 { 2579 return bufferSize; 2580 } 2581 2582 uint32 PVRefBufferAlloc::getNumBuffers() 2583 { 2584 return maxBuffers; 2585 } 2586 2587 2588 bool PVRefBufferAlloc::queryInterface(const PVUuid& uuid, PVInterface*& aInterface) 2589 { 2590 aInterface = NULL; // initialize aInterface to NULL in case uuid is not supported 2591 2592 if (PVMFFixedSizeBufferAllocUUID == uuid) 2593 { 2594 // Send back ptr to the allocator interface object 2595 PVMFFixedSizeBufferAlloc* myInterface = OSCL_STATIC_CAST(PVMFFixedSizeBufferAlloc*, this); 2596 refCount++; // increment interface refcount before returning ptr 2597 aInterface = OSCL_STATIC_CAST(PVInterface*, myInterface); 2598 return true; 2599 } 2600 2601 return false; 2602 } 2603 2604 #endif 2605 2606