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 /**
19 *
20 * @file pvmi_io_interface_node_inport.cpp
21 * @brief Input port for media io interface wrapper node
22 *
23 */
24
25 #include "pv_media_output_node_inport.h"
26 #include "pv_media_output_node.h"
27 #include "pvmf_common_audio_decnode.h"
28 #include "pvmf_video.h"
29 #include "pv_mime_string_utils.h"
30 #include "pvmf_media_cmd.h"
31 #include "pvmf_media_msg_format_ids.h"
32 #include "latmpayloadparser.h"
33 #include "media_clock_converter.h"
34 #include "time_comparison_utils.h"
35
36 #define LOGDATAPATH(x) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iDatapathLogger, PVLOGMSG_INFO, x);
37
38 #define PVMF_MOPORT_LOGDATAPATH(x) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iDatapathLogger, PVLOGMSG_INFO, x);
39 #define PVMF_MOPORT_LOGDATAPATH_IN(x) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iDatapathLoggerIn, PVLOGMSG_INFO, x);
40 #define PVMF_MOPORT_LOGDATAPATH_OUT(x) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iDatapathLoggerOut, PVLOGMSG_INFO, x);
41 #define PVMF_MOPORT_LOGREPOS(x) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iReposLogger, PVLOGMSG_INFO, x);
42 #define PVMF_MOPORT_LOGDEBUG(x) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, x);
43 #define PVMF_MOPORT_LOGERROR(x) PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, x);
44
45
46 //for logging media data info
LogMediaDataInfo(const char * msg,PVMFSharedMediaDataPtr mediaData)47 void PVMediaOutputNodePort::LogMediaDataInfo(const char* msg, PVMFSharedMediaDataPtr mediaData)
48 {
49 if (!mediaData.GetRep())
50 {
51 OSCL_UNUSED_ARG(msg);
52 return;
53 }
54 LOGDATAPATH(
55 (0, "MOUT %s %s MediaData SeqNum %d, SId %d, TS %d"
56 , PortName()
57 , msg
58 , mediaData->getSeqNum()
59 , mediaData->getStreamID()
60 , mediaData->getTimestamp()
61 ));
62 }
63
64
65 //for logging media data info plus write ID and cleanup q depth
LogMediaDataInfo(const char * msg,PVMFSharedMediaDataPtr mediaData,int32 cmdid,int32 qdepth)66 void PVMediaOutputNodePort::LogMediaDataInfo(const char* msg, PVMFSharedMediaDataPtr mediaData, int32 cmdid, int32 qdepth)
67 {
68 if (!mediaData.GetRep())
69 {
70 OSCL_UNUSED_ARG(msg);
71 OSCL_UNUSED_ARG(cmdid);
72 OSCL_UNUSED_ARG(qdepth);
73 return;
74 }
75 LOGDATAPATH(
76 (0, "MOUT %s %s, Write Id %d, MediaData SeqNum %d, SId %d, TS %d, Cleanup Q-depth %d"
77 , PortName()
78 , msg
79 , cmdid
80 , mediaData->getSeqNum()
81 , mediaData->getStreamID()
82 , mediaData->getTimestamp()
83 , qdepth
84 ));
85 }
86
87
88 //for logging media xfer info
LogDatapath(const char * msg)89 void PVMediaOutputNodePort::LogDatapath(const char*msg)
90 {
91
92 if (!iDatapathLogger)
93 {
94 OSCL_UNUSED_ARG(msg);
95 return; //unexpected call.
96 }
97 LOGDATAPATH(
98 (0, "MOUT %s %s"
99 , PortName()
100 , msg
101 ));
102 }
103
104
105 ////////////////////////////////////////////////////////////////////////////
PVMediaOutputNodePort(PVMediaOutputNode * aNode)106 PVMediaOutputNodePort::PVMediaOutputNodePort(PVMediaOutputNode* aNode)
107 : OsclTimerObject(OsclActiveObject::EPriorityNominal, "PVMediaOutputNodePort")
108 , PvmfPortBaseImpl(PVMF_MEDIAIO_NODE_INPUT_PORT_TAG
109 //this port handles its own port activity
110 , this
111 , 10, 10, 70
112 //output queue isn't needed.
113 , 0, 0, 0, "MediaOut")
114 , iNode(aNode)
115 {
116 AddToScheduler();
117 isUnCompressedMIO = false;
118
119 iExtensionRefCount = 0;
120 iPortFormat = PVMF_MIME_FORMAT_UNKNOWN;
121
122 iMediaTransfer = NULL;
123 iMioInfoErrorCmdId = 0;
124 iMediaType = PVMF_MEDIA_UNKNOWN;
125 iWriteState = EWriteOK;
126 iCleanupQueue.reserve(1);
127 iWriteAsyncContext = 0;
128 iWriteAsyncEOSContext = 0;
129 iWriteAsyncReConfigContext = 0;
130 iClock = NULL;
131 iClockNotificationsInf = NULL;
132 oClockCallBackPending = false;
133 iDelayEarlyFrameCallBkId = 0;
134 iClockRate = 1;
135 iEarlyMargin = 0;
136 iLateMargin = 0;
137 oActiveMediaOutputComp = true; // By default we treat the MIO's to be active.
138
139 // MIO node waits for MIO component configuration to complete before sending data. Once configuration is
140 // complete, MIO node waits for clock to start if mio component is passive. For active MIO's, it does not
141 // wait for clock to start before sending data. It sends data as soon as MIO component configuration is
142 // complete.
143
144 oProcessIncomingMessage = false;
145
146
147 oMIOComponentConfigured = false;
148
149 iConsecutiveFramesDropped = 0;
150 iLateFrameEventSent = false;
151
152 iFragIndex = 0;
153
154 iSkipTimestamp = 0;
155 iRecentStreamID = 0;
156 iSendStartOfDataEvent = false;
157
158 iFrameStepMode = false;
159 iClockFrameCount = 0;
160 iSyncFrameCount = 0;
161 iFramesDropped = 0;
162 iTotalFrames = 0;
163
164 iEosStreamIDVec.reserve(2);
165
166 iOsclErrorTrapImp = OsclErrorTrap::GetErrorTrapImp();
167 iLogger = PVLogger::GetLoggerObject("PVMediaOutputNodePort");
168 iDatapathLogger = PVLogger::GetLoggerObject("datapath.sinknode");
169 iDatapathLoggerIn = PVLogger::GetLoggerObject("datapath.sinknode.in");
170 iDatapathLoggerOut = PVLogger::GetLoggerObject("datapath.sinknode.out");
171 iReposLogger = PVLogger::GetLoggerObject("pvplayerrepos.mionode");
172 }
173
174 ////////////////////////////////////////////////////////////////////////////
ClearCleanupQueue()175 void PVMediaOutputNodePort::ClearCleanupQueue()
176 //clear the media transfer cleanup queue and log all messages.
177 {
178 while (!iCleanupQueue.empty())
179 {
180 PVMFSharedMediaDataPtr mediaData = iCleanupQueue.begin()->iData;
181 PVMFCommandId cmdId = iCleanupQueue.begin()->iCmdId;
182 iCleanupQueue.erase(iCleanupQueue.begin());
183 LogMediaDataInfo("Cleared"
184 , mediaData
185 , cmdId
186 , iCleanupQueue.size()
187 );
188 }
189 }
190
191 ////////////////////////////////////////////////////////////////////////////
~PVMediaOutputNodePort()192 PVMediaOutputNodePort::~PVMediaOutputNodePort()
193 {
194 Disconnect();
195 PvmfPortBaseImpl::ClearMsgQueues();
196 //cancel any pending write operations
197 if (!iCleanupQueue.empty())
198 {
199 int32 err;
200 OSCL_TRY(err, iMediaTransfer->cancelAllCommands(););
201 ClearCleanupQueue();
202 }
203 if (iClock != NULL)
204 {
205 if (iClockNotificationsInf != NULL)
206 {
207 iClockNotificationsInf->RemoveClockObserver(*this);
208 iClockNotificationsInf->RemoveClockStateObserver(*this);
209 iClock->DestroyMediaClockNotificationsInterface(iClockNotificationsInf);
210 iClockNotificationsInf = NULL;
211 }
212 }
213 // we need to clear the activity handler, since otherwise the PvmfPortBaseImpl destructor
214 // ends up calling back onto our HandlePortActivity method, which no longer exists because
215 // this objects's destructor has already been called.
216 SetActivityHandler(NULL);
217 }
218
219 ////////////////////////////////////////////////////////////////////////////
Configure(OSCL_String & fmtstr)220 PVMFStatus PVMediaOutputNodePort::Configure(OSCL_String& fmtstr)
221 {
222 //This is called when the format is being set.
223 if (iConnectedPort)
224 {
225 // Must disconnect before changing port properties, so return error
226 return PVMFFailure;
227 }
228 PVMFFormatType fmt = fmtstr.get_cstr();
229
230 if (IsFormatSupported(fmt))
231 {
232 iPortFormat = fmt;
233 iSinkFormat = fmt;
234 iSinkFormatString = fmtstr;
235 FormatUpdated();
236 return PVMFSuccess;
237 }
238 else
239 {
240 iPortFormat = PVMF_MIME_FORMAT_UNKNOWN;
241 iSinkFormat = PVMF_MIME_FORMAT_UNKNOWN;
242 iSinkFormatString = fmtstr;
243 return PVMFFailure;
244 }
245 }
246
247 ////////////////////////////////////////////////////////////////////////////
248 // override the PvmfPortBaseImpl routine
Connect(PVMFPortInterface * aPort)249 OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::Connect(PVMFPortInterface* aPort)
250 {
251 PVMFStatus status = PvmfPortBaseImpl::Connect(aPort);
252 if (status != PVMFSuccess)
253 {
254 return status;
255 }
256
257 if (iMediaTransfer == NULL)
258 {
259 iMediaTransfer = iNode->iMIOControl->createMediaTransfer(iNode->iMIOSession);
260 if (iMediaTransfer)
261 {
262 iMediaTransfer->setPeer(this);
263 }
264 else
265 {
266 return PVMFFailure;
267 }
268 }
269
270 iSkipTimestamp = 0;
271
272 OsclAny* temp = NULL;
273 aPort->QueryInterface(PVMI_CAPABILITY_AND_CONFIG_PVUUID, temp);
274 PvmiCapabilityAndConfig *config = OSCL_STATIC_CAST(PvmiCapabilityAndConfig*, temp);
275
276 if (config != NULL)
277 {
278 PvmiKvp* configKvp = NULL;
279 PvmiKvp* aRet_kvp = NULL;
280 int num_elements = 0;
281 PVMFStatus status = config->getParametersSync(NULL, NULL, configKvp, num_elements, NULL);
282
283 if (status == PVMFSuccess)
284 {
285 iNode->iMIOConfig->setParametersSync(iNode->iMIOSession,
286 configKvp,
287 num_elements,
288 aRet_kvp);
289 config->releaseParameters(NULL, configKvp, num_elements);
290 }
291 }
292 return PVMFSuccess;
293 }
294
295 ////////////////////////////////////////////////////////////////////////////
296 // override the PvmfPortBaseImpl routine
PeerConnect(PVMFPortInterface * aPort)297 OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::PeerConnect(PVMFPortInterface* aPort)
298 {
299 PVMFStatus status = PvmfPortBaseImpl::PeerConnect(aPort);
300 if (status != PVMFSuccess)
301 {
302 return status;
303 }
304
305 if (iMediaTransfer == NULL)
306 {
307 iMediaTransfer = iNode->iMIOControl->createMediaTransfer(iNode->iMIOSession);
308 if (iMediaTransfer)
309 {
310 iMediaTransfer->setPeer(this);
311 }
312 else
313 {
314 return PVMFFailure;
315 }
316 }
317 return PVMFSuccess;
318 }
319
CleanupMediaTransfer()320 void PVMediaOutputNodePort::CleanupMediaTransfer()
321 {
322 int32 err;
323 //Just in case the media transfer did not report all the async write
324 //completes, cancel any pending write operations and clear up the cleanup queue
325 if (!iCleanupQueue.empty())
326 {
327 err = 0;
328 OSCL_TRY(err, iMediaTransfer->cancelAllCommands(););
329 ClearCleanupQueue();
330 }
331 if (iNode && iNode->iMIOControl && iMediaTransfer)
332 {
333 iMediaTransfer->setPeer(NULL);
334 err = 0;
335 OSCL_TRY(err, iNode->iMIOControl->deleteMediaTransfer(iNode->iMIOSession, iMediaTransfer));
336 OSCL_FIRST_CATCH_ANY(err,
337 PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR,
338 (0, "PVMediaOutputNodePort::CleanupMediaTransfer Caught a leave when calling deleteMediaTransfer!"));
339 );
340 iMediaTransfer = NULL;
341 }
342 if (iClock != NULL)
343 {
344 if (iClockNotificationsInf != NULL)
345 {
346 iClockNotificationsInf->RemoveClockObserver(*this);
347 iClockNotificationsInf->RemoveClockStateObserver(*this);
348 iClock->DestroyMediaClockNotificationsInterface(iClockNotificationsInf);
349 }
350 iClockNotificationsInf = NULL;
351 iClock = NULL;
352 }
353 if (iCurrentMediaMsg.GetRep() != NULL)
354 {
355 iCurrentMediaMsg.Unbind();
356 }
357 }
358
359 ////////////////////////////////////////////////////////////////////////////
360 // override the PvmfPortBaseImpl routine
Disconnect()361 OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::Disconnect()
362 {
363 CleanupMediaTransfer();
364 return PvmfPortBaseImpl::Disconnect();
365 }
366
367 ////////////////////////////////////////////////////////////////////////////
368 // override the PvmfPortBaseImpl routine
PeerDisconnect()369 OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::PeerDisconnect()
370 {
371 PVMFStatus status = PvmfPortBaseImpl::PeerDisconnect();
372 if (status != PVMFSuccess)
373 {
374 return status;
375 }
376 CleanupMediaTransfer();
377 return PVMFSuccess;
378 }
379
380 ////////////////////////////////////////////////////////////////////////////
381 // override the PvmfPortBaseImpl routine
ClearMsgQueues()382 OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::ClearMsgQueues()
383 {
384 if (iCurrentMediaMsg.GetRep() != NULL)
385 {
386 iCurrentMediaMsg.Unbind();
387 }
388
389 PvmfPortBaseImpl::ClearMsgQueues();
390 //cancel any pending write operations
391 if (!iCleanupQueue.empty())
392 {
393 int32 err;
394 OSCL_TRY(err, iMediaTransfer->cancelAllCommands(););
395 ClearCleanupQueue();
396 }
397
398 //may need to generate port flow control now
399 PvmfPortBaseImpl::EvaluateIncomingBusy();
400
401 return PVMFSuccess;
402 }
403
404 ////////////////////////////////////////////////////////////////////////////
addRef()405 void PVMediaOutputNodePort::addRef()
406 // for PVInterface
407 {
408 ++iExtensionRefCount;
409 }
410
411 ///////////////////////////////////////////////////////////////////////////
removeRef()412 void PVMediaOutputNodePort::removeRef()
413 // for PVInterface
414 {
415 if (iExtensionRefCount > 0)
416 {
417 --iExtensionRefCount;
418 }
419 }
420
421 ////////////////////////////////////////////////////////////////////////////
queryInterface(const PVUuid & uuid,PVInterface * & iface)422 bool PVMediaOutputNodePort::queryInterface(const PVUuid& uuid, PVInterface*& iface)
423 // for PVInterface
424 {
425 if (uuid == PvmfNodesSyncControlUuid)
426 {
427 PvmfNodesSyncControlInterface* myInterface = OSCL_STATIC_CAST(PvmfNodesSyncControlInterface*, this);
428 iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
429 addRef();
430 }
431 else
432 {
433 iface = NULL;
434 return false;
435 }
436 return true;
437 }
438
439 ////////////////////////////////////////////////////////////////////////////
NodeStarted()440 void PVMediaOutputNodePort::NodeStarted()
441 {
442 //it is possible that we attempted to call writeasync
443 //before media output comp start (can happen for active components)
444 //in those cases the comp can either accept or reject data
445 //if it rejected it by doing a leave, attempt to send data again
446 //now that we are done with start. Do not do the same for passive
447 //comps since this method is called during a pause-resume, and we
448 //do not want to attempt sending media data to passive comps till
449 //clock has been started
450 if ((iWriteState == EWriteWait) &&
451 (true == oActiveMediaOutputComp))
452 {
453 iWriteState = EWriteOK;
454 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::NodeStarted - WriteAsync Enabled - Fmt=%s, iWriteState=%d",
455 iSinkFormatString.get_str(),
456 iWriteState));
457 oProcessIncomingMessage = true;
458
459 if (iCurrentMediaMsg.GetRep() != NULL)
460 {
461 //attempt to send data current media msg if any
462 SendData();
463 }
464 }
465
466 RunIfNotReady();
467 }
468
469 // Attempt to process incoming message only after the mio component is fully configured
470 // and the clock is set by the node.
ProcessIncomingMessageIfPossible()471 void PVMediaOutputNodePort::ProcessIncomingMessageIfPossible()
472 {
473 if (oMIOComponentConfigured && iClock)
474 {
475 PVMF_MOPORT_LOGDATAPATH(
476 (0, "PVMediaOutputNodePort::ProcessIncomingMessageIfPossible: Fmt - Fmt=%s, MIOCompConfigured=%d, ActiveMIO=%d, ClockState=%d",
477 iSinkFormatString.get_str(), oMIOComponentConfigured, oActiveMediaOutputComp, iClock->GetState()));
478
479 PVMF_MOPORT_LOGDEBUG(
480 (0, "PVMediaOutputNodePort::ProcessIncomingMessageIfPossible: Fmt - Fmt=%s, MIOCompConfigured=%d, ActiveMIO=%d, ClockState=%d",
481 iSinkFormatString.get_str(), oMIOComponentConfigured, oActiveMediaOutputComp, iClock->GetState()));
482
483 if (true == oActiveMediaOutputComp)
484 {
485 oProcessIncomingMessage = true;
486 }
487 else
488 {
489 if (iClock->GetState() == PVMFMediaClock::RUNNING)
490 {
491 oProcessIncomingMessage = true;
492 }
493 }
494 RunIfNotReady();
495 }
496 else
497 {
498 PVMF_MOPORT_LOGDEBUG(
499 (0, "PVMediaOutputNodePort::ProcessIncomingMessageIfPossible: Fmt - Fmt=%s, MIOCompConfigured=%d, iClock=0x%x",
500 iSinkFormatString.get_str(), oMIOComponentConfigured, iClock));
501 }
502 }
503
SetMIOComponentConfigStatus(bool aStatus)504 void PVMediaOutputNodePort::SetMIOComponentConfigStatus(bool aStatus)
505 {
506 oMIOComponentConfigured = aStatus;
507
508 ProcessIncomingMessageIfPossible();
509 }
510
511
512 ////////////////////////////////////////////////////////////////////////////
513 //for sync control interface
SetClock(PVMFMediaClock * aClock)514 PVMFStatus PVMediaOutputNodePort::SetClock(PVMFMediaClock* aClock)
515 {
516 if (NULL == aClock)
517 {
518 return PVMFErrArgument;
519 }
520 iClock = aClock;
521
522 ProcessIncomingMessageIfPossible();
523
524 iClock->ConstructMediaClockNotificationsInterface(iClockNotificationsInf, *this);
525
526 if (NULL == iClockNotificationsInf)
527 {
528 return PVMFErrNoMemory;
529 }
530
531 iClockNotificationsInf->SetClockObserver(*this);
532 iClockNotificationsInf->SetClockStateObserver(*this);
533
534 return PVMFSuccess;
535 }
536
EnableMediaSync()537 void PVMediaOutputNodePort::EnableMediaSync()
538 {
539 //wait on play clock
540 oProcessIncomingMessage = false;
541 oActiveMediaOutputComp = false;
542 }
543
544 ////////////////////////////////////////////////////////////////////////////
545 //for sync control interface
ChangeClockRate(int32 aRate)546 PVMFStatus PVMediaOutputNodePort::ChangeClockRate(int32 aRate)
547 {
548 if (0 == aRate)
549 {
550 // A 0 value of clockrate is not handled
551 return PVMFFailure;
552 }
553 iClockRate = aRate;
554
555 PVMFStatus status;
556 status = SetMIOParameterInt32((char*)MOUT_MEDIAXFER_OUTPUT_RATE, aRate);
557
558 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,
559 "PVMediaOutputNodePort::ChangeClockRate rate %d",
560 aRate));
561
562 return status;
563 }
564
565 ////////////////////////////////////////////////////////////////////////////
SetMargins(int32 aEarlyMargin,int32 aLateMargin)566 PVMFStatus PVMediaOutputNodePort::SetMargins(int32 aEarlyMargin, int32 aLateMargin)
567 //for sync control interface
568 {
569 iEarlyMargin = aEarlyMargin;
570 iLateMargin = aLateMargin;
571 return PVMFSuccess;
572 }
573
574 ////////////////////////////////////////////////////////////////////////////
ClockStarted()575 void PVMediaOutputNodePort::ClockStarted()
576 //for sync control interface
577 {
578 if (IsBusy())
579 {
580 // Cancel any long waits due to data synchronization done
581 // before clock was set and started
582 Cancel();
583 }
584 RunIfNotReady();
585 }
586
587
588 ////////////////////////////////////////////////////////////////////////////
ClockStopped()589 void PVMediaOutputNodePort::ClockStopped()
590 //for sync control interface
591 {
592 ;//ignore
593 }
594
595 ////////////////////////////////////////////////////////////////////////////
setPeer(PvmiMediaTransfer * aPeer)596 void PVMediaOutputNodePort::setPeer(PvmiMediaTransfer *aPeer)
597 //for PvmiMediaTransfer
598 {
599 OSCL_UNUSED_ARG(aPeer);
600 }
601
602 ////////////////////////////////////////////////////////////////////////////
useMemoryAllocators(OsclMemAllocator * write_alloc)603 void PVMediaOutputNodePort::useMemoryAllocators(OsclMemAllocator* write_alloc)
604 //for PvmiMediaTransfer
605 {
606 OSCL_UNUSED_ARG(write_alloc);
607 OSCL_LEAVE(OsclErrNotSupported);
608 }
609
610
611 ////////////////////////////////////////////////////////////////////////////
writeAsync(uint8 format_type,int32 format_index,uint8 * data,uint32 data_len,const PvmiMediaXferHeader & data_header_info,OsclAny * context)612 PVMFCommandId PVMediaOutputNodePort::writeAsync(uint8 format_type, int32 format_index,
613 uint8* data, uint32 data_len,
614 const PvmiMediaXferHeader& data_header_info,
615 OsclAny* context)
616 //for PvmiMediaTransfer
617 {
618 OSCL_UNUSED_ARG(data_header_info);
619 OSCL_UNUSED_ARG(context);
620
621 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
622 (0, "PVMediaOutputNodePort::writeAsync: format_type=%d, format_index=%d, data=0x%x, data_len=%d",
623 format_type, format_index, data, data_len));
624
625 PVMFAsyncEvent* event = NULL;
626 switch (format_type)
627 {
628 case PVMI_MEDIAXFER_FMT_TYPE_NOTIFICATION:
629 switch (format_index)
630 {
631 case PVMI_MEDIAXFER_FMT_INDEX_INFO_EVENT:
632 OSCL_ASSERT(iNode);
633 OSCL_ASSERT(iMediaTransfer);
634
635 if (!data)
636 {
637 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
638 (0, "PVMediaOutputNodePort::writeAsync: Error - data is NULL"));
639 OSCL_LEAVE(OsclErrArgument);
640 return -1;
641 }
642
643 if (data_len != sizeof(PVMFAsyncEvent))
644 {
645 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
646 (0, "PVMediaOutputNodePort::writeAsync: Error - data length is not size of PVMFAsyncEvent"));
647 OSCL_LEAVE(OsclErrArgument);
648 return -1;
649 }
650
651 event = OSCL_STATIC_CAST(PVMFAsyncEvent*, data);
652 iNode->ReportInfoEvent((*event));
653
654 // Not really processing this asynchronously. Just call writeComplete
655 // synchronously
656 iMediaTransfer->writeComplete(PVMFSuccess, iMioInfoErrorCmdId, context);
657 return iMioInfoErrorCmdId++;
658
659 case PVMI_MEDIAXFER_FMT_INDEX_ERROR_EVENT:
660 OSCL_ASSERT(iNode);
661 OSCL_ASSERT(iMediaTransfer);
662
663 if (!data)
664 {
665 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
666 (0, "PVMediaOutputNodePort::writeAsync: Error - data is NULL"));
667 OSCL_LEAVE(OsclErrArgument);
668 return -1;
669 }
670
671 if (data_len != sizeof(PVMFAsyncEvent))
672 {
673 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
674 (0, "PVMediaOutputNodePort::writeAsync: Error - data length is not size of PVMFAsyncEvent"));
675 OSCL_LEAVE(OsclErrArgument);
676 return -1;
677 }
678
679 event = OSCL_STATIC_CAST(PVMFAsyncEvent*, data);
680 iNode->ReportErrorEvent((*event));
681
682 // Not really processing this asynchronously. Just call writeComplete
683 // synchronously
684 iMediaTransfer->writeComplete(PVMFSuccess, iMioInfoErrorCmdId, context);
685 return iMioInfoErrorCmdId++;
686
687 default:
688 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
689 (0, "PVMediaOutputNodePort::writeAsync: Error - Unsupported format_index"));
690 OSCL_LEAVE(OsclErrNotSupported);
691 break;
692 }
693
694 default:
695 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
696 (0, "PVMediaOutputNodePort::writeAsync: Error - Unsupported format_type"));
697 OSCL_LEAVE(OsclErrNotSupported);
698 break;
699 }
700
701 return -1;
702 }
703
704
705 ////////////////////////////////////////////////////////////////////////////
writeComplete(PVMFStatus status,PVMFCommandId aCmdId,OsclAny * aContext)706 void PVMediaOutputNodePort::writeComplete(PVMFStatus status, PVMFCommandId aCmdId, OsclAny* aContext)
707 //for PvmiMediaTransfer
708 {
709 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO,
710 (0, "PVMediaOutputNodePort::writeComplete status %d cmdId %d context 0x%x", status, aCmdId, aContext));
711
712 // Check if the writeComplete is in response to EOS message
713 if (&iWriteAsyncEOSContext == (uint32*)aContext)
714 {
715 if (iWriteState == EWriteBusy)
716 {
717 // Synchronous completion
718 // Let EndOfData info event be sent out in EndOfData() function
719 iWriteState = EWriteOK;
720 }
721 else
722 {
723 // Report End of Data to the user of media output node
724 // only if the EOS media transfer completes successfully and
725 // there is no pending MIO control request
726 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::writeComplete For EOS - Fmt=%s",
727 iSinkFormatString.get_str()));
728 if (iEosStreamIDVec.size() != 0)
729 {
730 //iEosStreamIDVec is used as a FIFO to store the steamids of eos sent to mio comp.
731 //streamid is pushed in at front when call writeasync(eos) to mio comp.
732 //streamid is poped out from end when mio comp. calls writecomplete(eos),
733 //we report PVMFInfoEndOfData with the poped streamid.
734 //This logic depends on Mio comp. process data(at least eos msg) in a sequencial style.
735 uint32 EosStreamID = iEosStreamIDVec.back();
736
737 // Asynchronous completion
738 if (status == PVMFSuccess)
739 {
740 // Report EndofData to engine only if MIO comp sends success for End Of Stream.
741 // FOr other return codes just pop out the EOS from the vector.
742 iNode->ReportInfoEvent(PVMFInfoEndOfData, (OsclAny*)&EosStreamID);
743 }
744 else
745 {
746 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::writeComplete EOS media transfer completed but PVMFInfoEndOfData not sent"));
747 }
748
749 iEosStreamIDVec.pop_back();
750 }
751 else
752 {
753 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::writeComplete - Invalid iEosStreamIDVec size=0"));
754 OSCL_ASSERT(false);
755 }
756
757 }
758 }
759 // Check if the writeComplete is in response to Reconfig message
760 else if (&iWriteAsyncReConfigContext == (uint32*)aContext)
761 {
762 if (iWriteState == EWriteBusy)
763 {
764 // Synchronous completion
765 iWriteState = EWriteOK;
766 }
767 else
768 {
769 // Asynchronous completion
770 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::writeComplete For RECONFIG - Fmt=%s",
771 iSinkFormatString.get_str()));
772 }
773 }
774 //detect cases where the current SendData call is completing synchronously.
775 else if (iWriteState == EWriteBusy)
776 {
777 //synchronous completion
778 iWriteState = EWriteOK;
779 }
780 else
781 {
782 //asynchronous completion.
783 //do any memory cleanup
784 bool oCmdIdFound = false;
785 uint32 i;
786 for (i = 0; i < iCleanupQueue.size(); i++)
787 {
788 if (iCleanupQueue[i].iCmdId == aCmdId)
789 {
790 PVMFSharedMediaDataPtr mediaData = iCleanupQueue[i].iData;
791 iCleanupQueue.erase(&iCleanupQueue[i]);
792 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::writeComplete - Fmt=%s, Seq=%d, TS=%d, FIdx=%d, ClnUpQSize=%d",
793 iSinkFormatString.get_str(),
794 mediaData->getSeqNum(),
795 mediaData->getTimestamp(),
796 iFragIndex,
797 iCleanupQueue.size()));
798 oCmdIdFound = true;
799 break;
800 }
801 }
802 if (oCmdIdFound == false)
803 {
804 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::writeComplete - CmdId Not Found - Fmt=%s, FIdx=%d, ClnUpQSize=%d",
805 iSinkFormatString.get_str(),
806 iFragIndex,
807 iCleanupQueue.size()));
808 }
809 }
810 }
811
812 ////////////////////////////////////////////////////////////////////////////
readAsync(uint8 * data,uint32 max_data_len,OsclAny * context,int32 * formats,uint16 num_formats)813 PVMFCommandId PVMediaOutputNodePort::readAsync(uint8* data, uint32 max_data_len, OsclAny* context,
814 int32* formats, uint16 num_formats)
815 //for PvmiMediaTransfer
816 {
817 OSCL_UNUSED_ARG(data);
818 OSCL_UNUSED_ARG(max_data_len);
819 OSCL_UNUSED_ARG(context);
820 OSCL_UNUSED_ARG(formats);
821 OSCL_UNUSED_ARG(num_formats);
822 OSCL_LEAVE(OsclErrNotSupported);
823 return -1;
824 }
825
826
827 ////////////////////////////////////////////////////////////////////////////
readComplete(PVMFStatus status,PVMFCommandId read_cmd_id,int32 format_index,const PvmiMediaXferHeader & data_header_info,OsclAny * context)828 void PVMediaOutputNodePort::readComplete(PVMFStatus status, PVMFCommandId read_cmd_id,
829 int32 format_index, const PvmiMediaXferHeader& data_header_info,
830 OsclAny* context)
831 //for PvmiMediaTransfer
832 {
833 OSCL_UNUSED_ARG(status);
834 OSCL_UNUSED_ARG(read_cmd_id);
835 OSCL_UNUSED_ARG(format_index);
836 OSCL_UNUSED_ARG(data_header_info);
837 OSCL_UNUSED_ARG(context);
838 OSCL_LEAVE(OsclErrNotSupported);
839 }
840
841
842 ////////////////////////////////////////////////////////////////////////////
statusUpdate(uint32 status_flags)843 void PVMediaOutputNodePort::statusUpdate(uint32 status_flags)
844 //for PvmiMediaTransfer
845 {
846 PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_INFO,
847 (0, "PVMediaOutputNodePort::statusUpdate flags %d", status_flags));
848
849 if (status_flags & PVMI_MEDIAXFER_STATUS_WRITE)
850 {
851 //recover from a previous async write error.
852 if (iWriteState == EWriteWait)
853 {
854 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::statusUpdate - WriteAsync Enabled - Fmt=%s, iWriteState=%d",
855 iSinkFormatString.get_str(),
856 iWriteState));
857 iWriteState = EWriteOK;
858
859 // Allow data to be processed if possible
860 ProcessIncomingMessageIfPossible();
861
862 if (oProcessIncomingMessage == true)
863 {
864 if (iCurrentMediaMsg.GetRep() != NULL)
865 {
866 //attempt to send data current media msg if any
867 SendData();
868 }
869 //reschedule if there is more stuff waiting and
870 //if we can process more data
871 if (IncomingMsgQueueSize() > 0)
872 {
873 RunIfNotReady();
874 }
875 }
876 }
877 }
878 else
879 {
880 //disable write
881 iWriteState = EWriteWait;
882 oProcessIncomingMessage = false;
883 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::statusUpdate - WriteAsync Disabled - Fmt=%s, iWriteState=%d",
884 iSinkFormatString.get_str(),
885 iWriteState));
886 }
887 }
888
889
890 ////////////////////////////////////////////////////////////////////////////
cancelCommand(PVMFCommandId command_id)891 void PVMediaOutputNodePort::cancelCommand(PVMFCommandId command_id)
892 //for PvmiMediaTransfer
893 {
894 OSCL_UNUSED_ARG(command_id);
895 OSCL_LEAVE(OsclErrNotSupported);
896 }
897
898
899 ////////////////////////////////////////////////////////////////////////////
cancelAllCommands()900 void PVMediaOutputNodePort::cancelAllCommands()
901 //for PvmiMediaTransfer
902 {
903 OSCL_LEAVE(OsclErrNotSupported);
904 }
905
906
907 ////////////////////////////////////////////////////////////////////////////
IsFormatSupported(PVMFFormatType aFmt)908 bool PVMediaOutputNodePort::IsFormatSupported(PVMFFormatType aFmt)
909 // for PvmiCapabilityAndConfigPortFormatImpl interface
910 {
911 //Verify if the format is supported by the media I/O component.
912 PvmiKvp kvpFormatType;
913
914 OSCL_StackString<64> iKVPFormatType = _STRLIT_CHAR(PVMF_FORMAT_TYPE_VALUE_KEY);
915
916 kvpFormatType.key = NULL;
917 kvpFormatType.key = iKVPFormatType.get_str();
918 kvpFormatType.value.pChar_value = (char*)aFmt.getMIMEStrPtr();
919
920 PVMFStatus status = iNode->iMIOConfig->verifyParametersSync(NULL, &kvpFormatType, 1);
921 if (status != PVMFSuccess)
922 {
923 return false;
924 }
925 return true;
926 }
927
928 ////////////////////////////////////////////////////////////////////////////
FormatUpdated()929 void PVMediaOutputNodePort::FormatUpdated()
930 // for PvmiCapabilityAndConfigPortFormatImpl interface
931 {
932 //called when format was just set, either through capability and config,
933 //for by node during port request.
934 if (iSinkFormat.isAudio())
935 {
936 //set port name for datapath logging.
937 SetName("MediaOutIn(Audio)");
938
939 //pass the selected format to the MIO component.
940 //ignore any failure since not all MIO may support the feature.
941 SetMIOParameterPchar((char*)MOUT_AUDIO_FORMAT_KEY, iSinkFormatString.get_str());
942
943 //save the media type.
944 if (iSinkFormat.isCompressed())
945 {
946 iMediaType = PVMF_MEDIA_COMPRESSED_AUDIO;
947 }
948 else
949 {
950 iMediaType = PVMF_MEDIA_UNCOMPRESSED_AUDIO;
951 isUnCompressedMIO = true;
952 }
953 }
954 else if (iSinkFormat.isVideo())
955 {
956 //set port name for datapath logging.
957 SetName("MediaOutIn(Video)");
958
959 //pass the selected format to the MIO component.
960 //ignore any failure since not all MIO may support the feature.
961 SetMIOParameterPchar((char*)MOUT_VIDEO_FORMAT_KEY, iSinkFormatString.get_str());
962
963 //save the media type.
964 if (iSinkFormat.isCompressed())
965 {
966 iMediaType = PVMF_MEDIA_COMPRESSED_VIDEO;
967 }
968 else
969 {
970 iMediaType = PVMF_MEDIA_UNCOMPRESSED_VIDEO;
971 isUnCompressedMIO = true;
972 }
973 }
974 else if (iSinkFormat.isText())
975 {
976 //set port name for datapath logging.
977 SetName("MediaOutIn");
978
979 //pass the selected format to the MIO component.
980 //ignore any failure since not all MIO may support the feature.
981 SetMIOParameterPchar((char*)MOUT_TEXT_FORMAT_KEY, iSinkFormatString.get_str());
982
983 //save the media type.
984 iMediaType = PVMF_MEDIA_TEXT;
985 }
986 }
987
988 ////////////////////////////////////////////////////////////////////////////
SendData()989 void PVMediaOutputNodePort::SendData()
990 //send data to the MIO componenent.
991 {
992 const int32 toleranceWndForCallback = 0;
993 if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID)
994 {
995 if (oActiveMediaOutputComp)
996 {
997 SendEndOfData();
998 }
999 else if (iFrameStepMode == false)
1000 {
1001 uint32 delta = 0;
1002 PVMFMediaOutputNodePortMediaTimeStatus status = CheckMediaTimeStamp(delta);
1003 if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ON_TIME || status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_LATE)
1004 {
1005 SendEndOfData();
1006 }
1007 else if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_EARLY)
1008 {
1009
1010 OSCL_ASSERT(false == oClockCallBackPending);
1011 //stop processing input, since we are not done with the current media msg
1012 oProcessIncomingMessage = false;
1013 oClockCallBackPending = false;
1014
1015 if (NULL != iClockNotificationsInf)
1016 {
1017 PVMFStatus status =
1018 iClockNotificationsInf->SetCallbackDeltaTime(delta, //delta time in clock when callBack should be called
1019 toleranceWndForCallback,
1020 this, //observer object to be called on timeout
1021 false, //no threadLock
1022 NULL, //no context
1023 iDelayEarlyFrameCallBkId); //ID used to identify the timer for cancellation
1024 if (PVMFSuccess != status)
1025 {
1026 //If delta specified for the callback is too large, then callback to the Mediaclock notification interface does not succeed
1027 //Possible reasons for huge difference between the playback clock and the timestamp could be
1028 //Sample is intended to be played after a very long time from now (as indicated by the data source(streaming server/file)).
1029 //Timestamp is corrupted in the source node.
1030 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendData - Could not set callback notification for send data %d delta %u", status, delta));
1031 iNode->ReportErrorEvent(PVMFErrCorrupt, NULL, PVMFMoutNodeErr_Unexpected);
1032 return;
1033 }
1034 else
1035 {
1036 oClockCallBackPending = true;
1037 }
1038 }
1039 else
1040 {
1041 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendData - Fmt=%s, No callback notification Intf ",
1042 iSinkFormatString.get_str()));
1043 OSCL_ASSERT(false);
1044 }
1045 }
1046 }
1047 else if (iFrameStepMode == true)
1048 {
1049 PVMFMediaOutputNodePortMediaTimeStatus status = CheckMediaFrameStep();
1050 if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ON_TIME || status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_LATE)
1051 {
1052 SendEndOfData();
1053 }
1054 else if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_EARLY)
1055 {
1056 //stop processing input, since we are not done with the current media msg
1057 oProcessIncomingMessage = false;
1058 //wait on ClockCountUpdated call back from oscl clock
1059 }
1060 }
1061 }
1062 else if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_RE_CONFIG_FORMAT_ID)
1063 {
1064 SendReConfigNotification();
1065 }
1066 else if (iCurrentMediaMsg->getFormatID() < PVMF_MEDIA_CMD_FORMAT_IDS_START)
1067 {
1068 if (oActiveMediaOutputComp)
1069 {
1070 SendMediaData();
1071 }
1072 else if (iFrameStepMode == false)
1073 {
1074 uint32 delta = 0;
1075 PVMFMediaOutputNodePortMediaTimeStatus status = CheckMediaTimeStamp(delta);
1076 if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ON_TIME)
1077 {
1078 SendMediaData();
1079 }
1080 else if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_LATE)
1081 {
1082 iCurrentMediaMsg.Unbind();
1083 iFragIndex = 0;
1084 }
1085 else if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_EARLY)
1086 {
1087
1088 OSCL_ASSERT(false == oClockCallBackPending);
1089 //stop processing input, since we are not done with the current media msg
1090 oProcessIncomingMessage = false;
1091 oClockCallBackPending = false;
1092
1093 if (NULL != iClockNotificationsInf)
1094 {
1095 PVMFStatus status =
1096 iClockNotificationsInf->SetCallbackDeltaTime(delta, //delta time in clock when callBack should be called
1097 toleranceWndForCallback,
1098 this, //observer object to be called on timeout
1099 false, //no threadLock
1100 NULL, //no context
1101 iDelayEarlyFrameCallBkId); //ID used to identify the timer for cancellation
1102 if (PVMFSuccess != status)
1103 {
1104 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendData - Could not set callback notification for early frame %d delta %u", status, delta));
1105 iNode->ReportErrorEvent(PVMFErrCorrupt, NULL, PVMFMoutNodeErr_Unexpected);
1106 return;
1107 }
1108 else
1109 {
1110 oClockCallBackPending = true;
1111 }
1112 }
1113 else
1114 {
1115 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendData - Fmt=%s, No callback notification Intf ",
1116 iSinkFormatString.get_str()));
1117 OSCL_ASSERT(false);
1118 }
1119 }
1120 }
1121 else if (iFrameStepMode == true)
1122 {
1123 PVMFMediaOutputNodePortMediaTimeStatus status = CheckMediaFrameStep();
1124 if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ON_TIME)
1125 {
1126 SendMediaData();
1127 }
1128 else if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_LATE)
1129 {
1130 iCurrentMediaMsg.Unbind();
1131 iFragIndex = 0;
1132 }
1133 else if (status == PVMF_MEDIAOUTPUTNODEPORT_MEDIA_EARLY)
1134 {
1135 //stop processing input, since we are not done with the current media msg
1136 oProcessIncomingMessage = false;
1137 //wait on ClockCountUpdated call back from oscl clock
1138 }
1139 }
1140 }
1141 }
1142
1143 ////////////////////////////////////////////////////////////////////////////
SendMediaData()1144 void PVMediaOutputNodePort::SendMediaData()
1145 //send media data to the MIO componenent.
1146 {
1147 if (iWriteState != EWriteOK)
1148 {
1149 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendMediaData - Fmt=%s - Invalid WriteAsync State - State=%d",
1150 iSinkFormatString.get_str(),
1151 iWriteState));
1152 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendMediaData - Fmt=%s - Invalid WriteAsync State - State=%d",
1153 iSinkFormatString.get_str(),
1154 iWriteState));
1155 OSCL_ASSERT(false);
1156 }
1157
1158 PVMFSharedMediaDataPtr mediaData;
1159 convertToPVMFMediaData(mediaData, iCurrentMediaMsg);
1160
1161 uint32 duration = 0;
1162 if (mediaData->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_DURATION_AVAILABLE_BIT)
1163 {
1164 duration = mediaData->getDuration();
1165 }
1166
1167 // extract private data (if it is in fsi)
1168 OsclAny *privatedataptr = NULL;
1169 uint32 privatedatalength = 0;
1170
1171 OsclRefCounterMemFrag fsifrag;
1172 mediaData->getFormatSpecificInfo(fsifrag);
1173
1174 uint32 *data = (uint32 *)fsifrag.getMemFragPtr();
1175 uint32 data_len = fsifrag.getMemFragSize();
1176 if (data && data_len > 0)
1177 {
1178 //data to extract
1179 privatedataptr = (OsclAny*)(*data);
1180 privatedatalength = data_len;
1181 }
1182
1183
1184 for (uint32 fragindex = iFragIndex; fragindex < mediaData->getNumFragments();)
1185 {
1186 OsclRefCounterMemFrag frag;
1187 mediaData->getMediaFragment(fragindex, frag);
1188
1189 iWriteState = EWriteBusy;
1190 int32 err = OsclErrNone;
1191 int32 cmdId = 0;
1192
1193 uint32 flags = PVMI_MEDIAXFER_MEDIA_DATA_FLAG_NONE;
1194
1195 // The marker bit should only be set for the final frag to allow MIO to reassemble data properly
1196 if ((mediaData->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_M_BIT) &&
1197 (fragindex == (mediaData->getNumFragments() - 1)))
1198 {
1199 flags |= PVMI_MEDIAXFER_MEDIA_DATA_FLAG_MARKER_BIT;
1200 }
1201 if (mediaData->getMarkerInfo() & PVMF_MEDIA_DATA_MARKER_INFO_NO_RENDER_BIT)
1202 {
1203 flags |= PVMI_MEDIAXFER_MEDIA_DATA_FLAG_NO_RENDER_BIT;
1204 }
1205 PvmiMediaXferHeader mediaxferhdr;
1206 mediaxferhdr.seq_num = mediaData->getSeqNum();
1207 mediaxferhdr.timestamp = mediaData->getTimestamp();
1208 mediaxferhdr.duration = duration;
1209 mediaxferhdr.flags = flags;
1210 mediaxferhdr.stream_id = mediaData->getStreamID();
1211 mediaxferhdr.private_data_length = privatedatalength;
1212 mediaxferhdr.private_data_ptr = privatedataptr;
1213 err = WriteDataToMIO(cmdId, mediaxferhdr, frag);
1214
1215 if (err != OsclErrNone)
1216 {
1217 // A Busy or an InvalidState leave can occur in a writeAsync call. If a leave occurs in writeasync call,
1218 // suspend data transfer.
1219 // A Busy leave is not an error and is a normal flow control mechanism.
1220 // Some MIO components can do a InvalidState leave if writeasyncs are called before calling Start on MIOs.
1221 // Data transfer to MIOs will resume when
1222 // 1) In case of Busy Leave: A statusUpdate call from the MIO component tells us to resume.
1223 // 2) In case of InvalidState Leave: A statusUpdate call from the MIO component tells us to resume. OR
1224 // MIO sends the command complete for Start.
1225 iWriteState = EWriteWait;
1226
1227 //stop processing input, since we are not done with the current media msg
1228 oProcessIncomingMessage = false;
1229
1230 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendMediaData - WriteAsyncLeave - Fmt=%s, LeaveCode=%d",
1231 iSinkFormatString.get_str(),
1232 err));
1233
1234 return ;//wait on statusUpdate call or start complete from the MIO component.
1235 }
1236 else
1237 {
1238 fragindex++;
1239 iFragIndex++;
1240 if (fragindex == mediaData->getNumFragments())
1241 {
1242 //all fragments have been sent. see whether completion
1243 //is synchronous or asynchronous.
1244 if (iWriteState == EWriteBusy)
1245 {
1246 //asynchronous completion.
1247 //push the data onto the cleanup stack so it won't get cleaned
1248 //up until the component consumes it.
1249 iCleanupQueue.push_back(CleanupQueueElement(mediaData, cmdId));
1250 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendMediaData - AsyncWrite - Fmt=%s, Seq=%d, TS=%d, Dur=%d, FIdx=%d, ClnUpQSize=%d",
1251 iSinkFormatString.get_str(),
1252 mediaData->getSeqNum(),
1253 mediaData->getTimestamp(),
1254 duration,
1255 iFragIndex,
1256 iCleanupQueue.size()));
1257 }
1258 //else the write already completed synchronously.
1259 else
1260 {
1261 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendMediaData - SyncWrite - Fmt=%s, Seq=%d, TS=%d, Dur=%d, FIdx=%d, ClnUpQSize=%d",
1262 iSinkFormatString.get_str(),
1263 mediaData->getSeqNum(),
1264 mediaData->getTimestamp(),
1265 duration,
1266 iFragIndex,
1267 iCleanupQueue.size()));
1268 }
1269 //we are done with current media msg - either we are truly done (sync write complete) or we are
1270 //waiting on async write complete in which case media msg has been pushed into the cleanup queue
1271 iCurrentMediaMsg.Unbind();
1272 iFragIndex = 0;
1273 }
1274 iWriteState = EWriteOK;
1275 }
1276 }
1277 return;
1278 }
1279
1280 ////////////////////////////////////////////////////////////////////////////
SendEndOfData()1281 void PVMediaOutputNodePort::SendEndOfData()
1282 //send end of data notice to the MIO componenent.
1283 {
1284 if (iWriteState != EWriteOK)
1285 {
1286 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendEndOfData - Invalid WriteAsync State - State=%d", iWriteState));
1287 OSCL_ASSERT(false);
1288 }
1289
1290 uint32 eosseqnum = iCurrentMediaMsg->getSeqNum();
1291 uint32 eostimestamp = iCurrentMediaMsg->getTimestamp();
1292
1293 iWriteState = EWriteBusy;
1294
1295 int32 err;
1296 int32 cmdId = 0;
1297
1298 PvmiMediaXferHeader mediaxferhdr;
1299 mediaxferhdr.seq_num = eosseqnum;
1300 mediaxferhdr.timestamp = eostimestamp;
1301 mediaxferhdr.duration = 0;
1302 mediaxferhdr.flags = PVMI_MEDIAXFER_MEDIA_DATA_FLAG_NONE;
1303 mediaxferhdr.stream_id = iCurrentMediaMsg->getStreamID();
1304 uint32 EosStreamId = mediaxferhdr.stream_id;
1305
1306 //iEosStreamIDVec is used as a FIFO to store the steamids of eos sent to mio comp.
1307 //streamid is pushed in at front when call writeasync(eos) to mio comp.
1308 //streamid is poped out from end when mio comp. calls writecomplete(eos),
1309 //we report PVMFInfoEndOfData with the poped streamid.
1310 //This logic depends on Mio comp. process data(at least eos msg) in a sequencial style.
1311 iEosStreamIDVec.push_front(EosStreamId);
1312 OSCL_TRY(err,
1313 cmdId = iMediaTransfer->writeAsync(PVMI_MEDIAXFER_FMT_TYPE_NOTIFICATION, /*format_type*/
1314 PVMI_MEDIAXFER_FMT_INDEX_END_OF_STREAM, /*format_index*/
1315 NULL,
1316 0,
1317 mediaxferhdr,
1318 (OsclAny*) & iWriteAsyncEOSContext);
1319 );
1320
1321 if (err != OsclErrNone)
1322 {
1323 // A Busy or an InvalidState leave can occur in a writeAsync call. If a leave occurs in writeasync call,
1324 // suspend data transfer.
1325 // A Busy leave is not an error and is a normal flow control mechanism.
1326 // Some MIO components can do a InvalidState leave if writeasyncs are called before calling Start on MIOs.
1327 // Data transfer to MIOs will resume when
1328 // 1) In case of Busy Leave: A statusUpdate call from the MIO component tells us to resume.
1329 // 2) In case of InvalidState Leave: A statusUpdate call from the MIO component tells us to resume. OR
1330 // MIO sends the command complete for Start.
1331 iWriteState = EWriteWait;
1332
1333 //stop processing input, since we are not done with the current media msg
1334 oProcessIncomingMessage = false;
1335
1336 // StreamID popped from vector when leave occurs in the writeAsync call
1337 if (iEosStreamIDVec.size() != 0)
1338 {
1339 iEosStreamIDVec.erase(iEosStreamIDVec.begin());
1340 }
1341 else
1342 {
1343 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendEndOfData - Invalid iEosStreamIDVec size=0"));
1344 OSCL_ASSERT(false);
1345 }
1346
1347 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendEndOfData - WriteAsyncLeave - Fmt=%s, LeaveCode=%d",
1348 iSinkFormatString.get_str(),
1349 err));
1350
1351 return ;//wait on statusUpdate call or start complete from the MIO component.
1352 }
1353 else
1354 {
1355 if (iWriteState == EWriteBusy)
1356 {
1357 //asynchronous completion.
1358 //wait for writeComplete to be called for this request
1359 //log media data info.
1360 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendEndOfData - AsyncWrite - Fmt=%s, Seq=%d, TS=%d, ClnUpQSize=%d",
1361 iSinkFormatString.get_str(),
1362 iCurrentMediaMsg->getSeqNum(),
1363 iCurrentMediaMsg->getTimestamp(),
1364 iCleanupQueue.size()));
1365
1366 iWriteState = EWriteOK;
1367
1368 }
1369 //else the write already completed synchronously.
1370 else
1371 {
1372 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendEndOfData - SyncWrite - Fmt=%s, Seq=%d, TS=%d, ClnUpQSize=%d",
1373 iSinkFormatString.get_str(),
1374 iCurrentMediaMsg->getSeqNum(),
1375 iCurrentMediaMsg->getTimestamp(),
1376 iCleanupQueue.size()));
1377
1378 // Report End of Data to the user of media output node
1379 if (iEosStreamIDVec.size() != 0)
1380 {
1381 //iEosStreamIDVec is used as a FIFO to store the steamids of eos sent to mio comp.
1382 //streamid is pushed in at front when call writeasync(eos) to mio comp.
1383 //streamid is poped out from end when mio comp. calls writecomplete(eos),
1384 //we report PVMFInfoEndOfData with the poped streamid.
1385 //This logic depends on Mio comp. process data(at least eos msg) in a sequencial style.
1386 uint32 EosStreamID = iEosStreamIDVec.back();
1387 iNode->ReportInfoEvent(PVMFInfoEndOfData, (OsclAny*)&EosStreamID);
1388 iEosStreamIDVec.pop_back();
1389 }
1390 else
1391 {
1392 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendEndOfData - Invalid iEosStreamIDVec size=0"));
1393 OSCL_ASSERT(false);
1394 }
1395 }
1396 //we are done with current media msg - either we are truly done (sync write complete) or we are
1397 //waiting on async write complete. there is no need to push this msg into cleanup queue since it
1398 //is a notification as opossed to media data
1399 iCurrentMediaMsg.Unbind();
1400 iFragIndex = 0;
1401 }
1402 }
1403
1404 ////////////////////////////////////////////////////////////////////////////
SendReConfigNotification()1405 void PVMediaOutputNodePort::SendReConfigNotification()
1406 //send reconfig notice to the MIO componenent.
1407 {
1408 if (iWriteState != EWriteOK)
1409 {
1410 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendReConfigNotification - Invalid WriteAsync State - State=%d", iWriteState));
1411 OSCL_ASSERT(false);
1412 }
1413
1414 iWriteState = EWriteBusy;
1415 int32 err;
1416 int32 cmdId = 0;
1417 PvmiMediaXferHeader mediaxferhdr;
1418 mediaxferhdr.seq_num = iCurrentMediaMsg->getSeqNum();
1419 mediaxferhdr.timestamp = 0;
1420 mediaxferhdr.duration = 0;
1421 mediaxferhdr.flags = PVMI_MEDIAXFER_MEDIA_DATA_FLAG_NONE;
1422 mediaxferhdr.stream_id = iCurrentMediaMsg->getStreamID();
1423 OSCL_TRY(err,
1424 cmdId = iMediaTransfer->writeAsync(PVMI_MEDIAXFER_FMT_TYPE_NOTIFICATION, /*format_type*/
1425 PVMI_MEDIAXFER_FMT_INDEX_RE_CONFIG_NOTIFICATION, /*format_index*/
1426 NULL, 0,
1427 mediaxferhdr,
1428 (OsclAny*) & iWriteAsyncReConfigContext);
1429 );
1430
1431 if (err != OsclErrNone)
1432 {
1433 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::SendReConfigNotification SendReConfigNotification leave code %d", err));
1434 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendReConfigNotification SendReConfigNotification leave code %d", err));
1435 //we don't handle a leave here-- it's an error
1436 //media output comps should be open to recving reconfig anytime
1437 //they are free to process it at a later point in time and they may
1438 //choose to accept the reconfig and reject it. but there should never
1439 //be a case where cannot even queue the reconfig request
1440 iNode->ReportErrorEvent(PVMFErrResource, NULL, PVMFMoutNodeErr_WriteAsync);
1441 }
1442 else
1443 {
1444 if (iWriteState == EWriteBusy)
1445 {
1446 //asynchronous completion.
1447 //wait for writeComplete to be called for this request
1448 //log media data info.
1449 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendReConfigNotification - AsyncWrite - Fmt=%s, Seq=%d, TS=%d, ClnUpQSize=%d",
1450 iSinkFormatString.get_str(),
1451 iCurrentMediaMsg->getSeqNum(),
1452 iCurrentMediaMsg->getTimestamp(),
1453 iCleanupQueue.size()));
1454
1455 iWriteState = EWriteOK;
1456
1457 }
1458 //else the write already completed synchronously.
1459 else
1460 {
1461 //log media data info.
1462 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SendEndOfData - SyncWrite - Fmt=%s, Seq=%d, TS=%d, ClnUpQSize=%d",
1463 iSinkFormatString.get_str(),
1464 iCurrentMediaMsg->getSeqNum(),
1465 iCurrentMediaMsg->getTimestamp(),
1466 iCleanupQueue.size()));
1467 }
1468 //we are done with current media msg - either we are truly done (sync write complete) or we are
1469 //waiting on async write complete. there is no need to push this msg into cleanup queue since it
1470 //is a notification as opossed to media data
1471 iCurrentMediaMsg.Unbind();
1472 iFragIndex = 0;
1473 }
1474 }
1475
1476 ////////////////////////////////////////////////////////////////////////////
1477 PVMFMediaOutputNodePortMediaTimeStatus
CheckMediaTimeStamp(uint32 & aDelta)1478 PVMediaOutputNodePort::CheckMediaTimeStamp(uint32& aDelta)
1479 {
1480 PVMFTimestamp aTimeStamp = iCurrentMediaMsg->getTimestamp();
1481 aDelta = 0;
1482 //aTimeStamp is assumed to be in milliseconds
1483 if (iClock != NULL)
1484 {
1485 uint32 clock_msec32;
1486 bool overflowFlag = false;
1487
1488 iClock->GetCurrentTime32(clock_msec32, overflowFlag, PVMF_MEDIA_CLOCK_MSEC);
1489
1490
1491 uint32 clock_adjforearlymargin = clock_msec32 + iEarlyMargin;
1492 uint32 ts_adjforlatemargin = aTimeStamp + iLateMargin;
1493
1494 if ((clock_adjforearlymargin - aTimeStamp) > WRAP_THRESHOLD)
1495 {
1496 // This condition indicates that the timestamp is ahead of the adjusted playback clock
1497 // Note that since the computation is based on 32-bit values, it has a limitation that
1498 // it will not work for durations exceeding 2^32 milliseconds = 49+ days which is an acceptable
1499 // limit for this application.
1500 // Say clock is 1000ms, early margin is 200ms, then any timestamp later than 1200ms should be
1501 // held back. If ts is greater than 1200ms, then (1200 - ts) will be larger than wrap threshold
1502 uint32 deltaInMS = (aTimeStamp - clock_msec32);
1503 deltaInMS -= iEarlyMargin;
1504 if (iClockRate > 1)
1505 {
1506 //In case of rate change, calculate delta to acct
1507 //for clock rate
1508 MediaClockConverter mcc;
1509 mcc.set_timescale(iClockRate);
1510 //delta is in milliseconds
1511 mcc.set_clock_other_timescale(deltaInMS, 1000);
1512 //get the value in milliseconds
1513 aDelta = mcc.get_converted_ts(1000);
1514 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CheckMediaTimeStamp - Early - Fmt=%s, Seq=%d, Ts=%d, Clock=%d, DeltaInMS=%d, ClkRate=%d, DeltaInClkUnits=%d",
1515 iSinkFormatString.get_str(),
1516 iCurrentMediaMsg->getSeqNum(),
1517 aTimeStamp,
1518 clock_msec32,
1519 deltaInMS,
1520 iClockRate,
1521 aDelta));
1522 }
1523 else
1524 {
1525 aDelta = deltaInMS;
1526 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CheckMediaTimeStamp - Early - Fmt=%s, Seq=%d, Ts=%d, Clock=%d, Delta=%d",
1527 iSinkFormatString.get_str(),
1528 iCurrentMediaMsg->getSeqNum(),
1529 aTimeStamp,
1530 clock_msec32,
1531 aDelta));
1532 }
1533 iConsecutiveFramesDropped = 0;
1534 return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_EARLY;
1535 }
1536 else if ((ts_adjforlatemargin - clock_msec32) > WRAP_THRESHOLD)
1537 {
1538 // This condition indicates that the clock is ahead of the adjusted timestamp
1539 // Note that since the computation is based on 32-bit values, it has a limitation that
1540 // it will not work for durations exceeding 2^32 milliseconds = 49+ days which is an acceptable
1541 // limit for this application.
1542 // Say clock is 1000ms, late margin is 200ms, then any timestamp earlier than 800ms should be
1543 // dropped, as late. If ts is less than 800ms, then (ts + 200 - 1000) will be larger than wrap threshold
1544 aDelta = (clock_msec32 - aTimeStamp);
1545 iFramesDropped++;
1546 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CheckMediaTimeStamp - Late - Fmt=%s, Seq=%d, Ts=%d, Clock=%d, Delta=%d",
1547 iSinkFormatString.get_str(),
1548 iCurrentMediaMsg->getSeqNum(),
1549 aTimeStamp,
1550 clock_msec32,
1551 aDelta));
1552 iConsecutiveFramesDropped++;
1553 if (iMediaType == PVMF_MEDIA_UNCOMPRESSED_VIDEO)
1554 {
1555 if ((iConsecutiveFramesDropped >= THRESHOLD_FOR_DROPPED_VIDEO_FRAMES) && (iLateFrameEventSent == false))
1556 {
1557 iLateFrameEventSent = true;
1558 iNode->ReportInfoEvent(PVMFInfoVideoTrackFallingBehind, (OsclAny*)NULL);
1559 }
1560 }
1561 return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_LATE;
1562 }
1563 else
1564 {
1565 //ts falls in the interval (clock-latermargin, clock+earlymargin)
1566 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CheckMediaTimeStamp - OnTime - Fmt=%s, Seq=%d, Ts=%d, Clock=%d",
1567 iSinkFormatString.get_str(),
1568 iCurrentMediaMsg->getSeqNum(),
1569 aTimeStamp,
1570 clock_msec32));
1571 iConsecutiveFramesDropped = 0;
1572 return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ON_TIME;
1573 }
1574 }
1575 else
1576 {
1577
1578 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::CheckMediaTimeStamp - Fmt=%s, No PlayBack Clock!!!",
1579 iSinkFormatString.get_str()));
1580 OSCL_ASSERT(false);
1581 return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ERROR;
1582 }
1583 }
1584
1585 ////////////////////////////////////////////////////////////////////////////
1586 PVMFMediaOutputNodePortMediaTimeStatus
CheckMediaFrameStep()1587 PVMediaOutputNodePort::CheckMediaFrameStep()
1588 {
1589 if (iClock != NULL)
1590 {
1591 if (iClockFrameCount > iSyncFrameCount)
1592 {
1593 //this condition implies that clock count has
1594 //gone past the sync frame count, late frame, drop it
1595 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CheckMediaFrameStep - Late - Fmt=%s, Seq=%d, Ts=%d, iClockFrameCount=%d, iSyncFrameCount=%d",
1596 iSinkFormatString.get_str(),
1597 iCurrentMediaMsg->getSeqNum(),
1598 iCurrentMediaMsg->getTimestamp(),
1599 iClockFrameCount,
1600 iSyncFrameCount));
1601 iSyncFrameCount++;
1602 return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_LATE;
1603 }
1604 else if (iClockFrameCount < iSyncFrameCount)
1605 {
1606 //this condition implies that clock count is less than
1607 //the sync frame count, early frame, hold it
1608 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CheckMediaFrameStep - Early - Fmt=%s, Seq=%d, Ts=%d, iClockFrameCount=%d, iSyncFrameCount=%d",
1609 iSinkFormatString.get_str(),
1610 iCurrentMediaMsg->getSeqNum(),
1611 iCurrentMediaMsg->getTimestamp(),
1612 iClockFrameCount,
1613 iSyncFrameCount));
1614 return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_EARLY;
1615 }
1616 else
1617 {
1618 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CheckMediaFrameStep - OnTime - Fmt=%s, Seq=%d, Ts=%d, iClockFrameCount=%d, iSyncFrameCount=%d",
1619 iSinkFormatString.get_str(),
1620 iCurrentMediaMsg->getSeqNum(),
1621 iCurrentMediaMsg->getTimestamp(),
1622 iClockFrameCount,
1623 iSyncFrameCount));
1624 iSyncFrameCount++;
1625 return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ON_TIME;
1626 }
1627 }
1628 else
1629 {
1630
1631 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::CheckMediaTimeStamp - Fmt=%s, No PlayBack Clock!!!",
1632 iSinkFormatString.get_str()));
1633 OSCL_ASSERT(false);
1634 return PVMF_MEDIAOUTPUTNODEPORT_MEDIA_ERROR;
1635 }
1636 }
1637
1638 ////////////////////////////////////////////////////////////////////////////
Run()1639 void PVMediaOutputNodePort::Run()
1640 {
1641 /*
1642 * Media Output node inport does not process any more incoming messages
1643 * under following circumstances:
1644 * 1) Playback clock is NOT in RUNNING state
1645 * 2) Media output comp is in a STARTED state
1646 * 3) When waiting on media output comp to go ready from a busy state
1647 * Boolean "oProcessIncomingMessage" will be false if any of the above
1648 * conditions is true.
1649 * This while loop is intentional. This port doesnt do much in terms of
1650 * data processing. So we attempt to send as much data as we can in a
1651 * single Run call. Since we could process multiple media msgs per Run
1652 * we need to account for BOS and Skip as well.
1653 */
1654 while ((IncomingMsgQueueSize() > 0) || (iCurrentMediaMsg.GetRep() != NULL))
1655 {
1656 bool oMsgDqd = false;
1657 if (iCurrentMediaMsg.GetRep() == NULL)
1658 {
1659 //we are starting to process a new media msg
1660 iFragIndex = 0;
1661 if (DequeueIncomingMsg(iCurrentMediaMsg) != PVMFSuccess)
1662 {
1663 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::Run: DequeueIncomingMsg Failed - Fmt=%s",
1664 iSinkFormatString.get_str()));
1665 OSCL_ASSERT(0);
1666 }
1667 else
1668 {
1669 //this boolean avoids duplicate logs in case we are skipping data
1670 oMsgDqd = true;
1671 }
1672 }
1673 if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_BOS_FORMAT_ID)
1674 {
1675 uint32 msgStreamId = iCurrentMediaMsg->getStreamID();
1676 iBOSStreamIDVec.push_back(msgStreamId);
1677
1678 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::Run: BOS Recvd - Fmt=%s, TS=%d, StreamID=%d, Qs=%d",
1679 iSinkFormatString.get_str(),
1680 iCurrentMediaMsg->getTimestamp(),
1681 msgStreamId,
1682 IncomingMsgQueueSize()));
1683
1684 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::Run: BOS Recvd - Fmt=%s, TS=%d, StreamID=%d, Qs=%d",
1685 iSinkFormatString.get_str(),
1686 iCurrentMediaMsg->getTimestamp(),
1687 msgStreamId,
1688 IncomingMsgQueueSize()));
1689
1690 iNode->ReportBOS();
1691 iCurrentMediaMsg.Unbind();
1692 iFragIndex = 0;
1693 }
1694 else if (DataToSkip(iCurrentMediaMsg) == true)
1695 {
1696 //this condition implies that a skip timestamp has been set
1697 //and we are looking for a mediamsg whole timestamp is equal or greater than
1698 //iSkipTimestamp. All media msgs whose timestamps are less than iSkipTimestamp
1699 //will be dropped. There is no need for any additional checks. Just dequeue and toss
1700 if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID)
1701 {
1702 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::Run: EOSSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s",
1703 iCurrentMediaMsg->getStreamID(),
1704 iCurrentMediaMsg->getSeqNum(),
1705 iCurrentMediaMsg->getTimestamp(),
1706 iSinkFormatString.get_str()));
1707
1708 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::Run: EOSSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s",
1709 iCurrentMediaMsg->getStreamID(),
1710 iCurrentMediaMsg->getSeqNum(),
1711 iCurrentMediaMsg->getTimestamp(),
1712 iSinkFormatString.get_str()));
1713 }
1714 else
1715 {
1716 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::Run: MsgSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s",
1717 iCurrentMediaMsg->getStreamID(),
1718 iCurrentMediaMsg->getSeqNum(),
1719 iCurrentMediaMsg->getTimestamp(),
1720 iSinkFormatString.get_str()));
1721
1722 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::Run: MsgSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s",
1723 iCurrentMediaMsg->getStreamID(),
1724 iCurrentMediaMsg->getSeqNum(),
1725 iCurrentMediaMsg->getTimestamp(),
1726 iSinkFormatString.get_str()));
1727 }
1728
1729 iCurrentMediaMsg.Unbind();
1730 iFragIndex = 0;
1731 }
1732 else
1733 {
1734 //implies that this message needs to be consumed
1735 if (oMsgDqd == true)
1736 {
1737 //logging
1738 if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID)
1739 {
1740 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::Run - EOS Recvd - StreamID=%d, Seq=%d, TS=%d, Fmt=%s, Qs=%d",
1741 iCurrentMediaMsg->getStreamID(),
1742 iCurrentMediaMsg->getSeqNum(),
1743 iCurrentMediaMsg->getTimestamp(),
1744 iSinkFormatString.get_str(),
1745 IncomingMsgQueueSize()));
1746 }
1747 else if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_RE_CONFIG_FORMAT_ID)
1748 {
1749 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::Run - RECONFIG Recvd - Seq=%d, TS=%d, Fmt=%s, Qs=%d",
1750 iCurrentMediaMsg->getSeqNum(),
1751 iCurrentMediaMsg->getTimestamp(),
1752 iSinkFormatString.get_str(),
1753 IncomingMsgQueueSize()));
1754 }
1755 else if (iCurrentMediaMsg->getFormatID() < PVMF_MEDIA_CMD_FORMAT_IDS_START)
1756 {
1757 iTotalFrames++;
1758 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::Run - MediaMsg Recvd - Seq=%d, TS=%d, Fmt=%s, Qs=%d",
1759 iCurrentMediaMsg->getSeqNum(),
1760 iCurrentMediaMsg->getTimestamp(),
1761 iSinkFormatString.get_str(),
1762 IncomingMsgQueueSize()));
1763 }
1764 }
1765
1766 if ((iSendStartOfDataEvent == true) && oMIOComponentConfigured)
1767 {
1768 //implies that we are attempting to process the first media msg during
1769 //after skip, a mediamsg whose timestamp is equal to or greater than
1770 //iSkipTimestamp
1771 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::Run: PVMFInfoStartOfData - Fmt=%s",
1772 iSinkFormatString.get_str()));
1773 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::Run: PVMFInfoStartOfData - Fmt=%s",
1774 iSinkFormatString.get_str()));
1775 uint32 iStreamID = iRecentStreamID;
1776 iNode->ReportInfoEvent(PVMFInfoStartOfData, (OsclAny*)&iStreamID);
1777 iSendStartOfDataEvent = false;
1778 }
1779
1780 // We need to check for valid CurrentMediaMsg because it is possible that SendData has been
1781 // called from ClockStateUpdated when all tracks report InfoStartofData and Engine starts the clock
1782 // If dequeued data has already been sent, we cant send that data again, it will crash
1783 // so just return and AO will be scheduled again for next data.
1784 if ((oProcessIncomingMessage == true) && (iCurrentMediaMsg.GetRep() != NULL))
1785 {
1786 SendData();
1787 }
1788 else
1789 {
1790 //implies that we cannot send out any more data
1791 //no point continuing, just return
1792 //Do not reschedule here. We need to wait for
1793 //oProcessIncomingMessage to be true again
1794 return;
1795 }
1796 }
1797 }
1798 }
1799
1800
1801 ////////////////////////////////////////////////////////////////////////////
HandlePortActivity(const PVMFPortActivity & aActivity)1802 void PVMediaOutputNodePort::HandlePortActivity(const PVMFPortActivity& aActivity)
1803 //from PVMFPortActivityHandler. this port handles its own activity.
1804 {
1805 switch (aActivity.iType)
1806 {
1807 case PVMF_PORT_ACTIVITY_CREATED:
1808 iNode->ReportInfoEvent(PVMFInfoPortCreated, (OsclAny*)aActivity.iPort);
1809 break;
1810
1811 case PVMF_PORT_ACTIVITY_DELETED:
1812 iNode->ReportInfoEvent(PVMFInfoPortDeleted, (OsclAny*)aActivity.iPort);
1813 break;
1814
1815 case PVMF_PORT_ACTIVITY_CONNECT:
1816 iNode->ReportInfoEvent(PVMFInfoPortConnected, (OsclAny*)aActivity.iPort);
1817 break;
1818
1819 case PVMF_PORT_ACTIVITY_DISCONNECT:
1820 iNode->ReportInfoEvent(PVMFInfoPortDisconnected, (OsclAny*)aActivity.iPort);
1821 break;
1822
1823 case PVMF_PORT_ACTIVITY_INCOMING_MSG:
1824 if (IncomingMsgQueueSize() > 0)
1825 {
1826 PVMFSharedMediaMsgPtr peekMsgPtr;
1827 bool oBos = false;
1828 bool oMIOAlreadyConfigured = false;
1829 oMIOAlreadyConfigured = oMIOComponentConfigured;
1830 if (peekHead(peekMsgPtr, oBos))
1831 {
1832 /*
1833 * Media Output node inport does not process any more incoming messages
1834 * under following circumstances:
1835 * 1) Playback clock is NOT in RUNNING state
1836 * 2) Media output comp is in a STARTED state
1837 * 3) When waiting on media output comp to go ready from a busy state
1838 * Boolean "oProcessIncomingMessage" will be false if any of the above
1839 * conditions is true.
1840 * However BOS is an exception to all of these. BOS is not sent to media output comp,
1841 * nor should we worry about playback clock state or media output comp state while
1842 * processing BOS. When we get BOS we always send a notification to mediaoutput node
1843 * via the BOSObserver with BOS stream-id.
1844 */
1845 if (oBos)
1846 {
1847 if (DequeueIncomingMsg(iCurrentMediaMsg) == PVMFSuccess)
1848 {
1849 uint32 msgStreamId = peekMsgPtr->getStreamID();
1850 iBOSStreamIDVec.push_back(msgStreamId);
1851
1852 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::HPA: BOS Recvd - Fmt=%s, TS=%d, StreamID=%d, Qs=%d",
1853 iSinkFormatString.get_str(),
1854 peekMsgPtr->getTimestamp(),
1855 msgStreamId,
1856 IncomingMsgQueueSize()));
1857
1858 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA: BOS Recvd - Fmt=%s, TS=%d, StreamID=%d, Qs=%d",
1859 iSinkFormatString.get_str(),
1860 peekMsgPtr->getTimestamp(),
1861 msgStreamId,
1862 IncomingMsgQueueSize()));
1863
1864 iNode->ReportBOS();
1865
1866 iCurrentMediaMsg.Unbind();
1867 iFragIndex = 0;
1868 }
1869 else
1870 {
1871 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::HPA: DequeueIncomingMsg Failed - Fmt=%s",
1872 iSinkFormatString.get_str()));
1873 OSCL_ASSERT(false);
1874 }
1875 }
1876 else if (DataToSkip(peekMsgPtr) == true)
1877 {
1878 //this condition implies that a skip timestamp has been set
1879 //and we are looking for a mediamsg whole timestamp is equal or greater than
1880 //iSkipTimestamp. All media msgs whose timestamps are less than iSkipTimestamp
1881 //will be dropped. There is no need for any additional checks. Just dequeue and toss
1882 iCurrentMediaMsg.Unbind();
1883 iFragIndex = 0;
1884 if (DequeueIncomingMsg(iCurrentMediaMsg) == PVMFSuccess)
1885 {
1886 if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID)
1887 {
1888 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::HPA: EOSSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s",
1889 iCurrentMediaMsg->getStreamID(),
1890 iCurrentMediaMsg->getSeqNum(),
1891 iCurrentMediaMsg->getTimestamp(),
1892 iSinkFormatString.get_str()));
1893
1894 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA: EOSSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s",
1895 iCurrentMediaMsg->getStreamID(),
1896 iCurrentMediaMsg->getSeqNum(),
1897 iCurrentMediaMsg->getTimestamp(),
1898 iSinkFormatString.get_str()));
1899 }
1900 else
1901 {
1902 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::HPA: MsgSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s, Qs=%d",
1903 iCurrentMediaMsg->getStreamID(),
1904 iCurrentMediaMsg->getSeqNum(),
1905 iCurrentMediaMsg->getTimestamp(),
1906 iSinkFormatString.get_str(),
1907 IncomingMsgQueueSize()));
1908
1909 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA: MsgSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s, Qs=%d",
1910 iCurrentMediaMsg->getStreamID(),
1911 iCurrentMediaMsg->getSeqNum(),
1912 iCurrentMediaMsg->getTimestamp(),
1913 iSinkFormatString.get_str(),
1914 IncomingMsgQueueSize()));
1915 }
1916 iCurrentMediaMsg.Unbind();
1917 iFragIndex = 0;
1918 }
1919 else
1920 {
1921 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::HPA: DequeueIncomingMsg Failed - Fmt=%s",
1922 iSinkFormatString.get_str()));
1923 OSCL_ASSERT(false);
1924 }
1925 }
1926 else
1927 {
1928 if ((iSendStartOfDataEvent == true) && oMIOComponentConfigured)
1929 {
1930 //implies that we are attempting to process the first media msg during
1931 //after skip, a mediamsg whose timestamp is equal to or greater than
1932 //iSkipTimestamp
1933 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::HPA: PVMFInfoStartOfData - Fmt=%s",
1934 iSinkFormatString.get_str()));
1935 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA: PVMFInfoStartOfData - Fmt=%s",
1936 iSinkFormatString.get_str()));
1937 uint32 iStreamID = iRecentStreamID;
1938 iNode->ReportInfoEvent(PVMFInfoStartOfData, (OsclAny*)&iStreamID);
1939 iSendStartOfDataEvent = false;
1940 // Now check if the media msg is EOS notification OR media data.
1941 // If EOS then need to do writeComplete for EOS without sending it downstream
1942 // This will happen in cases where the media output node is waiting on configuration,
1943 // but for some reason the upstream node does not have a config to send.
1944 // (Think of cases where we have empty tracks in a presentation OR reposition to EndofClip just after Prepare).
1945 // In such cases, if we get EOS we want to notify the Engine with InfoEndofData for the track
1946 // so that Engine does not wait for EndOfData from the track and be in a hang state.
1947 if (peekMsgPtr->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID)
1948 {
1949 // There could be cases where MIO was already configured and then a reposition to End cmd
1950 // was given to Engine. In this case again EOS will be the first msg after skip but in this
1951 // case we want to send EOS downstream rather than sending InfoEndofData from here.
1952 if (!oMIOAlreadyConfigured)
1953 {
1954 // EOS is the first media msg received after Skip
1955 if (iCurrentMediaMsg.GetRep() != NULL)
1956 {
1957 // This should never happen. We cannot have a media msg being processed in this condition.
1958 // Just assert and return
1959 OSCL_ASSERT(false);
1960 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA: Processing previous msg iCurrentMediaMsg: 0x%x - Fmt=%s \
1961 when 1st media msg after skip is EOS, wrong, asserting",
1962 iCurrentMediaMsg.GetRep(), iSinkFormatString.get_str()));
1963 return;
1964 }
1965 // Dequeue the Incoming msg and send EndofData
1966 if (DequeueIncomingMsg(iCurrentMediaMsg) == PVMFSuccess)
1967 {
1968 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA - EOS Recvd - StreamID=%d, Seq=%d, TS=%d, Fmt=%s, Qs=%d",
1969 iCurrentMediaMsg->getStreamID(),
1970 iCurrentMediaMsg->getSeqNum(),
1971 iCurrentMediaMsg->getTimestamp(),
1972 iSinkFormatString.get_str(),
1973 IncomingMsgQueueSize()));
1974
1975 uint32 eosStreamId = iCurrentMediaMsg->getStreamID();
1976
1977 iNode->ReportInfoEvent(PVMFInfoEndOfData, (OsclAny*)&eosStreamId);
1978
1979 iCurrentMediaMsg.Unbind();
1980 iFragIndex = 0;
1981 }
1982 else
1983 {
1984 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::HPA: DequeueIncomingMsg Failed - Fmt=%s",
1985 iSinkFormatString.get_str()));
1986 OSCL_ASSERT(false);
1987 }
1988 return;
1989 }
1990 }
1991 }
1992 if (oProcessIncomingMessage)
1993 {
1994 //we are starting to process a new media msg
1995 if ((iCurrentMediaMsg.GetRep() != NULL) ||
1996 (iFragIndex != 0))
1997 {
1998 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA: DequeueIncomingMsg ignoring msg. Still processing previous msg iCurrentMediaMsg: 0x%x iFragIndex: %d- Fmt=%s",
1999 iCurrentMediaMsg.GetRep(), iFragIndex, iSinkFormatString.get_str()));
2000 return;
2001 }
2002 if (DequeueIncomingMsg(iCurrentMediaMsg) == PVMFSuccess)
2003 {
2004 if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID)
2005 {
2006 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA - EOS Recvd - StreamID=%d, Seq=%d, TS=%d, Fmt=%s, Qs=%d",
2007 iCurrentMediaMsg->getStreamID(),
2008 iCurrentMediaMsg->getSeqNum(),
2009 iCurrentMediaMsg->getTimestamp(),
2010 iSinkFormatString.get_str(),
2011 IncomingMsgQueueSize()));
2012 }
2013 else if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_RE_CONFIG_FORMAT_ID)
2014 {
2015 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA - RECONFIG Recvd - Seq=%d, TS=%d, Fmt=%s, Qs=%d",
2016 iCurrentMediaMsg->getSeqNum(),
2017 iCurrentMediaMsg->getTimestamp(),
2018 iSinkFormatString.get_str(),
2019 IncomingMsgQueueSize()));
2020 }
2021 else if (iCurrentMediaMsg->getFormatID() < PVMF_MEDIA_CMD_FORMAT_IDS_START)
2022 {
2023 iTotalFrames++;
2024 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::HPA - MediaMsg Recvd - Seq=%d, TS=%d, Fmt=%s, Qs=%d",
2025 iCurrentMediaMsg->getSeqNum(),
2026 iCurrentMediaMsg->getTimestamp(),
2027 iSinkFormatString.get_str(),
2028 IncomingMsgQueueSize()));
2029 }
2030
2031 SendData();
2032
2033
2034
2035 if ((oProcessIncomingMessage == true) &&
2036 (IncomingMsgQueueSize() > 0))
2037 {
2038 //implies that we can process more data, so reschedule
2039 //we could process all the messages in the incoming msg q
2040 //in a while loop here, but that might not be advisable
2041 //since this call is sort of an observer callback and
2042 //it might not be good idea to process more than one msg
2043 RunIfNotReady();
2044 }
2045 }
2046 else
2047 {
2048 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::HPA: DequeueIncomingMsg Failed - Fmt=%s",
2049 iSinkFormatString.get_str()));
2050 OSCL_ASSERT(false);
2051 }
2052 }
2053 }
2054 }
2055 }
2056 break;
2057
2058 default:
2059 break;
2060 }
2061 }
2062
2063
2064 ////////////////////////////////////////////////////////////////////////////
ConfigMIO(PvmiKvp * aParameters,PvmiKvp * & aRetParameters)2065 PVMFStatus PVMediaOutputNodePort::ConfigMIO(PvmiKvp* aParameters, PvmiKvp* &aRetParameters)
2066 //send config info to media I/O component.
2067 {
2068
2069 if (iMediaTransfer == NULL)
2070 {
2071 iMediaTransfer = iNode->iMIOControl->createMediaTransfer(iNode->iMIOSession);
2072 if (iMediaTransfer)
2073 {
2074 iMediaTransfer->setPeer(this);
2075 }
2076 else
2077 {
2078 return PVMFFailure;
2079 }
2080 }
2081
2082 if (0 == aParameters)
2083 {
2084 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO: No format-specific info for this track."));
2085 return PVMFSuccess;//no format-specific info, so nothing needed.
2086 }
2087 uint8* data = (uint8*)aParameters->value.key_specific_value;
2088 PVMFStatus status = PVMFFailure;
2089
2090 //formatted data gets sent to the MIO on first arrival
2091 switch (iMediaType)
2092 {
2093 case PVMF_MEDIA_UNCOMPRESSED_AUDIO:
2094 {
2095 //Send pcm16 info.
2096
2097 if (pv_mime_strcmp(aParameters->key, PVMF_FORMAT_SPECIFIC_INFO_KEY) == 0)
2098 {
2099 //ignore any failures since not all MIO may suppport the parameters.
2100 //Note: send the parameters individually since some MIO may not know
2101 //how to process arrays.
2102 channelSampleInfo* pcm16Info = (channelSampleInfo*)data;
2103 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO - SamplingRate=%d, NumChannels=%d",
2104 pcm16Info->samplingRate, pcm16Info->desiredChannels));
2105
2106 status = SetMIOParameterUint32((char*)MOUT_AUDIO_SAMPLING_RATE_KEY,
2107 pcm16Info->samplingRate);
2108 if (status == PVMFSuccess)
2109 {
2110 SetMIOParameterUint32((char*)MOUT_AUDIO_NUM_CHANNELS_KEY,
2111 pcm16Info->desiredChannels);
2112 }
2113 }
2114 else if (pv_mime_strcmp(aParameters->key, PVMF_FORMAT_SPECIFIC_INFO_KEY_PCM) == 0)
2115 {
2116 // this is
2117 //Do not send individual parameters to MIO component, send them all at once
2118
2119 int32 err;
2120 OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, aParameters, 1, aRetParameters););
2121
2122 if (err != OsclErrNone || aRetParameters)
2123 {
2124 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY_AUDIO failed "));
2125 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY_AUDIO failed "));
2126
2127 iNode->ReportErrorEvent(PVMFErrPortProcessing, NULL, PVMFMoutNodeErr_MediaIOSetParameterSync);
2128 return PVMFFailure;
2129 }
2130
2131 status = PVMFSuccess;
2132 }
2133 }
2134 break;
2135
2136 case PVMF_MEDIA_UNCOMPRESSED_VIDEO:
2137 {
2138 //Send yuv info.
2139 if (pv_mime_strcmp(aParameters->key, PVMF_FORMAT_SPECIFIC_INFO_KEY) == 0)
2140 {
2141 PVMFYuvFormatSpecificInfo0* yuvInfo = (PVMFYuvFormatSpecificInfo0*)data;
2142 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO - Width=%d, Height=%d, DispWidth=%d, DispHeight=%d",
2143 yuvInfo->width, yuvInfo->height, yuvInfo->display_width, yuvInfo->display_height));
2144 //Send yuv info.
2145 //ignore any failures since not all MIO may suppport the parameters.
2146 //Note: send the parameters individually since some MIO may not know
2147 //how to process arrays.
2148 status = SetMIOParameterUint32((char*)MOUT_VIDEO_WIDTH_KEY,
2149 yuvInfo->width);
2150 if (status == PVMFSuccess)
2151 {
2152 status = SetMIOParameterUint32((char*)MOUT_VIDEO_HEIGHT_KEY,
2153 yuvInfo->height);
2154 }
2155 if (status == PVMFSuccess)
2156 {
2157 status = SetMIOParameterUint32((char*)MOUT_VIDEO_DISPLAY_WIDTH_KEY,
2158 yuvInfo->display_width);
2159 }
2160 if (status == PVMFSuccess)
2161 {
2162 status = SetMIOParameterUint32((char*)MOUT_VIDEO_DISPLAY_HEIGHT_KEY,
2163 yuvInfo->display_height);
2164 }
2165 if (status == PVMFSuccess)
2166 {
2167 // ignore status here
2168 SetMIOParameterFormat((char*)MOUT_VIDEO_SUBFORMAT_KEY,
2169 yuvInfo->video_format);
2170 }
2171
2172
2173 }
2174 else if (pv_mime_strcmp(aParameters->key, PVMF_FORMAT_SPECIFIC_INFO_KEY_YUV) == 0)
2175 {
2176
2177 //Do not send individual parameters to MIO component, send them all at once
2178
2179 int32 err;
2180 OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, aParameters, 1, aRetParameters););
2181
2182 if (err != OsclErrNone || aRetParameters)
2183 {
2184 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY_VIDEO failed "));
2185 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY_VIDEO failed "));
2186
2187 iNode->ReportErrorEvent(PVMFErrPortProcessing, NULL, PVMFMoutNodeErr_MediaIOSetParameterSync);
2188 return PVMFFailure;
2189 }
2190
2191 status = PVMFSuccess;
2192 }
2193 }
2194 break;
2195 case PVMF_MEDIA_COMPRESSED_AUDIO:
2196 case PVMF_MEDIA_COMPRESSED_VIDEO:
2197 //for compressed formats, the format-specific info is sent as kvp
2198 {
2199 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO Setting Codec Header - Len=%d, Fmt=%s",
2200 aParameters->capacity, iSinkFormatString.get_str()));
2201
2202 // We will enable the following line after source node fix KVP issue
2203 //oscl_assert(aParameters->length == aParameters->capacity)
2204
2205 // We will remove the following line after source node fix KVP issue
2206 aParameters->length = aParameters->capacity;
2207
2208 int32 err;
2209 OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, aParameters, 1, aRetParameters););
2210
2211 if (err != OsclErrNone || aRetParameters)
2212 {
2213 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY failed "));
2214 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY failed "));
2215 //this is the first call, we don't handle a leave here-- it's an error
2216 iNode->ReportErrorEvent(PVMFErrPortProcessing, NULL, PVMFMoutNodeErr_MediaIOSetParameterSync);
2217 return PVMFFailure;
2218 }
2219 status = PVMFSuccess;
2220
2221 }
2222 break;
2223
2224 case PVMF_MEDIA_TEXT:
2225 //for text formats, the format-specific info is sent as kvp
2226 {
2227 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO Setting Codec Header - Len=%d, Fmt=%s",
2228 aParameters->capacity, iSinkFormatString.get_str()));
2229
2230 // We will enable the following line after source node fix KVP issue
2231 //oscl_assert(aParameters->length == aParameters->capacity)
2232
2233 // We will remove the following line after source node fix KVP issue
2234 aParameters->length = aParameters->capacity;
2235
2236 int32 err;
2237 OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, aParameters, 1, aRetParameters););
2238
2239 if (err != OsclErrNone || aRetParameters)
2240 {
2241 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY failed "));
2242 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ConfigMIO setParametersSync of PVMF_FORMAT_SPECIFIC_INFO_KEY failed "));
2243 //this is the first call, we don't handle a leave here-- it's an error
2244 iNode->ReportErrorEvent(PVMFErrPortProcessing, NULL, PVMFMoutNodeErr_MediaIOSetParameterSync);
2245 return PVMFFailure;
2246 }
2247 status = PVMFSuccess;
2248 }
2249 break;
2250
2251 default:
2252 status = PVMFErrNotSupported;
2253 OSCL_ASSERT(false);
2254 break;
2255 }
2256 if (status != PVMFSuccess)
2257 {
2258 iNode->ReportErrorEvent(PVMFErrResource, NULL, PVMFMoutNodeErr_MediaIOSetParameterSync);
2259 }
2260
2261 return status;
2262 }
2263
2264 ////////////////////////////////////////////////////////////////////////////
SetMIOParameterInt32(PvmiKeyType aKey,int32 aValue)2265 PVMFStatus PVMediaOutputNodePort::SetMIOParameterInt32(PvmiKeyType aKey, int32 aValue)
2266 //to set parameters to the MIO component through its config interface.
2267 {
2268 OsclMemAllocator alloc;
2269 PvmiKvp kvp;
2270 PvmiKvp* retKvp = NULL; // for return value
2271
2272 kvp.key = NULL;
2273 kvp.length = oscl_strlen(aKey) + 1; // +1 for \0
2274 kvp.capacity = kvp.length;
2275
2276 kvp.key = (PvmiKeyType)alloc.ALLOCATE(kvp.length);
2277 if (!kvp.key)
2278 return PVMFErrNoMemory;
2279
2280 oscl_strncpy(kvp.key, aKey, kvp.length);
2281 kvp.value.int32_value = aValue;
2282
2283 int32 err;
2284 OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, &kvp, 1, retKvp););
2285 alloc.deallocate(kvp.key);
2286
2287 if (err != OsclErrNone || retKvp)
2288 return PVMFFailure;
2289
2290 return PVMFSuccess;
2291 }
2292
2293 ////////////////////////////////////////////////////////////////////////////
SetMIOParameterUint32(PvmiKeyType aKey,uint32 aValue)2294 PVMFStatus PVMediaOutputNodePort::SetMIOParameterUint32(PvmiKeyType aKey, uint32 aValue)
2295 //to set parameters to the MIO component through its config interface.
2296 {
2297 OsclMemAllocator alloc;
2298 PvmiKvp kvp;
2299 PvmiKvp* retKvp = NULL; // for return value
2300
2301 kvp.key = NULL;
2302 kvp.length = oscl_strlen(aKey) + 1; // +1 for \0
2303 kvp.capacity = kvp.length;
2304
2305 kvp.key = (PvmiKeyType)alloc.ALLOCATE(kvp.length);
2306 if (!kvp.key)
2307 return PVMFErrNoMemory;
2308
2309 oscl_strncpy(kvp.key, aKey, kvp.length);
2310 kvp.value.uint32_value = aValue;
2311
2312 int32 err;
2313 OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, &kvp, 1, retKvp););
2314 alloc.deallocate(kvp.key);
2315
2316 if (err != OsclErrNone || retKvp)
2317 return PVMFFailure;
2318
2319 return PVMFSuccess;
2320 }
2321
2322
2323 ////////////////////////////////////////////////////////////////////////////
SetMIOParameterPchar(PvmiKeyType aKey,char * aValue)2324 PVMFStatus PVMediaOutputNodePort::SetMIOParameterPchar(PvmiKeyType aKey, char* aValue)
2325 //to set parameters to the MIO component through its config interface.
2326 {
2327 OsclMemAllocator alloc;
2328 PvmiKvp kvp;
2329 PvmiKvp* retKvp = NULL; // for return value
2330
2331 kvp.key = NULL;
2332 kvp.length = oscl_strlen(aKey) + 1; // +1 for \0
2333 kvp.capacity = kvp.length;
2334
2335 kvp.key = (PvmiKeyType)alloc.ALLOCATE(kvp.length);
2336 if (!kvp.key)
2337 return PVMFErrNoMemory;
2338
2339 oscl_strncpy(kvp.key, aKey, kvp.length);
2340 kvp.value.pChar_value = aValue;
2341
2342 int32 err;
2343 OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, &kvp, 1, retKvp););
2344 alloc.deallocate(kvp.key);
2345
2346 if (err != OsclErrNone || retKvp)
2347 return PVMFFailure;
2348
2349 return PVMFSuccess;
2350 }
2351
2352 ////////////////////////////////////////////////////////////////////////////
SetMIOParameterFormat(PvmiKeyType aKey,PVMFFormatType aFormatType)2353 PVMFStatus PVMediaOutputNodePort::SetMIOParameterFormat(PvmiKeyType aKey, PVMFFormatType aFormatType)
2354 //to set parameters to the MIO component through its config interface.
2355 {
2356 OsclMemAllocator alloc;
2357 PvmiKvp kvp;
2358 PvmiKvp* retKvp = NULL; // for return value
2359
2360 kvp.key = NULL;
2361 kvp.length = oscl_strlen(aKey) + 1; // +1 for \0
2362 kvp.capacity = kvp.length;
2363
2364 kvp.key = (PvmiKeyType)alloc.ALLOCATE(kvp.length);
2365 if (!kvp.key)
2366 return PVMFErrNoMemory;
2367
2368 oscl_strncpy(kvp.key, aKey, kvp.length);
2369 kvp.value.pChar_value = (char*)aFormatType.getMIMEStrPtr();
2370
2371 int32 err;
2372 OSCL_TRY(err, iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, &kvp, 1, retKvp););
2373 alloc.deallocate(kvp.key);
2374
2375 if (err != OsclErrNone || retKvp)
2376 return PVMFFailure;
2377
2378 return PVMFSuccess;
2379 }
2380
2381 ////////////////////////////////////////////////////////////////////////////
getParametersSync(PvmiMIOSession aSession,PvmiKeyType aIdentifier,PvmiKvp * & aParameters,int & num_parameter_elements,PvmiCapabilityContext aContext)2382 OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::getParametersSync(PvmiMIOSession aSession, PvmiKeyType aIdentifier,
2383 PvmiKvp*& aParameters, int& num_parameter_elements,
2384 PvmiCapabilityContext aContext)
2385 {
2386 PVMFStatus status = iNode->iMIOConfig->getParametersSync(aSession, aIdentifier, aParameters, num_parameter_elements,
2387 aContext);
2388 return status;
2389 }
2390
2391
2392 ////////////////////////////////////////////////////////////////////////////
releaseParameters(PvmiMIOSession aSession,PvmiKvp * aParameters,int num_elements)2393 OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::releaseParameters(PvmiMIOSession aSession, PvmiKvp* aParameters, int num_elements)
2394 {
2395 OSCL_UNUSED_ARG(aSession);
2396
2397 if (aParameters && iNode)
2398 {
2399 return iNode->iMIOConfig->releaseParameters(aSession, aParameters, num_elements);
2400 }
2401 return PVMFFailure;
2402 }
2403
2404
2405 ////////////////////////////////////////////////////////////////////////////
setParametersSync(PvmiMIOSession aSession,PvmiKvp * aParameters,int num_elements,PvmiKvp * & aRet_kvp)2406 OSCL_EXPORT_REF void PVMediaOutputNodePort::setParametersSync(PvmiMIOSession aSession,
2407 PvmiKvp* aParameters,
2408 int num_elements,
2409 PvmiKvp * &aRet_kvp)
2410 {
2411 PVMFStatus status = PVMFSuccess;
2412 OSCL_UNUSED_ARG(aSession);
2413 for (int32 i = 0; i < num_elements; i++)
2414 {
2415 if (pv_mime_strcmp(aParameters[i].key, PVMF_FORMAT_SPECIFIC_INFO_KEY) == 0)
2416 {
2417 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::setParametersSync - FSI - Fmt=%s",
2418 iSinkFormatString.get_str()));
2419 ConfigMIO(&aParameters[i], aRet_kvp);
2420 }
2421 else if (pv_mime_strcmp(aParameters[i].key, PVMF_FORMAT_SPECIFIC_INFO_KEY_YUV) == 0)
2422 {
2423 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::setParametersSync - FSI - Fmt=%s",
2424 iSinkFormatString.get_str()));
2425 status = ConfigMIO(&aParameters[i], aRet_kvp);
2426 if (status != PVMFSuccess)
2427 OSCL_LEAVE(PVMFFailure);
2428 }
2429 else if (pv_mime_strcmp(aParameters[i].key, PVMF_FORMAT_SPECIFIC_INFO_KEY_PCM) == 0)
2430 {
2431 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::setParametersSync - FSI - Fmt=%s",
2432 iSinkFormatString.get_str()));
2433 status = ConfigMIO(&aParameters[i], aRet_kvp);
2434 if (status != PVMFSuccess)
2435 OSCL_LEAVE(PVMFFailure);
2436 }
2437 else if ((pv_mime_strcmp(aParameters[i].key, MOUT_AUDIO_SAMPLING_RATE_KEY) == 0) ||
2438 (pv_mime_strcmp(aParameters[i].key, MOUT_AUDIO_NUM_CHANNELS_KEY) == 0) ||
2439 (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_WIDTH_KEY) == 0) ||
2440 (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_HEIGHT_KEY) == 0) ||
2441 (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_DISPLAY_WIDTH_KEY) == 0) ||
2442 (pv_mime_strcmp(aParameters[i].key, MOUT_VIDEO_DISPLAY_HEIGHT_KEY) == 0))
2443 {
2444 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::setParametersSync - FSI - Fmt=%s",
2445 iSinkFormatString.get_str()));
2446 //Null parameters, because we just notify that MIO has been configured.
2447 ConfigMIO(0, aRet_kvp);
2448 iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, &aParameters[i], 1, aRet_kvp);
2449 }
2450 else
2451 iNode->iMIOConfig->setParametersSync(iNode->iMIOSession, &aParameters[i], 1, aRet_kvp);
2452 }
2453 }
2454
2455
2456 ////////////////////////////////////////////////////////////////////////////
verifyParametersSync(PvmiMIOSession aSession,PvmiKvp * aParameters,int num_elements)2457 OSCL_EXPORT_REF PVMFStatus PVMediaOutputNodePort::verifyParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters, int num_elements)
2458 {
2459 OSCL_UNUSED_ARG(aSession);
2460 return (iNode->iMIOConfig->verifyParametersSync(iNode->iMIOSession, aParameters, num_elements));
2461 }
2462
2463
2464 ////////////////////////////////////////////////////////////////////////////
peekHead(PVMFSharedMediaMsgPtr & aMsgPtr,bool & bBos)2465 bool PVMediaOutputNodePort::peekHead(PVMFSharedMediaMsgPtr& aMsgPtr,
2466 bool& bBos)
2467 {
2468 if (iIncomingQueue.iQ.empty())
2469 {
2470 return false;
2471 }
2472 // get a pointer to the queue head
2473 aMsgPtr = iIncomingQueue.iQ.front();
2474 // check the format id first - treat BOS special
2475 if (aMsgPtr->getFormatID() == PVMF_MEDIA_CMD_BOS_FORMAT_ID)
2476 {
2477 bBos = true;
2478 }
2479 else
2480 {
2481 bBos = false;
2482 }
2483
2484 // This check is needed to handle cases where the media output node is waiting on configuration,
2485 // but for some reason the upstream node does not have a config to send.
2486 // (Think of cases where we have empty tracks in a presentation). In such cases, if we get EOS we want
2487 // to notify the media output node that configuration is complete, so that media output node can complete its pending start
2488 if (aMsgPtr->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID)
2489 {
2490 if (false == oMIOComponentConfigured)
2491 {
2492 OSCL_ASSERT(oProcessIncomingMessage != true);
2493 oMIOComponentConfigured = true;
2494 oProcessIncomingMessage = true;
2495 }
2496 }
2497 return true;
2498 }
2499
ProcessCallBack(uint32 callBackID,PVTimeComparisonUtils::MediaTimeStatus aTimerAccuracy,uint32 aDelta,const OsclAny * aContextData,PVMFStatus aStatus)2500 void PVMediaOutputNodePort::ProcessCallBack(uint32 callBackID,
2501 PVTimeComparisonUtils::MediaTimeStatus aTimerAccuracy,
2502 uint32 aDelta,
2503 const OsclAny* aContextData,
2504 PVMFStatus aStatus)
2505 {
2506 OSCL_UNUSED_ARG(aTimerAccuracy);
2507 OSCL_UNUSED_ARG(aDelta);
2508 OSCL_UNUSED_ARG(aContextData);
2509 PVMF_MOPORT_LOGDEBUG((0, "PVMediaOutputNodePort::ProcessCallBack In Callback id [%d] CallbackStatus [%d]", callBackID, aStatus));
2510 if (PVMFSuccess == aStatus)
2511 {
2512 if (iDelayEarlyFrameCallBkId == callBackID)
2513 {
2514 oClockCallBackPending = false;
2515 //timer expires, reset the boolean so that we can start processing more data if need be
2516 oProcessIncomingMessage = true;
2517 if (iCurrentMediaMsg.GetRep() != NULL)
2518 {
2519 //attempt to send data current media msg if any
2520 SendData();
2521 }
2522 //reschedule if there is more stuff waiting and
2523 //if we can process more data
2524 if ((oProcessIncomingMessage == true) &&
2525 (IncomingMsgQueueSize() > 0))
2526 {
2527 RunIfNotReady();
2528 }
2529 }
2530 else
2531 {
2532 PVMF_MOPORT_LOGERROR((0, "PVMediaOutputNodePort::ProcessCallBack- Error stray callback from iClockNotificationsInf callBackID[%d]", callBackID));
2533 OSCL_ASSERT(false);
2534 }
2535
2536 }
2537 }
2538
SetSkipTimeStamp(uint32 aSkipTS,uint32 aStreamID)2539 void PVMediaOutputNodePort::SetSkipTimeStamp(uint32 aSkipTS,
2540 uint32 aStreamID)
2541 {
2542 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::SetSkipTimeStamp: TS=%d, Fmt=%s",
2543 aSkipTS,
2544 iSinkFormatString.get_str()));
2545 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SetSkipTimeStamp: TS=%d, Fmt=%s",
2546 aSkipTS,
2547 iSinkFormatString.get_str()));
2548 iSkipTimestamp = aSkipTS;
2549 iRecentStreamID = aStreamID;
2550 iSendStartOfDataEvent = true;
2551 if (oClockCallBackPending)
2552 {
2553 iClockNotificationsInf->CancelCallback(iDelayEarlyFrameCallBkId, false);
2554 }
2555 oClockCallBackPending = false;
2556 iDelayEarlyFrameCallBkId = 0;
2557
2558 //release the current media msg right here instead of
2559 //waiting on a reschedule. this is to avoid deadlocks
2560 //in case the upstream node is just operating with a
2561 //single media msg
2562 if (iCurrentMediaMsg.GetRep() != NULL)
2563 {
2564 if (DataToSkip(iCurrentMediaMsg) == true)
2565 {
2566 if (iCurrentMediaMsg->getFormatID() == PVMF_MEDIA_CMD_EOS_FORMAT_ID)
2567 {
2568 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::SetSkipTimeStamp: EOSSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s",
2569 iCurrentMediaMsg->getStreamID(),
2570 iCurrentMediaMsg->getSeqNum(),
2571 iCurrentMediaMsg->getTimestamp(),
2572 iSinkFormatString.get_str()));
2573
2574 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SetSkipTimeStamp: EOSSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s",
2575 iCurrentMediaMsg->getStreamID(),
2576 iCurrentMediaMsg->getSeqNum(),
2577 iCurrentMediaMsg->getTimestamp(),
2578 iSinkFormatString.get_str()));
2579 }
2580 else
2581 {
2582 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::SetSkipTimeStamp: MsgSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s",
2583 iCurrentMediaMsg->getStreamID(),
2584 iCurrentMediaMsg->getSeqNum(),
2585 iCurrentMediaMsg->getTimestamp(),
2586 iSinkFormatString.get_str()));
2587
2588 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::SetSkipTimeStamp: MsgSkip - StreamId=%d, Seq=%d, TS=%d, Fmt=%s",
2589 iCurrentMediaMsg->getStreamID(),
2590 iCurrentMediaMsg->getSeqNum(),
2591 iCurrentMediaMsg->getTimestamp(),
2592 iSinkFormatString.get_str()));
2593 }
2594 iCurrentMediaMsg.Unbind();
2595 iFragIndex = 0;
2596 }
2597 }
2598 //wake up the AO to start processing messages
2599 RunIfNotReady();
2600 }
2601
CancelSkip()2602 void PVMediaOutputNodePort::CancelSkip()
2603 {
2604 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::CancelSkip: Fmt=%s",
2605 iSinkFormatString.get_str()));
2606 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::CancelSkip: Fmt=%s",
2607 iSinkFormatString.get_str()));
2608 iSkipTimestamp = 0;
2609 iRecentStreamID = 0;
2610 iSendStartOfDataEvent = false;
2611 }
2612
DataToSkip(PVMFSharedMediaMsgPtr & aMsg)2613 bool PVMediaOutputNodePort::DataToSkip(PVMFSharedMediaMsgPtr& aMsg)
2614 {
2615 //iRecentStreamID reflects the latest stream
2616 //that is being played. Msg with a streamid less than
2617 //iRecentStreamID belongs to an older stream and should
2618 //be skipped. Do not skip Msg that belong to the current
2619 //stream or a future stream (future being the case where
2620 //msg arrives before a skip request. Pls note that we
2621 //assume that the stream ids are a montonically increasing
2622 //sequence
2623 uint32 delta = 0;
2624 bool oOldStream = PVTimeComparisonUtils::IsEarlier(aMsg->getStreamID(), iRecentStreamID, delta);
2625 if (oOldStream && delta > 0)
2626 {
2627 //a zero delta could mean the stream ids are equal
2628 return true;
2629 }
2630 //we typically do not do timestamp checks on EOS.
2631 //old EOSes that needed to be discarded during a repositioning
2632 //would not pass the stream id check above. If we get this far
2633 //it means that the EOS belong to the current stream id and its
2634 //timestamp does not really matter.
2635 if (aMsg->getFormatID() != PVMF_MEDIA_CMD_EOS_FORMAT_ID)
2636 {
2637 //if we get here it means that the msg belong to current or a
2638 //future media stream. check against skip timestamp if we are
2639 //required to send PVMFInfoStartOfData. If we are not reqd to
2640 //send the event, we intentionally by pass any timestamp checks
2641 if (iSendStartOfDataEvent == true)
2642 {
2643 delta = 0;
2644 bool tsEarly = PVTimeComparisonUtils::IsEarlier(aMsg->getTimestamp(), iSkipTimestamp, delta);
2645 if (tsEarly && delta > 0)
2646 {
2647 //a zero delta could mean the timestamps are equal
2648 return true;
2649 }
2650 }
2651 }
2652 return false;
2653 }
2654
ClockTimebaseUpdated()2655 void PVMediaOutputNodePort::ClockTimebaseUpdated()
2656 {
2657 if (iClock == NULL)
2658 return;
2659
2660 if (iClock->GetCountTimebase())
2661 {
2662 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::ClockTimebaseUpdated: CountTimeBase Added - Fmt=%s",
2663 iSinkFormatString.get_str()));
2664 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ClockTimebaseUpdated: CountTimeBase Added - Fmt=%s",
2665 iSinkFormatString.get_str()));
2666 //Reset the frame step delta to zero.
2667 iFrameStepMode = true;
2668 iClock->GetCountTimebase()->GetCount(iClockFrameCount);
2669 iSyncFrameCount = iClockFrameCount;
2670 }
2671 else
2672 {
2673 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::ClockTimebaseUpdated: CountTimeBase Removed - Fmt=%s",
2674 iSinkFormatString.get_str()));
2675 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ClockTimebaseUpdated: CountTimeBase Removed - Fmt=%s",
2676 iSinkFormatString.get_str()));
2677 //reset frame step variables.
2678 iFrameStepMode = false;
2679 iSyncFrameCount = 0;
2680 iClockFrameCount = 0;
2681 }
2682 if (oClockCallBackPending)
2683 {
2684 iClockNotificationsInf->CancelCallback(iDelayEarlyFrameCallBkId, false);
2685 }
2686 oClockCallBackPending = false;
2687 iDelayEarlyFrameCallBkId = 0;
2688
2689 //reschedule if there is more stuff waiting and
2690 //if we can process more data
2691 if ((oProcessIncomingMessage == true) &&
2692 (IncomingMsgQueueSize() > 0))
2693 {
2694 RunIfNotReady();
2695 }
2696 }
2697
ClockCountUpdated()2698 void PVMediaOutputNodePort::ClockCountUpdated()
2699 {
2700 if (iClock && iClock->GetCountTimebase())
2701 {
2702 //read the new framecount
2703 iClock->GetCountTimebase()->GetCount(iClockFrameCount);
2704 //wake up the AO to process data
2705 oProcessIncomingMessage = true;
2706
2707 if (iCurrentMediaMsg.GetRep() != NULL)
2708 {
2709 //attempt to send data current media msg if any
2710 SendData();
2711 }
2712 //reschedule if there is more stuff waiting and
2713 //if we can process more data
2714 if ((oProcessIncomingMessage == true) &&
2715 (IncomingMsgQueueSize() > 0))
2716 {
2717 RunIfNotReady();
2718 }
2719 }
2720 }
2721
ClockAdjusted()2722 void PVMediaOutputNodePort::ClockAdjusted()
2723 {
2724 }
2725
NotificationsInterfaceDestroyed()2726 void PVMediaOutputNodePort::NotificationsInterfaceDestroyed()
2727 {
2728 iClockNotificationsInf = NULL;
2729 }
2730
ClockStateUpdated()2731 void PVMediaOutputNodePort::ClockStateUpdated()
2732 {
2733 if (iClock == NULL)
2734 return;
2735
2736 if (iClock->GetState() == PVMFMediaClock::PAUSED)
2737 {
2738 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::ClockStateUpdated: Clock Paused - Fmt=%s",
2739 iSinkFormatString.get_str()));
2740 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ClockStateUpdated: Clock Paused - Fmt=%s",
2741 iSinkFormatString.get_str()));
2742 //stop processing input msgs only for passive mediaoutput comps
2743 //for active ones continue to send, since the mediaoutput comp
2744 //is responsible for pacing of the data
2745 if (oActiveMediaOutputComp == false)
2746 {
2747 oProcessIncomingMessage = false;
2748 if (oClockCallBackPending)
2749 {
2750 iClockNotificationsInf->CancelCallback(iDelayEarlyFrameCallBkId, false);
2751 }
2752 oClockCallBackPending = false;
2753 iDelayEarlyFrameCallBkId = 0;
2754 }
2755 }
2756 else if (iClock->GetState() == PVMFMediaClock::RUNNING)
2757 {
2758 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::ClockStateUpdated: Clock Running - Fmt=%s",
2759 iSinkFormatString.get_str()));
2760 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ClockStateUpdated: Clock Running - Fmt=%s",
2761 iSinkFormatString.get_str()));
2762
2763 //If MIO component is configured, messages can be processed now.
2764 if (oMIOComponentConfigured)
2765 {
2766 oProcessIncomingMessage = true;
2767 }
2768
2769 if (oClockCallBackPending)
2770 {
2771 iClockNotificationsInf->CancelCallback(iDelayEarlyFrameCallBkId, false);
2772 }
2773 oClockCallBackPending = false;
2774 iDelayEarlyFrameCallBkId = 0;
2775
2776
2777 //reset write state as well, in case mo comp is still busy
2778 //it will leave again, so that state will get reset
2779 iWriteState = EWriteOK;
2780
2781 if (iCurrentMediaMsg.GetRep() != NULL)
2782 {
2783 //attempt to send data current media msg if any
2784 SendData();
2785 }
2786
2787 //reschedule if there is more stuff waiting and
2788 //if we can process more data
2789 if ((oProcessIncomingMessage == true) &&
2790 (IncomingMsgQueueSize() > 0))
2791 {
2792 RunIfNotReady();
2793 }
2794 }
2795 else if (iClock->GetState() == PVMFMediaClock::STOPPED)
2796 {
2797 PVMF_MOPORT_LOGREPOS((0, "PVMediaOutputNodePort::ClockStateUpdated: Clock Stopped - Fmt=%s",
2798 iSinkFormatString.get_str()));
2799 PVMF_MOPORT_LOGDATAPATH((0, "PVMediaOutputNodePort::ClockStateUpdated: Clock Stopped - Fmt=%s",
2800 iSinkFormatString.get_str()));
2801 //stop processing input msgs only for passive mediaoutput comps
2802 //for active ones continue to send, since the mediaoutput comp
2803 //is responsible for pacing of the data, this is to account for a case when clock is stopped
2804 //after repositioning.
2805 if (oActiveMediaOutputComp == false)
2806 {
2807 oProcessIncomingMessage = false;
2808 if (oClockCallBackPending)
2809 {
2810 iClockNotificationsInf->CancelCallback(iDelayEarlyFrameCallBkId, false);
2811 }
2812 oClockCallBackPending = false;
2813 iDelayEarlyFrameCallBkId = 0;
2814 }
2815 }
2816 RunIfNotReady();
2817 }
2818
ClearPreviousBOSStreamIDs(uint32 aID)2819 void PVMediaOutputNodePort::ClearPreviousBOSStreamIDs(uint32 aID)
2820 {
2821 //Pls note that we
2822 //assume that the stream ids are a montonically increasing
2823 //sequence
2824 Oscl_Vector<uint32, OsclMemAllocator>::iterator it;
2825 it = iBOSStreamIDVec.begin();
2826 while (it != iBOSStreamIDVec.end())
2827 {
2828 // iBOSStreamIDVec will contain the stream ID of the current stream being Played. On each skip call
2829 // all the previous streamid's will be removed from the vector leaving the current stream id. The
2830 // current stream id will be erased in the next skip media data call.
2831 if (*it < aID)
2832 {
2833 it = iBOSStreamIDVec.erase(it);
2834 }
2835 else
2836 {
2837 it++;
2838 }
2839 }
2840 }
2841
WriteDataToMIO(int32 & aCmdId,PvmiMediaXferHeader & aMediaxferhdr,OsclRefCounterMemFrag & aFrag)2842 int32 PVMediaOutputNodePort::WriteDataToMIO(int32 &aCmdId, PvmiMediaXferHeader &aMediaxferhdr, OsclRefCounterMemFrag &aFrag)
2843 {
2844 int32 leavecode = OsclErrNone;
2845 OSCL_TRY_NO_TLS(iOsclErrorTrapImp, leavecode,
2846 aCmdId = iMediaTransfer->writeAsync(PVMI_MEDIAXFER_FMT_TYPE_DATA, /*format_type*/
2847 PVMI_MEDIAXFER_FMT_INDEX_DATA, /*format_index*/
2848 (uint8*)aFrag.getMemFragPtr(),
2849 aFrag.getMemFragSize(),
2850 aMediaxferhdr,
2851 (OsclAny*) & iWriteAsyncContext););
2852 return leavecode;
2853 }
2854