Added pthread software sync for improved timestamps and pthread queue and sync control to make sure that frames are q...

Original commit message from CVS:
Added pthread software sync for improved timestamps and pthread queue and sync control to make sure that frames are queued if we sync on them
This commit is contained in:
Ronald S. Bultje 2001-12-23 19:14:18 +00:00
parent 6447e09f6b
commit 580121964c
5 changed files with 204 additions and 26 deletions

View file

@ -1,22 +1,30 @@
General idea:
General Idea:
=============
/ gstv4lsrc.[ch]
/ v4lsrc_calls.[ch]
_____/ gstv4lsrc.[ch]
_____/ \ v4lsrc_calls.[ch]
/
gstv4lelement.[ch] ------------- gstv4lmjpegsrc.[ch]
v4l_calls.[ch] ------------- v4lmjpegsrc_calls.[ch]
\
\ gstv4lmjpegsink.[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
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

View file

@ -1,5 +1,23 @@
TODO list (short term):
=======================
* v4lmjpegsrc: integrate input/norm autodetection
* v4lmjpegsink: build
* v4lsrc: threaded sync()
* v4lsrc: threaded wait-for-sync()-until-queue()
* BSD-src: build (based on Bt848/Bt878/Meteor API)
* libgstrec: build (a library for video recording)
* v4lmjpegsink: build (based on liblavplay (mjpegtools) and MJPEG/V4L API)
* v4lsrc: threaded sync() (done?)
* v4lsrc: threaded wait-for-sync()-until-queue() (done?)
TODO list (long term):
======================
* v4lmpegsrc: build (*hint* MPEG card needed *hint*)
* v4l2element && v4l2src: build (v4l2 supports far more features than
v4l1 so I really want seperate plugins for it)
* BSD-videosrc: build (based on Meteor API)
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

View file

@ -340,7 +340,6 @@ gst_v4lsrc_get (GstPad *pad)
GstV4lSrc *v4lsrc;
GstBuffer *buf;
gint num;
struct timeval timestamp;
g_return_val_if_fail (pad != NULL, NULL);
@ -368,10 +367,10 @@ gst_v4lsrc_get (GstPad *pad)
/* grab a frame from the device */
if (!gst_v4lsrc_grab_frame(v4lsrc, &num))
return NULL;
gettimeofday(&timestamp, 0); /* TODO: threaded sync() */
GST_BUFFER_DATA(buf) = gst_v4lsrc_get_buffer(v4lsrc, num);
GST_BUFFER_SIZE(buf) = v4lsrc->buffer_size;
buf->timestamp = timestamp.tv_sec * 1000000000 + timestamp.tv_usec * 1000;
buf->timestamp = v4lsrc->timestamp_soft_sync[num].tv_sec * 1000000000 +
v4lsrc->timestamp_soft_sync[num].tv_usec * 1000;
return buf;
}

View file

@ -59,6 +59,18 @@ struct _GstV4lSrc {
gboolean *frame_queued;
guint buffer_size;
/* a seperate pthread for the sync() thread (improves correctness of timestamps) */
gint8 *isready_soft_sync; /* 1 = ok, 0 = waiting, -1 = error */
struct timeval *timestamp_soft_sync;
pthread_t thread_soft_sync;
pthread_mutex_t mutex_soft_sync;
pthread_cond_t *cond_soft_sync;
/* num of queued frames and some pthread stuff to wait if there's not enough */
guint16 num_queued_frames;
pthread_mutex_t mutex_queued_frames;
pthread_cond_t cond_queued_frames;
/* caching values */
gint width;
gint height;

View file

@ -62,10 +62,91 @@ gst_v4lsrc_queue_frame (GstV4lSrc *v4lsrc,
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
@ -83,13 +164,19 @@ gst_v4lsrc_sync_next_frame (GstV4lSrc *v4lsrc,
*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;
@ -168,6 +255,42 @@ gst_v4lsrc_capture_init (GstV4lSrc *v4lsrc)
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);
@ -202,6 +325,8 @@ gst_v4lsrc_capture_start (GstV4lSrc *v4lsrc)
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))
@ -209,6 +334,16 @@ gst_v4lsrc_capture_start (GstV4lSrc *v4lsrc)
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;
}
@ -240,7 +375,7 @@ gst_v4lsrc_grab_frame (GstV4lSrc *v4lsrc, gint *num)
/******************************************************
* 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 *
@ -307,6 +442,9 @@ gst_v4lsrc_capture_stop (GstV4lSrc *v4lsrc)
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;
}
@ -329,6 +467,9 @@ gst_v4lsrc_capture_deinit (GstV4lSrc *v4lsrc)
/* 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);