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 #ifndef PVMF_DUMMY_FILEINPUT_NODE_H_INCLUDED 19 #include "pvmf_dummy_fileinput_node.h" 20 #endif 21 #ifndef PVMF_FILEINPUT_NODE_INTERNAL_H_INCLUDED 22 #include "pvmf_fileinput_node_internal.h" 23 #endif 24 #ifndef PVLOGGER_H_INCLUDED 25 #include "pvlogger.h" 26 #endif 27 #ifndef PVMF_COMMON_AUDIO_DECNODE_H_INCLUDE 28 #include "pvmf_common_audio_decnode.h" 29 #endif 30 #ifndef PVMF_VIDEO_H_INCLUDED 31 #include "pvmf_video.h" 32 #endif 33 #ifndef OSCL_DLL_H_INCLUDED 34 #include "oscl_dll.h" 35 #endif 36 #ifndef PVMF_VIDEO_H_INCLUDED 37 #include "pvmf_video.h" 38 #endif 39 #ifndef PVMF_DUMMY_FILEINPUT_NODE_FACTORY_H_INCLUDED 40 #include "pvmf_dummy_fileinput_node_factory.h" 41 #endif 42 #include "pvmf_media_cmd.h" 43 #include "pvmf_media_msg_format_ids.h" 44 45 // also defined in the pvmf_fileinput_node.h: 46 // This test splits each frame into two pieces and sends them in 2 separate messages. 47 // the first message has no marker bit set, the 2nd message has marker bit set 48 //#define FRAGMENTATION_TEST 49 50 OSCL_DLL_ENTRY_POINT_DEFAULT() 51 52 #define GetUnalignedDword( pb, dw ) \ 53 (dw) = ((uint32) *(pb + 3) << 24) + \ 54 ((uint32) *(pb + 2) << 16) + \ 55 ((uint16) *(pb + 1) << 8) + *pb; 56 57 #define GetUnalignedDwordEx( pb, dw ) GetUnalignedDword( pb, dw ); (pb) += sizeof(uint32); 58 #define LoadDWORD( dw, p ) GetUnalignedDwordEx( p, dw ) 59 60 /** 61 //Macros for calling PVLogger 62 */ 63 #define LOGERROR(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_REL,iLogger,PVLOGMSG_ERR,m); 64 #define LOGINFOHI(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG,iLogger,PVLOGMSG_INFO,m); 65 #define LOGINFOMED(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG,iLogger,PVLOGMSG_INFO,m); 66 #define LOGINFOLOW(m) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG,iLogger,PVLOGMSG_INFO,m); 67 #define LOGINFO(m) LOGINFOMED(m) 68 69 70 #define PVFILEIN_MEDIADATA_POOLNUM 16 71 #define PVFILEIN_MEDIADATA_CHUNKSIZE 128 72 73 //#define SEND_CONFIGINFO_SEPARATELY 74 const uint32 AMR_FRAME_DELAY = 20; // 20ms 75 76 77 /** Factory class */ 78 OSCL_EXPORT_REF PVMFNodeInterface* PVMFDummyFileInputNodeFactory::CreateDummyFileInputNode(PVMFFileInputSettings* aSettings, 79 int32 aPriority) 80 { 81 PVMFDummyFileInputNode* node = NULL; 82 int32 err = 0; 83 OSCL_TRY(err, node = OSCL_NEW(PVMFDummyFileInputNode, (aSettings, aPriority));); 84 OSCL_FIRST_CATCH_ANY(err, return NULL;); 85 return node; 86 } 87 88 OSCL_EXPORT_REF bool PVMFDummyFileInputNodeFactory::DeleteDummyFileInputNode(PVMFNodeInterface*& aNode) 89 { 90 if (!aNode) 91 return false; 92 PVMFDummyFileInputNode* node = (PVMFDummyFileInputNode*)aNode; 93 OSCL_DELETE(node); 94 aNode = NULL; 95 return true; 96 } 97 98 /** 99 ////////////////////////////////////////////////// 100 // Node Constructor & Destructor 101 ////////////////////////////////////////////////// 102 */ 103 104 OSCL_EXPORT_REF PVMFDummyFileInputNode::PVMFDummyFileInputNode(PVMFFileInputSettings* aSettings, int32 aPriority) 105 : OsclTimerObject(aPriority, "PVMFDummyFileInputNode") 106 , iMediaBufferMemPool(NULL) 107 , iMediaDataAlloc(NULL) 108 , iMediaDataMemPool(PVFILEIN_MEDIADATA_POOLNUM, PVFILEIN_MEDIADATA_CHUNKSIZE) 109 , iAudioData(NULL) 110 , iVideoData(NULL) 111 , iLogger(NULL) 112 , iFormatSpecificInfoSize(0) 113 , iSetFormatSpecificInfo(false) 114 , iFileHeaderSize(0) 115 , iFsOpen(false) 116 , iFileOpen(false) 117 , iDataEventCounter(0) 118 , iTotalNumFrames(0) 119 , iMilliSecondsPerDataEvent(0) 120 , iMicroSecondsPerDataEvent(0) 121 , iTSForRunIfInactive(0) 122 , iTimeStamp(0) 123 , iExtensionRefCount(0) 124 , iWaitingOnFreeChunk(false) 125 , iEndOfFileReached(false) 126 { 127 int32 err; 128 OSCL_TRY(err, 129 130 //Create the input command queue. Use a reserve to avoid lots of 131 //dynamic memory allocation. 132 iInputCommands.Construct(PVMF_FILEINPUT_NODE_COMMAND_ID_START, PVMF_FILEINPUT_NODE_COMMAND_VECTOR_RESERVE); 133 134 //Create the "current command" queue. It will only contain one 135 //command at a time, so use a reserve of 1. 136 iCurrentCommand.Construct(0, 1); 137 138 //Create the port vector. 139 iPortVector.Construct(PVMF_FILEINPUT_NODE_PORT_VECTOR_RESERVE); 140 141 //Set the node capability data. 142 //This node can support an unlimited number of ports. 143 iCapability.iCanSupportMultipleInputPorts = true; 144 iCapability.iCanSupportMultipleOutputPorts = true; 145 iCapability.iHasMaxNumberOfPorts = false; 146 iCapability.iMaxNumberOfPorts = 0;//no maximum 147 // chesterc: The node only supports the format of the input file, not 148 // all formats that the node could parse. 149 iCapability.iOutputFormatCapability.push_back(aSettings->iMediaFormat); 150 151 // construct iSettings 152 ConstructInputSettings(aSettings); 153 ); 154 155 if (err != OsclErrNone) 156 { 157 //if a leave happened, cleanup and re-throw the error 158 iInputCommands.clear(); 159 iCurrentCommand.clear(); 160 iPortVector.clear(); 161 iCapability.iInputFormatCapability.clear(); 162 iCapability.iOutputFormatCapability.clear(); 163 OSCL_CLEANUP_BASE_CLASS(PVMFNodeInterface); 164 OSCL_CLEANUP_BASE_CLASS(OsclTimerObject); 165 OSCL_LEAVE(err); 166 } 167 } 168 169 OSCL_EXPORT_REF PVMFDummyFileInputNode::~PVMFDummyFileInputNode() 170 { 171 //thread logoff 172 if (IsAdded()) 173 RemoveFromScheduler(); 174 175 //Cleanup allocated interfaces 176 177 //Cleanup allocated ports 178 while (!iPortVector.empty()) 179 iPortVector.Erase(&iPortVector.front()); 180 181 //Cleanup commands 182 //The command queues are self-deleting, but we want to 183 //notify the observer of unprocessed commands. 184 while (!iCurrentCommand.empty()) 185 { 186 CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFFailure); 187 } 188 while (!iInputCommands.empty()) 189 { 190 CommandComplete(iInputCommands, iInputCommands.front(), PVMFFailure); 191 } 192 193 CloseInputFile(); 194 iAlloc.deallocate((OsclAny*)iAudioData); 195 iAlloc.deallocate((OsclAny*)iVideoData); 196 197 if (iMediaBufferMemPool) 198 { 199 OSCL_DELETE(iMediaBufferMemPool); 200 iMediaBufferMemPool = NULL; 201 } 202 203 if (iMediaDataAlloc) 204 { 205 OSCL_DELETE(iMediaDataAlloc); 206 iMediaDataAlloc = NULL; 207 } 208 } 209 210 /** 211 ////////////////////////////////////////////////// 212 // Public Node API implementation 213 ////////////////////////////////////////////////// 214 */ 215 216 /** 217 //Do thread-specific node creation and go to "Idle" state. 218 */ 219 OSCL_EXPORT_REF PVMFStatus PVMFDummyFileInputNode::ThreadLogon() 220 { 221 LOGINFO((0, "FileInputNode:ThreadLogon")); 222 switch (iInterfaceState) 223 { 224 case EPVMFNodeCreated: 225 if (!IsAdded()) 226 AddToScheduler(); 227 iLogger = PVLogger::GetLoggerObject("PVMFDummyFileInputNode"); 228 SetState(EPVMFNodeIdle); 229 return PVMFSuccess; 230 break; 231 default: 232 return PVMFErrInvalidState; 233 break; 234 } 235 } 236 237 /** 238 //Do thread-specific node cleanup and go to "Created" state. 239 */ 240 OSCL_EXPORT_REF PVMFStatus PVMFDummyFileInputNode::ThreadLogoff() 241 { 242 LOGINFO((0, "FileInputNode:ThreadLogoff")); 243 switch (iInterfaceState) 244 { 245 case EPVMFNodeIdle: 246 if (IsAdded()) 247 RemoveFromScheduler(); 248 iLogger = NULL; 249 SetState(EPVMFNodeCreated); 250 return PVMFSuccess; 251 break; 252 253 default: 254 return PVMFErrInvalidState; 255 break; 256 } 257 } 258 259 /** 260 //retrieve node capabilities. 261 */ 262 OSCL_EXPORT_REF PVMFStatus PVMFDummyFileInputNode::GetCapability(PVMFNodeCapability& aNodeCapability) 263 { 264 LOGINFO((0, "FileInputNode:GetCapability")); 265 aNodeCapability = iCapability; 266 return PVMFSuccess; 267 } 268 269 /** 270 //retrive a port iterator. 271 */ 272 OSCL_EXPORT_REF PVMFPortIter* PVMFDummyFileInputNode::GetPorts(const PVMFPortFilter* aFilter) 273 { 274 LOGINFO((0, "FileInputNode:GetPorts")); 275 OSCL_UNUSED_ARG(aFilter);//port filter is not implemented. 276 iPortVector.Reset(); 277 return &iPortVector; 278 } 279 280 /** 281 //Queue an asynchronous node command 282 */ 283 OSCL_EXPORT_REF PVMFCommandId PVMFDummyFileInputNode::QueryUUID(PVMFSessionId s, const PvmfMimeString& aMimeType, 284 Oscl_Vector<PVUuid, OsclMemAllocator>& aUuids, 285 bool aExactUuidsOnly, 286 const OsclAny* aContext) 287 { 288 LOGINFO((0, "FileInputNode:QueryUUID")); 289 PVMFFileInputNodeCommand cmd; 290 cmd.PVMFFileInputNodeCommandBase::Construct(s, PVMF_GENERIC_NODE_QUERYUUID, aMimeType, aUuids, aExactUuidsOnly, aContext); 291 return QueueCommandL(cmd); 292 } 293 294 /** 295 //Queue an asynchronous node command 296 */ 297 OSCL_EXPORT_REF PVMFCommandId PVMFDummyFileInputNode::QueryInterface(PVMFSessionId s, const PVUuid& aUuid, 298 PVInterface*& aInterfacePtr, 299 const OsclAny* aContext) 300 { 301 LOGINFO((0, "FileInputNode:QueryInterface")); 302 PVMFFileInputNodeCommand cmd; 303 cmd.PVMFFileInputNodeCommandBase::Construct(s, PVMF_GENERIC_NODE_QUERYINTERFACE, aUuid, aInterfacePtr, aContext); 304 return QueueCommandL(cmd); 305 } 306 307 /** 308 //Queue an asynchronous node command 309 */ 310 OSCL_EXPORT_REF PVMFCommandId PVMFDummyFileInputNode::RequestPort(PVMFSessionId s, int32 aPortTag, const PvmfMimeString* aPortConfig, const OsclAny* aContext) 311 { 312 OSCL_UNUSED_ARG(aPortConfig); 313 LOGINFO((0, "FileInputNode:RequestPort")); 314 PVMFFileInputNodeCommand cmd; 315 cmd.PVMFFileInputNodeCommandBase::Construct(s, PVMF_GENERIC_NODE_REQUESTPORT, aPortTag, aPortConfig, aContext); 316 return QueueCommandL(cmd); 317 } 318 319 /** 320 //Queue an asynchronous node command 321 */ 322 OSCL_EXPORT_REF PVMFCommandId PVMFDummyFileInputNode::ReleasePort(PVMFSessionId s, PVMFPortInterface& aPort, const OsclAny* aContext) 323 { 324 LOGINFO((0, "FileInputNode:ReleasePort")); 325 PVMFFileInputNodeCommand cmd; 326 cmd.PVMFFileInputNodeCommandBase::Construct(s, PVMF_GENERIC_NODE_RELEASEPORT, aPort, aContext); 327 return QueueCommandL(cmd); 328 } 329 330 /** 331 //Queue an asynchronous node command 332 */ 333 OSCL_EXPORT_REF PVMFCommandId PVMFDummyFileInputNode::Init(PVMFSessionId s, const OsclAny* aContext) 334 { 335 LOGINFO((0, "FileInputNode:Init")); 336 PVMFFileInputNodeCommand cmd; 337 cmd.PVMFFileInputNodeCommandBase::Construct(s, PVMF_GENERIC_NODE_INIT, aContext); 338 return QueueCommandL(cmd); 339 } 340 341 /** 342 //Queue an asynchronous node command 343 */ 344 OSCL_EXPORT_REF PVMFCommandId PVMFDummyFileInputNode::Prepare(PVMFSessionId s, const OsclAny* aContext) 345 { 346 LOGINFO((0, "FileInputNode:Prepare")); 347 PVMFFileInputNodeCommand cmd; 348 cmd.PVMFFileInputNodeCommandBase::Construct(s, PVMF_GENERIC_NODE_PREPARE, aContext); 349 return QueueCommandL(cmd); 350 } 351 352 /** 353 //Queue an asynchronous node command 354 */ 355 OSCL_EXPORT_REF PVMFCommandId PVMFDummyFileInputNode::Start(PVMFSessionId s, const OsclAny* aContext) 356 { 357 LOGINFO((0, "FileInputNode:Start")); 358 PVMFFileInputNodeCommand cmd; 359 cmd.PVMFFileInputNodeCommandBase::Construct(s, PVMF_GENERIC_NODE_START, aContext); 360 return QueueCommandL(cmd); 361 } 362 363 /** 364 //Queue an asynchronous node command 365 */ 366 OSCL_EXPORT_REF PVMFCommandId PVMFDummyFileInputNode::Stop(PVMFSessionId s, const OsclAny* aContext) 367 { 368 LOGINFO((0, "FileInputNode:Stop")); 369 PVMFFileInputNodeCommand cmd; 370 cmd.PVMFFileInputNodeCommandBase::Construct(s, PVMF_GENERIC_NODE_STOP, aContext); 371 return QueueCommandL(cmd); 372 } 373 374 /** 375 //Queue an asynchronous node command 376 */ 377 OSCL_EXPORT_REF PVMFCommandId PVMFDummyFileInputNode::Flush(PVMFSessionId s, const OsclAny* aContext) 378 { 379 LOGINFO((0, "FileInputNode:Flush")); 380 PVMFFileInputNodeCommand cmd; 381 cmd.PVMFFileInputNodeCommandBase::Construct(s, PVMF_GENERIC_NODE_FLUSH, aContext); 382 return QueueCommandL(cmd); 383 } 384 385 /** 386 //Queue an asynchronous node command 387 */ 388 OSCL_EXPORT_REF PVMFCommandId PVMFDummyFileInputNode::Pause(PVMFSessionId s, const OsclAny* aContext) 389 { 390 LOGINFO((0, "FileInputNode:Pause")); 391 PVMFFileInputNodeCommand cmd; 392 cmd.PVMFFileInputNodeCommandBase::Construct(s, PVMF_GENERIC_NODE_PAUSE, aContext); 393 return QueueCommandL(cmd); 394 } 395 396 /** 397 //Queue an asynchronous node command 398 */ 399 OSCL_EXPORT_REF PVMFCommandId PVMFDummyFileInputNode::Reset(PVMFSessionId s, const OsclAny* aContext) 400 { 401 LOGINFO((0, "FileInputNode:Reset")); 402 PVMFFileInputNodeCommand cmd; 403 cmd.PVMFFileInputNodeCommandBase::Construct(s, PVMF_GENERIC_NODE_RESET, aContext); 404 return QueueCommandL(cmd); 405 } 406 407 /** 408 //Queue an asynchronous node command 409 */ 410 OSCL_EXPORT_REF PVMFCommandId PVMFDummyFileInputNode::CancelAllCommands(PVMFSessionId s, const OsclAny* aContext) 411 { 412 LOGINFO((0, "FileInputNode:CancelAllCommands")); 413 PVMFFileInputNodeCommand cmd; 414 cmd.PVMFFileInputNodeCommandBase::Construct(s, PVMF_GENERIC_NODE_CANCELALLCOMMANDS, aContext); 415 return QueueCommandL(cmd); 416 } 417 418 /** 419 //Queue an asynchronous node command 420 */ 421 OSCL_EXPORT_REF PVMFCommandId PVMFDummyFileInputNode::CancelCommand(PVMFSessionId s, PVMFCommandId aCmdId, const OsclAny* aContext) 422 { 423 LOGINFO((0, "FileInputNode:CancelCommand")); 424 PVMFFileInputNodeCommand cmd; 425 cmd.PVMFFileInputNodeCommandBase::Construct(s, PVMF_GENERIC_NODE_CANCELCOMMAND, aCmdId, aContext); 426 return QueueCommandL(cmd); 427 } 428 429 //////////////////////////////////////////////////////////////////////////// 430 OSCL_EXPORT_REF void PVMFDummyFileInputNode::addRef() 431 { 432 ++iExtensionRefCount; 433 } 434 435 //////////////////////////////////////////////////////////////////////////// 436 OSCL_EXPORT_REF void PVMFDummyFileInputNode::removeRef() 437 { 438 --iExtensionRefCount; 439 } 440 441 //////////////////////////////////////////////////////////////////////////// 442 OSCL_EXPORT_REF bool PVMFDummyFileInputNode::queryInterface(const PVUuid& uuid, PVInterface*& iface) 443 { 444 if (uuid == KPVMFFileInputNodeExtensionUuid) 445 { 446 PVMFFileInputNodeExtensionInterface* myInterface = OSCL_STATIC_CAST(PVMFFileInputNodeExtensionInterface*, this); 447 iface = OSCL_STATIC_CAST(PVInterface*, myInterface); 448 ++iExtensionRefCount; 449 return true; 450 } 451 452 return false; 453 } 454 455 //////////////////////////////////////////////////////////////////////////// 456 OSCL_EXPORT_REF bool PVMFDummyFileInputNode::GetBitstreamConfig(OsclRefCounterMemFrag& aConfig) 457 { 458 if (!iFormatSpecificInfo.getMemFragPtr()) 459 return false; 460 461 aConfig = iFormatSpecificInfo; 462 return true; 463 } 464 465 466 /** 467 //This routine is called by various command APIs to queue an 468 //asynchronous command for processing by the command handler AO. 469 //This function may leave if the command can't be queued due to 470 //memory allocation failure. 471 */ 472 PVMFCommandId PVMFDummyFileInputNode::QueueCommandL(PVMFFileInputNodeCommand& aCmd) 473 { 474 PVMFCommandId id; 475 476 id = iInputCommands.AddL(aCmd); 477 478 //wakeup the AO 479 RunIfNotReady(); 480 481 return id; 482 } 483 484 /** 485 ///////////////////////////////////////////////////// 486 // Asynchronous Command processing routines. 487 // These routines are all called under the AO. 488 ///////////////////////////////////////////////////// 489 */ 490 491 /** 492 //Called by the command handler AO to process a command from 493 //the input queue. 494 //Return true if a command was processed, false if the command 495 //processor is busy and can't process another command now. 496 */ 497 bool PVMFDummyFileInputNode::ProcessCommand(PVMFFileInputNodeCommand& aCmd) 498 { 499 //normally this node will not start processing one command 500 //until the prior one is finished. However, a hi priority 501 //command such as Cancel must be able to interrupt a command 502 //in progress. 503 if (!iCurrentCommand.empty() && !aCmd.hipri()) 504 return false; 505 506 switch (aCmd.iCmd) 507 { 508 case PVMF_GENERIC_NODE_QUERYUUID: 509 DoQueryUuid(aCmd); 510 break; 511 512 case PVMF_GENERIC_NODE_QUERYINTERFACE: 513 DoQueryInterface(aCmd); 514 break; 515 516 case PVMF_GENERIC_NODE_REQUESTPORT: 517 DoRequestPort(aCmd); 518 break; 519 520 case PVMF_GENERIC_NODE_RELEASEPORT: 521 DoReleasePort(aCmd); 522 break; 523 524 case PVMF_GENERIC_NODE_INIT: 525 DoInit(aCmd); 526 break; 527 528 case PVMF_GENERIC_NODE_PREPARE: 529 DoPrepare(aCmd); 530 break; 531 532 case PVMF_GENERIC_NODE_START: 533 DoStart(aCmd); 534 break; 535 536 case PVMF_GENERIC_NODE_STOP: 537 DoStop(aCmd); 538 break; 539 540 case PVMF_GENERIC_NODE_FLUSH: 541 DoFlush(aCmd); 542 break; 543 544 case PVMF_GENERIC_NODE_PAUSE: 545 DoPause(aCmd); 546 break; 547 548 case PVMF_GENERIC_NODE_RESET: 549 DoReset(aCmd); 550 break; 551 552 case PVMF_GENERIC_NODE_CANCELALLCOMMANDS: 553 DoCancelAllCommands(aCmd); 554 break; 555 556 case PVMF_GENERIC_NODE_CANCELCOMMAND: 557 DoCancelCommand(aCmd); 558 break; 559 560 default://unknown command type 561 CommandComplete(iInputCommands, aCmd, PVMFFailure); 562 break; 563 } 564 565 return true; 566 } 567 568 /** 569 //The various command handlers call this when a command is complete. 570 */ 571 void PVMFDummyFileInputNode::CommandComplete(PVMFFileInputNodeCmdQ& aCmdQ, PVMFFileInputNodeCommand& aCmd, PVMFStatus aStatus, OsclAny* aEventData) 572 { 573 LOGINFO((0, "FileInputNode:CommandComplete Id %d Cmd %d Status %d Context %d Data %d" 574 , aCmd.iId, aCmd.iCmd, aStatus, aCmd.iContext, aEventData)); 575 576 //create response 577 PVMFCmdResp resp(aCmd.iId, aCmd.iContext, aStatus, aEventData); 578 PVMFSessionId session = aCmd.iSession; 579 580 //Erase the command from the queue. 581 aCmdQ.Erase(&aCmd); 582 583 //Report completion to the session observer. 584 ReportCmdCompleteEvent(session, resp); 585 } 586 587 /** 588 //Called by the command handler AO to do the node Reset. 589 */ 590 void PVMFDummyFileInputNode::DoReset(PVMFFileInputNodeCommand& aCmd) 591 { 592 //This example node allows a reset from any idle state. 593 switch (iInterfaceState) 594 { 595 case EPVMFNodeCreated: 596 case EPVMFNodeIdle: 597 case EPVMFNodeInitialized: 598 case EPVMFNodePrepared: 599 { 600 //delete all ports and notify observer. 601 while (!iPortVector.empty()) 602 iPortVector.Erase(&iPortVector.front()); 603 604 //restore original port vector reserve. 605 iPortVector.Reconstruct(); 606 607 // close the input file 608 CloseInputFile(); 609 610 //logoff & go back to Created state. 611 SetState(EPVMFNodeIdle); 612 PVMFStatus status = ThreadLogoff(); 613 614 CommandComplete(iInputCommands, aCmd, status); 615 } 616 break; 617 618 default: 619 CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState); 620 break; 621 } 622 } 623 624 /** 625 //Called by the command handler AO to do the Query UUID 626 */ 627 void PVMFDummyFileInputNode::DoQueryUuid(PVMFFileInputNodeCommand& aCmd) 628 { 629 //This node supports Query UUID from any state 630 631 OSCL_String* mimetype; 632 Oscl_Vector<PVUuid, OsclMemAllocator> *uuidvec; 633 bool exactmatch; 634 aCmd.PVMFFileInputNodeCommandBase::Parse(mimetype, uuidvec, exactmatch); 635 636 //Try to match the input mimetype against any of 637 //the custom interfaces for this node 638 639 //Match against extension interface... 640 if (*mimetype == PVMF_FILEINPUT_NODE_EXTENSION_INTERFACE_MIMETYPE 641 //also match against base mimetypes for custom interface1, 642 //unless exactmatch is set. 643 || (!exactmatch && *mimetype == PVMF_FILEINPUT_NODE_MIMETYPE) 644 || (!exactmatch && *mimetype == PVMF_BASEMIMETYPE)) 645 { 646 647 PVUuid uuid(KPVMFFileInputNodeExtensionUuid); 648 uuidvec->push_back(uuid); 649 } 650 CommandComplete(iInputCommands, aCmd, PVMFSuccess); 651 } 652 653 /** 654 //Called by the command handler AO to do the Query Interface. 655 */ 656 void PVMFDummyFileInputNode::DoQueryInterface(PVMFFileInputNodeCommand& aCmd) 657 { 658 //This node supports Query Interface from any state 659 660 PVUuid* uuid; 661 PVInterface** ptr; 662 aCmd.PVMFFileInputNodeCommandBase::Parse(uuid, ptr); 663 664 if (*uuid == PVUuid(KPVMFFileInputNodeExtensionUuid)) 665 { 666 queryInterface(*uuid, *ptr); 667 CommandComplete(iInputCommands, aCmd, PVMFSuccess); 668 } 669 else 670 {//not supported 671 *ptr = NULL; 672 CommandComplete(iInputCommands, aCmd, PVMFFailure); 673 } 674 } 675 676 /** 677 //Called by the command handler AO to do the port request 678 */ 679 void PVMFDummyFileInputNode::DoRequestPort(PVMFFileInputNodeCommand& aCmd) 680 { 681 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 682 (0, "PVMFDummyFileInputNode::DoRequestPort")); 683 684 //This node supports port request from any state 685 686 //this node is limited to one port 687 if (iPortVector.size() > 0) 688 { 689 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, 690 (0, "PVMFDummyFileInputNode::DoRequestPort: Multiple port request!")); 691 CommandComplete(iInputCommands, aCmd, PVMFFailure); 692 } 693 694 //retrieve port tag. 695 int32 tag; 696 OSCL_String* mimetype; 697 aCmd.PVMFFileInputNodeCommandBase::Parse(tag, mimetype); 698 699 //(mimetype is not used on this node) 700 701 //validate the tag... 702 switch (tag) 703 { 704 case PVMF_DUMMY_FILEINPUT_NODE_PORT_TYPE_SOURCE: 705 break; 706 default: 707 { 708 //bad port tag 709 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, 710 (0, "PVMFDummyFileInputNode::DoRequestPort: Error - Invalid port tag")); 711 CommandComplete(iInputCommands, aCmd, PVMFFailure); 712 return; 713 } 714 break; 715 } 716 717 //Allocate a new port 718 OsclAny *ptr = NULL; 719 int32 err; 720 OSCL_TRY(err, ptr = iPortVector.Allocate();); 721 if (err != OsclErrNone || !ptr) 722 { 723 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, 724 (0, "PVMFDummyFileInputNode::DoRequestPort: Error - iPortVector Out of memory")); 725 CommandComplete(iInputCommands, aCmd, PVMFErrNoMemory); 726 return; 727 } 728 729 //create base port 730 PVMFFileDummyInputPort*port = NULL; 731 port = new(ptr) PVMFFileDummyInputPort(tag 732 , this //the node handles port activity. 733 , INPORT_CAPACITY, INPORT_RESERVE, INPORT_THRESOLD //no input queue needed. 734 , OUTPORT_CAPACITY, OUTPORT_RESERVE, OUTPORT_THRESOLD);//output queue has a limit of 10 with no reserve 735 736 //if format was provided in mimestring, set it now. 737 if (mimetype) 738 { 739 PVMFFormatType fmt = mimetype->get_str(); 740 if (fmt != PVMF_MIME_FORMAT_UNKNOWN 741 && port->IsFormatSupported(fmt)) 742 { 743 port->iFormat = fmt; 744 port->FormatUpdated(); 745 } 746 } 747 748 //Add the port to the port vector. 749 OSCL_TRY(err, iPortVector.AddL(port);); 750 if (err != OsclErrNone) 751 { 752 CommandComplete(iInputCommands, aCmd, PVMFErrNoMemory); 753 return; 754 } 755 756 //Return the port pointer to the caller. 757 CommandComplete(iInputCommands, aCmd, PVMFSuccess, (OsclAny*)port); 758 } 759 760 /** 761 //Called by the command handler AO to do the port release 762 */ 763 void PVMFDummyFileInputNode::DoReleasePort(PVMFFileInputNodeCommand& aCmd) 764 { 765 //This node supports release port from any state 766 767 //Find the port in the port vector 768 PVMFFileDummyInputPort *port; 769 PVMFPortInterface * tempInterface = NULL; 770 771 aCmd.PVMFFileInputNodeCommandBase::Parse(tempInterface); 772 port = OSCL_STATIC_CAST(PVMFFileDummyInputPort*, tempInterface); 773 774 PVMFFileDummyInputPort** portPtr = iPortVector.FindByValue(port); 775 if (portPtr) 776 { 777 //delete the port. 778 iPortVector.Erase(portPtr); 779 CommandComplete(iInputCommands, aCmd, PVMFSuccess); 780 } 781 else 782 { 783 //port not found. 784 CommandComplete(iInputCommands, aCmd, PVMFFailure); 785 } 786 } 787 788 /** 789 //Called by the command handler AO to do the node Init 790 */ 791 void PVMFDummyFileInputNode::DoInit(PVMFFileInputNodeCommand& aCmd) 792 { 793 switch (iInterfaceState) 794 { 795 case EPVMFNodeIdle: 796 { 797 //this node doesn't need to do anything 798 PVMFStatus status = Initialize(); 799 if (status == PVMFSuccess) 800 SetState(EPVMFNodeInitialized); 801 //else 802 // SetState(EPVMFNodeError); 803 804 CommandComplete(iInputCommands, aCmd, status); 805 } 806 break; 807 808 default: 809 CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState); 810 break; 811 } 812 } 813 814 /** 815 //Called by the command handler AO to do the node Prepare 816 */ 817 void PVMFDummyFileInputNode::DoPrepare(PVMFFileInputNodeCommand& aCmd) 818 { 819 switch (iInterfaceState) 820 { 821 case EPVMFNodeInitialized: 822 //this node doesn't need to do anything to get ready 823 //to start. 824 SetState(EPVMFNodePrepared); 825 CommandComplete(iInputCommands, aCmd, PVMFSuccess); 826 break; 827 828 default: 829 CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState); 830 break; 831 } 832 } 833 834 /** 835 //Called by the command handler AO to do the node Start 836 */ 837 void PVMFDummyFileInputNode::DoStart(PVMFFileInputNodeCommand& aCmd) 838 { 839 PVMFStatus status = PVMFSuccess; 840 switch (iInterfaceState) 841 { 842 case EPVMFNodePrepared: 843 iTimeStamp = 0; 844 // Don't break here. Continue to process start command 845 846 case EPVMFNodePaused: 847 // If it's a start from stopped or initialized state, iInputFile 848 // object will be NULL and output file will be opened and read 849 // from the beginning. 850 if (!iFileOpen) 851 { 852 if (iFs.Connect() != 0) return; 853 iFsOpen = true; 854 855 if (iInputFile.Open(iSettings.iFileName.get_cstr(), Oscl_File::MODE_READ | Oscl_File::MODE_BINARY, iFs)) 856 status = PVMFFailure; 857 858 if (status == PVMFSuccess) 859 { 860 iFileOpen = true; 861 if (iInputFile.Seek(iFileHeaderSize + iFormatSpecificInfoSize, Oscl_File::SEEKSET)) 862 status = PVMFFailure; 863 } 864 } 865 866 if (status == PVMFSuccess) 867 { 868 //transition to Started 869 SetState(EPVMFNodeStarted); 870 } 871 //else 872 // SetState(EPVMFNodeError); 873 874 break; 875 876 default: 877 status = PVMFErrInvalidState; 878 break; 879 } 880 881 CommandComplete(iInputCommands, aCmd, status); 882 } 883 884 /** 885 //Called by the command handler AO to do the node Stop 886 */ 887 void PVMFDummyFileInputNode::DoStop(PVMFFileInputNodeCommand& aCmd) 888 { 889 switch (iInterfaceState) 890 { 891 case EPVMFNodeStarted: 892 case EPVMFNodePaused: 893 894 // Clear queued messages in ports 895 uint32 i; 896 for (i = 0; i < iPortVector.size(); i++) 897 iPortVector[i]->ClearMsgQueues(); 898 899 // Close the input file 900 CloseInputFile(); 901 iDataEventCounter = 0; 902 903 //transition to Prepared state 904 SetState(EPVMFNodePrepared); 905 CommandComplete(iInputCommands, aCmd, PVMFSuccess); 906 break; 907 908 default: 909 CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState); 910 break; 911 } 912 } 913 914 /** 915 //Called by the command handler AO to do the node Flush 916 */ 917 void PVMFDummyFileInputNode::DoFlush(PVMFFileInputNodeCommand& aCmd) 918 { 919 switch (iInterfaceState) 920 { 921 case EPVMFNodeStarted: 922 case EPVMFNodePaused: 923 //the flush is asynchronous. move the command from 924 //the input command queue to the current command, where 925 //it will remain until the flush completes. 926 int32 err; 927 OSCL_TRY(err, iCurrentCommand.StoreL(aCmd);); 928 if (err != OsclErrNone) 929 { 930 CommandComplete(iInputCommands, aCmd, PVMFErrNoMemory); 931 return; 932 } 933 iInputCommands.Erase(&aCmd); 934 935 //Notify all ports to suspend their input 936 { 937 for (uint32 i = 0; i < iPortVector.size(); i++) 938 iPortVector[i]->SuspendInput(); 939 } 940 941 // Close the input file 942 CloseInputFile(); 943 break; 944 945 default: 946 CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState); 947 break; 948 } 949 } 950 951 /** 952 //A routine to tell if a flush operation is in progress. 953 */ 954 bool PVMFDummyFileInputNode::FlushPending() 955 { 956 return (iCurrentCommand.size() > 0 957 && iCurrentCommand.front().iCmd == PVMF_GENERIC_NODE_FLUSH); 958 } 959 960 961 /** 962 //Called by the command handler AO to do the node Pause 963 */ 964 void PVMFDummyFileInputNode::DoPause(PVMFFileInputNodeCommand& aCmd) 965 { 966 switch (iInterfaceState) 967 { 968 case EPVMFNodeStarted: 969 970 SetState(EPVMFNodePaused); 971 CommandComplete(iInputCommands, aCmd, PVMFSuccess); 972 break; 973 default: 974 CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState); 975 break; 976 } 977 } 978 979 /** 980 //Called by the command handler AO to do the Cancel All 981 */ 982 void PVMFDummyFileInputNode::DoCancelAllCommands(PVMFFileInputNodeCommand& aCmd) 983 { 984 //first cancel the current command if any 985 { 986 while (!iCurrentCommand.empty()) 987 CommandComplete(iCurrentCommand, iCurrentCommand[0], PVMFErrCancelled); 988 } 989 990 //next cancel all queued commands 991 { 992 //start at element 1 since this cancel command is element 0. 993 while (iInputCommands.size() > 1) 994 CommandComplete(iInputCommands, iInputCommands[1], PVMFErrCancelled); 995 } 996 997 //finally, report cancel complete. 998 CommandComplete(iInputCommands, aCmd, PVMFSuccess); 999 } 1000 1001 /** 1002 //Called by the command handler AO to do the Cancel single command 1003 */ 1004 void PVMFDummyFileInputNode::DoCancelCommand(PVMFFileInputNodeCommand& aCmd) 1005 { 1006 //extract the command ID from the parameters. 1007 PVMFCommandId id; 1008 aCmd.PVMFFileInputNodeCommandBase::Parse(id); 1009 1010 //first check "current" command if any 1011 { 1012 PVMFFileInputNodeCommand* cmd = iCurrentCommand.FindById(id); 1013 if (cmd) 1014 { 1015 //cancel the queued command 1016 CommandComplete(iCurrentCommand, *cmd, PVMFErrCancelled); 1017 //report cancel success 1018 CommandComplete(iInputCommands, aCmd, PVMFSuccess); 1019 return; 1020 } 1021 } 1022 1023 //next check input queue. 1024 { 1025 //start at element 1 since this cancel command is element 0. 1026 PVMFFileInputNodeCommand* cmd = iInputCommands.FindById(id, 1); 1027 if (cmd) 1028 { 1029 //cancel the queued command 1030 CommandComplete(iInputCommands, *cmd, PVMFErrCancelled); 1031 //report cancel success 1032 CommandComplete(iInputCommands, aCmd, PVMFSuccess); 1033 return; 1034 } 1035 } 1036 //if we get here the command isn't queued so the cancel fails. 1037 CommandComplete(iInputCommands, aCmd, PVMFFailure); 1038 } 1039 1040 ///////////////////////////////////////////////////// 1041 // Event reporting routines. 1042 ///////////////////////////////////////////////////// 1043 void PVMFDummyFileInputNode::SetState(TPVMFNodeInterfaceState s) 1044 { 1045 LOGINFO((0, "FileInputNode:SetState %d", s)); 1046 PVMFNodeInterface::SetState(s); 1047 } 1048 1049 void PVMFDummyFileInputNode::ReportErrorEvent(PVMFEventType aEventType, OsclAny* aEventData) 1050 { 1051 LOGINFO((0, "FileInputNode:NodeErrorEvent Type %d Data %d" 1052 , aEventType, aEventData)); 1053 1054 PVMFNodeInterface::ReportErrorEvent(aEventType, aEventData); 1055 } 1056 1057 void PVMFDummyFileInputNode::ReportInfoEvent(PVMFEventType aEventType, OsclAny* aEventData) 1058 { 1059 LOGINFO((0, "FileInputNode:NodeInfoEvent Type %d Data %d" 1060 , aEventType, aEventData)); 1061 1062 PVMFNodeInterface::ReportInfoEvent(aEventType, aEventData); 1063 } 1064 1065 ///////////////////////////////////////////////////// 1066 // Port Processing routines 1067 ///////////////////////////////////////////////////// 1068 1069 void PVMFDummyFileInputNode::HandlePortActivity(const PVMFPortActivity &aActivity) 1070 { 1071 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, 1072 (0, "0x%x PVMFDummyFileInputNode::PortActivity: port=0x%x, type=%d", 1073 this, aActivity.iPort, aActivity.iType)); 1074 1075 //A port is reporting some activity or state change. This code 1076 //figures out whether we need to queue a processing event 1077 //for the AO, and/or report a node event to the observer. 1078 1079 //int32 err = 0; 1080 switch (aActivity.iType) 1081 { 1082 case PVMF_PORT_ACTIVITY_CREATED: 1083 //Report port created info event to the node. 1084 PVMFNodeInterface::ReportInfoEvent(PVMFInfoPortCreated 1085 , (OsclAny*)aActivity.iPort); 1086 break; 1087 1088 case PVMF_PORT_ACTIVITY_DELETED: 1089 //Report port deleted info event to the node. 1090 PVMFNodeInterface::ReportInfoEvent(PVMFInfoPortDeleted 1091 , (OsclAny*)aActivity.iPort); 1092 break; 1093 1094 case PVMF_PORT_ACTIVITY_CONNECT: 1095 break; 1096 1097 case PVMF_PORT_ACTIVITY_DISCONNECT: 1098 break; 1099 1100 case PVMF_PORT_ACTIVITY_OUTGOING_MSG: 1101 // chesterc: No RunIfNotReady here. It will be called in Run after SendNewMediaMessage. 1102 // Calling RunIfNotReady here would screw up frame rate simulation 1103 break; 1104 1105 case PVMF_PORT_ACTIVITY_INCOMING_MSG: 1106 break; 1107 1108 case PVMF_PORT_ACTIVITY_OUTGOING_QUEUE_BUSY: 1109 break; 1110 1111 case PVMF_PORT_ACTIVITY_OUTGOING_QUEUE_READY: 1112 //wakeup to resume queueing outgoing messages. 1113 RunIfNotReady(); 1114 break; 1115 1116 case PVMF_PORT_ACTIVITY_CONNECTED_PORT_BUSY: 1117 break; 1118 1119 case PVMF_PORT_ACTIVITY_CONNECTED_PORT_READY: 1120 //wakeup to resume sending outgoing data. 1121 RunIfNotReady(); 1122 break; 1123 1124 default: 1125 break; 1126 } 1127 } 1128 1129 1130 /** 1131 ///////////////////////////////////////////////////// 1132 // Active object implementation 1133 ///////////////////////////////////////////////////// 1134 */ 1135 1136 /** 1137 //Example of a single-AO node implementation. This AO handles 1138 //both API commands and port activity. 1139 // 1140 //The AO will either process one command, send one outgoing message, 1141 //or create one new outgoing message per call. 1142 //It will re-schedule itself and run continuously 1143 //until it runs out of things to do. 1144 */ 1145 void PVMFDummyFileInputNode::Run() 1146 { 1147 /* 1148 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, 1149 (0, "0x%x PVMFDummyFileInputNode::Run: ENTER - iInputCommands.size=%d, iPortActivityQueue.size=%d", 1150 this, iInputCommands.size(), iPortActivityQueue.size())); 1151 */ 1152 1153 //Process commands. 1154 if (!iInputCommands.empty()) 1155 { 1156 if (ProcessCommand(iInputCommands.front())) 1157 { 1158 //note:it's possible the node could be reset so 1159 //check isAdded here to avoid scheduler panic. 1160 if (IsAdded()) 1161 RunIfNotReady(); 1162 return; 1163 } 1164 } 1165 1166 //Process ports 1167 if (iPortVector.size() > 0) 1168 { 1169 //Send output data. 1170 if (iInterfaceState == EPVMFNodeStarted || FlushPending()) 1171 { 1172 if (iPortVector[0]->OutgoingMsgQueueSize() > 0 1173 && !iPortVector[0]->IsConnectedPortBusy()) 1174 { 1175 PVMFStatus status = iPortVector[0]->Send(); 1176 if (status == PVMFSuccess) 1177 { 1178 //increment timestamp and frame counter 1179 IncTimestamp(); 1180 ++iDataEventCounter; 1181 RunIfNotReady(); 1182 return; 1183 } 1184 else if (status == PVMFErrBusy) 1185 { 1186 return;//wait on port ready callback 1187 } 1188 } 1189 while (iPortVector[0]->IncomingMsgQueueSize() > 0) 1190 { 1191 // Just purge this data so that we 1192 // don't have a memory lockup 1193 PVMFSharedMediaMsgPtr aMsg; 1194 iPortVector[0]->DequeueIncomingMsg(aMsg); 1195 } 1196 } 1197 1198 // Create new data and send to the output queue. 1199 // chesterc: In flush state, don't queue new data 1200 if (iInterfaceState == EPVMFNodeStarted && !FlushPending()) 1201 { 1202 if (!iPortVector[0]->IsOutgoingQueueBusy()) 1203 { 1204 PVMFStatus status = SendNewMediaMessage(); 1205 if (status == PVMFSuccess) 1206 { 1207 //Re-schedule if not end of file. 1208 RunIfNotReady(iTSForRunIfInactive); 1209 return; 1210 } 1211 } 1212 } 1213 1214 //Monitor completion of flush command. 1215 if (FlushPending()) 1216 { 1217 if (iPortVector[0]->IncomingMsgQueueSize() > 0 1218 || iPortVector[0]->OutgoingMsgQueueSize() > 0) 1219 { 1220 RunIfNotReady(); 1221 return;//wait on queues to empty. 1222 } 1223 1224 //Flush is complete. Go to prepared state. 1225 SetState(EPVMFNodePrepared); 1226 1227 //resume port input so the ports can be re-started. 1228 iPortVector[0]->ResumeInput(); 1229 1230 CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess); 1231 RunIfNotReady(); 1232 } 1233 } 1234 } 1235 1236 PVMFStatus PVMFDummyFileInputNode::SendNewMediaMessage() 1237 { 1238 #ifdef FRAGMENTATION_TEST 1239 PVMFSharedMediaMsgPtr mediaMsg; 1240 PVMFSharedMediaMsgPtr mediaMsg2; 1241 PVMFStatus status = GenerateMediaMessage2(mediaMsg, mediaMsg2); 1242 #else 1243 PVMFSharedMediaMsgPtr mediaMsg; 1244 PVMFStatus status = GenerateMediaMessage(mediaMsg); 1245 #endif 1246 1247 if (status == PVMFSuccess) 1248 { 1249 status = iPortVector[0]->QueueOutgoingMsg(mediaMsg); 1250 1251 if (status == PVMFSuccess) 1252 { 1253 //keep count of the number of source 1254 //frames generated on this port. 1255 iPortVector[0]->iNumFramesGenerated++; 1256 } 1257 else 1258 { 1259 //just discard the data... 1260 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, 1261 (0, "PVMFDummyFileInputNode::SendNewMediaMessage: Data lost!. ")); 1262 } 1263 #ifdef FRAGMENTATION_TEST 1264 if (!iEndOfFileReached) 1265 { 1266 // 2nd message exists unless EOF 1267 status = iPortVector[0]->QueueOutgoingMsg(mediaMsg2); 1268 1269 if (status == PVMFSuccess) 1270 { 1271 //keep count of the number of source 1272 //frames generated on this port. 1273 iPortVector[0]->iNumFramesGenerated++; 1274 } 1275 else 1276 { 1277 //just discard the data... 1278 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, 1279 (0, "PVMFDummyFileInputNode::SendNewMediaMessage: Data lost!. ")); 1280 } 1281 } 1282 #endif 1283 1284 } 1285 else if (iEndOfFileReached) 1286 { 1287 // end of file 1288 } 1289 else if (status != PVMFErrNoMemory) // excluding the case that memory pool runs out of memory 1290 { 1291 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, 1292 (0, "PVMFDummyFileInputNode::SendNewMediaMessage: Error - GenerateData failed")); 1293 PVMFNodeInterface* node = OSCL_STATIC_CAST(PVMFNodeInterface*, this); 1294 ReportErrorEvent(PVMF_FILEINPUT_NODE_ERROR_DATA_GENERATING_ERROR, (OsclAny*)node); 1295 } 1296 1297 return status; 1298 } 1299 1300 void PVMFDummyFileInputNode::DoCancel() 1301 {//the base class cancel operation is sufficient. 1302 OsclTimerObject::DoCancel(); 1303 } 1304 1305 1306 //////////////////////////////////////////////////////////////////////////// 1307 void PVMFDummyFileInputNode::ConstructInputSettings(PVMFFileInputSettings* aSettings) 1308 { 1309 iSettings.iFileName = aSettings->iFileName; 1310 iSettings.iFrameHeight = aSettings->iFrameHeight; 1311 iSettings.iFrameRate = aSettings->iFrameRate; 1312 iSettings.iFrameWidth = aSettings->iFrameWidth; 1313 iSettings.iLoopInputFile = aSettings->iLoopInputFile; 1314 iSettings.iMediaFormat = aSettings->iMediaFormat; 1315 iSettings.iNumChannels = aSettings->iNumChannels; 1316 iSettings.iSamplingFrequency = aSettings->iSamplingFrequency; 1317 iSettings.iTimescale = aSettings->iTimescale; 1318 iSettings.iNum20msFramesPerChunk = aSettings->iNum20msFramesPerChunk; 1319 iSettings.iFrameRateSimulation = aSettings->iFrameRateSimulation; 1320 iSettings.iFirstFrameTimestamp = aSettings->iFirstFrameTimestamp; 1321 iSettings.iBitrate = aSettings->iBitrate; 1322 } 1323 1324 //////////////////////////////////////////////////////////////////////////// 1325 void PVMFDummyFileInputNode::CloseInputFile() 1326 { 1327 if (iFileOpen) 1328 { 1329 iInputFile.Close(); 1330 iFileOpen = false; 1331 } 1332 1333 if (iFsOpen) 1334 { 1335 iFs.Close(); 1336 iFsOpen = false; 1337 } 1338 } 1339 1340 //////////////////////////////////////////////////////////////////////////// 1341 PVMFStatus PVMFDummyFileInputNode::Initialize() 1342 { 1343 if (iFs.Connect() != 0) return 0; 1344 1345 iFsOpen = true; 1346 1347 if (0 != iInputFile.Open(iSettings.iFileName.get_cstr(), Oscl_File::MODE_READ | Oscl_File::MODE_BINARY, iFs)) 1348 { 1349 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, 1350 (0, "PVMFDummyFileInputNode::HandleCmdInit: Error - iInputFile.Open failed")); 1351 return PVMFFailure; 1352 } 1353 1354 1355 iFileOpen = true; 1356 uint32 maxFrameSize = 0; 1357 1358 if (iSettings.iMediaFormat == PVMF_MIME_H2632000) 1359 { 1360 int32 fileStart = iInputFile.Tell(); 1361 iInputFile.Seek(0, Oscl_File::SEEKEND); 1362 int32 fileEnd = iInputFile.Tell(); 1363 iInputFile.Seek(fileStart, Oscl_File::SEEKSET); 1364 int32 fileSize = fileEnd - fileStart; 1365 1366 // Validate settings 1367 if (iSettings.iFrameHeight <= 0 || iSettings.iFrameWidth <= 0 || 1368 iSettings.iFrameRate <= 0 || iSettings.iTimescale <= 0) 1369 { 1370 CloseInputFile(); 1371 return PVMFErrArgument; 1372 } 1373 1374 fileStart = iInputFile.Tell(); 1375 iInputFile.Seek(0, Oscl_File::SEEKEND); 1376 fileEnd = iInputFile.Tell(); 1377 iInputFile.Seek(fileStart, Oscl_File::SEEKSET); 1378 fileSize = fileEnd - fileStart; 1379 iVideoData = (uint8*)iAlloc.allocate(fileSize); 1380 if (!iVideoData) 1381 { 1382 CloseInputFile(); 1383 return PVMFErrNoMemory; 1384 } 1385 1386 // Read the whole file to data buffer then go back to front 1387 iInputFile.Read((OsclAny*)iVideoData, sizeof(uint8), fileSize); 1388 iInputFile.Seek(fileStart, Oscl_File::SEEKSET); 1389 iMilliSecondsPerDataEvent = (int32)(1000 / iSettings.iFrameRate); 1390 iMicroSecondsPerDataEvent = iMilliSecondsPerDataEvent * 1000; 1391 1392 } 1393 1394 else if (iSettings.iMediaFormat == PVMF_MIME_AMR_IF2) 1395 { 1396 int32 fileStart, fileEnd, fileSize; 1397 fileStart = iInputFile.Tell(); 1398 iInputFile.Seek(0, Oscl_File::SEEKEND); 1399 fileEnd = iInputFile.Tell(); 1400 iInputFile.Seek(fileStart, Oscl_File::SEEKSET); 1401 fileSize = fileEnd - fileStart; 1402 iAudioData = (uint8*)iAlloc.allocate(fileSize); 1403 if (!iAudioData) 1404 { 1405 CloseInputFile(); 1406 return PVMFErrNoMemory; 1407 } 1408 1409 // Read the whole file to data buffer then go back to front 1410 iInputFile.Read((OsclAny*)iAudioData, sizeof(uint8), fileSize); 1411 iInputFile.Seek(fileStart, Oscl_File::SEEKSET); 1412 1413 } 1414 else 1415 CloseInputFile(); 1416 return PVMFErrArgument; 1417 1418 iDataEventCounter = 0; 1419 CloseInputFile(); 1420 1421 // Create memory pool for the media data, using the maximum frame size found earlier 1422 int32 err = 0; 1423 OSCL_TRY(err, 1424 if (iMediaBufferMemPool) 1425 { 1426 OSCL_DELETE(iMediaBufferMemPool); 1427 iMediaBufferMemPool = NULL; 1428 } 1429 iMediaBufferMemPool = OSCL_NEW(OsclMemPoolFixedChunkAllocator, 1430 (PVFILEIN_MEDIADATA_POOLNUM)); 1431 if (!iMediaBufferMemPool) 1432 OSCL_LEAVE(OsclErrNoMemory); 1433 1434 if (iMediaDataAlloc) 1435 { 1436 OSCL_DELETE(iMediaDataAlloc); 1437 iMediaDataAlloc = NULL; 1438 } 1439 iMediaDataAlloc = OSCL_NEW(PVMFSimpleMediaBufferCombinedAlloc, (iMediaBufferMemPool)); 1440 if (!iMediaDataAlloc) 1441 OSCL_LEAVE(OsclErrNoMemory); 1442 1443 // The first allocate call will set the chunk size of the memory pool. Use the max 1444 // frame size calculated earlier to set the chunk size. The allocated data will be 1445 // deallocated automatically as tmpPtr goes out of scope. 1446 OsclSharedPtr<PVMFMediaDataImpl> tmpPtr = iMediaDataAlloc->allocate(maxFrameSize); 1447 ); 1448 if (err != OsclErrNone) 1449 return PVMFFailure; 1450 1451 return PVMFSuccess; 1452 } 1453 1454 void PVMFDummyFileInputNode::IncTimestamp() 1455 { 1456 //Increment running timestamp if needed. 1457 if (iSettings.iMediaFormat == PVMF_MIME_AMR_IF2) 1458 { 1459 iTimeStamp += iMilliSecondsPerDataEvent; 1460 } 1461 } 1462 1463 void PVMFDummyFileInputNode::freechunkavailable(OsclAny* aContextData) 1464 { 1465 OSCL_UNUSED_ARG(aContextData); 1466 if (iWaitingOnFreeChunk) 1467 { 1468 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, 1469 (0, "PVMFDummyFileInputNode::freechunkavailable: Resuming processing, free chunk available.")); 1470 iWaitingOnFreeChunk = false; 1471 if (IsAdded()) 1472 { 1473 RunIfNotReady(); 1474 } 1475 } 1476 } 1477 1478 1479 PVMFStatus PVMFDummyFileInputNode::GenerateMediaMessage(PVMFSharedMediaMsgPtr& aMediaMsg) 1480 { 1481 1482 if (iInterfaceState != EPVMFNodeStarted) 1483 { 1484 return PVMFSuccess; 1485 } 1486 1487 uint32 bytesToRead = 0; 1488 uint32 timeStamp = 0; 1489 1490 //Find the frame... 1491 if (!((iSettings.iMediaFormat == PVMF_MIME_H2632000) || (iSettings.iMediaFormat == PVMF_MIME_AMR_IF2))) 1492 { 1493 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, 1494 (0, "PVMFDummyFileInputNode::HandleEventPortActivity: Error - Unsupported media format")); 1495 return PVMFFailure; 1496 } 1497 1498 if (timeStamp < iSettings.iFirstFrameTimestamp) 1499 { 1500 // Search for the first frame greater than the specified start time 1501 iTSForRunIfInactive = 0; 1502 return PVMFSuccess; 1503 } 1504 1505 // Create new media data buffer 1506 1507 PVMFSharedMediaDataPtr mediaData; 1508 int32 err = 0; 1509 OSCL_TRY(err, 1510 OsclSharedPtr<PVMFMediaDataImpl> mediaDataImpl = iMediaDataAlloc->allocate(bytesToRead); 1511 mediaData = PVMFMediaData::createMediaData(mediaDataImpl, &iMediaDataMemPool); 1512 ); 1513 if (err != OsclErrNone) 1514 { 1515 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, 1516 (0, "PVMFDummyFileInputNode::HandleEventPortActivity: Mempool empty-- calling notifyfreechunkavailable")); 1517 //register to receive notice when memory is available. 1518 iMediaBufferMemPool->notifyfreechunkavailable(*this); 1519 iWaitingOnFreeChunk = true; 1520 return PVMFErrNoMemory; 1521 } 1522 1523 // Retrieve memory fragment to write to 1524 1525 OsclRefCounterMemFrag refCtrMemFrag; 1526 mediaData->getMediaFragment(0, refCtrMemFrag); 1527 if (refCtrMemFrag.getCapacity() < bytesToRead) 1528 return PVMFFailure; 1529 1530 1531 // For AAC Latm, read the marker info before reading the data 1532 1533 // Read the frame from file 1534 1535 //uint32 len = iInputFile.Read(refCtrMemFrag.getMemFragPtr(), sizeof(uint8), bytesToRead ); 1536 if (iSettings.iMediaFormat == PVMF_MIME_H2632000) 1537 { 1538 oscl_memcpy(refCtrMemFrag.getMemFragPtr(), iVideoData, sizeof(iVideoData)); 1539 // update the filled length of the fragment 1540 mediaData->setMediaFragFilledLen(0, sizeof(iVideoData)); 1541 } 1542 else 1543 { 1544 oscl_memcpy(refCtrMemFrag.getMemFragPtr(), iAudioData, sizeof(iAudioData)); 1545 // update the filled length of the fragment 1546 mediaData->setMediaFragFilledLen(0, sizeof(iAudioData)); 1547 } 1548 1549 // Set timestamp 1550 mediaData->setTimestamp(timeStamp); 1551 // Set sequence number 1552 mediaData->setSeqNum(iDataEventCounter); 1553 1554 if (iSettings.iMediaFormat == PVMF_MIME_H2632000) 1555 1556 { 1557 // For M4V and H263 data always set the marker bit to 1 1558 OsclSharedPtr<PVMFMediaDataImpl> media_data_impl; 1559 mediaData->getMediaDataImpl(media_data_impl); 1560 media_data_impl->setMarkerInfo(1); 1561 } 1562 1563 1564 // Set format specific info in media data message 1565 #ifndef SEND_CONFIGINFO_SEPARATELY 1566 mediaData->setFormatSpecificInfo(iFormatSpecificInfo); 1567 #else 1568 if (iSetFormatSpecificInfo) 1569 { 1570 // Create new media data buffer 1571 OsclSharedPtr<PVMFMediaDataImpl> emptyImpl = iMediaDataAlloc.allocate(0); 1572 PVMFSharedMediaDataPtr volData; 1573 int errcode = 0; 1574 OSCL_TRY(errcode, volData = PVMFMediaData::createMediaData(emptyImpl, &iMediaDataMemPool)); 1575 OSCL_FIRST_CATCH_ANY(errcode, return PVMFErrNoMemory); 1576 1577 // Set format specific info in media data message 1578 volData->setFormatSpecificInfo(iFormatSpecificInfo); 1579 1580 // Send VOL header to downstream node 1581 PVMFSharedMediaMsgPtr volMsg; 1582 convertToPVMFMediaMsg(volMsg, volData); 1583 iSetFormatSpecificInfo = false; 1584 1585 ++iDataEventCounter; 1586 return PVMFSuccess; 1587 } 1588 #endif 1589 1590 // Send frame to downstream node 1591 1592 convertToPVMFMediaMsg(aMediaMsg, mediaData); 1593 1594 // Queue the next data event 1595 if (iSettings.iFrameRateSimulation) 1596 iTSForRunIfInactive = iMicroSecondsPerDataEvent; 1597 else 1598 iTSForRunIfInactive = 0; 1599 1600 return PVMFSuccess; 1601 } 1602 1603 1604 int32 PVMFDummyFileInputNode::GetIF2FrameSize(uint8 aFrameType) 1605 { 1606 // Last 4 bits of first byte of the package is frame type 1607 uint8 frameType = (uint8)(0x0f & aFrameType); 1608 1609 // Find frame size for each frame type 1610 switch (frameType) 1611 { 1612 case 0: // AMR 4.75 Kbps 1613 return 13; 1614 case 1: // AMR 5.15 Kbps 1615 return 14; 1616 case 2: // AMR 5.90 Kbps 1617 return 16; 1618 case 3: // AMR 6.70 Kbps 1619 return 18; 1620 case 4: // AMR 7.40 Kbps 1621 return 19; 1622 case 5: // AMR 7.95 Kbps 1623 return 21; 1624 case 6: // AMR 10.2 Kbps 1625 return 26; 1626 case 7: // AMR 12.2 Kbps 1627 return 31; 1628 case 8: // AMR Frame SID 1629 case 9: // AMR Frame GSM EFR SID 1630 case 10: // AMR Frame TDMA EFR SID 1631 case 11: // AMR Frame PDC EFR SID 1632 return 6; 1633 case 15: // AMR Frame No Data 1634 return 1; 1635 default: // Error - For Future Use 1636 return -1; 1637 } 1638 } 1639 1640 int32 PVMFDummyFileInputNode::LocateH263FrameHeader(uint8 *video_buffer, int32 vop_size) 1641 { 1642 int32 idx; 1643 uint8 *ptr; 1644 1645 idx = 1; 1646 ptr = video_buffer + 1; 1647 vop_size -= 4; 1648 do 1649 { 1650 ptr--; 1651 idx--; 1652 for (;;) 1653 { 1654 if (ptr[1]) 1655 { 1656 ptr += 2; 1657 idx += 2; 1658 } 1659 else if (ptr[0]) 1660 { 1661 ptr++; 1662 idx++; 1663 } 1664 else 1665 { 1666 break; 1667 } 1668 if (idx >= vop_size) return -1; 1669 } 1670 ptr += 2; 1671 idx += 2; 1672 } 1673 while ((video_buffer[idx] & 0xfc) != 0x80); 1674 1675 return idx - 2; 1676 } 1677