TuttleOFX
1
|
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