Exemple #1
0
void P2_MetaHandler::CacheFileData()
{
	XMP_Assert ( ! this->containsXMP );

	if ( this->parent->UsesClientIO() ) {
		XMP_Throw ( "P2 cannot be used with client-managed I/O", kXMPErr_InternalFailure );
	}

	// Make sure the clip's .XMP file exists.

	std::string xmpPath;
		
	this->MakeClipFilePath ( &xmpPath, ".XMP" );
	if ( ! Host_IO::Exists ( xmpPath.c_str() ) ) return;	// No XMP.

	// Read the entire .XMP file. We know the XMP exists, New_XMPFiles_IO is supposed to return 0
	// only if the file does not exist.

	bool readOnly = XMP_OptionIsClear ( this->parent->openFlags, kXMPFiles_OpenForUpdate );

	XMP_Assert ( this->parent->ioRef == 0 );
	XMPFiles_IO* xmpFile =  XMPFiles_IO::New_XMPFiles_IO ( xmpPath.c_str(), readOnly );
	if ( xmpFile == 0 ) XMP_Throw ( "P2 XMP file open failure", kXMPErr_InternalFailure );
	this->parent->ioRef = xmpFile;

	XMP_Int64 xmpLen = xmpFile->Length();
	if ( xmpLen > 100*1024*1024 ) {
		XMP_Throw ( "P2 XMP is outrageously large", kXMPErr_InternalFailure );	// Sanity check.
	}

	this->xmpPacket.erase();
	this->xmpPacket.append ( (size_t)xmpLen, ' ' );

	/*XMP_Int32 ioCount =*/ xmpFile->ReadAll ( (void*)this->xmpPacket.data(), (XMP_Int32)xmpLen );

	this->packetInfo.offset = 0;
	this->packetInfo.length = (XMP_Int32)xmpLen;
	FillPacketInfo ( this->xmpPacket, &this->packetInfo );

	this->containsXMP = true;

}	// P2_MetaHandler::CacheFileData
void MPEG2_MetaHandler::CacheFileData()
{
	bool readOnly = (! (this->parent->openFlags & kXMPFiles_OpenForUpdate));

	if ( this->parent->UsesClientIO() ) {
		XMP_Throw ( "MPEG2 cannot be used with client-managed I/O", kXMPErr_InternalFailure );
	}

	this->containsXMP = false;
	this->processedXMP = true;	// Whatever we do here is all that we do for XMPFiles::OpenFile.

	// Try to open the sidecar XMP file. Tolerate an open failure, there might not be any XMP.
	// Note that MPEG2_CheckFormat can't save the sidecar path because the handler doesn't exist then.

	if ( ! Host_IO::Exists ( this->sidecarPath.c_str() ) ) return;	// OK to not have XMP.

	XMPFiles_IO * localFile = XMPFiles_IO::New_XMPFiles_IO ( this->sidecarPath.c_str(), readOnly );
	if ( localFile == 0 ) XMP_Throw ( "Failure opening MPEG-2 XMP file", kXMPErr_ExternalFailure );
	this->parent->ioRef = localFile;

	// Extract the sidecar's contents and parse.

	this->packetInfo.offset = 0;	// We take the whole sidecar file.
	this->packetInfo.length = (XMP_Int32) localFile->Length();

	if ( this->packetInfo.length > 0 ) {

		this->xmpPacket.assign ( this->packetInfo.length, ' ' );
		localFile->ReadAll ( (void*)this->xmpPacket.c_str(), this->packetInfo.length );

		this->xmpObj.ParseFromBuffer ( this->xmpPacket.c_str(), (XMP_StringLen)this->xmpPacket.size() );
		this->containsXMP = true;

	}

	if ( readOnly ) {
		localFile->Close();
		delete localFile;
		this->parent->ioRef = 0;
	}

}	// MPEG2_MetaHandler::CacheFileData
Exemple #3
0
static bool ReadIDXFile ( const std::string& idxPath,
						  const std::string& clipName,
						  SXMPMeta* xmpObj,
						  bool& containsXMP,
						  MD5_CTX* md5Context,
						  bool digestFound )
{
	bool result = true;
	containsXMP = false;

	if ( clipName.size() != 25 ) return false;

	try {


		Host_IO::FileRef hostRef = Host_IO::Open ( idxPath.c_str(), Host_IO::openReadOnly );
		if ( hostRef == Host_IO::noFileRef ) return false;	// The open failed.
		XMPFiles_IO idxFile ( hostRef, idxPath.c_str(), Host_IO::openReadOnly );

		struct SHDV_HeaderBlock
		{
			char			mHeader[8];
			unsigned char	mValidFlag;
			unsigned char	mReserved;
			unsigned char	mECCTB;
			unsigned char   mSignalMode;
			unsigned char	mFileThousands;
			unsigned char	mFileHundreds;
			unsigned char	mFileTens;
			unsigned char	mFileUnits;
		};

		SHDV_HeaderBlock hdvHeaderBlock;
		memset ( &hdvHeaderBlock, 0, sizeof(SHDV_HeaderBlock) );

		idxFile.ReadAll ( hdvHeaderBlock.mHeader, 8 );
		idxFile.ReadAll ( &hdvHeaderBlock.mValidFlag, 1 );
		idxFile.ReadAll ( &hdvHeaderBlock.mReserved, 1 );
		idxFile.ReadAll ( &hdvHeaderBlock.mECCTB, 1 );
		idxFile.ReadAll ( &hdvHeaderBlock.mSignalMode, 1 );
		idxFile.ReadAll ( &hdvHeaderBlock.mFileThousands, 1 );
		idxFile.ReadAll ( &hdvHeaderBlock.mFileHundreds, 1 );
		idxFile.ReadAll ( &hdvHeaderBlock.mFileTens, 1 );
		idxFile.ReadAll ( &hdvHeaderBlock.mFileUnits, 1 );

		const int fileCount = (hdvHeaderBlock.mFileThousands - '0') * 1000 +
							  (hdvHeaderBlock.mFileHundreds  - '0') *  100 +
							  (hdvHeaderBlock.mFileTens      - '0') *   10 +
							  (hdvHeaderBlock.mFileUnits     - '0');

		// Read file info block.
		struct	SHDV_FileBlock
		{
			char			mDT[2];
			unsigned char	mFileNameYear;
			unsigned char	mFileNameMonth;
			unsigned char	mFileNameDay;
			unsigned char	mFileNameHour;
			unsigned char	mFileNameMinute;
			unsigned char	mFileNameSecond;
			unsigned char	mStartTimeCode[4];
			unsigned char	mTotalFrame[4];
		};

		SHDV_FileBlock hdvFileBlock;
		memset ( &hdvFileBlock, 0, sizeof(SHDV_FileBlock) );

		char filenameBuffer[256];
		std::string fileDateAndTime = clipName.substr(8);

		bool foundFileBlock = false;

		for ( int i=0; ((i < fileCount) && (! foundFileBlock)); ++i ) {

			idxFile.ReadAll ( hdvFileBlock.mDT, 2 );
			idxFile.ReadAll ( &hdvFileBlock.mFileNameYear, 1 );
			idxFile.ReadAll ( &hdvFileBlock.mFileNameMonth, 1 );
			idxFile.ReadAll ( &hdvFileBlock.mFileNameDay, 1 );
			idxFile.ReadAll ( &hdvFileBlock.mFileNameHour, 1 );
			idxFile.ReadAll ( &hdvFileBlock.mFileNameMinute, 1 );
			idxFile.ReadAll ( &hdvFileBlock.mFileNameSecond, 1 );
			idxFile.ReadAll ( &hdvFileBlock.mStartTimeCode, 4 );
			idxFile.ReadAll ( &hdvFileBlock.mTotalFrame, 4 );

			// Compose file name we expect from file contents and break out on match.
			sprintf ( filenameBuffer, "%02d-%02d-%02d_%02d%02d%02d",
					  hdvFileBlock.mFileNameYear + 2000,
					  hdvFileBlock.mFileNameMonth,
					  hdvFileBlock.mFileNameDay,
					  hdvFileBlock.mFileNameHour,
					  hdvFileBlock.mFileNameMinute,
					  hdvFileBlock.mFileNameSecond );

			foundFileBlock = (fileDateAndTime==filenameBuffer);

		}

		idxFile.Close();
		if ( ! foundFileBlock ) return false;

		// If digest calculation requested, calculate it and return.
		if ( md5Context != 0 ) {
			MD5Update ( md5Context, (XMP_Uns8*)(&hdvHeaderBlock), sizeof(SHDV_HeaderBlock) );
			MD5Update ( md5Context, (XMP_Uns8*)(&hdvFileBlock), sizeof(SHDV_FileBlock) );
		}

		// The xmpObj parameter must be provided in order to extract XMP
		if ( xmpObj == 0 ) return (md5Context != 0);

		// Standard def?
		const bool isSD = ((hdvHeaderBlock.mSignalMode == 0x80) || (hdvHeaderBlock.mSignalMode == 0));

		// Progressive vs interlaced extracted from high bit of ECCTB byte
		const bool clipIsProgressive = ((hdvHeaderBlock.mECCTB & 0x80) != 0);

		// Lowest three bits contain frame rate information
		const int sfr = (hdvHeaderBlock.mECCTB & 7) + (clipIsProgressive ? 0 : 8);

		// Sample scale and sample size.
		int clipSampleScale = 0;
		int clipSampleSize  = 0;
		std::string frameRate;

		// Frame rate
		switch ( sfr ) {
			case 0	: break; // Not valid in spec, but it's happening in test files.
			case 1	: clipSampleScale = 24000;	clipSampleSize = 1001; frameRate = "23.98p"; break;
			case 3	: clipSampleScale = 25;		clipSampleSize = 1;	   frameRate =    "25p"; break;
			case 4	: clipSampleScale = 30000;	clipSampleSize = 1001; frameRate = "29.97p"; break;
			case 11	: clipSampleScale = 25;		clipSampleSize = 1;	   frameRate =    "50i"; break;
			case 12	: clipSampleScale = 30000;	clipSampleSize = 1001; frameRate = "59.94i"; break;
		}

		containsXMP = true;

		// Frame size and PAR for HD (not clear on SD yet).
		std::string xmpString;
		XMP_StringPtr xmpValue = 0;

		if ( ! isSD ) {

			if ( digestFound || (! xmpObj->DoesPropertyExist ( kXMP_NS_DM, "videoFrameSize" )) ) {

				xmpValue = "1440";
				xmpObj->GetStructField ( kXMP_NS_DM, "videoFrameSize", kXMP_NS_DM, "w", &xmpString, 0 );
				if ( xmpString != xmpValue ) {
					xmpObj->SetStructField ( kXMP_NS_DM, "videoFrameSize", kXMP_NS_XMP_Dimensions, "w", xmpValue, 0 );
				}

				xmpValue = "1080";
				xmpObj->GetStructField ( kXMP_NS_DM, "videoFrameSize", kXMP_NS_DM, "h", &xmpString, 0 );
				if ( xmpString != xmpValue ) {
					xmpObj->SetStructField ( kXMP_NS_DM, "videoFrameSize", kXMP_NS_XMP_Dimensions, "h", xmpValue, 0 );
				}

				xmpValue = "pixels";
				xmpObj->GetStructField ( kXMP_NS_DM, "videoFrameSize", kXMP_NS_DM, "unit", &xmpString, 0 );
				if ( xmpString != xmpValue ) {
					xmpObj->SetStructField ( kXMP_NS_DM, "videoFrameSize", kXMP_NS_XMP_Dimensions, "unit", xmpValue, 0 );
				}
			}

			xmpValue = "4/3";
			if ( digestFound || (! xmpObj->DoesPropertyExist ( kXMP_NS_DM, "videoPixelAspectRatio" )) ) {
				xmpObj->SetProperty ( kXMP_NS_DM, "videoPixelAspectRatio", xmpValue, kXMP_DeleteExisting );
			}

		}

		// Sample size and scale.
		if ( clipSampleScale != 0 ) {

			char buffer[255];

			if ( digestFound || (! xmpObj->DoesPropertyExist ( kXMP_NS_DM, "startTimeScale" )) ) {
				sprintf(buffer, "%d", clipSampleScale);
				xmpValue = buffer;
				xmpObj->SetProperty ( kXMP_NS_DM, "startTimeScale", xmpValue, kXMP_DeleteExisting );
			}

			if ( digestFound || (! xmpObj->DoesPropertyExist ( kXMP_NS_DM, "startTimeSampleSize" )) ) {
				sprintf(buffer, "%d", clipSampleSize);
				xmpValue = buffer;
				xmpObj->SetProperty ( kXMP_NS_DM, "startTimeSampleSize", xmpValue, kXMP_DeleteExisting );
			}

			if ( digestFound || (! xmpObj->DoesPropertyExist ( kXMP_NS_DM, "duration" )) ) {

				const int frameCount = (hdvFileBlock.mTotalFrame[0] << 24) + (hdvFileBlock.mTotalFrame[1] << 16) +
									   (hdvFileBlock.mTotalFrame[2] << 8) + hdvFileBlock.mTotalFrame[3];

				sprintf ( buffer, "%d", frameCount );
				xmpValue = buffer;
				xmpObj->SetStructField ( kXMP_NS_DM, "duration", kXMP_NS_DM, "value", xmpValue, 0 );

				sprintf ( buffer, "%d/%d", clipSampleSize, clipSampleScale );
				xmpValue = buffer;
				xmpObj->SetStructField ( kXMP_NS_DM, "duration", kXMP_NS_DM, "scale", xmpValue, 0 );

			}

		}

		// Time Code.
		if ( digestFound || (! xmpObj->DoesPropertyExist ( kXMP_NS_DM, "startTimecode" )) ) {

			if ( (clipSampleScale != 0) && (clipSampleSize != 0) ) {

				const bool dropFrame = ( (0x40 & hdvFileBlock.mStartTimeCode[0]) != 0 ) && ( sfr == 4 || sfr == 12 );
				const char chDF = dropFrame ? ';' : ':';
				const int tcFrames  = ExtractTimeCodeByte ( hdvFileBlock.mStartTimeCode[0], 0x30 );
				const int tcSeconds = ExtractTimeCodeByte ( hdvFileBlock.mStartTimeCode[1], 0x70 );
				const int tcMinutes = ExtractTimeCodeByte ( hdvFileBlock.mStartTimeCode[2], 0x70 );
				const int tcHours   = ExtractTimeCodeByte ( hdvFileBlock.mStartTimeCode[3], 0x30 );

				// HH:MM:SS:FF or HH;MM;SS;FF
				char timecode[256];
				sprintf ( timecode, "%02d%c%02d%c%02d%c%02d", tcHours, chDF, tcMinutes, chDF, tcSeconds, chDF, tcFrames );
				std::string sonyTimeString = timecode;

				xmpObj->GetStructField ( kXMP_NS_DM, "startTimecode", kXMP_NS_DM, "timeValue", &xmpString, 0 );
				if ( xmpString != sonyTimeString ) {

					xmpObj->SetStructField ( kXMP_NS_DM, "startTimecode", kXMP_NS_DM, "timeValue", sonyTimeString, 0 );

					std::string timeFormat;
					if ( clipSampleSize == 1 ) {

						// 24, 25, 40, 50, 60
						switch ( clipSampleScale ) {
							case 24 : timeFormat = "24"; break;
							case 25 : timeFormat = "25"; break;
							case 50 : timeFormat = "50"; break;
							default : XMP_Assert ( false );
						}

						timeFormat += "Timecode";

					} else {

						// 23.976, 29.97, 59.94
						XMP_Assert ( clipSampleSize == 1001 );
						switch ( clipSampleScale ) {
							case 24000 : timeFormat = "23976"; break;
							case 30000 : timeFormat =  "2997"; break;
							case 60000 : timeFormat =  "5994"; break;
							default	   : XMP_Assert( false );  break;
						}

						timeFormat += dropFrame ? "DropTimecode" : "NonDropTimecode";

					}

					xmpObj->SetStructField ( kXMP_NS_DM, "startTimecode", kXMP_NS_DM, "timeFormat", timeFormat, 0 );

				}

			}

		}

		if ( digestFound || (! xmpObj->DoesPropertyExist ( kXMP_NS_DM, "CreateDate" )) ) {

			// Clip has date and time in the case of DT (otherwise date and time haven't been set).
			bool clipHasDate = ((hdvFileBlock.mDT[0] == 'D') && (hdvFileBlock.mDT[1] == 'T'));

			// Creation date
			if ( clipHasDate ) {

				// YYYY-MM-DDThh:mm:ssZ
				char date[256];
				sprintf ( date, "%4d-%02d-%02dT%02d:%02d:%02dZ",
						  hdvFileBlock.mFileNameYear + 2000,
						  hdvFileBlock.mFileNameMonth,
						  hdvFileBlock.mFileNameDay,
						  hdvFileBlock.mFileNameHour,
						  hdvFileBlock.mFileNameMinute,
						  hdvFileBlock.mFileNameSecond );

				XMP_StringPtr xmpDate = date;
				xmpObj->SetProperty ( kXMP_NS_XMP, "CreateDate", xmpDate, kXMP_DeleteExisting );

			}

		}

		// Frame rate.
		if ( digestFound || (! xmpObj->DoesPropertyExist ( kXMP_NS_DM, "videoFrameRate" )) ) {

			if ( frameRate.size() != 0 ) {
				xmpString = frameRate;
				xmpObj->SetProperty ( kXMP_NS_DM, "videoFrameRate", xmpString, kXMP_DeleteExisting );
			}

		}

	} catch ( ... ) {

		result = false;

	}

	return result;

}	// ReadIDXFile