Mercurial > mplayer.hg
comparison stream/tvi_v4l2.c @ 37126:6db1f7a10803
Use correct type of timestamps when recording from v4l2. Fix #2176
Patch by Jarek Czekalski <jarekczek at poczta onet pl>.
author | iive |
---|---|
date | Tue, 10 Jun 2014 15:41:02 +0000 |
parents | 389d43c448b3 |
children | ca7e13830a05 |
comparison
equal
deleted
inserted
replaced
37125:1236e38abf90 | 37126:6db1f7a10803 |
---|---|
61 #include "libmpcodecs/dec_teletext.h" | 61 #include "libmpcodecs/dec_teletext.h" |
62 #include "libaf/af_format.h" | 62 #include "libaf/af_format.h" |
63 #include "tv.h" | 63 #include "tv.h" |
64 #include "audio_in.h" | 64 #include "audio_in.h" |
65 | 65 |
66 // flag introduced in kernel 3.10 | |
67 #ifndef V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC | |
68 #define V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC 0x2000 | |
69 #endif | |
70 | |
66 #define info tvi_info_v4l2 | 71 #define info tvi_info_v4l2 |
67 static tvi_handle_t *tvi_init_v4l2(tv_param_t* tv_param); | 72 static tvi_handle_t *tvi_init_v4l2(tv_param_t* tv_param); |
68 /* information about this file */ | 73 /* information about this file */ |
69 const tvi_info_t tvi_info_v4l2 = { | 74 const tvi_info_t tvi_info_v4l2 = { |
70 tvi_init_v4l2, | 75 tvi_init_v4l2, |
107 struct v4l2_standard standard; | 112 struct v4l2_standard standard; |
108 struct v4l2_tuner tuner; | 113 struct v4l2_tuner tuner; |
109 struct map *map; | 114 struct map *map; |
110 int mapcount; | 115 int mapcount; |
111 int frames; | 116 int frames; |
112 volatile long long first_frame; | 117 volatile long long first_frame; ///< number of useconds |
113 long long curr_frame; | 118 long long curr_frame; ///< usec, using kernel timestamps |
119 int clk_id; /**< clk_id from clock_gettime | |
120 used in frame timestamps */ | |
114 /* audio video interleaving ;-) */ | 121 /* audio video interleaving ;-) */ |
115 volatile int streamon; | 122 volatile int streamon; |
116 pthread_t audio_grabber_thread; | 123 pthread_t audio_grabber_thread; |
117 pthread_mutex_t skew_mutex; | 124 pthread_mutex_t skew_mutex; |
118 | 125 |
486 } | 493 } |
487 } while (priv->standard.id != id); | 494 } while (priv->standard.id != id); |
488 return 0; | 495 return 0; |
489 } | 496 } |
490 | 497 |
498 /* | |
499 ** Gets current timestamp, using specified clock id. | |
500 ** @return number of microseconds. | |
501 */ | |
502 static long long get_curr_timestamp(int clk_id) | |
503 { | |
504 struct timespec ts; | |
505 clock_gettime(clk_id, &ts); | |
506 return (long long)ts.tv_sec * 1000000 + ts.tv_nsec / 1000; | |
507 } | |
508 | |
491 /***********************************************************************\ | 509 /***********************************************************************\ |
492 * * | 510 * * |
493 * * | 511 * * |
494 * Interface to mplayer * | 512 * Interface to mplayer * |
495 * * | 513 * * |
1529 info.short_name, strerror(errno)); | 1547 info.short_name, strerror(errno)); |
1530 priv->map[i].len = 0; | 1548 priv->map[i].len = 0; |
1531 return 0; | 1549 return 0; |
1532 } | 1550 } |
1533 priv->map[i].len = priv->map[i].buf.length; | 1551 priv->map[i].len = priv->map[i].buf.length; |
1552 priv->clk_id = (priv->map[i].buf.flags & V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC) | |
1553 ? CLOCK_MONOTONIC : CLOCK_REALTIME; | |
1534 /* count up to make sure this is correct everytime */ | 1554 /* count up to make sure this is correct everytime */ |
1535 priv->mapcount++; | 1555 priv->mapcount++; |
1536 | 1556 |
1537 if (ioctl(priv->video_fd, VIDIOC_QBUF, &(priv->map[i].buf)) < 0) { | 1557 if (ioctl(priv->video_fd, VIDIOC_QBUF, &(priv->map[i].buf)) < 0) { |
1538 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl queue buffer failed: %s\n", | 1558 mp_msg(MSGT_TV, MSGL_ERR, "%s: ioctl queue buffer failed: %s\n", |
1832 #endif | 1852 #endif |
1833 | 1853 |
1834 static void *audio_grabber(void *data) | 1854 static void *audio_grabber(void *data) |
1835 { | 1855 { |
1836 priv_t *priv = (priv_t*)data; | 1856 priv_t *priv = (priv_t*)data; |
1837 struct timeval tv; | |
1838 int i, audio_skew_ptr = 0; | 1857 int i, audio_skew_ptr = 0; |
1839 long long current_time, prev_skew = 0, prev_skew_uncorr = 0; | 1858 long long current_time, prev_skew = 0, prev_skew_uncorr = 0; |
1840 long long start_time_avg; | 1859 long long start_time_avg, curr_timestamp; |
1841 | 1860 |
1842 gettimeofday(&tv, NULL); | 1861 start_time_avg = priv->audio_start_time = get_curr_timestamp(priv->clk_id); |
1843 start_time_avg = priv->audio_start_time = (long long)1e6*tv.tv_sec + tv.tv_usec; | |
1844 audio_in_start_capture(&priv->audio_in); | 1862 audio_in_start_capture(&priv->audio_in); |
1845 for (i = 0; i < priv->aud_skew_cnt; i++) | 1863 for (i = 0; i < priv->aud_skew_cnt; i++) |
1846 priv->audio_skew_buffer[i] = 0; | 1864 priv->audio_skew_buffer[i] = 0; |
1847 for (i = 0; i < priv->aud_skew_cnt; i++) | 1865 for (i = 0; i < priv->aud_skew_cnt; i++) |
1848 priv->audio_skew_delta_buffer[i] = 0; | 1866 priv->audio_skew_delta_buffer[i] = 0; |
1856 continue; | 1874 continue; |
1857 #endif | 1875 #endif |
1858 pthread_mutex_lock(&priv->skew_mutex); | 1876 pthread_mutex_lock(&priv->skew_mutex); |
1859 if (priv->first_frame == 0) { | 1877 if (priv->first_frame == 0) { |
1860 // there is no first frame yet (unlikely to happen) | 1878 // there is no first frame yet (unlikely to happen) |
1861 gettimeofday(&tv, NULL); | 1879 start_time_avg = priv->audio_start_time = get_curr_timestamp(priv->clk_id); |
1862 start_time_avg = priv->audio_start_time = (long long)1e6*tv.tv_sec + tv.tv_usec; | |
1863 // fprintf(stderr, "warning - first frame not yet available!\n"); | 1880 // fprintf(stderr, "warning - first frame not yet available!\n"); |
1864 pthread_mutex_unlock(&priv->skew_mutex); | 1881 pthread_mutex_unlock(&priv->skew_mutex); |
1865 continue; | 1882 continue; |
1866 } | 1883 } |
1867 pthread_mutex_unlock(&priv->skew_mutex); | 1884 pthread_mutex_unlock(&priv->skew_mutex); |
1868 | 1885 |
1869 gettimeofday(&tv, NULL); | |
1870 | |
1871 priv->audio_recv_blocks_total++; | 1886 priv->audio_recv_blocks_total++; |
1872 current_time = (long long)1e6*tv.tv_sec + tv.tv_usec - priv->audio_start_time; | 1887 curr_timestamp = get_curr_timestamp(priv->clk_id); |
1888 current_time = curr_timestamp - priv->audio_start_time; | |
1873 | 1889 |
1874 if (priv->audio_recv_blocks_total < priv->aud_skew_cnt*2) { | 1890 if (priv->audio_recv_blocks_total < priv->aud_skew_cnt*2) { |
1875 start_time_avg += (long long)1e6*tv.tv_sec + tv.tv_usec - priv->audio_usecs_per_block*priv->audio_recv_blocks_total; | 1891 start_time_avg += curr_timestamp - priv->audio_usecs_per_block*priv->audio_recv_blocks_total; |
1876 priv->audio_start_time = start_time_avg/(priv->audio_recv_blocks_total+1); | 1892 priv->audio_start_time = start_time_avg/(priv->audio_recv_blocks_total+1); |
1877 } | 1893 } |
1878 | 1894 |
1879 // fprintf(stderr, "spb = %f, bs = %d, skew = %f\n", priv->audio_secs_per_block, priv->audio_in.blocksize, | 1895 // fprintf(stderr, "spb = %f, bs = %d, skew = %f\n", priv->audio_secs_per_block, priv->audio_in.blocksize, |
1880 // (double)(current_time - 1e6*priv->audio_secs_per_block*priv->audio_recv_blocks_total)/1e6); | 1896 // (double)(current_time - 1e6*priv->audio_secs_per_block*priv->audio_recv_blocks_total)/1e6); |