This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

DM355 CMEMK dm350mmap Error

Other Parts Discussed in Thread: TVP5146

i don`t know this issue.

anyone help me.

 r7 = C004ED84  r6 = C0B1C5A0  r5 = 00000000  r4 = C5626000
[<c0053968>] (do_exit+0x0/0xda0) from [<c003b6a8>] (die+0x350/0x3a0)
[<c003b358>] (die+0x0/0x3a0) from [<c003dcec>] (__do_kernel_fault+0x6c/0x7c)
[<c003dc80>] (__do_kernel_fault+0x0/0x7c) from [<c003df88>] (do_page_fault+0x1d4/0x1ec)
 r7 = 00000000  r6 = C0B1C5A0  r5 = C56279DC  r4 = 00000017
[<c003ddb4>] (do_page_fault+0x0/0x1ec) from [<c003e0ec>] (do_DataAbort+0x40/0xa4)
[<c003e0ac>] (do_DataAbort+0x0/0xa4) from [<c0035728>] (__dabt_svc+0x48/0x60)
 r8 = 00000000  r7 = 00000000  r6 = C0B1C5A0  r5 = C56279DC
 r4 = FFFFFFFF
[<c004ed48>] (mm_release+0x0/0x80) from [<c0053a7c>] (do_exit+0x114/0xda0)
 r7 = C004ED84  r6 = C0B1C5A0  r5 = 00000000  r4 = C5626000
[<c0053968>] (do_exit+0x0/0xda0) from [<c003b6a8>] (die+0x350/0x3a0)
[<c003b358>] (die+0x0/0x3a0) from [<c003dcec>] (__do_kernel_fault+0x6c/0x7c)
[<c003dc80>] (__do_kernel_fault+0x0/0x7c) from [<c003df88>] (do_page_fault+0x1d4/0x1ec)
 r7 = 00000000  r6 = C0B1C5A0  r5 = C5627B0C  r4 = 00000017
[<c003ddb4>] (do_page_fault+0x0/0x1ec) from [<c003e0ec>] (do_DataAbort+0x40/0xa4)
[<c003e0ac>] (do_DataAbort+0x0/0xa4) from [<c0035728>] (__dabt_svc+0x48/0x60)
 r8 = 00000000  r7 = 00000000  r6 = C0B1C5A0  r5 = C5627B0C
 r4 = FFFFFFFF
[<c004ed48>] (mm_release+0x0/0x80) from [<c0053a7c>] (do_exit+0x114/0xda0)
 r7 = C004ED84  r6 = C0B1C5A0  r5 = 00000000  r4 = C5626000
[<c0053968>] (do_exit+0x0/0xda0) from [<c003b6a8>] (die+0x350/0x3a0)
[<c003b358>] (die+0x0/0x3a0) from [<c003dcec>] (__do_kernel_fault+0x6c/0x7c)
[<c003dc80>] (__do_kernel_fault+0x0/0x7c) from [<c003df88>] (do_page_fault+0x1d4/0x1ec)
 r7 = 00000000  r6 = C0B1C5A0  r5 = C5627C3C  r4 = 00000017
[<c003ddb4>] (do_page_fault+0x0/0x1ec) from [<c003e0ec>] (do_DataAbort+0x40/0xa4)
[<c003e0ac>] (do_DataAbort+0x0/0xa4) from [<c0035728>] (__dabt_svc+0x48/0x60)
 r8 = 00000000  r7 = 00000000  r6 = C0B1C5A0  r5 = C5627C3C
 r4 = FFFFFFFF
[<c004ed48>] (mm_release+0x0/0x80) from [<c0053a7c>] (do_exit+0x114/0xda0)
 r7 = C0087378  r6 = C0B1C5A0  r5 = 00000000  r4 = C5626000
[<c0053968>] (do_exit+0x0/0xda0) from [<c003b6a8>] (die+0x350/0x3a0)
[<c003b358>] (die+0x0/0x3a0) from [<c003dcec>] (__do_kernel_fault+0x6c/0x7c)
[<c003dc80>] (__do_kernel_fault+0x0/0x7c) from [<c003df88>] (do_page_fault+0x1d4/0x1ec)
 r7 = 00000000  r6 = C0B1C5A0  r5 = C5627D6C  r4 = 00000817
[<c003ddb4>] (do_page_fault+0x0/0x1ec) from [<c003e0ec>] (do_DataAbort+0x40/0xa4)
[<c003e0ac>] (do_DataAbort+0x0/0xa4) from [<c0035728>] (__dabt_svc+0x48/0x60)
 r8 = C513F178  r7 = 00004000  r6 = C03D0D20  r5 = C5627D6C
 r4 = FFFFFFFF
[<c0087330>] (page_remove_rmap+0x0/0x74) from [<c00803bc>] (unmap_vmas+0x3a0/0x550)
[<c008001c>] (unmap_vmas+0x0/0x550) from [<c0085330>] (exit_mmap+0x7c/0x178)
[<c00852b4>] (exit_mmap+0x0/0x178) from [<c004ec08>] (mmput+0x44/0x104)
 r7 = C5695D70  r6 = C0B1C5A0  r5 = C5695D40  r4 = C5695D40
[<c004ebc4>] (mmput+0x0/0x104) from [<c0053b74>] (do_exit+0x20c/0xda0)
 r4 = C5626000
[<c0053968>] (do_exit+0x0/0xda0) from [<c0054824>] (sys_exit_group+0x0/0x1c)
[<c0054744>] (do_group_exit+0x0/0xe0) from [<c005eaac>] (get_signal_to_deliver+0x51c/0x564)
 r5 = 0000000B  r4 = C5626000
[<c005e590>] (get_signal_to_deliver+0x0/0x564) from [<c0039ee0>] (do_signal+0x78/0x538)
[<c0039e68>] (do_signal+0x0/0x538) from [<c0035bac>] (work_pending+0x1c/0x24)
Code: ebfff9cd e5954114 e3540000 0a00000e (e5973024)
 <6>note: app[1001] exited with preempt_count 1
Unable to handle kernel NULL pointer dereference at virtual address 00000024
pgd = c0004000
[00000024] *pgd=00000000
Internal error: Oops: 17 [#23]
Modules linked in: dm350mmap cmemk
CPU: 0
PC is at mm_release+0x3c/0x80
LR is at do_exit+0x114/0xda0
pc : [<c004ed84>]    lr : [<c0053a7c>]    Not tainted
sp : c5626360  ip : c5626388  fp : c5626384
r10: 0000000b  r9 : 00000008  r8 : 00000000
r7 : 00000000  r6 : c0b1c5a0  r5 : c0b1c5a0  r4 : 40018520
r3 : ffffffea  r2 : c048fa60  r1 : 00000000  r0 : 00000000
Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  Segment user
Control: 5317F  Table: 80EF0000  DAC: 00000015
Process app (pid: 1001, stack limit = 0xc56261a0)
---------------------------------------------------------------------

 

//  ======== app.c ========
#include <xdc/std.h>
#include <ti/sdo/ce/Engine.h>
#include <ti/sdo/ce/osal/Memory.h>
//#include <ti/sdo/ce/image/imgdec.h>
//#include <ti/sdo/ce/image/imgenc.h>
#include <ti/sdo/ce/image1/imgenc1.h>
#include <ti/sdo/ce/trace/gt.h>

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <asm/types.h>
#include <linux/videodev2.h>
#include <linux/fb.h>
#include <signal.h>
#include <sys/time.h>
#include <time.h>
#include <sys/file.h>
#include <fcntl.h>

// Davinci specific kernel headers
#include <media/davinci/davinci_vpfe.h>
#include <media/davinci/tvp5146.h>
//#include <video/davincifb.h>


// ************************************************************************
// Defined Macros
// ************************************************************************

//#define DEBUG_PRINT // Enables or disables debug output
//#define TIMING

#ifdef DEBUG_PRINT
#define DBG(fmt, args...) fprintf(stderr, "Encode Debug: " fmt, ## args)
#else
#define DBG(fmt, args...)
#endif

// always print error message
#define ERR(fmt, args...) fprintf(stderr, "Encode Error: " fmt, ## args)

// video capture device
#define V4L2_DEVICE "/dev/video0"

// Black color in UYVY format
#define UYVY_BLACK               0x10801080

// Scaling factors for the video standards
#define NOSTD           0
#define PALSTD          12
#define NTSCSTD         10

#define NUM_BUFS 3

// Frame size information
int D1_WIDTH = 720;
int D1_HEIGHT = 480;
int D1_FRAME_PIXELS = 345600; // 720*480;
int D1_FRAME_SIZE = 691200; // 720*480*2

// ************************************************************************
// Defined Data Structures
// ************************************************************************
typedef struct {
  unsigned int numBufs;
  char *bufs[3];
  int bufSizes[3];
} BufferDesc;

// Describes a capture frame buffer
typedef struct VideoBuffer {
  void   *start;
  size_t  length;
} VideoBuffer;


// *************************************************************************
// Global variabls
// *************************************************************************

// engine name and codec name
static String encoderName  = "jpegenc";
static String engineName   = "image";

// buffer descriptor
BufferDesc inBufs;
BufferDesc outBufs;

// XDM buffer descriptor
XDM1_BufDesc             inBufDesc;
XDM1_BufDesc             outBufDesc;

// XDM input/output args
IMGENC1_InArgs           inArgs;
IMGENC1_OutArgs          outArgs;

// image parameters
IMGENC1_Params imgParams = {
  sizeof(IMGENC1_Params), // size
  480,             // maxHeight
  720,              // maxWidth
  3,                     // maxScans
  XDM_DEFAULT,             // dataEndianness
  XDM_YUV_422ILE           // forceChromaFormat
};

// image dynamic parameters
IMGENC1_DynamicParams dynParams = {
  sizeof(IMGENC1_DynamicParams),  // size
  0,                              // numAU
  XDM_YUV_422ILE,                 // inputChromaFormat                 
  480,                            // inputHeight
  720,                            // inputWidth
  0,                              // captureWidth
  XDM_ENCODE_AU,                  // generateHeader
  73                              // qValue
};

// status
IMGENC1_Status imgStatus;

// engine and codec handle
Engine_Handle ce;
IMGENC1_Handle enc;

// input/output files and file pointers
char outFile[] = "image1.jpg";
char outFile1[] = "image10.jpg";
char qFile[] = "Qfile";
FILE *outFp;
FILE *qFp;

// pointer to video capture buffer managerment structure
VideoBuffer *vidBufs;

// input capture device handler
int inputFd;
int numVidBufs;

#ifdef TIMING
struct timeval ts;
struct timeval te;
int numFramesToTiming = 1000;
#endif

// *************************************************************************
// Function declarations
// *************************************************************************

int initCaptureDevice( VideoBuffer **vidBufsPtr, int *numVidBufsPtr,
         int svideoInput, int captureWidth, int captureHeight);

void cleanupCaptureDevice(int fd, VideoBuffer *vidBufs, int numVidBufs);

void cleanup();

void INThandler( int sig );

// ======== smain ========
Int smain(Int argc, String argv[]) {
  int i,j, imgIdx;
#ifdef TIMING
  int numFrames = 0;
  double t1, t2;
#endif
  XDAS_Int32 status;
  struct v4l2_buffer v4l2buf;

  if ( argc > 1 && !strcmp(argv[1], "-PAL") ) {
    D1_HEIGHT = 576;
    D1_FRAME_PIXELS = 414720; // 720*576;
    D1_FRAME_SIZE = 829440; // 720*576*2
    imgParams.maxHeight = D1_HEIGHT;
    dynParams.inputHeight = D1_HEIGHT;
    DBG( "App-> Application started for PAL signal.\n");
  } else {
    DBG( "App-> Application started for NTSC signal.\n");
  }

  // init variables;
  ce = NULL;
  enc = NULL;
  imgStatus.size = sizeof(IMGENC1_Status);
  outFp = NULL;
  qFp = NULL;
  inArgs.size  = sizeof(IMGENC1_InArgs);
  outArgs.size = sizeof(IMGENC1_OutArgs);

  // out bufers
  outBufs.numBufs = outBufDesc.numBufs = 1;
  outBufs.bufs[0] = NULL;
  outBufs.bufSizes[0] = D1_FRAME_PIXELS*3;
  /*outBufDesc.bufSizes = outBufs.bufSizes;
  outBufDesc.bufs     = outBufs.bufs;
   */
    outBufDesc.descs[0].bufSize = (XDAS_Int32*)outBufs.bufSizes;
    outBufDesc.descs[0].buf = (XDAS_Int8**)outBufs.bufs;
  
  // init capture device
  inputFd = initCaptureDevice( &vidBufs, &numVidBufs, FALSE,
          D1_WIDTH, D1_HEIGHT );
  if (inputFd == -1) {
    goto end;
  }

  inBufs.numBufs = inBufDesc.numBufs = 1;
  inBufs.bufSizes[0] = D1_FRAME_PIXELS<<1;
  /*inBufDesc.bufSizes = inBufs.bufSizes;
  inBufDesc.bufs     = inBufs.bufs;
  */
    inBufDesc.descs[0].bufSize = (XDAS_Int32*)inBufs.bufSizes;
    inBufDesc.descs[0].buf = (XDAS_Int8**)inBufs.bufs;

  // allocate output buffer
  outBufs.bufs[0] = Memory_contigAlloc( outBufs.bufSizes[0],
            Memory_DEFAULTALIGNMENT );
  DBG("alloc outbuf 0x%x, %d\n", outBufs.bufs[0], outBufs.bufSizes[0] );
  if ( outBufs.bufs[0] == NULL ) {
    ERR("Failed to allocate contiguous memory block for output.\n");
    goto end;
  }

  // reset, load, and start DSP Engine
  ce = Engine_open(engineName, NULL, NULL );
  if ( ce == NULL ) {
    ERR("error: can't open engine %s\n", engineName);
    goto end;
  }

  // allocate and initialize image encoder on the engine
  enc = IMGENC1_create( ce, encoderName, &imgParams );
  if ( enc == NULL ) {
    ERR("error: can't open codec %s\n", encoderName);
    goto end;
  }

  status = IMGENC1_control( enc, XDM_SETPARAMS,
      (IMGENC1_DynamicParams*)(&dynParams),
      (IMGENC1_Status*)(&imgStatus) );
  if ( status == IALG_EFAIL ) {
    ERR("error: can't set dyn params 0x%x\n", (int)(imgStatus.extendedError) );
    goto end;
  }

  status = IMGENC1_control( enc, XDM_GETBUFINFO,
      (IMGENC1_DynamicParams*)(&dynParams),
      (IMGENC1_Status*)(&imgStatus) );
  if ( status != IMGENC1_EOK ) {
    ERR("error: can't get buf info 0x%x\n", (int)(imgStatus.extendedError) );
    goto end;
  }

  DBG( "min inBuf num: %d\n", imgStatus.bufInfo.minNumInBufs );
  for ( j = 0; j < imgStatus.bufInfo.minNumInBufs; j++ ) {
    DBG( "inBuf[%d] size %d\n", j, imgStatus.bufInfo.minInBufSize[j] );  
  }

  DBG( "min outBuf num: %d\n", imgStatus.bufInfo.minNumOutBufs );
  for ( j = 0; j < imgStatus.bufInfo.minNumOutBufs; j++ ) {
    DBG( "outBuf[%d] size %d\n", j, imgStatus.bufInfo.minOutBufSize[j] );  
  }

  // ctrlC will terminate and clean up
  signal( SIGINT, INThandler );

  i = 0;
  imgIdx = 1;

#ifdef TIMING
  gettimeofday( &ts, NULL );
#endif

  while ( 1 ) {
    DBG("process frame %d\n", i++ );

    // open file streams for output
    if ( imgIdx >= 10 ) {
      j = imgIdx/10;
      outFile1[5] = '0'+j;
      outFile1[6] = '0'+ imgIdx-j*10;
      if ( (outFp = fopen(outFile1, "wb") ) == NULL) {
 ERR( "App-> : can't write to file %s\n", outFile1 );
 goto end;
      }
    }else {
      outFile[5] = '0'+imgIdx;
      if ( (outFp = fopen(outFile, "wb") ) == NULL) {
 ERR( "App-> ERROR: can't write to file %s\n", outFile );
 goto end;
      }
    }
    imgIdx++;
    if ( D1_HEIGHT == 480 ) {
      if ( imgIdx > 30 ) {
 imgIdx = 1;
 qFp = fopen( qFile, "rb" );
 if ( qFp ) {
   status = fread( &j, 1, 1, qFp );
   if ( status == 1 && j > 1 && j <= 100 )
     dynParams.qValue = j;
   fclose(qFp);
   qFp = 0;
 }
      }
    } else {
      if ( imgIdx > 25 ) {
 imgIdx = 1;
 qFp = fopen( qFile, "rb" );
 if ( qFp ) {
   status = fread( &j, 1, 1, qFp );
   if ( status == 1 && j > 1 && j <= 100 )
     dynParams.qValue = j;
   fclose(qFp);
   qFp = 0;
 }
      }
    }

    // lock the file
    do {
      j = lockf( fileno(outFp), F_LOCK, 0 );
      if ( !j )
 break;
      sleep ( 1 );
    } while ( 1 );

    // Get a frame buffer with captured data
    memset( &v4l2buf, 0, sizeof(v4l2buf) );
    v4l2buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    v4l2buf.memory = V4L2_MEMORY_MMAP;
    if ( ioctl(inputFd, VIDIOC_DQBUF, &v4l2buf) == -1 ) {
      if (errno == EAGAIN) {
 continue;
      }

      ERR("VIDIOC_DQBUF failed (%s)\n", strerror(errno) );
      goto end;
    }
    inBufs.bufs[0] = vidBufs[v4l2buf.index].start;

    // Encode
    status = IMGENC1_process( enc, &inBufDesc, &outBufDesc, &inArgs, &outArgs);
    if ( status != IMGENC1_EOK ) {
      ERR( "IMGENC_process() failed with a fatal error (%ld ext: %#lx\n",
    status, outArgs.extendedError);
      goto end;
    }

    // Issue captured frame buffer back to device driver
    if (ioctl(inputFd, VIDIOC_QBUF, &v4l2buf) == -1) {
      ERR("VIDIOC_QBUF failed (%s)\n", strerror(errno));
      goto end;
    }

    DBG( "%d bytes generated\n", outArgs.bytesGenerated );
    status = fwrite( outBufs.bufs[0], 1, outArgs.bytesGenerated, outFp );
    fclose( outFp );
    outFp = 0;

    status = IMGENC1_control( enc, XDM_SETPARAMS,
        (IMGENC1_DynamicParams*)(&dynParams),
        (IMGENC1_Status*)(&imgStatus) );
    if ( status == IALG_EFAIL ) {
      ERR("error: can't set dyn params 0x%x\n", (int)(imgStatus.extendedError) );
      goto end;
    }

    // usleep( 5000 );

#ifdef TIMING
    numFrames++;
    if ( numFrames >= numFramesToTiming ) {
      gettimeofday( &te, NULL );
      printf("%d frames encoded\n", numFramesToTiming );
      t1 = ts.tv_sec*1000.0 + (ts.tv_usec/1000.0);
      t2 = te.tv_sec*1000.0 + (te.tv_usec/1000.0);
      t2 -= t1;
      printf("Total time: %.3f ms, Average: %.3fms\n",
      t2, t2/numFramesToTiming );
      cleanup();
      break;
    }
#endif
  }

 end:

  return (0);
}

void cleanup() {

  // teardown the codecs
  if (enc) {
    DBG("delete encode\n");
    IMGENC1_delete(enc);
  }
 
  // close the engine
  if (ce) {
    DBG("delete engine\n");
    Engine_close(ce);
  }
 
  // close the files
  if ( outFp ) {
    DBG("close outfp\n" );
    fclose(outFp);
  }
  if ( qFp ) {
    DBG("close qFp\n");
    fclose( qFp );
  }

  if ( outBufs.bufs[0] ) {
    DBG("free outbuf 0x%x, %d\n", outBufs.bufs[0], outBufs.bufSizes[0] );
    Memory_contigFree( outBufs.bufs[0], outBufs.bufSizes[0] );
  }

  if ( inputFd != -1 ) {
    DBG("clean capture device\n");
    cleanupCaptureDevice(inputFd, vidBufs, numVidBufs );
  }

  DBG("app done.\n");
}

void INThandler( int sig ) {
  cleanup();
  exit(0);
}

// initCaptureDevice
int initCaptureDevice( VideoBuffer **vidBufsPtr, int *numVidBufsPtr,
         int svideoInput, int captureWidth, int captureHeight) {
  struct v4l2_requestbuffers  req;
  struct v4l2_capability      cap;
  struct v4l2_cropcap         cropCap;
  struct v4l2_crop            crop;
  struct v4l2_format          fmt;
  struct v4l2_buffer          buf;
  enum v4l2_buf_type          type;
  v4l2_std_id                 std;
  int                         input;
  int                         fd;
  int                         ret;
  VideoBuffer                *buffers;
  int                         numBufs;

  DBG("captureWidth = %d, captureHeight = %d\n", captureWidth, captureHeight);

  // Open video capture device
  fd = open(V4L2_DEVICE, O_RDWR | O_NONBLOCK, 0);
 
  if (fd == -1) {
    ERR("Cannot open %s (%s)\n", V4L2_DEVICE, strerror(errno));
    return -1;
  }

  // Select the video input
  if (svideoInput == TRUE) {
    input = TVP5146_AMUX_SVIDEO;
  } else {
    input = TVP5146_AMUX_COMPOSITE;
  }

  if (ioctl(fd, VIDIOC_S_INPUT, &input) == -1) {
    ERR("Failed to set video input to %d\n", input);
    return -1;
  }

  DBG("Set the capture input to id %d\n", input);

  // Query for capture device capabilities
  if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) {
    if (errno == EINVAL) {
      ERR("%s is no V4L2 device\n", V4L2_DEVICE);
      return -1;
    }
    ERR("Failed VIDIOC_QUERYCAP on %s (%s)\n", V4L2_DEVICE,
    strerror(errno));
    return -1;
  }

  if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
    ERR("%s is no video capture device\n", V4L2_DEVICE);
    return -1;
  }

  if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
    ERR("%s does not support streaming i/o\n", V4L2_DEVICE);
    return -1;
  }

  cropCap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  if (ioctl(fd, VIDIOC_CROPCAP, &cropCap) == -1) {
    ERR("VIDIOC_CROPCAP failed %d, %s\n", errno, strerror(errno));
    return -1;
  }

  // Auto detect PAL or NTSC using the capture driver as sanity check
  std = VPFE_STD_AUTO;
  if(ioctl(fd, VIDIOC_S_STD, &std) == -1) {
    ERR( "VIDIOC_S_STD (auto) failed on %s (%s)\n", V4L2_DEVICE,
  strerror(errno));
    return -1;
  }

  DBG("Checking video standard\n");

  do {
    ret = ioctl(fd, VIDIOC_QUERYSTD, &std);
  } while (ret == -1 && errno == EAGAIN);

  if (ret == -1) {
    ERR("VIDIOC_QUERYSTD failed on %s (%s)\n", V4L2_DEVICE,
 strerror(errno));
    return -1;
  }

  switch (std) {
  case V4L2_STD_NTSC:
    DBG("NTSC camera detected\n");
    if ( captureHeight == 576 ) {
      ERR("NTSC camera connected but PAL selected.\n");
      return -1;
    }
    break;
  case V4L2_STD_PAL:
    DBG("PAL camera detected\n");
    if ( captureHeight == 480 ) {
      ERR("PAL camera connected but NTSC selected.\n");
      return -1;
    }
    break;
  default:
    ERR("Camera (%s) using unsupported video standard\n", V4L2_DEVICE);
    return -1;
  }

  if(ioctl(fd, VIDIOC_S_STD, &std) == -1) {
    ERR("VIDIOC_S_STD failed on %s (%s)\n", V4L2_DEVICE,
 strerror(errno));
    return -1;
  }

  // Set the video capture image format
  memset ( &fmt, 0, sizeof(fmt) );
  fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  fmt.fmt.pix.width       = D1_WIDTH;
  fmt.fmt.pix.height      = D1_HEIGHT;
  fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
  fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
 
  DBG("Setting capture video format\n");

  // Set the video capture format
  if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) {
    ERR("VIDIOC_S_FMT failed on %s (%s)\n", V4L2_DEVICE,
 strerror(errno));
    return -1;
  }

  crop.type     = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  crop.c.left   = D1_WIDTH / 2 - captureWidth / 2;
  crop.c.top    = D1_HEIGHT / 2 - captureHeight / 2;
  crop.c.width  = captureWidth;
  crop.c.height = captureHeight;

  DBG("Setting capture cropping (%dx%d)\n", crop.c.width, crop.c.height);

  // Crop the image depending on requested image size
  if (ioctl(fd, VIDIOC_S_CROP, &crop) == -1) {
    ERR("VIDIOC_S_CROP failed %d, %s\n", errno, strerror(errno));
    return -1;
  }

  DBG( "Capturing %dx%d video (cropped to %dx%d)\n",
       fmt.fmt.pix.width, fmt.fmt.pix.height, crop.c.width, crop.c.height);

  memset( &req, 0, sizeof(req) );
  req.count  = NUM_BUFS;
  req.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  req.memory = V4L2_MEMORY_MMAP;
 
  // Allocate buffers in the capture device driver
  if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
    ERR("VIDIOC_REQBUFS failed on %s (%s)\n", V4L2_DEVICE,
 strerror(errno));
    return -1;
  }

  DBG("%d capture buffers were successfully allocated.\n", req.count);

  if (req.count < NUM_BUFS) {
    ERR("Insufficient buffer memory on %s\n", V4L2_DEVICE);
    return -1;
  }

  buffers = calloc( req.count, sizeof(*buffers) );

  if (!buffers) {
    ERR("Failed to allocate memory for capture buffer structs.\n");
    return -1;
  }

  // Map the allocated buffers to user space
  for (numBufs = 0; numBufs < req.count; numBufs++) {
    memset( &buf, 0, sizeof(buf) );
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = numBufs;
   
    if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) {
      ERR("Failed VIDIOC_QUERYBUF on %s (%s)\n", V4L2_DEVICE,
   strerror(errno));
      return -1;
    }

    buffers[numBufs].length = buf.length;
    buffers[numBufs].start = mmap(NULL, buf.length,
      PROT_READ | PROT_WRITE,
      MAP_SHARED,
      fd, buf.m.offset);
   
    if (buffers[numBufs].start == MAP_FAILED) {
      ERR("Failed to mmap buffer on %s (%s)\n", V4L2_DEVICE,
   strerror(errno));
      return -1;
    }

    DBG("Capture buffer %d mapped to address %#lx\n", numBufs,
 (unsigned long) buffers[numBufs].start);

    if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) {
      ERR("VIODIOC_QBUF failed on %s (%s)\n", V4L2_DEVICE,
   strerror(errno));
      return -1;
    }
  }

  // Start the video streaming
  type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
  if (ioctl(fd, VIDIOC_STREAMON, &type) == -1) {
    ERR("VIDIOC_STREAMON failed on %s (%s)\n", V4L2_DEVICE,
 strerror(errno));
    return -1;
  }

  *vidBufsPtr = buffers;
  *numVidBufsPtr = numBufs;
 
  return fd;
}


// cleanupCaptureDevice
void cleanupCaptureDevice(int fd, VideoBuffer *vidBufs, int numVidBufs) {
  enum v4l2_buf_type type;
  unsigned int       i;
   
  // Shut off the video capture
  type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  if (ioctl(fd, VIDIOC_STREAMOFF, &type) == -1) {
    ERR("VIDIOC_STREAMOFF failed (%s)\n", strerror(errno));
  }
 
  if (close(fd) == -1) {
    ERR("Failed to close capture device (%s)\n", strerror(errno));
  }

  for (i = 0; i < numVidBufs; ++i) {
    if (munmap(vidBufs[i].start, vidBufs[i].length) == -1) {
      ERR("Failed to unmap capture buffer %d\n", i);
    }
  }
 
  free(vidBufs);
}