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 * DVtest.c 25 * IOFWDVComponents 26 * 27 * Created by wgulland on Tue Oct 17 2000. 28 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 29 * 30 */ 31 32#include <Carbon/Carbon.h> 33 34#include <unistd.h> 35#include <stdio.h> 36#include <stdlib.h> 37 38#include <sys/types.h> 39#include <sys/stat.h> 40#include <fcntl.h> 41#include <IOKit/IOReturn.h> 42 43#include "DVFamily.h" 44 45typedef struct DVFuncsStruct { 46 UInt32 (*fDVCountDevices)( void ); 47 OSErr (*fDVGetIndDevice)( DVDeviceID * pDVDevice, UInt32 index ); 48 OSErr (*fDVSetDeviceName)( DVDeviceID deviceID, char * str ); 49 OSErr (*fDVGetDeviceName)( DVDeviceID deviceID, char * str ); 50 51 OSErr (*fDVOpenDriver)( DVDeviceID deviceID, DVDeviceRefNum *pRefNum ); 52 OSErr (*fDVCloseDriver)( DVDeviceRefNum refNum ); 53 54 OSErr (*fDVDoAVCTransaction)( DVDeviceRefNum refNum, AVCTransactionParamsPtr pParams ); 55 56 OSErr (*fDVIsEnabled)( DVDeviceRefNum refNum, Boolean *isEnabled); 57 OSErr (*fDVGetDeviceStandard)( DVDeviceRefNum refNum, UInt32 * pStandard ); 58 59 // DV Isoch Read 60 OSErr (*fDVEnableRead)( DVDeviceRefNum refNum ); 61 OSErr (*fDVDisableRead)( DVDeviceRefNum refNum ); 62 OSErr (*fDVReadFrame)( DVDeviceRefNum refNum, Ptr *ppReadBuffer, UInt32 * pSize ); 63 OSErr (*fDVReleaseFrame)( DVDeviceRefNum refNum, Ptr pReadBuffer ); 64 65 // DV Isoch Write 66 OSErr (*fDVEnableWrite)( DVDeviceRefNum refNum ); 67 OSErr (*fDVDisableWrite)( DVDeviceRefNum refNum ); 68 OSErr (*fDVGetEmptyFrame)( DVDeviceRefNum refNum, Ptr *ppEmptyFrameBuffer, UInt32 * pSize ); 69 OSErr (*fDVWriteFrame)( DVDeviceRefNum refNum, Ptr pWriteBuffer ); 70 OSErr (*fDVSetWriteSignalMode)( DVDeviceRefNum refNum, UInt8 mode); 71 72 // Notifications 73 OSErr (*fDVNewNotification)( DVDeviceRefNum refNum, DVNotifyProc notifyProc, 74 void *userData, DVNotificationID *pNotifyID ); 75 OSErr (*fDVNotifyMeWhen)( DVDeviceRefNum refNum, DVNotificationID notifyID, UInt32 events); 76 OSErr (*fDVCancelNotification)( DVDeviceRefNum refNum, DVNotificationID notifyID ); 77 OSErr (*fDVDisposeNotification)( DVDeviceRefNum refNum, DVNotificationID notifyID ); 78 79} DVFuncs, *DVFuncsPtr; 80 81static DVFuncs sDVFuncs; 82static char *sFile = "/tmp/dump.dv"; 83static int sWrite = 0; 84static int sLoop = 0; 85static int sSDL; 86static int sDVCPro; 87static int sNotifyTest; 88 89static CFBundleRef findMe() 90{ 91 CFURLRef bundleURL; 92 CFBundleRef myBundle; 93 Boolean didLoad = false; 94 // Make a CFURLRef from the CFString representation of the 95 // bundle's path. See the Core Foundation URL Services chapter 96 // for details. 97 bundleURL = CFURLCreateWithFileSystemPath( 98 kCFAllocatorDefault, 99 //CFSTR("/System/Library/Extensions/DVFamily.bundle"), 100 CFSTR("DVFamily.bundle"), 101 kCFURLPOSIXPathStyle, 102 true ); 103 104 // Make a bundle instance using the URLRef. 105 myBundle = CFBundleCreate( kCFAllocatorDefault, bundleURL ); 106 if(!myBundle) { 107 bundleURL = CFURLCreateWithFileSystemPath( 108 kCFAllocatorDefault, 109 CFSTR("/System/Library/Extensions/DVFamily.bundle"), 110 kCFURLPOSIXPathStyle, 111 true ); 112 113 // Make a bundle instance using the URLRef. 114 myBundle = CFBundleCreate( kCFAllocatorDefault, bundleURL ); 115 } 116 printf("Bundle: %p\n", myBundle); 117 118 // Try to load the executable from my bundle. 119 didLoad = CFBundleLoadExecutable( myBundle ); 120 printf("loaded? %d\n", didLoad); 121 122 sDVFuncs.fDVCountDevices = CFBundleGetFunctionPointerForName( 123 myBundle, CFSTR("DVCountDevices") ); 124 sDVFuncs.fDVGetIndDevice = CFBundleGetFunctionPointerForName( 125 myBundle, CFSTR("DVGetIndDevice") ); 126 sDVFuncs.fDVSetDeviceName = CFBundleGetFunctionPointerForName( 127 myBundle, CFSTR("DVSetDeviceName") ); 128 sDVFuncs.fDVGetDeviceName = CFBundleGetFunctionPointerForName( 129 myBundle, CFSTR("DVGetDeviceName") ); 130 sDVFuncs.fDVOpenDriver = CFBundleGetFunctionPointerForName( 131 myBundle, CFSTR("DVOpenDriver") ); 132 sDVFuncs.fDVCloseDriver = CFBundleGetFunctionPointerForName( 133 myBundle, CFSTR("DVCloseDriver") ); 134 135// AVC Stuff 136 sDVFuncs.fDVDoAVCTransaction = CFBundleGetFunctionPointerForName( 137 myBundle, CFSTR("DVDoAVCTransaction") ); 138 139 sDVFuncs.fDVIsEnabled = CFBundleGetFunctionPointerForName( 140 myBundle, CFSTR("DVIsEnabled") ); 141 sDVFuncs.fDVGetDeviceStandard = CFBundleGetFunctionPointerForName( 142 myBundle, CFSTR("DVGetDeviceStandard") ); 143 144// Isoch I/O 145 sDVFuncs.fDVEnableRead = CFBundleGetFunctionPointerForName( 146 myBundle, CFSTR("DVEnableRead") ); 147 sDVFuncs.fDVDisableRead = CFBundleGetFunctionPointerForName( 148 myBundle, CFSTR("DVDisableRead") ); 149 sDVFuncs.fDVReadFrame = CFBundleGetFunctionPointerForName( 150 myBundle, CFSTR("DVReadFrame") ); 151 sDVFuncs.fDVReleaseFrame = CFBundleGetFunctionPointerForName( 152 myBundle, CFSTR("DVReleaseFrame") ); 153 sDVFuncs.fDVEnableWrite = CFBundleGetFunctionPointerForName( 154 myBundle, CFSTR("DVEnableWrite") ); 155 sDVFuncs.fDVDisableWrite = CFBundleGetFunctionPointerForName( 156 myBundle, CFSTR("DVDisableWrite") ); 157 sDVFuncs.fDVGetEmptyFrame = CFBundleGetFunctionPointerForName( 158 myBundle, CFSTR("DVGetEmptyFrame") ); 159 sDVFuncs.fDVWriteFrame = CFBundleGetFunctionPointerForName( 160 myBundle, CFSTR("DVWriteFrame") ); 161 sDVFuncs.fDVSetWriteSignalMode = CFBundleGetFunctionPointerForName( 162 myBundle, CFSTR("DVSetWriteSignalMode") ); 163 164// Notifications 165 sDVFuncs.fDVNewNotification = CFBundleGetFunctionPointerForName( 166 myBundle, CFSTR("DVNewNotification") ); 167 sDVFuncs.fDVNotifyMeWhen = CFBundleGetFunctionPointerForName( 168 myBundle, CFSTR("DVNotifyMeWhen") ); 169 sDVFuncs.fDVCancelNotification = CFBundleGetFunctionPointerForName( 170 myBundle, CFSTR("DVCancelNotification") ); 171 sDVFuncs.fDVDisposeNotification = CFBundleGetFunctionPointerForName( 172 myBundle, CFSTR("DVDisposeNotification") ); 173 174 // Any CF objects returned from functions with "create" or 175 // "copy" in their names must be released by us! 176 CFRelease( bundleURL ); 177 return myBundle; 178} 179 180static OSErr doControlTest(DVDeviceRefNum refNum, UInt8 op1, UInt8 op2) 181{ 182 //Component control; 183 AVCTransactionParams avcParams; 184 char in[4], out[16]; 185 OSErr err; 186 187 // fill up the avc frame 188 in[0] = kAVCControlCommand; 189 in[1] = 0x20; // for now 190 in[2] = op1; 191 in[3] = op2; 192 193 // fill up the transaction parameter block 194 avcParams.commandBufferPtr = in; 195 avcParams.commandLength = sizeof(in); 196 avcParams.responseBufferPtr = out; 197 avcParams.responseBufferSize = sizeof(out); 198 avcParams.responseHandler = NULL; 199 200 err = sDVFuncs.fDVDoAVCTransaction(refNum, &avcParams ); 201 if(err) 202 printf("Error %d calling DVDoAVCTransaction(%ld)\n", err, refNum); 203 204 return err; 205} 206 207static void readFrames(DVDeviceRefNum refNum, int file, int numFrames) 208{ 209 OSErr err, wait; 210 Ptr pReadBuffer; 211 UInt32 size; 212 int i; 213 214 err = sDVFuncs.fDVEnableRead(refNum); 215 216 for(i=0; i<numFrames; i++) { 217 wait = sDVFuncs.fDVReadFrame( refNum, &pReadBuffer, &size ); 218 while(wait == -1) { 219 usleep(10000); // 10 milliseconds 220 wait = sDVFuncs.fDVReadFrame( refNum, &pReadBuffer, &size ); 221 } 222 if(file) 223 write(file, pReadBuffer, size); 224 err = sDVFuncs.fDVReleaseFrame( refNum, pReadBuffer ); 225 } 226 227 err = sDVFuncs.fDVDisableRead( refNum ); 228 229} 230 231static void destructoRead(DVDeviceRefNum refNum) 232{ 233 OSErr err, wait; 234 Ptr pReadBuffer; 235 UInt32 size; 236 int i; 237 238 do { 239 err = sDVFuncs.fDVEnableRead(refNum); 240 241 for(i=0; i<100; i++) { 242 wait = sDVFuncs.fDVReadFrame( refNum, &pReadBuffer, &size ); 243 while(wait == -1) { 244 //usleep(10000); // 10 milliseconds 245 wait = sDVFuncs.fDVReadFrame( refNum, &pReadBuffer, &size ); 246 } 247 err = sDVFuncs.fDVReleaseFrame( refNum, pReadBuffer ); 248 } 249 250 err = sDVFuncs.fDVDisableRead( refNum ); 251 } while(1); 252} 253 254static void writeFrames(DVDeviceRefNum refNum, int file) 255{ 256 OSErr err, wait; 257 Ptr pReadBuffer; 258 UInt32 size, len; 259 260 err = sDVFuncs.fDVEnableWrite(refNum); 261 if(err) 262 return; 263 264 do { 265 wait = sDVFuncs.fDVGetEmptyFrame( refNum, &pReadBuffer, &size ); 266 while(wait == -1) { 267 usleep(10000); // 10 milliseconds 268 wait = sDVFuncs.fDVGetEmptyFrame( refNum, &pReadBuffer, &size ); 269 } 270 if(wait) 271 break; 272 if(file) { 273 len = read(file, pReadBuffer, size); 274 if(len < size) { 275 if(sLoop) { 276 int res; 277 res = lseek(file, 0, SEEK_SET); 278 printf("lseek res %d\n", res); 279 //break; 280 } 281 else 282 break; 283 } 284 } 285 err = sDVFuncs.fDVWriteFrame( refNum, pReadBuffer ); 286 } while (1); 287 288 err = sDVFuncs.fDVDisableWrite( refNum ); 289 290} 291 292static void destructoWrite(DVDeviceID device, DVDeviceRefNum refNum, int file) 293{ 294 OSErr err, wait; 295 Ptr pReadBuffer; 296 UInt32 size, len; 297 int i; 298 299 do { 300 err = sDVFuncs.fDVEnableWrite(refNum); 301 if(err) { 302 sleep(1); 303 continue; 304 } 305 for(i=0; i<100; i++) { 306 wait = sDVFuncs.fDVGetEmptyFrame( refNum, &pReadBuffer, &size ); 307 while(wait == -1) { 308 usleep(10000); // 10 milliseconds 309 wait = sDVFuncs.fDVGetEmptyFrame( refNum, &pReadBuffer, &size ); 310 } 311 if(file) { 312 len = read(file, pReadBuffer, size); 313 if(len < size) { 314 int res; 315 res = lseek(file, 0, SEEK_SET); 316 printf("lseek res %d\n", res); 317 } 318 } 319 err = sDVFuncs.fDVWriteFrame( refNum, pReadBuffer ); 320 }; 321 322 err = sDVFuncs.fDVDisableWrite( refNum ); 323#if 1 324 err = sDVFuncs.fDVCloseDriver(refNum ); 325 err = sDVFuncs.fDVOpenDriver( device, &refNum ); 326 if(err) { 327 if(err == (OSErr)kIOReturnExclusiveAccess) { 328 do { 329 sleep(1); 330 err = sDVFuncs.fDVOpenDriver( device, &refNum ); 331 } 332 while (err == (OSErr)kIOReturnExclusiveAccess); 333 } 334 printf("Error %d calling DVOpenDriver(%ld)\n", err, device); 335 } 336#endif 337 } while (err == noErr); 338} 339 340static OSStatus myNotifyProc(DVEventRecordPtr event, void *userData ) 341{ 342 printf("event for device %d, event %d, userdata %p\n", 343 event->eventHeader.deviceID, event->eventHeader.theEvent, userData); 344 return noErr; 345} 346 347int main(int argc, char **argv) 348{ 349 CFBundleRef myBundle; 350 UInt32 numDevs, i; 351 UInt32 standard; 352 Boolean isEnabled; 353 OSErr err; 354 DVDeviceID device; 355 DVNotificationID notifyID; 356 char name[256]; 357 int file; 358 int pos = 1; 359 int destruct = 0; 360 361 while(argc > pos) { 362 if(strcmp(argv[pos], "-w") == 0) 363 sWrite = 1; 364 else if(strcmp(argv[pos], "-r") == 0) 365 sWrite = 0; 366 else if(strcmp(argv[pos], "-d") == 0) 367 destruct = 1; 368 else if(strcmp(argv[pos], "-l") == 0) 369 sLoop = 1; 370 else if(strcmp(argv[pos], "-sdl") == 0) 371 sSDL = 1; 372 else if(strcmp(argv[pos], "-DVCPro") == 0) 373 sDVCPro = 1; 374 else if(strcmp(argv[pos], "-n") == 0) 375 sNotifyTest = 1; 376 else if(strcmp(argv[pos], "-h") == 0) { 377 printf("%s [-w/-r] [-l(oop)] [-d(estructoTest)] [-sdl/-DVCPro] [-n(otify test] [filename]\n", argv[0]); 378 exit(0); 379 } 380 else 381 sFile = argv[pos]; 382 pos++; 383 } 384 myBundle = findMe(); 385 printf("sLoop = %d\n", sLoop); 386 numDevs = sDVFuncs.fDVCountDevices(); 387 printf("Number of devices: %ld\n", numDevs); 388 if(numDevs == 0) { 389 err = sDVFuncs.fDVNewNotification( kEveryDVDeviceRefNum, myNotifyProc, 390 0x1234, ¬ifyID ); 391 if(err) 392 printf("Error %d calling DVNewNotification(, %ld)\n", err, kEveryDVDeviceRefNum); 393 err = sDVFuncs.fDVNotifyMeWhen( kEveryDVDeviceRefNum, notifyID, 394 kDVDeviceAdded | kDVDeviceRemoved); 395 if(err) 396 printf("Error %d calling NotifyMeWhen(%ld, %ld)\n", err, kEveryDVDeviceRefNum, notifyID); 397 398 while (numDevs == 0 || sNotifyTest) { 399 printf("Waiting for devices: %ld\n", numDevs); 400 usleep(1000000); // 1000 milliseconds 401 numDevs = sDVFuncs.fDVCountDevices(); 402 } 403 } 404 for(i=1; i<=numDevs; i++) { 405 DVDeviceRefNum refNum; 406 err = sDVFuncs.fDVGetIndDevice(&device, i); 407 if(err) 408 printf("Error %d calling DVGetIndDevice(, %ld)\n", err, i); 409 err = sDVFuncs.fDVGetDeviceName(device, name); 410 if(err) 411 printf("Error %d calling DVGetDeviceName(%ld)\n", err, device); 412 else 413 printf("Device %ld name is %s\n", device, name); 414 415 err = sDVFuncs.fDVOpenDriver( device, &refNum ); 416 if(err) { 417 if(err == (OSErr)kIOReturnExclusiveAccess) { 418 do { 419 sleep(1); 420 err = sDVFuncs.fDVOpenDriver( device, &refNum ); 421 } 422 while (err == (OSErr)kIOReturnExclusiveAccess); 423 } 424 printf("Error %d calling DVOpenDriver(%ld)\n", err, device); 425 } 426 err = sDVFuncs.fDVGetDeviceStandard(refNum, &standard); 427 if(err) 428 printf("Error %d calling DVGetDeviceStandard(%ld)\n", err, device); 429 else if(standard == kNTSCStandard) 430 printf("Device %ld video standard is NTSC\n", device); 431 else if(standard == kPALStandard) 432 printf("Device %ld video standard is PAL\n", device); 433 else 434 printf("Device %ld, unknown video standard %ld\n", device, standard); 435 436 err = sDVFuncs.fDVIsEnabled(refNum, &isEnabled); 437 if(err) 438 printf("Error %d calling DVIsEnabled(%ld)\n", err, device); 439 else 440 printf("Device %ld isEnabled: %d\n", device, isEnabled); 441 442 if(sWrite) { 443 if(sSDL) { 444 err = sDVFuncs.fDVSetWriteSignalMode(refNum, kAVCSignalModeSDL525_60); 445 } 446 file = open(sFile, O_RDONLY, 0666); 447 printf("opened file, %d\n", file); 448 if(destruct) 449 destructoWrite(device, refNum, file); 450 else 451 writeFrames(refNum, file); 452 } 453 else { 454 file = open(sFile, O_CREAT | O_WRONLY | O_TRUNC, 0666); 455 // Start camera playing 456 457 err = doControlTest(refNum, kAVCPlayOpcode, kAVCPlayForward); 458 459 if(destruct) 460 destructoRead(refNum); 461 else 462 readFrames(refNum, file, 300); 463 464 //sleep(10); 465 err = doControlTest(refNum, kAVCWindOpcode, kAVCWindStop); 466 467 err = sDVFuncs.fDVCloseDriver( refNum ); 468 if(err) 469 printf("Error %d calling DVCloseDriver(%ld)\n", err, device); 470 while(sLoop) { 471 readFrames(refNum, 0, 300); 472 } 473 } 474 err = sDVFuncs.fDVCloseDriver(refNum ); 475 476 } 477 478 sleep(10); 479 // Unload the bundle's executable code. 480 // Don't, because there's no way to stop it! 481 //CFBundleUnloadExecutable( myBundle ); 482 //CFRelease( myBundle ); 483 return 0; 484} 485