comparison libmpdemux/tvi_v4l.c @ 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 0e1d45e44813
children 78d1fc838e3c
comparison
equal deleted inserted replaced
8416:a2e82bc939ae 8417:15e3d9c2c0ac
57 #define NTSC_HEIGHT 480 57 #define NTSC_HEIGHT 480
58 #define NTSC_FPS 30 58 #define NTSC_FPS 30
59 59
60 #define MAX_AUDIO_CHANNELS 10 60 #define MAX_AUDIO_CHANNELS 10
61 61
62 #define VID_BUF_SIZE_IMMEDIATE 3 62 #define VID_BUF_SIZE_IMMEDIATE 2
63 63
64 typedef struct { 64 typedef struct {
65 /* general */ 65 /* general */
66 char *video_device; 66 char *video_device;
67 int video_fd; 67 int video_fd;
105 volatile double audio_skew_factor; 105 volatile double audio_skew_factor;
106 volatile long long audio_skew_measure_time; 106 volatile long long audio_skew_measure_time;
107 volatile int audio_drop; 107 volatile int audio_drop;
108 108
109 int first; 109 int first;
110 int video_buffer_size; 110 int video_buffer_size_max;
111 unsigned char *video_ringbuffer; 111 volatile int video_buffer_size_current;
112 long long *video_timebuffer; 112 unsigned char **video_ringbuffer;
113 long long *video_timebuffer;
113 volatile int video_head; 114 volatile int video_head;
114 volatile int video_tail; 115 volatile int video_tail;
115 volatile int video_cnt; 116 volatile int video_cnt;
116 117
117 volatile int shutdown; 118 volatile int shutdown;
118 119
119 pthread_t audio_grabber_thread; 120 pthread_t audio_grabber_thread;
120 pthread_t video_grabber_thread; 121 pthread_t video_grabber_thread;
121 pthread_mutex_t audio_starter; 122 pthread_mutex_t audio_starter;
122 pthread_mutex_t skew_mutex; 123 pthread_mutex_t skew_mutex;
124 pthread_mutex_t video_buffer_mutex;
123 125
124 long long starttime; 126 long long starttime;
125 double audio_secs_per_block; 127 double audio_secs_per_block;
126 long long audio_skew_total; 128 long long audio_skew_total;
127 long audio_recv_blocks_total; 129 long audio_recv_blocks_total;
554 if (!tv_param_noaudio) { 556 if (!tv_param_noaudio) {
555 pthread_join(priv->audio_grabber_thread, NULL); 557 pthread_join(priv->audio_grabber_thread, NULL);
556 pthread_mutex_destroy(&priv->audio_starter); 558 pthread_mutex_destroy(&priv->audio_starter);
557 pthread_mutex_destroy(&priv->skew_mutex); 559 pthread_mutex_destroy(&priv->skew_mutex);
558 } 560 }
561 pthread_mutex_destroy(&priv->video_buffer_mutex);
559 pthread_join(priv->video_grabber_thread, NULL); 562 pthread_join(priv->video_grabber_thread, NULL);
560 mp_msg(MSGT_TV, MSGL_V, "done\n"); 563 mp_msg(MSGT_TV, MSGL_V, "done\n");
561 564
562 priv->audio[priv->audio_id].volume = 0; 565 priv->audio[priv->audio_id].volume = 0;
563 priv->audio[priv->audio_id].flags |= VIDEO_AUDIO_MUTE; 566 priv->audio[priv->audio_id].flags |= VIDEO_AUDIO_MUTE;
565 568
566 close(priv->video_fd); 569 close(priv->video_fd);
567 570
568 audio_in_uninit(&priv->audio_in); 571 audio_in_uninit(&priv->audio_in);
569 572
570 if (priv->video_ringbuffer) 573 if (priv->video_ringbuffer) {
574 int i;
575 for (i = 0; i < priv->video_buffer_size_current; i++) {
576 free(priv->video_ringbuffer[i]);
577 }
571 free(priv->video_ringbuffer); 578 free(priv->video_ringbuffer);
579 }
580
572 if (priv->video_timebuffer) 581 if (priv->video_timebuffer)
573 free(priv->video_timebuffer); 582 free(priv->video_timebuffer);
574 if (!tv_param_noaudio) { 583 if (!tv_param_noaudio) {
575 if (priv->audio_ringbuffer) 584 if (priv->audio_ringbuffer)
576 free(priv->audio_ringbuffer); 585 free(priv->audio_ringbuffer);
719 priv->audio_sent_blocks_total = 0; 728 priv->audio_sent_blocks_total = 0;
720 } 729 }
721 730
722 /* setup video parameters */ 731 /* setup video parameters */
723 if (priv->immediate_mode) { 732 if (priv->immediate_mode) {
724 priv->video_buffer_size = VID_BUF_SIZE_IMMEDIATE; 733 priv->video_buffer_size_max = VID_BUF_SIZE_IMMEDIATE;
725 } else { 734 } else {
726 priv->video_buffer_size = get_capture_buffer_size(priv); 735 priv->video_buffer_size_max = get_capture_buffer_size(priv);
727 } 736 }
737 priv->video_buffer_size_current = 0;
728 738
729 if (!tv_param_noaudio) { 739 if (!tv_param_noaudio) {
730 if (priv->video_buffer_size < 3.0*priv->fps*priv->audio_secs_per_block) { 740 if (priv->video_buffer_size_max < 3.0*priv->fps*priv->audio_secs_per_block) {
731 mp_msg(MSGT_TV, MSGL_ERR, "Video buffer shorter than 3 times audio frame duration.\n" 741 mp_msg(MSGT_TV, MSGL_ERR, "Video buffer shorter than 3 times audio frame duration.\n"
732 "You will probably experience heavy framedrops.\n"); 742 "You will probably experience heavy framedrops.\n");
733 } 743 }
734 } 744 }
735 745
736 mp_msg(MSGT_TV, MSGL_V, "Allocating a ring buffer for %d frames, %d MB total size.\n", 746 mp_msg(MSGT_TV, MSGL_V, "Using a ring buffer for maximum %d frames, %d MB total size.\n",
737 priv->video_buffer_size, 747 priv->video_buffer_size_max,
738 priv->video_buffer_size*priv->height*priv->bytesperline/(1024*1024)); 748 priv->video_buffer_size_max*priv->height*priv->bytesperline/(1024*1024));
739 749
740 priv->video_ringbuffer = (unsigned char*)malloc(priv->bytesperline * priv->height * priv->video_buffer_size); 750 priv->video_ringbuffer = (unsigned char**)malloc(priv->video_buffer_size_max*sizeof(unsigned char*));
741 if (!priv->video_ringbuffer) { 751 if (!priv->video_ringbuffer) {
742 mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate video buffer: %s\n", strerror(errno)); 752 mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate video buffer: %s\n", strerror(errno));
743 return 0; 753 return 0;
744 } 754 }
745 priv->video_timebuffer = (long long*)malloc(sizeof(long long) * priv->video_buffer_size); 755 for (i = 0; i < priv->video_buffer_size_max; i++)
756 priv->video_ringbuffer[i] = NULL;
757
758 priv->video_timebuffer = (long long*)malloc(sizeof(long long) * priv->video_buffer_size_max);
746 if (!priv->video_timebuffer) { 759 if (!priv->video_timebuffer) {
747 mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate time buffer: %s\n", strerror(errno)); 760 mp_msg(MSGT_TV, MSGL_ERR, "cannot allocate time buffer: %s\n", strerror(errno));
748 return 0; 761 return 0;
749 } 762 }
750 priv->video_head = 0; 763 priv->video_head = 0;
778 pthread_mutex_init(&priv->audio_starter, NULL); 791 pthread_mutex_init(&priv->audio_starter, NULL);
779 pthread_mutex_init(&priv->skew_mutex, NULL); 792 pthread_mutex_init(&priv->skew_mutex, NULL);
780 pthread_mutex_lock(&priv->audio_starter); 793 pthread_mutex_lock(&priv->audio_starter);
781 pthread_create(&priv->audio_grabber_thread, NULL, audio_grabber, priv); 794 pthread_create(&priv->audio_grabber_thread, NULL, audio_grabber, priv);
782 } 795 }
796 pthread_mutex_init(&priv->video_buffer_mutex, NULL);
783 /* we'll launch the video capture later, when a first request for a frame arrives */ 797 /* we'll launch the video capture later, when a first request for a frame arrives */
784 798
785 return(1); 799 return(1);
786 } 800 }
787 801
1204 for (framecount = 0; !priv->shutdown;) 1218 for (framecount = 0; !priv->shutdown;)
1205 { 1219 {
1206 for (i = 0; i < priv->nbuf && !priv->shutdown; i++, framecount++) { 1220 for (i = 0; i < priv->nbuf && !priv->shutdown; i++, framecount++) {
1207 1221
1208 if (priv->immediate_mode) { 1222 if (priv->immediate_mode) {
1209 while ((priv->video_tail+1) % priv->video_buffer_size == priv->video_head) { 1223 while (priv->video_cnt == priv->video_buffer_size_max) {
1210 usleep(10000); 1224 usleep(10000);
1211 if (priv->shutdown) { 1225 if (priv->shutdown) {
1212 return NULL; 1226 return NULL;
1213 } 1227 }
1214 } 1228 }
1272 mp_msg(MSGT_TV, MSGL_DBG3, "vcnt = %d, acnt = %d\n", priv->video_cnt, priv->audio_cnt); 1286 mp_msg(MSGT_TV, MSGL_DBG3, "vcnt = %d, acnt = %d\n", priv->video_cnt, priv->audio_cnt);
1273 1287
1274 prev_skew = skew; 1288 prev_skew = skew;
1275 prev_interval = interval; 1289 prev_interval = interval;
1276 1290
1277 if ((priv->video_tail+1) % priv->video_buffer_size == priv->video_head) { 1291 /* allocate a new buffer, if needed */
1292 pthread_mutex_lock(&priv->video_buffer_mutex);
1293 if (priv->video_buffer_size_current < priv->video_buffer_size_max) {
1294 if (priv->video_cnt == priv->video_buffer_size_current) {
1295 unsigned char *newbuf = (unsigned char*)malloc(priv->bytesperline * priv->height);
1296 if (newbuf) {
1297 memmove(priv->video_ringbuffer+priv->video_tail+1, priv->video_ringbuffer+priv->video_tail,
1298 (priv->video_buffer_size_current-priv->video_tail)*sizeof(unsigned char *));
1299 memmove(priv->video_timebuffer+priv->video_tail+1, priv->video_timebuffer+priv->video_tail,
1300 (priv->video_buffer_size_current-priv->video_tail)*sizeof(long long));
1301 priv->video_ringbuffer[priv->video_tail] = newbuf;
1302 if ((priv->video_head >= priv->video_tail) && (priv->video_cnt > 0)) priv->video_head++;
1303 priv->video_buffer_size_current++;
1304 }
1305 }
1306 }
1307 pthread_mutex_unlock(&priv->video_buffer_mutex);
1308
1309 if (priv->video_cnt == priv->video_buffer_size_current) {
1278 if (!priv->immediate_mode) { 1310 if (!priv->immediate_mode) {
1279 mp_msg(MSGT_TV, MSGL_ERR, "\nvideo buffer full - dropping frame\n"); 1311 mp_msg(MSGT_TV, MSGL_ERR, "\nvideo buffer full - dropping frame\n");
1280 } 1312 }
1281 } else { 1313 } else {
1282 if (priv->immediate_mode) { 1314 if (priv->immediate_mode) {
1286 // negative skew => there are more audio samples, increase interval 1318 // negative skew => there are more audio samples, increase interval
1287 // positive skew => less samples, shorten the interval 1319 // positive skew => less samples, shorten the interval
1288 priv->video_timebuffer[priv->video_tail] = interval - skew; 1320 priv->video_timebuffer[priv->video_tail] = interval - skew;
1289 } 1321 }
1290 1322
1291 copy_frame(priv, priv->video_ringbuffer+(priv->video_tail)*fsize, priv->mmap+priv->mbuf.offsets[frame]); 1323 copy_frame(priv, priv->video_ringbuffer[priv->video_tail], priv->mmap+priv->mbuf.offsets[frame]);
1292 priv->video_tail = (priv->video_tail+1)%priv->video_buffer_size; 1324 priv->video_tail = (priv->video_tail+1)%priv->video_buffer_size_current;
1293 priv->video_cnt++; 1325 priv->video_cnt++;
1294 } 1326 }
1295 1327
1296 } 1328 }
1297 1329
1306 if (priv->first) { 1338 if (priv->first) {
1307 pthread_create(&priv->video_grabber_thread, NULL, video_grabber, priv); 1339 pthread_create(&priv->video_grabber_thread, NULL, video_grabber, priv);
1308 priv->first = 0; 1340 priv->first = 0;
1309 } 1341 }
1310 1342
1311 while (priv->video_head == priv->video_tail) { 1343 while (priv->video_cnt == 0) {
1312 usleep(10000); 1344 usleep(10000);
1313 } 1345 }
1314 1346
1347 pthread_mutex_lock(&priv->video_buffer_mutex);
1315 interval = (double)priv->video_timebuffer[priv->video_head]*1e-6; 1348 interval = (double)priv->video_timebuffer[priv->video_head]*1e-6;
1316 memcpy(buffer, priv->video_ringbuffer+priv->video_head*priv->bytesperline * priv->height, len); 1349 memcpy(buffer, priv->video_ringbuffer[priv->video_head], len);
1317 priv->video_cnt--; 1350 priv->video_cnt--;
1318 priv->video_head = (++priv->video_head)%priv->video_buffer_size; 1351 priv->video_head = (++priv->video_head)%priv->video_buffer_size_current;
1352 pthread_mutex_unlock(&priv->video_buffer_mutex);
1319 return interval; 1353 return interval;
1320 } 1354 }
1321 1355
1322 static int get_video_framesize(priv_t *priv) 1356 static int get_video_framesize(priv_t *priv)
1323 { 1357 {
1327 static void *audio_grabber(void *data) 1361 static void *audio_grabber(void *data)
1328 { 1362 {
1329 priv_t *priv = (priv_t*)data; 1363 priv_t *priv = (priv_t*)data;
1330 struct timeval tv; 1364 struct timeval tv;
1331 int i, audio_skew_ptr = 0; 1365 int i, audio_skew_ptr = 0;
1332 long long /*tmp,*/ current_time, prev_skew = 0; 1366 long long current_time, prev_skew = 0;
1333 1367
1334 pthread_mutex_lock(&priv->audio_starter); 1368 pthread_mutex_lock(&priv->audio_starter);
1335 1369
1336 audio_in_start_capture(&priv->audio_in); 1370 audio_in_start_capture(&priv->audio_in);
1337 for (i = 0; i < priv->aud_skew_cnt; i++) 1371 for (i = 0; i < priv->aud_skew_cnt; i++)