Mercurial > mplayer.hg
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++) |