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