#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 */
staticint ivtv_prep_dev(struct ivtv *itv, int type)
{ struct ivtv_stream *s = &itv->streams[type]; int num_offset = ivtv_stream_info[type].num_offset; int num = itv->instance + ivtv_first_minor + num_offset;
/* These four fields are always initialized. If vdev.v4l2_dev == NULL, then thisstreamisnotinuse.Inthatcasenootherfieldsbutthese
four can be used. */
s->vdev.v4l2_dev = 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)) return0; if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) return0;
/* User explicitly selected 0 buffers for these streams, so don't
create them. */ if (ivtv_stream_info[type].dma != DMA_NONE &&
itv->options.kilobytes[type] == 0) {
IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name); return0;
}
/* 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].vdev.v4l2_dev == NULL) continue;
/* Allocate Stream */ if (ivtv_stream_alloc(&itv->streams[type])) break;
} if (type == IVTV_MAX_STREAMS) return0;
/* One or more streams could not be initialized. Clean 'em all up. */
ivtv_streams_cleanup(itv); return -ENOMEM;
}
staticint ivtv_reg_dev(struct ivtv *itv, int type)
{ struct ivtv_stream *s = &itv->streams[type]; int vfl_type = ivtv_stream_info[type].vfl_type; constchar *name; int num;
if (s->vdev.v4l2_dev == NULL) return0;
num = s->vdev.num; /* card number + user defined offset + device offset */ if (type != IVTV_ENC_STREAM_TYPE_MPG) { struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG];
if (s_mpg->vdev.v4l2_dev)
num = s_mpg->vdev.num + ivtv_stream_info[type].num_offset;
} if (itv->osd_video_pbase && (type == IVTV_DEC_STREAM_TYPE_YUV ||
type == IVTV_DEC_STREAM_TYPE_MPG)) {
s->vdev.device_caps |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
itv->v4l2_cap |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
}
video_set_drvdata(&s->vdev, s);
/* Register device. First try the desired minor, then any free one. */ if (video_register_device_no_warn(&s->vdev, vfl_type, num)) {
IVTV_ERR("Couldn't register v4l2 device for %s (device node number %d)\n",
s->name, num); return -ENOMEM;
}
name = video_device_node_name(&s->vdev);
switch (vfl_type) { case VFL_TYPE_VIDEO:
IVTV_INFO("Registered device %s for %s (%d kB)\n",
name, s->name, itv->options.kilobytes[type]); break; case VFL_TYPE_RADIO:
IVTV_INFO("Registered device %s for %s\n",
name, s->name); break; case VFL_TYPE_VBI: if (itv->options.kilobytes[type])
IVTV_INFO("Registered device %s for %s (%d kB)\n",
name, s->name, itv->options.kilobytes[type]); else
IVTV_INFO("Registered device %s for %s\n",
name, s->name); break;
} return0;
}
/* 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) return0;
/* One or more streams could not be initialized. Clean 'em all up. */
ivtv_streams_cleanup(itv); return -ENOMEM;
}
/* 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 : 4 * (itv->vbi.raw_size / itv->vbi.enc_size); /* The start/stop codes determine which VBI lines end up in the raw VBI data area. Thecodesarefromtable24inthesaa7115datasheet.Eachraw/sliced/videoline isframedwithcodesFF0000XXwhereXXistheSAV/EAV(Start/EndofActiveVideo) code.ThesevaluesforrawVBIareobtainedfromadriverdisassembly.Thesliced start/stopcodeswasdeducedfromthis,buttheydonotappearinthedriver. OthercodepairsthatIfoundare:0x250E6249/0x13545454and0x25256262/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;
}
/* 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: -IsitpossibletoselectparticularVBIlinesonlyforinclusionintheMPEG stream?CurrentlyyoucanonlygetthefirstXlines. -IsmixedrawandslicedVBIpossible? -What'sthemeaningoftheraw/slicedflag?
- 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; int captype = 0, subtype = 0; int enable_passthrough = 0;
/* Clear Streamoff flags in case left from last capture */
clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
if (atomic_read(&itv->capturing) == 0) { int digitizer;
/* Always use frame based mode. Experiments have demonstrated that byte streambasedmoderesultsindroppedframesandcorruption.Notoften, butoccasionally.ManythanksgotoLeonardOrbwhospentalotof
effort and time trying to trace the cause of the drop outs. */ /* 1 frame per DMA */ /*ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 128, 0); */
ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 1, 1);
/* Stuff from Windows, we don't know what it is */
ivtv_vapi(itv, CX2341X_ENC_SET_VERT_CROP_LINE, 1, 0); /* According to the docs, this should be correct. However, this is untested.Idon'tdareenablethiswithouthavingtestedit. Onlyveryfewoldcardsactuallyhavethishardwarecombination. ivtv_vapi(itv,CX2341X_ENC_SET_VERT_CROP_LINE,1, ((itv->hw_flags&IVTV_HW_SAA7114)&&itv->is_60hz)?10001:0);
*/
ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 3, !itv->has_cx23415);
ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 8, 0);
ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 4, 1);
ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);
/* set audio mode to left/stereo for dual/stereo mode. */
ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
/* set number of internal decoder buffers */
ivtv_vapi(itv, CX2341X_DEC_SET_DISPLAY_BUFFERS, 1, 0);
/* Let things settle before we actually start */
ivtv_msleep_timeout(10, 0);
/* Clear the following Interrupt mask bits for decoding */
ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_DECODE);
IVTV_DEBUG_IRQ("IRQ Mask is now: 0x%08x\n", itv->irqmask);
/* you're live! sit back and await interrupts :) */
atomic_inc(&itv->decoding); return0;
}
void ivtv_stop_all_captures(struct ivtv *itv)
{ int i;
for (i = IVTV_MAX_STREAMS - 1; i >= 0; i--) { struct ivtv_stream *s = &itv->streams[i];
if (s->vdev.v4l2_dev == NULL) continue; if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
ivtv_stop_v4l2_encode_stream(s, 0);
}
}
}
int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
{ struct ivtv *itv = s->itv;
DECLARE_WAITQUEUE(wait, current); int cap_type; int stopmode;
if (s->vdev.v4l2_dev == NULL) return -EINVAL;
/* This function assumes that you are allowed to stop the capture
and that we are actually capturing */
IVTV_DEBUG_INFO("Stop Capture\n");
if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) return0; if (atomic_read(&itv->capturing) == 0) return0;
switch (s->type) { case IVTV_ENC_STREAM_TYPE_YUV:
cap_type = 1; break; case IVTV_ENC_STREAM_TYPE_PCM:
cap_type = 1; break; case IVTV_ENC_STREAM_TYPE_VBI:
cap_type = 1; break; case IVTV_ENC_STREAM_TYPE_MPG: default:
cap_type = 0; break;
}
if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) { if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) { /* only run these if we're shutting down the last cap */ unsignedlong duration; unsignedlong then = jiffies;
add_wait_queue(&itv->eos_waitq, &wait);
set_current_state(TASK_INTERRUPTIBLE);
/* wait 2s for EOS interrupt */ while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) &&
time_before(jiffies,
then + msecs_to_jiffies(2000))) {
schedule_timeout(msecs_to_jiffies(10));
}
/* To convert jiffies to ms, we must multiply by 1000 *anddividebyHZ.Toavoidruntimedivision,we *convertthistomultiplicationby1000/HZ. *Sinceintegerdivisiontruncates,wegetthebest *accuracyifwedoaroundingcalculationoftheconstant. *ThinkofthecasewhereHZis1024.
*/
duration = ((1000 + HZ / 2) / HZ) * (jiffies - then);
if (!test_bit(IVTV_F_I_EOS, &itv->i_flags)) {
IVTV_DEBUG_WARN("%s: EOS interrupt not received! stopping anyway.\n", s->name);
IVTV_DEBUG_WARN("%s: waited %lu ms.\n", s->name, duration);
} else {
IVTV_DEBUG_INFO("%s: EOS took %lu ms to occur.\n", s->name, duration);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&itv->eos_waitq, &wait);
set_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
}
/* Handle any pending interrupts */
ivtv_msleep_timeout(100, 0);
}
atomic_dec(&itv->capturing);
/* Clear capture and no-read bits */
clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP);
if (atomic_read(&itv->capturing) > 0) { return0;
}
cx2341x_handler_set_busy(&itv->cxhdl, 0);
/* Set the following Interrupt mask bits for capture */
ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
timer_delete(&itv->dma_timer);
/* Raw-passthrough is implied on start. Make sure it's stopped so
the encoder will re-initialize when next started */
ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, 1, 2, 7);
/* Prevent others from starting/stopping streams while we
initiate/terminate passthrough mode */ if (enable) { if (itv->output_mode == OUT_PASSTHROUGH) { return0;
} if (ivtv_set_output_mode(itv, OUT_PASSTHROUGH) != OUT_PASSTHROUGH) return -EBUSY;
/* Fully initialize stream, and then unflag init */
set_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags);
set_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.