📄 ivtv-ioctl.c
字号:
{ 0, 0, 0, "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 } }, { 1, 0, V4L2_FMT_FLAG_COMPRESSED, "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 } } }; struct v4l2_fmtdesc *fmt = arg; enum v4l2_buf_type type = fmt->type; switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) return -EINVAL; break; default: return -EINVAL; } if (fmt->index > 1) return -EINVAL; *fmt = formats[fmt->index]; fmt->type = type; return 0; } case VIDIOC_G_INPUT:{ *(int *)arg = itv->active_input; break; } case VIDIOC_S_INPUT:{ int inp = *(int *)arg; if (inp < 0 || inp >= itv->nof_inputs) return -EINVAL; if (inp == itv->active_input) { IVTV_DEBUG_INFO("Input unchanged\n"); break; } if (atomic_read(&itv->capturing) > 0) { return -EBUSY; } IVTV_DEBUG_INFO("Changing input from %d to %d\n", itv->active_input, inp); itv->active_input = inp; /* Set the audio input to whatever is appropriate for the input type. */ itv->audio_input = itv->card->video_inputs[inp].audio_index; /* prevent others from messing with the streams until we're finished changing inputs. */ ivtv_mute(itv); ivtv_video_set_io(itv); ivtv_audio_set_io(itv); ivtv_unmute(itv); break; } case VIDIOC_G_OUTPUT:{ if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) return -EINVAL; *(int *)arg = itv->active_output; break; } case VIDIOC_S_OUTPUT:{ int outp = *(int *)arg; struct v4l2_routing route; if (outp >= itv->card->nof_outputs) return -EINVAL; if (outp == itv->active_output) { IVTV_DEBUG_INFO("Output unchanged\n"); break; } IVTV_DEBUG_INFO("Changing output from %d to %d\n", itv->active_output, outp); itv->active_output = outp; route.input = SAA7127_INPUT_TYPE_NORMAL; route.output = itv->card->video_outputs[outp].video_output; ivtv_saa7127(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); break; } case VIDIOC_G_FREQUENCY:{ struct v4l2_frequency *vf = arg; if (vf->tuner != 0) return -EINVAL; ivtv_call_i2c_clients(itv, cmd, arg); break; } case VIDIOC_S_FREQUENCY:{ struct v4l2_frequency vf = *(struct v4l2_frequency *)arg; if (vf.tuner != 0) return -EINVAL; ivtv_mute(itv); IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency); ivtv_call_i2c_clients(itv, cmd, &vf); ivtv_unmute(itv); break; } case VIDIOC_ENUMSTD:{ struct v4l2_standard *vs = arg; int idx = vs->index; if (idx < 0 || idx >= ARRAY_SIZE(enum_stds)) return -EINVAL; *vs = (enum_stds[idx].std & V4L2_STD_525_60) ? ivtv_std_60hz : ivtv_std_50hz; vs->index = idx; vs->id = enum_stds[idx].std; strcpy(vs->name, enum_stds[idx].name); break; } case VIDIOC_G_STD:{ *(v4l2_std_id *) arg = itv->std; break; } case VIDIOC_S_STD: { v4l2_std_id std = *(v4l2_std_id *) arg; if ((std & V4L2_STD_ALL) == 0) return -EINVAL; if (std == itv->std) break; if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) || atomic_read(&itv->capturing) > 0 || atomic_read(&itv->decoding) > 0) { /* Switching standard would turn off the radio or mess with already running streams, prevent that by returning EBUSY. */ return -EBUSY; } itv->std = std; itv->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0; itv->params.is_50hz = itv->is_50hz = !itv->is_60hz; itv->params.width = 720; itv->params.height = itv->is_50hz ? 576 : 480; itv->vbi.count = itv->is_50hz ? 18 : 12; itv->vbi.start[0] = itv->is_50hz ? 6 : 10; itv->vbi.start[1] = itv->is_50hz ? 318 : 273; if (itv->hw_flags & IVTV_HW_CX25840) { itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284; } IVTV_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)itv->std); /* Tuner */ ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std); if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { /* set display standard */ itv->std_out = std; itv->is_out_60hz = itv->is_60hz; itv->is_out_50hz = itv->is_50hz; ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std_out); ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz); itv->main_rect.left = itv->main_rect.top = 0; itv->main_rect.width = 720; itv->main_rect.height = itv->params.height; ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, 720, itv->main_rect.height, 0, 0); } break; } case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */ struct v4l2_tuner *vt = arg; if (vt->index != 0) return -EINVAL; ivtv_call_i2c_clients(itv, VIDIOC_S_TUNER, vt); break; } case VIDIOC_G_TUNER: { struct v4l2_tuner *vt = arg; if (vt->index != 0) return -EINVAL; memset(vt, 0, sizeof(*vt)); ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt); if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { strcpy(vt->name, "ivtv Radio Tuner"); vt->type = V4L2_TUNER_RADIO; } else { strcpy(vt->name, "ivtv TV Tuner"); vt->type = V4L2_TUNER_ANALOG_TV; } break; } case VIDIOC_G_SLICED_VBI_CAP: { struct v4l2_sliced_vbi_cap *cap = arg; int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; int f, l; enum v4l2_buf_type type = cap->type; memset(cap, 0, sizeof(*cap)); cap->type = type; if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { for (f = 0; f < 2; f++) { for (l = 0; l < 24; l++) { if (valid_service_line(f, l, itv->is_50hz)) { cap->service_lines[f][l] = set; } } } return 0; } if (type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) return -EINVAL; if (itv->is_60hz) { cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525; cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525; } else { cap->service_lines[0][23] = V4L2_SLICED_WSS_625; cap->service_lines[0][16] = V4L2_SLICED_VPS; } return 0; } return -EINVAL; } case VIDIOC_G_ENC_INDEX: { struct v4l2_enc_idx *idx = arg; struct v4l2_enc_idx_entry *e = idx->entry; int entries; int i; entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) % IVTV_MAX_PGM_INDEX; if (entries > V4L2_ENC_IDX_ENTRIES) entries = V4L2_ENC_IDX_ENTRIES; idx->entries = 0; for (i = 0; i < entries; i++) { *e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX]; if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) { idx->entries++; e++; } } itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX; break; } case VIDIOC_ENCODER_CMD: case VIDIOC_TRY_ENCODER_CMD: { struct v4l2_encoder_cmd *enc = arg; int try = cmd == VIDIOC_TRY_ENCODER_CMD; memset(&enc->raw, 0, sizeof(enc->raw)); switch (enc->cmd) { case V4L2_ENC_CMD_START: IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); enc->flags = 0; if (try) return 0; return ivtv_start_capture(id); case V4L2_ENC_CMD_STOP: IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; if (try) return 0; ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); return 0; case V4L2_ENC_CMD_PAUSE: IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); enc->flags = 0; if (try) return 0; if (!atomic_read(&itv->capturing)) return -EPERM; if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) return 0; ivtv_mute(itv); ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0); break; case V4L2_ENC_CMD_RESUME: IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); enc->flags = 0; if (try) return 0; if (!atomic_read(&itv->capturing)) return -EPERM; if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) return 0; ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1); ivtv_unmute(itv); break; default: IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); return -EINVAL; } break; } case VIDIOC_G_FBUF: { struct v4l2_framebuffer *fb = arg; int pixfmt; static u32 pixel_format[16] = { V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */ V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_RGB555, V4L2_PIX_FMT_RGB444, V4L2_PIX_FMT_RGB32, 0, 0, 0, V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */ V4L2_PIX_FMT_YUV565, V4L2_PIX_FMT_YUV555, V4L2_PIX_FMT_YUV444, V4L2_PIX_FMT_YUV32, 0, 0, 0, }; memset(fb, 0, sizeof(*fb)); if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -EINVAL; fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY | V4L2_FBUF_CAP_GLOBAL_ALPHA; ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); data[0] |= (read_reg(0x2a00) >> 7) & 0x40; pixfmt = (data[0] >> 3) & 0xf; fb->fmt.pixelformat = pixel_format[pixfmt]; fb->fmt.width = itv->osd_rect.width; fb->fmt.height = itv->osd_rect.height; fb->base = (void *)itv->osd_video_pbase; if (itv->osd_chroma_key_state) fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY; if (itv->osd_global_alpha_state) fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; pixfmt &= 7; /* no local alpha for RGB565 or unknown formats */ if (pixfmt == 1 || pixfmt > 4) break; /* 16-bit formats have inverted local alpha */ if (pixfmt == 2 || pixfmt == 3) fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA; else fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA; if (itv->osd_local_alpha_state) { /* 16-bit formats have inverted local alpha */ if (pixfmt == 2 || pixfmt == 3) fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA; else fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; } break; } case VIDIOC_S_FBUF: { struct v4l2_framebuffer *fb = arg; if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -EINVAL; itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; itv->osd_local_alpha_state = (fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0; itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; ivtv_set_osd_alpha(itv); break; } case VIDIOC_OVERLAY: { int *on = arg; if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -EINVAL; ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, *on != 0); break; } case VIDIOC_LOG_STATUS: { int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT; struct v4l2_input vidin; struct v4l2_audio audin; int i; IVTV_INFO("================= START STATUS CARD #%d =================\n", itv->num); IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name); if (itv->hw_flags & IVTV_HW_TVEEPROM) { struct tveeprom tv; ivtv_read_eeprom(itv, &tv); } ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL); ivtv_get_input(itv, itv->active_input, &vidin); ivtv_get_audio_input(itv, itv->audio_input, &audin); IVTV_INFO("Video Input: %s\n", vidin.name); IVTV_INFO("Audio Input: %s%s\n", audin.name, (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : ""); if (has_output) { struct v4l2_output vidout; struct v4l2_audioout audout; int mode = itv->output_mode; static const char * const output_modes[5] = { "None", "MPEG Streaming", "YUV Streaming", "YUV Frames", "Passthrough", }; static const char * const audio_modes[5] = {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -