示例#1
0
// skip over a KLV packet
UInt64 mxflib::Partition::Skip( UInt64 start )
{
	if( !start ) return 0;

	MXFFilePtr PF = Object->GetParentFile();

	PF->Seek( start );
	ULPtr FirstUL = PF->ReadKey();
	if(!FirstUL) return 0;

	// do the skip
	Length Len = PF->ReadBER();
	PF->Seek( PF->Tell() + Len );

	UInt64 ret = PF->Tell();

	// check in case we've hit the next Partition Pack
	ULPtr NextUL = PF->ReadKey();
	if(!NextUL) return 0;

	// Is this a partition pack?
	if(IsPartitionKey(NextUL->GetValue())) return 0;

	return ret;
}
示例#2
0
/*! If the UL has not yet been used the correct static or dynamic tag will 
 *	be determined and added to the primer
 *	\return The tag to use, or 0 if no more dynamic tags available
 */
Tag Primer::Lookup(ULPtr ItemUL, Tag TryTag /*=0*/)
{
	// If a tag has been suggested then try that
	if(TryTag != 0)
	{
		// Is it known by us?
		Primer::iterator it = find(TryTag);
		if(it != end())
		{
			// Only use it if the UL matches
			if(!memcmp((*it).second.GetValue(), ItemUL->GetValue(), 16)) return TryTag;
		}
		else
		{
			// It could be the right tag, but not yet in this primer
			// DRAGONS: Not implementer yet!!!
		}
	}

	// Do we have this UL already?
	std::map<UL, Tag>::iterator it = TagLookup.find(ItemUL);
	if(it != TagLookup.end())
	{
		return (*it).second;
	}

	// Try and find the type with this UL
	MDOTypePtr Type = MDOType::Find(ItemUL);
	if(Type)
	{
		if(Type->GetKey().Size != 2)
		{
			// No static tag supplied - fall through and use a dynamic tag
		}
		else
		{
			Tag ThisTag = (Type->GetKey().Data[0] << 8) + Type->GetKey().Data[1];
			insert(Primer::value_type(ThisTag, ItemUL));
			return ThisTag;
		}
	}

	// Generate a dynamic tag
	// DRAGONS: Not very efficient
	while(NextDynamic >= 0x8000)
	{
		if(find(NextDynamic) == end())
		{
			Tag Ret = NextDynamic;
			NextDynamic--;
			insert(Primer::value_type(Ret, ItemUL));
			return Ret;
		}
		NextDynamic--;
	}

	//! Out of dynamic tags!
	error("Run out of dynamic tags!\n");
	return 0;
}
示例#3
0
// skip over any KLVFill
// DRAGONS: does not iterate - only copes with single KLVFill
UInt64 mxflib::Partition::SkipFill( UInt64 start )
{
	if( !start ) return 0;

	MXFFilePtr PF = Object->GetParentFile();

	PF->Seek( start );
	ULPtr FirstUL = PF->ReadKey();
	if(!FirstUL) return 0;

	if(FirstUL->Matches(KLVFill_UL))
	{
		// Skip over the KLVFill
		Length Len = PF->ReadBER();
		PF->Seek( PF->Tell() + Len );
	}
	else
	{
		// was not KLVFill, so stay where we are
		PF->Seek( start );
	}

	UInt64 ret = PF->Tell();

	// check in case we've hit the next Partition Pack
	ULPtr NextUL = PF->ReadKey();
	if(!NextUL) return 0;

	// Is this a partition pack?
	if(IsPartitionKey(NextUL->GetValue()))
	{
		UInt8 byte14 = (NextUL->GetValue())[13];
		if( byte14 == 2 || byte14 == 3 || byte14 == 4 )	return 0;
		// we've found a Partition Pack - end of Body -- DRAGONS:?? Not true!!

		if( byte14 == 0x11 )	return 0;
		// we've found a RIP - end of Body
	}

	return ret;
}
示例#4
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;
}