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

📄 tvi_v4l2.c

📁 君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图片解码,浏览,电子书,录音,想学ucos,识货的人就下吧 russblock fmradio explore set
💻 C
📖 第 1 页 / 共 5 页
字号:
    }        request.type  = V4L2_BUF_TYPE_VIDEO_CAPTURE;    request.memory = V4L2_MEMORY_MMAP;    if (ioctl(priv->video_fd, VIDIOC_REQBUFS, &request) < 0) {        mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl request buffers failed: %s\n",               info.short_name, strerror(errno));        return 0;    }    /* query buffers */    if (!(priv->map = calloc(request.count, sizeof(struct map)))) {        mp_msg(MSGT_TV, MSGL_ERR, "%s: malloc capture buffers failed: %s\n",               info.short_name, strerror(errno));        return 0;    }    /* map and queue buffers */    for (i = 0; i < request.count; i++) {        memset(&priv->map[i].buf,0,sizeof(priv->map[i].buf));        priv->map[i].buf.index = i;        priv->map[i].buf.type  = V4L2_BUF_TYPE_VIDEO_CAPTURE;        priv->map[i].buf.memory  = V4L2_MEMORY_MMAP;        if (ioctl(priv->video_fd, VIDIOC_QUERYBUF, &(priv->map[i].buf)) < 0) {            mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query buffer failed: %s\n",                   info.short_name, strerror(errno));            free(priv->map);            priv->map = NULL;            return 0;        }        priv->map[i].addr = mmap (0, priv->map[i].buf.length, PROT_READ |                                  PROT_WRITE, MAP_SHARED, priv->video_fd, priv->map[i].buf.m.offset);        if (priv->map[i].addr == MAP_FAILED) {            mp_msg(MSGT_TV, MSGL_ERR, "%s: mmap capture buffer failed: %s\n",                   info.short_name, strerror(errno));            priv->map[i].len = 0;            return 0;        }        priv->map[i].len = priv->map[i].buf.length;        /* count up to make sure this is correct everytime */        priv->mapcount++;        if (ioctl(priv->video_fd, VIDIOC_QBUF, &(priv->map[i].buf)) < 0) {            mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl queue buffer failed: %s\n",                   info.short_name, strerror(errno));            return 0;        }    }#ifdef HAVE_TV_TELETEXT    /* start vbi thread */    if(priv->priv_vbi){        priv->vbi_shutdown = 0;        pthread_create(&priv->vbi_grabber_thread, NULL, vbi_grabber, priv);    }#endif    /* start audio thread */    priv->shutdown = 0;    priv->audio_skew_measure_time = 0;    priv->first_frame = 0;    priv->audio_skew = 0;    priv->first = 1;    set_mute(priv, 0);        return 1;}// copies a video framestatic inline void copy_frame(priv_t *priv, video_buffer_entry *dest, unsigned char *source,int len){    dest->framesize=len;    if(priv->tv_param->automute>0){        if (ioctl(priv->video_fd, VIDIOC_G_TUNER, &priv->tuner) >= 0) {            if(priv->tv_param->automute<<8>priv->tuner.signal){	        fill_blank_frame(dest->data,dest->framesize,fcc_vl2mp(priv->format.fmt.pix.pixelformat));	        set_mute(priv,1);	        return;	    }        }        set_mute(priv,0);    }    memcpy(dest->data, source, len);}// maximum skew change, in frames#define MAX_SKEW_DELTA 0.6static void *video_grabber(void *data){    priv_t *priv = (priv_t*)data;    long long skew, prev_skew, xskew, interval, prev_interval, delta;    int i;    int framesize = priv->format.fmt.pix.sizeimage;    fd_set rdset;    struct timeval timeout;    struct v4l2_buffer buf;    xskew = 0;    skew = 0;    interval = 0;    prev_interval = 0;    prev_skew = 0;    mp_msg(MSGT_TV, MSGL_V, "%s: going to capture\n", info.short_name);    if (ioctl(priv->video_fd, VIDIOC_STREAMON, &(priv->format.type)) < 0) {        mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl streamon failed: %s\n",               info.short_name, strerror(errno));        return 0;    }    priv->streamon = 1;    if (!priv->tv_param->noaudio) {        pthread_create(&priv->audio_grabber_thread, NULL, audio_grabber, priv);    }    for (priv->frames = 0; !priv->shutdown;)    {        int ret;                if (priv->immediate_mode) {            while (priv->video_cnt == priv->video_buffer_size_max) {                usleep(10000);                if (priv->shutdown) {                    return NULL;                }            }        }                        FD_ZERO (&rdset);        FD_SET (priv->video_fd, &rdset);        timeout.tv_sec = 1;        timeout.tv_usec = 0;        i = select(priv->video_fd + 1, &rdset, NULL, NULL, &timeout);        if (i < 0) {            mp_msg(MSGT_TV, MSGL_ERR, "%s: select failed: %s\n",                   info.short_name, strerror(errno));            continue;        }        else if (i == 0) {            mp_msg(MSGT_TV, MSGL_ERR, "%s: select timeout\n", info.short_name);            continue;        }        else if (!FD_ISSET(priv->video_fd, &rdset)) {            continue;        }        memset(&buf,0,sizeof(buf));        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;        buf.memory = V4L2_MEMORY_MMAP;        ret = ioctl(priv->video_fd, VIDIOC_DQBUF, &buf);        if (ret < 0) {            /*              if there's no signal, the buffer might me dequeued              so we query all the buffers to see which one we should              put back to queue              observed with saa7134 0.2.8              don't know if is it a bug or (mis)feature             */            mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl dequeue buffer failed: %s, idx = %d\n",                   info.short_name, strerror(errno), buf.index);            for (i = 0; i < priv->mapcount; i++) {                memset(&buf,0,sizeof(buf));                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;                buf.memory = V4L2_MEMORY_MMAP;                buf.index = i;                ret = ioctl(priv->video_fd, VIDIOC_QUERYBUF, &buf);                if (ret < 0) {                    mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl query buffer failed: %s, idx = %d\n",                           info.short_name, strerror(errno), buf.index);                    return 0;                }                if ((buf.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE)) == V4L2_BUF_FLAG_MAPPED) {                    if (ioctl(priv->video_fd, VIDIOC_QBUF, &(priv->map[i].buf)) < 0) {                        mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl queue buffer failed: %s\n",                               info.short_name, strerror(errno));                        return 0;                    }                                }            }            continue;        }        /* store the timestamp of the very first frame as reference */        if (!priv->frames++) {            if (!priv->tv_param->noaudio) pthread_mutex_lock(&priv->skew_mutex);            priv->first_frame = (long long)1e6*buf.timestamp.tv_sec + buf.timestamp.tv_usec;            if (!priv->tv_param->noaudio) pthread_mutex_unlock(&priv->skew_mutex);        }        priv->curr_frame = (long long)buf.timestamp.tv_sec*1e6+buf.timestamp.tv_usec;//        fprintf(stderr, "idx = %d, ts = %lf\n", buf.index, (double)(priv->curr_frame) / 1e6);        interval = priv->curr_frame - priv->first_frame;        delta = interval - prev_interval;        if (!priv->immediate_mode) {            // interpolate the skew in time            if (!priv->tv_param->noaudio) pthread_mutex_lock(&priv->skew_mutex);            xskew = priv->audio_skew + (interval - priv->audio_skew_measure_time)*priv->audio_skew_factor;            if (!priv->tv_param->noaudio) pthread_mutex_unlock(&priv->skew_mutex);             // correct extreme skew changes to avoid (especially) moving backwards in time            if (xskew - prev_skew > delta*MAX_SKEW_DELTA) {                skew = prev_skew + delta*MAX_SKEW_DELTA;            } else if (xskew - prev_skew < -delta*MAX_SKEW_DELTA) {                skew = prev_skew - delta*MAX_SKEW_DELTA;            } else {                skew = xskew;            }        }        mp_msg(MSGT_TV, MSGL_DBG3, "\nfps = %lf, interval = %lf, a_skew = %f, corr_skew = %f\n",               delta ? (double)1e6/delta : -1,               (double)1e-6*interval, (double)1e-6*xskew, (double)1e-6*skew);        mp_msg(MSGT_TV, MSGL_DBG3, "vcnt = %d, acnt = %d\n", priv->video_cnt, priv->audio_cnt);        prev_skew = skew;        prev_interval = interval;        /* allocate a new buffer, if needed */        pthread_mutex_lock(&priv->video_buffer_mutex);        if (priv->video_buffer_size_current < priv->video_buffer_size_max) {            if (priv->video_cnt == priv->video_buffer_size_current) {                unsigned char *newbuf = malloc(framesize);                if (newbuf) {                    memmove(priv->video_ringbuffer+priv->video_tail+1, priv->video_ringbuffer+priv->video_tail,                            (priv->video_buffer_size_current-priv->video_tail)*sizeof(video_buffer_entry));                    priv->video_ringbuffer[priv->video_tail].data = newbuf;                    if ((priv->video_head >= priv->video_tail) && (priv->video_cnt > 0)) priv->video_head++;                    priv->video_buffer_size_current++;                }            }        }        pthread_mutex_unlock(&priv->video_buffer_mutex);        if (priv->video_cnt == priv->video_buffer_size_current) {            if (!priv->immediate_mode) {                mp_msg(MSGT_TV, MSGL_ERR, "\nvideo buffer full - dropping frame\n");                if (priv->audio_insert_null_samples) {                    pthread_mutex_lock(&priv->audio_mutex);                    priv->dropped_frames_timeshift += delta;                    pthread_mutex_unlock(&priv->audio_mutex);                }            }        } else {            if (priv->immediate_mode) {                priv->video_ringbuffer[priv->video_tail].timestamp = 0;            } else {                // compensate for audio skew                // negative skew => there are more audio samples, increase interval                // positive skew => less samples, shorten the interval                priv->video_ringbuffer[priv->video_tail].timestamp = interval - skew;                if (priv->audio_insert_null_samples && priv->video_ringbuffer[priv->video_tail].timestamp > 0) {                    pthread_mutex_lock(&priv->audio_mutex);                    priv->video_ringbuffer[priv->video_tail].timestamp +=                         (priv->audio_null_blocks_inserted                         - priv->dropped_frames_timeshift/priv->audio_usecs_per_block)                        *priv->audio_usecs_per_block;                    pthread_mutex_unlock(&priv->audio_mutex);                }            }            copy_frame(priv, priv->video_ringbuffer+priv->video_tail, priv->map[buf.index].addr,buf.bytesused);            priv->video_tail = (priv->video_tail+1)%priv->video_buffer_size_current;            priv->video_cnt++;        }        if (ioctl(priv->video_fd, VIDIOC_QBUF, &buf) < 0) {            mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl queue buffer failed: %s\n",                   info.short_name, strerror(errno));            return 0;        }    }    return NULL;}#define MAX_LOOP 50static double grab_video_frame(priv_t *priv, char *buffer, int len){    double interval;    int loop_cnt = 0;    if (priv->first) {        pthread_create(&priv->video_grabber_thread, NULL, video_grabber, priv);        priv->first = 0;    }    while (priv->video_cnt == 0) {        usleep(10000);        if (loop_cnt++ > MAX_LOOP) return 0;    }    pthread_mutex_lock(&priv->video_buffer_mutex);    interval = (double)priv->video_ringbuffer[priv->video_head].timestamp*1e-6;    memcpy(buffer, priv->video_ringbuffer[priv->video_head].data, len);    priv->video_cnt--;    priv->video_head = (priv->video_head+1)%priv->video_buffer_size_current;    pthread_mutex_unlock(&priv->video_buffer_mutex);    return interval;}static int get_video_framesize(priv_t *priv){    /*       this routine will be called before grab_video_frame       thus let's return topmost frame's size    */    if (priv->video_cnt)        return priv->video_ringbuffer[priv->video_head].framesize;    /*      no video frames yet available. i don't know what to do in this case,      thus let's return some fallback result (for compressed format this will be      maximum allowed frame size.    */    return priv->format.fmt.pix.sizeimage;}//#define DOUBLESPEED#ifdef DOUBLESPEED// for testing purposes onlystatic void read_doublespeed(priv_t *priv){    char *bufx = calloc(priv->audio_in.blocksize, 2);    short *s;    short *d;    int i;        audio_in_read_chunk(&priv->audio_in, bufx);    audio_in_read_chunk(&priv->audio_in, bufx+priv->audio_in.blocksize);    s = bufx;    d = priv->audio_ringbuffer+priv->audio_tail*priv->audio_in.blocksize;    for (i = 0; i < priv->audio_in.blocksize/2; i++) {        *d++ = *s++;        *s++;    }    }#endifstatic void *audio_grabber(void *data){    priv_t *priv = (priv_t*)data;    struct timeval tv;    int i, audio_skew_ptr = 0;    long long current_time, prev_skew = 0, prev_skew_uncorr = 0;    long long start_time_avg;    gettimeofday(&tv, NULL);    start_time_avg = priv->audio_start_time = (long long)1e6*tv.tv_sec + tv.tv_usec;    audio_in_start_capture(&priv->audio_in);    for (i = 0; i < priv->aud_skew_cnt; i++)        priv->audio_skew_buffer[i] = 0;    for (i = 0; i < priv->aud_skew_cnt; i++)        priv->audio_skew_delta_buffer[i] = 0;    for (; !priv->shutdown;)    {#ifdef DOUBLESPEED        read_doublespeed(priv);#else        if (audio_in_read_chunk(&priv->audio_in, priv->audio_ringbuffer+priv->audio_tail*priv->audio_in.blocksize) < 0)            continue;#endif        

⌨️ 快捷键说明

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