blob: aa9a6814b307217ba102ff0ed60260da0c89b407 [file] [log] [blame]
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#include "pvmf_aacffparser_node.h"
#include "pvmf_aacffparser_outport.h"
#include "aacfileparser.h"
#include "media_clock_converter.h"
#include "pv_gau.h"
#include "pvlogger.h"
#include "oscl_error_codes.h"
#include "pvmf_fileformat_events.h"
#include "pvmf_basic_errorinfomessage.h"
#include "pvmf_errorinfomessage_extension.h"
#include "pvmf_media_cmd.h"
#include "pvmf_media_msg_format_ids.h"
#include "pv_mime_string_utils.h"
#include "pvmf_local_data_source.h"
#include "oscl_utf8conv.h"
#include "pvmi_kvp_util.h"
#include "oscl_exclusive_ptr.h"
#include "oscl_int64_utils.h"
#include "aacfileparser.h"
#include "pvmf_source_context_data.h"
#define PVAACFF_MEDIADATA_POOLNUM 8
#define PVAACFF_MEDIADATA_CHUNKSIZE 128
PVMFAACFFParserNode::PVMFAACFFParserNode(int32 aPriority)
: OsclTimerObject(aPriority, "PVMFAACFFParserNode")
{
iOutPort = NULL;
iCurrentCmdId = 0;
iAACParser = NULL;
iUseCPMPluginRegistry = false;
iFileHandle = NULL;
iLogger = NULL;
iExtensionRefCount = 0;
iFirstFrame = true;
iDataPathLogger = NULL;
iClockLogger = NULL;
iClientClock = NULL;
iCPM = NULL;
iCPMSessionID = 0xFFFFFFFF;
iCPMContentType = PVMF_CPM_CONTENT_FORMAT_UNKNOWN;
iCPMContentAccessFactory = NULL;
iCPMInitCmdId = 0;
iCPMOpenSessionCmdId = 0;
iCPMRegisterContentCmdId = 0;
iCPMRequestUsageId = 0;
iCPMUsageCompleteCmdId = 0;
iCPMCloseSessionCmdId = 0;
iCPMResetCmdId = 0;
iRequestedUsage.key = NULL;
iApprovedUsage.key = NULL;
iAuthorizationDataKvp.key = NULL;
iPreviewMode = false;
oSourceIsCurrent = false;
iPortDataLog = false;
iCPMMetaDataExtensionInterface = NULL;
iCPMGetMetaDataKeysCmdId = 0;
iCPMGetMetaDataValuesCmdId = 0;
iCPMGetLicenseInterfaceCmdId = 0;
iCPMGetLicenseCmdId = 0;
iCPMCancelGetLicenseCmdId = 0;
iAACParserNodeMetadataValueCount = 0;
iGenreIndex = 0;
iLyricsIndex = 0;
iDownloadProgressInterface = NULL;
iDownloadFileSize = 0;
iAACHeaderSize = 0;
iDataStreamInterface = NULL;
iDataStreamReadCapacityObserver = NULL;
iDataStreamFactory = NULL;
iAutoPaused = false;
iStreamID = 0;
int32 err;
OSCL_TRY(err, ConstructL());
if (err != OsclErrNone)
{
//if a leave happened, cleanup and re-throw the error
iInputCommands.clear();
iCurrentCommand.clear();
iCancelCommand.clear();
iCapability.iInputFormatCapability.clear();
iCapability.iOutputFormatCapability.clear();
OSCL_CLEANUP_BASE_CLASS(PVMFNodeInterface);
OSCL_CLEANUP_BASE_CLASS(OsclTimerObject);
OSCL_LEAVE(err);
}
iFileServer.Connect();
iInterfaceState = EPVMFNodeCreated;
}
void PVMFAACFFParserNode::ConstructL()
{
//Create the input command queue. Use a reserve to avoid lots of
//dynamic memory allocation.
iInputCommands.Construct(1, 5);
//Create the "current command" queue. It will only contain one
//command at a time, so use a reserve of 1.
iCurrentCommand.Construct(0, 1);
iCancelCommand.Construct(0, 1);
//Create the port vector.
//iPortVector.Construct(PVMF_SAMPLE_NODE_PORT_VECTOR_RESERVE);
//Set the node capability data.
//This node can support an unlimited number of ports.
iCapability.iCanSupportMultipleInputPorts = false;
iCapability.iCanSupportMultipleOutputPorts = false;
iCapability.iHasMaxNumberOfPorts = true;
iCapability.iMaxNumberOfPorts = 2;//no maximum
iCapability.iInputFormatCapability.push_back(PVMFFormatType(PVMF_MIME_AACFF));
iCapability.iOutputFormatCapability.push_back(PVMFFormatType(PVMF_MIME_MPEG4_AUDIO));
iAvailableMetadataKeys.reserve(PVMF_AAC_NUM_METADATA_VALUES);
iAvailableMetadataKeys.clear();
}
PVMFAACFFParserNode::~PVMFAACFFParserNode()
{
Cancel();
if (iCPM != NULL)
{
iCPM->ThreadLogoff();
PVMFCPMFactory::DestroyContentPolicyManager(iCPM);
iCPM = NULL;
}
if (IsAdded())
{
RemoveFromScheduler();
}
//Cleanup commands
//The command queues are self-deleting, but we want to
//notify the observer of unprocessed commands.
while (!iCurrentCommand.empty())
{
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFFailure);
}
while (!iCancelCommand.empty())
{
CommandComplete(iCancelCommand, iCancelCommand.front(), PVMFFailure);
}
while (!iInputCommands.empty())
{
CommandComplete(iInputCommands, iInputCommands.front(), PVMFFailure);
}
//Cleanup allocated ports
ReleaseTrack();
CleanupFileSource();
iFileServer.Close();
if (iRequestedUsage.key)
{
OSCL_ARRAY_DELETE(iRequestedUsage.key);
iRequestedUsage.key = NULL;
}
if (iApprovedUsage.key)
{
OSCL_ARRAY_DELETE(iApprovedUsage.key);
iApprovedUsage.key = NULL;
}
if (iAuthorizationDataKvp.key)
{
OSCL_ARRAY_DELETE(iAuthorizationDataKvp.key);
iAuthorizationDataKvp.key = NULL;
}
if (iFileHandle != NULL)
{
OSCL_ARRAY_DELETE(iFileHandle);
iFileHandle = NULL;
}
if (iDownloadProgressInterface != NULL)
{
iDownloadProgressInterface->cancelResumeNotification();
iDownloadProgressInterface->removeRef();
}
}
PVMFStatus PVMFAACFFParserNode::ThreadLogon()
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::ThreadLogon() Called"));
if (iInterfaceState == EPVMFNodeCreated)
{
if (!IsAdded())
{
AddToScheduler();
}
iLogger = PVLogger::GetLoggerObject("PVMFAACParserNode");
iDataPathLogger = PVLogger::GetLoggerObject("datapath.sourcenode.aacparsernode");
iClockLogger = PVLogger::GetLoggerObject("clock");
iFileServer.Connect();
SetState(EPVMFNodeIdle);
return PVMFSuccess;
}
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACParserNode::ThreadLogon() - Invalid State"));
return PVMFErrInvalidState;
}
/**
//Do thread-specific node cleanup and go to "Created" state.
*/
PVMFStatus PVMFAACFFParserNode::ThreadLogoff()
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::ThreadLogoff() Called"));
if (iInterfaceState == EPVMFNodeIdle)
{
CleanupFileSource();
iFileServer.Close();
if (IsAdded())
{
RemoveFromScheduler();
}
iLogger = NULL;
iDataPathLogger = NULL;
iClockLogger = NULL;
SetState(EPVMFNodeCreated);
return PVMFSuccess;
}
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACParserNode::ThreadLogoff() - Invalid State"));
return PVMFErrInvalidState;
}
PVMFStatus PVMFAACFFParserNode::GetCapability(PVMFNodeCapability& aNodeCapability)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::GetCapability() called"));
// TODO: Return the appropriate format capability
aNodeCapability = iCapability;
return PVMFSuccess;
}
PVMFPortIter* PVMFAACFFParserNode::GetPorts(const PVMFPortFilter* aFilter)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::GetPorts() called"));
OSCL_UNUSED_ARG(aFilter);//port filter is not implemented.
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACParserNode::GetPorts() Not Implemented"));
return NULL;
}
PVMFCommandId PVMFAACFFParserNode::QueryUUID(PVMFSessionId s, const PvmfMimeString& aMimeType,
Oscl_Vector<PVUuid, OsclMemAllocator>& aUuids,
bool aExactUuidsOnly,
const OsclAny* aContext)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::QueryUUID called"));
PVMFAACFFParserNodeCommand cmd;
cmd.PVMFAACFFParserNodeCommandBase::Construct(s, PVMF_AAC_PARSER_NODE_QUERYUUID, aMimeType, aUuids, aExactUuidsOnly, aContext);
return QueueCommandL(cmd);
}
PVMFCommandId PVMFAACFFParserNode::QueryInterface(PVMFSessionId s, const PVUuid& aUuid,
PVInterface*& aInterfacePtr,
const OsclAny* aContext)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::QueryInterface called"));
PVMFAACFFParserNodeCommand cmd;
cmd.PVMFAACFFParserNodeCommandBase::Construct(s, PVMF_AAC_PARSER_NODE_QUERYINTERFACE, aUuid, aInterfacePtr, aContext);
return QueueCommandL(cmd);
}
PVMFCommandId PVMFAACFFParserNode::RequestPort(PVMFSessionId s, int32 aPortTag, const PvmfMimeString* aPortConfig, const OsclAny* aContext)
{
OSCL_UNUSED_ARG(aPortConfig);
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::RequestPort called"));
PVMFAACFFParserNodeCommand cmd;
cmd.PVMFAACFFParserNodeCommandBase::Construct(s, PVMF_AAC_PARSER_NODE_REQUESTPORT, aPortTag, aContext);
return QueueCommandL(cmd);
}
PVMFCommandId PVMFAACFFParserNode::ReleasePort(PVMFSessionId s, PVMFPortInterface& aPort, const OsclAny* aContext)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::ReleasePort called"));
PVMFAACFFParserNodeCommand cmd;
cmd.PVMFAACFFParserNodeCommandBase::Construct(s, PVMF_AAC_PARSER_NODE_RELEASEPORT, aPort, aContext);
return QueueCommandL(cmd);
}
PVMFCommandId PVMFAACFFParserNode::Init(PVMFSessionId s, const OsclAny* aContext)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::Init called"));
PVMFAACFFParserNodeCommand cmd;
cmd.PVMFAACFFParserNodeCommandBase::Construct(s, PVMF_AAC_PARSER_NODE_INIT, aContext);
return QueueCommandL(cmd);
}
PVMFCommandId PVMFAACFFParserNode::Prepare(PVMFSessionId s, const OsclAny* aContext)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::Prepare called"));
PVMFAACFFParserNodeCommand cmd;
cmd.PVMFAACFFParserNodeCommandBase::Construct(s, PVMF_AAC_PARSER_NODE_PREPARE, aContext);
return QueueCommandL(cmd);
}
PVMFCommandId PVMFAACFFParserNode::Start(PVMFSessionId s, const OsclAny* aContext)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::Start called"));
PVMFAACFFParserNodeCommand cmd;
cmd.PVMFAACFFParserNodeCommandBase::Construct(s, PVMF_AAC_PARSER_NODE_START, aContext);
return QueueCommandL(cmd);
}
PVMFCommandId PVMFAACFFParserNode::Stop(PVMFSessionId s, const OsclAny* aContext)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::Stop called"));
PVMFAACFFParserNodeCommand cmd;
cmd.PVMFAACFFParserNodeCommandBase::Construct(s, PVMF_AAC_PARSER_NODE_STOP, aContext);
return QueueCommandL(cmd);
}
PVMFCommandId PVMFAACFFParserNode::Flush(PVMFSessionId s, const OsclAny* aContext)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::Flush called"));
PVMFAACFFParserNodeCommand cmd;
cmd.PVMFAACFFParserNodeCommandBase::Construct(s, PVMF_AAC_PARSER_NODE_FLUSH, aContext);
return QueueCommandL(cmd);
}
PVMFCommandId PVMFAACFFParserNode::Pause(PVMFSessionId s, const OsclAny* aContext)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::Pause called"));
PVMFAACFFParserNodeCommand cmd;
cmd.PVMFAACFFParserNodeCommandBase::Construct(s, PVMF_AAC_PARSER_NODE_PAUSE, aContext);
return QueueCommandL(cmd);
}
PVMFCommandId PVMFAACFFParserNode::Reset(PVMFSessionId s, const OsclAny* aContext)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::Reset called"));
PVMFAACFFParserNodeCommand cmd;
cmd.PVMFAACFFParserNodeCommandBase::Construct(s, PVMF_AAC_PARSER_NODE_RESET, aContext);
return QueueCommandL(cmd);
}
PVMFCommandId PVMFAACFFParserNode::CancelAllCommands(PVMFSessionId s, const OsclAny* aContext)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::CancelAllCommands called"));
PVMFAACFFParserNodeCommand cmd;
cmd.PVMFAACFFParserNodeCommandBase::Construct(s, PVMF_AAC_PARSER_NODE_CANCELALLCOMMANDS, aContext);
return QueueCommandL(cmd);
}
PVMFCommandId PVMFAACFFParserNode::CancelCommand(PVMFSessionId s, PVMFCommandId aCmdId, const OsclAny* aContext)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::CancelCommand called"));
PVMFAACFFParserNodeCommand cmd;
cmd.PVMFAACFFParserNodeCommandBase::Construct(s, PVMF_AAC_PARSER_NODE_CANCELCOMMAND, aCmdId, aContext);
return QueueCommandL(cmd);
}
// From PVMFMetadataExtensionInterface
uint32 PVMFAACFFParserNode::GetNumMetadataKeys(char* aQueryKeyString)
{
uint32 num_entries = 0;
if (aQueryKeyString == NULL)
{
num_entries = iAvailableMetadataKeys.size();
}
else
{
for (uint32 i = 0; i < iAvailableMetadataKeys.size(); i++)
{
if (pv_mime_strcmp(iAvailableMetadataKeys[i].get_cstr(), aQueryKeyString) >= 0)
{
num_entries++;
}
}
for (uint32 j = 0; j < iCPMMetadataKeys.size(); j++)
{
/* Check if the key matches the query key */
if (pv_mime_strcmp(iCPMMetadataKeys[j].get_cstr(),
aQueryKeyString) >= 0)
{
num_entries++;
}
}
}
if ((iCPMMetaDataExtensionInterface != NULL))
{
num_entries +=
iCPMMetaDataExtensionInterface->GetNumMetadataKeys(aQueryKeyString);
}
return num_entries;
}
// From PVMFMetadataExtensionInterface
uint32 PVMFAACFFParserNode::GetNumMetadataValues(PVMFMetadataList& aKeyList)
{
uint32 numkeys = aKeyList.size();
if (iAACParser == NULL || numkeys == 0)
{
return 0;
}
uint32 numvalentries = 0;
for (uint32 lcv = 0; lcv < numkeys; lcv++)
{
if (iAACParser->IsID3Frame(aKeyList[lcv]))
{
++numvalentries;
}
else if (!oscl_strcmp(aKeyList[lcv].get_cstr(), PVAACMETADATA_DURATION_KEY) &&
iAACFileInfo.iDuration > 0)
{
// Duration
// Increment the counter for the number of values found so far
++numvalentries;
}
else if (!oscl_strcmp(aKeyList[lcv].get_cstr(), PVAACMETADATA_RANDOM_ACCESS_DENIED_KEY))
{
// random-acess-denied
// Increment the counter for the number of values found so far
++numvalentries;
}
else if (!oscl_strcmp(aKeyList[lcv].get_cstr(), PVAACMETADATA_NUMTRACKS_KEY))
{
// Number of tracks
// Increment the counter for the number of values found so far
++numvalentries;
}
else if ((oscl_strcmp(aKeyList[lcv].get_cstr(), PVAACMETADATA_TRACKINFO_BITRATE_KEY) == 0) &&
iAACFileInfo.iBitrate > 0)
{
// Bitrate
// Increment the counter for the number of values found so far
++numvalentries;
}
else if ((oscl_strcmp(aKeyList[lcv].get_cstr(), PVAACMETADATA_TRACKINFO_SAMPLERATE_KEY) == 0) &&
iAACFileInfo.iSampleFrequency > 0)
{
// Sampling rate
// Increment the counter for the number of values found so far
++numvalentries;
}
else if ((oscl_strcmp(aKeyList[lcv].get_cstr(), PVAACMETADATA_TRACKINFO_AUDIO_FORMAT_KEY) == 0) &&
iAACFileInfo.iFormat != EAACUnrecognized)
{
// Format
// Increment the counter for the number of values found so far
++numvalentries;
}
}
if ((iCPMMetaDataExtensionInterface != NULL))
{
numvalentries +=
iCPMMetaDataExtensionInterface->GetNumMetadataValues(aKeyList);
}
return numvalentries;
}
// From PVMFMetadataExtensionInterface
PVMFCommandId PVMFAACFFParserNode::GetNodeMetadataKeys(PVMFSessionId aSessionId, PVMFMetadataList& aKeyList,
uint32 starting_index, int32 max_entries, char* query_key, const OsclAny* aContext)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::GetNodeMetadataKeys called"));
PVMFAACFFParserNodeCommand cmd;
cmd.PVMFAACFFParserNodeCommand::Construct(aSessionId, PVMF_AAC_PARSER_NODE_GETNODEMETADATAKEYS, aKeyList, starting_index, max_entries, query_key, aContext);
return QueueCommandL(cmd);
}
// From PVMFMetadataExtensionInterface
PVMFCommandId PVMFAACFFParserNode::GetNodeMetadataValues(PVMFSessionId aSessionId, PVMFMetadataList& aKeyList,
Oscl_Vector<PvmiKvp, OsclMemAllocator>& aValueList, uint32 starting_index, int32 max_entries, const OsclAny* aContext)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::GetNodeMetadataValues called"));
PVMFAACFFParserNodeCommand cmd;
cmd.PVMFAACFFParserNodeCommand::Construct(aSessionId, PVMF_AAC_PARSER_NODE_GETNODEMETADATAVALUES, aKeyList, aValueList, starting_index, max_entries, aContext);
return QueueCommandL(cmd);
}
// From PVMFMetadataExtensionInterface
PVMFStatus PVMFAACFFParserNode::ReleaseNodeMetadataKeys(PVMFMetadataList& , uint32 , uint32)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::ReleaseNodeMetadataKeys called"));
//nothing needed-- there's no dynamic allocation in this node's key list
return PVMFSuccess;
}
// From PVMFMetadataExtensionInterface
PVMFStatus PVMFAACFFParserNode::ReleaseNodeMetadataValues(Oscl_Vector<PvmiKvp, OsclMemAllocator>& aValueList, uint32 start, uint32 end)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::ReleaseNodeMetadataValues called"));
if (start > end || aValueList.size() == 0)
{
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACFFParserNode::ReleaseNodeMetadataValues() Invalid start/end index"));
return PVMFErrArgument;
}
end = OSCL_MIN(aValueList.size(), iAACParserNodeMetadataValueCount);
for (uint32 i = start; i < end; i++)
{
if (aValueList[i].key != NULL)
{
switch (GetValTypeFromKeyString(aValueList[i].key))
{
case PVMI_KVPVALTYPE_WCHARPTR:
if (aValueList[i].value.pWChar_value != NULL)
{
OSCL_ARRAY_DELETE(aValueList[i].value.pWChar_value);
aValueList[i].value.pWChar_value = NULL;
}
break;
case PVMI_KVPVALTYPE_CHARPTR:
if (aValueList[i].value.pChar_value != NULL)
{
OSCL_ARRAY_DELETE(aValueList[i].value.pChar_value);
aValueList[i].value.pChar_value = NULL;
}
break;
case PVMI_KVPVALTYPE_UINT32:
case PVMI_KVPVALTYPE_UINT8:
// No memory to free for these valtypes
break;
default:
// Should not get a value that wasn't created from here
break;
}
OSCL_ARRAY_DELETE(aValueList[i].key);
aValueList[i].key = NULL;
}
}
return PVMFSuccess;
}
// From PvmfDataSourcePlaybackControlInterface
PVMFCommandId PVMFAACFFParserNode::SetDataSourcePosition(PVMFSessionId aSessionId
, PVMFTimestamp aTargetNPT
, PVMFTimestamp& aActualNPT
, PVMFTimestamp& aActualMediaDataTS
, bool aSeekToSyncPoint
, uint32 aStreamID
, OsclAny* aContext)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::SetDataSourcePosition called"));
PVMFAACFFParserNodeCommand cmd;
cmd.PVMFAACFFParserNodeCommand::Construct(aSessionId, PVMF_AAC_PARSER_NODE_SET_DATASOURCE_POSITION, aTargetNPT, aActualNPT,
aActualMediaDataTS, aSeekToSyncPoint, aStreamID, aContext);
return QueueCommandL(cmd);
}
// From PvmfDataSourcePlaybackControlInterface
PVMFCommandId PVMFAACFFParserNode::QueryDataSourcePosition(PVMFSessionId aSessionId
, PVMFTimestamp aTargetNPT
, PVMFTimestamp& aActualNPT
, bool aSeekToSyncPoint
, OsclAny* aContext)
{
PVMFAACFFParserNodeCommand cmd;
cmd.PVMFAACFFParserNodeCommand::Construct(aSessionId, PVMF_AAC_PARSER_NODE_QUERY_DATASOURCE_POSITION, aTargetNPT, aActualNPT, aSeekToSyncPoint, aContext);
return QueueCommandL(cmd);
}
PVMFCommandId PVMFAACFFParserNode::QueryDataSourcePosition(PVMFSessionId aSessionId
, PVMFTimestamp aTargetNPT
, PVMFTimestamp& aSeekPointBeforeTargetNPT
, PVMFTimestamp& aSeekPointAfterTargetNPT
, OsclAny* aContext
, bool aSeekToSyncPoint)
{
OSCL_UNUSED_ARG(aSeekPointAfterTargetNPT);
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
(0, "PVMFAACFFParserNode::QueryDataSourcePosition: aTargetNPT=%d, aSeekToSyncPoint=%d, aContext=0x%x",
aTargetNPT, aSeekToSyncPoint, aContext));
PVMFAACFFParserNodeCommand cmd;
// Construct not changes. aSeekPointBeforeTargetNPT will act as aActualtNPT
cmd.PVMFAACFFParserNodeCommand::Construct(aSessionId, PVAACFF_NODE_CMD_QUERYDATASOURCEPOSITION, aTargetNPT, aSeekPointBeforeTargetNPT, aSeekToSyncPoint, aContext);
return QueueCommandL(cmd);
}
// From PvmfDataSourcePlaybackControlInterface
PVMFCommandId PVMFAACFFParserNode::SetDataSourceRate(PVMFSessionId aSessionId
, int32 aRate
, PVMFTimebase* aTimebase
, OsclAny* aContext)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::SetDataSourceRate called"));
PVMFAACFFParserNodeCommand cmd;
cmd.PVMFAACFFParserNodeCommand::Construct(aSessionId, PVMF_AAC_PARSER_NODE_SET_DATASOURCE_RATE, aRate, aTimebase, aContext);
return QueueCommandL(cmd);
}
void
PVMFAACFFParserNode::MoveCmdToCurrentQueue(PVMFAACFFParserNodeCommand& aCmd)
{
int32 err;
OSCL_TRY(err, iCurrentCommand.StoreL(aCmd););
if (err != OsclErrNone)
{
CommandComplete(iInputCommands, aCmd, PVMFErrNoMemory);
return;
}
iInputCommands.Erase(&aCmd);
return;
}
void
PVMFAACFFParserNode::MoveCmdToCancelQueue(PVMFAACFFParserNodeCommand& aCmd)
{
/*
* note: the StoreL cannot fail since the queue is never more than 1 deep
* and we reserved space.
*/
iCancelCommand.StoreL(aCmd);
iInputCommands.Erase(&aCmd);
}
void PVMFAACFFParserNode::Run()
{
//Process async node commands.
if (!iInputCommands.empty())
{
ProcessCommand();
/*
* note: need to check the state before re-scheduling
* since the node could have been reset in the ProcessCommand
* call.
*/
if (iInterfaceState != EPVMFNodeCreated)
{
RunIfNotReady();
}
return;
}
// Send outgoing messages
if (iInterfaceState == EPVMFNodeStarted || FlushPending())
{
PVAACFFNodeTrackPortInfo* trackPortInfoPtr = NULL;
if (!GetTrackInfo(iOutPort, trackPortInfoPtr))
{
PVMF_AACPARSERNODE_LOGERROR((0, "PVAACParserNode::Run: Error - GetTrackInfo failed"));
return;
}
ProcessPortActivity(trackPortInfoPtr);
if (CheckForPortRescheduling())
{
/*
* Re-schedule since there is atleast one port that needs processing
*/
RunIfNotReady();
}
}
// Detect Flush command completion.
if (FlushPending()
&& iOutPort
&& iOutPort->OutgoingMsgQueueSize() == 0)
{
SetState(EPVMFNodePrepared);
//Flush is complete.
//resume port input so the ports can be re-started.
iOutPort->ResumeInput();
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess);
}
}
bool PVMFAACFFParserNode::RetrieveTrackConfigInfo(PVAACFFNodeTrackPortInfo& aTrackPortInfo)
{
// Check if the track has decoder config info
uint32 specinfosize = iAACParser->GetTrackDecoderSpecificInfoSize();
if (specinfosize == 0)
{
// There is no decoder specific info so return as error. AAC requires audio config header
return false;
}
// Create mem frag for decoder specific config
OsclMemAllocDestructDealloc<uint8> my_alloc;
OsclRefCounter* my_refcnt;
uint aligned_refcnt_size = oscl_mem_aligned_size(sizeof(OsclRefCounterSA< OsclMemAllocDestructDealloc<uint8> >));
uint8* my_ptr = NULL;
int32 errcode = 0;
OSCL_TRY(errcode, my_ptr = (uint8*) my_alloc.ALLOCATE(aligned_refcnt_size + specinfosize));
OSCL_FIRST_CATCH_ANY(errcode, return false);
my_refcnt = OSCL_PLACEMENT_NEW(my_ptr, OsclRefCounterSA< OsclMemAllocDestructDealloc<uint8> >(my_ptr));
my_ptr += aligned_refcnt_size;
OsclMemoryFragment memfrag;
memfrag.len = specinfosize;
memfrag.ptr = my_ptr;
OsclRefCounterMemFrag configinfo_refcntmemfrag(memfrag, my_refcnt, specinfosize);
// Retrieve the decoder specific info from file parser
uint8* specinfoptr = iAACParser->GetTrackDecoderSpecificInfoContent();
if (specinfoptr == NULL)
{
// Error
return false;
}
// Copy the decoder specific info to the memory fragment
oscl_memcpy(memfrag.ptr, specinfoptr, specinfosize);
// Save format specific info
aTrackPortInfo.iFormatSpecificConfig = configinfo_refcntmemfrag;
return true;
}
PVMFStatus PVMFAACFFParserNode::RetrieveMediaSample(PVAACFFNodeTrackPortInfo* aTrackInfoPtr,
PVMFSharedMediaDataPtr& aMediaDataOut)
{
// Create a data buffer from pool
int errcode = OsclErrNoResources;
OsclSharedPtr<PVMFMediaDataImpl> mediaDataImplOut;
mediaDataImplOut = aTrackInfoPtr->iResizableSimpleMediaMsgAlloc->allocate(MAXTRACKDATASIZE);
if (mediaDataImplOut.GetRep() != NULL)
{
errcode = OsclErrNone;
}
OsclMemPoolResizableAllocatorObserver* resizableAllocObs =
OSCL_STATIC_CAST(OsclMemPoolResizableAllocatorObserver*, aTrackInfoPtr);
// Enable flag to receive event when next deallocate() is called on pool
if (errcode != OsclErrNone)
{
aTrackInfoPtr->iTrackDataMemoryPool->notifyfreeblockavailable(*resizableAllocObs);
return PVMFErrBusy;
}
// Now create a PVMF media data from pool
errcode = OsclErrNoResources;
aMediaDataOut = PVMFMediaData::createMediaData(mediaDataImplOut, aTrackInfoPtr->iMediaDataMemPool);
if (aMediaDataOut.GetRep() != NULL)
{
errcode = OsclErrNone;
}
OsclMemPoolFixedChunkAllocatorObserver* fixedChunkObs =
OSCL_STATIC_CAST(OsclMemPoolFixedChunkAllocatorObserver*, aTrackInfoPtr);
// Enable flag to receive event when next deallocate() is called on pool
if (errcode != OsclErrNone)
{
aTrackInfoPtr->iMediaDataMemPool->notifyfreechunkavailable(*fixedChunkObs);
return PVMFErrBusy;
}
// Retrieve memory fragment to write to
OsclRefCounterMemFrag refCtrMemFragOut;
OsclMemoryFragment memFragOut;
aMediaDataOut->getMediaFragment(0, refCtrMemFragOut);
memFragOut.ptr = refCtrMemFragOut.getMemFrag().ptr;
Oscl_Vector<uint32, OsclMemAllocator> payloadSizeVec;
uint32 numsamples = NUM_AAC_FRAMES;
// Set up the GAU structure
GAU gau;
gau.numMediaSamples = numsamples;
gau.buf.num_fragments = 1;
gau.buf.buf_states[0] = NULL;
gau.buf.fragments[0].ptr = refCtrMemFragOut.getMemFrag().ptr;
gau.buf.fragments[0].len = refCtrMemFragOut.getCapacity();
bool oIncludeADTSHeaders = false;
if ((aTrackInfoPtr->oADTS == true) &&
(PVMF_AAC_PARSER_NODE_INCLUDE_ADTS_HEADERS == 1))
{
oIncludeADTSHeaders = true;
}
int32 retval = iAACParser->GetNextBundledAccessUnits(&numsamples, &gau, oIncludeADTSHeaders);
uint32 actualdatasize = 0;
for (uint32 i = 0; i < numsamples; i++)
{
actualdatasize += gau.info[i].len;
}
if (retval == AACBitstreamObject::EVERYTHING_OK)
{
memFragOut.len = actualdatasize;
// Set Actual size
aMediaDataOut->setMediaFragFilledLen(0, actualdatasize);
// Resize memory fragment
aTrackInfoPtr->iResizableSimpleMediaMsgAlloc->ResizeMemoryFragment(mediaDataImplOut);
// Compute the continous timestamp
aTrackInfoPtr->iContinuousTimeStamp = gau.info[0].ts + aTrackInfoPtr->iTimestampOffset;
uint32 timestamp = 0xFFFFFFFF;
if (gau.info[0].ts != 0xFFFFFFFF)
{
// Retrieve timestamp and convert to milliseconds
aTrackInfoPtr->iClockConverter->update_clock(gau.info[0].ts + aTrackInfoPtr->iTimestampOffset);
timestamp = aTrackInfoPtr->iClockConverter->get_converted_ts(1000);
}
// Set the media data's timestamp
aTrackInfoPtr->iPrevSampleTimeStamp = gau.info[0].ts;
aMediaDataOut->setTimestamp(timestamp);
aMediaDataOut->setSeqNum(aTrackInfoPtr->iSeqNum);
aMediaDataOut->setStreamID(iStreamID);
if (aTrackInfoPtr->iSeqNum == 0)
{
aMediaDataOut->setFormatSpecificInfo(aTrackInfoPtr->iFormatSpecificConfig);
}
aTrackInfoPtr->iSeqNum += 1;
// Set M bit to 1 always - ASF FF only outputs complete frames
uint32 markerInfo = 0;
markerInfo |= PVMF_MEDIA_DATA_MARKER_INFO_M_BIT;
// Set Key Frame bit
if (iFirstFrame)
{
markerInfo |= PVMF_MEDIA_DATA_MARKER_INFO_RANDOM_ACCESS_POINT_BIT;
iFirstFrame = false;
}
mediaDataImplOut->setMarkerInfo(markerInfo);
}
else if (retval == AACBitstreamObject::READ_ERROR)
{
payloadSizeVec.clear();
if (iDownloadProgressInterface != NULL)
{
iDownloadProgressInterface->requestResumeNotification(aTrackInfoPtr->iPrevSampleTimeStamp,
iDownloadComplete);
iAutoPaused = true;
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACParserNode::RetrieveMediaSample() - Auto Pause Triggered - TS=%d", aTrackInfoPtr->iPrevSampleTimeStamp));
PVMF_AACPARSERNODE_LOGDATATRAFFIC((0, "PVMFAACParserNode::RetrieveMediaSample() - Auto Pause Triggered - TS=%d", aTrackInfoPtr->iPrevSampleTimeStamp));
return PVMFErrBusy;
}
else
{
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACParserNode::RetrieveMediaSample() - Sample Retrieval Failed - Insufficient Data In File"));
return PVMFFailure;
}
}
else if (retval == AACBitstreamObject::END_OF_FILE)
{
PVMF_AACPARSERNODE_LOGDATATRAFFIC((0, "PVMFAACParserNode::RetrieveMediaSample() - END_OF_FILE Reached"));
aTrackInfoPtr->oEOSReached = true;
return PVMFInfoEndOfData;
}
else
{
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACParserNode::RetrieveMediaSample() - Sample Retrieval Failed"));
return PVMFFailure;
}
return PVMFSuccess;
}
void PVMFAACFFParserNode::PushToAvailableMetadataKeysList(const char* aKeystr, char* aOptionalParam)
{
if (aKeystr == NULL)
{
return;
}
int32 leavecode = 0;
if (aOptionalParam)
{
OSCL_TRY(leavecode, iAvailableMetadataKeys.push_front(aKeystr);
iAvailableMetadataKeys[0] += aOptionalParam;);
}
else
{
OSCL_TRY(leavecode, iAvailableMetadataKeys.push_front(aKeystr));
}
}
void PVMFAACFFParserNode::DoInit(PVMFAACFFParserNodeCommand& aCmd)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::DoInit() Called"));
if (iInterfaceState != EPVMFNodeIdle)
{
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
return;
}
MoveCmdToCurrentQueue(aCmd);
if (iCPM)
{
/*
* Go thru CPM commands before parsing the file in case
* of a new source file.
* - Init CPM
* - Open Session
* - Register Content
* - Get Content Type
* - Approve Usage
* In case the source file has already been parsed skip to
* - Approve Usage
*/
if (oSourceIsCurrent == false)
{
InitCPM();
}
else
{
RequestUsage();
}
}
else
{
PVMFStatus status = CheckForAACHeaderAvailability();
if (status == PVMFSuccess)
{
status = ParseAACFile();
SetState(EPVMFNodeInitialized);
}
CommandComplete(iCurrentCommand,
iCurrentCommand.front(),
status);
}
}
PVMFStatus PVMFAACFFParserNode::CheckForAACHeaderAvailability()
{
if (iDataStreamInterface != NULL)
{
/*
* First check if we have minimum number of bytes to recognize
* the file and determine the header size.
*/
uint32 currCapacity = 0;
iDataStreamInterface->QueryReadCapacity(iDataStreamSessionID,
currCapacity);
if (currCapacity < AAC_MIN_DATA_SIZE_FOR_RECOGNITION)
{
iRequestReadCapacityNotificationID =
iDataStreamInterface->RequestReadCapacityNotification(iDataStreamSessionID,
*this,
AAC_MIN_DATA_SIZE_FOR_RECOGNITION);
return PVMFPending;
}
CAACFileParser* iAACParserTemp;
PVMF_AAC_PARSER_NODE_NEW(NULL, CAACFileParser, (), iAACParserTemp);
uint32 headerSize32 = 0;
if (OK == iAACParserTemp->getAACHeaderLen(iSourceURL, false, &iFileServer ,
iDataStreamFactory, iFileHandle, &headerSize32))
{
if (currCapacity < headerSize32)
{
iRequestReadCapacityNotificationID =
iDataStreamInterface->RequestReadCapacityNotification(iDataStreamSessionID,
*this,
headerSize32);
return PVMFPending;
}
}
else
{
return PVMFFailure;
}
PVMF_AAC_PARSER_NODE_DELETE(NULL, CAACFileParser, iAACParserTemp);
}
return PVMFSuccess;
}
PVMFStatus PVMFAACFFParserNode::ParseAACFile()
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACFFParserNode::ParseFile() In"));
PVMF_AAC_PARSER_NODE_NEW(NULL, CAACFileParser, (), iAACParser);
if (iAACParser == NULL)
{
PVMF_AACPARSERNODE_LOGINFOHI((0, "PVMFAACFFParserNode::ParseFile() Instantion of AAC file parser failed"));
return PVMFErrNoMemory;
}
bool oParseCompleteFile = true;
if (iDownloadProgressInterface != NULL)
{
//a PDL session
oParseCompleteFile = false;
}
PVMFDataStreamFactory* dsFactory = iCPMContentAccessFactory;
if ((dsFactory == NULL) && (iDataStreamFactory != NULL))
{
dsFactory = iDataStreamFactory;
}
if (!(iAACParser->InitAACFile(iSourceURL, oParseCompleteFile, &iFileServer , dsFactory, iFileHandle)))
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFAACFFParserNode::ParseFile() Parsing of AAC file parser failed"));
OSCL_DELETE(iAACParser);
iAACParser = NULL;
return PVMFErrNoResources;
}
// Retrieve the file info from the parser
iAACFileInfoValid = iAACParser->RetrieveFileInfo(iAACFileInfo);
// Retrieve the ID3 metadata from the file if available
PvmiKvpSharedPtrVector iID3Data;
iID3DataValid = iAACParser->RetrieveID3Info(iID3Data);
// Initialize the meta-data keys
iAvailableMetadataKeys.clear();
int32 leavecode = 0;
if (iAACFileInfoValid || iID3DataValid)
{
// Following keys are available when the AAC file has been parsed
if (iAACFileInfo.iDuration > 0)
{
leavecode = 0;
OSCL_TRY(leavecode, iAvailableMetadataKeys.push_back(PVAACMETADATA_DURATION_KEY));
}
leavecode = 0;
OSCL_TRY(leavecode, iAvailableMetadataKeys.push_back(PVAACMETADATA_NUMTRACKS_KEY));
leavecode = 0;
OSCL_TRY(leavecode, iAvailableMetadataKeys.push_back(PVAACMETADATA_RANDOM_ACCESS_DENIED_KEY));
if (iAACFileInfo.iBitrate > 0)
{
leavecode = 0;
OSCL_TRY(leavecode, iAvailableMetadataKeys.push_back(PVAACMETADATA_TRACKINFO_BITRATE_KEY));
}
if (iAACFileInfo.iSampleFrequency > 0)
{
leavecode = 0;
OSCL_TRY(leavecode, iAvailableMetadataKeys.push_back(PVAACMETADATA_TRACKINFO_SAMPLERATE_KEY));
}
leavecode = 0;
OSCL_TRY(leavecode, iAvailableMetadataKeys.push_back(PVAACMETADATA_TRACKINFO_AUDIO_FORMAT_KEY));
}
if (iID3DataValid)
{
leavecode = 0;
OSCL_TRY(leavecode,
for (uint s = 0; s < iID3Data.size(); s++)
{
OSCL_HeapString<OsclMemAllocator> keystr((const char *)((*iID3Data[s]).key), oscl_strlen((const char *)((*iID3Data[s]).key)));
iAvailableMetadataKeys.push_back(keystr);
}
);
}
//set clip duration on download progress interface
//applicable to PDL sessions
{
if (iAACFileInfoValid)
{
if ((iDownloadProgressInterface != NULL) && (iAACFileInfo.iDuration != 0))
{
iDownloadProgressInterface->setClipDuration(OSCL_CONST_CAST(uint32, iAACFileInfo.iDuration));
}
}
}
return PVMFSuccess;
}
void PVMFAACFFParserNode::DoPrepare(PVMFAACFFParserNodeCommand& aCmd)
{
switch (iInterfaceState)
{
case EPVMFNodeInitialized:
//this node doesn't need to do anything to get ready
//to start.
SetState(EPVMFNodePrepared);
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
return;
default:
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
return;
}
}
void PVMFAACFFParserNode::DoStart(PVMFAACFFParserNodeCommand& aCmd)
{
switch (iInterfaceState)
{
case EPVMFNodePrepared:
case EPVMFNodePaused:
//nothing needed
SetState(EPVMFNodeStarted);
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
return;
default:
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
return;
}
}
void PVMFAACFFParserNode::DoStop(PVMFAACFFParserNodeCommand& aCmd)
{
iStreamID = 0;
switch (iInterfaceState)
{
case EPVMFNodeStarted:
case EPVMFNodePaused:
if (iDataStreamInterface != NULL)
{
PVInterface* iFace = OSCL_STATIC_CAST(PVInterface*, iDataStreamInterface);
PVUuid uuid = PVMIDataStreamSyncInterfaceUuid;
iDataStreamFactory->DestroyPVMFCPMPluginAccessInterface(uuid, iFace);
iDataStreamInterface = NULL;
}
// Stop data source
// Clear queued messages in ports
if (iOutPort)
{
iOutPort->ClearMsgQueues();
}
// stop and reset position to beginning
ResetAllTracks();
iTrack.iTimestampOffset = 0;
// Reset the AAC FF to beginning
if (iAACParser)
{
uint32 tmpuint32 = 0;
iAACParser->ResetPlayback(0, tmpuint32);
}
SetState(EPVMFNodePrepared);
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
return;
default:
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
return;
}
}
void PVMFAACFFParserNode::DoPause(PVMFAACFFParserNodeCommand& aCmd)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::DoPauseNode() Called"));
if (iInterfaceState != EPVMFNodeStarted)
{
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
return;
}
SetState(EPVMFNodePaused);
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
return;
}
void PVMFAACFFParserNode::DoReset(PVMFAACFFParserNodeCommand& aCmd)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::DoReset() Called"));
MoveCmdToCurrentQueue(aCmd);
if (iDownloadProgressInterface != NULL)
{
iDownloadProgressInterface->cancelResumeNotification();
}
if (iFileHandle != NULL)
{
/* Indicates that the init was successfull */
if ((iCPM))
{
SendUsageComplete();
}
else
{
CompleteReset();
}
}
else
{
/*
* Reset without init completing, so just reset the parser node,
* no CPM stuff necessary
*/
CompleteReset();
}
}
void PVMFAACFFParserNode::CompleteReset()
{
/* stop and cleanup */
ReleaseTrack();
CleanupFileSource();
SetState(EPVMFNodeIdle);
CommandComplete(iCurrentCommand, iCurrentCommand.front(), PVMFSuccess);
}
void PVMFAACFFParserNode::DoRequestPort(PVMFAACFFParserNodeCommand& aCmd, PVMFPortInterface*& aPort)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFAACFFParserNode::DoRequestPort() In"));
aPort = NULL;
int32 tag;
OSCL_String* mimetype;
aCmd.PVMFAACFFParserNodeCommandBase::Parse(tag, mimetype);
//validate the tag...
switch (tag)
{
case PVMF_AAC_PARSER_NODE_PORT_TYPE_SOURCE:
break;
default:
//bad port tag
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACFFParserNode::DoRequestPort: Error - Invalid port tag"));
CommandComplete(iInputCommands, aCmd, PVMFFailure);
return;
}
//Allocate a new port
int32 leavecode = 0;
OSCL_TRY(leavecode, iOutPort = OSCL_NEW(PVMFAACFFParserOutPort, (PVMF_AAC_PARSER_NODE_PORT_TYPE_SOURCE, this)););
if (leavecode != OsclErrNone || !iOutPort)
{
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACFFParserNode::DoRequestPort: Error - Out of memory"));
CommandComplete(iInputCommands, aCmd, PVMFErrNoMemory);
return;
}
//validate the requested format
if (mimetype)
{
PVMFFormatType fmt = mimetype->get_str();
if (!iOutPort->IsFormatSupported(fmt))
{
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACFFParserNode::DoRequestPort: Error - Invalid Format!"));
PVMF_AAC_PARSER_NODE_DELETE(NULL, PVMFAACFFParserOutPort, iOutPort);
iOutPort = NULL;
CommandComplete(iInputCommands, aCmd, PVMFFailure);
return;
}
}
{
if (!iAACParser)
{
CommandComplete(iInputCommands, aCmd, PVMFFailure);
return;
}
TPVAacFileInfo aacinfo;
oscl_memset(&aacinfo, 0, sizeof(TPVAacFileInfo));
if (!iAACParser->RetrieveFileInfo(aacinfo))
{
CommandComplete(iInputCommands, aCmd, PVMFFailure);
return;
}
MediaClockConverter* clockconv = NULL;
OsclMemPoolResizableAllocator* trackdatamempool = NULL;
TrackDataMemPoolProxyAlloc* trackdatamempoolproxy = NULL;
PVMFSimpleMediaBufferCombinedAlloc* mediadataimplalloc = NULL;
PVMFMemPoolFixedChunkAllocator* mediadatamempool = NULL;
PVMF_AAC_PARSER_NODE_NEW(NULL, MediaClockConverter, (aacinfo.iTimescale), clockconv);
PVMF_AAC_PARSER_NODE_NEW(NULL, OsclMemPoolResizableAllocator, (2*MAXTRACKDATASIZE), trackdatamempool);
PVMF_AAC_PARSER_NODE_NEW(NULL, TrackDataMemPoolProxyAlloc, (*trackdatamempool), trackdatamempoolproxy);
PVMF_AAC_PARSER_NODE_NEW(NULL, PVMFSimpleMediaBufferCombinedAlloc, (trackdatamempoolproxy), mediadataimplalloc);
OSCL_TRY(leavecode,
mediadatamempool = OSCL_NEW(PVMFMemPoolFixedChunkAllocator, ("AacFFPar", PVAACFF_MEDIADATA_POOLNUM, PVAACFF_MEDIADATA_CHUNKSIZE));
);
if (leavecode || !clockconv || !trackdatamempool || !trackdatamempoolproxy || !mediadataimplalloc || !mediadatamempool)
{
PVMF_AAC_PARSER_NODE_DELETE(NULL, PVMFAACFFParserOutPort, ((PVMFAACFFParserOutPort*)iOutPort));
iOutPort = NULL;
if (clockconv)
{
PVMF_AAC_PARSER_NODE_DELETE(NULL, MediaClockConverter, clockconv);
}
if (trackdatamempool)
{
trackdatamempool->removeRef();
}
if (trackdatamempoolproxy)
{
PVMF_AAC_PARSER_NODE_DELETE(NULL, TrackDataMemPoolProxyAlloc, trackdatamempoolproxy)
}
if (mediadataimplalloc)
{
PVMF_AAC_PARSER_NODE_DELETE(NULL, PVMFSimpleMediaBufferCombinedAlloc, mediadataimplalloc);
}
if (mediadatamempool)
{
PVMF_AAC_PARSER_NODE_DELETE(NULL, PVMFMemPoolFixedChunkAllocator, mediadatamempool);
}
CommandComplete(iInputCommands, aCmd, PVMFErrNoMemory);
return;
}
trackdatamempool->enablenullpointerreturn();
mediadatamempool->enablenullpointerreturn();
// Construct iTrack
iTrack.iTrackId = 0; // Only support 1 channel so far
iTrack.iPort = iOutPort;
iTrack.iClockConverter = clockconv;
iTrack.iTrackDataMemoryPool = trackdatamempool;
iTrack.iTrackDataMemoryPoolProxy = trackdatamempoolproxy;
iTrack.iMediaDataImplAlloc = mediadataimplalloc;
iTrack.iMediaDataMemPool = mediadatamempool;
iTrack.iNode = OSCL_STATIC_CAST(OsclTimerObject*, this);
aPort = iOutPort;
if (aacinfo.iFormat == EAACADTS)
{
iTrack.oADTS = true;
}
}
PVMFResizableSimpleMediaMsgAlloc* resizableSimpleMediaDataImplAlloc = NULL;
OsclExclusivePtr<PVMFResizableSimpleMediaMsgAlloc> resizableSimpleMediaDataImplAllocAutoPtr;
PVMF_AAC_PARSER_NODE_NEW(NULL,
PVMFResizableSimpleMediaMsgAlloc,
(iTrack.iTrackDataMemoryPool),
resizableSimpleMediaDataImplAlloc);
iTrack.iResizableSimpleMediaMsgAlloc = resizableSimpleMediaDataImplAlloc;
RetrieveTrackConfigInfo(iTrack);
//Return the port pointer to the caller.
CommandComplete(iInputCommands, aCmd, PVMFSuccess, (OsclAny*)aPort);
return;
}
void PVMFAACFFParserNode::ResetAllTracks()
{
iTrack.iMediaData.Unbind();
iTrack.iSeqNum = 0;
iFirstFrame = false;
iTrack.oEOSReached = false;
iTrack.oEOSSent = false;
iTrack.oProcessOutgoingMessages = true;
iTrack.oQueueOutgoingMessages = true;
}
bool PVMFAACFFParserNode::ReleaseTrack()
{
if (iOutPort)
{
iOutPort->Disconnect();
PVMF_AAC_PARSER_NODE_DELETE(NULL, PVMFAACFFParserOutPort, ((PVMFAACFFParserOutPort*)iOutPort));
iOutPort = NULL;
}
iTrack.iMediaData.Unbind();
if (iTrack.iClockConverter)
{
PVMF_AAC_PARSER_NODE_DELETE(NULL, MediaClockConverter, iTrack.iClockConverter);
iTrack.iClockConverter = NULL;
}
if (iTrack.iTrackDataMemoryPool)
{
iTrack.iTrackDataMemoryPool->removeRef();
iTrack.iTrackDataMemoryPool = NULL;
}
if (iTrack.iTrackDataMemoryPoolProxy)
{
PVMF_AAC_PARSER_NODE_DELETE(NULL, TrackDataMemPoolProxyAlloc, iTrack.iTrackDataMemoryPoolProxy);
iTrack.iTrackDataMemoryPoolProxy = NULL;
}
if (iTrack.iMediaDataImplAlloc)
{
PVMF_AAC_PARSER_NODE_DELETE(NULL, PVMFSimpleMediaBufferCombinedAlloc, iTrack.iMediaDataImplAlloc);
iTrack.iMediaDataImplAlloc = NULL;
}
if (iTrack.iMediaDataMemPool != NULL)
{
iTrack.iMediaDataMemPool->CancelFreeChunkAvailableCallback();
iTrack.iMediaDataMemPool->removeRef();
iTrack.iMediaDataMemPool = NULL;
}
if (iTrack.iResizableSimpleMediaMsgAlloc)
{
PVMF_AAC_PARSER_NODE_DELETE(NULL,
PVMFResizableSimpleMediaMsgAlloc,
iTrack.iResizableSimpleMediaMsgAlloc);
iTrack.iResizableSimpleMediaMsgAlloc = NULL;
}
return true;
}
void PVMFAACFFParserNode::CleanupFileSource()
{
iAvailableMetadataKeys.clear();
if (iAACParser)
{
PVMF_AAC_PARSER_NODE_DELETE(NULL, CAACFileParser, iAACParser);
}
iAACParser = NULL;
iAACParserNodeMetadataValueCount = 0;
iUseCPMPluginRegistry = false;
iCPMSourceData.iFileHandle = NULL;
if (iCPMContentAccessFactory != NULL)
{
iCPMContentAccessFactory->removeRef();
iCPMContentAccessFactory = NULL;
}
if (iDataStreamFactory != NULL)
{
iDataStreamFactory->removeRef();
iDataStreamFactory = NULL;
}
iCPMContentType = PVMF_CPM_CONTENT_FORMAT_UNKNOWN;
iPreviewMode = false;
oSourceIsCurrent = false;
if (iFileHandle)
{
OSCL_DELETE(iFileHandle);
}
iFileHandle = NULL;
}
void PVMFAACFFParserNode::SetState(TPVMFNodeInterfaceState s)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACFFParserNode::SetState() %d", s));
PVMFNodeInterface::SetState(s);
}
void PVMFAACFFParserNode::ReportAACFFParserErrorEvent(PVMFEventType aEventType, OsclAny* aEventData, PVUuid* aEventUUID, int32* aEventCode)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACFFParserNode:ReportAACFFParserErrorEvent Type %d Data %d"
, aEventType, aEventData));
if (aEventUUID && aEventCode)
{
PVMFBasicErrorInfoMessage* eventmsg;
PVMF_AAC_PARSER_NODE_NEW(NULL,
PVMFBasicErrorInfoMessage,
(*aEventCode, *aEventUUID, NULL),
eventmsg);
PVMFAsyncEvent asyncevent(PVMFErrorEvent, aEventType, NULL, eventmsg, aEventData, NULL, 0);
PVMFNodeInterface::ReportErrorEvent(asyncevent);
eventmsg->removeRef();
}
else
{
PVMFNodeInterface::ReportErrorEvent(aEventType, aEventData);
}
}
void PVMFAACFFParserNode::ReportAACFFParserInfoEvent(PVMFEventType aEventType, OsclAny* aEventData, PVUuid* aEventUUID, int32* aEventCode)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACFFParserNode:ReportAACFFParserInfoEvent Type %d Data %d"
, aEventType, aEventData));
if (aEventUUID && aEventCode)
{
PVMFBasicErrorInfoMessage* eventmsg;
PVMF_AAC_PARSER_NODE_NEW(NULL,
PVMFBasicErrorInfoMessage,
(*aEventCode, *aEventUUID, NULL),
eventmsg);
PVMFAsyncEvent asyncevent(PVMFInfoEvent, aEventType, NULL, eventmsg, aEventData, NULL, 0);
PVMFNodeInterface::ReportInfoEvent(asyncevent);
eventmsg->removeRef();
}
else
{
PVMFNodeInterface::ReportInfoEvent(aEventType, aEventData);
}
}
void PVMFAACFFParserNode::HandlePortActivity(const PVMFPortActivity &aActivity)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACFFParserNode::PortActivity: port=0x%x, type=%d",
aActivity.iPort, aActivity.iType));
/*
* A port is reporting some activity or state change. This code
* figures out whether we need to queue a processing event
* for the AO, and/or report a node event to the observer.
*/
switch (aActivity.iType)
{
case PVMF_PORT_ACTIVITY_CREATED:
/*
* Report port created info event to the node.
*/
ReportInfoEvent(PVMFInfoPortCreated, (OsclAny*)aActivity.iPort);
break;
case PVMF_PORT_ACTIVITY_DELETED:
{
/*
* Report port deleted info event to the node.
*/
ReportInfoEvent(PVMFInfoPortDeleted, (OsclAny*)aActivity.iPort);
}
break;
case PVMF_PORT_ACTIVITY_CONNECT:
break;
case PVMF_PORT_ACTIVITY_DISCONNECT:
break;
case PVMF_PORT_ACTIVITY_OUTGOING_MSG:
{
/*
* An outgoing message was queued on this port.
* Wakeup the node to process the same.
*/
RunIfNotReady();
}
break;
case PVMF_PORT_ACTIVITY_INCOMING_MSG:
{
/*
* There are no input ports to this node
*/
OSCL_ASSERT(false);
}
break;
case PVMF_PORT_ACTIVITY_OUTGOING_QUEUE_BUSY:
{
/*
* This implies that this output port cannot accept any more
* msgs on its outgoing queue. This implies that we should stop
* retrieving samples from file to queue.
*/
PVAACFFNodeTrackPortInfo* trackInfoPtr = NULL;
if (!GetTrackInfo(aActivity.iPort, trackInfoPtr))
{
ReportErrorEvent(PVMFErrPortProcessing, (OsclAny*)(aActivity.iPort));
PVMF_AACPARSERNODE_LOGERROR((0, "0x%x PVMFAACFFParserNode::HandlePortActivity: Error - GetTrackInfo failed", this));
return;
}
trackInfoPtr->oQueueOutgoingMessages = false;
}
break;
case PVMF_PORT_ACTIVITY_OUTGOING_QUEUE_READY:
{
/*
* Outgoing queue was previously busy, but is now ready.
* We are ready to send new samples from file.
*/
PVAACFFNodeTrackPortInfo* trackInfoPtr = NULL;
if (!GetTrackInfo(aActivity.iPort, trackInfoPtr))
{
ReportErrorEvent(PVMFErrPortProcessing, (OsclAny*)(aActivity.iPort));
PVMF_AACPARSERNODE_LOGERROR((0, "0x%x PVMFAACFFParserNode::HandlePortActivity: Error - GetTrackInfo failed", this));
return;
}
trackInfoPtr->oQueueOutgoingMessages = true;
RunIfNotReady();
}
break;
case PVMF_PORT_ACTIVITY_CONNECTED_PORT_BUSY:
{
/*
* The connected port has become busy (its incoming queue is
* busy). There is nothing to do but to wait for connected port
* ready.
*/
PVAACFFNodeTrackPortInfo* trackInfoPtr = NULL;
if (!GetTrackInfo(aActivity.iPort, trackInfoPtr))
{
ReportErrorEvent(PVMFErrPortProcessing, (OsclAny*)(aActivity.iPort));
PVMF_AACPARSERNODE_LOGERROR((0, "0x%x PVMFAACFFParserNode::HandlePortActivity: Error - GetTrackInfo failed", this));
return;
}
trackInfoPtr->oProcessOutgoingMessages = false;
}
break;
case PVMF_PORT_ACTIVITY_CONNECTED_PORT_READY:
{
/*
* The connected port has transitioned from Busy to Ready.
* It's time to start sending messages again.
*/
PVAACFFNodeTrackPortInfo* trackInfoPtr = NULL;
if (!GetTrackInfo(aActivity.iPort, trackInfoPtr))
{
ReportErrorEvent(PVMFErrPortProcessing, (OsclAny*)(aActivity.iPort));
PVMF_AACPARSERNODE_LOGERROR((0, "0x%x PVMFAACFFParserNode::HandlePortActivity: Error - GetTrackInfo failed", this));
return;
}
trackInfoPtr->oProcessOutgoingMessages = true;
RunIfNotReady();
}
break;
default:
break;
}
}
PVMFCommandId PVMFAACFFParserNode::QueueCommandL(PVMFAACFFParserNodeCommand& aCmd)
{
if (IsAdded())
{
PVMFCommandId id;
id = iInputCommands.AddL(aCmd);
/* Wakeup the AO */
RunIfNotReady();
return id;
}
OSCL_LEAVE(OsclErrInvalidState);
return -1;
}
/**
//A routine to tell if a flush operation is in progress.
*/
bool PVMFAACFFParserNode::FlushPending()
{
return (iCurrentCommand.size() > 0
&& iCurrentCommand.front().iCmd == PVMF_AAC_PARSER_NODE_FLUSH);
}
/**
//Called by the command handler AO to process a command from
//the input queue.
//Return true if a command was processed, false if the command
//processor is busy and can't process another command now.
*/
void PVMFAACFFParserNode::ProcessCommand()
{
//This call will process the first node command in the input queue.
//Can't do anything when an asynchronous cancel is in progress-- just
//need to wait on completion.
if (!iCancelCommand.empty())
{
return; //keep waiting.
}
//If a command is in progress, only a hi-pri command can interrupt it.
if (!iCurrentCommand.empty()
&& !iInputCommands.front().hipri() && iInputCommands.front().iCmd != PVMF_AAC_PARSER_NODE_CANCEL_GET_LICENSE)
{
return; //keep waiting
}
//The newest or highest pri command is in the front of the queue.
OSCL_ASSERT(!iInputCommands.empty());
PVMFAACFFParserNodeCommand& aCmd = iInputCommands.front();
PVMFStatus cmdstatus;
OsclAny* eventdata = NULL;
if (aCmd.hipri() || aCmd.iCmd == PVMF_AAC_PARSER_NODE_CANCEL_GET_LICENSE)
{
//Process the Hi-Pri commands.
switch (aCmd.iCmd)
{
case PVMF_AAC_PARSER_NODE_CANCELALLCOMMANDS:
DoCancelAllCommands(aCmd);
break;
case PVMF_AAC_PARSER_NODE_CANCELCOMMAND:
DoCancelCommand(aCmd);
break;
case PVMF_AAC_PARSER_NODE_CANCEL_GET_LICENSE:
DoCancelGetLicense(aCmd);
break;
default:
OSCL_ASSERT(false);
CommandComplete(iInputCommands, aCmd, PVMFErrNotSupported);
break;
}
}
else
{
//Process the normal pri commands.
switch (aCmd.iCmd)
{
case PVMF_AAC_PARSER_NODE_QUERYUUID:
DoQueryUuid(aCmd);
break;
case PVMF_AAC_PARSER_NODE_QUERYINTERFACE:
DoQueryInterface(aCmd);
break;
case PVMF_AAC_PARSER_NODE_REQUESTPORT:
{
PVMFPortInterface*port;
DoRequestPort(aCmd, port);
eventdata = (OsclAny*)port;
}
break;
case PVMF_AAC_PARSER_NODE_RELEASEPORT:
DoReleasePort(aCmd);
break;
case PVMF_AAC_PARSER_NODE_INIT:
DoInit(aCmd);
break;
case PVMF_AAC_PARSER_NODE_PREPARE:
DoPrepare(aCmd);
break;
case PVMF_AAC_PARSER_NODE_START:
DoStart(aCmd);
break;
case PVMF_AAC_PARSER_NODE_STOP:
DoStop(aCmd);
break;
case PVMF_AAC_PARSER_NODE_FLUSH:
DoFlush(aCmd);
break;
case PVMF_AAC_PARSER_NODE_PAUSE:
DoPause(aCmd);
break;
case PVMF_AAC_PARSER_NODE_RESET:
DoReset(aCmd);
break;
case PVMF_AAC_PARSER_NODE_GETNODEMETADATAKEYS:
{
cmdstatus = DoGetMetadataKeys(aCmd);
if (cmdstatus != PVMFPending)
{
CommandComplete(iInputCommands, aCmd, cmdstatus);
}
else
{
MoveCmdToCurrentQueue(aCmd);
}
}
break;
case PVMF_AAC_PARSER_NODE_GETNODEMETADATAVALUES:
{
cmdstatus = DoGetMetadataValues(aCmd);
if (cmdstatus != PVMFPending)
{
CommandComplete(iInputCommands, aCmd, cmdstatus);
}
else
{
MoveCmdToCurrentQueue(aCmd);
}
}
break;
case PVMF_AAC_PARSER_NODE_SET_DATASOURCE_POSITION:
{
cmdstatus = DoSetDataSourcePosition(aCmd);
if (cmdstatus != PVMFPending)
{
CommandComplete(iInputCommands, aCmd, cmdstatus);
}
else
{
MoveCmdToCurrentQueue(aCmd);
}
}
break;
case PVMF_AAC_PARSER_NODE_QUERY_DATASOURCE_POSITION:
{
cmdstatus = DoQueryDataSourcePosition(aCmd);
if (cmdstatus != PVMFPending)
{
CommandComplete(iInputCommands, aCmd, cmdstatus);
}
else
{
MoveCmdToCurrentQueue(aCmd);
}
}
break;
case PVMF_AAC_PARSER_NODE_SET_DATASOURCE_RATE:
cmdstatus = DoSetDataSourceRate(aCmd);
if (cmdstatus != PVMFPending)
{
CommandComplete(iInputCommands, aCmd, cmdstatus);
}
else
{
MoveCmdToCurrentQueue(aCmd);
}
break;
case PVMF_AAC_PARSER_NODE_GET_LICENSE_W:
{
PVMFStatus status = DoGetLicense(aCmd, true);
if (status == PVMFPending)
{
MoveCmdToCurrentQueue(aCmd);
}
else
{
CommandComplete(iInputCommands, aCmd, status);
}
}
break;
case PVMF_AAC_PARSER_NODE_GET_LICENSE:
{
PVMFStatus status = DoGetLicense(aCmd);
if (status == PVMFPending)
{
MoveCmdToCurrentQueue(aCmd);
}
else
{
CommandComplete(iInputCommands, aCmd, status);
}
}
break;
default:
OSCL_ASSERT(false);
CommandComplete(iInputCommands, aCmd, PVMFErrNotSupported);
break;
}
}
}
PVMFStatus PVMFAACFFParserNode::ProcessOutgoingMsg(PVAACFFNodeTrackPortInfo* aTrackInfoPtr)
{
//Called by the AO to process one message off the outgoing
//message queue for the given port. This routine will
//try to send the data to the connected port.
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::ProcessOutgoingMsg() Called aPort=0x%x", aTrackInfoPtr->iPort));
PVMFStatus status = aTrackInfoPtr->iPort->Send();
if (status == PVMFErrBusy)
{
/* Connected port is busy */
aTrackInfoPtr->oProcessOutgoingMessages = false;
PVMF_AACPARSERNODE_LOGDATATRAFFIC((0, "PVMFAACParserNode::ProcessOutgoingMsg() Connected port is in busy state"));
}
else if (status != PVMFSuccess)
{
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACParserNode::ProcessOutgoingMsg() - aTrackInfoPtr->iPort->Send() Failed"));
}
return status;
}
void PVMFAACFFParserNode::DoCancelAllCommands(PVMFAACFFParserNodeCommand& aCmd)
{
//first cancel the current command if any
while (!iCurrentCommand.empty())
{
MoveCmdToCancelQueue(aCmd);
// CommandComplete(iCurrentCommand,iCurrentCommand[0],PVMFErrCancelled);
}
//next cancel all queued commands
//start at element 1 since this cancel command is element 0.
while (iInputCommands.size() > 1)
{
CommandComplete(iInputCommands, iInputCommands[1], PVMFErrCancelled);
}
//finally, report cancel complete.
CommandComplete(iInputCommands, iInputCommands[0], PVMFSuccess);
return;
}
/**
//Called by the command handler AO to do the Cancel single command
*/
void PVMFAACFFParserNode::DoCancelCommand(PVMFAACFFParserNodeCommand& aCmd)
{
//extract the command ID from the parameters.
PVMFCommandId id;
aCmd.PVMFAACFFParserNodeCommandBase::Parse(id);
//first check "current" command if any
PVMFAACFFParserNodeCommand* cmd = iCurrentCommand.FindById(id);
if (cmd)
{
MoveCmdToCancelQueue(*cmd);
CommandComplete(iCurrentCommand, *cmd, PVMFErrCancelled);
return;
}
//next check input queue.
//start at element 1 since this cancel command is element 0.
cmd = iInputCommands.FindById(id, 1);
if (cmd)
{
//cancel the queued command
CommandComplete(iInputCommands, *cmd, PVMFErrCancelled);
//report cancel success
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
return;
}
//if we get here the command isn't queued so the cancel fails.
CommandComplete(iInputCommands, aCmd, PVMFErrArgument);
}
void PVMFAACFFParserNode::DoFlush(PVMFAACFFParserNodeCommand& aCmd)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::DoFlushNode() Called"));
if (iInterfaceState != EPVMFNodeStarted &&
iInterfaceState != EPVMFNodePaused)
{
CommandComplete(iInputCommands, aCmd, PVMFErrInvalidState);
return;
}
/*
* the flush is asynchronous. move the command from
* the input command queue to the current command, where
* it will remain until the flush completes.
*/
MoveCmdToCurrentQueue(aCmd);
return;
}
void PVMFAACFFParserNode::DoReleasePort(PVMFAACFFParserNodeCommand& aCmd)
{
//This node supports release port from any state
//Find the port in the port vector
PVMFPortInterface* p = NULL;
aCmd.PVMFAACFFParserNodeCommandBase::Parse(p);
PVMFAACFFParserOutPort* port = (PVMFAACFFParserOutPort*)p;
if (iOutPort == port)
{
iTrack.iMediaData.Unbind();
OSCL_DELETE(((PVMFAACFFParserOutPort*)iTrack.iPort));
iTrack.iPort = NULL;
iOutPort = NULL;
ReleaseTrack();
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
return;
}
else
{
//port not found.
CommandComplete(iInputCommands, aCmd, PVMFFailure);
return;
}
}
void PVMFAACFFParserNode::DoQueryUuid(PVMFAACFFParserNodeCommand& aCmd)
{
//This node supports Query UUID from any state
OSCL_String* mimetype;
Oscl_Vector<PVUuid, OsclMemAllocator> *uuidvec;
bool exactmatch;
aCmd.PVMFAACFFParserNodeCommandBase::Parse(mimetype, uuidvec, exactmatch);
if (*mimetype == PVMF_DATA_SOURCE_INIT_INTERFACE_MIMETYPE)
{
PVUuid uuid(PVMF_DATA_SOURCE_INIT_INTERFACE_UUID);
uuidvec->push_back(uuid);
}
else if (*mimetype == PVMF_TRACK_SELECTION_INTERFACE_MIMETYPE)
{
PVUuid uuid(PVMF_TRACK_SELECTION_INTERFACE_UUID);
uuidvec->push_back(uuid);
}
else if (*mimetype == PVMF_DATA_SOURCE_PLAYBACK_CONTROL_INTERFACE_MIMETYPE)
{
PVUuid uuid(PvmfDataSourcePlaybackControlUuid);
uuidvec->push_back(uuid);
}
else if (*mimetype == PVMF_META_DATA_EXTENSION_INTERFACE_MIMETYPE)
{
PVUuid uuid(KPVMFMetadataExtensionUuid);
uuidvec->push_back(uuid);
}
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
return;
}
void PVMFAACFFParserNode::DoQueryInterface(PVMFAACFFParserNodeCommand& aCmd)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::DoQueryInterface() Called"));
PVUuid* uuid;
PVInterface** ptr;
aCmd.PVMFAACFFParserNodeCommandBase::Parse(uuid, ptr);
if (queryInterface(*uuid, *ptr))
{
(*ptr)->addRef();
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
}
else
{
//not supported
*ptr = NULL;
CommandComplete(iInputCommands, aCmd, PVMFErrNotSupported);
}
}
void PVMFAACFFParserNode::addRef()
{
++iExtensionRefCount;
}
void PVMFAACFFParserNode::removeRef()
{
--iExtensionRefCount;
}
PVMFStatus PVMFAACFFParserNode::QueryInterfaceSync(PVMFSessionId aSession,
const PVUuid& aUuid,
PVInterface*& aInterfacePtr)
{
OSCL_UNUSED_ARG(aSession);
aInterfacePtr = NULL;
if (queryInterface(aUuid, aInterfacePtr))
{
aInterfacePtr->addRef();
return PVMFSuccess;
}
return PVMFErrNotSupported;
}
bool PVMFAACFFParserNode::queryInterface(const PVUuid& uuid, PVInterface*& iface)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::queryInterface called"));
if (uuid == PVMF_DATA_SOURCE_INIT_INTERFACE_UUID)
{
PVMFDataSourceInitializationExtensionInterface* myInterface = OSCL_STATIC_CAST(PVMFDataSourceInitializationExtensionInterface*, this);
iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
}
else if (uuid == PVMF_TRACK_SELECTION_INTERFACE_UUID)
{
PVMFTrackSelectionExtensionInterface* myInterface = OSCL_STATIC_CAST(PVMFTrackSelectionExtensionInterface*, this);
iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
}
else if (uuid == KPVMFMetadataExtensionUuid)
{
PVMFMetadataExtensionInterface* myInterface = OSCL_STATIC_CAST(PVMFMetadataExtensionInterface*, this);
iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
}
else if (uuid == PvmfDataSourcePlaybackControlUuid)
{
PvmfDataSourcePlaybackControlInterface* myInterface = OSCL_STATIC_CAST(PvmfDataSourcePlaybackControlInterface*, this);
iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
}
else if (uuid == PVMIDatastreamuserInterfaceUuid)
{
PVMIDatastreamuserInterface* myInterface = OSCL_STATIC_CAST(PVMIDatastreamuserInterface*, this);
iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
}
else if (uuid == PVMF_FF_PROGDOWNLOAD_SUPPORT_INTERFACE_UUID)
{
PVMFFormatProgDownloadSupportInterface* myInterface = OSCL_STATIC_CAST(PVMFFormatProgDownloadSupportInterface*, this);
iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
}
else if (uuid == PVMFCPMPluginLicenseInterfaceUuid)
{
PVMFCPMPluginLicenseInterface* myInterface = OSCL_STATIC_CAST(PVMFCPMPluginLicenseInterface*, this);
iface = OSCL_STATIC_CAST(PVInterface*, myInterface);
}
else
{
return false;
}
return true;
}
PVMFStatus PVMFAACFFParserNode::SetSourceInitializationData(OSCL_wString& aSourceURL, PVMFFormatType& aSourceFormat, OsclAny* aSourceData)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::SetSourceInitializationData called"));
if (aSourceFormat == PVMF_MIME_AACFF)
{
/* Clean up any previous sources */
CleanupFileSource();
iSourceFormat = aSourceFormat;
iSourceURL = aSourceURL;
if (aSourceData)
{
// Old context object? query for local datasource availability
PVInterface* pvInterface =
OSCL_STATIC_CAST(PVInterface*, aSourceData);
PVInterface* localDataSrc = NULL;
PVUuid localDataSrcUuid(PVMF_LOCAL_DATASOURCE_UUID);
if (pvInterface->queryInterface(localDataSrcUuid, localDataSrc))
{
PVMFLocalDataSource* context =
OSCL_STATIC_CAST(PVMFLocalDataSource*, localDataSrc);
iPreviewMode = context->iPreviewMode;
if (context->iFileHandle)
{
PVMF_AAC_PARSER_NODE_NEW(NULL,
OsclFileHandle,
(*(context->iFileHandle)),
iFileHandle);
iCPMSourceData.iFileHandle = iFileHandle;
}
iCPMSourceData.iPreviewMode = iPreviewMode;
iCPMSourceData.iIntent = context->iIntent;
}
else
{
// New context object ?
PVInterface* sourceDataContext = NULL;
PVInterface* commonDataContext = NULL;
PVUuid sourceContextUuid(PVMF_SOURCE_CONTEXT_DATA_UUID);
PVUuid commonContextUuid(PVMF_SOURCE_CONTEXT_DATA_COMMON_UUID);
if (pvInterface->queryInterface(sourceContextUuid, sourceDataContext) &&
sourceDataContext->queryInterface(commonContextUuid, commonDataContext))
{
PVMFSourceContextDataCommon* context =
OSCL_STATIC_CAST(PVMFSourceContextDataCommon*, commonDataContext);
iPreviewMode = context->iPreviewMode;
if (context->iFileHandle)
{
PVMF_AAC_PARSER_NODE_NEW(NULL,
OsclFileHandle,
(*(context->iFileHandle)),
iFileHandle);
iCPMSourceData.iFileHandle = iFileHandle;
}
iCPMSourceData.iPreviewMode = iPreviewMode;
iCPMSourceData.iIntent = context->iIntent;
}
}
}
/*
* create a CPM object here...
*/
iUseCPMPluginRegistry = true;
{
//cleanup any prior instance
if (iCPM)
{
iCPM->ThreadLogoff();
PVMFCPMFactory::DestroyContentPolicyManager(iCPM);
iCPM = NULL;
}
iCPM = PVMFCPMFactory::CreateContentPolicyManager(*this);
//thread logon may leave if there are no plugins
int32 err;
OSCL_TRY(err, iCPM->ThreadLogon(););
OSCL_FIRST_CATCH_ANY(err,
iCPM->ThreadLogoff();
PVMFCPMFactory::DestroyContentPolicyManager(iCPM);
iCPM = NULL;
iUseCPMPluginRegistry = false;
);
}
return PVMFSuccess;
}
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACParserNode::SetSourceInitializationData - Unsupported Format"));
return PVMFFailure;
}
PVMFStatus PVMFAACFFParserNode::SetClientPlayBackClock(PVMFMediaClock* aClientClock)
{
OSCL_UNUSED_ARG(aClientClock);
return PVMFSuccess;
}
PVMFStatus PVMFAACFFParserNode::SetEstimatedServerClock(PVMFMediaClock* aClientClock)
{
OSCL_UNUSED_ARG(aClientClock);
return PVMFSuccess;
}
//From PVMFTrackSelectionExtensionInterface
PVMFStatus PVMFAACFFParserNode::GetMediaPresentationInfo(PVMFMediaPresentationInfo& aInfo)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFAACFFParserNode::GetMediaPresentationInfo() called"));
// Check to make sure the AAC file has been parsed
if (!iAACParser) return PVMFFailure;
aInfo.setDurationValue(iAACFileInfo.iDuration);
// Current version of AAC parser is limited to 1 channel
PVMFTrackInfo tmpTrackInfo;
// set the port tag for this track
tmpTrackInfo.setPortTag(PVMF_AAC_PARSER_NODE_PORT_TYPE_SOURCE);
// track id
tmpTrackInfo.setTrackID(0);
TPVAacFileInfo aacinfo;
if (!iAACParser->RetrieveFileInfo(aacinfo)) return PVMFErrNotSupported;
// bitrate
tmpTrackInfo.setTrackBitRate(aacinfo.iBitrate);
// timescale
tmpTrackInfo.setTrackDurationTimeScale((uint64)aacinfo.iTimescale);
// config info
// mime type
OSCL_FastString mime_type;
switch (aacinfo.iFormat)
{
case EAACADIF:
case EAACRaw:
mime_type = PVMF_MIME_ADIF;
break;
case EAACADTS:
mime_type = PVMF_MIME_MPEG4_AUDIO;
break;
default:
mime_type = "";
break;
}
tmpTrackInfo.setTrackMimeType(mime_type);
OsclRefCounterMemFrag config;
PVAACFFNodeTrackPortInfo trackPortInfo;
if (!RetrieveTrackConfigInfo(trackPortInfo))
{
return PVMFFailure;
}
config = trackPortInfo.iFormatSpecificConfig;
tmpTrackInfo.setTrackConfigInfo(config);
// add the track
aInfo.addTrackInfo(tmpTrackInfo);
return PVMFSuccess;
}
PVMFStatus PVMFAACFFParserNode::SelectTracks(PVMFMediaPresentationInfo& aInfo)
{
OSCL_UNUSED_ARG(aInfo);
return PVMFSuccess;
}
PVMFStatus PVMFAACFFParserNode::DoGetMetadataKeys(PVMFAACFFParserNodeCommand& aCmd)
{
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFAACFFParserNode::DoGetMetadataKeys() In"));
/* Get Metadata keys from CPM for protected content only */
if ((iCPMMetaDataExtensionInterface != NULL))
{
GetCPMMetaDataKeys();
return PVMFPending;
}
return (CompleteGetMetadataKeys(aCmd));
}
PVMFStatus
PVMFAACFFParserNode::CompleteGetMetadataKeys(PVMFAACFFParserNodeCommand& aCmd)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::CompleteGetMetadataKeys Called"));
// File must be parsed
if (!iAACParser)
{
return PVMFErrInvalidState;
}
PVMFMetadataList* keylistptr = NULL;
uint32 starting_index;
int32 max_entries;
char* query_key = NULL;
aCmd.PVMFAACFFParserNodeCommand::Parse(keylistptr, starting_index, max_entries, query_key);
// Check parameters
if (keylistptr == NULL)
{
// The list pointer is invalid
return PVMFErrArgument;
}
if ((starting_index > (iAvailableMetadataKeys.size() - 1)) || max_entries == 0)
{
// Invalid starting index and/or max entries
return PVMFErrArgument;
}
// Copy the requested keys
uint32 num_entries = 0;
int32 num_added = 0;
uint32 lcv = 0;
for (lcv = 0; lcv < iAvailableMetadataKeys.size(); lcv++)
{
if (query_key == NULL)
{
// No query key so this key is counted
++num_entries;
if (num_entries > starting_index)
{
// Past the starting index so copy the key
PVMFStatus status = PushValueToList(iAvailableMetadataKeys, keylistptr, lcv);
if (PVMFErrNoMemory == status)
{
return status;
}
num_added++;
}
}
else
{
// Check if the key matche the query key
if (pv_mime_strcmp(iAvailableMetadataKeys[lcv].get_cstr(), query_key) >= 0)
{
// This key is counted
++num_entries;
if (num_entries > starting_index)
{
// Past the starting index so copy the key
PVMFStatus status = PushValueToList(iAvailableMetadataKeys, keylistptr, lcv);
if (PVMFErrNoMemory == status)
{
return status;
}
num_added++;
}
}
}
// Check if max number of entries have been copied
if (max_entries > 0 && num_added >= max_entries)
{
break;
}
}
for (lcv = 0; lcv < iCPMMetadataKeys.size(); lcv++)
{
if (query_key == NULL)
{
/* No query key so this key is counted */
++num_entries;
if (num_entries > (uint32)starting_index)
{
/* Past the starting index so copy the key */
PVMFStatus status = PushValueToList(iCPMMetadataKeys, keylistptr, lcv);
if (PVMFErrNoMemory == status)
{
return status;
}
num_added++;
}
}
else
{
/* Check if the key matches the query key */
if (pv_mime_strcmp(iCPMMetadataKeys[lcv].get_cstr(), query_key) >= 0)
{
/* This key is counted */
++num_entries;
if (num_entries > (uint32)starting_index)
{
/* Past the starting index so copy the key */
PVMFStatus status = PushValueToList(iCPMMetadataKeys, keylistptr, lcv);
if (PVMFErrNoMemory == status)
{
return status;
}
num_added++;
}
}
}
/* Check if max number of entries have been copied */
if ((max_entries > 0) && (num_added >= max_entries))
{
break;
}
}
return PVMFSuccess;
}
void PVMFAACFFParserNode::ReleaseMetadataValue(PvmiKvp& aValueKVP)
{
switch (GetValTypeFromKeyString(aValueKVP.key))
{
case PVMI_KVPVALTYPE_CHARPTR:
if (aValueKVP.value.pChar_value != NULL)
{
OSCL_ARRAY_DELETE(aValueKVP.value.pChar_value);
aValueKVP.value.pChar_value = NULL;
}
break;
case PVMI_KVPVALTYPE_WCHARPTR:
if (aValueKVP.value.pWChar_value != NULL)
{
OSCL_ARRAY_DELETE(aValueKVP.value.pWChar_value);
aValueKVP.value.pWChar_value = NULL;
}
break;
default:
// Add more case statements if other value types are returned
break;
}
OSCL_ARRAY_DELETE(aValueKVP.key);
aValueKVP.key = NULL;
}
PVMFStatus PVMFAACFFParserNode::DoGetMetadataValues(PVMFAACFFParserNodeCommand& aCmd)
{
int32 leavecode = 0;
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::DoGetMetaDataValues Called"));
// File must be parsed
if (!iAACParser)
{
return PVMFErrInvalidState;
}
PVMFMetadataList* keylistptr_in = NULL;
PVMFMetadataList* keylistptr = NULL;
Oscl_Vector<PvmiKvp, OsclMemAllocator>* valuelistptr = NULL;
uint32 starting_index;
int32 max_entries;
aCmd.PVMFAACFFParserNodeCommand::Parse(keylistptr_in, valuelistptr, starting_index, max_entries);
// Check the parameters
if (keylistptr_in == NULL || valuelistptr == NULL)
{
return PVMFErrArgument;
}
keylistptr = keylistptr_in;
//If numkeys is one, just check to see if the request
//is for ALL metadata
if (keylistptr_in->size() == 1)
{
if (oscl_strncmp((*keylistptr)[0].get_cstr(),
PVAAC_ALL_METADATA_KEY,
oscl_strlen(PVAAC_ALL_METADATA_KEY)) == 0)
{
//use the complete metadata key list
keylistptr = &iAvailableMetadataKeys;
}
}
uint32 numkeys = keylistptr->size();
if (starting_index > (numkeys - 1) || numkeys <= 0 || max_entries == 0)
{
// Don't do anything
return PVMFErrArgument;
}
uint32 numvalentries = 0;
int32 numentriesadded = 0;
uint32 lcv = 0;
PvmiKvpSharedPtrVector iFrame;
//add ID3 Data
for (lcv = 0; lcv < numkeys; lcv++)
{
iAACParser->GetID3Frame((*keylistptr)[lcv], iFrame);
if (iFrame.size() > 0)
{
PvmiKvp KeyVal;
KeyVal.key = NULL;
KeyVal.length = 0;
char *key = (*(iFrame.back())).key;
int32 len = (*(iFrame.back())).length;
++numvalentries;
leavecode = CreateNewArray(KeyVal.key, key);
oscl_strncpy(KeyVal.key , key, oscl_strlen(key) + 1);
KeyVal.length = len;
KeyVal.capacity = (*(iFrame.back())).capacity;
PvmiKvpValueType ValueType = GetValTypeFromKeyString(key);
switch (ValueType)
{
case PVMI_KVPVALTYPE_WCHARPTR:
leavecode = CreateNewArray(KeyVal.value.pWChar_value, len);
oscl_strncpy(KeyVal.value.pWChar_value , (*(iFrame.back())).value.pWChar_value, len);
break;
case PVMI_KVPVALTYPE_CHARPTR:
leavecode = CreateNewArray(KeyVal.value.pChar_value, len);
oscl_strncpy(KeyVal.value.pChar_value , (*(iFrame.back())).value.pChar_value, len);
break;
case PVMI_KVPVALTYPE_UINT32:
KeyVal.value.uint32_value = (*(iFrame.back())).value.uint32_value;
break;
default:
break;
}
leavecode = PushBackKeyVal(valuelistptr, KeyVal);
OSCL_FIRST_CATCH_ANY(leavecode, ReleaseMetadataValue(KeyVal);
break;);
++numentriesadded;
iFrame.pop_back();
}
}
//add rest of the data
for (lcv = 0; lcv < numkeys; lcv++)
{
int32 leavecode = 0;
PvmiKvp KeyVal;
KeyVal.key = NULL;
if (!oscl_strcmp((*keylistptr)[lcv].get_cstr(), PVAACMETADATA_DURATION_KEY) &&
iAACFileInfo.iDuration > 0)
{
// Duration
// Increment the counter for the number of values found so far
++numvalentries;
// Create a value entry if past the starting index
if (numvalentries > starting_index)
{
uint32 duration = (uint32)iAACFileInfo.iDuration;
PVMFStatus retval =
PVMFCreateKVPUtils::CreateKVPForUInt32Value(KeyVal,
PVAACMETADATA_DURATION_KEY,
duration,
(char *)PVAACMETADATA_TIMESCALE1000);
if (retval != PVMFSuccess && retval != PVMFErrArgument)
{
break;
}
}
}
else if (!oscl_strcmp((*keylistptr)[lcv].get_cstr(), PVAACMETADATA_RANDOM_ACCESS_DENIED_KEY))
{
/*
* Random Access
* Increment the counter for the number of values found so far
*/
++numvalentries;
/* Create a value entry if past the starting index */
if (numvalentries > (uint32)starting_index)
{
bool random_access_denied = false;
if (iAACFileInfo.iFormat == EAACADIF || iAACFileInfo.iFormat == EAACRaw)
{
random_access_denied = true;
}
PVMFStatus retval =
PVMFCreateKVPUtils::CreateKVPForBoolValue(KeyVal,
PVAACMETADATA_RANDOM_ACCESS_DENIED_KEY,
random_access_denied,
NULL);
if (retval != PVMFSuccess && retval != PVMFErrArgument)
{
break;
}
}
}
else if (!oscl_strcmp((*keylistptr)[lcv].get_cstr(), PVAACMETADATA_NUMTRACKS_KEY))
{
// Number of tracks
// Increment the counter for the number of values found so far
++numvalentries;
// Create a value entry if past the starting index
if (numvalentries > starting_index)
{
uint32 numtracksuint32 = 1;
PVMFStatus retval = PVMFCreateKVPUtils::CreateKVPForUInt32Value(KeyVal,
PVAACMETADATA_NUMTRACKS_KEY,
numtracksuint32,
NULL);
if (retval != PVMFSuccess && retval != PVMFErrArgument)
{
break;
}
}
}
else if ((oscl_strcmp((*keylistptr)[lcv].get_cstr(), PVAACMETADATA_TRACKINFO_BITRATE_KEY) == 0) &&
iAACFileInfo.iBitrate > 0)
{
// Bitrate
// Increment the counter for the number of values found so far
++numvalentries;
// Create a value entry if past the starting index
if (numvalentries > starting_index)
{
uint32 bitRate = (uint32)iAACFileInfo.iBitrate;
PVMFStatus retval = PVMFCreateKVPUtils::CreateKVPForUInt32Value(KeyVal,
PVAACMETADATA_TRACKINFO_BITRATE_KEY,
bitRate,
NULL);
if (retval != PVMFSuccess && retval != PVMFErrArgument)
{
break;
}
}
}
else if ((oscl_strcmp((*keylistptr)[lcv].get_cstr(), PVAACMETADATA_TRACKINFO_SAMPLERATE_KEY) == 0) &&
iAACFileInfo.iSampleFrequency > 0)
{
// Sampling rate
// Increment the counter for the number of values found so far
++numvalentries;
// Create a value entry if past the starting index
if (numvalentries > starting_index)
{
uint32 sampleFreq = (uint32)iAACFileInfo.iSampleFrequency;
PVMFStatus retval = PVMFCreateKVPUtils::CreateKVPForUInt32Value(KeyVal,
PVAACMETADATA_TRACKINFO_BITRATE_KEY,
sampleFreq,
NULL);
if (retval != PVMFSuccess && retval != PVMFErrArgument)
{
break;
}
}
}
else if ((oscl_strcmp((*keylistptr)[lcv].get_cstr(), PVAACMETADATA_TRACKINFO_AUDIO_FORMAT_KEY) == 0) &&
iAACFileInfo.iFormat != EAACUnrecognized)
{
// Format
// Increment the counter for the number of values found so far
++numvalentries;
// Create a value entry if past the starting index
if (numvalentries > starting_index)
{
PVMFStatus retval = PVMFSuccess;
switch (iAACFileInfo.iFormat)
{
case EAACADTS:
retval = PVMFCreateKVPUtils::CreateKVPForCharStringValue(KeyVal,
PVAACMETADATA_TRACKINFO_AUDIO_FORMAT_KEY,
_STRLIT_CHAR(PVMF_MIME_ADTS));
break;
case EAACADIF:
retval = PVMFCreateKVPUtils::CreateKVPForCharStringValue(KeyVal,
PVAACMETADATA_TRACKINFO_AUDIO_FORMAT_KEY,
_STRLIT_CHAR(PVMF_MIME_ADIF));
break;
case EAACRaw:
retval = PVMFCreateKVPUtils::CreateKVPForCharStringValue(KeyVal,
PVAACMETADATA_TRACKINFO_AUDIO_FORMAT_KEY,
_STRLIT_CHAR(PVMF_MIME_MPEG4_AUDIO));
break;
default:
break;
}
}
else
{
// Memory allocation failed so clean up
if (KeyVal.key)
{
OSCL_ARRAY_DELETE(KeyVal.key);
KeyVal.key = NULL;
}
if (KeyVal.value.pChar_value)
{
OSCL_ARRAY_DELETE(KeyVal.value.pChar_value);
}
break;
}
}
// Add the KVP to the list if the key string was created
if (KeyVal.key != NULL)
{
leavecode = PushBackKeyVal(valuelistptr, KeyVal);
OSCL_FIRST_CATCH_ANY(leavecode, ReleaseMetadataValue(KeyVal);
break;);
// Increment the counter for number of value entries added to the list
++numentriesadded;
// Check if the max number of value entries were added
if (max_entries > 0 && numentriesadded >= max_entries)
{
// Maximum number of values added so break out of the loop
break;
}
}
}
iAACParserNodeMetadataValueCount = (*valuelistptr).size();
if ((iCPMMetaDataExtensionInterface != NULL))
{
iCPMGetMetaDataValuesCmdId =
iCPMMetaDataExtensionInterface->GetNodeMetadataValues(iCPMSessionID,
(*keylistptr_in),
(*valuelistptr),
0);
return PVMFPending;
}
return PVMFSuccess;
}
PVMFStatus
PVMFAACFFParserNode::DoSetDataSourcePosition(PVMFAACFFParserNodeCommand& aCmd)
{
//file must be parsed
if (!iAACParser)
{
return PVMFErrInvalidState;
}
if (!iOutPort)
{
return PVMFErrInvalidState;
}
uint32 targetNPT = 0;
uint32* actualNPT = NULL;
uint32* actualMediaDataTS = NULL;
bool jumpToIFrame = false;
uint32 streamID = 0;
ResetAllTracks();
iFirstFrame = true;
aCmd.PVMFAACFFParserNodeCommand::Parse(targetNPT, actualNPT, actualMediaDataTS, jumpToIFrame, streamID);
// validate the parameters
if (actualNPT == NULL || actualMediaDataTS == NULL)
{
return PVMFErrArgument;
}
//store to send the BOS
iTrack.iSendBOS = true;
//save the stream id for next media segment
iStreamID = streamID;
*actualNPT = 0;
*actualMediaDataTS = 0;
int32 result;
// check if passed targetNPT is greater than or equal to clip duration.
if ((targetNPT >= (uint32)iAACFileInfo.iDuration) && (iAACFileInfo.iFormat != EAACRaw))
{
if (iAACFileInfo.iFormat == EAACADIF)
{
uint32 tmpuint32 = 0;
result = iAACParser->ResetPlayback(0, tmpuint32);
if (result != AACBitstreamObject::EVERYTHING_OK)
{
return PVMFErrResource;
}
// Adjust the offset so the timestamp after reposition would begin past the current position for sure
iTrack.iTimestampOffset += iAACFileInfo.iDuration;
// Reset the clock to time 0
iTrack.iClockConverter->set_clock(0, 0);
// Set the return parameters
*actualNPT = iAACFileInfo.iDuration;
*actualMediaDataTS = iTrack.iTimestampOffset;
iTrack.oEOSReached = true;
}
else
{
// Peek the next sample to get the duration of the last sample
uint32 timestamp;
result = iAACParser->PeekNextTimestamp(timestamp);
if (result != AACBitstreamObject::EVERYTHING_OK)
{
return PVMFErrResource;
}
uint32 millisecTS = iTrack.iClockConverter->get_converted_ts(1000);
*actualMediaDataTS = millisecTS;
// Reset the track to begining of clip.
uint32 tmpuint32 = 0;
result = iAACParser->ResetPlayback(0, tmpuint32);
if (result != AACBitstreamObject::EVERYTHING_OK)
{
return PVMFErrResource;
}
//Peek new position to get the actual new timestamp
uint32 newtimestamp;
result = iAACParser->PeekNextTimestamp(newtimestamp);
if (result != AACBitstreamObject::EVERYTHING_OK)
{
return PVMFErrResource;
}
*actualNPT = iAACFileInfo.iDuration;
//Adjust the offset to add to future timestamps.
iTrack.iTimestampOffset += (timestamp - newtimestamp);
MediaClockConverter mcc(1000);
uint32 delta = PVMF_AAC_PARSER_NODE_TS_DELTA_DURING_REPOS_IN_MS;
uint32 wrap_count = 0;
mcc.set_clock(delta, wrap_count);
uint32 deltaintimescale = mcc.get_converted_ts(iTrack.iClockConverter->get_timescale());
iTrack.iTimestampOffset += deltaintimescale;
iTrack.oEOSReached = true;
}
return PVMFSuccess;
}
if (iAACFileInfo.iFormat == EAACADIF)
{
// ADIF has no timestamp and repositioning is limited to beginning of file
// Reposition to time 0
uint32 tmpuint32 = 0;
result = iAACParser->ResetPlayback(0, tmpuint32);
if (result != AACBitstreamObject::EVERYTHING_OK)
{
return PVMFErrResource;
}
// Adjust the offset so the timestamp after reposition would begin past the current position for sure
iTrack.iTimestampOffset += iAACFileInfo.iDuration;
// Reset the clock to time 0
iTrack.iClockConverter->set_clock(0, 0);
// Set the return parameters
*actualNPT = 0;
*actualMediaDataTS = iTrack.iTimestampOffset;
PVMF_AACPARSERNODE_LOGDATATRAFFIC((0, "PVMFAACParserNode::DoSetDataSourcePosition - ADIF -targetNPT=%d, actualNPT=%d, actualMediaDataTS=%d",
targetNPT, *actualNPT, *actualMediaDataTS));
}
else if (iAACFileInfo.iFormat == EAACRaw)
{
// Raw AAC has no timestamp and repositioning is limited to beginning of file
// Reposition to time 0
uint32 tmpuint32 = 0;
result = iAACParser->ResetPlayback(0, tmpuint32);
if (result != AACBitstreamObject::EVERYTHING_OK)
{
return PVMFErrResource;
}
// Adjust the offset so the timestamp after reposition would begin past the current position for sure
// Since duration of raw AAC bitstream file is unknown use a hardcoded value of 1 hour
iTrack.iTimestampOffset += 3600000;
// Reset the clock to time 0
iTrack.iClockConverter->set_clock(0, 0);
// Set the return parameters
*actualNPT = 0;
*actualMediaDataTS = iTrack.iTimestampOffset;
PVMF_AACPARSERNODE_LOGDATATRAFFIC((0, "PVMFAACParserNode::DoSetDataSourcePosition - RAWAAC - targetNPT=%d, actualNPT=%d, actualMediaDataTS=%d",
targetNPT, *actualNPT, *actualMediaDataTS));
}
else
{
// The media data timestamp of the next sample will start from the maximum
// of timestamp on all selected tracks. This media data timestamp will
// correspond to the actual NPT.
// Peek the next sample to get the duration of the last sample
uint32 timestamp;
result = iAACParser->PeekNextTimestamp(timestamp);
if (result != AACBitstreamObject::EVERYTHING_OK)
{
return PVMFErrResource;
}
// Adjust the timestamp to the end of the last sample, i.e. adding the delta to next sample
// iTrack.iClockConverter->update_clock(timestamp);
uint32 millisecTS = iTrack.iClockConverter->get_converted_ts(1000);
*actualMediaDataTS = millisecTS;
// Reset the clock to this new starting point.
// iTrack.iClockConverter->set_clock(timestamp,0);
// Reposition
// If new position is past the end of clip, AAC FF should set the position to the last frame
uint32 tmpuint32 = 0;
result = iAACParser->ResetPlayback(targetNPT, tmpuint32);
if (result != AACBitstreamObject::EVERYTHING_OK)
{
if (AACBitstreamObject::END_OF_FILE == result)
{
uint32 timestamp;
result = iAACParser->PeekNextTimestamp(timestamp);
if (result != AACBitstreamObject::EVERYTHING_OK)
{
return PVMFErrResource;
}
// Adjust the timestamp to the end of the last sample, i.e. adding the delta to next sample
// iTrack.iClockConverter->update_clock(timestamp);
uint32 millisecTS = iTrack.iClockConverter->get_converted_ts(1000);
*actualMediaDataTS = millisecTS;
// Reset the track to begining of clip.
uint32 tmpuint32 = 0;
result = iAACParser->ResetPlayback(0, tmpuint32);
if (result != AACBitstreamObject::EVERYTHING_OK)
{
return PVMFErrResource;
}
//Peek new position to get the actual new timestamp
uint32 newtimestamp;
result = iAACParser->PeekNextTimestamp(newtimestamp);
if (result != AACBitstreamObject::EVERYTHING_OK)
{
return PVMFErrResource;
}
*actualNPT = newtimestamp;
//Adjust the offset to add to future timestamps.
iTrack.iTimestampOffset += (timestamp - newtimestamp);
MediaClockConverter mcc(1000);
uint32 delta = PVMF_AAC_PARSER_NODE_TS_DELTA_DURING_REPOS_IN_MS;
uint32 wrap_count = 0;
mcc.set_clock(delta, wrap_count);
uint32 deltaintimescale = mcc.get_converted_ts(iTrack.iClockConverter->get_timescale());
iTrack.iTimestampOffset += deltaintimescale;
iTrack.oEOSReached = true;
return PVMFSuccess;
}
else
{
return PVMFErrResource;
}
}
//Peek new position to get the actual new timestamp
uint32 newtimestamp;
result = iAACParser->PeekNextTimestamp(newtimestamp);
if (result != AACBitstreamObject::EVERYTHING_OK)
{
return PVMFErrResource;
}
*actualNPT = newtimestamp;
//Adjust the offset to add to future timestamps.
iTrack.iTimestampOffset += (timestamp - newtimestamp);
MediaClockConverter mcc(1000);
uint32 delta = PVMF_AAC_PARSER_NODE_TS_DELTA_DURING_REPOS_IN_MS;
uint32 wrap_count = 0;
mcc.set_clock(delta, wrap_count);
uint32 deltaintimescale = mcc.get_converted_ts(iTrack.iClockConverter->get_timescale());
iTrack.iTimestampOffset += deltaintimescale;
PVMF_AACPARSERNODE_LOGDATATRAFFIC((0, "PVMFAACParserNode::DoSetDataSourcePosition - ADTS - targetNPT=%d, actualNPT=%d, actualMediaDataTS=%d",
targetNPT, *actualNPT, *actualMediaDataTS));
}
return PVMFSuccess;
}
PVMFStatus PVMFAACFFParserNode::DoQueryDataSourcePosition(PVMFAACFFParserNodeCommand& aCmd)
{
//file must be parsed
if (!iAACParser)
{
return PVMFErrInvalidState;
}
if (!iOutPort)
{
return PVMFErrInvalidState;
}
uint32 targetNPT = 0;
uint32* actualNPT = NULL;
bool jumpToIFrame = false;
aCmd.PVMFAACFFParserNodeCommand::Parse(targetNPT, actualNPT, jumpToIFrame);
if (actualNPT == NULL)
{
return PVMFErrArgument;
}
*actualNPT = 0;
// Query
// If new position is past the end of clip, AAC FF should set the position to the last frame
*actualNPT = iAACParser->SeekPointFromTimestamp(targetNPT);
return PVMFSuccess;
}
PVMFStatus PVMFAACFFParserNode::DoSetDataSourceRate(PVMFAACFFParserNodeCommand& aCmd)
{
OSCL_UNUSED_ARG(aCmd);
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::DoSetDataSourceRate() In"));
return PVMFSuccess;
}
/* CPM related */
void PVMFAACFFParserNode::InitCPM()
{
iCPMInitCmdId = iCPM->Init();
}
void PVMFAACFFParserNode::OpenCPMSession()
{
iCPMOpenSessionCmdId = iCPM->OpenSession(iCPMSessionID);
}
void PVMFAACFFParserNode::CPMRegisterContent()
{
iCPMRegisterContentCmdId = iCPM->RegisterContent(iCPMSessionID,
iSourceURL,
iSourceFormat,
(OsclAny*) & iCPMSourceData);
}
void PVMFAACFFParserNode::GetCPMLicenseInterface()
{
iCPMLicenseInterfacePVI = NULL;
iCPMGetLicenseInterfaceCmdId =
iCPM->QueryInterface(iCPMSessionID,
PVMFCPMPluginLicenseInterfaceUuid,
iCPMLicenseInterfacePVI);
}
bool PVMFAACFFParserNode::GetCPMContentAccessFactory()
{
PVMFStatus status = iCPM->GetContentAccessFactory(iCPMSessionID,
iCPMContentAccessFactory);
if (status != PVMFSuccess)
{
return false;
}
return true;
}
bool PVMFAACFFParserNode::GetCPMMetaDataExtensionInterface()
{
PVInterface* temp = NULL;
bool retVal =
iCPM->queryInterface(KPVMFMetadataExtensionUuid, temp);
iCPMMetaDataExtensionInterface = OSCL_STATIC_CAST(PVMFMetadataExtensionInterface*, temp);
return retVal;
}
void PVMFAACFFParserNode::RequestUsage()
{
PopulateDRMInfo();
if (iDataStreamReadCapacityObserver != NULL)
{
iCPMContentAccessFactory->SetStreamReadCapacityObserver(iDataStreamReadCapacityObserver);
}
iCPMRequestUsageId = iCPM->ApproveUsage(iCPMSessionID,
iRequestedUsage,
iApprovedUsage,
iAuthorizationDataKvp,
iUsageID,
iCPMContentAccessFactory);
/** Logic for playing after acquired license */
oSourceIsCurrent = true;
}
void PVMFAACFFParserNode::PopulateDRMInfo()
{
/* Cleanup any old key */
if (iRequestedUsage.key)
{
OSCL_ARRAY_DELETE(iRequestedUsage.key);
iRequestedUsage.key = NULL;
}
if (iApprovedUsage.key)
{
OSCL_ARRAY_DELETE(iApprovedUsage.key);
iApprovedUsage.key = NULL;
}
if (iAuthorizationDataKvp.key)
{
OSCL_ARRAY_DELETE(iAuthorizationDataKvp.key);
iAuthorizationDataKvp.key = NULL;
}
if ((iCPMContentType == PVMF_CPM_FORMAT_OMA1) ||
(iCPMContentType == PVMF_CPM_FORMAT_AUTHORIZE_BEFORE_ACCESS))
{
int32 UseKeyLen = oscl_strlen(_STRLIT_CHAR(PVMF_CPM_REQUEST_USE_KEY_STRING));
int32 AuthKeyLen = oscl_strlen(_STRLIT_CHAR(PVMF_CPM_AUTHORIZATION_DATA_KEY_STRING));
int32 leavecode = 0;
OSCL_TRY(leavecode,
iRequestedUsage.key = OSCL_ARRAY_NEW(char, UseKeyLen + 1);
iApprovedUsage.key = OSCL_ARRAY_NEW(char, UseKeyLen + 1);
iAuthorizationDataKvp.key = OSCL_ARRAY_NEW(char, AuthKeyLen + 1);
);
if (leavecode || !iRequestedUsage.key || !iApprovedUsage.key || !iAuthorizationDataKvp.key)
{
if (iRequestedUsage.key)
{
OSCL_ARRAY_DELETE(iRequestedUsage.key);
iRequestedUsage.key = NULL;
}
if (iApprovedUsage.key)
{
OSCL_ARRAY_DELETE(iApprovedUsage.key);
iApprovedUsage.key = NULL;
}
if (iAuthorizationDataKvp.key)
{
OSCL_ARRAY_DELETE(iAuthorizationDataKvp.key);
iAuthorizationDataKvp.key = NULL;
}
return;
}
oscl_strncpy(iRequestedUsage.key,
_STRLIT_CHAR(PVMF_CPM_REQUEST_USE_KEY_STRING),
UseKeyLen);
iRequestedUsage.key[UseKeyLen] = 0;
iRequestedUsage.length = 0;
iRequestedUsage.capacity = 0;
if (iPreviewMode)
{
iRequestedUsage.value.uint32_value =
(BITMASK_PVMF_CPM_DRM_INTENT_PREVIEW |
BITMASK_PVMF_CPM_DRM_INTENT_PAUSE |
BITMASK_PVMF_CPM_DRM_INTENT_SEEK_FORWARD |
BITMASK_PVMF_CPM_DRM_INTENT_SEEK_BACK);
}
else
{
iRequestedUsage.value.uint32_value =
(BITMASK_PVMF_CPM_DRM_INTENT_PLAY |
BITMASK_PVMF_CPM_DRM_INTENT_PAUSE |
BITMASK_PVMF_CPM_DRM_INTENT_SEEK_FORWARD |
BITMASK_PVMF_CPM_DRM_INTENT_SEEK_BACK);
}
oscl_strncpy(iApprovedUsage.key,
_STRLIT_CHAR(PVMF_CPM_REQUEST_USE_KEY_STRING),
UseKeyLen);
iApprovedUsage.key[UseKeyLen] = 0;
iApprovedUsage.length = 0;
iApprovedUsage.capacity = 0;
iApprovedUsage.value.uint32_value = 0;
oscl_strncpy(iAuthorizationDataKvp.key,
_STRLIT_CHAR(PVMF_CPM_AUTHORIZATION_DATA_KEY_STRING),
AuthKeyLen);
iAuthorizationDataKvp.key[AuthKeyLen] = 0;
iAuthorizationDataKvp.length = 0;
iAuthorizationDataKvp.capacity = 0;
iAuthorizationDataKvp.value.pUint8_value = NULL;
}
else
{
//Error
OSCL_ASSERT(false);
}
}
void PVMFAACFFParserNode::SendUsageComplete()
{
iCPMUsageCompleteCmdId = iCPM->UsageComplete(iCPMSessionID, iUsageID);
}
void PVMFAACFFParserNode::CloseCPMSession()
{
iCPMCloseSessionCmdId = iCPM->CloseSession(iCPMSessionID);
}
void PVMFAACFFParserNode::ResetCPM()
{
iCPMResetCmdId = iCPM->Reset();
}
void PVMFAACFFParserNode::GetCPMMetaDataKeys()
{
if (iCPMMetaDataExtensionInterface != NULL)
{
iCPMMetadataKeys.clear();
iCPMGetMetaDataKeysCmdId =
iCPMMetaDataExtensionInterface->GetNodeMetadataKeys(iCPMSessionID,
iCPMMetadataKeys,
0,
PVMF_AAC_PARSER_NODE_MAX_CPM_METADATA_KEYS);
}
}
PVMFStatus
PVMFAACFFParserNode::CheckCPMCommandCompleteStatus(PVMFCommandId aID,
PVMFStatus aStatus)
{
PVMFStatus status = aStatus;
if (aID == iCPMGetLicenseInterfaceCmdId)
{
if (aStatus == PVMFErrNotSupported)
{
/* License Interface is Optional */
status = PVMFSuccess;
}
}
else if (aID == iCPMRegisterContentCmdId)
{
if (aStatus == PVMFErrNotSupported)
{
/* CPM doesnt care about this content */
status = PVMFErrNotSupported;
}
}
else if (aID == iCPMRequestUsageId)
{
if (iCPMSourceData.iIntent & BITMASK_PVMF_SOURCE_INTENT_GETMETADATA)
{
if (aStatus != PVMFSuccess)
{
/*
* If we are doing metadata only then we don't care
* if license is not available
*/
status = PVMFSuccess;
}
}
}
return status;
}
void PVMFAACFFParserNode::CPMCommandCompleted(const PVMFCmdResp& aResponse)
{
PVMFCommandId id = aResponse.GetCmdId();
PVMFStatus status =
CheckCPMCommandCompleteStatus(id, aResponse.GetCmdStatus());
if (id == iCPMCancelGetLicenseCmdId)
{
/*
* if this command is CancelGetLicense, we will return success or fail here.
*/
OSCL_ASSERT(!iCancelCommand.empty());
CommandComplete(iCancelCommand,
iCancelCommand.front(),
status);
return;
}
//if CPM comes back as PVMFErrNotSupported then by pass rest of the CPM
//sequence. Fake success here so that node doesnt treat this as an error
else if (id == iCPMRegisterContentCmdId && status == PVMFErrNotSupported)
{
/* CPM does not care about this content, so treat it as unprotected */
PVMFStatus status = CheckForAACHeaderAvailability();
if (status == PVMFSuccess)
{
status = ParseAACFile();
SetState(EPVMFNodeInitialized);
}
/* End of Node Init sequence. */
OSCL_ASSERT(!iCurrentCommand.empty());
OSCL_ASSERT(iCurrentCommand.front().iCmd == PVMF_AAC_PARSER_NODE_INIT);
CommandComplete(iCurrentCommand,
iCurrentCommand.front(),
status);
return;
}
if (status != PVMFSuccess)
{
/*
* If any command fails, the sequence fails.
*/
CommandComplete(iCurrentCommand,
iCurrentCommand.front(),
aResponse.GetCmdStatus(),
NULL,
NULL,
NULL,
aResponse.GetEventExtensionInterface());
}
else
{
/*
* process the response, and issue the next command in
* the sequence.
*/
if (id == iCPMInitCmdId)
{
OpenCPMSession();
}
else if (id == iCPMOpenSessionCmdId)
{
CPMRegisterContent();
}
else if (id == iCPMRegisterContentCmdId)
{
GetCPMLicenseInterface();
}
else if (id == iCPMGetLicenseInterfaceCmdId)
{
iCPMLicenseInterface = OSCL_STATIC_CAST(PVMFCPMPluginLicenseInterface*, iCPMLicenseInterfacePVI);
iCPMLicenseInterfacePVI = NULL;
GetCPMMetaDataExtensionInterface();
iCPMContentType = iCPM->GetCPMContentType(iCPMSessionID);
if ((iCPMContentType == PVMF_CPM_FORMAT_OMA1) ||
(iCPMContentType == PVMF_CPM_FORMAT_AUTHORIZE_BEFORE_ACCESS))
{
RequestUsage();
}
else
{
/* CPM does not care about this content, so treat it as unprotected */
PVMFStatus status = CheckForAACHeaderAvailability();
if (status == PVMFSuccess)
{
status = ParseAACFile();
SetState(EPVMFNodeInitialized);
}
/* End of Node Init sequence. */
OSCL_ASSERT(!iCurrentCommand.empty());
OSCL_ASSERT(iCurrentCommand.front().iCmd == PVMF_AAC_PARSER_NODE_INIT);
CommandComplete(iCurrentCommand,
iCurrentCommand.front(),
status);
}
}
else if (id == iCPMRequestUsageId)
{
/** Logic for playing after acquired license */
oSourceIsCurrent = false;
if ((iCPMContentType == PVMF_CPM_FORMAT_OMA1) ||
(iCPMContentType == PVMF_CPM_FORMAT_AUTHORIZE_BEFORE_ACCESS))
{
GetCPMContentAccessFactory();
if (CheckForAACHeaderAvailability() == PVMFSuccess)
{
if (ParseAACFile())
{
/* End of Node Init sequence. */
OSCL_ASSERT(!iCurrentCommand.empty());
OSCL_ASSERT(iCurrentCommand.front().iCmd == PVMF_AAC_PARSER_NODE_INIT);
CompleteInit();
}
}
}
else
{
/* Unknown format - should never get here */
OSCL_ASSERT(false);
}
}
else if (id == iCPMGetMetaDataKeysCmdId)
{
/* End of GetNodeMetaDataKeys */
PVMFStatus status =
CompleteGetMetadataKeys(iCurrentCommand.front());
CommandComplete(iCurrentCommand,
iCurrentCommand.front(),
status,
NULL,
NULL,
NULL,
NULL);
}
else if (id == iCPMUsageCompleteCmdId)
{
CloseCPMSession();
}
else if (id == iCPMCloseSessionCmdId)
{
ResetCPM();
}
else if (id == iCPMResetCmdId)
{
/* End of Node Reset sequence */
OSCL_ASSERT(!iCurrentCommand.empty());
OSCL_ASSERT(iCurrentCommand.front().iCmd == PVMF_AAC_PARSER_NODE_RESET);
CompleteReset();
}
else if (id == iCPMGetMetaDataValuesCmdId)
{
/* End of GetNodeMetaDataValues */
OSCL_ASSERT(!iCurrentCommand.empty());
OSCL_ASSERT(iCurrentCommand.front().iCmd == PVMF_AAC_PARSER_NODE_GETNODEMETADATAVALUES);
CompleteGetMetaDataValues();
}
else if (id == iCPMGetLicenseCmdId)
{
CompleteGetLicense();
}
else
{
/* Unknown cmd ?? - error */
CommandComplete(iCurrentCommand,
iCurrentCommand.front(),
PVMFFailure);
}
}
/*
* if there was any pending cancel, it was waiting on
* this command to complete-- so the cancel is now done.
*/
if (!iCancelCommand.empty())
{
if (iCancelCommand.front().iCmd != PVMF_AAC_PARSER_NODE_CANCEL_GET_LICENSE)
{
CommandComplete(iCancelCommand,
iCancelCommand.front(),
PVMFSuccess);
}
}
}
void PVMFAACFFParserNode::PassDatastreamFactory(PVMFDataStreamFactory& aFactory,
int32 aFactoryTag,
const PvmfMimeString* aFactoryConfig)
{
OSCL_UNUSED_ARG(aFactoryTag);
OSCL_UNUSED_ARG(aFactoryConfig);
iDataStreamFactory = &aFactory;
PVUuid uuid = PVMIDataStreamSyncInterfaceUuid;
PVInterface* iFace =
iDataStreamFactory->CreatePVMFCPMPluginAccessInterface(uuid);
if (iFace != NULL)
{
iDataStreamInterface = OSCL_STATIC_CAST(PVMIDataStreamSyncInterface*, iFace);
iDataStreamInterface->OpenSession(iDataStreamSessionID, PVDS_READ_ONLY);
}
}
void
PVMFAACFFParserNode::PassDatastreamReadCapacityObserver(PVMFDataStreamReadCapacityObserver* aObserver)
{
iDataStreamReadCapacityObserver = aObserver;
}
void PVMFAACFFParserNode::CompleteInit()
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::CompleteInit() Called"));
if (iCPM)
{
if (iApprovedUsage.value.uint32_value !=
iRequestedUsage.value.uint32_value)
{
CommandComplete(iCurrentCommand,
iCurrentCommand.front(),
PVMFErrAccessDenied,
NULL, NULL, NULL);
return;
}
}
SetState(EPVMFNodeInitialized);
CommandComplete(iCurrentCommand,
iCurrentCommand.front(),
PVMFSuccess);
return;
}
void PVMFAACFFParserNode::CompleteGetMetaDataValues()
{
CommandComplete(iCurrentCommand,
iCurrentCommand.front(),
PVMFSuccess);
}
bool PVMFAACFFParserNode::GetTrackInfo(PVMFPortInterface* aPort,
PVAACFFNodeTrackPortInfo*& aTrackInfoPtr)
{
if (iTrack.iPort == aPort)
{
aTrackInfoPtr = &iTrack;
return true;
}
return false;
}
bool PVMFAACFFParserNode::GetTrackInfo(int32 aTrackID,
PVAACFFNodeTrackPortInfo*& aTrackInfoPtr)
{
if (iTrack.iTrackId == aTrackID)
{
aTrackInfoPtr = &iTrack;
return true;
}
return false;
}
bool PVMFAACFFParserNode::CheckForPortRescheduling()
{
PVAACFFNodeTrackPortInfo* trackInfoPtr = NULL;
if (!GetTrackInfo(iOutPort, trackInfoPtr))
{
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACParserNode::CheckForPortRescheduling: Error - GetPortContainer failed"));
return false;
}
if ((trackInfoPtr->oProcessOutgoingMessages) ||
(trackInfoPtr->oQueueOutgoingMessages))
{
/*
* Found a port that has outstanding activity and
* is not busy.
*/
return true;
}
/*
* No port processing needed - either all port activity queues are empty
* or the ports are backed up due to flow control.
*/
return false;
}
void PVMFAACFFParserNode::CommandComplete(PVMFAACFFParserNodeCmdQ& aCmdQ,
PVMFAACFFParserNodeCommand& aCmd,
PVMFStatus aStatus,
OsclAny* aEventData,
PVUuid* aEventUUID,
int32* aEventCode,
PVInterface* aExtMsg)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::CommandComplete() In Id %d Cmd %d Status %d Context %d Data %d",
aCmd.iId, aCmd.iCmd, aStatus, aCmd.iContext, aEventData));
PVInterface* extif = NULL;
PVMFBasicErrorInfoMessage* errormsg = NULL;
if (aExtMsg)
{
extif = aExtMsg;
}
else if (aEventUUID && aEventCode)
{
PVMF_AAC_PARSER_NODE_NEW(NULL,
PVMFBasicErrorInfoMessage,
(*aEventCode, *aEventUUID, NULL),
errormsg);
extif = OSCL_STATIC_CAST(PVInterface*, errormsg);
}
PVMFCmdResp resp(aCmd.iId, aCmd.iContext, aStatus, extif, aEventData);
PVMFSessionId session = aCmd.iSession;
/* Erase the command from the queue. */
aCmdQ.Erase(&aCmd);
/* Report completion to the session observer.*/
ReportCmdCompleteEvent(session, resp);
if (errormsg)
{
errormsg->removeRef();
}
}
bool PVMFAACFFParserNode::ProcessPortActivity(PVAACFFNodeTrackPortInfo* aTrackInfoPtr)
{
/*
* called by the AO to process a port activity message
*/
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::ProcessPortActivity() Called"));
PVMFStatus status;
if (aTrackInfoPtr->oQueueOutgoingMessages)
{
status = QueueMediaSample(aTrackInfoPtr);
if ((status != PVMFErrBusy) &&
(status != PVMFSuccess) &&
(status != PVMFErrInvalidState))
{
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACParserNode::ProcessPortActivity() QueueMediaSample Failed - Err=%d", status));
return false;
}
if (iAutoPaused == true)
{
aTrackInfoPtr->oQueueOutgoingMessages = false;
PVMF_AACPARSERNODE_LOGDATATRAFFIC((0, "PVMFAACParserNode::QueueMediaSample() - Auto Paused"));
return PVMFErrBusy;
}
if (aTrackInfoPtr->iPort->IsOutgoingQueueBusy())
{
aTrackInfoPtr->oQueueOutgoingMessages = false;
PVMF_AACPARSERNODE_LOGDATATRAFFIC((0, "PVMFAACParserNode::QueueMediaSample() Port Outgoing Queue Busy"));
return PVMFErrBusy;
}
}
if (aTrackInfoPtr->oProcessOutgoingMessages)
{
if (aTrackInfoPtr->iPort->OutgoingMsgQueueSize() > 0)
{
status = ProcessOutgoingMsg(aTrackInfoPtr);
/*
* Report any unexpected failure in port processing...
* (the InvalidState error happens when port input is suspended,
* so don't report it.)
*/
if ((status != PVMFErrBusy) &&
(status != PVMFSuccess) &&
(status != PVMFErrInvalidState))
{
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACParserNode::ProcessPortActivity() ProcessOutgoingMsg Failed - Err=%d", status));
ReportErrorEvent(PVMFErrPortProcessing);
}
}
else
{
/* Nothing to send - wait for more data */
aTrackInfoPtr->oProcessOutgoingMessages = false;
}
}
return true;
}
PVMFStatus PVMFAACFFParserNode::QueueMediaSample(PVAACFFNodeTrackPortInfo* aTrackInfoPtr)
{
if (iAutoPaused == true)
{
aTrackInfoPtr->oQueueOutgoingMessages = false;
PVMF_AACPARSERNODE_LOGDATATRAFFIC((0, "PVMFAACParserNode::QueueMediaSample() - Auto Paused"));
return PVMFErrBusy;
}
if (aTrackInfoPtr->iPort->IsOutgoingQueueBusy())
{
aTrackInfoPtr->oQueueOutgoingMessages = false;
PVMF_AACPARSERNODE_LOGDATATRAFFIC((0, "PVMFAACParserNode::QueueMediaSample() Port Outgoing Queue Busy"));
return PVMFErrBusy;
}
if (aTrackInfoPtr->oQueueOutgoingMessages)
{
PVMFStatus status;
if (aTrackInfoPtr->iSendBOS == true)
{
status = SendBeginOfMediaStreamCommand(aTrackInfoPtr);
return status;
}
if ((aTrackInfoPtr->oEOSReached == false) && (aTrackInfoPtr->oEOSSent == false))
{
PVMFSharedMediaDataPtr mediaDataOut;
status = RetrieveMediaSample(&iTrack, mediaDataOut);
if (status == PVMFErrBusy)
{
aTrackInfoPtr->oQueueOutgoingMessages = false;
if (iAutoPaused == true)
{
PauseAllMediaRetrieval();
}
return status;
}
else if (status == PVMFSuccess)
{
if (aTrackInfoPtr->oEOSReached == false)
{
PVMFSharedMediaMsgPtr msgOut;
convertToPVMFMediaMsg(msgOut, mediaDataOut);
/* For logging purposes */
uint32 markerInfo = mediaDataOut->getMarkerInfo();
uint32 noRender = 0;
uint32 keyFrameBit = 0;
if (markerInfo & PVMF_MEDIA_DATA_MARKER_INFO_NO_RENDER_BIT)
{
noRender = 1;
}
if (markerInfo & PVMF_MEDIA_DATA_MARKER_INFO_RANDOM_ACCESS_POINT_BIT)
{
keyFrameBit = 1;
}
uint32 nptTS32 = 0;
nptTS32 = Oscl_Int64_Utils::get_uint64_lower32(aTrackInfoPtr->iPrevSampleTimeStamp);
PVMF_AACPARSERNODE_LOGDATATRAFFIC((0, "PVMFAACParserNode::QueueMediaSample() TrackID=%d, SeqNum=%d, SampleLen=%d, NptTS=%d, SampleTS=%d, NR=%d, KEY=%d, MimeType=%s",
aTrackInfoPtr->iTrackId,
msgOut->getSeqNum(),
mediaDataOut->getFilledSize(),
nptTS32,
msgOut->getTimestamp(),
noRender,
keyFrameBit,
aTrackInfoPtr->iTrackMimeType.get_cstr()));
status = aTrackInfoPtr->iPort->QueueOutgoingMsg(msgOut);
if (status != PVMFSuccess)
{
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACParserNode::QueueMediaSample: Error - QueueOutgoingMsg failed"));
ReportErrorEvent(PVMFErrPortProcessing);
}
/* This flag will get reset to false if the connected port is busy */
aTrackInfoPtr->oProcessOutgoingMessages = true;
return status;
}
}
else if (status == PVMFInfoEndOfData)
{
status = GenerateAndSendEOSCommand(aTrackInfoPtr);
return status;
}
else
{
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACParserNode::QueueMediaSample() - Sample Retrieval Failed"));
ReportErrorEvent(PVMFErrCorrupt);
return PVMFFailure;
}
}
else if (aTrackInfoPtr->oEOSReached == true)
{
status = GenerateAndSendEOSCommand(aTrackInfoPtr);
return status;
}
}
return PVMFSuccess;
}
PVMFStatus PVMFAACFFParserNode:: GenerateAndSendEOSCommand(PVAACFFNodeTrackPortInfo* aTrackInfoPtr)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACParserNode::GenerateAndSendEOSCommand Called"));
if (aTrackInfoPtr->iPort->IsOutgoingQueueBusy() == true)
{
/* come back later */
PVMF_AACPARSERNODE_LOGDATATRAFFIC((0, "PVMFAACParserNode::GenerateAndSendEOSCommand: Waiting - Output Queue Busy"));
return PVMFErrBusy;
}
if ((aTrackInfoPtr->oEOSSent == false) && (aTrackInfoPtr->oEOSReached == true))
{
PVMFSharedMediaCmdPtr sharedMediaCmdPtr = PVMFMediaCmd::createMediaCmd();
sharedMediaCmdPtr->setFormatID(PVMF_MEDIA_CMD_EOS_FORMAT_ID);
sharedMediaCmdPtr->setStreamID(iStreamID);
sharedMediaCmdPtr->setSeqNum(aTrackInfoPtr->iSeqNum++);
aTrackInfoPtr->iContinuousTimeStamp += PVMF_AAC_PARSER_NODE_TS_DELTA_DURING_REPOS_IN_MS;
uint32 ts32 = Oscl_Int64_Utils::get_uint64_lower32(aTrackInfoPtr->iContinuousTimeStamp);
sharedMediaCmdPtr->setTimestamp(ts32);
PVMFSharedMediaMsgPtr msg;
convertToPVMFMediaCmdMsg(msg, sharedMediaCmdPtr);
PVMFStatus status = aTrackInfoPtr->iPort->QueueOutgoingMsg(msg);
if (status != PVMFSuccess)
{
ReportErrorEvent(PVMFErrPortProcessing, (OsclAny*)(aTrackInfoPtr->iPort));
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACParserNode::GenerateAndSendEOSCommand: Error Sending EOS"));
return status;
}
aTrackInfoPtr->oEOSSent = true;
aTrackInfoPtr->oQueueOutgoingMessages = false;
aTrackInfoPtr->oProcessOutgoingMessages = true;
return (status);
}
aTrackInfoPtr->oQueueOutgoingMessages = false;
return PVMFFailure;
}
void PVMFAACFFParserNode::DataStreamCommandCompleted(const PVMFCmdResp& aResponse)
{
if (aResponse.GetCmdId() == iRequestReadCapacityNotificationID)
{
PVMFStatus cmdStatus = aResponse.GetCmdStatus();
if (cmdStatus == PVMFSuccess)
{
if (CheckForAACHeaderAvailability() == PVMFSuccess)
{
if (iCPMContentType == PVMF_CPM_FORMAT_AUTHORIZE_BEFORE_ACCESS)
{
if (ParseAACFile())
{
{
/* End of Node Init sequence. */
OSCL_ASSERT(!iCurrentCommand.empty());
OSCL_ASSERT(iCurrentCommand.front().iCmd == PVMF_AAC_PARSER_NODE_INIT);
CompleteInit();
}
}
}
else
{
if (ParseAACFile())
{
/* End of Node Init sequence. */
OSCL_ASSERT(!iCurrentCommand.empty());
OSCL_ASSERT(iCurrentCommand.front().iCmd == PVMF_AAC_PARSER_NODE_INIT);
CompleteInit();
}
}
}
}
else
{
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACParserNode::DataStreamCommandCompleted() Failed %d", cmdStatus));
CommandComplete(iCurrentCommand,
iCurrentCommand.front(),
PVMFErrResource);
}
}
else
{
OSCL_ASSERT(false);
}
}
void PVMFAACFFParserNode::playResumeNotification(bool aDownloadComplete)
{
OSCL_UNUSED_ARG(aDownloadComplete);
iAutoPaused = false;
PVAACFFNodeTrackPortInfo* trackInfoPtr = NULL;
if (!GetTrackInfo(iOutPort, trackInfoPtr))
{
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACParserNode::playResumeNotification: Error - GetPortContainer failed"));
return;
}
if (trackInfoPtr->oQueueOutgoingMessages == false)
{
trackInfoPtr->oQueueOutgoingMessages = true;
}
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACParserNode::playResumeNotification() - Auto Resume Triggered - FileSize = %d, NPT = %d", iFileSizeLastConvertedToTime, iLastNPTCalcInConvertSizeToTime));
PVMF_AACPARSERNODE_LOGDATATRAFFIC((0, "PVMFAACParserNode::playResumeNotification() - Auto Resume Triggered - FileSize = %d, NPT = %d", iFileSizeLastConvertedToTime, iLastNPTCalcInConvertSizeToTime));
RunIfNotReady();
}
void PVMFAACFFParserNode::setFileSize(const uint32 aFileSize)
{
iDownloadFileSize = aFileSize;
}
void PVMFAACFFParserNode::setDownloadProgressInterface(PVMFDownloadProgressInterface* aInterface)
{
if (aInterface == NULL)
{
OSCL_ASSERT(false);
}
iDownloadProgressInterface = aInterface;
}
int32 PVMFAACFFParserNode::convertSizeToTime(uint32 aFileSize, uint32& aNPTInMS)
{
OSCL_UNUSED_ARG(aFileSize);
OSCL_UNUSED_ARG(aNPTInMS);
return -1;
}
void PVMFAACFFParserNode::DataStreamInformationalEvent(const PVMFAsyncEvent& aEvent)
{
OSCL_UNUSED_ARG(aEvent);
OSCL_LEAVE(OsclErrNotSupported);
}
void PVMFAACFFParserNode::DataStreamErrorEvent(const PVMFAsyncEvent& aEvent)
{
OSCL_UNUSED_ARG(aEvent);
OSCL_LEAVE(OsclErrNotSupported);
}
void PVMFAACFFParserNode::PauseAllMediaRetrieval()
{
PVAACFFNodeTrackPortInfo* trackInfoPtr = NULL;
if (!GetTrackInfo(iOutPort, trackInfoPtr))
{
PVMF_AACPARSERNODE_LOGERROR((0, "PVMFAACParserNode::PauseAllMediaRetrieval: Error - GetPortContainer failed"));
return;
}
trackInfoPtr->oQueueOutgoingMessages = false;
return;
}
bool PVMFAACFFParserNode::SendBeginOfMediaStreamCommand(PVAACFFNodeTrackPortInfo* aTrackInfoPtr)
{
PVMFSharedMediaCmdPtr sharedMediaCmdPtr = PVMFMediaCmd::createMediaCmd();
sharedMediaCmdPtr->setFormatID(PVMF_MEDIA_CMD_BOS_FORMAT_ID);
sharedMediaCmdPtr->setTimestamp(aTrackInfoPtr->iTimestampOffset);
uint32 seqNum = 0;
sharedMediaCmdPtr->setSeqNum(seqNum);
PVMFSharedMediaMsgPtr mediaMsgOut;
convertToPVMFMediaCmdMsg(mediaMsgOut, sharedMediaCmdPtr);
mediaMsgOut->setStreamID(iStreamID);
PVMFStatus status = aTrackInfoPtr->iPort->QueueOutgoingMsg(mediaMsgOut);
if (status != PVMFSuccess)
{
// Output queue is busy, so wait for the output queue being ready
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
(0, "PVMFAACFFParserNode::SendBeginOfMediaStreamCommand: Outgoing queue busy. "));
return PVMFFailure;
}
aTrackInfoPtr->iSendBOS = false;
PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFAACFFParserNode::SendBeginOfMediaStreamCommand() Out StreamId %d ", iStreamID));
return PVMFSuccess;
}
PVMFCommandId
PVMFAACFFParserNode::GetLicense(PVMFSessionId aSessionId,
OSCL_wString& aContentName,
OsclAny* aData,
uint32 aDataSize,
int32 aTimeoutMsec,
OsclAny* aContextData)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACFFParserNode::GetLicense - Wide called"));
PVMFAACFFParserNodeCommand cmd;
cmd.PVMFAACFFParserNodeCommand::Construct(aSessionId,
PVMF_AAC_PARSER_NODE_GET_LICENSE_W,
aContentName,
aData,
aDataSize,
aTimeoutMsec,
aContextData);
return QueueCommandL(cmd);
}
PVMFCommandId
PVMFAACFFParserNode::GetLicense(PVMFSessionId aSessionId,
OSCL_String& aContentName,
OsclAny* aData,
uint32 aDataSize,
int32 aTimeoutMsec,
OsclAny* aContextData)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACFFParserNode::GetLicense - Wide called"));
PVMFAACFFParserNodeCommand cmd;
cmd.PVMFAACFFParserNodeCommand::Construct(aSessionId,
PVMF_AAC_PARSER_NODE_GET_LICENSE,
aContentName,
aData,
aDataSize,
aTimeoutMsec,
aContextData);
return QueueCommandL(cmd);
}
PVMFCommandId
PVMFAACFFParserNode::CancelGetLicense(PVMFSessionId aSessionId
, PVMFCommandId aCmdId
, OsclAny* aContextData)
{
PVMFAACFFParserNodeCommand cmd;
cmd.PVMFAACFFParserNodeCommandBase::Construct(aSessionId,
PVMF_AAC_PARSER_NODE_CANCEL_GET_LICENSE,
aCmdId,
aContextData);
return QueueCommandL(cmd);
}
PVMFStatus
PVMFAACFFParserNode::GetLicenseStatus(PVMFCPMLicenseStatus& aStatus)
{
if (iCPMLicenseInterface)
return iCPMLicenseInterface->GetLicenseStatus(aStatus);
return PVMFFailure;
}
PVMFStatus
PVMFAACFFParserNode::DoGetLicense(PVMFAACFFParserNodeCommand& aCmd,
bool aWideCharVersion)
{
if (iCPMLicenseInterface == NULL)
{
return PVMFErrNotSupported;
}
if (aWideCharVersion == true)
{
OSCL_wString* contentName = NULL;
OsclAny* data = NULL;
uint32 dataSize = 0;
int32 timeoutMsec = 0;
aCmd.PVMFAACFFParserNodeCommand::Parse(contentName,
data,
dataSize,
timeoutMsec);
iCPMGetLicenseCmdId =
iCPMLicenseInterface->GetLicense(iCPMSessionID,
*contentName,
data,
dataSize,
timeoutMsec);
}
else
{
OSCL_String* contentName = NULL;
OsclAny* data = NULL;
uint32 dataSize = 0;
int32 timeoutMsec = 0;
aCmd.PVMFAACFFParserNodeCommand::Parse(contentName,
data,
dataSize,
timeoutMsec);
iCPMGetLicenseCmdId =
iCPMLicenseInterface->GetLicense(iCPMSessionID,
*contentName,
data,
dataSize,
timeoutMsec);
}
return PVMFPending;
}
void PVMFAACFFParserNode::CompleteGetLicense()
{
CommandComplete(iCurrentCommand,
iCurrentCommand.front(),
PVMFSuccess);
}
void PVMFAACFFParserNode::DoCancelGetLicense(PVMFAACFFParserNodeCommand& aCmd)
{
PVMF_AACPARSERNODE_LOGSTACKTRACE((0, "PVMFAACFFParserNode::DoCancelGetLicense() Called"));
PVMFStatus status = PVMFErrArgument;
if (iCPMLicenseInterface == NULL)
{
status = PVMFErrNotSupported;
}
else
{
/* extract the command ID from the parameters.*/
PVMFCommandId id;
aCmd.PVMFAACFFParserNodeCommandBase::Parse(id);
/* first check "current" command if any */
PVMFAACFFParserNodeCommand* cmd = iCurrentCommand.FindById(id);
if (cmd)
{
if (cmd->iCmd == PVMF_AAC_PARSER_NODE_GET_LICENSE_W || cmd->iCmd == PVMF_AAC_PARSER_NODE_GET_LICENSE)
{
iCPMCancelGetLicenseCmdId =
iCPMLicenseInterface->CancelGetLicense(iCPMSessionID, iCPMGetLicenseCmdId);
/*
* the queued commands are all asynchronous commands to the
* CPM module. CancelGetLicense can cancel only for GetLicense cmd.
* We need to wait CPMCommandCompleted.
*/
MoveCmdToCancelQueue(aCmd);
return;
}
}
/*
* next check input queue.
* start at element 1 since this cancel command is element 0.
*/
cmd = iInputCommands.FindById(id, 1);
if (cmd)
{
if (cmd->iCmd == PVMF_AAC_PARSER_NODE_GET_LICENSE_W || cmd->iCmd == PVMF_AAC_PARSER_NODE_GET_LICENSE)
{
/* cancel the queued command */
CommandComplete(iInputCommands, *cmd, PVMFErrCancelled, NULL, NULL);
/* report cancel success */
CommandComplete(iInputCommands, aCmd, PVMFSuccess);
return;
}
}
}
/* if we get here the command isn't queued so the cancel fails */
CommandComplete(iInputCommands, aCmd, status);
return;
}
int32 PVMFAACFFParserNode::CreateNewArray(char*& aPtr, char *aKey)
{
int32 leavecode = 0;
OSCL_TRY(leavecode,
aPtr = OSCL_ARRAY_NEW(char, oscl_strlen(aKey) + 1););
return leavecode;
}
int32 PVMFAACFFParserNode::CreateNewArray(char*& aPtr, int32 aLen)
{
int32 leavecode = 0;
OSCL_TRY(leavecode,
aPtr = OSCL_ARRAY_NEW(char, aLen););
return leavecode;
}
int32 PVMFAACFFParserNode::CreateNewArray(oscl_wchar*& aPtr, int32 aLen)
{
int32 leavecode = 0;
OSCL_TRY(leavecode,
aPtr = OSCL_ARRAY_NEW(oscl_wchar, aLen););
return leavecode;
}
int32 PVMFAACFFParserNode::PushBackKeyVal(Oscl_Vector<PvmiKvp, OsclMemAllocator>*& aValueListPtr, PvmiKvp &aKeyVal)
{
int32 leavecode = 0;
OSCL_TRY(leavecode, (*aValueListPtr).push_back(aKeyVal));
return leavecode;
}
PVMFStatus PVMFAACFFParserNode::PushValueToList(Oscl_Vector<OSCL_HeapString<OsclMemAllocator>, OsclMemAllocator> &aRefMetaDataKeys, PVMFMetadataList *&aKeyListPtr, uint32 aLcv)
{
int32 leavecode = 0;
OSCL_TRY(leavecode, aKeyListPtr->push_back(aRefMetaDataKeys[aLcv]));
OSCL_FIRST_CATCH_ANY(leavecode, PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFAACFFParserNode::PushValueToList() Memory allocation failure when copying metadata key")); return PVMFErrNoMemory);
return PVMFSuccess;
}