📄 ivtv-streams.c
字号:
/* init/start/stop/exit stream functions Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> Copyright (C) 2004 Chris Kennedy <c@groovy.org> Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *//* License: GPL * Author: Kevin Thayer <nufan_wfk at yahoo dot com> * * This file will hold API related functions, both internal (firmware api) * and external (v4l2, etc) * * ----- * MPG600/MPG160 support by T.Adachi <tadachi@tadachi-net.com> * and Takeru KOMORIYA<komoriya@paken.org> * * AVerMedia M179 GPIO info by Chris Pinkham <cpinkham@bc2va.org> * using information provided by Jiun-Kuei Jung @ AVerMedia. */#include "ivtv-driver.h"#include "ivtv-fileops.h"#include "ivtv-queue.h"#include "ivtv-mailbox.h"#include "ivtv-ioctl.h"#include "ivtv-irq.h"#include "ivtv-yuv.h"#include "ivtv-cards.h"#include "ivtv-streams.h"static struct file_operations ivtv_v4l2_enc_fops = { .owner = THIS_MODULE, .read = ivtv_v4l2_read, .write = ivtv_v4l2_write, .open = ivtv_v4l2_open, .ioctl = ivtv_v4l2_ioctl, .release = ivtv_v4l2_close, .poll = ivtv_v4l2_enc_poll,};static struct file_operations ivtv_v4l2_dec_fops = { .owner = THIS_MODULE, .read = ivtv_v4l2_read, .write = ivtv_v4l2_write, .open = ivtv_v4l2_open, .ioctl = ivtv_v4l2_ioctl, .release = ivtv_v4l2_close, .poll = ivtv_v4l2_dec_poll,};#define IVTV_V4L2_DEC_MPG_OFFSET 16 /* offset from 0 to register decoder mpg v4l2 minors on */#define IVTV_V4L2_ENC_PCM_OFFSET 24 /* offset from 0 to register pcm v4l2 minors on */#define IVTV_V4L2_ENC_YUV_OFFSET 32 /* offset from 0 to register yuv v4l2 minors on */#define IVTV_V4L2_DEC_YUV_OFFSET 48 /* offset from 0 to register decoder yuv v4l2 minors on */#define IVTV_V4L2_DEC_VBI_OFFSET 8 /* offset from 0 to register decoder vbi input v4l2 minors on */#define IVTV_V4L2_DEC_VOUT_OFFSET 16 /* offset from 0 to register vbi output v4l2 minors on */static struct { const char *name; int vfl_type; int minor_offset; int dma, pio; enum v4l2_buf_type buf_type; const struct file_operations *fops;} ivtv_stream_info[] = { { /* IVTV_ENC_STREAM_TYPE_MPG */ "encoder MPG", VFL_TYPE_GRABBER, 0, PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, &ivtv_v4l2_enc_fops }, { /* IVTV_ENC_STREAM_TYPE_YUV */ "encoder YUV", VFL_TYPE_GRABBER, IVTV_V4L2_ENC_YUV_OFFSET, PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, &ivtv_v4l2_enc_fops }, { /* IVTV_ENC_STREAM_TYPE_VBI */ "encoder VBI", VFL_TYPE_VBI, 0, PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VBI_CAPTURE, &ivtv_v4l2_enc_fops }, { /* IVTV_ENC_STREAM_TYPE_PCM */ "encoder PCM", VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET, PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE, &ivtv_v4l2_enc_fops }, { /* IVTV_ENC_STREAM_TYPE_RAD */ "encoder radio", VFL_TYPE_RADIO, 0, PCI_DMA_NONE, 1, V4L2_BUF_TYPE_PRIVATE, &ivtv_v4l2_enc_fops }, { /* IVTV_DEC_STREAM_TYPE_MPG */ "decoder MPG", VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET, PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, &ivtv_v4l2_dec_fops }, { /* IVTV_DEC_STREAM_TYPE_VBI */ "decoder VBI", VFL_TYPE_VBI, IVTV_V4L2_DEC_VBI_OFFSET, PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_CAPTURE, &ivtv_v4l2_enc_fops }, { /* IVTV_DEC_STREAM_TYPE_VOUT */ "decoder VOUT", VFL_TYPE_VBI, IVTV_V4L2_DEC_VOUT_OFFSET, PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_OUTPUT, &ivtv_v4l2_dec_fops }, { /* IVTV_DEC_STREAM_TYPE_YUV */ "decoder YUV", VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET, PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, &ivtv_v4l2_dec_fops }};static void ivtv_stream_init(struct ivtv *itv, int type){ struct ivtv_stream *s = &itv->streams[type]; struct video_device *dev = s->v4l2dev; /* we need to keep v4l2dev, so restore it afterwards */ memset(s, 0, sizeof(*s)); s->v4l2dev = dev; /* initialize ivtv_stream fields */ s->itv = itv; s->type = type; s->name = ivtv_stream_info[type].name; if (ivtv_stream_info[type].pio) s->dma = PCI_DMA_NONE; else s->dma = ivtv_stream_info[type].dma; s->buf_size = itv->stream_buf_size[type]; if (s->buf_size) s->buffers = (itv->options.kilobytes[type] * 1024 + s->buf_size - 1) / s->buf_size; spin_lock_init(&s->qlock); init_waitqueue_head(&s->waitq); s->id = -1; s->sg_handle = IVTV_DMA_UNMAPPED; ivtv_queue_init(&s->q_free); ivtv_queue_init(&s->q_full); ivtv_queue_init(&s->q_dma); ivtv_queue_init(&s->q_predma); ivtv_queue_init(&s->q_io);}static int ivtv_prep_dev(struct ivtv *itv, int type){ struct ivtv_stream *s = &itv->streams[type]; int minor_offset = ivtv_stream_info[type].minor_offset; int minor; /* These four fields are always initialized. If v4l2dev == NULL, then this stream is not in use. In that case no other fields but these four can be used. */ s->v4l2dev = NULL; s->itv = itv; s->type = type; s->name = ivtv_stream_info[type].name; /* Check whether the radio is supported */ if (type == IVTV_ENC_STREAM_TYPE_RAD && !(itv->v4l2_cap & V4L2_CAP_RADIO)) return 0; if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) return 0; /* card number + user defined offset + device offset */ minor = itv->num + ivtv_first_minor + minor_offset; /* User explicitly selected 0 buffers for these streams, so don't create them. */ if (ivtv_stream_info[type].dma != PCI_DMA_NONE && itv->options.kilobytes[type] == 0) { IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name); return 0; } ivtv_stream_init(itv, type); /* allocate and initialize the v4l2 video device structure */ s->v4l2dev = video_device_alloc(); if (s->v4l2dev == NULL) { IVTV_ERR("Couldn't allocate v4l2 video_device for %s\n", s->name); return -ENOMEM; } s->v4l2dev->type = VID_TYPE_CAPTURE | VID_TYPE_TUNER | VID_TYPE_TELETEXT | VID_TYPE_CLIPPING | VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER; if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { s->v4l2dev->type |= VID_TYPE_MPEG_DECODER; } snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "ivtv%d %s", itv->num, s->name); s->v4l2dev->minor = minor; s->v4l2dev->dev = &itv->dev->dev; s->v4l2dev->fops = ivtv_stream_info[type].fops; s->v4l2dev->release = video_device_release; return 0;}/* Initialize v4l2 variables and prepare v4l2 devices */int ivtv_streams_setup(struct ivtv *itv){ int type; /* Setup V4L2 Devices */ for (type = 0; type < IVTV_MAX_STREAMS; type++) { /* Prepare device */ if (ivtv_prep_dev(itv, type)) break; if (itv->streams[type].v4l2dev == NULL) continue; /* Allocate Stream */ if (ivtv_stream_alloc(&itv->streams[type])) break; } if (type == IVTV_MAX_STREAMS) return 0; /* One or more streams could not be initialized. Clean 'em all up. */ ivtv_streams_cleanup(itv); return -ENOMEM;}static int ivtv_reg_dev(struct ivtv *itv, int type){ struct ivtv_stream *s = &itv->streams[type]; int vfl_type = ivtv_stream_info[type].vfl_type; int minor; if (s->v4l2dev == NULL) return 0; minor = s->v4l2dev->minor; /* Register device. First try the desired minor, then any free one. */ if (video_register_device(s->v4l2dev, vfl_type, minor) && video_register_device(s->v4l2dev, vfl_type, -1)) { IVTV_ERR("Couldn't register v4l2 device for %s minor %d\n", s->name, minor); video_device_release(s->v4l2dev); s->v4l2dev = NULL; return -ENOMEM; } switch (vfl_type) { case VFL_TYPE_GRABBER: IVTV_INFO("Registered device video%d for %s (%d kB)\n", s->v4l2dev->minor, s->name, itv->options.kilobytes[type]); break; case VFL_TYPE_RADIO: IVTV_INFO("Registered device radio%d for %s\n", s->v4l2dev->minor - MINOR_VFL_TYPE_RADIO_MIN, s->name); break; case VFL_TYPE_VBI: if (itv->options.kilobytes[type]) IVTV_INFO("Registered device vbi%d for %s (%d kB)\n", s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, s->name, itv->options.kilobytes[type]); else IVTV_INFO("Registered device vbi%d for %s\n", s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, s->name); break; } return 0;}/* Register v4l2 devices */int ivtv_streams_register(struct ivtv *itv){ int type; int err = 0; /* Register V4L2 devices */ for (type = 0; type < IVTV_MAX_STREAMS; type++) err |= ivtv_reg_dev(itv, type); if (err == 0) return 0; /* One or more streams could not be initialized. Clean 'em all up. */ ivtv_streams_cleanup(itv); return -ENOMEM;}/* Unregister v4l2 devices */void ivtv_streams_cleanup(struct ivtv *itv){ int type; /* Teardown all streams */ for (type = 0; type < IVTV_MAX_STREAMS; type++) { struct video_device *vdev = itv->streams[type].v4l2dev; itv->streams[type].v4l2dev = NULL; if (vdev == NULL) continue; ivtv_stream_free(&itv->streams[type]); /* Unregister device */ video_unregister_device(vdev); }}static void ivtv_vbi_setup(struct ivtv *itv){ int raw = itv->vbi.sliced_in->service_set == 0; u32 data[CX2341X_MBOX_MAX_DATA]; int lines; int i; /* Reset VBI */ ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0); /* setup VBI registers */ itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in); /* determine number of lines and total number of VBI bytes. A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1 The '- 1' byte is probably an unused U or V byte. Or something... A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal header, 42 data bytes + checksum (to be confirmed) */ if (raw) { lines = itv->vbi.count * 2; } else { lines = itv->is_60hz ? 24 : 38; if (itv->is_60hz && (itv->hw_flags & IVTV_HW_CX25840)) lines += 2; } itv->vbi.enc_size = lines * (raw ? itv->vbi.raw_size : itv->vbi.sliced_size); /* Note: sliced vs raw flag doesn't seem to have any effect TODO: check mode (0x02) value with older ivtv versions. */ data[0] = raw | 0x02 | (0xbd << 8); /* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */ data[1] = 1; /* The VBI frames are stored in a ringbuffer with this size (with a VBI frame as unit) */ data[2] = raw ? 4 : 8; /* The start/stop codes determine which VBI lines end up in the raw VBI data area. The codes are from table 24 in the saa7115 datasheet. Each raw/sliced/video line is framed with codes FF0000XX where XX is the SAV/EAV (Start/End of Active Video) code. These values for raw VBI are obtained from a driver disassembly. The sliced start/stop codes was deduced from this, but they do not appear in the driver. Other code pairs that I found are: 0x250E6249/0x13545454 and 0x25256262/0x38137F54. However, I have no idea what these values are for. */ if (itv->hw_flags & IVTV_HW_CX25840) { /* Setup VBI for the cx25840 digitizer */ if (raw) { data[3] = 0x20602060; data[4] = 0x30703070; } else { data[3] = 0xB0F0B0F0; data[4] = 0xA0E0A0E0; } /* Lines per frame */ data[5] = lines; /* bytes per line */ data[6] = (raw ? itv->vbi.raw_size : itv->vbi.sliced_size); } else { /* Setup VBI for the saa7115 digitizer */ if (raw) { data[3] = 0x25256262; data[4] = 0x387F7F7F; } else { data[3] = 0xABABECEC; data[4] = 0xB6F1F1F1; } /* Lines per frame */ data[5] = lines; /* bytes per line */ data[6] = itv->vbi.enc_size / lines; } IVTV_DEBUG_INFO( "Setup VBI API header 0x%08x pkts %d buffs %d ln %d sz %d\n", data[0], data[1], data[2], data[5], data[6]); ivtv_api(itv, CX2341X_ENC_SET_VBI_CONFIG, 7, data); /* returns the VBI encoder memory area. */ itv->vbi.enc_start = data[2]; itv->vbi.fpi = data[0]; if (!itv->vbi.fpi) itv->vbi.fpi = 1; IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d\n", itv->vbi.enc_start, data[1], itv->vbi.fpi); /* select VBI lines. Note that the sliced argument seems to have no effect. */ for (i = 2; i <= 24; i++) { int valid; if (itv->is_60hz) { valid = i >= 10 && i < 22; } else { valid = i >= 6 && i < 24; } ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, i - 1, valid, 0 , 0, 0); ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, (i - 1) | 0x80000000, valid, 0, 0, 0); } /* Remaining VBI questions: - Is it possible to select particular VBI lines only for inclusion in the MPEG stream? Currently you can only get the first X lines. - Is mixed raw and sliced VBI possible? - What's the meaning of the raw/sliced flag? - What's the meaning of params 2, 3 & 4 of the Select VBI command? */}int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s){ u32 data[CX2341X_MBOX_MAX_DATA]; struct ivtv *itv = s->itv; struct cx2341x_mpeg_params *p = &itv->params; int captype = 0, subtype = 0; int enable_passthrough = 0; if (s->v4l2dev == NULL) return -EINVAL; IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name); switch (s->type) { case IVTV_ENC_STREAM_TYPE_MPG: captype = 0; subtype = 3; /* Stop Passthrough */ if (itv->output_mode == OUT_PASSTHROUGH) { ivtv_passthrough_mode(itv, 0); enable_passthrough = 1; } itv->mpg_data_received = itv->vbi_data_inserted = 0; itv->dualwatch_jiffies = jiffies; itv->dualwatch_stereo_mode = p->audio_properties & 0x0300; itv->search_pack_header = 0; break; case IVTV_ENC_STREAM_TYPE_YUV: if (itv->output_mode == OUT_PASSTHROUGH) { captype = 2; subtype = 11; /* video+audio+decoder */ break; } captype = 1; subtype = 1; break; case IVTV_ENC_STREAM_TYPE_PCM: captype = 1; subtype = 2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -