#include "DVLib.h"
#include <pthread.h>
#include <mach/mach_port.h>
#include <mach/thread_act.h>
#include <mach/vm_map.h>
#include <mach/mach_time.h>
#include <syslog.h> // Debug messages
#include <IOKit/IOMessage.h>
#include <IOKit/firewire/IOFireWireLibIsoch.h>
#include <IOKit/avc/IOFireWireAVCConsts.h>
#include <IOKit/pwr_mgt/IOPMLib.h>
#include "IsochronousDataHandler.h"
#define kDVRequestID 0
#define ALT_TIMING 1
#define PAGE_SIZE 4096;
#define kNoPlug 0xdeadbeef
#define kWriteChannel 62
#define kReadChannel 61
enum {
kNoP2PConnection = 0,
kWriteP2PConnection = 1,
kReadP2PConnection = 2
};
#define kAVCSignalModeDVCPro50_525_60 0x74
#define kAVCSignalModeDVCPro50_625_50 0xF4
#define kAVCSignalModeDVCPro100_525_60 0x70
#define kAVCSignalModeDVCPro100_625_50 0xF0
#define kAVCSignalModeMask_DVCPro50 0x74
#define kAVCSignalModeMask_DVCPro100 0x70
#define kAVCSignalModeMask_HD 0x08
enum {
kDVRunning = 0,
kDVStopped = 1,
kDVWriteOverrun = 2,
kDVReadOverrun = 3,
kDVStopping = 4
};
enum {
kPALBit = 0x800000, kSTypeMask = 0x7c0000, kSTypeSD = 0x00000,
kSTypeSDL = 0x40000,
kSTypeHD = 0x80000
};
enum {
kNumPacketsPerInputBuffer = 100,
kDVSDPayloadPacketSize = 480,
kDVSDLPayloadPacketSize = 240,
kDVHDPayloadPacketSize = 960,
kDVCPro50PayloadPacketSize = 960,
kDVCPro100PayloadPacketSize = 1920,
kNumPingPongs = 8, kNumPacketsPerPingPong = 100,
kNumDCLsPerPingPongPacket = 1,
kRecordNumDCLs =
kNumPingPongs * (kNumPacketsPerPingPong * kNumDCLsPerPingPongPacket+3)+6,
kMaxDCLSize = 32,
kRecordDCLProgramSize = kMaxDCLSize * kRecordNumDCLs,
};
enum {
kNTSCFrameRateNumerator = 2997,
kNTSCFrameRateDenominator = 100,
kNTSCPlayFramePeriodNumerator = kNTSCFrameRateDenominator,
kNTSCPlayFramePeriodDenominator = kNTSCFrameRateNumerator,
kNTSCNumDataPacketsPerDVFrame = 250,
kNTSCNumDataPacketsPerGroup = 125,
kPALFrameRateNumerator = 25,
kPALFrameRateDenominator = 1,
kPALPlayFramePeriodNumerator = kPALFrameRateDenominator,
kPALPlayFramePeriodDenominator = kPALFrameRateNumerator,
kPALNumDataPacketsPerDVFrame = 300,
kPALNumDataPacketsPerGroup = 150,
kDVPacketAlignSlop = 8, kDVPacketCIPSize = 8,
kPlaySYTDelay = 3, };
enum {
kFrameSize_SD525_60 = 120000,
kFrameSize_DVCPro525_60 = 120000,
kFrameSize_SD625_50 = 144000,
kFrameSize_DVCPro625_50 = 144000,
kFrameSize_SDL525_60 = 60000,
kFrameSize_SDL625_50 = 72000,
kFrameSize_DVCPro50_525_60 = 240000,
kFrameSize_HD1125_60 = 240000,
kFrameSize_DVCPro50_625_50 = 288000,
kFrameSize_HD1250_50 = 288000,
kFrameSize_DVCPro100_525_60 = 480000,
kFrameSize_DVCPro100_625_50 = 576000
};
typedef struct {
UInt32 fRequest;
void * fParams;
} DVReq;
typedef struct {
mach_msg_header_t msgHdr;
DVReq dvRequest;
} SendMsg;
typedef struct {
mach_msg_header_t msgHdr;
DVReq dvRequest;
mach_msg_trailer_t trailer;
} ReceiveMsg;
struct DVLocalOutStruct;
typedef struct DVLocalOutStruct DVLocalOut, *DVLocalOutPtr;
typedef struct _DVStreamStruct {
IOFireWireLibDeviceRef pFWDevice;
IOFireWireAVCLibProtocolInterface **fAVCProtoInterface;
IOFireWireLibLocalIsochPortRef pFWLocalIsochPort;
IOFireWireLibRemoteIsochPortRef pFWRemoteIsochPort;
IOFireWireLibIsochChannelRef fIsochChannelRef;
UInt32 fPlug; DVThread * fThread;
DVFrameVars fFrames;
DCLCommandPtr pDCLList; UInt8 * fDCLBuffers; UInt32 fDCLBufferSize; UInt64 fChannelMask; UInt8 fSignalMode; UInt8 fIsocChannel; UInt8 fMaxSpeed; DVDevice *pDVDevice;
UInt32 fDVFrameSize; } DVStream;
struct DVLocalOutStruct
{
DVLocalOutPtr pNextLocalData;
DVLocalOutPtr pPrevLocalData;
DVGlobalOutPtr pGlobalData;
DCLJumpPtr pEndOfBufferGroupDCLJump;
DCLLabelPtr pStartOfBufferGroupDCLLabel;
DCLJumpPtr pBufferGroupSkipEmptyPacketDCLJump;
DCLLabelPtr pBufferGroupSkipEmptyPacketDCLLabel;
DCLLabelPtr pBufferGroupDontSkipEmptyPacketDCLLabel;
UInt32 * pBufferGroupTimeStampPtr;
DCLCommandPtr pFirstBufferGroupDCLCommand;
DCLCommandPtr pLastBufferGroupDCLCommand;
DCLCommandPtr timeStampUpdateDCLList;
DCLCommandPtr * bufferGroupUpdateDCLList;
UInt32 updateListSize;
UInt32 numPackets;
UInt32 fBlockNum;
bool skippingEmptyPacket;
};
struct DVGlobalOutStruct {
DVStream fStreamVars;
UInt8 * fDCLCommandPool;
UInt32 fTotalPool;
UInt32 fAllocatedPool;
DVSharedVars fSharedDCLVars;
DVLocalOut fLocalDataArray[kNumPlayBufferGroups]; UInt8 * pEmptyTransmitBuffers; DCLLabelPtr pUnderrunDCLLabel; UInt32 totalPackets; UInt32 activePackets; UInt32 nominalFrameCycleTime; UInt32 nextSYT; UInt32 nextDBC; UInt32 numDataPacketsPerFrame; UInt32 numDataPacketsPerGroup; UInt32 playFramePeriodNumerator;
UInt32 playFramePeriodDenominator;
UInt32 playFrameRateNumerator, playFrameRateDenominator;
UInt32 fDataPacketSize; UInt32 fDataQuadSize; UInt32 fAlignQuadSize; UInt32 fHeader0; UInt32 fHeader1; UInt32 nextDataPacketNum; UInt32 * pImageBuffer; bool fUpdateBuffers; bool pendingDVWriteUnderrunHandler;
bool deferredDVWriteFree;
bool dvWriteStopInProgress;
};
typedef struct DVLocalInStruct
{
DVGlobalInPtr pGlobalData;
DCLCommandPtr fFirstCmd;
DCLLabelPtr fStateLabel;
DCLJumpPtr fStateJmp;
UInt32 fBlockNum;
UInt32 * fTimeStampPtr;
} DVLocalIn, *DVLocalInPtr;
struct DVGlobalInStruct
{
DVStream fStreamVars;
DCLCommandPtr *ppUpdateDCLList;
UInt32 packetCount;
UInt32 fLastFrameTime;
DVLocalIn fLocalDataArray[kNumPingPongs];
DCLLabelPtr fTerminal;
UInt8 *pImageBuffer;
UInt8 lastSequenceCount;
UInt8 fState; UInt8 fSynced;
UInt8 fRestarted;
bool pendingDVReadUnderrunHandler;
bool deferredDVReadFree;
bool dvReadStopInProgress;
};
static IOReturn buildWriteProgram(DVGlobalOutPtr pGlobalData);
static IOReturn allocateBuffers(DVGlobalOutPtr pGlobalData);
static void DVWritePoll(DVGlobalOutPtr globs);
static void DVReadPoll(DVGlobalInPtr globs);
static void closeStream(DVStream *stream);
static void doDVReadHandleInputUnderrun( DVGlobalInPtr pGlobalData );
static void doDVHandleOutputUnderrun( DVGlobalOutPtr pGlobalData );
#include <CoreFoundation/CFRuntime.h>
#if ( MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 ) && defined(CF_USING_COLLECTABLE_MEMORY)
#define REGISTER_THREADS_WITH_GC 1
#else // MAC_OS_X_VERSION_MIN_REQUIRED < 1060
#define REGISTER_THREADS_WITH_GC 0
#endif // MAC_OS_X_VERSION_MIN_REQUIRED < 1060
#if REGISTER_THREADS_WITH_GC
#include <dlfcn.h>
typedef void (*ObjCRegisterThreadWithCollectorPtr)(void);
#endif REGISTER_THREADS_WITH_GC
UInt32 AddFWCycleTimeToFWCycleTime( UInt32 cycleTime1, UInt32 cycleTime2 )
{
UInt32 secondCount,
cycleCount,
cycleOffset;
UInt32 cycleTime;
cycleOffset = (cycleTime1 & 0x0FFF) + (cycleTime2 & 0x0FFF);
cycleCount = (cycleTime1 & 0x01FFF000) + (cycleTime2 & 0x01FFF000);
if (cycleOffset > 3071)
{
cycleCount += 0x1000;
cycleOffset -= 3072;
}
secondCount = (cycleTime1 & 0xFE000000) + (cycleTime2 & 0xFE000000);
if (cycleCount > (7999 << 12))
{
secondCount += 0x02000000;
cycleCount -= (8000 << 12);
}
cycleTime = secondCount | cycleCount | cycleOffset;
return (cycleTime);
}
UInt32 SubtractFWCycleTimeFromFWCycleTime( UInt32 cycleTime1, UInt32 cycleTime2)
{
SInt32 secondCount,
cycleCount,
cycleOffset;
UInt32 cycleTime;
cycleOffset = (cycleTime1 & 0x0FFF) - (cycleTime2 & 0x0FFF);
cycleCount = (cycleTime1 & 0x01FFF000) - (cycleTime2 & 0x01FFF000);
if (cycleOffset < 0)
{
cycleCount -= 0x1000;
cycleOffset += 3072;
}
secondCount = (cycleTime1 & 0xFE000000) - (cycleTime2 & 0xFE000000);
if (cycleCount < 0)
{
secondCount -= 0x02000000;
cycleCount += (8000 << 12);
}
cycleTime = secondCount | cycleCount | cycleOffset;
return (cycleTime);
}
static UInt32 ConvertFractionalSecondsToFWCycleTime( UInt32 secondsNumerator, UInt32 secondsDenominator )
{
UInt32 iSecondsCount2;
UInt32 iCycleCount2;
UInt32 iCycleOffset2;
UInt32 mSecondCount;
UInt32 mCycleCount;
UInt32 secondsCycleTime2;
iSecondsCount2 = secondsNumerator / secondsDenominator;
mSecondCount = secondsNumerator % secondsDenominator;
iCycleCount2 = (mSecondCount * 8000) / secondsDenominator;
mCycleCount = (mSecondCount * 8000) % secondsDenominator;
iCycleOffset2 = (mCycleCount * 3072) / secondsDenominator;
secondsCycleTime2 = (iSecondsCount2 << 25) | (iCycleCount2 << 12) | iCycleOffset2;
return (secondsCycleTime2);
}
static IOReturn writePlug(IOFireWireAVCLibProtocolInterface **interface, UInt32 plug, UInt32 val)
{
return (*interface)->updateOutputPlug(interface, plug,
(*interface)->readOutputPlug(interface, plug), val);
}
static void handlePCRLock(void *refcon, UInt32 generation, UInt16 nodeID, UInt32 plug,
UInt32 oldVal, UInt32 newVal)
{
}
static IOReturn writeDeviceOutputMCR(IOFireWireLibDeviceRef interface, UInt32 mask, UInt32 val)
{
UInt32 oldVal, newVal;
UInt32 oldValHost, newValHost;
IOReturn err;
FWAddress addr;
io_object_t obj;
addr.nodeID = 0;
addr.addressHi = 0xffff;
addr.addressLo = 0xf0000900;
obj = (*interface)->GetDevice(interface);
err = (*interface)->ReadQuadlet(interface, obj, &addr, &oldVal, false, 0);
oldValHost = EndianU32_BtoN( oldVal );
if(err == kIOReturnSuccess) {
if( (oldValHost & mask) != val) {
newValHost = (oldValHost & ~mask) | val;
newVal = EndianU32_NtoB( newValHost );
err = (*interface)->CompareSwap(interface, obj, &addr, oldVal, newVal, false, 0);
}
}
return err;
}
static IOReturn MakeP2PConnectionForWrite(DVDevice *pDVDevice,UInt32 plug, UInt32 chan)
{
IOReturn err;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: MakeP2PConnectionForWrite begin\n");
#endif
err = (*pDVDevice->fAVCInterface)->makeP2PInputConnection(pDVDevice->fAVCInterface, plug, chan);
if (err == kIOReturnSuccess)
{
pDVDevice->p2pConnected = kWriteP2PConnection;
pDVDevice->p2pPlug = plug;
pDVDevice->p2pChan = chan;
}
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: MakeP2PConnectionForWrite end\n");
#endif
return err;
}
static IOReturn BreakP2PConnectionForWrite(DVDevice *pDVDevice,UInt32 plug, UInt32 chan)
{
IOReturn err;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: BreakP2PConnectionForWrite begin\n");
#endif
err = (*pDVDevice->fAVCInterface)->breakP2PInputConnection(pDVDevice->fAVCInterface, plug);
pDVDevice->p2pConnected = kNoP2PConnection;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: BreakP2PConnectionForWrite end\n");
#endif
return err;
}
static IOReturn MakeP2PConnectionForRead(DVDevice *pDVDevice,UInt32 plug, UInt32 chan)
{
IOReturn err;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: MakeP2PConnectionForRead begin\n");
#endif
err = (*pDVDevice->fAVCInterface)->makeP2POutputConnection(pDVDevice->fAVCInterface, plug,chan,kFWSpeedInvalid);
if (err == kIOReturnSuccess)
{
pDVDevice->p2pConnected = kReadP2PConnection;
pDVDevice->p2pPlug = plug;
pDVDevice->p2pChan = chan;
}
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: MakeP2PConnectionForRead end\n");
#endif
return err;
}
static IOReturn BreakP2PConnectionForRead(DVDevice *pDVDevice,UInt32 plug, UInt32 chan)
{
IOReturn err;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: BreakP2PConnectionForRead begin\n");
#endif
err = (*pDVDevice->fAVCInterface)->breakP2POutputConnection(pDVDevice->fAVCInterface, plug);
pDVDevice->p2pConnected = kNoP2PConnection;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: BreakP2PConnectionForRead end\n");
#endif
return err;
}
void AVCUnitMessageCallback(void * refCon, UInt32 type, void * arg )
{
DVDevice *pDVDevice = (DVDevice*) refCon;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: AVCUnitMessageCallback begin, type = 0x%08X\n",type);
#endif
if (pDVDevice->fThread->fDeviceMessage != NULL)
pDVDevice->fThread->fDeviceMessage((void*)pDVDevice->deviceIndex,type,arg);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: AVCUnitMessageCallback end\n");
#endif
return;
}
static IOReturn getSignalMode(IOFireWireAVCLibUnitInterface **avc, UInt8 *mode)
{
UInt32 size;
UInt8 cmd[4],response[4];
IOReturn res;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: getSignalMode begin\n");
#endif
cmd[0] = kAVCStatusInquiryCommand;
cmd[1] = IOAVCAddress(kAVCTapeRecorder, 0);
cmd[2] = kAVCOutputSignalModeOpcode;
cmd[3] = kAVCSignalModeDummyOperand;
size = 4;
res = (*avc)->AVCCommand(avc, cmd, 4, response, &size);
if(res == kIOReturnSuccess) {
*mode = response[3];
}
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: getSignalMode end\n");
#endif
return res;
}
static bool isDVCPro(IOFireWireAVCLibUnitInterface **avc, UInt8 *pMode)
{
UInt32 size;
UInt8 cmd[10],response[10];
IOReturn res;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: isDVCPro begin\n");
#endif
cmd[0] = kAVCStatusInquiryCommand;
cmd[1] = kAVCUnitAddress;
cmd[2] = kAVCVendorDependentOpcode;
cmd[3] = 0;
cmd[4] = 0x80;
cmd[5] = 0x45;
cmd[6] = 0x82;
cmd[7] = 0x48;
cmd[8] = 0xff;
cmd[9] = 0xff;
size = 10;
res = (*avc)->AVCCommand(avc, cmd, 10, response, &size);
if ((res == kIOReturnSuccess) && (response[0] == kAVCImplementedStatus))
{
cmd[0] = kAVCStatusInquiryCommand;
cmd[1] = kAVCUnitAddress;
cmd[2] = kAVCOutputPlugSignalFormatOpcode;
cmd[3] = 0;
cmd[4] = 0xFF;
cmd[5] = 0xFF;
cmd[6] = 0xFF;
cmd[7] = 0xFF;
size = 8;
res = (*avc)->AVCCommand(avc, cmd, 8, response, &size);
if (res == kIOReturnSuccess && response[0] == kAVCImplementedStatus)
*pMode = response[5];
else
*pMode = 0x00;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: isDVCPro end:true\n");
#endif
return true;
}
else
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: isDVCPro end:false\n");
#endif
return false;
}
}
static bool isSDL(IOFireWireAVCLibUnitInterface **avc, UInt8 signalMode)
{
IOReturn res;
bool hasSDL;
UInt32 size;
UInt8 cmd[4],response[4];
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: isSDL begin\n");
#endif
cmd[0] = kAVCControlCommand;
cmd[1] = IOAVCAddress(kAVCTapeRecorder, 0);
cmd[2] = kAVCInputSignalModeOpcode;
cmd[3] = (signalMode & ~kAVCSignalModeMask_STYPE) | kAVCSignalModeMask_SDL;
size = 4;
res = (*avc)->AVCCommand(avc, cmd, 4, response, &size);
if(res != kIOReturnSuccess || response[0] != kAVCAcceptedStatus)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: isSDL end:false\n");
#endif
return false; }
cmd[0] = kAVCStatusInquiryCommand;
cmd[1] = IOAVCAddress(kAVCTapeRecorder, 0);
cmd[2] = kAVCInputSignalModeOpcode;
cmd[3] = kAVCSignalModeDummyOperand;
size = 4;
res = (*avc)->AVCCommand(avc, cmd, 4, response, &size);
hasSDL = (response[3] & kAVCSignalModeMask_STYPE) == kAVCSignalModeMask_SDL;
cmd[0] = kAVCControlCommand;
cmd[1] = IOAVCAddress(kAVCTapeRecorder, 0);
cmd[2] = kAVCInputSignalModeOpcode;
cmd[3] = signalMode;
size = 4;
res = (*avc)->AVCCommand(avc, cmd, 4, response, &size);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: isSDL end:%s\n",(hasSDL==true ? "true" : "false"));
#endif
return hasSDL;
}
static bool isMPEG(IOFireWireAVCLibUnitInterface **avc)
{
UInt32 size;
UInt8 cmd[8],response[8];
IOReturn res;
cmd[0] = kAVCStatusInquiryCommand;
cmd[1] = kAVCUnitAddress;
cmd[2] = kAVCOutputPlugSignalFormatOpcode;
cmd[3] = 0;
cmd[4] = 0xFF;
cmd[5] = 0xFF;
cmd[6] = 0xFF;
cmd[7] = 0xFF;
size = 8;
res = (*avc)->AVCCommand(avc, cmd, 8, response, &size);
if ((res == kIOReturnSuccess) &&
(response[0] == kAVCImplementedStatus) &&
(response[4] == 0xA0))
return true;
else
return false;
}
static void deviceArrived(void *refcon, io_iterator_t iterator )
{
io_object_t obj;
DVThread * dvThread = (DVThread *)refcon;
UInt8 dvcProMode;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: deviceArrived begin\n");
#endif
while(obj = IOIteratorNext(iterator)) {
CFMutableDictionaryRef properties;
CFNumberRef dataDesc;
CFStringRef strDesc;
kern_return_t err;
UInt64 GUID;
int refound = 0;
int device;
DVDevice *dev = NULL;
err = IORegistryEntryCreateCFProperties(obj, &properties, kCFAllocatorDefault, kNilOptions);
dataDesc = (CFNumberRef)CFDictionaryGetValue(properties, CFSTR("GUID"));
CFNumberGetValue(dataDesc, kCFNumberSInt64Type, &GUID);
for(device=0; device<dvThread->fNumDevices; device++) {
if(GUID == dvThread->fDevices[device].fGUID) {
refound = 1;
dev = &dvThread->fDevices[device];
break;
}
}
if(!refound) {
CFBooleanRef hasFCP;
device = dvThread->fNumDevices;
dvThread->fNumDevices++;
dev = &dvThread->fDevices[device];
strDesc = (CFStringRef)CFDictionaryGetValue(properties, CFSTR("FireWire Product Name"));
if(strDesc) {
dev->fName[0] = 0;
CFStringGetCString(strDesc, dev->fName, sizeof(dev->fName), kCFStringEncodingMacRoman);
}
hasFCP = (CFBooleanRef)CFDictionaryGetValue(properties, CFSTR("supportsFCP"));
dev->fSupportsFCP = true;
if(hasFCP)
dev->fSupportsFCP = CFBooleanGetValue(hasFCP);
dev->fGUID = GUID;
dev->fMaxSpeed = kFWSpeed100MBit;
dev->fWriteChan = kWriteChannel;
dev->fReadChan = kReadChannel;
}
CFRelease(properties);
dev->fObject = obj;
dev->fThread = dvThread;
err = openAVCUnit(dev->fObject, &dev->fAVCInterface, dvThread);
if(err == kIOReturnSuccess)
{
UInt8 mode, stype;
if (dev->fSupportsFCP)
{
if(isDVCPro(dev->fAVCInterface,&dvcProMode))
{
if ((dvcProMode == kAVCSignalModeDVCPro100_525_60) || (dvcProMode == kAVCSignalModeDVCPro100_625_50))
{
DVDeviceTerminate(dev);
dvThread->fNumDevices--;
continue; }
}
else if (isMPEG(dev->fAVCInterface))
{
DVDeviceTerminate(dev);
dvThread->fNumDevices--;
continue; }
}
dev->deviceIndex = device+1;
(*dev->fAVCInterface)->setMessageCallback(dev->fAVCInterface, (void *) dev, AVCUnitMessageCallback);
if(dev->fSupportsFCP)
{
err = getSignalMode(dev->fAVCInterface, &mode);
if(err == kIOReturnSuccess)
{
if(mode & kAVCSignalModeMask_50)
dev->standard = palIn;
else
dev->standard = ntscIn;
stype = mode & kAVCSignalModeMask_STYPE;
if(stype == kAVCSignalModeMask_DVCPro25)
{
dev->fDVFormats |= 1 << kIDHDVCPro_25;
}
else if(stype == kAVCSignalModeMask_DVCPro50)
{
dev->fDVFormats |= 1 << kIDHDVCPro_50;
dev->fMaxSpeed = kFWSpeed400MBit; }
else
{
if(isDVCPro(dev->fAVCInterface,&dvcProMode))
{
if((dvcProMode & kAVCSignalModeMask_STYPE) == kAVCSignalModeMask_DVCPro50)
{
dev->fDVFormats |= 1 << kIDHDVCPro_50;
dev->fMaxSpeed = kFWSpeed400MBit; }
else
dev->fDVFormats |= 1 << kIDHDVCPro_25;
}
}
if(stype == kAVCSignalModeMask_SDL)
dev->fDVFormats |= 1 << kIDHDV_SDL;
else
{
if(isSDL(dev->fAVCInterface, mode))
dev->fDVFormats |= 1 << kIDHDV_SDL;
}
}
else
{
dev->fDVFormats = 1 << kIDHDV_SD; dev->standard = ntscIn;
}
}
else
{
dev->fDVFormats = 1 << kIDHDV_SD; dev->standard = ntscIn; }
(dvThread->fAddedFunc)(dvThread->fAddedRefCon, dev, device+1, refound);
}
}
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: deviceArrived end\n");
#endif
}
static OSStatus DVthreadExit(DVThread *dvThread, UInt32 params)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVthreadExit begin\n");
#endif
if(dvThread->fNotifySource)
CFRunLoopSourceInvalidate(dvThread->fNotifySource);
if(dvThread->fPowerNotifySource)
CFRunLoopSourceInvalidate(dvThread->fPowerNotifySource);
CFRunLoopStop(dvThread->fWorkLoop) ;
dvThread->fTimerFunc = NULL;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVthreadExit end\n");
#endif
return noErr;
}
static void *DVRTThreadStart(DVThread *dvThread)
{
#if REGISTER_THREADS_WITH_GC
if (CF_USING_COLLECTABLE_MEMORY)
{
void *dlhandle = dlopen("/usr/lib/libobjc.dylib", RTLD_LAZY | RTLD_LOCAL);
if( dlhandle != NULL ) {
ObjCRegisterThreadWithCollectorPtr objcRegisterThreadWithCollector = dlsym( dlhandle, "objc_registerThreadWithCollector" );
if( objcRegisterThreadWithCollector != NULL )
objcRegisterThreadWithCollector();
else syslog(LOG_INFO, "dlsym(objc_registerThreadWithCollector) failed");
dlclose( dlhandle );
}
else syslog(LOG_INFO, "dlopen(/usr/lib/libobjc.dylib) failed");
}
#endif // REGISTER_THREADS_WITH_GC
ReceiveMsg msg;
kern_return_t err;
int delay;
int run = true;
int i;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVRTThreadStart begin\n");
#endif
deviceArrived(dvThread, dvThread->fMatchEnumer);
DVSignalSync(&dvThread->fRequestSyncer, &dvThread->fSyncRequest, 1);
delay = 12; while(run) {
int nextTick;
#if TIMING
CFAbsoluteTime start;
start = CFAbsoluteTimeGetCurrent();
#endif
err = mach_msg(&msg.msgHdr, MACH_RCV_MSG | MACH_RCV_TIMEOUT,
0, sizeof(msg), dvThread->fRequestMachPort, delay, MACH_PORT_NULL);
#if TIMING
DVLog(dvThread, 'mmsg', start, CFAbsoluteTimeGetCurrent());
#endif
if(err == MACH_MSG_SUCCESS) {
switch (msg.msgHdr.msgh_id) {
case kDVRequestID:
dvThread->fRequestResult = (dvThread->fRequestFunc)(dvThread->fRequestArg, dvThread->fRequestParam);
if(dvThread->fRequestFunc == DVthreadExit)
run = false;
DVSignalSync(&dvThread->fRequestSyncer, &dvThread->fSyncRequest, (UInt32)dvThread->fRequestFunc);
}
}
for(i=0; i<kDVMaxStreamsActive; i++) {
if(dvThread->fInStreams[i])
DVReadPoll(dvThread->fInStreams[i]);
if(dvThread->fOutStreams[i])
DVWritePoll(dvThread->fOutStreams[i]);
}
if(dvThread->fTimerFunc) {
dvThread->fTimerFunc(NULL, dvThread->fTimerRefCon);
delay = 12; nextTick = (int)((dvThread->requestTimeoutTime-CFAbsoluteTimeGetCurrent())*1000.0);
if(nextTick <= 0)
nextTick = 1;
if(nextTick < delay)
delay = nextTick;
}
}
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVRTThreadStart end\n");
#endif
return NULL;
}
static void *DVRLThreadStart(DVThread *thread)
{
#if REGISTER_THREADS_WITH_GC
if (CF_USING_COLLECTABLE_MEMORY)
{
void *dlhandle = dlopen("/usr/lib/libobjc.dylib", RTLD_LAZY | RTLD_LOCAL);
if( dlhandle != NULL ) {
ObjCRegisterThreadWithCollectorPtr objcRegisterThreadWithCollector = dlsym( dlhandle, "objc_registerThreadWithCollector" );
if( objcRegisterThreadWithCollector != NULL )
objcRegisterThreadWithCollector();
else syslog(LOG_INFO, "dlsym(objc_registerThreadWithCollector) failed");
dlclose( dlhandle );
}
else syslog(LOG_INFO, "dlopen(/usr/lib/libobjc.dylib) failed");
}
#endif // REGISTER_THREADS_WITH_GC
CFRunLoopRef loop;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVRLThreadStart begin\n");
#endif
loop = CFRunLoopGetCurrent();
if(thread->fNotifySource)
CFRunLoopAddSource(loop, thread->fNotifySource, kCFRunLoopDefaultMode);
if(thread->fPowerNotifySource)
CFRunLoopAddSource(loop, thread->fPowerNotifySource, kCFRunLoopDefaultMode);
CFRetain(loop);
thread->fWorkLoop = loop;
thread->fRunLoopIsRunning = true;
DVSignalSync(&thread->fRequestSyncer, &thread->fSyncRequest, 1);
CFRunLoopRun();
thread->fRunLoopIsRunning = false;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVRLThreadStart end\n");
#endif
return NULL;
}
void
PowerManagementNotificationCallback(void * refcon,
io_service_t service,
natural_t messageType,
void * messageArgument )
{
DVThread *dvThread = (DVThread*) refcon;
UInt32 i;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: PowerManagementNotificationCallback begin\n");
#endif
if (messageType == kIOMessageSystemHasPoweredOn)
{
for(i=0; i<kDVMaxStreamsActive; i++)
{
if(dvThread->fInStreams[i])
{
syslog(LOG_INFO, "DV PowerManagementNotificationCallback, Restarting input stream %d\n",i);
if (dvThread->fInStreams[i]->dvReadStopInProgress == false)
{
dvThread->fInStreams[i]->pendingDVReadUnderrunHandler = true;
DVRequest(dvThread->fInStreams[i]->fStreamVars.fThread,
doDVReadHandleInputUnderrun,
dvThread->fInStreams[i],
0);
}
}
if(dvThread->fOutStreams[i])
{
syslog(LOG_INFO, "DV PowerManagementNotificationCallback, Restarting output stream %d\n",i);
if (dvThread->fOutStreams[i]->dvWriteStopInProgress == false)
{
dvThread->fOutStreams[i]->pendingDVWriteUnderrunHandler = true;
DVRequest(dvThread->fOutStreams[i]->fStreamVars.fThread,
doDVHandleOutputUnderrun,
dvThread->fOutStreams[i],
0);
}
}
}
}
IOAllowPowerChange (dvThread->fPowerNotifyConnect, (long) messageArgument);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: PowerManagementNotificationCallback end\n");
#endif
}
DVThread * DVCreateThread(DVDeviceArrivedFunc deviceAdded, void * addedRefCon,
CFRunLoopTimerCallBack timerTick, void *timerRefCon, IOFWAVCMessageCallback deviceMessage)
{
UInt32 i;
IOReturn err;
mach_port_t masterDevicePort;
DVThread *dvThread;
const UInt8 num = kAVCTapeRecorder;
CFMutableDictionaryRef dict = 0;
CFNumberRef tape;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVCreateThread begin\n");
#endif
dict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if(!dict)
return nil;
tape = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt8Type, &num);
if(!tape)
return nil;
CFDictionarySetValue( dict, CFSTR(kIOProviderClassKey), CFSTR("IOFireWireAVCSubUnit") );
CFDictionarySetValue( dict, CFSTR("SubUnit_Type"), tape);
CFRelease(tape);
if ((err = IOMasterPort(bootstrap_port, &masterDevicePort)) != KERN_SUCCESS) {
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVCreateThread end:failed to get master port\n");
#endif
return NULL;
}
dvThread = malloc(sizeof(DVThread));
bzero(dvThread, sizeof(DVThread));
for(i = 0 ; i < kDVMaxDevicesActive ; i++){
dvThread->fDevices[i].fOutPlug = kNoPlug;
}
pthread_mutex_init(&dvThread->fRequestSyncer.fMutex, NULL);
pthread_cond_init(&dvThread->fRequestSyncer.fSyncCond, NULL);
pthread_mutex_init(&dvThread->fRequestMutex, NULL);
dvThread->fNotifyPort = IONotificationPortCreate(masterDevicePort);
dvThread->fNotifySource = IONotificationPortGetRunLoopSource(dvThread->fNotifyPort);
err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &dvThread->fRequestMachPort);
err = mach_port_insert_right(mach_task_self(), dvThread->fRequestMachPort, dvThread->fRequestMachPort,
MACH_MSG_TYPE_MAKE_SEND);
if(timerTick) {
dvThread->fTimerFunc = timerTick;
dvThread->fTimerRefCon = timerRefCon;
}
dvThread->fAddedRefCon = addedRefCon;
dvThread->fAddedFunc = deviceAdded;
dvThread->fDeviceMessage = deviceMessage;
err = IOServiceAddMatchingNotification( dvThread->fNotifyPort,
kIOMatchedNotification, dict,
deviceArrived, dvThread, &dvThread->fMatchEnumer );
dvThread->fPowerNotifyConnect = IORegisterForSystemPower ( dvThread,
&dvThread->fPowerNotifyPort,
PowerManagementNotificationCallback,
&dvThread->fPowerManagementNotifier);
dvThread->fPowerNotifySource = IONotificationPortGetRunLoopSource(dvThread->fPowerNotifyPort);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVCreateThread end\n");
#endif
return dvThread;
}
static void setThreadPriority(pthread_t thread)
{
double mult;
thread_time_constraint_policy_data_t constraints;
kern_return_t result;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: setThreadPriority begin\n");
#endif
mach_timebase_info_data_t tTBI;
mach_timebase_info(&tTBI);
mult = ((double)tTBI.denom / (double)tTBI.numer) * 1000000;
constraints.period = 12*mult;
constraints.computation = 2*mult;
constraints.constraint = 24*mult;
constraints.preemptible = TRUE;
result = thread_policy_set(pthread_mach_thread_np(thread), THREAD_TIME_CONSTRAINT_POLICY,
(thread_policy_t)&constraints, THREAD_TIME_CONSTRAINT_POLICY_COUNT);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: setThreadPriority end\n");
#endif
}
void DVSetTimeoutTime(DVThread * dvThread, CFAbsoluteTime fireDate)
{
dvThread->setTimeoutTime = CFAbsoluteTimeGetCurrent();
dvThread->requestTimeoutTime = fireDate;
}
void DVRunThread(DVThread * dvThread)
{
pthread_attr_t threadAttr; pthread_t thread;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVRunThread begin\n");
#endif
dvThread->fSyncRequest = 0;
pthread_attr_init(&threadAttr);
pthread_create(&thread, &threadAttr, DVRLThreadStart, dvThread);
dvThread->fRLThread = thread;
DVWaitSync(&dvThread->fRequestSyncer, &dvThread->fSyncRequest);
dvThread->fSyncRequest = 0;
pthread_create(&thread, &threadAttr, DVRTThreadStart, dvThread);
dvThread->fRTThread = thread;
setThreadPriority(thread);
DVWaitSync(&dvThread->fRequestSyncer, &dvThread->fSyncRequest);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVRunThread end\n");
#endif
}
void DVFreeThread(DVThread * dvThread)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVFreeThread begin\n");
#endif
DVRequest(dvThread, DVthreadExit, dvThread, 0);
pthread_join(dvThread->fRTThread, NULL);
pthread_join(dvThread->fRLThread, NULL);
CFRelease(dvThread->fWorkLoop);
if(dvThread->fMatchEnumer)
IOObjectRelease(dvThread->fMatchEnumer);
if(dvThread->fNotifyPort) {
CFMachPortRef hack;
CFMachPortContext context;
Boolean shouldFreeInfo;
context.version = 1;
context.info = (void *) dvThread->fNotifyPort;
context.retain = NULL;
context.release = NULL;
context.copyDescription = NULL;
hack = CFMachPortCreateWithPort(NULL, IONotificationPortGetMachPort(dvThread->fNotifyPort),
NULL, &context, &shouldFreeInfo);
CFMachPortInvalidate(hack);
IONotificationPortDestroy(dvThread->fNotifyPort);
CFRelease(hack);
}
if(dvThread->fPowerNotifyPort) {
CFMachPortRef hack;
CFMachPortContext context;
Boolean shouldFreeInfo;
context.version = 1;
context.info = (void *) dvThread->fPowerNotifyPort;
context.retain = NULL;
context.release = NULL;
context.copyDescription = NULL;
hack = CFMachPortCreateWithPort(NULL, IONotificationPortGetMachPort(dvThread->fPowerNotifyPort),
NULL, &context, &shouldFreeInfo);
printf( "DVFreeThread - CFMachPortCreateWithPort hack = %p, fPowerNotifyPort= %p\n", hack, dvThread->fPowerNotifyPort );
CFMachPortInvalidate(hack);
IONotificationPortDestroy(dvThread->fPowerNotifyPort);
CFRelease(hack);
}
mach_port_destroy(mach_task_self(), dvThread->fRequestMachPort);
pthread_mutex_destroy(&dvThread->fRequestSyncer.fMutex);
pthread_cond_destroy(&dvThread->fRequestSyncer.fSyncCond);
pthread_mutex_destroy(&dvThread->fRequestMutex);
IODeregisterForSystemPower(&dvThread->fPowerManagementNotifier);
IOServiceClose(dvThread->fPowerNotifyConnect);
memset(dvThread, 0xde, sizeof(DVThread));
free(dvThread);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVFreeThread end\n");
#endif
}
void DVSignalSync(ThreadSyncer *sync, UInt32 *var, UInt32 val)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVSignalSync begin\n");
#endif
pthread_mutex_lock(&sync->fMutex);
*var = val;
pthread_mutex_unlock(&sync->fMutex);
pthread_cond_broadcast(&sync->fSyncCond);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVSignalSync end\n");
#endif
}
void DVWaitSync(ThreadSyncer *sync, UInt32 *var)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVWaitSync begin\n");
#endif
{
pthread_mutex_lock(&sync->fMutex);
while(!*var) {
pthread_cond_wait(&sync->fSyncCond, &sync->fMutex);
}
pthread_mutex_unlock(&sync->fMutex);
}
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVWaitSync end\n");
#endif
}
void DVLock(ThreadSyncer *sync)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVLock begin\n");
#endif
pthread_mutex_lock(&sync->fMutex);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVLock end\n");
#endif
}
void DVUnlock(ThreadSyncer *sync)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVUnlock begin\n");
#endif
pthread_mutex_unlock(&sync->fMutex);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVUnlock end\n");
#endif
}
static IOReturn isochPortGetSupported(
IOFireWireLibIsochPortRef interface,
IOFWSpeed* outMaxSpeed,
UInt64* outChanSupported)
{
DVStream *stream;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: isochPortGetSupported begin\n");
#endif
stream = (DVStream *)((*interface)->GetRefCon(interface));
if(*outMaxSpeed > stream->fMaxSpeed)
*outMaxSpeed = stream->fMaxSpeed;
*outChanSupported = stream->fChannelMask;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: isochPortGetSupported end\n");
#endif
return kIOReturnSuccess;
}
static IOReturn isochPortAllocate(
IOFireWireLibIsochPortRef interface,
IOFWSpeed maxSpeed,
UInt32 channel)
{
DVStream *stream;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: isochPortAllocate begin\n");
#endif
stream = (DVStream *)((*interface)->GetRefCon(interface));
stream->fIsocChannel = channel;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: isochPortAllocate end\n");
#endif
return kIOReturnSuccess;
}
IOReturn openFireWireUnit(IOFireWireAVCLibUnitInterface **avcInterface, IOFireWireSessionRef session, IOFireWireLibDeviceRef *retInterface, DVThread *thread)
{
IOFireWireLibDeviceRef resultInterface;
IOReturn err = kIOReturnNoMemory;
int opened = false;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: openFireWireUnit begin\n");
#endif
do {
resultInterface = (*avcInterface)->getAncestorInterface(avcInterface, "IOFireWireUnit",
CFUUIDGetUUIDBytes(kIOFireWireLibTypeID), CFUUIDGetUUIDBytes(kIOFireWireUnitInterfaceID_v3));
if(!resultInterface)
break;
if(session)
err = (*resultInterface)->OpenWithSessionRef(resultInterface, session);
else
err = (*resultInterface)->Open(resultInterface);
if(err)
break;
opened = true;
err = (*resultInterface)->AddIsochCallbackDispatcherToRunLoop(resultInterface, thread->fWorkLoop);
} while (false);
if(!err)
*retInterface = resultInterface;
else {
if(opened)
(*resultInterface)->Close(resultInterface);
if(resultInterface)
(*resultInterface)->Release(resultInterface);
}
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: openFireWireUnit end\n");
#endif
return err;
}
IOReturn openAVCUnit(io_object_t obj, IOFireWireAVCLibUnitInterface ***retInterface, DVThread *thread)
{
IOCFPlugInInterface** theCFPlugInInterface;
IOFireWireAVCLibUnitInterface **resultInterface = 0 ;
SInt32 theScore ;
IOReturn err;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: openAVCUnit begin\n");
#endif
err = IOCreatePlugInInterfaceForService(
obj,
kIOFireWireAVCLibUnitTypeID,
kIOCFPlugInInterfaceID, & theCFPlugInInterface,
& theScore);
if (!err) {
HRESULT comErr;
comErr = (*theCFPlugInInterface)->QueryInterface(
theCFPlugInInterface,
CFUUIDGetUUIDBytes(kIOFireWireAVCLibUnitInterfaceID),
(void**) & resultInterface);
if (comErr == S_OK) {
err = (*resultInterface)->addCallbackDispatcherToRunLoop(resultInterface, thread->fWorkLoop );
}
else
err = comErr;
(*theCFPlugInInterface)->Release(theCFPlugInInterface); }
if(!err)
*retInterface = resultInterface;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: openAVCUnit end\n");
#endif
return err;
}
IOReturn openAVCProto(IOFireWireAVCLibUnitInterface **avcInterface, IOFireWireAVCLibProtocolInterface ***retInterface, DVThread *thread)
{
IOFireWireAVCLibProtocolInterface **resultInterface;
IOReturn err = noErr;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: openAVCProto begin\n");
#endif
do {
resultInterface = (*avcInterface)->getProtocolInterface(avcInterface,
CFUUIDGetUUIDBytes(kIOFireWireAVCLibProtocolTypeID),
CFUUIDGetUUIDBytes(kIOFireWireAVCLibProtocolInterfaceID));
if(!resultInterface)
break;
err = (*resultInterface)->addCallbackDispatcherToRunLoop(resultInterface, thread->fWorkLoop);
} while (false);
if(!err)
*retInterface = resultInterface;
else {
if(resultInterface)
(*resultInterface)->Release(resultInterface);
}
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: openAVCProto end\n");
#endif
return err;
}
void DVDeviceTerminate(DVDevice *dev)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVDeviceTerminate begin\n");
#endif
DVDeviceClose(dev);
if(dev->fAVCInterface)
{
(*dev->fAVCInterface)->removeCallbackDispatcherFromRunLoop(dev->fAVCInterface);
if (dev->fThread->fWorkLoop != CFRunLoopGetCurrent())
{
while ((CFRunLoopIsWaiting(dev->fThread->fWorkLoop) == false ) && (dev->fThread->fRunLoopIsRunning == true))
usleep(1000); }
(*dev->fAVCInterface)->Release(dev->fAVCInterface);
dev->fAVCInterface = NULL;
}
if(dev->fObject) {
IOObjectRelease(dev->fObject);
dev->fObject = NULL;
}
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVDeviceTerminate end\n");
#endif
}
IOReturn DVDeviceOpen(DVThread *dvThread, DVDevice *device)
{
IOReturn err = noErr;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVDeviceOpen begin\n");
#endif
if(!device->fAVCInterface)
return kIOReturnNoMemory;
do {
err = (*device->fAVCInterface)->open(device->fAVCInterface);
if(err != kIOReturnSuccess) break;
err = openFireWireUnit(device->fAVCInterface, (*device->fAVCInterface)->getSessionRef(device->fAVCInterface),
&device->fDevInterface, dvThread);
if(err != kIOReturnSuccess) break;
err = openAVCProto(device->fAVCInterface, &device->fAVCProtoInterface, dvThread);
if(err != kIOReturnSuccess) break;
err = (*device->fAVCProtoInterface)->allocateOutputPlug(device->fAVCProtoInterface,
device, handlePCRLock, &device->fOutPlug);
if(err != kIOReturnSuccess) break;
err = writePlug(device->fAVCProtoInterface, device->fOutPlug, 122 << kIOFWPCROutputPayloadPhase);
if(err != kIOReturnSuccess) break;
} while (0);
if(err != kIOReturnSuccess)
DVDeviceClose(device);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVDeviceOpen end\n");
#endif
return err;
}
static IOReturn doDVDeviceClose(DVDevice *dev)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: doDVDeviceClose begin\n");
#endif
if(dev->fDevInterface) {
UInt32 ref;
(*dev->fDevInterface)->Close(dev->fDevInterface);
(*dev->fDevInterface)->RemoveIsochCallbackDispatcherFromRunLoop(dev->fDevInterface);
ref = (*dev->fDevInterface)->Release(dev->fDevInterface);
dev->fDevInterface = NULL;
}
if(dev->fAVCProtoInterface)
{
UInt32 ref;
if(dev->fOutPlug != kNoPlug) {
(*dev->fAVCProtoInterface)->freeOutputPlug(dev->fAVCProtoInterface, dev->fOutPlug);
dev->fOutPlug = kNoPlug;
}
(*dev->fAVCProtoInterface)->removeCallbackDispatcherFromRunLoop(dev->fAVCProtoInterface);
ref = (*dev->fAVCProtoInterface)->Release(dev->fAVCProtoInterface);
dev->fAVCProtoInterface = NULL;
}
if(dev->fAVCInterface) {
(*dev->fAVCInterface)->close(dev->fAVCInterface);
}
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: doDVDeviceClose end\n");
#endif
return kIOReturnSuccess;
}
void DVDeviceClose(DVDevice *dev)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVDeviceClose begin\n");
#endif
DVRequest(dev->fThread, doDVDeviceClose, dev, 0);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVDeviceClose end\n");
#endif
}
IOReturn DVRequest(DVThread *thread, IOReturn (*func)(void *arg, UInt32 param), void *arg, UInt32 param)
{
IOReturn result;
if(thread->fRTThread != pthread_self()) {
pthread_mutex_lock(&thread->fRequestMutex);
thread->fSyncRequest = 0;
thread->fRequestFunc = func;
thread->fRequestArg = arg;
thread->fRequestParam = param;
{
SendMsg msg;
bzero( &msg, sizeof(msg));
msg.msgHdr.msgh_remote_port = thread->fRequestMachPort;
msg.msgHdr.msgh_bits = MACH_MSGH_BITS(
MACH_MSG_TYPE_COPY_SEND,
MACH_MSG_TYPE_COPY_SEND );
msg.msgHdr.msgh_size = sizeof(msg);
msg.msgHdr.msgh_id = kDVRequestID;
mach_msg(&msg.msgHdr, MACH_SEND_MSG,
msg.msgHdr.msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL);
}
DVWaitSync(&thread->fRequestSyncer, &thread->fSyncRequest);
result = thread->fRequestResult;
pthread_mutex_unlock(&thread->fRequestMutex);
}
else
result = (*func)(arg, param);
return result;
}
static void initStream(DVStream *stream, DVDevice *device, UInt32 plug, UInt32 channel, DVThread *thread)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: initStream begin\n");
#endif
stream->pFWDevice = device->fDevInterface;
stream->pDVDevice = device;
stream->fAVCProtoInterface = device->fAVCProtoInterface;
stream->fPlug = plug;
stream->fIsocChannel = channel;
stream->fMaxSpeed = device->fMaxSpeed;
stream->fThread = thread;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: initStream end\n");
#endif
}
static IOReturn openStream(DVStream *stream, bool forWrite, UInt32 packetSize)
{
IOReturn err;
IOFireWireLibIsochPortRef talker, listener;
IOVirtualRange bufRange;
bool allocBandwidth;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: openStream begin\n");
#endif
do {
if(forWrite) {
allocBandwidth = true;
}
else {
UInt32 plugVal, plugValHost;
io_object_t obj;
FWAddress addr;
UInt32 size;
addr.nodeID = 0;
addr.addressHi = 0xffff;
addr.addressLo = 0xf0000904;
size = 4;
obj = (*stream->pFWDevice)->GetDevice(stream->pFWDevice);
err = (*stream->pFWDevice)->ReadQuadlet(stream->pFWDevice, obj, &addr, &plugVal, false, 0);
plugValHost = EndianU32_BtoN( plugVal );
if(plugValHost & (kIOFWPCRBroadcast | kIOFWPCRP2PCount)) {
UInt32 chan = (plugValHost & kIOFWPCRChannel)>>kIOFWPCRChannelPhase;
stream->fChannelMask = 1ULL << (63-chan);
allocBandwidth = false;
}
else {
#ifdef USE_P2P_CONNECTIONS_FOR_DV_READ
stream->fChannelMask = ~1ULL;
allocBandwidth = true;
#else
stream->fChannelMask = 1ULL; allocBandwidth = false;
#endif
}
}
stream->fIsochChannelRef = (*stream->pFWDevice)->CreateIsochChannel(stream->pFWDevice, allocBandwidth, packetSize,
stream->fMaxSpeed, CFUUIDGetUUIDBytes(kIOFireWireIsochChannelInterfaceID));
if (NULL == stream->fIsochChannelRef) {
err = memFullErr;
break;
}
bufRange.address = (IOVirtualAddress)stream->fDCLBuffers;
bufRange.length = stream->fDCLBufferSize;
if(forWrite) {
stream->pFWLocalIsochPort = (*stream->pFWDevice)->CreateLocalIsochPort(stream->pFWDevice, 1 ,
stream->pDCLList, kFWDCLCycleEvent, 0, 0x0000f000, nil, 0, &bufRange, 1,
CFUUIDGetUUIDBytes(kIOFireWireLocalIsochPortInterfaceID));
stream->fChannelMask = ~1ULL;
}
else {
stream->pFWLocalIsochPort = (*stream->pFWDevice)->CreateLocalIsochPort(stream->pFWDevice, 0 ,
stream->pDCLList, 0, 0, 0, nil, 0, &bufRange, 1,
CFUUIDGetUUIDBytes(kIOFireWireLocalIsochPortInterfaceID));
}
if (!stream->pFWLocalIsochPort) {
err = memFullErr;
break;
}
stream->pFWRemoteIsochPort = (*stream->pFWDevice)->CreateRemoteIsochPort(stream->pFWDevice, 0, CFUUIDGetUUIDBytes(kIOFireWireRemoteIsochPortInterfaceID) );
(*stream->pFWRemoteIsochPort)->SetRefCon( stream->pFWRemoteIsochPort, stream);
(*stream->pFWRemoteIsochPort)->SetGetSupportedHandler( stream->pFWRemoteIsochPort, &isochPortGetSupported);
(*stream->pFWRemoteIsochPort)->SetAllocatePortHandler( stream->pFWRemoteIsochPort, &isochPortAllocate);
if(forWrite) {
talker = (IOFireWireLibIsochPortRef) stream->pFWLocalIsochPort;
listener = (IOFireWireLibIsochPortRef)stream->pFWRemoteIsochPort;
}
else {
listener = (IOFireWireLibIsochPortRef) stream->pFWLocalIsochPort;
talker = (IOFireWireLibIsochPortRef)stream->pFWRemoteIsochPort;
}
err = (*stream->fIsochChannelRef)->SetTalker( stream->fIsochChannelRef, talker);
if(err)
break;
err = (*stream->fIsochChannelRef)->AddListener( stream->fIsochChannelRef, listener);
if(err)
break;
(*stream->fIsochChannelRef)->TurnOnNotification(stream->fIsochChannelRef);
err = (*stream->fIsochChannelRef)->AllocateChannel(stream->fIsochChannelRef);
if(err)
break;
if(forWrite) {
err = writePlug(stream->fAVCProtoInterface, stream->fPlug,
kIOFWPCROnline | kIOFWPCRBroadcast | (1 << kIOFWPCRP2PCountPhase) |
(stream->fIsocChannel<<kIOFWPCRChannelPhase) |
(15 << kIOFWPCROutputOverheadPhase) | (122 << kIOFWPCROutputPayloadPhase));
if(err)
break;
err = MakeP2PConnectionForWrite(stream->pDVDevice,0,stream->fIsocChannel);
}
else
{
#ifdef USE_P2P_CONNECTIONS_FOR_DV_READ
err = MakeP2PConnectionForRead(stream->pDVDevice,0,stream->fIsocChannel);
#endif
}
err = (*stream->fIsochChannelRef)->Start(stream->fIsochChannelRef);
if(err)
break;
stream->fFrames.fStatus = kDVRunning;
} while (false);
if(err)
closeStream(stream);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: openStream end\n");
#endif
return err;
}
static void closeStream(DVStream *stream)
{
IOReturn err;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: closeStream begin\n");
#endif
stream->fFrames.fStatus = kDVStopped;
if(stream->fIsochChannelRef) {
(*stream->fIsochChannelRef)->TurnOffNotification(stream->fIsochChannelRef);
err = (*stream->fIsochChannelRef)->Stop(stream->fIsochChannelRef);
err = (*stream->fIsochChannelRef)->ReleaseChannel(stream->fIsochChannelRef);
(*stream->fIsochChannelRef)->Release(stream->fIsochChannelRef);
stream->fIsochChannelRef = NULL;
}
if(stream->pFWLocalIsochPort) {
(*stream->pFWLocalIsochPort)->Release(stream->pFWLocalIsochPort);
stream->pFWLocalIsochPort = NULL;
}
if(stream->pFWRemoteIsochPort) {
(*stream->pFWRemoteIsochPort)->Release(stream->pFWRemoteIsochPort);
stream->pFWRemoteIsochPort = NULL;
}
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: closeStream end\n");
#endif
}
static IOReturn DVAllocFrames(DVFrameVars *pFrameData, UInt32 numFrames, UInt32 frameSize,
DVFrameVars **frameVars, UInt8 **frames)
{
int i;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVAllocFrames begin\n");
#endif
pFrameData->fNumFrames = numFrames;
pFrameData->fFrames = malloc(numFrames*frameSize);
pFrameData->fReader = 0;
pFrameData->fWriter = 0;
pFrameData->fDroppedFrames = 0;
pFrameData->fStatus = 0;
for(i=0; i<numFrames; i++) {
frames[i] = pFrameData->fFrames + i*frameSize;
}
*frameVars = pFrameData;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVAllocFrames end\n");
#endif
return kIOReturnSuccess;
}
static void DVFreeFrames(DVFrameVars *pFrameData)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVFreeFrames begin\n");
#endif
if(!pFrameData->fFrames)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVFreeFrames end:no frames\n");
#endif
return;
}
free(pFrameData->fFrames);
pFrameData->fFrames = NULL;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVFreeFrames end\n");
#endif
}
static void DVGetNextFullOutputFrame(DVFrameVars *pFrameData, UInt8** ppFrame, UInt32 frameSize )
{
if(NULL == *ppFrame) {
*ppFrame = pFrameData->fFrames;
}
else {
if (pFrameData->fReader + 1 < pFrameData->fWriter) {
pFrameData->fReader++;
}
else {
pFrameData->fDroppedFrames++;
}
*ppFrame = pFrameData->fFrames +
frameSize*(pFrameData->fReader % pFrameData->fNumFrames);
}
}
void DVSetInputFrameSizeAndMode(DVFrameVars *pFrameData, UInt32 bytes, UInt8 mode, UInt32 frameTime )
{
int index = pFrameData->fWriter % pFrameData->fNumFrames;
int i;
pFrameData->fFrameSize[index] = bytes;
pFrameData->fFrameStandard[index] = mode;
pFrameData->fFrameTime[index] = frameTime;
pFrameData->fFrameStatus[index] = kReady;
for(i=pFrameData->fWriter + 1; i < pFrameData->fReader + pFrameData->fNumFrames; i++) {
if(pFrameData->fFrameStatus[i % pFrameData->fNumFrames] != kReading)
break;
}
if (i< pFrameData->fReader + pFrameData->fNumFrames)
pFrameData->fWriter = i;
else {
pFrameData->fDroppedFrames++;
}
}
void DVGetNextEmptyInputFrame(DVFrameVars *pFrameData, UInt8** ppFrame, UInt32 frameSize )
{
int index = pFrameData->fWriter % pFrameData->fNumFrames;
*ppFrame = pFrameData->fFrames + frameSize*index;
pFrameData->fFrameStatus[index] = kWriting;
}
static UInt32 getEmptyPacketsPerGroup(DVGlobalOutPtr pGlobalData, UInt32 numDataPacketsPerPlayBufferGroup)
{
UInt32 numEmptyPacketsPerPlayBufferGroup;
UInt32 A1, C1, d1, n1;
A1 = numDataPacketsPerPlayBufferGroup;
C1 = pGlobalData->numDataPacketsPerFrame;
n1 = pGlobalData->playFrameRateNumerator;
d1 = pGlobalData->playFrameRateDenominator;
#if ALT_TIMING
{
UInt32 d2 = C1*n1;
UInt32 n2 = (8000 * d1 * A1) - (d2 * A1) + d2;
numEmptyPacketsPerPlayBufferGroup = n2 / d2;
}
#else
numEmptyPacketsPerPlayBufferGroup = (8000 * d1 * A1 + (n1 * C1)/2) / (n1 * C1) - A1;
#endif
return numEmptyPacketsPerPlayBufferGroup;
}
static void FreeDCLCommandPool(DVGlobalOutPtr pGlobalData)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: FreeDCLCommandPool begin\n");
#endif
if( pGlobalData->fDCLCommandPool != NULL ) {
free(pGlobalData->fDCLCommandPool);
pGlobalData->fDCLCommandPool = NULL;
}
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: FreeDCLCommandPool end\n");
#endif
}
static IOReturn AllocateDCLCommandPool(DVGlobalOutPtr pGlobalData, UInt32 total )
{
UInt8 * pDCLCommandPool;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: AllocateDCLCommandPool begin\n");
#endif
pDCLCommandPool = malloc(total);
if (pDCLCommandPool == NULL)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: AllocateDCLCommandPool end:no pool\n");
#endif
return kIOReturnNoMemory;
}
else
{
pGlobalData->fTotalPool = total;
pGlobalData->fAllocatedPool = 0;
pGlobalData->fDCLCommandPool = pDCLCommandPool;
}
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: AllocateDCLCommandPool end\n");
#endif
return kIOReturnSuccess;
}
static DCLCommandPtr AllocateDCLCommand(DVGlobalOutPtr pGlobalData, UInt32 dclSize )
{
DCLCommandPtr pDCLCommand;
if(pGlobalData->fAllocatedPool + dclSize <= pGlobalData->fTotalPool) {
pDCLCommand = (DCLCommandPtr)(pGlobalData->fDCLCommandPool + pGlobalData->fAllocatedPool);
pGlobalData->fAllocatedPool += dclSize;
}
else {
syslog(LOG_INFO, "Trying to allocated DCL command size %d, no space left\n", dclSize);
pDCLCommand = NULL;
}
return (pDCLCommand);
}
static DVLocalOutPtr DVAllocatePlayBufferGroup(DVGlobalOutPtr pGlobalData, int num)
{
DVLocalOutPtr pLocalData,
pPrevLocalData,
pNextLocalData;
pLocalData = &pGlobalData->fLocalDataArray[num];
pLocalData->pGlobalData = pGlobalData;
pLocalData->fBlockNum = num;
if(num == 0) {
pPrevLocalData = &pGlobalData->fLocalDataArray[kNumPlayBufferGroups-1];
}
else
pPrevLocalData = &pGlobalData->fLocalDataArray[num-1];
if(num == kNumPlayBufferGroups-1)
pNextLocalData = &pGlobalData->fLocalDataArray[0];
else
pNextLocalData = &pGlobalData->fLocalDataArray[num+1];
pLocalData->pNextLocalData = pNextLocalData;
pLocalData->pPrevLocalData = pPrevLocalData;
return (pLocalData);
}
static void DVDeallocatePlayBufferGroup( DVLocalOutPtr pLocalData )
{
if ( pLocalData != NULL )
{
if ( pLocalData->bufferGroupUpdateDCLList != NULL )
free(pLocalData->bufferGroupUpdateDCLList);
}
}
static IOReturn DVCreatePlayBufferGroupUpdateList( DVLocalOutPtr pLocalData)
{
DCLCommandPtr pDCLCommand,
pLastDCLCommand;
DCLCommandPtr *updateDCLList,
*pUpdateDCLListEntry;
UInt32 opcode;
UInt32 updateListSize;
IOReturn error = 0;
pDCLCommand = pLocalData->pFirstBufferGroupDCLCommand;
pLastDCLCommand = pLocalData->pLastBufferGroupDCLCommand;
updateListSize = 0;
while (pDCLCommand != pLastDCLCommand)
{
opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
if ((opcode == kDCLSendPacketStartOp) || (opcode == kDCLSendPacketOp))
updateListSize++;
pDCLCommand = pDCLCommand->pNextDCLCommand;
}
opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
if ((opcode == kDCLSendPacketStartOp) || (opcode == kDCLSendPacketOp))
updateListSize++;
updateDCLList = (DCLCommandPtr *)malloc( updateListSize * sizeof (DCLCommandPtr) );
if (updateDCLList == NULL)
{
error = kIOReturnNoMemory;
}
else
{
bzero( updateDCLList, updateListSize * sizeof (DCLCommandPtr) );
}
if (error == 0)
{
pDCLCommand = pLocalData->pFirstBufferGroupDCLCommand;
pLastDCLCommand = pLocalData->pLastBufferGroupDCLCommand;
pUpdateDCLListEntry = updateDCLList;
while (pDCLCommand != pLastDCLCommand)
{
opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
if ((opcode == kDCLSendPacketStartOp) || (opcode == kDCLSendPacketOp))
*pUpdateDCLListEntry++ = pDCLCommand;
pDCLCommand = pDCLCommand->pNextDCLCommand;
}
opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
if ((opcode == kDCLSendPacketStartOp) || (opcode == kDCLSendPacketOp))
*pUpdateDCLListEntry++ = pDCLCommand;
}
if (error == 0)
{
pLocalData->bufferGroupUpdateDCLList = updateDCLList;
pLocalData->updateListSize = updateListSize;
}
else
{
pLocalData->bufferGroupUpdateDCLList = NULL;
pLocalData->updateListSize = 0;
}
return ( error );
}
static void ModifyDCLJump(IOFireWireLibLocalIsochPortRef port, DCLJumpPtr pDCLJump, DCLLabelPtr pDCLLabel)
{
if (port) {
(*port)->ModifyJumpDCL( port, pDCLJump, pDCLLabel);
}
}
void DVSilenceFrame(UInt8 mode, UInt8* frame)
{
UInt32 i,j,k,n;
UInt8 *tPtr;
UInt8 sType = ((mode & 0x7C) >> 2);
tPtr = frame;
if ((tPtr[3] & 0x80) == 0)
n=10; else
n=12;
if (sType == 1)
n /= 2; else if (sType == 0x1D)
n *= 2;
for (i=0;i<n;i++)
{
for (j=0;j<9;j++)
{
tPtr = frame + (i * 12000) + ((j * 16 + 6) * 80) + 8;
for (k=0;k<72;k++)
*tPtr++ = 0x0;
}
}
}
static void DVUpdateOutputBuffers( DVLocalOutPtr pLocalData )
{
DCLCommandPtr pCurrentDCLCommand;
DCLTransferPacketPtr pDCLTransferPacket;
DVLocalOutPtr pPrevLocalData;
DVGlobalOutPtr pGlobalData;
UInt16 localNodeID;
UInt32 shiftedNodeID; UInt32 nominalFrameCycleTime;
UInt32 syt;
UInt32 *pBuffer, *pImageBuffer, *pLastImageBuffer;
UInt32 packetNum, dataPacketNum, numPackets;
UInt32 dbc;
UInt8 stype;
pGlobalData = pLocalData->pGlobalData;
pCurrentDCLCommand = pLocalData->pFirstBufferGroupDCLCommand;
nominalFrameCycleTime = pGlobalData->nominalFrameCycleTime;
pPrevLocalData = pLocalData->pPrevLocalData;
syt = pGlobalData->nextSYT;
dbc = pGlobalData->nextDBC;
dataPacketNum = pGlobalData->nextDataPacketNum;
(*pGlobalData->fStreamVars.pFWDevice)->GetLocalNodeID(pGlobalData->fStreamVars.pFWDevice, &localNodeID);
localNodeID &= 0x3f;
shiftedNodeID = (UInt32)localNodeID << 24;
while (pCurrentDCLCommand->opcode != kDCLSendPacketStartOp)
pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand;
pDCLTransferPacket = (DCLTransferPacketPtr) pCurrentDCLCommand;
numPackets = pLocalData->numPackets;
if(pGlobalData->fUpdateBuffers) {
if( pGlobalData->pImageBuffer == NULL ) {
DVGetNextFullOutputFrame(&pGlobalData->fStreamVars.fFrames,
(UInt8 **)&(pGlobalData->pImageBuffer),
pGlobalData->fStreamVars.fDVFrameSize);
}
}
pImageBuffer = ( pGlobalData->pImageBuffer + (pGlobalData->fDataQuadSize * dataPacketNum) );
for( packetNum = 0; packetNum < numPackets; packetNum++)
{
pBuffer = (UInt32 *) pDCLTransferPacket->buffer;
pBuffer[0] = EndianU32_NtoB( pGlobalData->fHeader0 | (dbc & 0xFF) | shiftedNodeID );
pBuffer[1] = EndianU32_NtoB( pGlobalData->fHeader1 | 0xFFFF );
if (pDCLTransferPacket->size > kDVPacketCIPSize)
{
if (dataPacketNum == 0)
{
pBuffer[1] = EndianU32_NtoB( pGlobalData->fHeader1 | (syt & 0xFFFF) );
syt = AddFWCycleTimeToFWCycleTime(syt, pGlobalData->nominalFrameCycleTime);
}
if(pGlobalData->fUpdateBuffers) {
bcopy(pImageBuffer, (void *)((UInt32)(pDCLTransferPacket->buffer) + kDVPacketCIPSize),
pGlobalData->fDataPacketSize);
pImageBuffer += pGlobalData->fDataQuadSize;
}
stype = pGlobalData->fStreamVars.fSignalMode & kAVCSignalModeMask_STYPE;
switch (stype)
{
case kAVCSignalModeMask_DVCPro50:
dbc += 2; break;
case kAVCSignalModeMask_DVCPro100:
dbc += 4; break;
case kAVCSignalModeMask_SDL:
case kAVCSignalModeMask_DVCPro25:
case kAVCSignalModeMask_HD:
default: dbc += 1; break;
};
dataPacketNum++;
if (dataPacketNum == pGlobalData->numDataPacketsPerFrame )
{
dataPacketNum = 0;
if(pGlobalData->fUpdateBuffers) {
pLastImageBuffer = pGlobalData->pImageBuffer;
DVGetNextFullOutputFrame(&pGlobalData->fStreamVars.fFrames,
(UInt8 **)&(pGlobalData->pImageBuffer),
pGlobalData->fStreamVars.fDVFrameSize);
pImageBuffer = pGlobalData->pImageBuffer;
if (pImageBuffer == pLastImageBuffer)
DVSilenceFrame(pGlobalData->fStreamVars.fSignalMode, (UInt8 *)pImageBuffer);
} } }
pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand;
while (pCurrentDCLCommand != NULL)
{
if (pCurrentDCLCommand->opcode != kDCLSendPacketStartOp)
pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand;
else
break;
}
pDCLTransferPacket = (DCLTransferPacketPtr) pCurrentDCLCommand;
}
pGlobalData->nextSYT = syt;
pGlobalData->nextDBC = dbc;
pGlobalData->nextDataPacketNum = dataPacketNum;
}
static void DVHandleOutput(DVLocalOutPtr pLocalData)
{
DVGlobalOutPtr pGlobalData;
DVLocalOutPtr pPrevLocalData;
UInt32 nominalFrameCycleTime;
UInt32 fractionalFrameCycleCount,
fractionalFrameCycleOffset;
SInt32 timeDrift;
UInt32 cycleDrift;
UInt32 projectedTimeStamp,
projectedSYT;
#if TIMING
CFAbsoluteTime cstart, cend;
cstart = CFAbsoluteTimeGetCurrent();
#endif
pPrevLocalData = pLocalData->pPrevLocalData;
pGlobalData = pLocalData->pGlobalData;
nominalFrameCycleTime = pGlobalData->nominalFrameCycleTime;
if (pLocalData->skippingEmptyPacket)
{
ModifyDCLJump(pGlobalData->fStreamVars.pFWLocalIsochPort,
pLocalData->pBufferGroupSkipEmptyPacketDCLJump, pLocalData->pBufferGroupDontSkipEmptyPacketDCLLabel);
pGlobalData->activePackets++;
pLocalData->skippingEmptyPacket = false;
}
projectedTimeStamp = *pLocalData->pBufferGroupTimeStampPtr; projectedTimeStamp = AddFWCycleTimeToFWCycleTime(projectedTimeStamp, 1 << 12);
projectedTimeStamp = AddFWCycleTimeToFWCycleTime(projectedTimeStamp, pGlobalData->activePackets << 12);
projectedTimeStamp = SubtractFWCycleTimeFromFWCycleTime(projectedTimeStamp, pLocalData->numPackets << 12);
projectedSYT = pGlobalData->nextSYT;
if(pGlobalData->nextDataPacketNum != 0) {
projectedSYT = SubtractFWCycleTimeFromFWCycleTime(projectedSYT, nominalFrameCycleTime);
fractionalFrameCycleOffset =
((nominalFrameCycleTime & 0x0FFF) * pGlobalData->nextDataPacketNum) /
pGlobalData->numDataPacketsPerFrame;
fractionalFrameCycleCount =
((nominalFrameCycleTime & 0x01FFF000) * pGlobalData->nextDataPacketNum) /
pGlobalData->numDataPacketsPerFrame;
fractionalFrameCycleCount =
(fractionalFrameCycleCount & 0x01FFF000) +
(((fractionalFrameCycleCount & 0x0FFF) * 3072) / 4096);
projectedSYT = AddFWCycleTimeToFWCycleTime (projectedSYT, fractionalFrameCycleOffset);
projectedSYT = AddFWCycleTimeToFWCycleTime (projectedSYT, fractionalFrameCycleCount);
}
cycleDrift = AddFWCycleTimeToFWCycleTime(projectedTimeStamp, kPlaySYTDelay << 12);
cycleDrift = SubtractFWCycleTimeFromFWCycleTime(cycleDrift, projectedSYT);
timeDrift = (cycleDrift >> 12) & 0x000F;
if ((timeDrift > 0) && (timeDrift < 0x0008))
{
ModifyDCLJump(pGlobalData->fStreamVars.pFWLocalIsochPort,
pLocalData->pBufferGroupSkipEmptyPacketDCLJump, pLocalData->pBufferGroupSkipEmptyPacketDCLLabel);
pGlobalData->activePackets--;
pLocalData->skippingEmptyPacket = true;
}
DVUpdateOutputBuffers( pLocalData );
ModifyDCLJump (pGlobalData->fStreamVars.pFWLocalIsochPort,
pLocalData->pEndOfBufferGroupDCLJump, pGlobalData->pUnderrunDCLLabel);
ModifyDCLJump (pGlobalData->fStreamVars.pFWLocalIsochPort,
pPrevLocalData->pEndOfBufferGroupDCLJump, pLocalData->pStartOfBufferGroupDCLLabel);
pGlobalData->fSharedDCLVars.fDMAPos = pLocalData->fBlockNum;
#if TIMING
cend = CFAbsoluteTimeGetCurrent();
DVLog(pGlobalData->fStreamVars.fThread, 'isoc', cstart, cend);
#endif
}
static void DVWritePoll(DVGlobalOutPtr globs)
{
int i, pos;
pos = globs->fSharedDCLVars.fDMAPos;
for(i=pos; i<kNumPlayBufferGroups; i++)
if(*globs->fLocalDataArray[i].pBufferGroupTimeStampPtr != 0xffffffff) {
DVHandleOutput(&globs->fLocalDataArray[i]);
*globs->fLocalDataArray[i].pBufferGroupTimeStampPtr = 0xffffffff;
}
for(i=0; i<pos; i++)
if(*globs->fLocalDataArray[i].pBufferGroupTimeStampPtr != 0xffffffff) {
DVHandleOutput(&globs->fLocalDataArray[i]);
*globs->fLocalDataArray[i].pBufferGroupTimeStampPtr = 0xffffffff;
}
}
static void doDVHandleOutputUnderrun( DVGlobalOutPtr pGlobalData )
{
IOReturn err;
syslog(LOG_INFO, "DVHandleOutputUnderrun: 0x%p\n", pGlobalData);
DVStream *stream;
if ((pGlobalData->pendingDVWriteUnderrunHandler == true) && (pGlobalData->deferredDVWriteFree == true))
{
free(pGlobalData);
return;
}
pGlobalData->pendingDVWriteUnderrunHandler = false;
stream = &pGlobalData->fStreamVars;
if (stream->fIsochChannelRef == NULL)
return;
closeStream(&pGlobalData->fStreamVars);
FreeDCLCommandPool(pGlobalData);
BreakP2PConnectionForWrite(pGlobalData->fStreamVars.pDVDevice,0,pGlobalData->fStreamVars.fIsocChannel);
err = buildWriteProgram(pGlobalData);
if(err != kIOReturnSuccess)
syslog(LOG_INFO, "DVHandleOutputUnderrun: buildWriteProgram returned %x\n", err);
err = DVWriteStart(pGlobalData);
}
static void DVHandleOutputUnderrun( DCLCommandPtr pDCLCommandPtr )
{
DVGlobalOutPtr pGlobalData;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVHandleOutputUnderrun begin\n");
#endif
pGlobalData = (DVGlobalOutPtr)((DCLCallProcPtr)pDCLCommandPtr)->procData;
if (pGlobalData->dvWriteStopInProgress == false)
{
pGlobalData->pendingDVWriteUnderrunHandler = true;
DVRequest(pGlobalData->fStreamVars.fThread, doDVHandleOutputUnderrun, pGlobalData, 0);
}
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVHandleOutputUnderrun end\n");
#endif
}
static void DVDisposeDCLOutput( DVGlobalOutPtr pOutputData )
{
DVLocalOutPtr pLocalData, pNextLocalData;
UInt32 bufferGroupNum;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVDisposeDCLOutput begin\n");
#endif
if( pOutputData != NULL )
{
pLocalData = &pOutputData->fLocalDataArray[0];
for (bufferGroupNum = 0; bufferGroupNum < kNumPlayBufferGroups; bufferGroupNum++)
{
if( pLocalData != NULL )
{
pNextLocalData = pLocalData->pNextLocalData;
DVDeallocatePlayBufferGroup (pLocalData);
pLocalData = pNextLocalData;
}
}
FreeDCLCommandPool(pOutputData);
if( pOutputData->fStreamVars.fDCLBuffers != NULL)
{
vm_deallocate(mach_task_self(), (vm_address_t)pOutputData->fStreamVars.fDCLBuffers,
pOutputData->fStreamVars.fDCLBufferSize);
}
}
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVDisposeDCLOutput end\n");
#endif
}
static IOReturn allocateBuffers(DVGlobalOutPtr pGlobalData)
{
UInt32 numDataPacketsPerPage;
UInt32 numEmptyPackets;
UInt32 pageSize;
UInt32 emptySize; UInt32 transmitBuffersSize;
IOReturn res;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: allocateBuffers begin\n");
#endif
UInt8 stype = pGlobalData->fStreamVars.fSignalMode & kAVCSignalModeMask_STYPE;
switch (stype)
{
case kAVCSignalModeMask_SDL:
pGlobalData->fHeader0 = 0x003c0000;
pGlobalData->fHeader1 = 0x80040000;
pGlobalData->fDataPacketSize = kDVSDLPayloadPacketSize; break;
case kAVCSignalModeMask_DVCPro25:
pGlobalData->fHeader0 = 0x00780000;
pGlobalData->fHeader1 = 0x80780000;
pGlobalData->fDataPacketSize = kDVSDPayloadPacketSize; break;
case kAVCSignalModeMask_DVCPro50:
pGlobalData->fHeader0 = 0x00784000;
pGlobalData->fHeader1 = 0x80740000;
pGlobalData->fDataPacketSize = kDVCPro50PayloadPacketSize; break;
case kAVCSignalModeMask_DVCPro100:
pGlobalData->fHeader0 = 0x00788000;
pGlobalData->fHeader1 = 0x80700000;
pGlobalData->fDataPacketSize = kDVCPro50PayloadPacketSize; break;
case kAVCSignalModeMask_HD:
pGlobalData->fHeader0 = 0x00F00000;
pGlobalData->fHeader1 = 0x80080000;
pGlobalData->fDataPacketSize = kDVCPro50PayloadPacketSize; break;
default: pGlobalData->fHeader0 = 0x00780000;
pGlobalData->fHeader1 = 0x80000000;
pGlobalData->fDataPacketSize = kDVSDPayloadPacketSize; break;
};
pGlobalData->fDataQuadSize = pGlobalData->fDataPacketSize/4; pGlobalData->fAlignQuadSize = (pGlobalData->fDataPacketSize + kDVPacketCIPSize + 15)/16;
pGlobalData->fAlignQuadSize *= 4; pGlobalData->fSharedDCLVars.fAlignedPacketSize = 4*pGlobalData->fAlignQuadSize; pGlobalData->fSharedDCLVars.fPacketDataSize = pGlobalData->fDataPacketSize;
if( !(pGlobalData->fStreamVars.fSignalMode & kAVCSignalModeMask_50) )
{
pGlobalData->playFramePeriodNumerator = kNTSCPlayFramePeriodNumerator;
pGlobalData->playFramePeriodDenominator = kNTSCPlayFramePeriodDenominator;
pGlobalData->playFrameRateNumerator = kNTSCFrameRateNumerator;
pGlobalData->playFrameRateDenominator = kNTSCFrameRateDenominator;
pGlobalData->numDataPacketsPerFrame = kNTSCNumDataPacketsPerDVFrame;
pGlobalData->numDataPacketsPerGroup = kNTSCNumDataPacketsPerGroup;
}
else
{
pGlobalData->fHeader1 |= kPALBit;
pGlobalData->playFramePeriodNumerator = kPALPlayFramePeriodNumerator;
pGlobalData->playFramePeriodDenominator = kPALPlayFramePeriodDenominator;
pGlobalData->playFrameRateNumerator = kPALFrameRateNumerator;
pGlobalData->playFrameRateDenominator = kPALFrameRateDenominator;
pGlobalData->numDataPacketsPerFrame = kPALNumDataPacketsPerDVFrame;
pGlobalData->numDataPacketsPerGroup = kPALNumDataPacketsPerGroup;
}
pGlobalData->nominalFrameCycleTime = ConvertFractionalSecondsToFWCycleTime
(pGlobalData->playFramePeriodNumerator, pGlobalData->playFramePeriodDenominator);
pGlobalData->fSharedDCLVars.fNumGroups = kNumPlayBufferGroups;
pGlobalData->fSharedDCLVars.fGroupSize = pGlobalData->numDataPacketsPerGroup;
pageSize = PAGE_SIZE;
numDataPacketsPerPage = pageSize /
(pGlobalData->fDataPacketSize + kDVPacketCIPSize + kDVPacketAlignSlop);
#if ALT_TIMING
numEmptyPackets = getEmptyPacketsPerGroup(pGlobalData, pGlobalData->numDataPacketsPerGroup) * kNumPlayBufferGroups;
#else
numEmptyPackets =
getEmptyPacketsPerGroup(pGlobalData, pGlobalData->numDataPacketsPerGroup * kNumPlayBufferGroups) + kNumPlayBufferGroups/2;
#endif
transmitBuffersSize = pGlobalData->numDataPacketsPerGroup * kNumPlayBufferGroups * pageSize;
transmitBuffersSize /= numDataPacketsPerPage;
emptySize = numEmptyPackets * (kDVPacketCIPSize + kDVPacketAlignSlop);
pGlobalData->fStreamVars.fDCLBufferSize =
transmitBuffersSize + emptySize + sizeof(UInt32)*kNumPlayBufferGroups;
vm_allocate(mach_task_self(), (vm_address_t *)&pGlobalData->fStreamVars.fDCLBuffers,
pGlobalData->fStreamVars.fDCLBufferSize, VM_FLAGS_ANYWHERE);
if( pGlobalData->fStreamVars.fDCLBuffers == NULL ) {
res = kIOReturnNoMemory;
goto bail;
}
bzero( pGlobalData->fStreamVars.fDCLBuffers, pGlobalData->fStreamVars.fDCLBufferSize );
pGlobalData->pEmptyTransmitBuffers = pGlobalData->fStreamVars.fDCLBuffers + transmitBuffersSize;
pGlobalData->fSharedDCLVars.fTimeStampPtrs = (UInt32 *)(pGlobalData->pEmptyTransmitBuffers + emptySize);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: allocateBuffers end\n");
#endif
return kIOReturnSuccess;
bail:
DVDisposeDCLOutput( pGlobalData );
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: allocateBuffers end:fail\n");
#endif
return res;
}
static IOReturn buildWriteProgram(DVGlobalOutPtr pGlobalData)
{
UInt32 numEmptyPacketsInPlayBufferGroup;
DCLCommandPtr pDCLCommand;
DCLCommandPtr pFirstBufferGroupDCLCommand;
DCLLabelPtr pUnderrunDCLLabel,
pBufferGroupDCLLabel,
pDCLLabel;
DCLTransferPacketPtr pDCLTransferPacket;
DCLCallProcPtr pDCLCallProc;
DCLSetTagSyncBitsPtr pDCLSetTagSyncBits;
DCLJumpPtr pDCLJump,
pBufferGroupDCLJump;
DCLLabelPtr pBufferGroupSkipEmptyPacketDCLLabel;
DCLUpdateDCLListPtr pDCLUpdateDCLList;
DCLPtrTimeStampPtr pDCLTimeStamp;
DVLocalOutPtr pPlayBufferGroupData;
UInt32 * pTransmitBuffer;
UInt8 * pEmptyTransmitBuffer;
volatile UInt32 * pTimeStampPtr;
UInt32 bufferGroupNum;
UInt32 dataPacketNum;
UInt32 numPackets;
UInt32 emptyPacketNumerator;
UInt32 pageOffset;
IOReturn res;
UInt32 totalDCLSize;
UInt32 totalEmpty, emptySoFar;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: buildWriteProgram begin\n");
#endif
#if ALT_TIMING
totalEmpty = getEmptyPacketsPerGroup(pGlobalData, pGlobalData->numDataPacketsPerGroup) * kNumPlayBufferGroups;
#else
totalEmpty = getEmptyPacketsPerGroup(pGlobalData, pGlobalData->numDataPacketsPerGroup * kNumPlayBufferGroups) + kNumPlayBufferGroups/2;
#endif
emptySoFar = 0;
pTransmitBuffer = (UInt32 *) pGlobalData->fStreamVars.fDCLBuffers;
pEmptyTransmitBuffer = pGlobalData->pEmptyTransmitBuffers;
pTimeStampPtr = pGlobalData->fSharedDCLVars.fTimeStampPtrs;
totalDCLSize = 2 * sizeof(DCLLabel) + sizeof(DCLSetTagSyncBits) + sizeof(DCLJump) + sizeof(DCLCallProc) +
kNumPlayBufferGroups * (pGlobalData->numDataPacketsPerGroup * sizeof(DCLTransferPacket) + 3*sizeof(DCLLabel) + 2*sizeof(DCLJump) + sizeof(DCLPtrTimeStamp) + 2*sizeof(DCLUpdateDCLList) + sizeof(DCLCallProc) + totalEmpty * sizeof(DCLTransferPacket));
res = AllocateDCLCommandPool(pGlobalData, totalDCLSize);
if (res)
goto bail;
pGlobalData->totalPackets = 0;
pGlobalData->activePackets = 0;
pDCLSetTagSyncBits = (DCLSetTagSyncBitsPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLSetTagSyncBits));
pDCLCommand = (DCLCommandPtr) pDCLSetTagSyncBits;
pDCLSetTagSyncBits->opcode = kDCLSetTagSyncBitsOp;
pDCLSetTagSyncBits->tagBits = 1;
pDCLSetTagSyncBits->syncBits = 0;
pGlobalData->fStreamVars.pDCLList = pDCLCommand;
for (bufferGroupNum = 0; bufferGroupNum < kNumPlayBufferGroups; bufferGroupNum++)
{
pPlayBufferGroupData = DVAllocatePlayBufferGroup( pGlobalData, bufferGroupNum);
dataPacketNum = 0;
numPackets = 0;
emptyPacketNumerator = 0;
#if ALT_TIMING
numEmptyPacketsInPlayBufferGroup = totalEmpty/kNumPlayBufferGroups;
#else
numEmptyPacketsInPlayBufferGroup = (totalEmpty*(bufferGroupNum+1)+kNumPlayBufferGroups/2)/kNumPlayBufferGroups - emptySoFar;
#endif
emptySoFar += numEmptyPacketsInPlayBufferGroup;
pFirstBufferGroupDCLCommand = NULL;
pBufferGroupSkipEmptyPacketDCLLabel = NULL;
pGlobalData->fSharedDCLVars.fDataOffset[bufferGroupNum] =
(UInt8*)pTransmitBuffer - pGlobalData->fStreamVars.fDCLBuffers;
pBufferGroupDCLLabel = (DCLLabelPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLLabel));
pPlayBufferGroupData->pStartOfBufferGroupDCLLabel = pBufferGroupDCLLabel;
pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pBufferGroupDCLLabel;
pDCLCommand = (DCLCommandPtr) pBufferGroupDCLLabel;
pBufferGroupDCLLabel->opcode = kDCLLabelOp;
while (dataPacketNum < pGlobalData->numDataPacketsPerGroup)
{
pDCLTransferPacket = (DCLTransferPacketPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLTransferPacket));
pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLTransferPacket;
pDCLCommand = (DCLCommandPtr) pDCLTransferPacket;
pDCLTransferPacket->opcode = kDCLSendPacketStartOp;
pDCLTransferPacket->size = pGlobalData->fDataPacketSize + kDVPacketCIPSize;
pageOffset = (UInt32) (pTransmitBuffer + pGlobalData->fAlignQuadSize) & 0x0fff;
if (pageOffset < (4*pGlobalData->fAlignQuadSize) && pageOffset > 0)
{
pTransmitBuffer += pGlobalData->fAlignQuadSize;
pTransmitBuffer = (UInt32 *)((UInt32)pTransmitBuffer & 0xfffff000);
}
pDCLTransferPacket->buffer = (UInt8 *) pTransmitBuffer;
pTransmitBuffer += pGlobalData->fAlignQuadSize;
if (pFirstBufferGroupDCLCommand == NULL)
pFirstBufferGroupDCLCommand = (DCLCommandPtr) pDCLCommand;
dataPacketNum++;
numPackets++;
emptyPacketNumerator += numEmptyPacketsInPlayBufferGroup;
if (emptyPacketNumerator >= pGlobalData->numDataPacketsPerGroup)
{
if (pBufferGroupSkipEmptyPacketDCLLabel == NULL)
{
pDCLJump = (DCLJumpPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLJump));
pPlayBufferGroupData->pBufferGroupSkipEmptyPacketDCLJump = pDCLJump;
pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLJump;
pDCLCommand = (DCLCommandPtr) pDCLJump;
pDCLJump->opcode = kDCLJumpOp | kFWDCLOpDynamicFlag;
pDCLLabel = (DCLLabelPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLLabel));
pPlayBufferGroupData->pBufferGroupDontSkipEmptyPacketDCLLabel = pDCLLabel;
pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLLabel;
pDCLCommand = (DCLCommandPtr) pDCLLabel;
pDCLLabel->opcode = kDCLLabelOp;
pDCLJump->pJumpDCLLabel = pDCLLabel;
}
pDCLTransferPacket = (DCLTransferPacketPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLTransferPacket));
pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLTransferPacket;
pDCLCommand = (DCLCommandPtr) pDCLTransferPacket;
pDCLTransferPacket->opcode = kDCLSendPacketStartOp;
pDCLTransferPacket->buffer = pEmptyTransmitBuffer;
pDCLTransferPacket->size = kDVPacketCIPSize;
pEmptyTransmitBuffer += kDVPacketCIPSize+kDVPacketAlignSlop;
numPackets++;
emptyPacketNumerator -= pGlobalData->numDataPacketsPerGroup;
if (pBufferGroupSkipEmptyPacketDCLLabel == NULL)
{
pDCLLabel = (DCLLabelPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLLabel));
pBufferGroupSkipEmptyPacketDCLLabel = pDCLLabel;
pPlayBufferGroupData->pBufferGroupSkipEmptyPacketDCLLabel = pBufferGroupSkipEmptyPacketDCLLabel;
pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLLabel;
pDCLCommand = (DCLCommandPtr) pDCLLabel;
pDCLLabel->opcode = kDCLLabelOp;
}
}
}
pPlayBufferGroupData->numPackets = numPackets;
pPlayBufferGroupData->pFirstBufferGroupDCLCommand = pFirstBufferGroupDCLCommand;
pPlayBufferGroupData->pLastBufferGroupDCLCommand = (DCLCommandPtr) pDCLCommand;
DVCreatePlayBufferGroupUpdateList( pPlayBufferGroupData );
pGlobalData->totalPackets += numPackets;
pGlobalData->activePackets += numPackets;
#if ALT_TIMING
{
UInt32 nominalProgramCycleTime = 0;
UInt32 nominalActivePackets = 0;
SInt32 cycleDrift = 0;
nominalProgramCycleTime = ConvertFractionalSecondsToFWCycleTime( pGlobalData->playFramePeriodNumerator*(kNumPlayBufferGroups/2),
pGlobalData->playFramePeriodDenominator );
nominalActivePackets = ((nominalProgramCycleTime & 0x01FFF000) >> 12);
cycleDrift = pGlobalData->activePackets - ((nominalActivePackets*(bufferGroupNum+1)) / kNumPlayBufferGroups);
if(cycleDrift > 0) {
pGlobalData->activePackets--;
pPlayBufferGroupData->pBufferGroupSkipEmptyPacketDCLJump->pJumpDCLLabel = pPlayBufferGroupData->pBufferGroupSkipEmptyPacketDCLLabel;
pPlayBufferGroupData->skippingEmptyPacket = true;
}
else
pPlayBufferGroupData->skippingEmptyPacket = false;
}
#else
emptyError = getEmptyPacketsPerGroup(pGlobalData, pGlobalData->numDataPacketsPerGroup*(bufferGroupNum+1));
emptyError = pGlobalData->activePackets - pGlobalData->numDataPacketsPerGroup*(bufferGroupNum+1) - emptyError;
if(emptyError > 0) {
pGlobalData->activePackets--;
pPlayBufferGroupData->pBufferGroupSkipEmptyPacketDCLJump->pJumpDCLLabel = pPlayBufferGroupData->pBufferGroupSkipEmptyPacketDCLLabel;
pPlayBufferGroupData->skippingEmptyPacket = true;
}
else
pPlayBufferGroupData->skippingEmptyPacket = false;
#endif
pDCLTimeStamp = (DCLPtrTimeStampPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLPtrTimeStamp));
pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLTimeStamp;
pDCLCommand = (DCLCommandPtr) pDCLTimeStamp;
pDCLTimeStamp->opcode = kDCLPtrTimeStampOp;
*pTimeStampPtr = 0xffffffff; pDCLTimeStamp->timeStampPtr = pTimeStampPtr++;
pPlayBufferGroupData->pBufferGroupTimeStampPtr = pDCLTimeStamp->timeStampPtr;
pPlayBufferGroupData->timeStampUpdateDCLList = (DCLCommandPtr) pDCLTimeStamp;
pDCLUpdateDCLList = (DCLUpdateDCLListPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLUpdateDCLList));
pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLUpdateDCLList;
pDCLCommand = (DCLCommandPtr) pDCLUpdateDCLList;
pDCLUpdateDCLList->opcode = kDCLUpdateDCLListOp;
pDCLUpdateDCLList->dclCommandList = &(pPlayBufferGroupData->timeStampUpdateDCLList);
pDCLUpdateDCLList->numDCLCommands = 1;
#if 0
pDCLUpdateDCLList = (DCLUpdateDCLListPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLUpdateDCLList));
pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLUpdateDCLList;
pDCLCommand = (DCLCommandPtr) pDCLUpdateDCLList;
pDCLUpdateDCLList->opcode = kDCLUpdateDCLListOp;
pDCLUpdateDCLList->dclCommandList = pPlayBufferGroupData->bufferGroupUpdateDCLList;
pDCLUpdateDCLList->numDCLCommands = pPlayBufferGroupData->updateListSize;
#endif
pBufferGroupDCLJump = (DCLJumpPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLJump));
pPlayBufferGroupData->pEndOfBufferGroupDCLJump = pBufferGroupDCLJump;
pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pBufferGroupDCLJump;
pDCLCommand = (DCLCommandPtr) pBufferGroupDCLJump;
pBufferGroupDCLJump->opcode = kDCLJumpOp | kFWDCLOpDynamicFlag;
pBufferGroupDCLJump->pJumpDCLLabel = nil; }
pUnderrunDCLLabel = (DCLLabelPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLLabel));
pGlobalData->pUnderrunDCLLabel = pUnderrunDCLLabel;
pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pUnderrunDCLLabel;
pDCLCommand = (DCLCommandPtr) pUnderrunDCLLabel;
pUnderrunDCLLabel->opcode = kDCLLabelOp;
pDCLTransferPacket = (DCLTransferPacketPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLTransferPacket));
pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLTransferPacket;
pDCLCommand = (DCLCommandPtr) pDCLTransferPacket;
pDCLTransferPacket->opcode = kDCLSendPacketStartOp;
pDCLTransferPacket->buffer = pGlobalData->pEmptyTransmitBuffers;
pDCLTransferPacket->size = kDVPacketCIPSize;
pDCLCallProc = (DCLCallProcPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLCallProc));
pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLCallProc;
pDCLCallProc->pNextDCLCommand = NULL;
pDCLCallProc->opcode = kDCLCallProcOp;
pDCLCallProc->proc = DVHandleOutputUnderrun;
pDCLCallProc->procData = (UInt32) pGlobalData;
for (bufferGroupNum = 0; bufferGroupNum < kNumPlayBufferGroups; bufferGroupNum++)
{
pPlayBufferGroupData = &pGlobalData->fLocalDataArray[bufferGroupNum];
if (bufferGroupNum == (kNumPlayBufferGroups-1))
pPlayBufferGroupData->pEndOfBufferGroupDCLJump->pJumpDCLLabel =
pGlobalData->pUnderrunDCLLabel;
else
pPlayBufferGroupData->pEndOfBufferGroupDCLJump->pJumpDCLLabel =
pGlobalData->fLocalDataArray[bufferGroupNum+1].pStartOfBufferGroupDCLLabel;
}
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: buildWriteProgram end\n");
#endif
return kIOReturnSuccess;
bail:
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: buildWriteProgram end:fail\n");
#endif
return res;
}
DVGlobalOutPtr DVAllocWrite(DVDevice *device, DVThread *thread)
{
DVGlobalOutPtr globs;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVAllocWrite begin\n");
#endif
globs = malloc(sizeof(DVGlobalOut));
if(!globs)
return NULL;
bzero(globs, sizeof(DVGlobalOut));
initStream(&globs->fStreamVars, device, device->fOutPlug, device->fWriteChan, thread);
globs->fUpdateBuffers = 1;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVAllocWrite end\n");
#endif
return globs;
}
IOReturn DVWriteSetSignalMode(DVGlobalOutPtr globs, UInt8 mode)
{
globs->fStreamVars.fSignalMode = mode;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVWriteSetSignalMode begin\n");
#endif
switch (mode)
{
case kAVCSignalModeSD525_60:
case kAVCSignalModeDVCPro525_60:
globs->fStreamVars.fDVFrameSize = kFrameSize_SD525_60;
break;
case kAVCSignalModeSD625_50:
case kAVCSignalModeDVCPro625_50:
globs->fStreamVars.fDVFrameSize = kFrameSize_SD625_50;
break;
case kAVCSignalModeSDL525_60:
globs->fStreamVars.fDVFrameSize = kFrameSize_SDL525_60;
break;
case kAVCSignalModeSDL625_50:
globs->fStreamVars.fDVFrameSize = kFrameSize_SDL625_50;
break;
case kAVCSignalModeDVCPro50_525_60:
case kAVCSignalModeHD1125_60:
globs->fStreamVars.fDVFrameSize = kFrameSize_DVCPro50_525_60;
break;
case kAVCSignalModeDVCPro50_625_50:
case kAVCSignalModeHD1250_50:
globs->fStreamVars.fDVFrameSize = kFrameSize_DVCPro50_625_50;
break;
case kAVCSignalModeDVCPro100_525_60:
globs->fStreamVars.fDVFrameSize = kFrameSize_DVCPro100_525_60;
break;
case kAVCSignalModeDVCPro100_625_50:
globs->fStreamVars.fDVFrameSize = kFrameSize_DVCPro100_625_50;
break;
default:
globs->fStreamVars.fDVFrameSize = kFrameSize_SD625_50;
break;
};
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVWriteSetSignalMode end\n");
#endif
return kIOReturnSuccess;
}
IOReturn DVWriteAllocFrames(DVGlobalOutPtr pGlobalData, UInt32 numFrames,
DVFrameVars **frameVars, UInt8 **frames)
{
IOReturn err;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVWriteAllocFrames begin\n");
#endif
do {
err = DVAllocFrames(&pGlobalData->fStreamVars.fFrames,
numFrames,
pGlobalData->fStreamVars.fDVFrameSize,
frameVars,
frames);
if(err != kIOReturnSuccess)
break;
err = allocateBuffers(pGlobalData);
if(err != kIOReturnSuccess)
break;
err = buildWriteProgram(pGlobalData);
} while (0);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVWriteAllocFrames end\n");
#endif
return err;
}
UInt8 * DVWriteGetDCLBuffer(DVGlobalOutPtr pGlobalData, DVSharedVars **varPtr)
{
pGlobalData->fUpdateBuffers = 0;
*varPtr = &pGlobalData->fSharedDCLVars;
return pGlobalData->fStreamVars.fDCLBuffers;
}
static IOReturn doDVWriteStart(DVGlobalOutPtr pGlobalData)
{
IOReturn err;
DVLocalOutPtr pPlayBufferGroupData;
UInt32 bufferGroupNum;
int i;
DVThread * dvThread = pGlobalData->fStreamVars.fThread;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: doDVWriteStart begin\n");
#endif
do {
pGlobalData->nextSYT = kPlaySYTDelay<<12;
pGlobalData->nextDBC = 0;
pGlobalData->nextDataPacketNum = 0;
pGlobalData->pImageBuffer = NULL;
pGlobalData->fSharedDCLVars.fDMAPos = 0;
pGlobalData->pendingDVWriteUnderrunHandler = false;
pGlobalData->deferredDVWriteFree = false;
pGlobalData->dvWriteStopInProgress = false;
pPlayBufferGroupData = &pGlobalData->fLocalDataArray[0];
for (bufferGroupNum = 0; bufferGroupNum < kNumPlayBufferGroups; bufferGroupNum++)
{
DVUpdateOutputBuffers( pPlayBufferGroupData);
pPlayBufferGroupData = pPlayBufferGroupData->pNextLocalData;
}
err = openStream(&pGlobalData->fStreamVars, true, pGlobalData->fDataPacketSize + kDVPacketCIPSize);
for(i=0; i<kDVMaxStreamsActive; i++) {
if(dvThread->fOutStreams[i] == NULL) {
dvThread->fOutStreams[i] = pGlobalData;
break;
}
else if(dvThread->fOutStreams[i] == pGlobalData) {
break; }
}
} while (0);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: doDVWriteStart end\n");
#endif
return err;
}
IOReturn DVWriteStart(DVGlobalOutPtr pGlobalData)
{
IOReturn err;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVWriteStart begin\n");
#endif
err = DVRequest(pGlobalData->fStreamVars.fThread, doDVWriteStart, pGlobalData, 0);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVWriteStart end\n");
#endif
return err;
}
static void doDVWriteStop(DVGlobalOutPtr pGlobalData)
{
int i;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: doDVWriteStop begin\n");
#endif
pGlobalData->dvWriteStopInProgress = true;
DVThread * dvThread = pGlobalData->fStreamVars.fThread;
for(i=0; i<kDVMaxStreamsActive; i++) {
if(dvThread->fOutStreams[i] == pGlobalData) {
dvThread->fOutStreams[i] = NULL;
break;
}
}
closeStream(&pGlobalData->fStreamVars);
BreakP2PConnectionForWrite(pGlobalData->fStreamVars.pDVDevice,0,pGlobalData->fStreamVars.fIsocChannel);
DVDisposeDCLOutput(pGlobalData);
pGlobalData->dvWriteStopInProgress = false;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: doDVWriteStop end\n");
#endif
}
void DVWriteStop(DVGlobalOutPtr pGlobalData)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVWriteStop begin\n");
#endif
DVRequest(pGlobalData->fStreamVars.fThread, doDVWriteStop, pGlobalData, 0);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVWriteStop end\n");
#endif
}
void DVWriteFreeFrames(DVGlobalOutPtr globs)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVWriteFreeFrames begin\n");
#endif
DVFreeFrames(&globs->fStreamVars.fFrames);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVWriteFreeFrames end\n");
#endif
}
void DVWriteFree(DVGlobalOutPtr globs)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVWriteFree begin\n");
#endif
if (globs->pendingDVWriteUnderrunHandler == true)
globs->deferredDVWriteFree = true;
else
free(globs);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVWriteFree end\n");
#endif
}
DVGlobalInPtr DVAllocRead(DVDevice *device, DVThread *thread)
{
DVGlobalInPtr globs;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVAllocRead begin\n");
#endif
globs = malloc(sizeof(DVGlobalIn));
if(!globs)
return NULL;
bzero(globs, sizeof(DVGlobalIn));
initStream(&globs->fStreamVars, device, kNoPlug, device->fReadChan, thread);
if (device->standard == 0)
DVReadSetSignalMode(globs,0x00); else
DVReadSetSignalMode(globs,0x80);
return globs;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVAllocRead end\n");
#endif
}
IOReturn DVReadSetSignalMode(DVGlobalInPtr globs, UInt8 mode)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVReadSetSignalMode begin\n");
#endif
globs->fStreamVars.fSignalMode = mode;
switch (mode)
{
case kAVCSignalModeSD525_60:
case kAVCSignalModeDVCPro525_60:
globs->fStreamVars.fDVFrameSize = kFrameSize_SD525_60;
break;
case kAVCSignalModeSD625_50:
case kAVCSignalModeDVCPro625_50:
globs->fStreamVars.fDVFrameSize = kFrameSize_SD625_50;
break;
case kAVCSignalModeSDL525_60:
globs->fStreamVars.fSignalMode = kAVCSignalModeSD525_60;
globs->fStreamVars.fDVFrameSize = kFrameSize_SD525_60;
break;
case kAVCSignalModeSDL625_50:
globs->fStreamVars.fSignalMode = kAVCSignalModeSD625_50;
globs->fStreamVars.fDVFrameSize = kFrameSize_SD625_50;
break;
case kAVCSignalModeDVCPro50_525_60:
case kAVCSignalModeHD1125_60:
globs->fStreamVars.fDVFrameSize = kFrameSize_DVCPro50_525_60;
break;
case kAVCSignalModeDVCPro50_625_50:
case kAVCSignalModeHD1250_50:
globs->fStreamVars.fDVFrameSize = kFrameSize_DVCPro50_625_50;
break;
case kAVCSignalModeDVCPro100_525_60:
globs->fStreamVars.fDVFrameSize = kFrameSize_DVCPro100_525_60;
break;
case kAVCSignalModeDVCPro100_625_50:
globs->fStreamVars.fDVFrameSize = kFrameSize_DVCPro100_625_50;
break;
default:
globs->fStreamVars.fSignalMode = kAVCSignalModeSD625_50;
globs->fStreamVars.fDVFrameSize = kFrameSize_SD625_50;
break;
};
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVReadSetSignalMode end\n");
#endif
return kIOReturnSuccess;
}
IOReturn DVReadAllocFrames(DVGlobalInPtr globs, UInt32 numFrames,
DVFrameVars **frameVars, UInt8 **frames)
{
IOReturn err;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVReadAllocFrames begin\n");
#endif
err = DVAllocFrames(&globs->fStreamVars.fFrames,
numFrames,
globs->fStreamVars.fDVFrameSize,
frameVars,
frames);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVReadAllocFrames end\n");
#endif
return err;
}
static void doDVReadHandleInputUnderrun( DVGlobalInPtr pGlobalData )
{
UInt32 timeNow, lastFrameTime;
DVStream *stream;
int pingPongNum;
if ((pGlobalData->pendingDVReadUnderrunHandler == true) && (pGlobalData->deferredDVReadFree == true))
{
free(pGlobalData);
return;
}
pGlobalData->pendingDVReadUnderrunHandler = false;
stream = &pGlobalData->fStreamVars;
if (stream->fIsochChannelRef == NULL)
return;
(*stream->pFWDevice)->
GetCycleTime(stream->pFWDevice, &timeNow);
syslog(LOG_INFO, "At %8.3f Req time %8.3f, now %8.3f\n",
stream->fThread->setTimeoutTime, stream->fThread->requestTimeoutTime, CFAbsoluteTimeGetCurrent());
syslog(LOG_INFO, "DVReadHandleInputUnderrun: 0x%p, last block = %d, status %d, writer %d reader %d timeNow %x\n",
pGlobalData, pGlobalData->fState, stream->fFrames.fStatus,
stream->fFrames.fWriter, stream->fFrames.fReader, timeNow);
lastFrameTime = stream->fFrames.fFrameTime[(stream->fFrames.fWriter-1)%stream->fFrames.fNumFrames];
(*stream->fIsochChannelRef)->Stop(stream->fIsochChannelRef);
for (pingPongNum = 0; pingPongNum < kNumPingPongs; pingPongNum++)
{
if (pingPongNum < (kNumPingPongs-1))
ModifyDCLJump(pGlobalData->fStreamVars.pFWLocalIsochPort,
pGlobalData->fLocalDataArray[pingPongNum].fStateJmp, pGlobalData->fLocalDataArray[pingPongNum+1].fStateLabel);
else
ModifyDCLJump(pGlobalData->fStreamVars.pFWLocalIsochPort,
pGlobalData->fLocalDataArray[pingPongNum].fStateJmp, pGlobalData->fTerminal);
*pGlobalData->fLocalDataArray[pingPongNum].fTimeStampPtr = 0xffffffff;
}
pGlobalData->fState = 0;
pGlobalData->fSynced = 0;
pGlobalData->fRestarted = true;
pGlobalData->fLastFrameTime = lastFrameTime;
(*stream->fIsochChannelRef)->Start(stream->fIsochChannelRef);
}
static void DVReadHandleInputUnderrun( DCLCommandPtr pDCLCommandPtr )
{
DVGlobalInPtr pGlobalData;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVReadHandleInputUnderrun begin\n");
#endif
pGlobalData = (DVGlobalInPtr)((DCLCallProcPtr)pDCLCommandPtr)->procData;
if (pGlobalData->dvReadStopInProgress == false)
{
pGlobalData->pendingDVReadUnderrunHandler = true;
DVRequest(pGlobalData->fStreamVars.fThread, doDVReadHandleInputUnderrun, pGlobalData, 0);
}
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVReadHandleInputUnderrun end\n");
#endif
}
static void DVStorePackets(DVLocalInPtr pLocalData)
{
DVGlobalInPtr pGlobalData;
DCLCommandPtr pCurrentCmd;
DCLTransferPacketPtr pDCLTransferPacket;
UInt8 * pPacketBuffer;
UInt32 packetHeader, packetSize, packetNum, packetPerFrame;
bool vSyncDetected;
UInt8 currentSequenceCount;
int prevBlock;
UInt8 fn;
UInt8 stype;
UInt32 actualModeFrameSize;
short syncData;
UInt32 cipHeader;
#if TIMING
CFAbsoluteTime cstart, cend;
cstart = CFAbsoluteTimeGetCurrent();
#endif
pGlobalData = pLocalData->pGlobalData;
pCurrentCmd = pLocalData->fFirstCmd;
packetPerFrame = (pGlobalData->fStreamVars.fSignalMode & kAVCSignalModeMask_50) ?
kPALNumDataPacketsPerDVFrame : kNTSCNumDataPacketsPerDVFrame;
for ( packetNum = 0; packetNum < kNumPacketsPerInputBuffer; packetNum++ )
{
pDCLTransferPacket = (DCLTransferPacketPtr) pCurrentCmd;
pPacketBuffer = (UInt8*)pDCLTransferPacket->buffer;
packetHeader = *((UInt32*) pPacketBuffer);
pPacketBuffer += 4; packetSize = (packetHeader & kFWIsochDataLength) >> kFWIsochDataLengthPhase;
#if 1
fn = ((pPacketBuffer[2] & 0xC0) >> 6);
if (fn == 0)
fn = 1;
else
fn = 1 << fn;
if(packetSize < 8) {
syslog(LOG_INFO, "DVStorePackets: size %d header 0x%x\n", packetSize, packetHeader);
packetSize = 8;
}
else
{
if(packetSize > 8 && packetSize != (pPacketBuffer[1]*4*fn) + 8) {
syslog(LOG_INFO, "DVStorePackets: size %d header 0x%x\n", packetSize, packetHeader);
packetSize = 8;
}
cipHeader = *(UInt32 *)(pPacketBuffer+4);
cipHeader = EndianU32_BtoN( cipHeader );
if (pGlobalData->fStreamVars.fSignalMode != ((cipHeader >> 16) & 0xff))
{
if (((cipHeader >> 16) & 0xff) & kAVCSignalModeMask_50)
actualModeFrameSize = kPALNumDataPacketsPerDVFrame * (packetSize-8);
else
actualModeFrameSize = kNTSCNumDataPacketsPerDVFrame * (packetSize-8);
if (actualModeFrameSize > pGlobalData->fStreamVars.fDVFrameSize)
{
syslog(LOG_INFO, "DVStorePackets (received frame too large for frame-buffer): expected DV mode: %d, actual DV mode: %d\n",
pGlobalData->fStreamVars.fSignalMode, (cipHeader >> 16) & 0xff);
packetSize = 8;
}
}
}
#endif
if( packetSize > 8 ) {
currentSequenceCount = pPacketBuffer[3];
stype = pGlobalData->fStreamVars.fSignalMode & kAVCSignalModeMask_STYPE;
switch (stype)
{
case kAVCSignalModeMask_DVCPro50:
pGlobalData->lastSequenceCount += 2;
break;
case kAVCSignalModeMask_DVCPro100:
pGlobalData->lastSequenceCount += 4;
break;
case kAVCSignalModeMask_SDL:
case kAVCSignalModeMask_DVCPro25:
case kAVCSignalModeMask_HD:
default: pGlobalData->lastSequenceCount += 1;
break;
};
packetSize -= 8;
syncData = *(short *)(pPacketBuffer + 8); syncData = EndianS16_BtoN(syncData);
vSyncDetected = ((syncData & 0xE0F8 ) == 0x0000 );
if( vSyncDetected ) {
UInt32 frameEnd = SubtractFWCycleTimeFromFWCycleTime(*pLocalData->fTimeStampPtr, (kNumPacketsPerInputBuffer - packetNum) << 12);
UInt32 cip2 = *(UInt32 *)(pPacketBuffer+4);
cip2 = EndianU32_BtoN( cip2 );
pGlobalData->fStreamVars.fSignalMode = (cip2 >> 16) & 0xff;
packetPerFrame = (pGlobalData->fStreamVars.fSignalMode & kAVCSignalModeMask_50) ?
kPALNumDataPacketsPerDVFrame : kNTSCNumDataPacketsPerDVFrame;
if( pGlobalData->packetCount == packetPerFrame ) {
DVSetInputFrameSizeAndMode(&pGlobalData->fStreamVars.fFrames, packetPerFrame * packetSize,
pGlobalData->fStreamVars.fSignalMode, frameEnd);
}
else {
if(pGlobalData->fRestarted) {
UInt32 lastFrameTime;
SInt32 cycleDiff, secsDiff;
UInt32 dropped;
lastFrameTime = pGlobalData->fLastFrameTime;
cycleDiff = ((frameEnd & 0x01FFF000) - (lastFrameTime & 0x01FFF000));
if(cycleDiff < 0) {
cycleDiff += 8000 << 12;
frameEnd -= 0x02000000;
}
secsDiff = (frameEnd & 0x0e000000) - (lastFrameTime & 0x0e000000);
if(secsDiff < 0)
secsDiff += 0x10000000;
secsDiff >>= 25;
cycleDiff >>= 12;
cycleDiff += secsDiff * 8000;
if(pGlobalData->fStreamVars.fSignalMode & kAVCSignalModeMask_50)
dropped = (cycleDiff * kPALFrameRateNumerator + (4000*kPALFrameRateDenominator)) / (8000*kPALFrameRateDenominator);
else
dropped = (cycleDiff * kNTSCFrameRateNumerator + (4000*kNTSCFrameRateDenominator)) / (8000*kNTSCFrameRateDenominator);
pGlobalData->fStreamVars.fFrames.fDroppedFrames += dropped;
pGlobalData->fRestarted = false;
}
}
pGlobalData->packetCount = 0;
pGlobalData->lastSequenceCount = currentSequenceCount;
DVGetNextEmptyInputFrame(&pGlobalData->fStreamVars.fFrames,
&(pGlobalData->pImageBuffer),
pGlobalData->fStreamVars.fDVFrameSize);
pGlobalData->fSynced = true;
}
if(pGlobalData->fSynced) {
pPacketBuffer += 8;
if (currentSequenceCount == pGlobalData->lastSequenceCount && pGlobalData->packetCount < packetPerFrame) {
bcopy( pPacketBuffer, (void *)((UInt32) pGlobalData->pImageBuffer + (pGlobalData->packetCount * packetSize)), packetSize );
pGlobalData->packetCount++;
}
else {
pGlobalData->packetCount = 0;
pGlobalData->fSynced = false;
}
}
pGlobalData->lastSequenceCount = currentSequenceCount;
}
pCurrentCmd = pCurrentCmd->pNextDCLCommand;
}
pGlobalData->fState = pLocalData->fBlockNum;
if(pLocalData->fBlockNum == 0)
prevBlock = kNumPingPongs-1;
else
prevBlock = pLocalData->fBlockNum-1;
ModifyDCLJump(pGlobalData->fStreamVars.pFWLocalIsochPort,
pGlobalData->fLocalDataArray[prevBlock].fStateJmp, pLocalData->fStateLabel);
ModifyDCLJump(pGlobalData->fStreamVars.pFWLocalIsochPort, pLocalData->fStateJmp, pGlobalData->fTerminal);
#if TIMING
cend = CFAbsoluteTimeGetCurrent();
DVLog(pGlobalData->fStreamVars.fThread, 'isoc', cstart, cend);
#endif
}
void DVReadPoll(DVGlobalInPtr globs)
{
int i, pos;
pos = globs->fState;
for(i=pos; i<kNumPingPongs; i++)
if(*globs->fLocalDataArray[i].fTimeStampPtr != 0xffffffff) {
DVStorePackets(&globs->fLocalDataArray[i]);
*globs->fLocalDataArray[i].fTimeStampPtr = 0xffffffff;
}
for(i=0; i<pos; i++)
if(*globs->fLocalDataArray[i].fTimeStampPtr != 0xffffffff) {
DVStorePackets(&globs->fLocalDataArray[i]);
*globs->fLocalDataArray[i].fTimeStampPtr = 0xffffffff;
}
}
IOReturn DVReadStart(DVGlobalInPtr globs)
{
DCLCommandPtr opcodes;
UInt8 * pingPongBuffer = NULL;
UInt8 * pingPongPtr;
UInt8 * pDCLCommand;
DCLLabelPtr pStartDCLLabel;
DCLLabelPtr pBlockDCLLabel;
DCLLabelPtr pUnderrunDCLLabel;
DCLTransferPacketPtr pDCLTransferPacket;
DCLPtrTimeStampPtr pDCLTimeStamp;
DCLCallProcPtr pUnderrunDCLCallProc;
DCLJumpPtr pDCLPingPongLoop;
int pingPongNum, packetNum;
UInt32 updateListSize;
UInt32 bufferSize;
DCLUpdateDCLListPtr pDCLUpdateDCLList;
DCLCommandPtr *updateDCLList, *startUpdateDCLList;
DVLocalInPtr pLocalData;
IOReturn res;
UInt32 * timeStampPtr;
int i;
UInt32 packetBufferSize;
UInt32 alignedDVPacketSize;
UInt32 pingPongBufferSize;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVReadStart begin\n");
#endif
pingPongBuffer = NULL;
globs->fStreamVars.pDCLList = NULL;
globs->ppUpdateDCLList = NULL;
globs->pImageBuffer = NULL;
globs->fStreamVars.fDCLBuffers = NULL;
globs->packetCount = 0;
globs->fState = 0;
globs->pendingDVReadUnderrunHandler = false;
globs->deferredDVReadFree = false;
globs->dvReadStopInProgress = false;
switch (globs->fStreamVars.fSignalMode)
{
case kAVCSignalModeSDL525_60:
case kAVCSignalModeSDL625_50:
packetBufferSize = 252;
alignedDVPacketSize = 512;
break;
case kAVCSignalModeDVCPro50_525_60:
case kAVCSignalModeHD1125_60:
case kAVCSignalModeDVCPro50_625_50:
case kAVCSignalModeHD1250_50:
packetBufferSize = 972;
alignedDVPacketSize = 1024;
break;
case kAVCSignalModeDVCPro100_525_60:
case kAVCSignalModeDVCPro100_625_50:
packetBufferSize = 1932;
alignedDVPacketSize = 2048;
break;
case kAVCSignalModeSD525_60:
case kAVCSignalModeDVCPro525_60:
case kAVCSignalModeSD625_50:
case kAVCSignalModeDVCPro625_50:
default:
packetBufferSize = 492;
alignedDVPacketSize = 512;
break;
};
pingPongBufferSize = kNumPingPongs * kNumPacketsPerPingPong * alignedDVPacketSize;
bufferSize = pingPongBufferSize + alignedDVPacketSize + kNumPingPongs * sizeof(UInt32);
vm_allocate(mach_task_self(), (vm_address_t *)&pingPongBuffer,
bufferSize, VM_FLAGS_ANYWHERE);
if (pingPongBuffer == NULL)
{
res = kIOReturnNoMemory;
goto bail;
}
timeStampPtr = (UInt32 *)(pingPongBuffer + pingPongBufferSize + alignedDVPacketSize);
globs->fStreamVars.fDCLBuffers = pingPongBuffer;
globs->fStreamVars.fDCLBufferSize = bufferSize;
bzero( pingPongBuffer, bufferSize );
opcodes = (DCLCommandPtr)malloc(kRecordDCLProgramSize);
globs->fStreamVars.pDCLList = opcodes;
if (opcodes == NULL)
{
res = kIOReturnNoMemory;
goto bail;
}
bzero( opcodes, kRecordDCLProgramSize );
pDCLCommand = (UInt8 *)opcodes;
updateDCLList = (DCLCommandPtr *)malloc(kRecordNumDCLs * sizeof(DCLCommandPtr));
globs->ppUpdateDCLList = updateDCLList;
if (updateDCLList == NULL)
{
res = kIOReturnNoMemory;
goto bail;
}
bzero( updateDCLList, kRecordNumDCLs * sizeof(DCLCommandPtr));
pStartDCLLabel = (DCLLabelPtr) pDCLCommand;
pDCLCommand += sizeof (DCLLabel);
pStartDCLLabel->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
pStartDCLLabel->opcode = kDCLLabelOp;
pingPongPtr = pingPongBuffer;
for (pingPongNum = 0; pingPongNum < kNumPingPongs; pingPongNum++)
{
pLocalData = &globs->fLocalDataArray[pingPongNum];
pLocalData->pGlobalData = globs;
pLocalData->fBlockNum = pingPongNum;
pLocalData->fTimeStampPtr = timeStampPtr;
*timeStampPtr = 0xffffffff;
startUpdateDCLList = updateDCLList;
updateListSize = 0;
pBlockDCLLabel = (DCLLabelPtr) pDCLCommand;
pDCLCommand += sizeof (DCLLabel);
pBlockDCLLabel->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
pBlockDCLLabel->opcode = kDCLLabelOp;
pLocalData->fStateLabel = pBlockDCLLabel;
pLocalData->fFirstCmd = (DCLCommandPtr) pDCLCommand;
for (packetNum = 0; packetNum < kNumPacketsPerPingPong; packetNum++)
{
pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
pDCLCommand += sizeof (DCLTransferPacket);
pDCLTransferPacket->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
pDCLTransferPacket->opcode = kDCLReceivePacketStartOp;
pDCLTransferPacket->buffer = pingPongPtr;
pDCLTransferPacket->size = packetBufferSize;
*updateDCLList++ = (DCLCommandPtr) pDCLTransferPacket;
updateListSize++;
pingPongPtr += alignedDVPacketSize;
}
pDCLTimeStamp = (DCLPtrTimeStampPtr) pDCLCommand;
pDCLCommand += sizeof (DCLPtrTimeStamp);
pDCLTimeStamp->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
pDCLTimeStamp->opcode = kDCLPtrTimeStampOp;
pDCLTimeStamp->timeStampPtr = timeStampPtr++;
*updateDCLList++ = (DCLCommandPtr) pDCLTimeStamp;
updateListSize++;
pDCLUpdateDCLList = (DCLUpdateDCLListPtr) pDCLCommand;
pDCLCommand += sizeof (DCLUpdateDCLList);
pDCLUpdateDCLList->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
pDCLUpdateDCLList->opcode = kDCLUpdateDCLListOp;
pDCLUpdateDCLList->dclCommandList = startUpdateDCLList;
pDCLUpdateDCLList->numDCLCommands = updateListSize;
pDCLPingPongLoop = (DCLJumpPtr) pDCLCommand;
pDCLCommand += sizeof (DCLJump);
pDCLPingPongLoop->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
pDCLPingPongLoop->opcode = kDCLJumpOp | kFWDCLOpDynamicFlag;
pDCLPingPongLoop->pJumpDCLLabel = (DCLLabelPtr)pDCLCommand;
pLocalData->fStateJmp = pDCLPingPongLoop;
}
pUnderrunDCLLabel = (DCLLabelPtr) pDCLCommand;
pDCLCommand += sizeof (DCLLabel);
pUnderrunDCLLabel->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
pUnderrunDCLLabel->opcode = kDCLLabelOp;
globs->fTerminal = pUnderrunDCLLabel;
pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
pDCLCommand += sizeof (DCLTransferPacket);
pDCLTransferPacket->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
pDCLTransferPacket->opcode = kDCLReceivePacketStartOp;
pDCLTransferPacket->buffer = pingPongPtr;
pDCLTransferPacket->size = packetBufferSize;
pUnderrunDCLCallProc = (DCLCallProcPtr) pDCLCommand;
pDCLCommand += sizeof (DCLCallProc);
pUnderrunDCLCallProc->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
pUnderrunDCLCallProc->opcode = kDCLCallProcOp;
pUnderrunDCLCallProc->proc = DVReadHandleInputUnderrun;
pUnderrunDCLCallProc->procData = (UInt32)globs;
pUnderrunDCLLabel = (DCLLabelPtr) pDCLCommand;
pDCLCommand += sizeof (DCLLabel);
pUnderrunDCLLabel->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
pUnderrunDCLLabel->opcode = kDCLLabelOp;
pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
pDCLCommand += sizeof (DCLTransferPacket);
pDCLTransferPacket->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
pDCLTransferPacket->opcode = kDCLReceivePacketStartOp;
pDCLTransferPacket->buffer = pingPongPtr;
pDCLTransferPacket->size = packetBufferSize;
pDCLPingPongLoop = (DCLJumpPtr) pDCLCommand;
pDCLPingPongLoop->pNextDCLCommand = NULL;
pDCLPingPongLoop->opcode = kDCLJumpOp;
pDCLPingPongLoop->pJumpDCLLabel = pUnderrunDCLLabel;
res = openStream(&globs->fStreamVars, false, kDVSDPayloadPacketSize + kDVPacketCIPSize);
if(res != kIOReturnSuccess)
goto bail;
for(i=0; i<kDVMaxStreamsActive; i++) {
if(globs->fStreamVars.fThread->fInStreams[i] == NULL) {
globs->fStreamVars.fThread->fInStreams[i] = globs;
break;
}
}
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVReadStart end\n");
#endif
return kIOReturnSuccess;
bail:
syslog(LOG_INFO, "DVRead::Start() failed: 0x%x\n", res);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVReadStart end:bail\n");
#endif
return res;
}
static IOReturn doDVReadStop(DVGlobalInPtr pGlobalData)
{
int i;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: doDVReadStop begin\n");
#endif
pGlobalData->dvReadStopInProgress = true;
for(i=0; i<kDVMaxStreamsActive; i++) {
if(pGlobalData->fStreamVars.fThread->fInStreams[i] == pGlobalData) {
pGlobalData->fStreamVars.fThread->fInStreams[i] = NULL;
break;
}
}
#ifdef USE_P2P_CONNECTIONS_FOR_DV_READ
BreakP2PConnectionForRead(pGlobalData->fStreamVars.pDVDevice,0,pGlobalData->fStreamVars.fIsocChannel);
#endif
closeStream(&pGlobalData->fStreamVars);
if ( pGlobalData->ppUpdateDCLList) {
free( pGlobalData->ppUpdateDCLList); pGlobalData->ppUpdateDCLList = NULL;
}
if ( pGlobalData->fStreamVars.pDCLList) {
free( pGlobalData->fStreamVars.pDCLList); pGlobalData->fStreamVars.pDCLList = NULL;
}
if ( pGlobalData->fStreamVars.fDCLBuffers) {
vm_deallocate(mach_task_self(), (vm_address_t)pGlobalData->fStreamVars.fDCLBuffers,
pGlobalData->fStreamVars.fDCLBufferSize);
pGlobalData->fStreamVars.fDCLBuffers = NULL;
}
pGlobalData->dvReadStopInProgress = false;
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: doDVReadStop end\n");
#endif
return kIOReturnSuccess;
}
void DVReadStop(DVGlobalInPtr pGlobalData)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVReadStop begin\n");
#endif
DVRequest(pGlobalData->fStreamVars.fThread, doDVReadStop, pGlobalData, 0);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVReadStop end\n");
#endif
}
void DVReadFreeFrames(DVGlobalInPtr globs)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVReadFreeFrames begin\n");
#endif
DVFreeFrames(&globs->fStreamVars.fFrames);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVReadFreeFrames end\n");
#endif
}
void DVReadFree(DVGlobalInPtr globs)
{
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVReadFree begin\n");
#endif
if (globs->pendingDVReadUnderrunHandler == true)
globs->deferredDVReadFree = true;
else
free(globs);
#ifdef kIDH_Verbose_Debug_Logging
syslog(LOG_INFO, "DVLib: DVReadFree end\n");
#endif
}
void DVLog(DVThread *thread, UInt32 tag, CFAbsoluteTime start, CFAbsoluteTime end)
{
#if TIMING
Log * log;
log = &thread->fLog[thread->fLogPos];
log->tag = tag;
log->start = start;
log->end = end;
thread->fLogPos++;
if(thread->fLogPos >= kLogSize)
thread->fLogPos = 0;
#endif
}
void DVDumpLog(DVThread *thread)
{
#if TIMING
Log * log;
UInt32 tag;
int i;
for(i=thread->fLogPos; i<kLogSize; i++) {
log = &thread->fLog[i];
tag = log->tag;
if(tag) {
syslog(LOG_INFO, "%d %c%c%c%c %8.3f to %8.3f\n", i, tag>>24, tag>>16, tag>>8, tag, log->start, log->end);
}
else
syslog(LOG_INFO, "%d %x %8.3f to %8.3f\n", i, tag, log->start, log->end);
}
for(i=0; i< thread->fLogPos; i++) {
log = &thread->fLog[i];
tag = log->tag;
if(tag) {
syslog(LOG_INFO, "%d %c%c%c%c %8.3f to %8.3f\n", i, tag>>24, tag>>16, tag>>8, tag, log->start, log->end);
}
else
syslog(LOG_INFO, "%d %x %8.3f to %8.3f\n", i, tag, log->start, log->end);
}
#endif
}