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/* 24 cc -framework QuickTime -I/System/Library/Extensions/IOFWDV.kext/Headers -I/System/Library/Frameworks/QuickTime.framework/Headers -I/System/Library/Frameworks/Carbon.framework/Headers testcomp.c /System/Library/Extensions/IOFWDV.kext/libIOFWDV.a -o testcomp 25 */ 26 27#include <stdio.h> 28#include <stdlib.h> 29 30#include <sys/types.h> 31#include <sys/stat.h> 32#include <fcntl.h> 33#include <iokit/IOKitLib.h> 34 35//#define TARGET_CARBON 1 36#include <Carbon/Carbon.h> 37 38//#include <Carbon/MacMemory.h> 39//#include <Carbon/Components.h> 40 41#include "IsochronousDataHandler.h" 42#include "DeviceControl.h" 43 44static int done = 0; 45static int file = 0; 46static QTAtomSpec videoConfig; 47 48static void printP(const char *s) 49{ 50 int len = *s++; 51 while(len--) 52 printf("%c", *s++); 53} 54 55static void print4(const char *s, UInt32 val) 56{ 57 printf("%s'%c%c%c%c'(0x%x)", s, val>>24, val>>16, val>>8, val, val); 58} 59 60// called when a new isoch read is received 61static OSStatus DVIsochComponentReadCallback( IDHGenericEvent *eventRecord, void *userData) 62{ 63 OSErr result = noErr; 64 IDHParameterBlock *pb = (IDHParameterBlock *) eventRecord; 65 66#if 1 67 ComponentInstance theInst = userData; 68 69 if(file) 70 write(file, pb->buffer, pb->actualCount); 71 72 result = IDHReleaseBuffer( theInst, pb); 73 // fill out structure 74 pb->buffer = NULL; 75 pb->requestedCount = 120000; 76 pb->actualCount = 0; 77 pb->completionProc = DVIsochComponentReadCallback; 78 // do another read 79 result = IDHRead( theInst, pb); 80 if( result != noErr) { 81 printf("IDHRead error %d\n", result); 82 } 83#else 84 printf("read complete for block 0x%x, refcon 0x%x\n", pb, userData); 85#endif 86 done++; 87 return result; 88} 89 90// called when a new isoch read is received 91static OSStatus DVIsochComponentWriteCallback( IDHGenericEvent *eventRecord, void *userData) 92{ 93 OSErr result = noErr; 94 IDHParameterBlock *pb = (IDHParameterBlock *) eventRecord; 95 96#if 1 97 ComponentInstance theInst = userData; 98 99 if(file) { 100 int len; 101 len = read(file, pb->buffer, 120000); 102 if(len < 120000) 103 return result; 104 } 105#if WRITEBUFF 106#else 107 pb->buffer = nil; 108#endif 109 // fill out structure 110 pb->requestedCount = 120000; 111 pb->actualCount = 0; 112 pb->completionProc = DVIsochComponentWriteCallback; 113 // do another write 114 result = IDHWrite( theInst, pb); 115 if( result != noErr) { 116 printf("IDHWrite error %d\n", result); 117 } 118#else 119 printf("write complete for block 0x%x, refcon 0x%x\n", pb, userData); 120#endif 121 done++; 122 return result; 123} 124 125static void doControlTest(ComponentInstance theInst, QTAtomSpec *currentIsochConfig) 126{ 127 //Component control; 128 ComponentInstance controlInst; 129 ComponentResult result; 130 IDHDeviceStatus devStatus; 131 DVCTransactionParams pParams; 132 char in[4], out[16]; 133 int i; 134 135 result = IDHGetDeviceControl(theInst, &controlInst); 136 if(result) 137 goto Exit; 138 //controlInst = OpenComponent(control); 139 // get the local node's fw ref id 140 result = IDHGetDeviceStatus( theInst, currentIsochConfig, &devStatus); 141 if(result) 142 goto Exit; 143 //result = FWClockPrivSetFWReferenceID(clockInst, (FWReferenceID) devStatus.localNodeID ); 144 //if(result) 145 // goto Exit; 146 147 // set the clock's fw id 148 //clockInst = OpenDefaultComponent(clockComponentType, systemMicrosecondClock); 149 150 if(!controlInst) 151 goto Exit; 152 153 154 // fill up the avc frame 155 in[0] = 0x00; //kAVCControlCommand; 156 in[1] = 0x20; // for now 157 in[2] = 0xc3; //kAVCPlayOpcode; 158 in[3] = 0x75; //kAVCPlayForward; 159 160 // fill up the transaction parameter block 161 pParams.commandBufferPtr = in; 162 pParams.commandLength = sizeof(in); 163 pParams.responseBufferPtr = out; 164 pParams.responseBufferSize = sizeof(out); 165 pParams.responseHandler = NULL; 166 167 do { 168 for(i=0; i<sizeof(out); i++) 169 out[i] = 0; 170 result = DeviceControlDoAVCTransaction( controlInst, &pParams); 171 if(result == kIOReturnOffline) { 172 printf("offline!!\n"); 173 sleep(1); 174 continue; 175 } 176 if(result) 177 goto Exit; 178 printf("Received %d bytes:", pParams.responseBufferSize); 179 for(i=0; i<sizeof(out); i++) 180 printf("%d(0x%x) ", out[i], out[i]); 181 printf("\n"); 182 } while(result != kIOReturnSuccess); 183 184 //sleep(10); 185 CallComponentClose(controlInst, 0); 186 187Exit: 188 if(result != noErr) 189 printf("Control error %d(%x)\n", result, result); 190} 191 192static OSErr doReadTest(ComponentInstance theInst) 193{ 194 Ptr myBuffer; 195 IDHParameterBlock isochParamBlock; 196 OSErr err; 197 198 // open the DV device for reading 199 err = IDHOpenDevice( theInst, kIDHOpenForReadTransactions); 200 if( err != noErr) 201 goto error; 202 203 printf("Opened device\n"); 204 doControlTest(theInst, &videoConfig); 205 206 file = open("/tmp/dump.rawdv", O_CREAT | O_WRONLY | O_TRUNC, 0666); 207#if 0 208 { 209 int i; 210 // we are doing isoch reads with only one buffer at a time 211 //myBuffer = NewPtrClear(120000); 212 213 for(i=0; i<1000; i++) { 214 215 // isochParamBlock.buffer = myBuffer; 216 isochParamBlock.buffer = nil; 217 isochParamBlock.requestedCount = 120000; // NTSC buffer size 218 isochParamBlock.actualCount = 0; 219 isochParamBlock.refCon = (void *)0x12345678; 220 221 222 isochParamBlock.completionProc = 0; 223 224 err = IDHRead( theInst, &isochParamBlock); 225 if( err != noErr) 226 goto error; 227 write(file, isochParamBlock.buffer, 120000); 228 err = IDHReleaseBuffer( theInst, &isochParamBlock); 229 if( err != noErr) 230 goto error; 231 } 232 233 } 234#else 235 isochParamBlock.buffer = nil; 236 isochParamBlock.requestedCount = 120000; // NTSC buffer size 237 isochParamBlock.actualCount = 0; 238 isochParamBlock.refCon = (void *)theInst; 239 240 241 isochParamBlock.completionProc = DVIsochComponentReadCallback; 242 243 err = IDHRead( theInst, &isochParamBlock); 244 if( err != noErr) 245 goto error; 246 printf("Issued read\n"); 247 248 while(!done) 249 sleep(1); 250 sleep(10); 251 printf("Did %d frames\n", done); 252// err = IDHReleaseBuffer( theInst, &isochParamBlock); 253#endif 254 // close the DV device 255 err = IDHCloseDevice( theInst); 256 if( err != noErr) 257 goto error; 258 259 printf("Closed device\n"); 260 261 printf("Read %d bytes\n", isochParamBlock.actualCount); 262 if(isochParamBlock.actualCount) 263 { 264 int i,j; 265 UInt8 *p = (UInt8 *)isochParamBlock.buffer; 266 for(i=0; i<100; i++) { 267 printf("%d: ", i*40); 268 for(j=0; j<40; j++) 269 printf("%2x ",*p++); 270 printf("\n"); 271 } 272 } 273error: 274 return err; 275} 276 277static OSErr doWriteTest(ComponentInstance theInst) 278{ 279 Ptr myBuffer; 280 IDHParameterBlock isochParamBlock; 281 OSErr err; 282 283 // open the DV device for writing 284 err = IDHOpenDevice( theInst, kIDHOpenForWriteTransactions); 285 if( err != noErr) 286 goto error; 287 288 printf("Opened device\n"); 289 290 myBuffer = NewPtrClear(120000); 291 file = open("/work/dinosaur.rawdv", O_RDONLY, 0666); 292 printf("open file: %d\n", file); 293#if 0 294 { 295 int i; 296 // we are doing isoch reads with only one buffer at a time 297 298 for(i=0; i<1000; i++) { 299 file = open("/work/dinosaur.rawdv", O_RDONLY, 0666); 300 printf("open file: %d\n", file); 301 while(true) { 302 int len; 303 len = read(file, myBuffer, 120000); 304 if(len < 120000) 305 break; 306 isochParamBlock.buffer = myBuffer; 307 //isochParamBlock.buffer = nil; 308 isochParamBlock.requestedCount = 120000; // NTSC buffer size 309 isochParamBlock.actualCount = 0; 310 isochParamBlock.refCon = (void *)0x12345678; 311 312 isochParamBlock.completionProc = 0; 313 314 err = IDHWrite( theInst, &isochParamBlock); 315 if( err != noErr) 316 goto error; 317 } 318 close(file); 319 file = open("/work/dinosaur.rawdv", O_RDONLY, 0666); 320 printf("open file: %d\n", file); 321 } 322 } 323#else 324#if WRITEBUFF 325 read(file, myBuffer, 120000); 326 isochParamBlock.buffer = myBuffer; 327#else 328 isochParamBlock.buffer = nil; 329#endif 330 isochParamBlock.requestedCount = 120000; // NTSC buffer size 331 isochParamBlock.actualCount = 0; 332 isochParamBlock.refCon = (void *)theInst; 333 334 335 isochParamBlock.completionProc = DVIsochComponentWriteCallback; 336 337 err = IDHWrite( theInst, &isochParamBlock); 338 if( err != noErr) 339 goto error; 340 printf("Issued write\n"); 341 342 while(!done) 343 sleep(1); 344 sleep(100); 345 printf("Did %d frames\n", done); 346#endif 347 // close the DV device 348 err = IDHCloseDevice( theInst); 349 if( err != noErr) 350 goto error; 351 352 printf("Closed device\n"); 353 354error: 355 return err; 356} 357 358 359static void OpenDV() 360{ 361 ComponentInstance theInst; 362 ComponentResult version; 363 QTAtomContainer deviceList = NULL; 364 short nDVDevices, i, j; 365 QTAtom deviceAtom; 366 UInt32 cmpFlag; 367 UInt32 isoversion; 368 long size; 369 OSErr err; 370 371 theInst = OpenDefaultComponent('ihlr', 'dv '); 372 printf("Instance is 0x%x\n", theInst); 373 if(theInst == NULL) 374 return; 375 376 version = CallComponentVersion(theInst); 377 printf("Version is 0x%x\n", version); 378 379 do { 380 err = IDHGetDeviceList( theInst, &deviceList); 381 if( err != noErr) 382 goto error; 383 384 nDVDevices = QTCountChildrenOfType( deviceList, kParentAtomIsContainer, kIDHDeviceAtomType); 385 if(nDVDevices > 0) 386 break; 387 sleep(1); 388 } while(true); 389 390 391 QTLockContainer( deviceList); 392 // find the cmp atom 393 deviceAtom = QTFindChildByIndex( deviceList, kParentAtomIsContainer, kIDHUseCMPAtomType, 1, nil); 394 if( deviceAtom == nil) 395 goto error; 396 397 // get the value of the cmp atom 398 QTCopyAtomDataToPtr( deviceList, deviceAtom, true, sizeof( cmpFlag), &cmpFlag, &size); 399 400 // find the version atom 401 deviceAtom = QTFindChildByIndex( deviceList, kParentAtomIsContainer, kIDHIsochVersionAtomType, 1, nil); 402 if( deviceAtom == nil) 403 goto error; 404 405 // get the value of the version atom 406 QTCopyAtomDataToPtr( deviceList, deviceAtom, true, sizeof( isoversion), &isoversion, &size); 407 408 printf("Version 0x%x. %d DV devices, use CMP flag is %d\n", isoversion, nDVDevices, cmpFlag); 409 410 for( i=0; i<nDVDevices; ++i) 411 { 412 QTAtom isochAtom, dataAtom; 413 UInt32 test[2]; 414 int nConfigs; 415 char cameraName[256]; 416 IDHDeviceID deviceID; 417 IDHDeviceStatus deviceStatus; 418 419 // get the atom to this device 420 deviceAtom = QTFindChildByIndex( deviceList, kParentAtomIsContainer, kIDHDeviceAtomType, i + 1, nil); 421 if( deviceAtom == nil) 422 goto error; 423 424 printf("device %d ", i); 425 426 dataAtom = QTFindChildByIndex( deviceList, deviceAtom, kIDHUniqueIDType, 1, nil); 427 if( dataAtom == nil) 428 goto error; 429 QTCopyAtomDataToPtr( deviceList, dataAtom, true, sizeof( test), test, &size); 430 printf("guid 0x%x%08x ", test[0], test[1]); 431 432 dataAtom = QTFindChildByIndex( deviceList, deviceAtom, kIDHNameAtomType, 1, nil); 433 if( dataAtom == nil) 434 goto error; 435 QTCopyAtomDataToPtr( deviceList, dataAtom, true, 255, cameraName, &size); 436 cameraName[size] = 0; 437 printf("%s ", cameraName+1); 438 439 dataAtom = QTFindChildByIndex( deviceList, deviceAtom, kIDHDeviceIDType, 1, nil); 440 if( dataAtom == nil) 441 goto error; 442 QTCopyAtomDataToPtr( deviceList, dataAtom, true, sizeof( deviceID), &deviceID, &size); 443 printf("deviceID 0x%x ", deviceID); 444 445 dataAtom = QTFindChildByIndex( deviceList, deviceAtom, 'ddin', 1, nil); 446 if( dataAtom == nil) 447 goto error; 448 QTCopyAtomDataToPtr( deviceList, dataAtom, true, sizeof( deviceStatus), &deviceStatus, &size); 449 printf("\ndevice status:\n"); 450 printf("version %d\n", deviceStatus.version); 451 printf("physicallyConnected %d\n", deviceStatus.physicallyConnected); 452 printf("readEnabled %d ", deviceStatus.readEnabled); 453 printf("writeEnabled %d ", deviceStatus.writeEnabled); 454 printf("exclusiveAccess %d\n", deviceStatus.exclusiveAccess); 455 printf("currentBandwidth %d ", deviceStatus.currentBandwidth); 456 printf("currentChannel %d ", deviceStatus.currentChannel); 457 printf("inputStandard %d ", deviceStatus.inputStandard); 458 printf("deviceActive %d\n", deviceStatus.deviceActive); 459 460 // find the isoch characteristics for this device 461 isochAtom = QTFindChildByIndex( deviceList, deviceAtom, kIDHIsochServiceAtomType, 1, nil); 462 if( isochAtom == nil) 463 goto error; 464 465 // how many configs exist for this device 466 nConfigs = QTCountChildrenOfType( deviceList, isochAtom, kIDHIsochModeAtomType); 467 printf("\n%d configs:\n", nConfigs); 468 469 videoConfig.atom = nil; // start with no selected config 470 471 // process each config 472 for( j=0; j<nConfigs; ++j) 473 { 474 OSType mediaType; 475 QTAtom configAtom, mediaAtom; 476 477 // get this configs atom 478 configAtom = QTFindChildByIndex( deviceList, isochAtom, kIDHIsochModeAtomType, j + 1, nil); 479 if( configAtom == nil) 480 goto error; 481 482 printf("Config %d",j); 483 // find the media type atom 484 mediaAtom = QTFindChildByIndex( deviceList, configAtom, kIDHIsochMediaType, 1, nil); 485 if( mediaAtom == nil) 486 goto error; 487 488 // get the value of the mediaType atom 489 QTCopyAtomDataToPtr( deviceList, mediaAtom, true, sizeof( mediaType), &mediaType, &size); 490 print4(" Media type:", mediaType); 491 492 // is this config an video config? 493 if( mediaType == kIDHVideoMediaAtomType) // found video device 494 { 495 videoConfig.container = deviceList; // save this config 496 videoConfig.atom = configAtom; 497 //break; 498 } 499 printf("\n"); 500 } 501 printf("-----\n"); 502 503 } 504 505 if( videoConfig.atom == nil) // no good configs found 506 goto error; 507 508 QTUnlockContainer( deviceList); 509 deviceList = NULL; 510 511 printf("setting config\n"); 512 // set isoch to use this config 513 err = IDHSetDeviceConfiguration( theInst, &videoConfig); 514 if( err != noErr) 515 goto error; 516 517#if 1 518 err = doReadTest(theInst); 519#else 520 err = doWriteTest(theInst); 521#endif 522 if( err != noErr) 523 goto error; 524 525error: 526 if( err != noErr) 527 printf("error %d(0x%x)\n", err, err); 528 if(deviceList) { 529 QTUnlockContainer( deviceList); 530 } 531 532 CallComponentClose(theInst, 0); 533 534} 535 536 537int main(void) 538{ 539 UInt32 seed = GetComponentListModSeed(); 540 UInt32 num; 541 Handle aName; 542 ComponentDescription desc, aDesc; 543 Component aComponent; 544 ComponentInstance theInst; 545 ComponentResult version; 546 547 printf("Component seed is %d\n", seed); 548 desc.componentType = 0; /* A unique 4-byte code indentifying the command set */ 549 //desc.componentType = 'ihlr'; /* A unique 4-byte code indentifying the command set */ 550 desc.componentSubType = 0; /* Particular flavor of this instance */ 551 desc.componentManufacturer = 0; /* Vendor indentification */ 552 desc.componentFlags = 0; /* 8 each for Component,Type,SubType,Manuf/revision */ 553 desc.componentFlagsMask = 0; /* Mask for specifying which flags to consider in search, zero during registration */ 554 555 num = CountComponents(&desc); 556 printf("%d components match\n", num); 557 558 aComponent = 0; 559 aName = NewHandleClear(200); 560 while (aComponent = FindNextComponent(aComponent, &desc)) { 561 OSErr oops; 562 printf("Found component 0x%x:", aComponent); 563 oops = GetComponentInfo(aComponent, &aDesc, aName, 564 NULL, NULL); 565 if(oops) 566 printf("GetComponentInfo() returned error %d\n", oops); 567 else { 568 if(GetHandleSize(aName)) 569 printP(*aName); 570 else 571 printf("Unnamed"); 572 print4(", Type ", aDesc.componentType); 573 574 print4(", SubType ", aDesc.componentSubType); 575 print4(", Manufacturer ", aDesc.componentManufacturer); 576 printf("\n"); 577 } 578 } 579 580 OpenDV(); 581 return 0; 582} 583 584