• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
CreateDummyFileInputNode(PVMFFileInputSettings * aSettings,int32 aPriority)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 
DeleteDummyFileInputNode(PVMFNodeInterface * & aNode)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 
PVMFDummyFileInputNode(PVMFFileInputSettings * aSettings,int32 aPriority)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 
~PVMFDummyFileInputNode()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 */
ThreadLogon()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 */
ThreadLogoff()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 */
GetCapability(PVMFNodeCapability & aNodeCapability)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 */
GetPorts(const PVMFPortFilter * aFilter)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 */
QueryUUID(PVMFSessionId s,const PvmfMimeString & aMimeType,Oscl_Vector<PVUuid,OsclMemAllocator> & aUuids,bool aExactUuidsOnly,const OsclAny * aContext)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 */
QueryInterface(PVMFSessionId s,const PVUuid & aUuid,PVInterface * & aInterfacePtr,const OsclAny * aContext)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 */
RequestPort(PVMFSessionId s,int32 aPortTag,const PvmfMimeString * aPortConfig,const OsclAny * aContext)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 */
ReleasePort(PVMFSessionId s,PVMFPortInterface & aPort,const OsclAny * aContext)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 */
Init(PVMFSessionId s,const OsclAny * aContext)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 */
Prepare(PVMFSessionId s,const OsclAny * aContext)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 */
Start(PVMFSessionId s,const OsclAny * aContext)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 */
Stop(PVMFSessionId s,const OsclAny * aContext)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 */
Flush(PVMFSessionId s,const OsclAny * aContext)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 */
Pause(PVMFSessionId s,const OsclAny * aContext)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 */
Reset(PVMFSessionId s,const OsclAny * aContext)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 */
CancelAllCommands(PVMFSessionId s,const OsclAny * aContext)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 */
CancelCommand(PVMFSessionId s,PVMFCommandId aCmdId,const OsclAny * aContext)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 ////////////////////////////////////////////////////////////////////////////
addRef()430 OSCL_EXPORT_REF void PVMFDummyFileInputNode::addRef()
431 {
432     ++iExtensionRefCount;
433 }
434 
435 ////////////////////////////////////////////////////////////////////////////
removeRef()436 OSCL_EXPORT_REF void PVMFDummyFileInputNode::removeRef()
437 {
438     --iExtensionRefCount;
439 }
440 
441 ////////////////////////////////////////////////////////////////////////////
queryInterface(const PVUuid & uuid,PVInterface * & iface)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 ////////////////////////////////////////////////////////////////////////////
GetBitstreamConfig(OsclRefCounterMemFrag & aConfig)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 */
QueueCommandL(PVMFFileInputNodeCommand & aCmd)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 */
ProcessCommand(PVMFFileInputNodeCommand & aCmd)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 */
CommandComplete(PVMFFileInputNodeCmdQ & aCmdQ,PVMFFileInputNodeCommand & aCmd,PVMFStatus aStatus,OsclAny * aEventData)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 */
DoReset(PVMFFileInputNodeCommand & aCmd)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 */
DoQueryUuid(PVMFFileInputNodeCommand & aCmd)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 */
DoQueryInterface(PVMFFileInputNodeCommand & aCmd)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 */
DoRequestPort(PVMFFileInputNodeCommand & aCmd)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 */
DoReleasePort(PVMFFileInputNodeCommand & aCmd)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 */
DoInit(PVMFFileInputNodeCommand & aCmd)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 */
DoPrepare(PVMFFileInputNodeCommand & aCmd)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 */
DoStart(PVMFFileInputNodeCommand & aCmd)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 */
DoStop(PVMFFileInputNodeCommand & aCmd)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 */
DoFlush(PVMFFileInputNodeCommand & aCmd)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 */
FlushPending()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 */
DoPause(PVMFFileInputNodeCommand & aCmd)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 */
DoCancelAllCommands(PVMFFileInputNodeCommand & aCmd)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 */
DoCancelCommand(PVMFFileInputNodeCommand & aCmd)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 /////////////////////////////////////////////////////
SetState(TPVMFNodeInterfaceState s)1043 void PVMFDummyFileInputNode::SetState(TPVMFNodeInterfaceState s)
1044 {
1045     LOGINFO((0, "FileInputNode:SetState %d", s));
1046     PVMFNodeInterface::SetState(s);
1047 }
1048 
ReportErrorEvent(PVMFEventType aEventType,OsclAny * aEventData)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 
ReportInfoEvent(PVMFEventType aEventType,OsclAny * aEventData)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 
HandlePortActivity(const PVMFPortActivity & aActivity)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 */
Run()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 
SendNewMediaMessage()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 
DoCancel()1300 void PVMFDummyFileInputNode::DoCancel()
1301 {//the base class cancel operation is sufficient.
1302     OsclTimerObject::DoCancel();
1303 }
1304 
1305 
1306 ////////////////////////////////////////////////////////////////////////////
ConstructInputSettings(PVMFFileInputSettings * aSettings)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 ////////////////////////////////////////////////////////////////////////////
CloseInputFile()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 ////////////////////////////////////////////////////////////////////////////
Initialize()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 
IncTimestamp()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 
freechunkavailable(OsclAny * aContextData)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 
GenerateMediaMessage(PVMFSharedMediaMsgPtr & aMediaMsg)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 
GetIF2FrameSize(uint8 aFrameType)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 
LocateH263FrameHeader(uint8 * video_buffer,int32 vop_size)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