⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 grab.c

📁 FFmpeg is an audio/video conversion tool. It includes libavcodec, the leading open source codec libr
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Linux video grab interface * Copyright (c) 2000,2001 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include "avformat.h"#include <unistd.h>#include <fcntl.h>#include <sys/ioctl.h>#include <sys/mman.h>#include <sys/time.h>#define _LINUX_TIME_H 1#include <linux/videodev.h>#include <time.h>typedef struct {    int fd;    int frame_format; /* see VIDEO_PALETTE_xxx */    int use_mmap;    int width, height;    int frame_rate;    int frame_rate_base;    int64_t time_frame;    int frame_size;    struct video_capability video_cap;    struct video_audio audio_saved;    uint8_t *video_buf;    struct video_mbuf gb_buffers;    struct video_mmap gb_buf;    int gb_frame;    /* ATI All In Wonder specific stuff */    /* XXX: remove and merge in libavcodec/imgconvert.c */    int aiw_enabled;    int deint;    int halfw;    uint8_t *src_mem;    uint8_t *lum_m4_mem;} VideoData;static int aiw_init(VideoData *s);static int aiw_read_picture(VideoData *s, uint8_t *data);static int aiw_close(VideoData *s);static int grab_read_header(AVFormatContext *s1, AVFormatParameters *ap){    VideoData *s = s1->priv_data;    AVStream *st;    int width, height;    int video_fd, frame_size;    int ret, frame_rate, frame_rate_base;    int desired_palette;    struct video_tuner tuner;    struct video_audio audio;    const char *video_device;    int j;    if (!ap || ap->width <= 0 || ap->height <= 0 || ap->frame_rate <= 0)        return -1;        width = ap->width;    height = ap->height;    frame_rate      = ap->frame_rate;    frame_rate_base = ap->frame_rate_base;    st = av_new_stream(s1, 0);    if (!st)        return -ENOMEM;    av_set_pts_info(st, 48, 1, 1000000); /* 48 bits pts in us */    s->width = width;    s->height = height;    s->frame_rate      = frame_rate;    s->frame_rate_base = frame_rate_base;    video_device = ap->device;    if (!video_device)        video_device = "/dev/video";    video_fd = open(video_device, O_RDWR);    if (video_fd < 0) {        perror(video_device);        goto fail;    }        if (ioctl(video_fd,VIDIOCGCAP, &s->video_cap) < 0) {        perror("VIDIOCGCAP");        goto fail;    }    if (!(s->video_cap.type & VID_TYPE_CAPTURE)) {	av_log(s1, AV_LOG_ERROR, "Fatal: grab device does not handle capture\n");        goto fail;    }    desired_palette = -1;    if (st->codec.pix_fmt == PIX_FMT_YUV420P) {        desired_palette = VIDEO_PALETTE_YUV420P;    } else if (st->codec.pix_fmt == PIX_FMT_YUV422) {        desired_palette = VIDEO_PALETTE_YUV422;    } else if (st->codec.pix_fmt == PIX_FMT_BGR24) {        desired_palette = VIDEO_PALETTE_RGB24;    }        /* set tv standard */    if (ap->standard && !ioctl(video_fd, VIDIOCGTUNER, &tuner)) {	if (!strcasecmp(ap->standard, "pal"))	    tuner.mode = VIDEO_MODE_PAL;	else if (!strcasecmp(ap->standard, "secam"))	    tuner.mode = VIDEO_MODE_SECAM;	else	    tuner.mode = VIDEO_MODE_NTSC;	ioctl(video_fd, VIDIOCSTUNER, &tuner);    }        /* unmute audio */    audio.audio = 0;    ioctl(video_fd, VIDIOCGAUDIO, &audio);    memcpy(&s->audio_saved, &audio, sizeof(audio));    audio.flags &= ~VIDEO_AUDIO_MUTE;    ioctl(video_fd, VIDIOCSAUDIO, &audio);    ret = ioctl(video_fd,VIDIOCGMBUF,&s->gb_buffers);    if (ret < 0) {        /* try to use read based access */        struct video_window win;        struct video_picture pict;        int val;        win.x = 0;        win.y = 0;        win.width = width;        win.height = height;        win.chromakey = -1;        win.flags = 0;        ioctl(video_fd, VIDIOCSWIN, &win);        ioctl(video_fd, VIDIOCGPICT, &pict);#if 0        printf("v4l: colour=%d hue=%d brightness=%d constrast=%d whiteness=%d\n",               pict.colour,               pict.hue,               pict.brightness,               pict.contrast,               pict.whiteness);#endif                /* try to choose a suitable video format */        pict.palette = desired_palette;        if (desired_palette == -1 || (ret = ioctl(video_fd, VIDIOCSPICT, &pict)) < 0) {            pict.palette=VIDEO_PALETTE_YUV420P;            ret = ioctl(video_fd, VIDIOCSPICT, &pict);            if (ret < 0) {                pict.palette=VIDEO_PALETTE_YUV422;                ret = ioctl(video_fd, VIDIOCSPICT, &pict);                if (ret < 0) {                    pict.palette=VIDEO_PALETTE_RGB24;                    ret = ioctl(video_fd, VIDIOCSPICT, &pict);                    if (ret < 0)                         goto fail1;                }            }        }        s->frame_format = pict.palette;        val = 1;        ioctl(video_fd, VIDIOCCAPTURE, &val);        s->time_frame = av_gettime() * s->frame_rate / s->frame_rate_base;        s->use_mmap = 0;                /* ATI All In Wonder automatic activation */        if (!strcmp(s->video_cap.name, "Km")) {            if (aiw_init(s) < 0)                goto fail;            s->aiw_enabled = 1;            /* force 420P format because convertion from YUV422 to YUV420P               is done in this driver (ugly) */            s->frame_format = VIDEO_PALETTE_YUV420P;        }    } else {        s->video_buf = mmap(0,s->gb_buffers.size,PROT_READ|PROT_WRITE,MAP_SHARED,video_fd,0);        if ((unsigned char*)-1 == s->video_buf) {            perror("mmap");            goto fail;        }        s->gb_frame = 0;        s->time_frame = av_gettime() * s->frame_rate / s->frame_rate_base;                /* start to grab the first frame */        s->gb_buf.frame = s->gb_frame % s->gb_buffers.frames;        s->gb_buf.height = height;        s->gb_buf.width = width;        s->gb_buf.format = desired_palette;        if (desired_palette == -1 || (ret = ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf)) < 0) {            s->gb_buf.format = VIDEO_PALETTE_YUV420P;                        ret = ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf);            if (ret < 0 && errno != EAGAIN) {                /* try YUV422 */                s->gb_buf.format = VIDEO_PALETTE_YUV422;                                ret = ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf);                if (ret < 0 && errno != EAGAIN) {                    /* try RGB24 */                    s->gb_buf.format = VIDEO_PALETTE_RGB24;                    ret = ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf);                }            }        }        if (ret < 0) {            if (errno != EAGAIN) {            fail1:                av_log(s1, AV_LOG_ERROR, "Fatal: grab device does not support suitable format\n");            } else {                av_log(s1, AV_LOG_ERROR,"Fatal: grab device does not receive any video signal\n");            }            goto fail;        }	for (j = 1; j < s->gb_buffers.frames; j++) {	  s->gb_buf.frame = j;	  ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf);	}        s->frame_format = s->gb_buf.format;        s->use_mmap = 1;    }    switch(s->frame_format) {    case VIDEO_PALETTE_YUV420P:        frame_size = (width * height * 3) / 2;        st->codec.pix_fmt = PIX_FMT_YUV420P;        break;    case VIDEO_PALETTE_YUV422:        frame_size = width * height * 2;        st->codec.pix_fmt = PIX_FMT_YUV422;        break;    case VIDEO_PALETTE_RGB24:        frame_size = width * height * 3;        st->codec.pix_fmt = PIX_FMT_BGR24; /* NOTE: v4l uses BGR24, not RGB24 ! */        break;    default:        goto fail;    }    s->fd = video_fd;    s->frame_size = frame_size;        st->codec.codec_type = CODEC_TYPE_VIDEO;    st->codec.codec_id = CODEC_ID_RAWVIDEO;    st->codec.width = width;    st->codec.height = height;    st->codec.frame_rate      = frame_rate;    st->codec.frame_rate_base = frame_rate_base;    return 0; fail:    if (video_fd >= 0)        close(video_fd);    av_free(st);    return AVERROR_IO;}static int v4l_mm_read_picture(VideoData *s, uint8_t *buf){    uint8_t *ptr;    while (ioctl(s->fd, VIDIOCSYNC, &s->gb_frame) < 0 &&           (errno == EAGAIN || errno == EINTR));    ptr = s->video_buf + s->gb_buffers.offsets[s->gb_frame];    memcpy(buf, ptr, s->frame_size);    /* Setup to capture the next frame */    s->gb_buf.frame = s->gb_frame;    if (ioctl(s->fd, VIDIOCMCAPTURE, &s->gb_buf) < 0) {        if (errno == EAGAIN)            av_log(NULL, AV_LOG_ERROR, "Cannot Sync\n");        else            perror("VIDIOCMCAPTURE");        return AVERROR_IO;    }    /* This is now the grabbing frame */    s->gb_frame = (s->gb_frame + 1) % s->gb_buffers.frames;    return s->frame_size;}static int grab_read_packet(AVFormatContext *s1, AVPacket *pkt){    VideoData *s = s1->priv_data;    int64_t curtime, delay;    struct timespec ts;    /* Calculate the time of the next frame */    s->time_frame += int64_t_C(1000000);    /* wait based on the frame rate */    for(;;) {        curtime = av_gettime();        delay = s->time_frame  * s->frame_rate_base / s->frame_rate - curtime;        if (delay <= 0) {            if (delay < int64_t_C(-1000000) * s->frame_rate_base / s->frame_rate) {                /* printf("grabbing is %d frames late (dropping)\n", (int) -(delay / 16666)); */                s->time_frame += int64_t_C(1000000);            }            break;        }            ts.tv_sec = delay / 1000000;        ts.tv_nsec = (delay % 1000000) * 1000;        nanosleep(&ts, NULL);    }    if (av_new_packet(pkt, s->frame_size) < 0)        return AVERROR_IO;    pkt->pts = curtime & ((1LL << 48) - 1);    /* read one frame */    if (s->aiw_enabled) {        return aiw_read_picture(s, pkt->data);    } else if (s->use_mmap) {        return v4l_mm_read_picture(s, pkt->data);    } else {        if (read(s->fd, pkt->data, pkt->size) != pkt->size)            return AVERROR_IO;        return s->frame_size;    }}static int grab_read_close(AVFormatContext *s1){    VideoData *s = s1->priv_data;    if (s->aiw_enabled)        aiw_close(s);    if (s->use_mmap)        munmap(s->video_buf, s->gb_buffers.size);    /* mute audio. we must force it because the BTTV driver does not       return its state correctly */    s->audio_saved.flags |= VIDEO_AUDIO_MUTE;    ioctl(s->fd, VIDIOCSAUDIO, &s->audio_saved);    close(s->fd);    return 0;}static AVInputFormat video_grab_device_format = {    "video4linux",    "video grab",    sizeof(VideoData),    NULL,    grab_read_header,    grab_read_packet,    grab_read_close,    .flags = AVFMT_NOFILE,};/* All in Wonder specific stuff *//* XXX: remove and merge in libavcodec/imgconvert.c */static int aiw_init(VideoData *s){    int width, height;    width = s->width;    height = s->height;    if ((width == s->video_cap.maxwidth && height == s->video_cap.maxheight) ||        (width == s->video_cap.maxwidth && height == s->video_cap.maxheight*2) ||        (width == s->video_cap.maxwidth/2 && height == s->video_cap.maxheight)) {                s->deint=0;        s->halfw=0;        if (height == s->video_cap.maxheight*2) s->deint=1;        if (width == s->video_cap.maxwidth/2) s->halfw=1;    } else {        av_log(NULL, AV_LOG_ERROR, "\nIncorrect Grab Size Supplied - Supported Sizes Are:\n");        av_log(NULL, AV_LOG_ERROR, " %dx%d  %dx%d %dx%d\n\n",                s->video_cap.maxwidth,s->video_cap.maxheight,                s->video_cap.maxwidth,s->video_cap.maxheight*2,                s->video_cap.maxwidth/2,s->video_cap.maxheight);        goto fail;    }    if (s->halfw == 0) {        s->src_mem = av_malloc(s->width*2);    } else {        s->src_mem = av_malloc(s->width*4);    }    if (!s->src_mem) goto fail;    s->lum_m4_mem = av_malloc(s->width);    if (!s->lum_m4_mem)        goto fail;    return 0; fail:    av_freep(&s->src_mem);    av_freep(&s->lum_m4_mem);    return -1;}#ifdef HAVE_MMX#include "../libavcodec/i386/mmx.h"#define LINE_WITH_UV \                    movq_m2r(ptr[0],mm0); \                    movq_m2r(ptr[8],mm1);  \                    movq_r2r(mm0, mm4); \                    punpcklbw_r2r(mm1,mm0); \                    punpckhbw_r2r(mm1,mm4); \

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -