/**
*** Copyright (c) 2001-2002 Equator Technologies, Inc.
**/
/************************************************************************
***
*** FILENAME: vidcap.c
***
*** DESCRIPTION:
*** Test application for video capture and display.
***
*** This application captures and displays PAL or NTSC video.
***
*** Note: The Shark board only has one video input path.
***
************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <eti/drv.h>
#include "vidcap.h"
// Constants
#define NUM_BUF_IN 4
#define NUM_BUF_OUT 4
#define CHANNEL_SWITCH_PERIOD 150 // in frames
#define USE_VCXO 0 // define if VCXO usage is preferred to fixed clock
// Macro for checking a driver return code
#define CHECK_RC(rc, fnname) \
if (ETIDRV_CHECK_ERROR(rc)) { \
printf(fnname ## " failed, error = 0x%08x\n", rc); \
exit(1); \
}
typedef enum {
SYNC_STATE_OK,
SYNC_STATE_VIN_HALTED,
SYNC_STATE_LOST,
SYNC_STATE_SIZEOF
} SyncState;
// Static variables
static DrvHandle VdisHandle = NULL;
static DrvHandle BufHandleIn[2] = { NULL, NULL };
static DrvHandle VcapHandle[2] = { NULL, NULL };
static DrvHandle VinHandle[2] = { NULL, NULL };
// Turns each source on or off. This value is set by a command line argument.
static BOOL bUsePort[2] = { TRUE, FALSE };
static SyncState SyncLost[2] = { SYNC_STATE_OK, SYNC_STATE_OK };
static UINT8 *pBufferBlockOut = NULL;
static UINT8 *pBufferBlockIn[2] = { NULL, NULL };
static UINT8 *pCurBufIn = NULL;
static UINT8 *pCurBufOut = NULL;
// Functions
static void RestartCallback (void *pArg)
{
int portNum = pArg ? 1 : 0;
//
// do as little as possible in the interrupt handler for end
// of frame. Halt the video in to avoid any overflows, and do
// the rest in CheckSync later.
//
if (SyncLost[portNum] == SYNC_STATE_LOST)
{
EtiVinHalt(VinHandle[portNum]);
SyncLost[portNum] = SYNC_STATE_VIN_HALTED;
}
}
//
// This code checks to see if sync has been lost, and restarts
// video capture.
//
static SCODE CheckSync (int iPortCount, int iFrameCount)
{
SCODE err = ETIDRV_OK;
VIN_STATUS VinStatus;
if (SyncLost[iPortCount] == SYNC_STATE_VIN_HALTED) {
//
// If sync was lost on the previous frame, restart video capture.
//
printf("Sync lost on frame %d... restarting Vin and continuing DS\n", iFrameCount);
err = EtiBufInvalidateDsBuffer(BufHandleIn[iPortCount]);
CHECK_RC(err, "EtiBufInvalidateDsBuffer");
err = EtiBufContinue(BufHandleIn[iPortCount]);
CHECK_RC(err, "EtiBufContinue");
err = EtiVinKick(VinHandle[iPortCount]);
CHECK_RC(err, "EtiVinKick");
SyncLost[iPortCount] = SYNC_STATE_OK;
}
else if (SyncLost[iPortCount] == SYNC_STATE_OK) {
//
// If sync wasn't lost on the previous frame, see if
// it was lost on this frame
//
// Check the state of the "LessLine" field of Vin status
err = EtiVinGetStatus(VinHandle[iPortCount], &VinStatus, TRUE);
CHECK_RC(err, "EtiVinGetStatus");
// If sync was lost, halt the DS at the end of the next transfer so that it
// stops on a clean buffer boundary. Restart capture in the next loop.
if (VinStatus.bLessLine) {
printf("Lessline on frame %d... halting DS\n", iFrameCount);
SyncLost[iPortCount] = SYNC_STATE_LOST;
err = EtiBufPause(BufHandleIn[iPortCount]);
CHECK_RC(err, "EtiBufPause");
}
}
return err;
}
//
// Vidcap initialization, allocation of all buffers, media drivers resources,
// etc.
//
SCODE InitVidcap (BOOL bUsePal, BOOL bUsePort0, BOOL bUsePort1)
{
SCODE err = ETIDRV_OK;
DrvHandle BoardHandle = NULL;
BOARD_COMMAND BoardCommand;
VCAP_SETTINGS VcapSettings;
VDIS_SETTINGS VdisSettings;
UINT32 uiDisplayType = 0;
int iPortCount;
int iBufCount;
ETI_VIDBUFINFO BufInfo;
int iWidth, iHeight;
err = EtiDriverInit();
// CHECK_RC(err, "EtiDriverInit");
bUsePort[0] = bUsePort0;
bUsePort[1] = bUsePort1;
err = EtiBoardOpen(&BoardHandle, ETI_OPENMODE_MODIFY, 0);
// CHECK_RC(err, "EtiBoardOpen");
#if USE_VCXO
// This command will cause the Stingray or Dolphin to use the
// VCXO rather than the fixed reference clock
err = EtiBoardCommand(BoardHandle, COMMAND_VCXO_CLOCK, 0);
// CHECK_RC(err, "EtiBoardCommand");
#endif
if (bUsePal) {
// Set board chips for PAL input and output
err = EtiBoardCommand(BoardHandle, COMMAND_PAL_VID_INPUT, 0);
// CHECK_RC(err, "EtiBoardCommand");
err = EtiBoardCommand(BoardHandle, COMMAND_PAL_VID_INPUT, 1);
//CHECK_RC(err, "EtiBoardCommand");
err = EtiBoardCommand(BoardHandle, COMMAND_PAL_VID_OUTPUT, 0);
// CHECK_RC(err, "EtiBoardCommand");
}
// See if alternate video input was selected
for (iPortCount = 0; iPortCount < 2; iPortCount++) {
if (bUsePort[iPortCount] > 1) {
switch (bUsePort[iPortCount]) {
case 2:
BoardCommand = COMMAND_COMP1_VID_INPUT;
break;
case 3:
BoardCommand = COMMAND_COMP2_VID_INPUT;
break;
default:
printf("Error: bUsePort is to large\n");
exit(1);
}
err = EtiBoardCommand(BoardHandle, BoardCommand, iPortCount);
//CHECK_RC(err, "EtiBoardCommand");
}
}
err = EtiBoardClose(BoardHandle);
//CHECK_RC(err, "EtiBoardClose");
BoardHandle = NULL;
//
// Set up the drivers and buffers for each input port requested
//
for (iPortCount = 0; iPortCount < 2; iPortCount++) {
if (bUsePort[iPortCount]) {
// Open Vcap driver
err = EtiVcapOpen(&(VcapHandle[iPortCount]), ETI_OPENMODE_MODIFY, iPortCount);
CHECK_RC(err, "EtiVcapOpen");
// Get default settings
VcapSettings.iVersion = ETI_DRIVER_VER;
err = EtiVcapDefault(VcapHandle[iPortCount], &VcapSettings, bUsePal);
CHECK_RC(err, "EtiVcapDefault");
// Store values from video capture for use in video display functions
BufInfo = VcapSettings.BufInfo;
iWidth = BufInfo.u.LayoutOffsets.iYWidth;
iHeight = BufInfo.u.LayoutOffsets.iYHeight;
printf("Image size is %d x %d\n", iWidth, iHeight);
// Open video capture
VcapSettings.BufSettings.pEobCallback = RestartCallback;
VcapSettings.BufSettings.pEobData = (void *) iPortCount;
err = EtiVcapSetup(VcapHandle[iPortCount], &VcapSettings);
CHECK_RC(err, "EtiVcapSetup");
BufHandleIn[iPortCount] = EtiVcapGetBufHandle(VcapHandle[iPortCount]);
VinHandle[iPortCount] = EtiVcapGetVinHandle(VcapHandle[iPortCount]);
// Allocate buffers
pBufferBlockIn[iPortCount] = malloc(NUM_BUF_IN * ETI_MAX_FRAMESIZE);
if (!pBufferBlockIn[iPortCount]) {
printf("Memory allocation failed\n");
exit(1);
}
printf("Buffers located at 0x%08x\n", pBufferBlockIn[iPortCount]);
// Queue up the buffers
pCurBufIn = pBufferBlockIn[iPortCount];
printf("___________ x\n");
for (iBufCount = 0; iBufCount < NUM_BUF_IN; iBufCount++) {
err = EtiBufBufferReady(BufHandleIn[iPortCount], pCurBufIn, NULL, 0);
CHECK_RC(err, "EtiBufBufferReady");
pCurBufIn += ETI_MAX_FRAMESIZE;