LINUX MPEG4 DVR源代码

这是一个简单的,但却是相当完整的DVR的source code:LINUX MPEG4 DVR源代码。此中只有视频,没有音频,落鹤生推荐大家好好看看。此代码可用以下命令编译:gcc -o linux_dvr linux_dvr.c -lxvidcore。有问题可以来论坛(http://bbs.rosoo.net)讨论。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/videodev.h>
#include "xvid.h"
#define FRAMERATE_INCR 1001
#define SMALL_EPS (1e-10)
#define VIDEO "/dev/video"
#define INDEX 0
#define IOCTL(fd, req, addr ) \
((-1==ioctl(fd,req,addr))?(perror(#req),close(fd),exit(EXIT_FAILURE)):0)

static float ARG_FRAMERATE = 25.00f;
static int ARG_QUALITY = 4;
static int ARG_MAXKEYINTERVAL = 250;
static char * ARG_OUTPUTFILE= "out.m4u";
static FILE * fp = NULL;
static int done = 0;
static const int motion_presets[] = {
    /* quality 0 */
    0,

    /* quality 1 */
    XVID_ME_ADVANCEDDIAMOND16,

    /* quality 2 */
    XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16,

    /* quality 3 */
    XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 |
    XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8,

    /* quality 4 */
    XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 |
    XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8 |
    XVID_ME_CHROMA_PVOP | XVID_ME_CHROMA_BVOP,

    /* quality 5 */
    XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 |
    XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8 |
    XVID_ME_CHROMA_PVOP | XVID_ME_CHROMA_BVOP,

    /* quality 6 */
    XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 | XVID_ME_EXTSEARCH16 |
    XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8 | XVID_ME_EXTSEARCH8 |
    XVID_ME_CHROMA_PVOP | XVID_ME_CHROMA_BVOP,

};
static const int vop_presets[] = {
    /* quality 0 */
    0,

    /* quality 1 */
    0,

    /* quality 2 */
    XVID_VOP_HALFPEL,

    /* quality 3 */
    XVID_VOP_HALFPEL | XVID_VOP_INTER4V,

    /* quality 4 */
    XVID_VOP_HALFPEL | XVID_VOP_INTER4V,

    /* quality 5 */
    XVID_VOP_HALFPEL | XVID_VOP_INTER4V |
    XVID_VOP_TRELLISQUANT,

    /* quality 6 */
    XVID_VOP_HALFPEL | XVID_VOP_INTER4V |
    XVID_VOP_TRELLISQUANT | XVID_VOP_HQACPRED,

};

static int XDIM=352,YDIM=288;
static use_assembler = 0;
static void *enc_handle = NULL;

static int enc_init(int use_assembler);
static int enc_main(unsigned char *image,
                    unsigned char *bitstream,
                    int *key,
                    int *stats_type,
                    int *stats_quant,
                    int *stats_length,
                    int stats[3]);
static int enc_stop();
//signal act method defination
static void clean(int signum)
{
    done=1;
}
int
main(int argc,char *argv[])
{
    //register SIGINT action method ,to save the m4u file
    signal(SIGINT,clean);
    int fd;
    struct v4l2_capability cap;   
    struct v4l2_format format;
    struct v4l2_requestbuffers reqbuf;
    struct v4l2_buffer buffer;
    struct v4l2_input input;
    int index=0,i;
    for (i=1; i< argc; i++) {

        if (strcmp("-asm", argv[i]) == 0 ) {
            use_assembler = 1;
        }else if(strcmp("-f", argv[i]) == 0 && i < argc -1){
            i++;
            ARG_OUTPUTFILE = argv[i];
        }else if(strcmp("-i", argv[i]) == 0 && i < argc -1){
            i++;
            index = atoi(argv[i]);
        } else if(strcmp("-w", argv[i]) == 0 && i < argc -1){
            i++;
            XDIM = atoi(argv[i]);
        } else if(strcmp("-h", argv[i]) == 0 && i < argc -1){
            i++;
            YDIM = atoi(argv[i]);
        }
    }
   
    //init capture card
   
    fd = open(VIDEO,O_RDWR);
    if(fd<0)
    {
        perror("Can't open /dev/video device");
        exit(errno);
    }
    //if card can't support video capture and by means of steamio,exit
   
    IOCTL(fd, VIDIOC_QUERYCAP, &cap);
    if ( !(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
         &&!(cap.capabilities & V4L2_CAP_STREAMING))
    {
        fprintf(stderr, "Couldn't use the card \n");
        exit(3);
    }       
   
    //query input and select the desired input
   
    IOCTL(fd, VIDIOC_G_INPUT, &index);
    input.index = index;
    IOCTL(fd, VIDIOC_ENUMINPUT, &input);
    printf ("Current input: Index %i,Name %s\n", index,input.name);   
    for(i=0;;i++)
    {
        if(i!=index)
        {
            input.index = i;
            if(-1==ioctl(fd, VIDIOC_ENUMINPUT, &input))
                break;
            else
                printf ("Other input: Index %i,Name %s\n",i,input.name);
        }
    }
    IOCTL(fd, VIDIOC_S_INPUT, &index);
   
    //get current video format,set the desired format
   
    format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    IOCTL(fd,VIDIOC_G_FMT,&format);
    format.fmt.pix.width = XDIM;
    format.fmt.pix.height = YDIM;
    format.fmt.pix.pixelformat = V4L2_PIX_FMT_YVU420;
    format.fmt.pix.field = V4L2_FIELD_ANY;//V4L2_FIELD_INTERLACED
   
    IOCTL(fd,VIDIOC_S_FMT,&format);

    XDIM = format.fmt.pix.width;
    printf("Gotten width %d\n",XDIM);
    YDIM = format.fmt.pix.height;
    printf("Gotten height %d\n",YDIM);
   
    //let driver get the buffers
   
    reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    reqbuf.memory = V4L2_MEMORY_MMAP;
    reqbuf.count = 4;
    IOCTL(fd,VIDIOC_REQBUFS,&reqbuf );
    if (reqbuf.count < 4)
    {
       printf ("Not enough buffer memory for driver\n");
       exit (5);
    }

//mmap the driver's buffer to application address
   
    //create relative buffers struct to be used by mmap

    struct
    {
        void * start;
        size_t length;
    } buffers[reqbuf.count];
   
    //mmap the driver's kernel buffer into application
   
    for (i=0;i<reqbuf.count;i++)
    {
        buffer.type = reqbuf.type;
        buffer.index =i ;
       
        //query the status of one buffer ,mmap the driver buffer
       
        IOCTL(fd,VIDIOC_QUERYBUF,&buffer);
        buffers[i].length = buffer.length;
        buffers[i].start = mmap (NULL,buffer.length,
                                 PROT_READ | PROT_WRITE,
                                 MAP_SHARED,
                                 fd,buffer.m.offset);
        if (buffers[i].start == MAP_FAILED)
        {
           close(fd);
           perror ("mmap");
           exit(errno);
        }
    }
    //begin video capture
   
    IOCTL(fd,VIDIOC_STREAMON,&reqbuf.type);        
   
    //enqueue all driver buffers
    for (i=0;i<reqbuf.count;i++)
    {       
        buffer.type = reqbuf.type;
        buffer.index = i;
        IOCTL(fd,VIDIOC_QUERYBUF, &buffer);
        IOCTL(fd,VIDIOC_QBUF,&buffer);
    }
    //init xvid
   
    int result;
    result = enc_init(1);
    if(result!=0)
    {
    fprintf(stderr, "Encore INIT problem, return value %d\n", result);
    goto clean_all;          
    }
   
    //get mem of mpg4 frame
   
    uint8_t *mp4_buffer = NULL;   
    mp4_buffer = (unsigned char *) malloc(XDIM*YDIM);
    if (mp4_buffer==NULL)
    {
        fprintf(stderr,"malloc error");
        goto clean_all;
    }
       int key;
    int stats_type;
    int stats_quant;
    int stats_length;
    int sse[3];       
   
    //create store mp4 file
   
    fp= fopen(ARG_OUTPUTFILE, "rb");
    if (fp== NULL) {
        perror("Error opening output file.");
        exit(-1);
    }        

//main loop ,frame capture,compressed

    i = 0;
    int outbytes,m4v_size;
    while(!done)
    {
        //dequeue one frame
           
        buffer.type = reqbuf.type;
        buffer.index = i;
        IOCTL(fd, VIDIOC_QUERYBUF, &buffer);
        IOCTL(fd, VIDIOC_DQBUF, &buffer);
        /*debug info
        printf("current frame's unix time seconds :%d\n",buffer.timestamp.tv_sec);
        printf("current frame's unix time mcicoseconds :%d\n",buffer.timestamp.tv_usec);
        */
      
        //compress a frame
       
        m4v_size = enc_main((uint8_t *)buffers[i].start,
                             mp4_buffer+16,
                             &key, &stats_type,&stats_quant, &stats_length, sse);
       
        //store into output file
        outbytes = fwrite(mp4_buffer, 1, m4v_size, fp);
        if(outbytes != m4v_size)
        {
            fprintf(stderr,"Error writing the m4u file\n");
            exit(7);
        }
       
        //enqueue one frame
           
        buffer.type = reqbuf.type;
        buffer.index = i;
        IOCTL(fd, VIDIOC_QUERYBUF, &buffer );
        IOCTL(fd, VIDIOC_QBUF, &buffer );
        i++;           
        if( i >= reqbuf.count )
            i = 0;
    }
clean_all:
    fclose(fp);
    enc_stop();   
    //stop capture
    IOCTL(fd, VIDIOC_STREAMOFF, &reqbuf.type );
    //unmmap the apllication buffer
    for (i=0;i<reqbuf.count;i++)
        munmap (buffers[i].start,buffers[i].length);   
    //release the dynamic mem
    close(fd);
    return 0;
}

int
enc_init(int use_assembler)
{
    int xerr;
    //xvid_plugin_cbr_t cbr;
    xvid_plugin_single_t single;
    xvid_plugin_2pass1_t rc2pass1;
    xvid_plugin_2pass2_t rc2pass2;
    //xvid_plugin_fixed_t rcfixed;
    xvid_enc_plugin_t plugins[7];
    xvid_gbl_init_t xvid_gbl_init;
    xvid_enc_create_t xvid_enc_create;

    /*------------------------------------------------------------------------
    * XviD core initialization
    *----------------------------------------------------------------------*/

    /* Set version -- version checking will done by xvidcore */
    memset(&xvid_gbl_init, 0, sizeof(xvid_gbl_init));
    xvid_gbl_init.version = XVID_VERSION;
    xvid_gbl_init.debug = 0;


    /* Do we have to enable ASM optimizations ? */
    if (use_assembler) {
        xvid_gbl_init.cpu_flags = 0;
    }

    /* Initialize XviD core -- Should be done once per __process__ */
    xvid_global(NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL);

    /*------------------------------------------------------------------------
    * XviD encoder initialization
    *----------------------------------------------------------------------*/

    /* Version again */
    memset(&xvid_enc_create, 0, sizeof(xvid_enc_create));
    xvid_enc_create.version = XVID_VERSION;

    /* Width and Height of input frames */
    xvid_enc_create.width = XDIM;
    xvid_enc_create.height = YDIM;
    xvid_enc_create.profile = XVID_PROFILE_S_L3;

    /* init plugins */
    xvid_enc_create.zones = NULL;
    xvid_enc_create.num_zones = 0;

    xvid_enc_create.plugins = NULL;
    xvid_enc_create.num_plugins = 0;

    /* No fancy thread tests */
    xvid_enc_create.num_threads = 0;

    /* Frame rate - Do some quick float fps = fincr/fbase hack */
    if ((ARG_FRAMERATE - (int) ARG_FRAMERATE) < SMALL_EPS) {
        xvid_enc_create.fincr = 1;
        xvid_enc_create.fbase = (int) ARG_FRAMERATE;
    } else {
        xvid_enc_create.fincr = FRAMERATE_INCR;
        xvid_enc_create.fbase = (int) (FRAMERATE_INCR * ARG_FRAMERATE);
    }

    /* Maximum key frame interval */
    if (ARG_MAXKEYINTERVAL > 0) {
        xvid_enc_create.max_key_interval = ARG_MAXKEYINTERVAL;
    }else {
        xvid_enc_create.max_key_interval = (int) ARG_FRAMERATE *10;
    }

    /* Bframes settings */
    xvid_enc_create.max_bframes = 0;
    xvid_enc_create.bquant_ratio = 150;
    xvid_enc_create.bquant_offset = 100;

    /* Dropping ratio frame -- we don't need that */
    xvid_enc_create.frame_drop_ratio = 0;

    /* Global encoder options */
    xvid_enc_create.global = 0;

    /* I use a small value here, since will not encode whole movies, but short clips */
    xerr = xvid_encore(NULL, XVID_ENC_CREATE, &xvid_enc_create, NULL);

    /* Retrieve the encoder instance from the structure */
    enc_handle = xvid_enc_create.handle;

    return (xerr);
}

int
enc_main(unsigned char *image,
        unsigned char *bitstream,
        int *key,
        int *stats_type,
        int *stats_quant,
        int *stats_length,
        int sse[3])
{
    int ret;

    xvid_enc_frame_t xvid_enc_frame;
    xvid_enc_stats_t xvid_enc_stats;

    /* Version for the frame and the stats */
    memset(&xvid_enc_frame, 0, sizeof(xvid_enc_frame));
    xvid_enc_frame.version = XVID_VERSION;

    memset(&xvid_enc_stats, 0, sizeof(xvid_enc_stats));
    xvid_enc_stats.version = XVID_VERSION;

    /* Bind output buffer */
    xvid_enc_frame.bitstream = bitstream;
    xvid_enc_frame.length = -1;

    /* Initialize input image fields */
    if (image) {
        xvid_enc_frame.input.plane[0] = image;
        xvid_enc_frame.input.csp = XVID_CSP_I420;
        xvid_enc_frame.input.stride[0] = XDIM;
    } else {
        xvid_enc_frame.input.csp = XVID_CSP_NULL;
    }

    /* Set up core's general features */
    xvid_enc_frame.vol_flags = 0;

    /* Set up core's general features */
    xvid_enc_frame.vop_flags = vop_presets[ARG_QUALITY];

    /* Frame type -- let core decide for us */
    xvid_enc_frame.type = XVID_TYPE_AUTO;

    /* Force the right quantizer -- It is internally managed by RC plugins */
    xvid_enc_frame.quant = 3;

    /* Set up motion estimation flags */
    xvid_enc_frame.motion = motion_presets[ARG_QUALITY];

    /* We don't use special matrices */
    xvid_enc_frame.quant_intra_matrix = NULL;
    xvid_enc_frame.quant_inter_matrix = NULL;

    /* Encode the frame */
    ret = xvid_encore(enc_handle, XVID_ENC_ENCODE, &xvid_enc_frame,
                    &xvid_enc_stats);

    *key = (xvid_enc_frame.out_flags & XVID_KEYFRAME);
    *stats_type = xvid_enc_stats.type;
    *stats_quant = xvid_enc_stats.quant;
    *stats_length = xvid_enc_stats.length;
    sse[0] = xvid_enc_stats.sse_y;
    sse[1] = xvid_enc_stats.sse_u;
    sse[2] = xvid_enc_stats.sse_v;
    return (ret);
}

int
enc_stop()
{
    int xerr;

    /* Destroy the encoder instance */
    xerr = xvid_encore(enc_handle, XVID_ENC_DESTROY, NULL, NULL);

    return (xerr);
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值