-General idea:
+General Idea:
+=============
- / gstv4lsrc.[ch]
- / v4lsrc_calls.[ch]
- /
-gstv4lelement.[ch] ------------- gstv4lmjpegsrc.[ch]
-v4l_calls.[ch] ------------- v4lmjpegsrc_calls.[ch]
- \
- \ gstv4lmjpegsink.[ch]
- \ v4lmjpegsink_calls.[ch]
+ _____/ gstv4lsrc.[ch]
+ _____/ \ v4lsrc_calls.[ch]
+ /
+gstv4lelement.[ch] _/____________/ gstv4lmjpegsrc.[ch]
+v4l_calls.[ch] \ \ v4lmjpegsrc_calls.[ch]
+ \_____
+ \_____/ gstv4lmjpegsink.[ch]
+ \ v4lmjpegsink_calls.[ch]
-
-I.e., all the files on thei right are child classes of
-the v4lelement 'parent' on the left.mjpegsink is still
+I.e., all the files on the right are child classes of
+the v4lelement 'parent' on the left. mjpegsink is still
todo.
-Generic idea:
* v4lelement handles generic v4l stuff (picture settings,
audio, norm/input setting, open()/close())
* v4lsrc, v4lmjpegsrc handle the capture specific
functions. Maybe we'd need a v4lmpegsrc too
* v4lmjpegsink handles mjpeg hardware playback of video
+
+Useful Documentation:
+=====================
+MJPEG/V4L API : ./videodev_mjpeg.h
+V4L API : /usr/include/linux/videodev.h or
+ http://roadrunner.swansea.uk.linux.org/v4l.shtml
+V4L2 API : http://www.thedirks.org/v4l2/
+BSD/Meteor API: /usr/include/machine/ioctl_meteor.h
+mjpegtools : http://www.sourceforge.net/projects/mjpeg
v4lsrc->frame_queued[num] = TRUE;
+ pthread_mutex_lock(&(v4lsrc->mutex_queued_frames));
+ v4lsrc->num_queued_frames++;
+ pthread_cond_broadcast(&(v4lsrc->cond_queued_frames));
+ pthread_mutex_unlock(&(v4lsrc->mutex_queued_frames));
+
return TRUE;
}
+/******************************************************
+ * gst_v4lsrc_soft_sync_thread()
+ * syncs on frames and signals the main thread
+ * purpose: actually get the correct frame timestamps
+ ******************************************************/
+
+static void *
+gst_v4lsrc_soft_sync_thread (void *arg)
+{
+ GstV4lSrc *v4lsrc = GST_V4LSRC(arg);
+ guint16 frame = 0;
+
+#ifdef DEBUG
+ fprintf(stderr, "gst_v4lsrc_soft_sync_thread()\n");
+#endif
+
+ /* Allow easy shutting down by other processes... */
+ pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, NULL );
+ pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL );
+
+ while (1)
+ {
+ /* are there queued frames left? */
+ pthread_mutex_lock(&(v4lsrc->mutex_queued_frames));
+ if (v4lsrc->num_queued_frames < 1)
+ {
+ pthread_cond_wait(&(v4lsrc->cond_queued_frames),
+ &(v4lsrc->mutex_queued_frames));
+ }
+ pthread_mutex_unlock(&(v4lsrc->mutex_queued_frames));
+
+ /* if still wrong, we got interrupted and we should exit */
+ if (v4lsrc->num_queued_frames < 1)
+ {
+ goto end;
+ }
+
+ /* sync on the frame */
+retry:
+ if (ioctl(GST_V4LELEMENT(v4lsrc)->video_fd, VIDIOCSYNC, &frame) < 0)
+ {
+ /* if the sync() got interrupted, we can retry */
+ if (errno == EINTR)
+ goto retry;
+ gst_element_error(GST_ELEMENT(v4lsrc),
+ "Error syncing on a buffer (%d): %s",
+ frame, sys_errlist[errno]);
+ pthread_mutex_lock(&(v4lsrc->mutex_soft_sync));
+ v4lsrc->isready_soft_sync[frame] = -1;
+ pthread_cond_broadcast(&(v4lsrc->cond_soft_sync[frame]));
+ pthread_mutex_unlock(&(v4lsrc->mutex_soft_sync));
+ goto end;
+ }
+ else
+ {
+ pthread_mutex_lock(&(v4lsrc->mutex_soft_sync));
+ gettimeofday(&(v4lsrc->timestamp_soft_sync[frame]), NULL);
+ v4lsrc->isready_soft_sync[frame] = 1;
+ pthread_cond_broadcast(&(v4lsrc->cond_soft_sync[frame]));
+ pthread_mutex_unlock(&(v4lsrc->mutex_soft_sync));
+ }
+
+ frame = (frame+1)%v4lsrc->mbuf.frames;
+
+ pthread_mutex_lock(&(v4lsrc->mutex_queued_frames));
+ v4lsrc->num_queued_frames--;
+ pthread_mutex_unlock(&(v4lsrc->mutex_queued_frames));
+ }
+
+end:
+ gst_element_info(GST_ELEMENT(v4lsrc),
+ "Software sync thread got signalled to exit");
+ pthread_exit(NULL);
+}
+
+
/******************************************************
* gst_v4lsrc_sync_frame():
* sync on a frame for capturing
*num = (v4lsrc->sync_frame + 1)%v4lsrc->mbuf.frames;
- if (ioctl(GST_V4LELEMENT(v4lsrc)->video_fd, VIDIOCSYNC, num) < 0)
+ /* "software sync()" on the frame */
+ pthread_mutex_lock(&(v4lsrc->mutex_soft_sync));
+ if (v4lsrc->isready_soft_sync[*num])
{
- gst_element_error(GST_ELEMENT(v4lsrc),
- "Error syncing on a buffer (%d): %s",
- *num, sys_errlist[errno]);
- return FALSE;
+ pthread_cond_wait(&(v4lsrc->cond_soft_sync[*num]),
+ &(v4lsrc->mutex_soft_sync));
}
+ pthread_mutex_unlock(&(v4lsrc->mutex_soft_sync));
+
+ if (v4lsrc->isready_soft_sync[*num] < 0)
+ return FALSE;
+
+ v4lsrc->isready_soft_sync[*num] = 0;
v4lsrc->frame_queued[*num] = FALSE;
for (n=0;n<v4lsrc->mbuf.frames;n++)
v4lsrc->frame_queued[n] = FALSE;
+ /* init the pthread stuff */
+ pthread_mutex_init(&(v4lsrc->mutex_soft_sync), NULL);
+ v4lsrc->isready_soft_sync = (gint8 *) malloc(sizeof(gint8) * v4lsrc->mbuf.frames);
+ if (!v4lsrc->isready_soft_sync)
+ {
+ gst_element_error(GST_ELEMENT(v4lsrc),
+ "Error creating software-sync buffer tracker: %s",
+ sys_errlist[errno]);
+ return FALSE;
+ }
+ for (n=0;n<v4lsrc->mbuf.frames;n++)
+ v4lsrc->isready_soft_sync[n] = 0;
+ v4lsrc->timestamp_soft_sync = (struct timeval *)
+ malloc(sizeof(struct timeval) * v4lsrc->mbuf.frames);
+ if (!v4lsrc->timestamp_soft_sync)
+ {
+ gst_element_error(GST_ELEMENT(v4lsrc),
+ "Error creating software-sync timestamp tracker: %s",
+ sys_errlist[errno]);
+ return FALSE;
+ }
+ v4lsrc->cond_soft_sync = (pthread_cond_t *)
+ malloc(sizeof(pthread_cond_t) * v4lsrc->mbuf.frames);
+ if (!v4lsrc->cond_soft_sync)
+ {
+ gst_element_error(GST_ELEMENT(v4lsrc),
+ "Error creating software-sync condition tracker: %s",
+ sys_errlist[errno]);
+ return FALSE;
+ }
+ for (n=0;n<v4lsrc->mbuf.frames;n++)
+ pthread_cond_init(&(v4lsrc->cond_soft_sync[n]), NULL);
+
+ pthread_mutex_init(&(v4lsrc->mutex_queued_frames), NULL);
+ pthread_cond_init(&(v4lsrc->cond_queued_frames), NULL);
+
/* Map the buffers */
GST_V4LELEMENT(v4lsrc)->buffer = mmap(0, v4lsrc->mbuf.size,
PROT_READ, MAP_SHARED, GST_V4LELEMENT(v4lsrc)->video_fd, 0);
GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lsrc));
GST_V4L_CHECK_ACTIVE(GST_V4LELEMENT(v4lsrc));
+ v4lsrc->num_queued_frames = 0;
+
/* queue all buffers, this starts streaming capture */
for (n=0;n<v4lsrc->mbuf.frames;n++)
if (!gst_v4lsrc_queue_frame(v4lsrc, n))
v4lsrc->sync_frame = -1;
+ /* start the sync() thread (correct timestamps) */
+ if ( pthread_create( &(v4lsrc->thread_soft_sync), NULL,
+ gst_v4lsrc_soft_sync_thread, (void *) v4lsrc ) )
+ {
+ gst_element_error(GST_ELEMENT(v4lsrc),
+ "Failed to create software sync thread: %s",
+ sys_errlist[errno]);
+ return FALSE;
+ }
+
return TRUE;
}
/******************************************************
* gst_v4lsrc_get_buffer():
* get the address of the just-capture buffer
- * return value: TRUE on success, FALSE on error
+ * return value: the buffer's address or NULL
******************************************************/
guint8 *
if (!gst_v4lsrc_sync_next_frame(v4lsrc, &num))
return FALSE;
+ pthread_cancel(v4lsrc->thread_soft_sync);
+ pthread_join(v4lsrc->thread_soft_sync, NULL);
+
return TRUE;
}
/* free buffer tracker */
free(v4lsrc->frame_queued);
+ free(v4lsrc->cond_soft_sync);
+ free(v4lsrc->isready_soft_sync);
+ free(v4lsrc->timestamp_soft_sync);
/* unmap the buffer */
munmap(GST_V4LELEMENT(v4lsrc)->buffer, v4lsrc->mbuf.size);