changeset 8417:15e3d9c2c0ac

allocate the video buffer on the fly, instead of one big chunk at startup
author henry
date Tue, 10 Dec 2002 09:11:42 +0000
parents a2e82bc939ae
children d40800e52617
files libmpdemux/tvi_v4l.c
diffstat 1 files changed, 55 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/libmpdemux/tvi_v4l.c	Tue Dec 10 00:13:09 2002 +0000
+++ b/libmpdemux/tvi_v4l.c	Tue Dec 10 09:11:42 2002 +0000
@@ -59,7 +59,7 @@
 
 #define MAX_AUDIO_CHANNELS	10
 
-#define VID_BUF_SIZE_IMMEDIATE 3
+#define VID_BUF_SIZE_IMMEDIATE 2
 
 typedef struct {
     /* general */
@@ -107,9 +107,10 @@
     volatile int                audio_drop;
 
     int                         first;
-    int                         video_buffer_size;
-    unsigned char		*video_ringbuffer;
-    long long			*video_timebuffer;
+    int                         video_buffer_size_max;
+    volatile int                video_buffer_size_current;
+    unsigned char		**video_ringbuffer;
+    long long                   *video_timebuffer;
     volatile int		video_head;
     volatile int		video_tail;
     volatile int		video_cnt;
@@ -120,6 +121,7 @@
     pthread_t			video_grabber_thread;
     pthread_mutex_t             audio_starter;
     pthread_mutex_t             skew_mutex;
+    pthread_mutex_t             video_buffer_mutex;
 
     long long                   starttime;
     double                      audio_secs_per_block;
@@ -556,6 +558,7 @@
 	pthread_mutex_destroy(&priv->audio_starter);
 	pthread_mutex_destroy(&priv->skew_mutex);
     }
+    pthread_mutex_destroy(&priv->video_buffer_mutex);
     pthread_join(priv->video_grabber_thread, NULL);
     mp_msg(MSGT_TV, MSGL_V, "done\n");
 
@@ -567,8 +570,14 @@
 
     audio_in_uninit(&priv->audio_in);
 
-    if (priv->video_ringbuffer)
+    if (priv->video_ringbuffer) {
+	int i;
+	for (i = 0; i < priv->video_buffer_size_current; i++) {
+	    free(priv->video_ringbuffer[i]);
+	}
 	free(priv->video_ringbuffer);
+    }
+    
     if (priv->video_timebuffer)
 	free(priv->video_timebuffer);
     if (!tv_param_noaudio) {
@@ -721,28 +730,32 @@
 
     /* setup video parameters */
     if (priv->immediate_mode) {
-	priv->video_buffer_size = VID_BUF_SIZE_IMMEDIATE;
+	priv->video_buffer_size_max = VID_BUF_SIZE_IMMEDIATE;
     } else {
-	priv->video_buffer_size = get_capture_buffer_size(priv);
+	priv->video_buffer_size_max = get_capture_buffer_size(priv);
     }
+    priv->video_buffer_size_current = 0;
 
     if (!tv_param_noaudio) {
-	if (priv->video_buffer_size < 3.0*priv->fps*priv->audio_secs_per_block) {
+	if (priv->video_buffer_size_max < 3.0*priv->fps*priv->audio_secs_per_block) {
 	    mp_msg(MSGT_TV, MSGL_ERR, "Video buffer shorter than 3 times audio frame duration.\n"
 		   "You will probably experience heavy framedrops.\n");
 	}
     }
 
-    mp_msg(MSGT_TV, MSGL_V, "Allocating a ring buffer for %d frames, %d MB total size.\n",
-	   priv->video_buffer_size,
-	   priv->video_buffer_size*priv->height*priv->bytesperline/(1024*1024));
+    mp_msg(MSGT_TV, MSGL_V, "Using a ring buffer for maximum %d frames, %d MB total size.\n",
+	   priv->video_buffer_size_max,
+	   priv->video_buffer_size_max*priv->height*priv->bytesperline/(1024*1024));
 
-    priv->video_ringbuffer = (unsigned char*)malloc(priv->bytesperline * priv->height * priv->video_buffer_size);
+    priv->video_ringbuffer = (unsigned char**)malloc(priv->video_buffer_size_max*sizeof(unsigned char*));
     if (!priv->video_ringbuffer) {
 	mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate video buffer: %s\n", strerror(errno));
 	return 0;
     }
-    priv->video_timebuffer = (long long*)malloc(sizeof(long long) * priv->video_buffer_size);
+    for (i = 0; i < priv->video_buffer_size_max; i++)
+	priv->video_ringbuffer[i] = NULL;
+    
+    priv->video_timebuffer = (long long*)malloc(sizeof(long long) * priv->video_buffer_size_max);
     if (!priv->video_timebuffer) {
 	mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate time buffer: %s\n", strerror(errno));
 	return 0;
@@ -780,6 +793,7 @@
 	pthread_mutex_lock(&priv->audio_starter);
 	pthread_create(&priv->audio_grabber_thread, NULL, audio_grabber, priv);
     }
+    pthread_mutex_init(&priv->video_buffer_mutex, NULL);
     /* we'll launch the video capture later, when a first request for a frame arrives */
 
     return(1);
@@ -1206,7 +1220,7 @@
 	for (i = 0; i < priv->nbuf && !priv->shutdown; i++, framecount++) {
 
 	    if (priv->immediate_mode) {
-		while ((priv->video_tail+1) % priv->video_buffer_size == priv->video_head) {
+		while (priv->video_cnt == priv->video_buffer_size_max) {
 		    usleep(10000);
                     if (priv->shutdown) {
                       return NULL;
@@ -1274,7 +1288,25 @@
 	    prev_skew = skew;
 	    prev_interval = interval;
 	    
-	    if ((priv->video_tail+1) % priv->video_buffer_size == priv->video_head) {
+	    /* allocate a new buffer, if needed */
+	    pthread_mutex_lock(&priv->video_buffer_mutex);
+	    if (priv->video_buffer_size_current < priv->video_buffer_size_max) {
+		if (priv->video_cnt == priv->video_buffer_size_current) {
+		    unsigned char *newbuf = (unsigned char*)malloc(priv->bytesperline * priv->height);
+		    if (newbuf) {
+			memmove(priv->video_ringbuffer+priv->video_tail+1, priv->video_ringbuffer+priv->video_tail,
+			       (priv->video_buffer_size_current-priv->video_tail)*sizeof(unsigned char *));
+			memmove(priv->video_timebuffer+priv->video_tail+1, priv->video_timebuffer+priv->video_tail,
+			       (priv->video_buffer_size_current-priv->video_tail)*sizeof(long long));
+			priv->video_ringbuffer[priv->video_tail] = newbuf;
+			if ((priv->video_head >= priv->video_tail) && (priv->video_cnt > 0)) priv->video_head++;
+			priv->video_buffer_size_current++;
+		    }
+		}
+	    }
+	    pthread_mutex_unlock(&priv->video_buffer_mutex);
+
+	    if (priv->video_cnt == priv->video_buffer_size_current) {
 		if (!priv->immediate_mode) {
 		    mp_msg(MSGT_TV, MSGL_ERR, "\nvideo buffer full - dropping frame\n");
 		}
@@ -1288,8 +1320,8 @@
 		    priv->video_timebuffer[priv->video_tail] = interval - skew;
 		}
 		
-		copy_frame(priv, priv->video_ringbuffer+(priv->video_tail)*fsize, priv->mmap+priv->mbuf.offsets[frame]);
-		priv->video_tail = (priv->video_tail+1)%priv->video_buffer_size;
+		copy_frame(priv, priv->video_ringbuffer[priv->video_tail], priv->mmap+priv->mbuf.offsets[frame]);
+		priv->video_tail = (priv->video_tail+1)%priv->video_buffer_size_current;
 		priv->video_cnt++;
 	    }
 
@@ -1308,14 +1340,16 @@
 	priv->first = 0;
     }
 
-    while (priv->video_head == priv->video_tail) {
+    while (priv->video_cnt == 0) {
 	usleep(10000);
     }
 
+    pthread_mutex_lock(&priv->video_buffer_mutex);
     interval = (double)priv->video_timebuffer[priv->video_head]*1e-6;
-    memcpy(buffer, priv->video_ringbuffer+priv->video_head*priv->bytesperline * priv->height, len);
+    memcpy(buffer, priv->video_ringbuffer[priv->video_head], len);
     priv->video_cnt--;
-    priv->video_head = (++priv->video_head)%priv->video_buffer_size;
+    priv->video_head = (++priv->video_head)%priv->video_buffer_size_current;
+    pthread_mutex_unlock(&priv->video_buffer_mutex);
     return interval;
 }
 
@@ -1329,7 +1363,7 @@
     priv_t *priv = (priv_t*)data;
     struct timeval tv;
     int i, audio_skew_ptr = 0;
-    long long /*tmp,*/ current_time, prev_skew = 0;
+    long long current_time, prev_skew = 0;
 
     pthread_mutex_lock(&priv->audio_starter);