TuttleOFX  1
DPXHeader.cpp
Go to the documentation of this file.
00001 // -*- mode: C++; tab-width: 4 -*-
00002 // vi: ts=4
00003 
00004 /*
00005  * Copyright (c) 2009, Patrick A. Palmer.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions are met:
00010  *
00011  *   - Redistributions of source code must retain the above copyright notice,
00012  *     this list of conditions and the following disclaimer.
00013  *
00014  *   - Redistributions in binary form must reproduce the above copyright
00015  *     notice, this list of conditions and the following disclaimer in the
00016  *     documentation and/or other materials provided with the distribution.
00017  *
00018  *   - Neither the name of Patrick A. Palmer nor the names of its
00019  *     contributors may be used to endorse or promote products derived from
00020  *     this software without specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
00023  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
00025  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
00026  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
00027  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
00028  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
00029  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
00030  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
00031  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
00032  * POSSIBILITY OF SUCH DAMAGE.
00033  */
00034  
00035  
00036 
00037 #include <cassert>
00038 #include <cstdio>
00039 #include <cstring>
00040 #include <ctime>
00041 #include <limits>
00042 
00043 
00044 #include "DPXHeader.h"
00045 #include "EndianSwap.h"
00046 
00047 
00048 
00049 // function prototypes
00050 static void EmptyString(char *, const int);
00051 
00052 
00053 
00054 
00055 char Hex(char x)
00056 {
00057         if (x >= 10) 
00058                 return (x-10+'A');
00059         else
00060                 return (x+'0');
00061 }
00062 
00063 
00064 
00065 dpx::Header::Header() : GenericHeader(), IndustryHeader(), datumSwap(true)
00066 {
00067 }
00068 
00069 
00070 
00071 dpx::GenericHeader::GenericHeader() 
00072 {
00073         this->Reset();
00074 }
00075 
00076 
00077 void dpx::GenericHeader::Reset()
00078 {
00079         // File Information
00080         this->magicNumber = MAGIC_COOKIE;
00081         this->imageOffset = ~0;
00082         EmptyString(this->version, 8);
00083         ::strcpy(this->version, SMPTE_VERSION);
00084         fileSize = sizeof(dpx::Header);
00085         this->dittoKey = 1;                                                                     // new
00086 
00087         // genericSize is the size of the file/image/orientation headers
00088         // sizeof(dpx::GenericHeader) won't give the correct results because
00089         // of compiler padding
00090         //              file header is 768 bytes
00091         //              image header is 640 bytes
00092         //              orientation header 256 bytes
00093 
00094         this->genericSize = 768 + 640 + 256;
00095 
00096         // industrySize is the size of the motion picture/television headers
00097         //              motion picture header is 256 bytes
00098         //              television header is 128 bytes
00099         this->industrySize = 256 + 128;
00100 
00101         this->userSize = 0;
00102         EmptyString(this->fileName, 100);
00103         EmptyString(this->creationTimeDate, 24);
00104         EmptyString(this->creator, 100);
00105         EmptyString(this->project, 200);
00106         EmptyString(this->copyright, 200);
00107         this->encryptKey = 0xffffffff;
00108         EmptyString(this->reserved1, 104);
00109 
00110         // Image Information
00111         this->imageOrientation = kUndefinedOrientation;
00112         this->numberOfElements = 0xffff;
00113         this->pixelsPerLine = this->linesPerElement = 0xffffffff;
00114         EmptyString(this->reserved2, 52);
00115 
00116         // Image Orientation
00117         this->xOffset = this->yOffset = 0xffffffff;
00118         this->xCenter = this->yCenter = std::numeric_limits<float>::quiet_NaN();
00119         this->xOriginalSize = this->yOriginalSize = 0xffffffff;
00120         EmptyString(this->sourceImageFileName, 100);
00121         EmptyString(this->sourceTimeDate, 24);
00122         EmptyString(this->inputDevice, 32);
00123         EmptyString(this->inputDeviceSerialNumber, 32);
00124         this->border[0] = this->border[1] = this->border[2] = this->border[3] = 0xffff;
00125         this->aspectRatio[0] = this->aspectRatio[1] = 0xffffffff;
00126         this->xScannedSize = this->yScannedSize = std::numeric_limits<float>::quiet_NaN();
00127         EmptyString(this->reserved3, 28);
00128 }
00129 
00130 
00131 dpx::IndustryHeader::IndustryHeader()
00132 {
00133         this->Reset();
00134 }
00135 
00136 
00137 void dpx::IndustryHeader::Reset()
00138 {
00139         // Motion Picture Industry Specific
00140         EmptyString(this->filmManufacturingIdCode, 2);
00141         EmptyString(this->filmType, 2);
00142         EmptyString(this->perfsOffset, 2);
00143         EmptyString(this->prefix, 6);
00144         EmptyString(this->count, 4);
00145         EmptyString(this->format, 32);
00146         this->framePosition = this->sequenceLength = this->heldCount = 0xffffffff;
00147         this->frameRate = this->shutterAngle = std::numeric_limits<float>::quiet_NaN();
00148         EmptyString(this->frameId, 32);
00149         EmptyString(this->slateInfo, 200);
00150         EmptyString(this->reserved4, 56);
00151 
00152         // Television Industry Specific
00153         this->timeCode = this->userBits = 0xffffffff;
00154         this->interlace = this->fieldNumber = 0xff;
00155         this->videoSignal = kUndefined;
00156         this->zero = 0xff;
00157         this->horizontalSampleRate = this->verticalSampleRate = this->temporalFrameRate = std::numeric_limits<float>::quiet_NaN();
00158         this->timeOffset = this->gamma = std::numeric_limits<float>::quiet_NaN();
00159         this->blackLevel = this->blackGain = std::numeric_limits<float>::quiet_NaN();
00160         this->breakPoint = this->whiteLevel = this->integrationTimes = std::numeric_limits<float>::quiet_NaN();
00161         EmptyString(this->reserved5, 76);
00162 }
00163 
00164 
00165 dpx::ImageElement::ImageElement()
00166 {
00167         this->dataSign = 0xffffffff;
00168         this->lowData = 0xffffffff;
00169         this->lowQuantity = 0xffffffff;
00170         this->highData = 0xffffffff;
00171         this->highQuantity = 0xffffffff;
00172         this->descriptor = kUndefinedDescriptor;
00173         this->transfer = kUndefinedCharacteristic;      
00174         this->colorimetric = kUndefinedCharacteristic;
00175         this->bitDepth = 0xff;
00176         this->packing = this->encoding = 0xffff;
00177         this->dataOffset = this->endOfLinePadding = this->endOfImagePadding = 0xffffffff;
00178         EmptyString(this->description, 32);
00179 }
00180 
00181 
00182 bool dpx::Header::Read(InStream *io)
00183 {
00184         // rewind file
00185         io->Rewind();
00186 
00187         // read in the header from the file
00188         size_t r = sizeof(GenericHeader) + sizeof(IndustryHeader);
00189         if (io->Read(&(this->magicNumber), r) != r)
00190                 return false;
00191 
00192         // validate
00193         return this->Validate();
00194 }
00195 
00196 
00197 // Check to see if the compiler placed the data members in the expected memory offsets
00198 
00199 bool dpx::Header::Check()
00200 {
00201         // genericSize is the size of the file/image/orientation headers
00202         // sizeof(dpx::GenericHeader) won't give the correct results because
00203         // of compiler padding
00204         //              file header is 768 bytes
00205         //              image header is 640 bytes
00206         //              orientation header 256 bytes
00207 
00208         if (sizeof(GenericHeader) != (768 + 640 + 256))
00209                 return false;
00210 
00211         // industrySize is the size of the motion picture/television headers
00212         //              motion picture header is 256 bytes
00213         //              television header is 128 bytes
00214         if (sizeof(IndustryHeader) != (256 + 128))
00215                 return false;
00216         
00217         // data size checks
00218         if (sizeof(U8) != 1 || sizeof(U16) != 2 || sizeof(U32) != 4 || sizeof(R32) != 4 || sizeof(R64) != 8)
00219                 return false;
00220                 
00221         return true;
00222 }
00223 
00224 
00225 
00226 bool dpx::Header::Write(OutStream *io)
00227 {
00228         // validate and byte swap, if necessary
00229         if (!this->Validate())
00230                 return false;
00231 
00232         // write the header to the file
00233         size_t r = sizeof(GenericHeader) + sizeof(IndustryHeader);
00234         if (io->Write(&(this->magicNumber), r) != r)
00235                 return false;
00236 
00237         // swap back - data is in file, now we need it native again
00238         this->Validate();
00239         return true;
00240 }
00241 
00242 
00243 bool dpx::Header::WriteOffsetData(OutStream *io)
00244 {
00245         // calculate the number of elements
00246         this->CalculateNumberOfElements();
00247 
00248         // write the image offset
00249         const long FIELD2 = 4;                  // offset to image in header
00250         if (io->Seek(FIELD2, OutStream::kStart) == false)
00251                 return false;
00252         if (this->RequiresByteSwap())
00253                 SwapBytes(this->imageOffset);
00254         if (io->Write(&this->imageOffset, sizeof(U32)) == false)
00255                 return false;
00256         if (this->RequiresByteSwap())
00257                 SwapBytes(this->imageOffset);
00258                         
00259         
00260         // write the file size
00261         const long FIELD4 = 16;                 // offset to total image file size in header
00262         if (io->Seek(FIELD4, OutStream::kStart) == false)
00263                 return false;
00264         if (this->RequiresByteSwap())
00265                 SwapBytes(this->fileSize);
00266         if (io->Write(&this->fileSize, sizeof(U32)) == false)
00267                 return false;
00268         if (this->RequiresByteSwap())
00269                 SwapBytes(this->fileSize);
00270                         
00271         // write the number of elements
00272         const long FIELD19 = 770;               // offset to number of image elements in header
00273         if (io->Seek(FIELD19, OutStream::kStart) == false)
00274                 return false;
00275         if (this->RequiresByteSwap())
00276                 SwapBytes(this->numberOfElements);
00277         if (io->Write(&this->numberOfElements, sizeof(U16)) == false)
00278                 return false;
00279         if (this->RequiresByteSwap())
00280                 SwapBytes(this->numberOfElements);
00281         
00282         // write the image offsets
00283         const long FIELD21_12 = 808;    // offset to image offset in image element data structure
00284         const long IMAGE_STRUCTURE = 72;        // sizeof the image data structure
00285         
00286         int i;
00287         for (i = 0; i < MAX_ELEMENTS; i++)
00288         {
00289                         // only write if there is a defined image description
00290                         if (this->chan[i].descriptor == kUndefinedDescriptor)
00291                                 continue;
00292                                 
00293                         // seek to the image offset entry in each image element
00294                         if (io->Seek((FIELD21_12 + (IMAGE_STRUCTURE * i)), OutStream::kStart) == false)
00295                                 return false;
00296 
00297                         // write
00298                         if (this->RequiresByteSwap())
00299                                 SwapBytes(this->chan[i].dataOffset);
00300                         if (io->Write(&this->chan[i].dataOffset, sizeof(U32)) == false)
00301                                 return false;
00302                         if (this->RequiresByteSwap())
00303                                 SwapBytes(this->chan[i].dataOffset);
00304 
00305         }
00306         
00307         return true;
00308 }
00309 
00310 
00311 bool dpx::Header::ValidMagicCookie(const U32 magic)
00312 {
00313         U32 mc = MAGIC_COOKIE;
00314         
00315         if (magic == mc)
00316                 return true;
00317         else if (magic == SwapBytes(mc))
00318                 return true;
00319         else
00320                 return false;
00321 }
00322 
00323 
00324 bool dpx::Header::DetermineByteSwap(const U32 magic) const
00325 {
00326         U32 mc = MAGIC_COOKIE;
00327         
00328         bool byteSwap = false;
00329         
00330         if (magic != mc)
00331                 byteSwap = true;
00332         
00333         return byteSwap;
00334 }
00335 
00336                 
00337 bool dpx::Header::Validate()
00338 {
00339         // check magic cookie
00340         if (!this->ValidMagicCookie(this->magicNumber))
00341                 return false;
00342                 
00343         // determine if bytes needs to be swapped around
00344         if (this->DetermineByteSwap(this->magicNumber))
00345         {
00346                 // File information
00347                 SwapBytes(this->imageOffset);
00348                 SwapBytes(this->fileSize);
00349                 SwapBytes(this->dittoKey);
00350                 SwapBytes(this->genericSize);
00351                 SwapBytes(this->industrySize);
00352                 SwapBytes(this->userSize);
00353                 SwapBytes(this->encryptKey);
00354 
00355                 // Image information
00356                 SwapBytes(this->imageOrientation);
00357                 SwapBytes(this->numberOfElements);
00358                 SwapBytes(this->pixelsPerLine);
00359                 SwapBytes(this->linesPerElement);
00360                 for (int i = 0; i < MAX_ELEMENTS; i++) 
00361                 {
00362                         SwapBytes(this->chan[i].dataSign);
00363                         SwapBytes(this->chan[i].lowData);
00364                         SwapBytes(this->chan[i].lowQuantity);
00365                         SwapBytes(this->chan[i].highData);
00366                         SwapBytes(this->chan[i].highQuantity);
00367                         SwapBytes(this->chan[i].descriptor);
00368                         SwapBytes(this->chan[i].transfer);
00369                         SwapBytes(this->chan[i].colorimetric);
00370                         SwapBytes(this->chan[i].bitDepth);
00371                         SwapBytes(this->chan[i].packing);
00372                         SwapBytes(this->chan[i].encoding);
00373                         SwapBytes(this->chan[i].dataOffset);
00374                         SwapBytes(this->chan[i].endOfLinePadding);
00375                         SwapBytes(this->chan[i].endOfImagePadding);
00376                 }
00377 
00378 
00379                 // Image Origination information
00380                 SwapBytes(this->xOffset);
00381                 SwapBytes(this->yOffset);
00382                 SwapBytes(this->xCenter);
00383                 SwapBytes(this->yCenter);
00384                 SwapBytes(this->xOriginalSize);
00385                 SwapBytes(this->yOriginalSize);
00386                 SwapBytes(this->border[0]);
00387                 SwapBytes(this->border[1]);
00388                 SwapBytes(this->border[2]);
00389                 SwapBytes(this->border[3]);
00390                 SwapBytes(this->aspectRatio[0]);
00391                 SwapBytes(this->aspectRatio[1]);
00392 
00393 
00394                 // Motion Picture Industry Specific
00395                 SwapBytes(this->framePosition);
00396                 SwapBytes(this->sequenceLength);
00397                 SwapBytes(this->heldCount);
00398                 SwapBytes(this->frameRate);
00399                 SwapBytes(this->shutterAngle);
00400 
00401 
00402                 // Television Industry Specific
00403                 SwapBytes(this->timeCode);
00404                 SwapBytes(this->userBits);
00405                 SwapBytes(this->interlace);
00406                 SwapBytes(this->fieldNumber);
00407                 SwapBytes(this->videoSignal);
00408                 SwapBytes(this->zero);
00409                 SwapBytes(this->horizontalSampleRate);
00410                 SwapBytes(this->verticalSampleRate);
00411                 SwapBytes(this->temporalFrameRate);
00412                 SwapBytes(this->timeOffset);
00413                 SwapBytes(this->gamma);
00414                 SwapBytes(this->blackLevel);
00415                 SwapBytes(this->blackGain);
00416                 SwapBytes(this->breakPoint);
00417                 SwapBytes(this->whiteLevel);
00418                 SwapBytes(this->integrationTimes);
00419         }
00420         
00421         return true;
00422 }
00423 
00424 
00425 
00426 void dpx::Header::Reset()
00427 {
00428         GenericHeader::Reset();
00429         IndustryHeader::Reset();
00430 }
00431 
00432 
00433 int dpx::GenericHeader::ImageElementComponentCount(const int element) const
00434 {
00435         int count = 1;
00436 
00437         switch (this->chan[element].descriptor) 
00438         {
00439         case kUserDefinedDescriptor:
00440         case kRed:
00441         case kGreen:
00442         case kBlue:
00443         case kAlpha:
00444         case kLuma:
00445         case kColorDifference:
00446         case kDepth:
00447                 count = 1;
00448                 break;
00449         case kCompositeVideo:
00450                 count = 1; 
00451                 break;
00452         case kRGB:
00453                 count = 3;
00454                 break;
00455         case kRGBA:
00456         case kABGR:
00457                 count = 4;
00458                 break;
00459         case kCbYCrY:
00460                 count = 2;
00461                 break;
00462         case kCbYACrYA:
00463                 count = 3;
00464                 break;
00465         case kCbYCr:
00466                 count = 3;
00467                 break;
00468         case kCbYCrA:
00469                 count = 4;
00470                 break;
00471         case kUserDefined2Comp:                 
00472                 count = 2; 
00473                 break;
00474         case kUserDefined3Comp:
00475                 count = 3;
00476                 break;
00477         case kUserDefined4Comp:
00478                 count = 4;
00479                 break;
00480         case kUserDefined5Comp:
00481                 count = 5;
00482                 break;
00483         case kUserDefined6Comp:
00484                 count = 6;
00485                 break;
00486         case kUserDefined7Comp:
00487                 count = 7;
00488                 break;
00489         case kUserDefined8Comp:
00490                 count = 8;
00491                 break;
00492         };
00493 
00494         return count;
00495 }
00496 
00497 
00498 int dpx::GenericHeader::ImageElementCount() const
00499 {
00500         if(this->numberOfElements>0 && this->numberOfElements<=MAX_ELEMENTS)
00501                 return this->numberOfElements;
00502         
00503         // If the image header does not list a valid number of elements,
00504         // count how many defined image descriptors we have...
00505         
00506         int i = 0;
00507         
00508         while (i < MAX_ELEMENTS )
00509         {
00510                 if (this->ImageDescriptor(i) == kUndefinedDescriptor)
00511                         break;
00512                 i++;
00513         }
00514         
00515         return i;
00516 }
00517 
00518 
00519 void dpx::GenericHeader::CalculateNumberOfElements()
00520 {
00521         this->numberOfElements = 0xffff;
00522         int i = this->ImageElementCount();
00523         
00524         if (i == 0)
00525                 this->numberOfElements = 0xffff;
00526         else
00527                 this->numberOfElements = U16(i);        
00528 }
00529 
00530 
00531 void dpx::Header::CalculateOffsets()
00532 {
00533         int i;
00534 
00535         for (i = 0; i < MAX_ELEMENTS; i++)
00536         {
00537                 // only write if there is a defined image description
00538                 if (this->chan[i].descriptor == kUndefinedDescriptor)
00539                         continue;
00540         
00541 
00542         }
00543 }
00544 
00545 
00546 dpx::DataSize dpx::GenericHeader::ComponentDataSize(const int element) const
00547 {
00548         if (element < 0 || element >= MAX_ELEMENTS)
00549                 return kByte;
00550                 
00551         dpx::DataSize ret;
00552         
00553         switch (this->chan[element].bitDepth)
00554         {
00555         case 8:
00556                 ret = kByte;
00557                 break;
00558         case 10:
00559         case 12:
00560         case 16:
00561                 ret = kWord;
00562                 break;
00563         case 32:
00564                 ret = kFloat;
00565                 break;
00566         case 64:
00567                 ret = kDouble;
00568                 break;
00569         default:
00570                 assert(0 && "Unknown bit depth");
00571                 ret = kDouble;
00572                 break;
00573         }
00574         
00575         return ret;
00576 }
00577 
00578 
00579 int dpx::GenericHeader::ComponentByteCount(const int element) const
00580 {
00581         if (element < 0 || element >= MAX_ELEMENTS)
00582                 return kByte;
00583                 
00584         int ret;
00585         
00586         switch (this->chan[element].bitDepth)
00587         {
00588         case 8:
00589                 ret = sizeof(U8);
00590                 break;
00591         case 10:
00592         case 12:
00593         case 16:
00594                 ret = sizeof(U16);
00595                 break;
00596         case 32:
00597                 ret = sizeof(R32);
00598                 break;
00599         case 64:
00600                 ret = sizeof(R64);
00601                 break;
00602         default:
00603                 assert(0 && "Unknown bit depth");
00604                 ret = sizeof(R64);
00605                 break;
00606         }
00607         
00608         return ret;
00609 }
00610 
00611 
00612 int dpx::GenericHeader::DataSizeByteCount(const DataSize ds)
00613 {
00614 
00615         int ret;
00616         
00617         switch (ds)
00618         {
00619         case kByte:
00620                 ret = sizeof(U8);
00621                 break;
00622         case kWord:
00623                 ret = sizeof(U16);
00624                 break;
00625         case kInt:
00626                 ret = sizeof(U32);
00627                 break;
00628         case kFloat:
00629                 ret = sizeof(R32);
00630                 break;
00631         case kDouble:
00632                 ret = sizeof(R64);
00633                 break;
00634         }
00635         
00636         return ret;
00637 }
00638 
00639 
00640 void dpx::IndustryHeader::FilmEdgeCode(char *edge) const
00641 {
00642         edge[0] = this->filmManufacturingIdCode[0];
00643         edge[1] = this->filmManufacturingIdCode[1];
00644         edge[2] = this->filmType[0];
00645         edge[3] = this->filmType[1];
00646         edge[4] = this->perfsOffset[0];
00647         edge[5] = this->perfsOffset[1];
00648         edge[6] = this->prefix[0];
00649         edge[7] = this->prefix[1];
00650         edge[8] = this->prefix[2];
00651         edge[9] = this->prefix[3];
00652         edge[10] = this->prefix[4];
00653         edge[11] = this->prefix[5];
00654         edge[12] = this->count[0];
00655         edge[13] = this->count[1];
00656         edge[14] = this->count[2];
00657         edge[15] = this->count[3];
00658         edge[16] = '\0';
00659 }
00660 
00661 
00662 void dpx::IndustryHeader::SetFileEdgeCode(const char *edge)
00663 {
00664         this->filmManufacturingIdCode[0] = edge[0];
00665         this->filmManufacturingIdCode[1] = edge[1];
00666         this->filmType[0] = edge[2];
00667         this->filmType[1] = edge[3];
00668         this->perfsOffset[0] = edge[4];
00669         this->perfsOffset[1] = edge[5];
00670         this->prefix[0] = edge[6];
00671         this->prefix[1] = edge[7];
00672         this->prefix[2] = edge[8];
00673         this->prefix[3] = edge[9];
00674         this->prefix[4] = edge[10];
00675         this->prefix[5] = edge[11];
00676         this->count[0] = edge[12];
00677         this->count[1] = edge[13];
00678         this->count[2] = edge[14];
00679         this->count[3] = edge[15];
00680 }
00681 
00682 
00683 void dpx::IndustryHeader::TimeCode(char *str) const
00684 {
00685         register U32 tc = this->timeCode;
00686         ::sprintf(str, "%c%c:%c%c:%c%c:%c%c", 
00687                 Hex((tc & 0xf0000000) >> 28),  Hex((tc & 0xf000000) >> 24),
00688                 Hex((tc & 0xf00000) >> 20),  Hex((tc & 0xf0000) >> 16),
00689                 Hex((tc & 0xf000) >> 12),  Hex((tc & 0xf00) >> 8),
00690                 Hex((tc & 0xf0) >> 4),  Hex(tc & 0xf));
00691 }
00692 
00693 
00694 void dpx::IndustryHeader::UserBits(char *str) const
00695 {
00696         register U32 ub = this->userBits;
00697         ::sprintf(str, "%c%c:%c%c:%c%c:%c%c", 
00698                 Hex((ub & 0xf0000000) >> 28),  Hex((ub & 0xf000000) >> 24),
00699                 Hex((ub & 0xf00000) >> 20),  Hex((ub & 0xf0000) >> 16),
00700                 Hex((ub & 0xf000) >> 12),  Hex((ub & 0xf00) >> 8),
00701                 Hex((ub & 0xf0) >> 4),  Hex(ub & 0xf));
00702 }
00703 
00704 
00705 dpx::U32 dpx::IndustryHeader::TCFromString(const char *str) const
00706 {
00707         // make sure the string is the correct length
00708         if (::strlen(str) != 11)
00709                 return U32(~0);
00710 
00711         U32 tc = 0;
00712         int i, idx;
00713         U8 ch;
00714         U32 value, mask;
00715 
00716         for (i = 0; i < 8; i++)
00717         {
00718                 // determine string index skipping :
00719                 idx = i + ((i + 1) / 3);
00720                 ch = str[idx];
00721 
00722                 // error check
00723                 if (ch < '0' || ch > '9')
00724                         return 0xffffffff;
00725 
00726                 value = U32(ch - '0') << (28 - (i*4));
00727                 mask = 0xf << (28 - (i*4));
00728 
00729                 // mask in new value
00730                 tc = (tc & ~mask) | (value & mask);
00731         }
00732 
00733         return tc;
00734 }
00735 
00736 
00737 void dpx::IndustryHeader::SetTimeCode(const char *str)
00738 {
00739         U32 tc = this->TCFromString(str);
00740         if (tc != 0xffffffff)
00741                 this->timeCode = tc;
00742 }
00743 
00744 
00745 void dpx::IndustryHeader::SetUserBits(const char *str)
00746 {
00747         U32 ub = this->TCFromString(str);
00748         if (ub != 0xffffffff)
00749                 this->timeCode = ub;
00750 }
00751                 
00752 
00753 
00754 static void EmptyString(char *str, const int len)
00755 {
00756         for (int i = 0; i < len; i++)
00757                 str[i] = '\0';
00758 }
00759 
00760 
00761 void dpx::GenericHeader::SetCreationTimeDate(const long sec)
00762 {
00763         struct tm *tm_time;
00764         char str[32];
00765         
00766 #ifdef WIN32
00767         _tzset();
00768 #endif
00769 
00770         const time_t t = time_t(sec);
00771         tm_time = ::localtime(&t);
00772         ::strftime(str, 32, "%Y:%m:%d:%H:%M:%S%Z", tm_time);
00773         ::strncpy(this->creationTimeDate, str, 24);
00774 }
00775 
00776 
00777 void dpx::GenericHeader::SetSourceTimeDate(const long sec)
00778 {
00779         struct tm *tm_time;
00780         char str[32];
00781         
00782 #ifdef WIN32
00783         _tzset();
00784 #endif
00785 
00786         const time_t t = time_t(sec);
00787         tm_time = ::localtime(&t);
00788         ::strftime(str, 32, "%Y:%m:%d:%H:%M:%S%Z", tm_time);
00789         ::strncpy(this->sourceTimeDate, str, 24);
00790 }
00791 
00792 
00793 
00794 bool dpx::Header::DatumSwap(const int element) const
00795 {
00796         if (this->datumSwap)
00797         {
00798                 if (this->ImageDescriptor(element) == kRGB || this->ImageDescriptor(element) == kCbYCrY)
00799                         return true;
00800         }
00801         return false;
00802 }
00803 
00804 
00805 void dpx::Header::SetDatumSwap(const bool swap)
00806 {
00807         this->datumSwap = swap;
00808 }
00809 
00810 // Height()
00811 // this function determines the height of the image taking in account for the image orientation
00812 // if an image is 1920x1080 but is oriented top to bottom, left to right then the height stored
00813 // in the image is 1920 rather than 1080
00814 
00815 dpx::U32 dpx::Header::Height() const
00816 {
00817         U32 h;
00818         
00819         switch (this->ImageOrientation())
00820         {
00821         case kTopToBottomLeftToRight:
00822         case kTopToBottomRightToLeft:
00823         case kBottomToTopLeftToRight:
00824         case kBottomToTopRightToLeft:
00825                 h = this->PixelsPerLine();
00826                 break;
00827         default:        
00828                 h = this->LinesPerElement();
00829                 break;
00830         }
00831 
00832         return h;
00833 }
00834 
00835 
00836 // Width()
00837 // this function determines the width of the image taking in account for the image orientation
00838 // if an image is 1920x1080 but is oriented top to bottom, left to right then the width stored
00839 // in the image is 1920 rather than 1080
00840 
00841 dpx::U32 dpx::Header::Width() const
00842 {
00843         U32 w;
00844 
00845         switch (this->ImageOrientation())
00846         {
00847         case kTopToBottomLeftToRight:
00848         case kTopToBottomRightToLeft:
00849         case kBottomToTopLeftToRight:
00850         case kBottomToTopRightToLeft:
00851                 w = this->LinesPerElement();
00852                 break;
00853         default:        
00854                 w = this->PixelsPerLine();
00855                 break;
00856         }
00857 
00858         return w;
00859 }
00860 
00861 
00862