Move call to Initialise into Constructor making sure that it only gets called once. Move channel switching out of PostCapture into just after capturing image in order to free up more time for image to stabilise while we do other things like timestamping etc which happen in Capture.

This commit is contained in:
Isaac Isaac 2021-02-23 13:11:34 -05:00
parent 0ac3e6fd5b
commit 3225851224
1 changed files with 86 additions and 81 deletions

View File

@ -340,7 +340,7 @@ LocalCamera::LocalCamera(
Debug(2, "V4L support enabled, using V4L%d api", v4l_version); Debug(2, "V4L support enabled, using V4L%d api", v4l_version);
} }
if ( !last_camera || channel != last_camera->channel ) { if ( (!last_camera) || (channel != last_camera->channel) ) {
// We are the first, or only, input that uses this channel // We are the first, or only, input that uses this channel
channel_prime = true; channel_prime = true;
channel_index = channel_count++; channel_index = channel_count++;
@ -382,19 +382,19 @@ LocalCamera::LocalCamera(
} }
#endif #endif
if ( capture ) { if (capture) {
if ( last_camera ) { if (last_camera) {
if ( (p_method == "v4l2" && v4l_version != 2) || (p_method == "v4l1" && v4l_version != 1) ) if ((p_method == "v4l2" && v4l_version != 2) || (p_method == "v4l1" && v4l_version != 1))
Fatal( "Different Video For Linux version used for monitors sharing same device" ); Fatal("Different Video For Linux version used for monitors sharing same device");
if ( standard != last_camera->standard ) if (standard != last_camera->standard)
Warning( "Different video standards defined for monitors sharing same device, results may be unpredictable or completely wrong" ); Warning("Different video standards defined for monitors sharing same device, results may be unpredictable or completely wrong");
if ( palette != last_camera->palette ) if (palette != last_camera->palette)
Warning( "Different video palettes defined for monitors sharing same device, results may be unpredictable or completely wrong" ); Warning("Different video palettes defined for monitors sharing same device, results may be unpredictable or completely wrong");
if ( width != last_camera->width || height != last_camera->height ) if (width != last_camera->width or height != last_camera->height)
Warning( "Different capture sizes defined for monitors sharing same device, results may be unpredictable or completely wrong" ); Warning("Different capture sizes defined for monitors sharing same device, results may be unpredictable or completely wrong");
} }
#if HAVE_LIBSWSCALE #if HAVE_LIBSWSCALE
@ -676,6 +676,8 @@ LocalCamera::LocalCamera(
imgConversionContext = nullptr; imgConversionContext = nullptr;
} // end if capture and conversion_tye == swscale } // end if capture and conversion_tye == swscale
#endif #endif
if ( device_prime )
Initialise();
} // end LocalCamera::LocalCamera } // end LocalCamera::LocalCamera
LocalCamera::~LocalCamera() { LocalCamera::~LocalCamera() {
@ -1971,7 +1973,10 @@ int LocalCamera::Contrast( int p_contrast ) {
} }
int LocalCamera::PrimeCapture() { int LocalCamera::PrimeCapture() {
Initialise();
get_VideoStream();
if ( !device_prime )
return 1;
Debug(2, "Priming capture"); Debug(2, "Priming capture");
#if ZM_HAS_V4L2 #if ZM_HAS_V4L2
@ -1989,8 +1994,10 @@ int LocalCamera::PrimeCapture() {
vid_buf.memory = v4l2_data.reqbufs.memory; vid_buf.memory = v4l2_data.reqbufs.memory;
vid_buf.index = frame; vid_buf.index = frame;
if ( vidioctl(vid_fd, VIDIOC_QBUF, &vid_buf) < 0 ) if (vidioctl(vid_fd, VIDIOC_QBUF, &vid_buf) < 0) {
Fatal("Failed to queue buffer %d: %s", frame, strerror(errno)); Error("Failed to queue buffer %d: %s", frame, strerror(errno));
return 0;
}
} }
v4l2_data.bufptr = nullptr; v4l2_data.bufptr = nullptr;
@ -1998,9 +2005,11 @@ int LocalCamera::PrimeCapture() {
//enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
//enum v4l2_buf_type type = v4l2_data.fmt.type; //enum v4l2_buf_type type = v4l2_data.fmt.type;
enum v4l2_buf_type type = (v4l2_buf_type)v4l2_data.fmt.type; enum v4l2_buf_type type = (v4l2_buf_type)v4l2_data.fmt.type;
if ( vidioctl(vid_fd, VIDIOC_STREAMON, &type) < 0 ) if (vidioctl(vid_fd, VIDIOC_STREAMON, &type) < 0) {
Fatal("Failed to start capture stream: %s", strerror(errno)); Error("Failed to start capture stream: %s", strerror(errno));
return -1;
} }
} // end if v4l_version == 2
#endif // ZM_HAS_V4L2 #endif // ZM_HAS_V4L2
#if ZM_HAS_V4L1 #if ZM_HAS_V4L1
if ( v4l_version == 1 ) { if ( v4l_version == 1 ) {
@ -2013,7 +2022,6 @@ int LocalCamera::PrimeCapture() {
} }
} }
#endif // ZM_HAS_V4L1 #endif // ZM_HAS_V4L1
mVideoStreamId = 0;
return 1; return 1;
} // end LocalCamera::PrimeCapture } // end LocalCamera::PrimeCapture
@ -2046,7 +2054,6 @@ int LocalCamera::Capture(ZMPacket &zm_packet) {
memset(&vid_buf, 0, sizeof(vid_buf)); memset(&vid_buf, 0, sizeof(vid_buf));
vid_buf.type = v4l2_data.fmt.type; vid_buf.type = v4l2_data.fmt.type;
//vid_buf.memory = V4L2_MEMORY_MMAP;
vid_buf.memory = v4l2_data.reqbufs.memory; vid_buf.memory = v4l2_data.reqbufs.memory;
Debug(3, "Capturing %d frames", captures_per_frame); Debug(3, "Capturing %d frames", captures_per_frame);
@ -2114,6 +2121,65 @@ int LocalCamera::Capture(ZMPacket &zm_packet) {
buffer = v4l1_data.bufptr+v4l1_data.frames.offsets[capture_frame]; buffer = v4l1_data.bufptr+v4l1_data.frames.offsets[capture_frame];
} }
#endif // ZM_HAS_V4L1 #endif // ZM_HAS_V4L1
#if ZM_HAS_V4L2
if ( v4l_version == 2 ) {
if ( channel_count > 1 ) {
int next_channel = (channel_index+1)%channel_count;
Debug(3, "Switching video source to %d", channels[next_channel]);
if ( vidioctl(vid_fd, VIDIOC_S_INPUT, &channels[next_channel]) < 0 ) {
Error("Failed to set camera source %d: %s", channels[next_channel], strerror(errno));
return -1;
}
v4l2_std_id stdId = standards[next_channel];
if ( vidioctl(vid_fd, VIDIOC_S_STD, &stdId) < 0 ) {
Error("Failed to set video format %d: %s", standards[next_channel], strerror(errno));
}
}
if ( v4l2_data.bufptr ) {
Debug(3, "Requeueing buffer %d", v4l2_data.bufptr->index);
if ( vidioctl(vid_fd, VIDIOC_QBUF, v4l2_data.bufptr) < 0 ) {
Error("Unable to requeue buffer %d: %s", v4l2_data.bufptr->index, strerror(errno));
return -1;
}
} else {
Error("Unable to requeue buffer due to not v4l2_data")
}
}
#if ZM_HAS_V4L1
else
#endif // ZM_HAS_V4L1
#endif // ZM_HAS_V4L2
#if ZM_HAS_V4L1
if ( v4l_version == 1 ) {
if ( channel_count > 1 ) {
Debug(3, "Switching video source");
int next_channel = (channel_index+1)%channel_count;
struct video_channel vid_src;
memset(&vid_src, 0, sizeof(vid_src));
vid_src.channel = channel;
if ( ioctl(vid_fd, VIDIOCGCHAN, &vid_src) < 0 ) {
Error("Failed to get camera source %d: %s", channel, strerror(errno));
return -1;
}
vid_src.channel = channels[next_channel];
vid_src.norm = standards[next_channel];
vid_src.flags = 0;
vid_src.type = VIDEO_TYPE_CAMERA;
if ( ioctl(vid_fd, VIDIOCSCHAN, &vid_src) < 0 ) {
Error("Failed to set camera source %d: %s", channel, strerror(errno));
return -1;
}
}
Debug(3, "Requeueing frame %d", v4l1_data.active_frame);
if ( ioctl(vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[v4l1_data.active_frame]) < 0 ) {
Error("Capture failure for frame %d: %s", v4l1_data.active_frame, strerror(errno));
return -1;
}
v4l1_data.active_frame = (v4l1_data.active_frame+1)%v4l1_data.frames.frames;
}
#endif // ZM_HAS_V4L1
} /* prime capture */ } /* prime capture */
@ -2179,69 +2245,8 @@ int LocalCamera::Capture(ZMPacket &zm_packet) {
} // end int LocalCamera::Capture() } // end int LocalCamera::Capture()
int LocalCamera::PostCapture() { int LocalCamera::PostCapture() {
return 1;
Debug(4, "Post-capturing"); Debug(4, "Post-capturing");
// Requeue the buffer unless we need to switch or are a duplicate camera on a channel
if ( channel_count > 1 || channel_prime ) {
#if ZM_HAS_V4L2
if ( v4l_version == 2 ) {
if ( channel_count > 1 ) {
int next_channel = (channel_index+1)%channel_count;
Debug(3, "Switching video source to %d", channels[next_channel]);
if ( vidioctl(vid_fd, VIDIOC_S_INPUT, &channels[next_channel]) < 0 ) {
Error("Failed to set camera source %d: %s", channels[next_channel], strerror(errno));
return -1;
}
v4l2_std_id stdId = standards[next_channel];
if ( vidioctl(vid_fd, VIDIOC_S_STD, &stdId) < 0 ) {
Error("Failed to set video format %d: %s", standards[next_channel], strerror(errno));
}
}
if ( v4l2_data.bufptr ) {
Debug(3, "Requeueing buffer %d", v4l2_data.bufptr->index);
if ( vidioctl(vid_fd, VIDIOC_QBUF, v4l2_data.bufptr) < 0 ) {
Error("Unable to requeue buffer %d: %s", v4l2_data.bufptr->index, strerror(errno));
return -1;
}
} else {
Error("Unable to requeue buffer due to not v4l2_data")
}
}
#if ZM_HAS_V4L1
else
#endif // ZM_HAS_V4L1
#endif // ZM_HAS_V4L2
#if ZM_HAS_V4L1
if ( v4l_version == 1 ) {
if ( channel_count > 1 ) {
Debug(3, "Switching video source");
int next_channel = (channel_index+1)%channel_count;
struct video_channel vid_src;
memset(&vid_src, 0, sizeof(vid_src));
vid_src.channel = channel;
if ( ioctl(vid_fd, VIDIOCGCHAN, &vid_src) < 0 ) {
Error("Failed to get camera source %d: %s", channel, strerror(errno));
return -1;
}
vid_src.channel = channels[next_channel];
vid_src.norm = standards[next_channel];
vid_src.flags = 0;
vid_src.type = VIDEO_TYPE_CAMERA;
if ( ioctl(vid_fd, VIDIOCSCHAN, &vid_src) < 0 ) {
Error("Failed to set camera source %d: %s", channel, strerror(errno));
return -1;
}
}
Debug(3, "Requeueing frame %d", v4l1_data.active_frame);
if ( ioctl(vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[v4l1_data.active_frame]) < 0 ) {
Error("Capture failure for frame %d: %s", v4l1_data.active_frame, strerror(errno));
return -1;
}
v4l1_data.active_frame = (v4l1_data.active_frame+1)%v4l1_data.frames.frames;
}
#endif // ZM_HAS_V4L1
}
return 0; return 0;
} }