📄 vidcap.c
字号:
/**
*** 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;
}
printf("___________ y\n");
}
}
//
// Set up video display
//
uiDisplayType = bUsePal ? VDIS_DISPLAYTYPE_625 : VDIS_DISPLAYTYPE_525;
// Open Vdis driver
err = EtiVdisOpen(&VdisHandle, ETI_OPENMODE_MODIFY, 0);
CHECK_RC(err, "EtiVdisOpen");
// Get default settings video display
VdisSettings.iVersion = ETI_DRIVER_VER;
err = EtiVdisDefault(VdisHandle, &VdisSettings, uiDisplayType,
iWidth, iHeight, 0, FALSE);
CHECK_RC(err, "EtiVdisDefault");
EtiUtilPrintVidBufInfo(&BufInfo);
// Add buffer as a surface
err = EtiVdisAddSurface(VdisHandle, &VdisSettings, VDIS_STREAM_V2,
&BufInfo, 0, 0, 0, 0, 100);
CHECK_RC(err, "EtiVdisAddSurface");
// If the reference clock is being used, the VCXO can be disabled
// with the following line:
// VdisSettings.bVcxoOff = TRUE;
// Open video display driver
err = EtiVdisSetup(VdisHandle, &VdisSettings);
CHECK_RC(err, "EtiVdisSetup");
// Allocate output buffers
pBufferBlockOut = calloc(NUM_BUF_OUT, ETI_MAX_FRAMESIZE);
if (!pBufferBlockOut) {
printf("Memory allocation failed\n");
exit(1);
}
// Queue up all but the last display buffer
pCurBufOut = pBufferBlockOut;
for (iBufCount = 0; iBufCount < NUM_BUF_OUT - 1; iBufCount++) {
err = EtiVdisBufferReady(VdisHandle, VDIS_STREAM_V2, pCurBufOut, NULL);
CHECK_RC(err, "EtiVdisBufferReady");
pCurBufOut += ETI_MAX_FRAMESIZE;
}
// Last buffer will be used by the first iteration of the loop
//
// Start video capture
//
for (iPortCount = 0; iPortCount < 2; iPortCount++) {
if (bUsePort[iPortCount]) {
err = EtiVcapKick(VcapHandle[iPortCount]);
CHECK_RC(err, "EtiVcapKick");
}
}
//
// Start display
//
err = EtiVdisKick(VdisHandle);
CHECK_RC(err, "EtiVdisKick");
return err;
}
//
// Processes a single buffer from capture side, passing it over to display
//
SCODE ProcessVidcapSingle (int iFrameCount)
{
SCODE err = ETIDRV_OK;
BOOL bBothChannels = bUsePort[0] && bUsePort[1];
int iPortCount;
static int iDisplayPort = 0;
for (iPortCount = 0; iPortCount < 2; iPortCount++) {
if (bUsePort[iPortCount]) {
printf("___________ 1\n");
// Get a video frame
err = EtiBufGetBuffer(BufHandleIn[iPortCount], (void **) &pCurBufIn,
NULL, BUF_INFINITE_WAIT);
CHECK_RC(err, "EtiBufGetBuffer");
err = CheckSync (iPortCount, iFrameCount);
CHECK_RC(err, "CheckSync");
// Process video frame here
if (!bBothChannels || iPortCount == iDisplayPort) {
memcpy(pCurBufOut, pCurBufIn, ETI_MAX_FRAMESIZE);
}
printf("___________ 2\n");
// Give the input buffer back to the capture driver
err = EtiBufBufferReady(BufHandleIn[iPortCount], pCurBufIn, NULL, 0);
CHECK_RC(err, "EtiBufBufferReady");
printf("___________ 3\n");
}
printf("___________ ok\n");
}
// Send the output buffer to the display driver
err = EtiVdisBufferReady(VdisHandle, VDIS_STREAM_V2, pCurBufOut, NULL);
CHECK_RC(err, "EtiVdisBufferReady");
// Get a new output buffer
err = EtiVdisGetBuffer(VdisHandle, VDIS_STREAM_V2, (void **) &pCurBufOut,
NULL, BUF_INFINITE_WAIT);
CHECK_RC(err, "EtiVdisGetBuffer");
// Check the video display FIFOs
err = EtiVdisCheckFifos(VdisHandle, TRUE);
if (ETIDRV_CHECK_NOT_OK(err)) {
printf("EtiVdisCheckFifos failed, error = 0x%08x\n", err);
}
if (iFrameCount % CHANNEL_SWITCH_PERIOD == 0) {
iDisplayPort ^= 1;
}
if ((iFrameCount & 0xffff) == 0xffff)
printf ("%d frames processed\n", iFrameCount);
}
//
// Frees all allocated resources
//
SCODE CloseVidcap (void)
{
SCODE err = ETIDRV_OK;
int iPortCount;
//
// Close all the drivers and free all memory
//
for (iPortCount = 0; iPortCount < 2; iPortCount++) {
if (bUsePort[iPortCount]) {
err = EtiVcapClose(VcapHandle[iPortCount]);
CHECK_RC(err, "EtiVcapClose");
VcapHandle[iPortCount] = NULL;
free(pBufferBlockIn[iPortCount]);
}
}
err = EtiVdisClose(VdisHandle);
CHECK_RC(err, "EtiVdisClose");
VdisHandle = NULL;
free(pBufferBlockOut);
//
// Check to make sure all memory that was allocated by the
// drivers was properly freed
//
EtiUtilListAllocatedMemory();
}
//
// Main processing function
//
SCODE ProcessVidcap(BOOL bUsePal, // Set to 0 to capture/display NTSC
BOOL bUsePort0, // Capture from video port 0
BOOL bUsePort1, // Capture from video port 1
int iFramesToCapture // Number of frames to capture (0=capture forever)
)
{
SCODE err = ETIDRV_OK;
int iFrameCount;
err = InitVidcap (bUsePal, bUsePort0, bUsePort1);
CHECK_RC (err, "InitVidcap");
//
// Loop the desired number of frames (0 = forever)
//
iFrameCount = 0;
while (iFramesToCapture == 0 ||
iFrameCount < iFramesToCapture) {
err = ProcessVidcapSingle (iFrameCount);
CHECK_RC (err, "ProcessVidcapSingle");
++iFrameCount;
}
err = CloseVidcap ();
CHECK_RC (err, "CloseVidcap");
return err;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -