1/* 2 * Copyright (c) 2009 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23#define __PRINT__ // Print headers don't compile for some reason 24#include <Carbon/Carbon.h> 25#include <QuickTime/QuickTime.h> 26 27#include <stdio.h> 28#include <stdlib.h> 29#include <pthread.h> 30 31#include <sys/types.h> 32#include <sys/stat.h> 33#include <fcntl.h> 34#include <iokit/IOKitLib.h> 35 36#include "IsochronousDataHandler.h" 37#include "DeviceControl.h" 38 39#define WRITEBUFF 1 40 41#if WRITEBUFF 42#define SYNC 0 43static Ptr myBuffer1, myBuffer2; 44#endif 45 46static int issued = 0; 47static int completed = 0; 48pthread_mutex_t globalsMutex; // lock this before updating globals 49pthread_cond_t syncCond; // To synchronize threads. 50int finished=0; 51static int file = 0; 52static QTAtomSpec videoConfig; 53static int frameSize = 120000; // NTSC 144000 PAL 54static char *sFile; 55static int sSDL; 56static int sDVCPro; 57static int sDVCPro50; 58static int sFormat = 0; // DV 59static int sLoop; 60static UInt64 sGUID = 0; 61 62static void printP(const char *s) 63{ 64 int len = *s++; 65 while(len--) 66 printf("%c", *s++); 67} 68 69static void print4(const char *s, UInt32 val) 70{ 71 printf("%s'%c%c%c%c'(0x%x)", s, val>>24, val>>16, val>>8, val, val); 72} 73 74// called when a new isoch write is done 75static OSStatus DVIsochComponentWriteCallback( IDHGenericEvent *eventRecord, void *userData) 76{ 77 struct timeval tod; 78 OSErr result = noErr; 79 IDHParameterBlock *pb = (IDHParameterBlock *) eventRecord; 80 81 ComponentInstance theInst = userData; 82 if(file) { 83 int len; 84 len = read(file, pb->buffer, frameSize); 85 //len = read(file, myBuffer, frameSize); 86 if(len < frameSize) { 87 pthread_mutex_lock(&globalsMutex); 88 finished = 1; 89 pthread_mutex_unlock(&globalsMutex); 90 pthread_cond_broadcast(&syncCond); 91 printf("Completed %d\n", completed++); 92 return result; 93 } 94 } 95#if WRITEBUFF 96#else 97 pb->buffer = nil; 98#endif 99 // fill out structure 100 pb->requestedCount = frameSize; 101 pb->actualCount = 0; 102 pb->completionProc = DVIsochComponentWriteCallback; 103 // do another write 104 //gettimeofday(&tod, NULL); 105 //printf("Completed %d, issuing write %d @ %d:%d\n", completed++, issued, tod.tv_sec, tod.tv_usec); 106 result = IDHWrite( theInst, pb); 107 if( result != noErr) { 108 printf("IDHWrite error %d\n", result); 109 } 110 issued++; 111 return result; 112} 113 114static OSErr doWriteTest(ComponentInstance theInst) 115{ 116 struct timeval tod; 117 TimeRecord time; 118 IDHParameterBlock isochParamBlock1, isochParamBlock2; 119 ComponentResult err; 120 int len; 121 122 finished = 0; 123 err = pthread_mutex_init(&globalsMutex, NULL); 124 err = pthread_cond_init(&syncCond, NULL); 125 126 file = open(sFile, O_RDONLY, 0666); 127 printf("open file: %d\n", file); 128#if WRITEBUFF 129 if(!myBuffer1) 130 myBuffer1 = NewPtr(frameSize); 131 if(!myBuffer2) 132 myBuffer2 = NewPtr(frameSize); 133 read(file, myBuffer1, frameSize); 134 isochParamBlock1.buffer = myBuffer1; 135#else 136 isochParamBlock1.buffer = nil; 137#endif 138 isochParamBlock1.requestedCount = frameSize; // NTSC buffer size 139 isochParamBlock1.actualCount = 0; 140 isochParamBlock1.refCon = (void *)theInst; 141 142#if SYNC 143 isochParamBlock1.completionProc = nil; 144#else 145 isochParamBlock1.completionProc = DVIsochComponentWriteCallback; 146#endif 147 148 isochParamBlock2 = isochParamBlock1; 149 150 // open the DV device for writing 151 err = IDHOpenDevice( theInst, kIDHOpenForWriteTransactions); 152 if( err != noErr) 153 goto error; 154 155 printf("Opened device\n"); 156 157 //err = IDHGetDeviceTime(theInst, &time); 158 //if( err != noErr) 159 // goto error; 160 //gettimeofday(&tod, NULL); 161 //printf("issuing write %d @ %d:%d = 0x%x:0x%x\n", 162 //issued, tod.tv_sec, tod.tv_usec, time.value.hi, time.value.lo); 163 err = IDHWrite( theInst, &isochParamBlock1); 164 if( err != noErr) 165 goto error; 166 err = IDHGetDeviceTime(theInst, &time); 167 if( err != noErr) 168 goto error; 169 gettimeofday(&tod, NULL); 170 printf("issued write %d @ %d:%d = 0x%x:0x%x\n", 171 issued, tod.tv_sec, tod.tv_usec, time.value.hi, time.value.lo); 172 issued++; 173#if SEND2 174#if WRITEBUFF 175 read(file, myBuffer2, frameSize); 176 isochParamBlock2.buffer = myBuffer2; 177#endif 178 err = IDHWrite( theInst, &isochParamBlock2); 179 if( err != noErr) 180 goto error; 181 err = IDHGetDeviceTime(theInst, &time); 182 if( err != noErr) 183 goto error; 184 gettimeofday(&tod, NULL); 185 printf("issued write %d @ %d:%d = 0x%x:0x%x\n", 186 issued, tod.tv_sec, tod.tv_usec, time.value.hi, time.value.lo); 187 issued++; 188#endif 189 190#if SYNC 191 do { 192 len = read(file, myBuffer1, frameSize); 193 if(len != frameSize) { 194 finished = 1; 195 break; 196 } 197 err = IDHWrite( theInst, &isochParamBlock1); 198 if( err != noErr) 199 goto error; 200 err = IDHGetDeviceTime(theInst, &time); 201 if( err != noErr) 202 goto error; 203 gettimeofday(&tod, NULL); 204 printf("issued write %d @ %d:%d = 0x%x:0x%x\n", 205 issued, tod.tv_sec, tod.tv_usec, time.value.hi, time.value.lo); 206 issued++; 207 } while (true); 208#endif 209 210 // Wait for work thread to finish initializing globals 211 err = pthread_mutex_lock(&globalsMutex); 212 while(!finished) { 213 err = pthread_cond_wait(&syncCond, &globalsMutex); 214 } 215 err = pthread_mutex_unlock(&globalsMutex); 216 217 // close the DV device 218 err = IDHCloseDevice( theInst); 219 if( err != noErr) 220 goto error; 221 printf("Did %d frames\n", issued); 222 223 printf("Closed device\n"); 224 225 close(sFile); 226 227error: 228 if(err) 229 printf("Error %d(0x%x) in doWriteTest\n", err, err); 230 return err; 231} 232 233 234static void OpenDV() 235{ 236 ComponentInstance theInst; 237 ComponentResult version; 238 QTAtomContainer deviceList = NULL; 239 short nDVDevices, i, j; 240 QTAtom deviceAtom; 241 UInt32 cmpFlag; 242 UInt32 isoversion; 243 long size; 244 OSErr err; 245 246 theInst = OpenDefaultComponent('ihlr', 'dv '); 247 printf("Instance is 0x%x\n", theInst); 248 if(theInst == NULL) 249 return; 250 251 version = CallComponentVersion(theInst); 252 printf("Version is 0x%x\n", version); 253 254 do { 255 err = IDHGetDeviceList( theInst, &deviceList); 256 if( err != noErr) 257 goto error; 258 259 nDVDevices = QTCountChildrenOfType( deviceList, kParentAtomIsContainer, kIDHDeviceAtomType); 260 if(nDVDevices > 0) 261 break; 262 printf("Waiting for a camera...\n"); 263 sleep(1); 264 } while(true); 265 266 267 QTLockContainer( deviceList); 268 // find the cmp atom 269 deviceAtom = QTFindChildByIndex( deviceList, kParentAtomIsContainer, kIDHUseCMPAtomType, 1, nil); 270 if( deviceAtom == nil) 271 goto error; 272 273 // get the value of the cmp atom 274 QTCopyAtomDataToPtr( deviceList, deviceAtom, true, sizeof( cmpFlag), &cmpFlag, &size); 275 276 // find the version atom 277 deviceAtom = QTFindChildByIndex( deviceList, kParentAtomIsContainer, kIDHIsochVersionAtomType, 1, nil); 278 if( deviceAtom == nil) 279 goto error; 280 281 // get the value of the version atom 282 QTCopyAtomDataToPtr( deviceList, deviceAtom, true, sizeof( isoversion), &isoversion, &size); 283 284 printf("Version 0x%x. %d DV devices, use CMP flag is %d\n", isoversion, nDVDevices, cmpFlag); 285 286 for( i=0; i<nDVDevices; ++i) 287 { 288 QTAtom isochAtom, dataAtom; 289 UInt64 test; 290 int nConfigs; 291 char cameraName[256]; 292 IDHDeviceID deviceID; 293 IDHDeviceStatus deviceStatus; 294 295 // get the atom to this device 296 deviceAtom = QTFindChildByIndex( deviceList, kParentAtomIsContainer, kIDHDeviceAtomType, i + 1, nil); 297 if( deviceAtom == nil) 298 goto error; 299 300 printf("device %d ", i); 301 302 dataAtom = QTFindChildByIndex( deviceList, deviceAtom, kIDHUniqueIDType, 1, nil); 303 if( dataAtom == nil) 304 goto error; 305 QTCopyAtomDataToPtr( deviceList, dataAtom, true, sizeof( test), &test, &size); 306 printf("guid 0x%016llx ", test); 307 dataAtom = QTFindChildByIndex( deviceList, deviceAtom, kIDHNameAtomType, 1, nil); 308 if( dataAtom == nil) 309 goto error; 310 QTCopyAtomDataToPtr( deviceList, dataAtom, true, 255, cameraName, &size); 311 cameraName[size] = 0; 312 printf("%s ", cameraName+1); 313 314 dataAtom = QTFindChildByIndex( deviceList, deviceAtom, kIDHDeviceIDType, 1, nil); 315 if( dataAtom == nil) 316 goto error; 317 QTCopyAtomDataToPtr( deviceList, dataAtom, true, sizeof( deviceID), &deviceID, &size); 318 printf("deviceID 0x%x ", deviceID); 319 320 dataAtom = QTFindChildByIndex( deviceList, deviceAtom, 'ddin', 1, nil); 321 if( dataAtom == nil) 322 goto error; 323 QTCopyAtomDataToPtr( deviceList, dataAtom, true, sizeof( deviceStatus), &deviceStatus, &size); 324 printf("\ndevice status:\n"); 325 printf("version %d\n", deviceStatus.version); 326 printf("physicallyConnected %d\n", deviceStatus.physicallyConnected); 327 printf("readEnabled %d ", deviceStatus.readEnabled); 328 printf("writeEnabled %d ", deviceStatus.writeEnabled); 329 printf("exclusiveAccess %d\n", deviceStatus.exclusiveAccess); 330 printf("currentBandwidth %d ", deviceStatus.currentBandwidth); 331 printf("currentChannel %d ", deviceStatus.currentChannel); 332 printf("inputStandard %d ", deviceStatus.inputStandard); 333 printf("deviceActive %d\n", deviceStatus.deviceActive); 334 printf("supported DV types %x\n", deviceStatus.outputFormats); 335 336 // find the isoch characteristics for this device 337 isochAtom = QTFindChildByIndex( deviceList, deviceAtom, kIDHIsochServiceAtomType, 1, nil); 338 if( isochAtom == nil) 339 goto error; 340 341 // how many configs exist for this device 342 nConfigs = QTCountChildrenOfType( deviceList, isochAtom, kIDHIsochModeAtomType); 343 printf("\n%d configs:\n", nConfigs); 344 345 videoConfig.atom = nil; // start with no selected config 346 347 // process each config 348 for( j=0; j<nConfigs; ++j) 349 { 350 OSType mediaType; 351 QTAtom configAtom, mediaAtom, nameAtom; 352 353 // get this configs atom 354 configAtom = QTFindChildByIndex( deviceList, isochAtom, kIDHIsochModeAtomType, j + 1, nil); 355 if( configAtom == nil) 356 goto error; 357 358 printf("Config %d",j); 359 // find the media type atom 360 mediaAtom = QTFindChildByIndex( deviceList, configAtom, kIDHIsochMediaType, 1, nil); 361 if( mediaAtom == nil) 362 goto error; 363 364 // get the value of the mediaType atom 365 QTCopyAtomDataToPtr( deviceList, mediaAtom, true, sizeof( mediaType), &mediaType, &size); 366 print4(" Media type:", mediaType); 367 nameAtom = QTFindChildByIndex( deviceList, configAtom, kIDHNameAtomType, 1, nil); 368 if( nameAtom != nil) { 369 QTCopyAtomDataToPtr( deviceList, nameAtom, true, 255, cameraName, &size); 370 cameraName[size] = 0; 371 printf(" name '%s' ", cameraName+1); 372 } 373 // is this config an video config? 374 if( mediaType == kIDHVideoMediaAtomType) // found video device 375 { 376 QTAtom frameSizeAtom; 377 frameSizeAtom = QTFindChildByIndex( deviceList, configAtom, 378 kIDHDataBufferSizeAtomType, 1, nil); 379 // ignore DV_SDL config 380 if(strcmp(cameraName+1, "DV-SDL")) { 381 if(frameSizeAtom) { 382 QTCopyAtomDataToPtr( deviceList, frameSizeAtom, true, sizeof( frameSize), &frameSize, &size); 383 if(sSDL) 384 frameSize /= 2; 385 if (sDVCPro50) 386 frameSize *= 2; 387 printf("Config buffer size %d\n", frameSize); 388 } 389 videoConfig.container = deviceList; // save this config 390 videoConfig.atom = configAtom; 391 } 392 } 393 printf("\n"); 394 } 395 printf("-----\n"); 396 if(sGUID == test) 397 break; 398 } 399 400 if( videoConfig.atom == nil) // no good configs found 401 goto error; 402 403 printf("setting config\n"); 404 // set isoch to use this config 405 err = IDHSetDeviceConfiguration( theInst, &videoConfig); 406 if( err != noErr) 407 goto error; 408 409 IDHSetFormat( theInst, sFormat); 410 411 err = doWriteTest(theInst); 412 413 if( err != noErr) 414 goto error; 415 416error: 417 if( err != noErr) 418 printf("error %d(0x%x)\n", err, err); 419 if(deviceList) { 420 QTUnlockContainer( deviceList); 421 QTDisposeAtomContainer(deviceList); 422 } 423 424 CloseComponent(theInst); 425 426} 427 428 429int main(int argc, char **argv) 430{ 431 UInt32 seed = GetComponentListModSeed(); 432 UInt32 num; 433 Handle aName; 434 ComponentDescription desc, aDesc; 435 Component aComponent; 436 ComponentInstance theInst; 437 ComponentResult version; 438 439 int pos = 1; 440 441 sFile = "/tmp/dump.dv"; 442 sSDL = 0; 443 sDVCPro = 0; 444 sDVCPro50 = 0; 445 446 while(argc > pos) { 447 if(strcmp(argv[pos], "-sdl") == 0) 448 sSDL = 1; 449 else if(strcmp(argv[pos], "-DVCPro") == 0) 450 sDVCPro = 1; 451 else if(strcmp(argv[pos], "-DVCPro50") == 0) 452 sDVCPro50 = 1; 453 else if(strcmp(argv[pos], "-l") == 0) 454 sLoop = 1; 455 else if(strcmp(argv[pos], "-guid") == 0 && argc > pos + 1) { 456 pos++; 457 sGUID = strtoq(argv[pos], NULL, 0); 458 } 459 else 460 sFile = argv[pos]; 461 pos++; 462 } 463 464 if(sSDL) { 465 frameSize /= 2; 466 sFormat = kIDHDV_SDL; 467 } 468 else if(sDVCPro) { 469 sFormat = kIDHDVCPro_25; 470 } 471 else if(sDVCPro50) { 472 frameSize *= 2; 473 sFormat = kIDHDVCPro_50; 474 } 475 476 477 printf("Reading from %s\n", sFile); 478 printf("Component seed is %d\n", seed); 479 desc.componentType = 'ihlr'; /* A unique 4-byte code indentifying the command set */ 480 desc.componentSubType = 0; /* Particular flavor of this instance */ 481 desc.componentManufacturer = 0; /* Vendor indentification */ 482 desc.componentFlags = 0; /* 8 each for Component,Type,SubType,Manuf/revision */ 483 desc.componentFlagsMask = 0; /* Mask for specifying which flags to consider in search, zero during registration */ 484 485 num = CountComponents(&desc); 486 printf("%d components match\n", num); 487 488 aComponent = 0; 489 aName = NewHandleClear(200); 490 while (aComponent = FindNextComponent(aComponent, &desc)) { 491 OSErr oops; 492 printf("Found component 0x%x:", aComponent); 493 oops = GetComponentInfo(aComponent, &aDesc, aName, 494 NULL, NULL); 495 if(oops) 496 printf("GetComponentInfo() returned error %d\n", oops); 497 else { 498 if(GetHandleSize(aName)) 499 printP(*aName); 500 else 501 printf("Unnamed"); 502 print4(", Type ", aDesc.componentType); 503 504 print4(", SubType ", aDesc.componentSubType); 505 print4(", Manufacturer ", aDesc.componentManufacturer); 506 printf("\n"); 507 } 508 } 509 510 do { 511 OpenDV(); 512 } while (sLoop); 513 return 0; 514} 515 516