Пример #1
0
//! Scan a metadata object for strong references in sub-objects and add those to this partition
void Partition::AddMetadataSubs(MDObjectPtr &NewObject, bool ForceFirst)
{
	MDObjectULList::iterator it = NewObject->begin();
	MDObjectULList::iterator itend = NewObject->end();
	while(it != itend)
	{
		if((*it).second->GetRefType() == DICT_REF_STRONG)
		{
			MDObjectPtr Link = (*it).second->GetLink();
			if(Link)
			{
				AddMetadata(Link, ForceFirst);

				// Prevent the new item being top-level (which it may be as we are not added yet)
				// DRAGONS: There is surely a better way than this!!
				TopLevelMetadata.remove(Link);
			}
		}
		else if(!((*it).second->empty()))
		{
			AddMetadataSubs((*it).second, ForceFirst);
		}
		it++;
	}
}
Пример #2
0
	/*! DRAGONS: We use the current UTF16String GetString trait to ensure that we always have the correct handling,
	 *           even if the user wants these strings handled differently (i.e. we do it their way!)
	 */
	std::list<std::string> SplitStringArray(const MDObjectPtr &Array)
	{
		std::list<std::string> Ret;

		// Quit early if an invalid parameter
		if(!Array) return Ret;

		// Build a working string
		static MDTypePtr ValType = MDType::Find("UTF16String");
		MDObjectPtr Value = ValType ? new MDObject(ValType) : NULL;
		if(!Value)
		{
			error("Can't build UTF16String value required by SplitStringArray() - need this type to be defined in the dictionary file\n");
			return Ret;
		}

		// Assemble the data value (which may be an array of sub-values)
		DataChunkPtr Data = Array->PutData();

		// Get a pointer to the start of the data
		UInt8 *pData = Data->Data;

		// The number of bytes of data to split
		size_t BytesLeft = Data->Size;

		while(BytesLeft > 1)
		{
			// Find the end of the current string
			size_t Len = 0;
			UInt8 *p = pData;
			while(BytesLeft > 1)
			{
				BytesLeft -= 2;
				Len += 2;
				UInt16 Char = GetU16(p);
				p += 2;

				// End when we find a null
				if(Char == 0) break;
			}

			// Copy this string to the working value
			Value->SetValue(pData, Len);

			// Read out the traits-formatted version of the string
			Ret.push_back(Value->GetString());

			// Move the pointer forward to the next value after the string terminator
			pData = p;
		}

		return Ret;
	}
Пример #3
0
	/*! DRAGONS: We use the current UTF16String SetString trait to ensure that we always have the correct handling,
	 *           even if the user wants these strings handled differently (i.e. we do it their way!)
	 */
	void SetStringArray(MDObjectPtr &Array, const std::list<std::string> &Strings)
	{
		// Abort if we are send a NULL pointer
		if(!Array) return;

		// Don't bother if we have nothing to do
		if(Strings.empty()) return;

		// Build a working string
		static MDTypePtr ValType = MDType::Find("UTF16String");
		MDObjectPtr Value = ValType ? new MDObject(ValType) : NULL;
		if(!Value)
		{
			error("Can't build UTF16String value required by SetStringArray() - need this type to be defined in the dictionary file\n");
			return;
		}

		// Get a buffer in which to build the final string array, make it quite granular as it will keep growing
		DataChunkPtr Buffer = new DataChunk();
		Buffer->SetGranularity(16 * 1024);

		std::list<std::string>::const_iterator it = Strings.begin();
		while(it != Strings.end())
		{
			Value->SetString(*it);
			DataChunkPtr ThisString = Value->PutData();
			Buffer->Append(ThisString);
			
			// Add terminator if required, i.e. if the sub-string we just added did not end in a zero
			UInt8 *p = &ThisString->Data[ThisString->Size];

			// Terminate if either of the last two bytes in the current buffer is non-zero - or if the string was too short to have a terminator
			if((ThisString->Size) < 2 || ((*(--p) != 0) || (*(--p) != 0)))
			{
				const UInt8 Term[2] = { 0, 0};
				Buffer->Set(2, Term, Buffer->Size);
			}

			it++;
		}

		// Set the value from this buffer
		Array->SetValue(Buffer);
	}
Пример #4
0
//! Read any index table segments from a file
MDObjectListPtr mxflib::Partition::ReadIndex(MXFFilePtr File, UInt64 Size)
{
	MDObjectListPtr Ret = new MDObjectList;

	while(Size)
	{
		UInt64 Location = File->Tell();
		UInt64 Bytes;

		MDObjectPtr NewIndex = File->ReadObject(NULL);
		if(NewIndex)
		{
			if((NewIndex->Name() == "IndexTableSegment") || (NewIndex->Name() == "V10IndexTableSegment"))
			{
				Ret->push_back(NewIndex);
				Bytes = File->Tell() - Location;
			}
			else if( NewIndex->IsA(KLVFill_UL) )
			{
				// Skip over the filler
				Bytes = File->Tell() - Location;
			}
			else
			{
				error("Expected to find an IndexTableSegment - found %s at %s\n", 
					  NewIndex->FullName().c_str(), NewIndex->GetSourceLocation().c_str());
				break;
			}
		}
		else
		{
			error("Error reading IndexTableSegment at 0x%s in %s\n", 
				   Int64toHexString(Location,8).c_str(), File->Name.c_str());
			break;
		}

		if(Bytes > Size) break;

		Size -= Bytes;
	}

	return Ret;
}
Пример #5
0
/*! \note This call will modify properties SampleRate, DataStart and DataSize */
MDObjectPtr mxflib::WAVE_PCM_EssenceSubParser::BuildWaveAudioDescriptor(FileHandle InFile, UInt64 Start /*=0*/)
{
	const unsigned int ID_RIFF = 0x52494646;		//! "RIFF"
	const unsigned int ID_fmt  = 0x666d7420;		//! "fmt "
	const unsigned int ID_data = 0x64617461;		//! "data"

	MDObjectPtr Ret;

	FileSeek(InFile, Start);
	U32Pair Header = ReadRIFFHeader(InFile);

	// Can't build a descriptor if it isn't a RIFF file!
	if(Header.first != ID_RIFF) return Ret;
	if(Header.second < 4) return Ret;

	// Read the RIFF file type (always 4 bytes)
	DataChunkPtr ChunkData = FileReadChunk(InFile, 4);
	
	// Can't build a descriptor if it isn't a WAVE file!
	if(memcmp(ChunkData->Data, "WAVE", 4) != 0) return Ret;

	// Scan the chunks within the RIFF file
	// DRAGONS: To do this properly we would check the file size in the RIFF chunk
	// DRAGONS: "LIST" chunks are "sets" and are not yet supported
	for(;;)
	{
		Header = ReadRIFFHeader(InFile);

		// End of file?
		if((Header.first == 0) && (Header.second == 0)) break;

		if(Header.first == ID_fmt)
		{
			ChunkData = FileReadChunk(InFile, Header.second);
			if(ChunkData->Size < 16) return Ret;

			UInt16 AudioFormat = GetU16_LE(&ChunkData->Data[0]);
			if(AudioFormat != 1) return Ret;

			Ret = new MDObject(WaveAudioDescriptor_UL);
			if(!Ret) return Ret;

			// Set the sample rate
			char Buffer[32];
			SampleRate = GetU32_LE(&ChunkData->Data[4]);
			sprintf(Buffer, "%d/1", SampleRate);
			Ret->SetString(SampleRate_UL, Buffer);
			Ret->SetString(AudioSamplingRate_UL, Buffer);

			// Must assume not locked!
			Ret->SetUInt(Locked_UL, 0);

			// Set channel count
			UInt16 Chan = GetU16_LE(&ChunkData->Data[2]);
			Ret->SetUInt(ChannelCount_UL, Chan);

			// Set quantization bits
			UInt16 Quant = GetU16_LE(&ChunkData->Data[14]);
			Ret->SetUInt(QuantizationBits_UL, Quant);

			// Calculate the number of bytes per sample
			SampleSize = ((Quant+7) / 8) * Chan;

			// Set the block alignment
			Ret->SetUInt(BlockAlign_UL, GetU16_LE(&ChunkData->Data[12]));

			// Set the byte-rate
			Ret->SetUInt(AvgBps_UL, GetU32_LE(&ChunkData->Data[8]));
		}
		else if(Header.first == ID_data)
		{
			// Record the location of the audio data
			DataStart = FileTell(InFile);
			DataSize = Header.second;

			// ...and skip the chunk value
			FileSeek(InFile, FileTell(InFile) + Header.second);
		}
		else
		{
			// Skip the chunk value
			FileSeek(InFile, FileTell(InFile) + Header.second);
		}
	}

	return Ret;
}
Пример #6
0
/*! Note that any strongly linked objects are also added */
void mxflib::Partition::AddMetadata(MDObjectPtr NewObject, bool ForceFirst /*=false*/)
{
	// Start out without a target
	bool has_target = false;

	// Start out not (strong) reffed
	bool linked = false;

	// Add us to the list of all items - done last if forcing first as the child items will get added first
	if(!ForceFirst) AllMetadata.push_back(NewObject);

	// Add this object to the ref target list if it is one. At the same time any objects
	// linked from this object (before this function was called) are added as well
	// Note: although nothing currently does it it is theoretically possible to
	//       have more than one target entry in a set
	MDObjectULList::iterator it = NewObject->begin();
	while(it != NewObject->end())
	{
		ClassRef RefType = (*it).second->GetRefType();

		if(RefType == ClassRefTarget)
		{
			if((*it).second->Value->GetData().Size != 16)
			{
				error("Metadata Object \"%s/%s\" should be a reference target (a UUID), but has size %d\n",
					  NewObject->Name().c_str(), (*it).second->Name().c_str(), (*it).second->Value->GetData().Size);
			}
			else
			{
				has_target = true;

				UUIDPtr ID = new UUID((*it).second->Value->PutData()->Data);
				RefTargets.insert(std::map<UUID, MDObjectPtr>::value_type(*ID, NewObject));

				// Try and satisfy all refs to this set
				for(;;)
				{
					std::multimap<UUID, MDObjectPtr>::iterator mit = UnmatchedRefs.find(*ID);

					// Exit when no more refs to this object
					if(mit == UnmatchedRefs.end()) break;

					// Sanity check!
					if((*mit).second->GetLink())
					{
						error("Internal error - %s at 0x%s in UnmatchedRefs but already linked!\n", (*mit).second->FullName().c_str() , Int64toHexString((*mit).second->GetLocation(), 8).c_str());
					}

					// Make the link
					(*mit).second->SetLink(NewObject);

					// If we are the tagert of a strong ref we won't get added to the top level
					if((*mit).second->GetRefType() == DICT_REF_STRONG) linked = true;

					// Remove from the unmatched refs map
					UnmatchedRefs.erase(mit);

					// loop for any more refs to this set
				}
			}
		}
		else if(RefType == ClassRefStrong)
		{
			MDObjectPtr Link = (*it).second->GetLink();
			if(Link)
			{
				AddMetadata(Link, ForceFirst);

				// Prevent the new item being top-level (which it may be as we are not added yet)
				// DRAGONS: There is surely a better way than this!!
				TopLevelMetadata.remove(Link);
			}
			// If this item is not a link, it may contain links
			else if((*it).second->size())
			{
				MDObject::iterator subit = (*it).second->begin();
				while(subit != (*it).second->end())
				{
					Link = (*subit).second->GetLink();
					if(Link)
					{
						AddMetadata(Link, ForceFirst);

						// Prevent the new item being top-level (which it may be as we are not added yet)
						// DRAGONS: There is surely a better way than this!!
						TopLevelMetadata.remove(Link);
					}
					subit++;
				}
			}
		} 
		else if(!((*it).second->empty()))
		{
			AddMetadataSubs((*it).second, ForceFirst);
		}

		it++;
	}

	// Add any forced-first items after thier children
	if(ForceFirst) AllMetadata.push_front(NewObject);

	// If we are not yet (strong) reffed then we are top level
	if(!linked)
	{
		if(ForceFirst) TopLevelMetadata.push_front(NewObject);
		else TopLevelMetadata.push_back(NewObject);
	}

	// Satisfy, or record as un-matched, all outgoing references
	ProcessChildRefs(NewObject);
}
Пример #7
0
/*! \note The value of "Size" does not include the size of any filler before
 *        the primer, but the return value does
 *  \return The number of bytes read (<b>including</b> any preceeding filler)
 */
Length mxflib::Partition::ReadMetadata(MXFFilePtr File, Length Size)
{
	Length Bytes = 0;
	Length FillerBytes = 0;

	// Clear any existing metadata, including the primer
	ClearMetadata(false);

	// Quick return for NULL metadata
	if(Size == 0) return 0;

	// Record the position of the current item
	Position Location = File->Tell();

	// Check for a leading filler item
	{
		ULPtr FirstUL = File->ReadKey();
		if(!FirstUL)
		{
			error("Error reading first KLV after %s at 0x%s in %s\n", FullName().c_str(), 
				  Int64toHexString(GetLocation(),8).c_str(), GetSource().c_str());
			return 0;
		}

		if(FirstUL->Matches(KLVFill_UL))
		{
			// Skip over the filler, recording how far we went
			Position NewLocation = File->ReadBER();
			NewLocation += File->Tell();
			FillerBytes = NewLocation - Location;
			Location = NewLocation;
		}
	}

	// Sanity check the size for this platform
	// TODO: Should we fix this so that we can read larger metadata - but if so where in memory would we put it if its > 4GB on a 32-bit machine?
	if((sizeof(size_t) < 8) && Size > 0xffffffff)
	{
		error("Maximum read size on this platform is 4Gbytes - However, requested to read metadata at 0x%s which has size of 0x%s\n",
			   Int64toHexString(Location,8).c_str(), Int64toHexString(Size,8).c_str());

		return 0;
	}

	// Read enough bytes for the metadata
	File->Seek(Location);
	DataChunkPtr Data = File->Read(static_cast<size_t>(Size));

	if(Data->Size != static_cast<size_t>(Size))
	{
		error("Header Metadata starting at 0x%s should contain 0x%s bytes, but only 0x%s could be read\n",
			  Int64toHexString(Location,8).c_str(), Int64toHexString(Size,8).c_str(), Int64toHexString(Data->Size,8).c_str());

		Size = static_cast<Length>(Data->Size);
	}

	// Start of data buffer
	const UInt8 *BuffPtr = Data->Data;

	while(Size)
	{
		Length BytesAtItemStart = Bytes;
		if(Size < 16)
		{
			error("Less than 16-bytes of header metadata available after reading 0x%s bytes at 0x%s in file \"%s\"\n", 
				 Int64toHexString(Bytes, 8).c_str(), Int64toHexString(File->Tell(),8).c_str(), File->Name.c_str() );
			break;
		}

/*		// Sanity check the keys
		if((BuffPtr[0] != 6) || (BuffPtr[1] != 0x0e))
		{
			error("Invalid KLV key found at 0x%s in file \"%s\"\n", Int64toHexString(File->Tell(),8).c_str(), File->Name.c_str() );
			break;
		}
*/
		// Build an object (it may come back as an "unknown")
		ULPtr NewUL = new UL(BuffPtr);

		/* If we are loading metadictionaries, we do so when we first read the Preface key */
		if(Feature(FeatureLoadMetadict))
		{
			if(NewUL->Matches(Preface_UL))
			{
				LoadMetadict();
			}
		}

		MDObjectPtr NewItem = new MDObject(NewUL);
		mxflib_assert(NewItem);

		BuffPtr += 16;
		Size -= 16;
		Bytes += 16;

		if(Size < 1)
		{
			error("Incomplete BER length at 0x%s in file \"%s\"\n", Int64toHexString(File->Tell(),8).c_str(), File->Name.c_str() );
			break;
		}

		Length Len = *BuffPtr++;
		Size--;
		Bytes++;
		if(Len >= 0x80)
		{
			UInt32 i = (UInt32)Len & 0x7f;
			if(Size < i)
			{
				error("Incomplete BER length at 0x%s in \"%s\"\n", Int64toHexString(File->Tell(),8).c_str(), File->Name.c_str() );
				break;
			}

			Len = 0;
			while(i--) 
			{
				Len = ((Len<<8) + *(BuffPtr++));
				Size--;
				Bytes++;
			}
		}

		// DRAGONS: KLV Size limit!!
		if(Len > 0xffffffff)
		{
			error("Current implementation KLV size limit of 0xffffffff bytes exceeded at 0x%s in file \"%s\"\n", 
				  Int64toHexString(Location + Bytes,8).c_str(), File->Name.c_str() );
			break;
		}

		if(Size < Len)
		{
			error("KLV length is %s but available data size is only %s after reading 0x%s of header metadata at 0x%s in \"%s\"\n", 
				  UInt64toString(Len).c_str(), UInt64toString(Size).c_str(), Int64toHexString(Bytes, 8).c_str(),
				  Int64toHexString(Location + Bytes,8).c_str(), File->Name.c_str() );

			// Try reading what we have
			Len = Size;
		}

		// Check for the primer until we have found it
		if(!PartitionPrimer)
		{
			if(NewItem->IsA(Primer_UL))
			{
				PartitionPrimer = new Primer;
				UInt32 ThisBytes = PartitionPrimer->ReadValue(BuffPtr, (UInt32)Len);
				Size -= ThisBytes;
				Bytes += ThisBytes;
				BuffPtr += ThisBytes;

				// Skip further processing for the primer
				continue;
			}
		}

		// Skip any filler items
		if(NewItem->IsA(KLVFill_UL))
		{
			Size -= Len;
			Bytes += Len;
			BuffPtr += Len;
			
			// Don't add the filler
			continue;
		}
		
		if(Len)
		{
			NewItem->SetParent(File, BytesAtItemStart + Location,(UInt32)( Bytes - BytesAtItemStart));

			NewItem->ReadValue(BuffPtr,(UInt32) Len, PartitionPrimer);

			// Skip total length, not just the length actually consumed
			Size -= Len;
			Bytes += Len;
			BuffPtr += Len;
		}

		AddMetadata(NewItem);
	}


	return Bytes + FillerBytes;
}
Пример #8
0
//! Load any metadictionaties that are in the list of currently loaded objects
bool mxflib::Partition::LoadMetadict(void)
{
	bool Ret = true;

	/* Search for the metadictionary */
	MDObjectList::iterator it = AllMetadata.begin();
	while(it != AllMetadata.end())
	{
		if((*it)->IsA(MetaDictionary_UL))
		{
			/* We need to set up a symbol space for this metadictionary
			   At the moment we attach it to one named with the instance ID of this metadictionary item */
			std::string SymSpaceName = (*it)->GetString(InstanceUID_UL);

			// If there was no InstanceUID, add a random symspace
			if(SymSpaceName.empty()) SymSpaceName = RandomUL()->GetString();
			
			// See if we already have this symbol space (may have already loaded a copy of this metadictionary) - if not, build it
            SymbolSpacePtr SymSpace = SymbolSpace::FindSymbolSpace(SymSpaceName);
			if(!SymSpace) SymSpace = new SymbolSpace(SymSpaceName);
			
			// Load the metdictionary and update the running status
			if(!LoadMetadictionary(*it, SymSpace)) Ret = false;
		}
		else if((*it)->IsA(Root_UL))
		{
			// FIXME: Use UL when ready
			//MDObjectPtr RootExtensions = (*it)->Child(RootExtensions_UL);
			MDObjectPtr RootExtensions = (*it)->Child("RootExtensions");
			if(RootExtensions)
			{
				MDObject::iterator Ext_it = RootExtensions->begin();
				while(Ext_it != RootExtensions->end())
				{
					// Get the actual data group
					MDObjectPtr ExtensionGroup = (*Ext_it).second->GetRef();

					if(!ExtensionGroup)
					{
						error("Broken link in ExtensionGroup reference at %s\n", (*Ext_it).second->GetSourceLocation().c_str());
					}
					else
					{
						/* We need to set up a symbol space for this metadictionary */
						// FIXME: Use UL when ready
						//std::string SymSpaceName = ExtensionGroup->GetString(SymbolSpace_UL);
						std::string SymSpaceName = ExtensionGroup->GetString("SymbolSpace");

						// If there was no SymbolSpace property, add a random symspace
						if(SymSpaceName.empty()) SymSpaceName = RandomUL()->GetString();
						
						// See if we already have this symbol space (may have already loaded a copy of this metadictionary) - if not, build it
						SymbolSpacePtr SymSpace = SymbolSpace::FindSymbolSpace(SymSpaceName);
						if(!SymSpace) SymSpace = new SymbolSpace(SymSpaceName);
						
						// Load the metdictionary and update the running status
						if(!LoadMetadictionary(ExtensionGroup, SymSpace)) Ret = false;
					}

					Ext_it++;
				}
			}
		}

		it++;
	}

	return Ret;
}
Пример #9
0
//! Satisfy, or record as un-matched, all outgoing references
void mxflib::Partition::ProcessChildRefs(MDObjectPtr ThisObject)
{
	MDObjectULList::iterator it = ThisObject->begin();
	while(it != ThisObject->end())
	{
		// Only try to match references if not already matched
		if(!(*it).second->GetLink())
		{
			ClassRef Ref = (*it).second->GetRefType();
			if(IsRefSource(Ref))
			{
				if(!(*it).second->Value)
				{
					if(Ref != ClassRefGlobal)
					{
						error("Metadata Object \"%s/%s\" should be a reference source (a UUID), but has no valid value\n",
							  ThisObject->Name().c_str(), (*it).second->Name().c_str());
					}
				}
				// Container for child items
				else if((*it).second->Value->GetData().Size == 0)
				{
					// Recurse to add refs for our children
					if((*it).second->size()) ProcessChildRefs((*it).second);
				}
				else if((*it).second->Value->GetData().Size != 16)
				{
					if(Ref == ClassRefGlobal)
					{
						error("Metadata Object \"%s/%s\" should be a global reference (a UL or UUID), but has size %d\n",
							  ThisObject->Name().c_str(), (*it).second->Name().c_str(), (*it).second->Value->GetData().Size);
					}
					else
					{
						error("Metadata Object \"%s/%s\" should be a reference source (a UUID), but has size %d\n",
							  ThisObject->Name().c_str(), (*it).second->Name().c_str(), (*it).second->Value->GetData().Size);
					}
				}
				else
				{
					UUIDPtr ID = new UUID((*it).second->Value->PutData()->Data);
					std::map<UUID, MDObjectPtr>::iterator mit = RefTargets.find(*ID);

					if(mit == RefTargets.end())
					{
						// Not matched yet, so add to the list of outstanding refs
						UnmatchedRefs.insert(std::multimap<UUID, MDObjectPtr>::value_type(*ID, (*it).second));
					}
					else
					{
						// Make the link
						(*it).second->SetLink((*mit).second);

						// If we have made a strong ref, remove the target from the top level
						if(Ref == DICT_REF_STRONG) TopLevelMetadata.remove((*mit).second);
					}
				}
			}
		}

		it++;
	}
}
Пример #10
0
//! Dump an object and any physical or logical children
void DumpObject(MDObjectPtr Object, std::string Prefix)
{
	if(DumpLocation) printf("0x%s : ", Int64toHexString(Object->GetLocation(),8).c_str());

	if(Object->IsModified()) printf("%s%s is *MODIFIED*\n", Object->FullName().c_str(), Prefix.c_str() );

#ifdef OPTION3ENABLED
	if(ShowBaseline)
	{
		if(!Object->IsBaseline())
		{
			if(Object->GetBaselineUL())
			{
				MDOTypePtr BaselineClass = MDOType::Find(Object->GetBaselineUL());
				if(BaselineClass)
				{
					printf("%sBaseline: %s\n", Prefix.c_str(), BaselineClass->Name().c_str());
				}
				else
				{
					printf("%sNote: Current dictionary does not contain a set with the baseline UL used to wrap this non-baseline class\n", Prefix.c_str());
					printf("%sBaseline: %s\n", Prefix.c_str(), Object->GetBaselineUL()->GetString().c_str());
				}
				Prefix += "  ";
			}
			else
			{
				printf("%sNote: Current dictionary flags this class as non-baseline, but it is not wrapped in a baseline class\n", Prefix.c_str());
			}
		}
		else
		{
			if(Object->GetBaselineUL())
			{
				printf("%sNote: Current dictionary flags this class as baseline, but it is wrapped as a non-baseline class\n", Prefix.c_str());

				MDOTypePtr BaselineClass = MDOType::Find(Object->GetBaselineUL());
				if(BaselineClass)
				{
					printf("%sBaseline: %s\n", Prefix.c_str(), BaselineClass->Name().c_str());
				}
				else
				{
					printf("%sNote: Current dictionary does not contain a set with the baseline UL used to wrap this non-baseline class\n", Prefix.c_str());
					printf("%sBaseline: %s\n", Prefix.c_str(), Object->GetBaselineUL()->GetString().c_str());
				}
				Prefix += "  ";
			}
		}
	}
#endif // OPTION3ENABLED

	if(Object->GetLink())
	{
		if(Object->GetRefType() == ClassRefStrong)
		{
			printf("%s%s = %s\n", Prefix.c_str(), Object->Name().c_str(), Object->GetString().c_str());

			if(DumpLocation) printf("0x%s : ", Int64toHexString(Object->GetLocation(),8).c_str());
			printf("%s%s -> Strong Reference to %s\n", Prefix.c_str(), Object->Name().c_str(), Object->GetLink()->Name().c_str());

			DumpObject(Object->GetLink(), Prefix + "  ");
		}
		else if(Object->GetRefType() == ClassRefGlobal)
		{
			if(FollowGlobals)
			{
				printf("%s%s = %s\n", Prefix.c_str(), Object->Name().c_str(), Object->GetString().c_str());

				if(DumpLocation) printf("0x%s : ", Int64toHexString(Object->GetLocation(),8).c_str());
				printf("%s%s -> Global Reference to %s\n", Prefix.c_str(), Object->Name().c_str(), Object->GetLink()->Name().c_str());

				DumpObject(Object->GetLink(), Prefix + "  ");
			}
			else
			{
				printf("%s%s -> Global Reference to %s, %s\n", Prefix.c_str(), Object->Name().c_str(), Object->GetLink()->Name().c_str(), Object->GetString().c_str());
			}
		}
		else if(Object->GetRefType() == ClassRefMeta)
		{
			std::string TargetName = Object->GetLink()->GetString(MetaDefinitionName_UL, Object->GetLink()->Name());
			printf("%s%s -> MetaDictionary Reference to %s %s\n", Prefix.c_str(), Object->Name().c_str(), TargetName.c_str(), Object->GetString().c_str());
		}
		else if(Object->GetRefType() == ClassRefDict)
		{
			std::string TargetName = Object->GetLink()->GetString(DefinitionObjectName_UL, Object->GetLink()->Name());
			printf("%s%s -> Dictionary Reference to %s %s\n", Prefix.c_str(), Object->Name().c_str(), TargetName.c_str(), Object->GetString().c_str());
		}
		else
		{
			printf("%s%s -> Weak Reference to %s %s\n", Prefix.c_str(), Object->Name().c_str(), Object->GetLink()->Name().c_str(), Object->GetString().c_str());
		}
	}
	else
	{
		if(Object->IsDValue())
		{
			printf("%s%s = <Unknown>\n", Prefix.c_str(), Object->Name().c_str());
		}
		else
		{
			// Check first for values that are not reference batches
			if(Object->IsAValue())
			{
//if(Object->Name().find("Unknown") == std::string::npos)
				printf("%s%s = %s\n", Prefix.c_str(), Object->Name().c_str(), Object->GetString().c_str());
//else			printf("%s%s\n", Prefix.c_str(), Object->Name().c_str());
if(Object->GetRefType() == ClassRefMeta)
	printf("%s%s is an unsatisfied MetaRef\n", Prefix.c_str(), Object->Name().c_str());
else if(Object->GetRefType() == ClassRefDict)
	printf("%s%s is an unsatisfied DictRef\n", Prefix.c_str(), Object->Name().c_str());
			}
			else
			{
				printf("%s%s\n", Prefix.c_str(), Object->Name().c_str());
				MDObjectULList::iterator it = Object->begin();

				if(!SortedDump)
				{
					/* Dump Objects in the order stored */
					while(it != Object->end())
					{
						DumpObject((*it).second, Prefix + "  ");
						it++;
					}
				}
				else
				{
					/* Dump Objects in alphabetical order - to allow easier file comparisons */
					std::multimap<std::string, MDObjectPtr> ChildMap;
					std::multimap<std::string, MDObjectPtr>::iterator CM_Iter;

					while(it != Object->end())
					{
						ChildMap.insert(std::multimap<std::string, MDObjectPtr>::value_type((*it).second->Name(), (*it).second));
						it++;
					}

					CM_Iter = ChildMap.begin();
					while(CM_Iter != ChildMap.end())
					{
						DumpObject((*CM_Iter).second, Prefix + "  ");
						CM_Iter++;
					}
				}
			}
		}
	}

	return;
}
Пример #11
0
//! Do the main processing (less any pause before exit)
int main_process(int argc, char *argv[])
{
	printf("Dump an MXF file using MXFLib\n");

	std::string DictName = "dict.xml";
	std::list<std::string> SuppDicts;
	int num_options = 0;
	for(int i=1; i<argc; i++)
	{
		if(argv[i][0] == '-')
		{
			num_options++;
			if((argv[i][1] == 'a') || (argv[i][1] == 'A'))
				SortedDump = true;
			else if((argv[i][1] == 'v') || (argv[i][1] == 'V'))
				DebugMode = true;
			else if((argv[i][1] == 'i') || (argv[i][1] == 'I'))
				FullIndex = true;
			else if((argv[i][1] == 'c') || (argv[i][1] == 'C'))
			{
				if(argv[i][2] == '0')
					DumpIDs = false;
				else
					CheckDump = true;
			}
			else if((argv[i][1] == 'b') || (argv[i][1] == 'B'))
				FullBody = true;
//			else if((argv[i][1] == 'g') || (argv[i][1] == 'G'))
//				FollowGlobals = true;
			else if((argv[i][1] == 'l') || (argv[i][1] == 'L'))
				DumpLocation = true;
#ifdef OPTION3ENABLED
			else if((argv[i][1] == 'o') || (argv[i][1] == 'O'))
				ShowBaseline = true;
#endif // OPTION3ENABLED
			else if((argv[i][1] == 'd') || (argv[i][1] == 'D'))
			{
				int Start = 2;
				if((Start == 2) && ((argv[i][Start] == 'd') || (argv[i][Start] == 'D'))) Start++;
				if((argv[i][Start] == '=') || (argv[i][Start] == ':')) Start++;
				if(argv[i][Start]) SuppDicts.push_back(&argv[i][Start]);
				else if(argc > (i+1))
				{
					SuppDicts.push_back(argv[++i]);
					num_options++;
				}
			}
			else if((argv[i][1] == 'u') || (argv[i][1] == 'U'))
			{
				MDObject::SetParseDark(true);
			}
			else if((argv[i][1] == 'x') || (argv[i][1] == 'X'))
			{
				if(argv[i][2] == '0') SetLabelFormat(LabelFormatHex);
				else if(argv[i][2] == '1') SetLabelFormat(LabelFormatTextHex);
				else SetLabelFormat(LabelFormatTextHexMask);
			}
			else if(tolower(argv[i][1]) == 't')
			{
				SetFeature(FeatureLoadMetadict);
				printf("Loading metadictionary contents from file\n");
				if(argv[i][2] == '1')
				{
					BootstrapDict = true;
					printf("Starting with only a minimum compiled-in dictionary\n");
				}
			}
			else if((argv[i][1] == 'm') || (argv[i][1] == 'M'))
			{
				int Start = 2;
				if((argv[i][Start] == '=') || (argv[i][Start] == ':')) Start++;
				if(argv[i][Start]) DictName = &argv[i][Start];
				else if(argc > (i+1))
				{
					DictName = argv[++i];
					num_options++;
				}
#ifdef COMPILED_DICT
				UseCompiledDict = false;
#endif // COMPILED_DICT
			}
			else if((argv[i][1] == 'z') || (argv[i][1] == 'Z'))
				PauseBeforeExit = true;
		}
	}

	if (argc - num_options < 2)
	{
		printf("\nUsage:   %s [options] <filename>\n\n", argv[0]);
		printf("Options: -a         Dump sub-items alpha-sorted\n");
		printf("         -b         Dump body partitions (rather than just header and footer)\n");
		printf("         -c         Check dump (produce simple counts for automated testing)\n");
		printf("         -c0        Don't dump UUID, UMID and Timestamp values (for comparing files)\n");
		printf("         -dd <dict> Load supplementary dictionary (also -d for legacy)\n");
		printf("         -g         Follow global references (if linked)\n");
		printf("         -i         Dump full index tables (can be lengthy)\n");
		printf("         -l         Show the location (byte offset) of metadata items dumped\n");
#ifdef COMPILED_DICT
		printf("         -m <dict>  Specify main dictionary (instead of compile-time version)\n");
#else
		printf("         -m <dict>  Specify main dictionary (instead of dict.xml)\n");
#endif // COMPILED_DICT
#ifdef OPTION3ENABLED
		printf("         -o         Show baseline UL for sets with ObjectClass property\n");
#endif // OPTION3ENABLED
		printf("         -t         Load metadictionary contents from file\n");
		printf("         -t1        Load metadictionary and start from a minimal subset\n");
		printf("         -u         Attempt to parse unknown or 'dark' sets\n");
		printf("         -v         Verbose mode - shows lots of debug info\n");
		printf("         -x0        Always show labels as hex data\n");
		printf("         -x1        Append hex data to labels\n");
		printf("         -x2 or -x  Append hex data to labels if 'fuzzy' matching used\n");
		printf("         -z         Pause for input before final exit\n");
		return 1;
	}

	if(BootstrapDict)
	{
		printf("- using a minimal compile-time dictionary and extending from metadictionary\n");
		LoadDictionary(BootDict);
	}
	else
	{
		if( UseCompiledDict )
		{
			printf("- using compile-time dictionary\n");
			LoadDictionary(DictData);
		}
		else
		{
			printf("- using dictionary %s\n", DictName.c_str());
			LoadDictionary(DictName);
		}
	}

	std::list<std::string>::iterator DictIt = SuppDicts.begin();
	while(DictIt != SuppDicts.end())
	{
		LoadDictionary(*DictIt);
		DictIt++;
	}

	// If we are NOT dumping IDs replace thier traits
	if(!DumpIDs)
	{
		UpdateTraitsMapping("Internal-UUID", new MessageTraits("{UUID}"));
		UpdateTraitsMapping("UUID", new MessageTraits("{UUID}"));
		UpdateTraitsMapping("UMID", new MessageTraits("{UMID}"));
		UpdateTraitsMapping("Timestamp", new MessageTraits("{Timestamp}"));
	}

	MXFFilePtr TestFile = new MXFFile;
	if (! TestFile->Open(argv[num_options+1], true))
	{
		perror(argv[num_options+1]);
		return 1;
	}

	// Get a RIP (however possible)
	TestFile->GetRIP();

	unsigned int PartitionNumber = 0;
	RIP::iterator it = TestFile->FileRIP.begin();
	while(it != TestFile->FileRIP.end())
	{
		PartitionNumber++;
		if(CheckDump)
			printf("\nPartition for BodySID 0x%04x\n", (*it).second->BodySID);
		else
			printf("\nPartition at 0x%s is for BodySID 0x%04x\n", Int64toHexString((*it).second->ByteOffset,8).c_str(), (*it).second->BodySID);

		// Only dump header and footer unless asked for all partitions
		if(FullBody || (PartitionNumber == 1) || (PartitionNumber == TestFile->FileRIP.size()))
		{
			TestFile->Seek((*it).second->ByteOffset);
			PartitionPtr ThisPartition = TestFile->ReadPartition();
			if(ThisPartition)
			{
				if(CheckDump)
				{
					if(ThisPartition->ReadMetadata() == 0)
					{
						printf("No header metadata in this partition\n");
					}
					else
					{
						printf(" Top level count = %d\n", (int)ThisPartition->TopLevelMetadata.size());
						printf(" Set/Pack count = %d\n", (int)ThisPartition->AllMetadata.size());
						
						size_t Count = 0;
						MDObjectList::iterator it = ThisPartition->AllMetadata.begin();
						while(it != ThisPartition->AllMetadata.end())
						{
							Count += (*it)->size();
							it++;
						}

						printf(" Sub item count = %d\n", (int)Count);
					}

					// Read any index table segments!
					MDObjectListPtr Segments = ThisPartition->ReadIndex();
					if(Segments->empty())
					{
						printf("No index table in this partition\n");
					}
					else
					{
						IndexTablePtr Table = new IndexTable;

						MDObjectList::iterator it = Segments->begin();

						while(it != Segments->end())
						{
							// Summarize this new segment
							
							UInt32 Streams = 1;
							MDObjectPtr DeltaEntryArray = (*it)[DeltaEntryArray_UL];
							if(DeltaEntryArray && DeltaEntryArray->GetType()->size())
							{
								Streams = static_cast<UInt32>(DeltaEntryArray->size() / DeltaEntryArray->GetType()->size());
								if(Streams == 0) Streams = 1;	// Fix for bad DeltaEntryArray
							}

							Position Start = (*it)->GetInt64(IndexStartPosition_UL);
							Length Duration = (*it)->GetInt64(IndexDuration_UL);
							UInt32 IndexSID = (*it)->GetUInt(IndexSID_UL);
							UInt32 BodySID = (*it)->GetUInt(BodySID_UL);
							
							if(Duration == 0) printf("CBR Index Table Segment (covering whole Essence Container) :\n");
							else printf("\nIndex Table Segment (first edit unit = %s, duration = %s) :\n", Int64toString(Start).c_str(), Int64toString(Duration).c_str());

							printf("  Indexing BodySID 0x%04x from IndexSID 0x%04x\n", BodySID, IndexSID);

							it++;
						}
					}
				}
				else
				{
					// Don't dump the last partition unless it is a footer or we are dumping all
					// DRAGONS: What is the PartitionNumber != RIP-Size thing about?
					if(FullBody || (PartitionNumber == 1) || (PartitionNumber != TestFile->FileRIP.size()) 
								|| (ThisPartition->IsA(CompleteFooter_UL)) || (ThisPartition->IsA(Footer_UL)) )
					{
						DumpObject(ThisPartition->Object,"");

						if(ThisPartition->ReadMetadata() == 0)
						{
							printf("No header metadata in this partition\n");
						}
						else
						{
							printf("\nHeader Metadata:\n");
							
							MDObjectList::iterator it2 = ThisPartition->TopLevelMetadata.begin();
							while(it2 != ThisPartition->TopLevelMetadata.end())
							{
								DumpObject(*it2,"  ");
								it2++;
							}
							printf("\n");
						}

						// Read any index table segments!
						MDObjectListPtr Segments = ThisPartition->ReadIndex();
						if(Segments->empty())
						{
							printf("No index table in this partition\n");
						}
						else
						{
							IndexTablePtr Table = new IndexTable;

							MDObjectList::iterator it = Segments->begin();

							while(it != Segments->end())
							{
								Table->AddSegment(*it);
							
								// Demonstrate this new segment
								
								UInt32 Streams = 1;
								MDObjectPtr DeltaEntryArray = (*it)[DeltaEntryArray_UL];
								if(DeltaEntryArray)
								{
									Streams = static_cast<UInt32>(DeltaEntryArray->size());
									if(Streams == 0) Streams = 1;	// Fix for bad DeltaEntryArray
								}

								Position Start = (*it)->GetInt64(IndexStartPosition_UL);
								Length Duration = (*it)->GetInt64(IndexDuration_UL);
								UInt32 IndexSID = (*it)->GetUInt(IndexSID_UL);
								UInt32 BodySID = (*it)->GetUInt(BodySID_UL);
								
								if(Duration == 0) printf("CBR Index Table Segment (covering whole Essence Container) :\n");
								else printf("\nIndex Table Segment (first edit unit = %s, duration = %s) :\n", Int64toString(Start).c_str(), Int64toString(Duration).c_str());

								printf("  Indexing BodySID 0x%04x from IndexSID 0x%04x\n", BodySID, IndexSID);

								if(Duration < 1) Duration = 6;		// Could be CBR
								if(!FullIndex && Duration > 35) Duration = 35;	// Don't go mad!

								int i;
								printf( "\n Bytestream Order:\n" );
								for(i=0; i<Duration; i++)
								{
									UInt32 j;
									for(j=0; j<Streams; j++)
									{
										IndexPosPtr Pos = Table->Lookup(Start + i,j,false);
										printf("  EditUnit %3s for stream %d is at 0x%s", Int64toString(Start + i).c_str(), j, Int64toHexString(Pos->Location,8).c_str());
										printf(", TempOffset=%d", Pos->TemporalOffset);
										printf(", Flags=%02x", Pos->Flags);
										if(Pos->Exact) printf("  *Exact*\n"); else printf("\n");
									}
								}

								printf( "\n Presentation Order:\n" );
								for(i=0; i<Duration; i++)
								{
									UInt32 j;
									for(j=0; j<Streams; j++)
									{
										IndexPosPtr Pos = Table->Lookup(Start + i,j);
										printf("  EditUnit %3s for stream %d is at 0x%s", Int64toString(Start + i).c_str(), j, Int64toHexString(Pos->Location,8).c_str());
										printf(", TempOffset=%d", Pos->TemporalOffset);
										printf(", Flags=%02x", Pos->Flags);
	///									printf(", Keyframe is at 0x%s", Int64toHexString(Pos->KeyLocation,8).c_str() );

										if(Pos->Exact) printf("  *Exact*\n");
										else if(Pos->OtherPos) printf(" (Location of un-reordered position %s)\n", Int64toString(Pos->ThisPos).c_str());
										else printf("\n");
									}
								}

								it++;
							}
						}
					}
				}
			}
		}

		it++;
	}

	if(TestFile->ReadRIP())
	{
		printf("\nRead RIP\n");
		PartitionInfoMap::iterator it = TestFile->FileRIP.begin();
		while(it != TestFile->FileRIP.end())
		{
			if(CheckDump)
				printf("  BodySID 0x%04x", (*it).second->BodySID);
			else
				printf("  BodySID 0x%04x is at 0x%s", (*it).second->BodySID, Int64toHexString((*it).second->ByteOffset,8).c_str());

			if((*it).second->ThePartition)
				printf(" type %s\n", (*it).second->ThePartition->Name().c_str());
			else
				printf(" and is not loaded\n");

			it++;
		}
	}

	if(TestFile->ScanRIP())
	{
		printf("\nScanned RIP\n");
		PartitionInfoMap::iterator it = TestFile->FileRIP.begin();
		while(it != TestFile->FileRIP.end())
		{
			if(CheckDump)
				printf("  BodySID 0x%04x", (*it).second->BodySID);
			else
				printf("  BodySID 0x%04x is at 0x%s", (*it).second->BodySID, Int64toHexString((*it).second->ByteOffset,8).c_str());

			if((*it).second->ThePartition)
				printf(" type %s\n", (*it).second->ThePartition->Name().c_str());
			else
				printf(" and is not loaded\n");

			it++;
		}
	}

/*	if(TestFile->BuildRIP())
	{
		printf("\nBuilt RIP\n");
		PartitionInfoList::iterator it = TestFile->FileRIP.begin();
		while(it != TestFile->FileRIP.end())
		{
			printf("  BodySID 0x%04x is at 0x%s", (*it)->BodySID, Int64toHexString((*it)->ByteOffset,8).c_str());

			if((*it)->ThePartition)
				printf(" type %s\n", (*it)->ThePartition->Name().c_str());
			else
				printf(" and is not loaded\n");

			it++;
		}
	}
*/
	TestFile->Close();

/*	PrimerPtr NewPrimer = new Primer;

	unsigned char Key[16] = { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x04, 0x04, 0x06, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00 };
	
	Tag ThisTag = NewPrimer->Lookup(new UL(Key));
	printf("Tag    = %s\n", Tag2String(ThisTag).c_str());

	Key[11] = 5;
	ThisTag = NewPrimer->Lookup(new UL(Key));
	printf("NewTag = %s\n", Tag2String(ThisTag).c_str());

	ThisTag = NewPrimer->Lookup(new UL(Key));
	printf("NewTag = %s\n", Tag2String(ThisTag).c_str());

	Key[12] = 1;
	ThisTag = NewPrimer->Lookup(new UL(Key));
	printf("NewTag = %s\n", Tag2String(ThisTag).c_str());
*/

	return 0;
}
Пример #12
0
//! Get the offset to add to lines in field 2
int ANCVBISource::Field2Offset(void)
{
	if(F2Offset >= 0) return F2Offset;

	MDObjectPtr Descriptor = MasterSource->GetDescriptor();
	if(!Descriptor)
	{
		error("EssenceDescriptor not defined for master source of ANCVBISource before calling Field2Offset()\n");
		F2Offset = 0;
		return F2Offset;
	}

	// If this is a multpile descriptor, locate the video
	// DRAGONS: If we can't find a picture descriptor we will drop through with the MultipleDescriptor and give a "does not have a VideoLineMap" error
	if(Descriptor->IsA(MultipleDescriptor_UL))
	{
		MDObject::iterator it = Descriptor->begin();
		while(it != Descriptor->end())
		{
			if((*it).second->IsA(GenericPictureEssenceDescriptor_UL))
			{
				Descriptor = (*it).second;
				break;
			}
			it++;
		}
	}


	/* Check if this is interlaced essence */

	if(Descriptor->IsDValue(FrameLayout_UL))
	{
		warning("EssenceDescriptor for ANCVBISource does not have a valid FrameLayout\n");
		F2Offset = 0;
		return F2Offset;
	}

	if(Descriptor->GetInt(FrameLayout_UL) != 1)
	{
		F2Offset = 0;
		return F2Offset;
	}

	
	/* Calculate F1 to F2 distance from Video Line Map */

	MDObjectPtr VideoLineMap = Descriptor->Child(VideoLineMap_UL);
	if(!VideoLineMap)
	{
		error("EssenceDescriptor for ANCVBISource does not have a valid VideoLineMap\n");
		F2Offset = 0;
		return F2Offset;
	}

	MDObjectPtr F1Entry = VideoLineMap->Child(0);
	MDObjectPtr F2Entry = VideoLineMap->Child(1);
	if((!F1Entry) || (!F2Entry))
	{
		error("EssenceDescriptor for ANCVBISource does not have a valid VideoLineMap\n");
		F2Offset = 0;
		return F2Offset;
	}

	F2Offset = static_cast<int>(F2Entry->GetInt() - F1Entry->GetInt());
	return F2Offset;
}
Пример #13
0
/*! \return A smart pointer to the new WrappingConfig for this source as a sub-stream of the specified master, or NULL if not a valid combination
 */
EssenceParser::WrappingConfigPtr ANCVBISource::MakeWrappingConfig(WrappingConfigPtr MasterCfg)
{
	EssenceParser::WrappingConfigPtr SubCfg;

	/* First we validate our requirements */

	// Only valid for frame wrapping
	if(MasterCfg->WrapOpt->ThisWrapType != WrappingOption::Frame) return SubCfg;

	// Not valid if we have no line sources
	if(Sources.empty()) return SubCfg;

	/* Now check each line source is happy */
	// TODO: Can we build a sub-set version where we only include those line sources that are happy?

	std::string Description;
	ANCVBILineSourceList::iterator it = Sources.begin();
	while(it != Sources.end())
	{
		std::string ThisDesc = (*it)->ValidateConfig(MasterCfg);
		if(ThisDesc.empty()) return SubCfg;

		if(!Description.empty()) Description += ", plus ";
		Description += ThisDesc;

		it++;
	}

	/* Requested wrapping is valid, build the new config */

	SubCfg = new EssenceParser::WrappingConfig();

	SubCfg->Parser = MasterCfg->Parser;

	SubCfg->WrapOpt = new WrappingOption();
	SubCfg->WrapOpt->Handler = SubCfg->Parser;
	SubCfg->WrapOpt->Name = "";
	SubCfg->WrapOpt->Description = Description;
	SubCfg->WrapOpt->GCEssenceType = GetGCEssenceType();
	SubCfg->WrapOpt->GCElementType = GetGCElementType();
	SubCfg->WrapOpt->ThisWrapType = MasterCfg->WrapOpt->ThisWrapType;
	SubCfg->WrapOpt->CanSlave = false;
	SubCfg->WrapOpt->CanIndex = false;
	SubCfg->WrapOpt->CBRIndex = false;
	SubCfg->WrapOpt->BERSize = 4;
	SubCfg->WrapOpt->BytesPerEditUnit = 0;

	SubCfg->WrapOpt->WrappingUL = GetWrappingUL();

	SubCfg->EssenceDescriptor = new MDObject(ANCDataDescriptor_UL);
	MDObjectPtr SampleRate = SubCfg->EssenceDescriptor->AddChild(SampleRate_UL);
	SampleRate->SetInt("Numerator", MasterCfg->EditRate.Numerator);
	SampleRate->SetInt("Denominator", MasterCfg->EditRate.Denominator);
	SubCfg->EssenceDescriptor->SetValue(EssenceContainer_UL, DataChunk(16,SubCfg->WrapOpt->WrappingUL->GetValue()));

	SubCfg->Stream = 0;
	SubCfg->EditRate = MasterCfg->EditRate;
	SubCfg->StartTimecode = 0;

	return SubCfg;
}