summaryrefslogtreecommitdiffstats
path: root/libmpdemux
diff options
context:
space:
mode:
authorhenry <henry@b3059339-0415-0410-9bf9-f77b7e298cf2>2005-05-14 05:42:37 +0000
committerhenry <henry@b3059339-0415-0410-9bf9-f77b7e298cf2>2005-05-14 05:42:37 +0000
commit32a79425350dc255514bb423b85de478121dc2f7 (patch)
tree40e3f92b335ec7e6afae551088fde4dc49c84ca3 /libmpdemux
parent781402e06d4cb3a301606180464f4de92d9560ae (diff)
downloadmpv-32a79425350dc255514bb423b85de478121dc2f7.tar.bz2
mpv-32a79425350dc255514bb423b85de478121dc2f7.tar.xz
improve playback with mplayer -tv immediatemode=0
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@15450 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libmpdemux')
-rw-r--r--libmpdemux/tvi_v4l2.c90
1 files changed, 73 insertions, 17 deletions
diff --git a/libmpdemux/tvi_v4l2.c b/libmpdemux/tvi_v4l2.c
index d99b415d36..3c4e3573ff 100644
--- a/libmpdemux/tvi_v4l2.c
+++ b/libmpdemux/tvi_v4l2.c
@@ -118,10 +118,16 @@ typedef struct {
volatile int shutdown;
double audio_secs_per_block;
+ long long audio_usecs_per_block;
long long audio_skew_total;
long long audio_skew_delta_total;
long audio_recv_blocks_total;
long audio_sent_blocks_total;
+ pthread_mutex_t audio_mutex;
+ int audio_insert_null_samples;
+ volatile long audio_null_blocks_inserted;
+ volatile long long dropped_frames_timeshift;
+ long long dropped_frames_compensated;
} priv_t;
#include "tvi_def.h"
@@ -144,8 +150,8 @@ static void *video_grabber(void *data);
This may be an useful translation table for some others:
IMGFMT_RGB8 == V4L2_PIX_FMT_RGB332
- IMGFMT_RGB15 == V4L2_PIX_FMT_RGB555
- IMGFMT_RGB16 == V4L2_PIX_FMT_RGB565
+ IMGFMT_BGR15 == V4L2_PIX_FMT_RGB555
+ IMGFMT_BGR16 == V4L2_PIX_FMT_RGB565
IMGFMT_RGB24 == V4L2_PIX_FMT_RGB24
IMGFMT_RGB32 == V4L2_PIX_FMT_RGB32
IMGFMT_BGR24 == V4L2_PIX_FMT_BGR24
@@ -841,6 +847,7 @@ static int uninit(priv_t *priv)
if (!tv_param_noaudio && !tv_param_immediate) {
pthread_join(priv->audio_grabber_thread, NULL);
pthread_mutex_destroy(&priv->skew_mutex);
+ pthread_mutex_destroy(&priv->audio_mutex);
}
if (priv->input.audioset) {
@@ -1168,6 +1175,7 @@ static int start(priv_t *priv)
priv->audio_secs_per_block = (double)priv->audio_in.blocksize/(priv->audio_in.samplerate
*priv->audio_in.channels
*priv->audio_in.bytes_per_sample);
+ priv->audio_usecs_per_block = 1e6*priv->audio_secs_per_block;
priv->audio_head = 0;
priv->audio_tail = 0;
priv->audio_cnt = 0;
@@ -1177,6 +1185,13 @@ static int start(priv_t *priv)
priv->audio_skew_delta_total = 0;
priv->audio_recv_blocks_total = 0;
priv->audio_sent_blocks_total = 0;
+ priv->audio_null_blocks_inserted = 0;
+ priv->audio_insert_null_samples = 0;
+ priv->dropped_frames_timeshift = 0;
+ priv->dropped_frames_compensated = 0;
+
+ pthread_mutex_init(&priv->skew_mutex, NULL);
+ pthread_mutex_init(&priv->audio_mutex, NULL);
}
/* setup video parameters */
@@ -1210,6 +1225,8 @@ static int start(priv_t *priv)
return 0;
}
+ pthread_mutex_init(&priv->video_buffer_mutex, NULL);
+
priv->video_head = 0;
priv->video_tail = 0;
priv->video_cnt = 0;
@@ -1318,7 +1335,7 @@ static inline void copy_frame(priv_t *priv, unsigned char *dest, unsigned char *
static void *video_grabber(void *data)
{
priv_t *priv = (priv_t*)data;
- long long skew, prev_skew, xskew, interval, prev_interval;
+ long long skew, prev_skew, xskew, interval, prev_interval, delta;
int i;
int framesize = priv->format.fmt.pix.height*priv->format.fmt.pix.width*
pixfmt2depth(priv->format.fmt.pix.pixelformat)/8;
@@ -1341,7 +1358,6 @@ static void *video_grabber(void *data)
priv->streamon = 1;
if (!tv_param_noaudio) {
- pthread_mutex_init(&priv->skew_mutex, NULL);
pthread_create(&priv->audio_grabber_thread, NULL, audio_grabber, priv);
}
@@ -1424,6 +1440,7 @@ static void *video_grabber(void *data)
// fprintf(stderr, "idx = %d, ts = %lf\n", buf.index, (double)(priv->curr_frame) / 1e6);
interval = priv->curr_frame - priv->first_frame;
+ delta = interval - prev_interval;
if (!priv->immediate_mode) {
// interpolate the skew in time
@@ -1431,17 +1448,17 @@ static void *video_grabber(void *data)
xskew = priv->audio_skew + (interval - priv->audio_skew_measure_time)*priv->audio_skew_factor;
pthread_mutex_unlock(&priv->skew_mutex);
// correct extreme skew changes to avoid (especially) moving backwards in time
- if (xskew - prev_skew > (interval - prev_interval)*MAX_SKEW_DELTA) {
- skew = prev_skew + (interval - prev_interval)*MAX_SKEW_DELTA;
- } else if (xskew - prev_skew < -(interval - prev_interval)*MAX_SKEW_DELTA) {
- skew = prev_skew - (interval - prev_interval)*MAX_SKEW_DELTA;
+ if (xskew - prev_skew > delta*MAX_SKEW_DELTA) {
+ skew = prev_skew + delta*MAX_SKEW_DELTA;
+ } else if (xskew - prev_skew < -delta*MAX_SKEW_DELTA) {
+ skew = prev_skew - delta*MAX_SKEW_DELTA;
} else {
skew = xskew;
}
}
mp_msg(MSGT_TV, MSGL_DBG3, "\nfps = %lf, interval = %lf, a_skew = %f, corr_skew = %f\n",
- (interval != prev_interval) ? (double)1e6/(interval - prev_interval) : -1,
+ delta ? (double)1e6/delta : -1,
(double)1e-6*interval, (double)1e-6*xskew, (double)1e-6*skew);
mp_msg(MSGT_TV, MSGL_DBG3, "vcnt = %d, acnt = %d\n", priv->video_cnt, priv->audio_cnt);
@@ -1469,6 +1486,11 @@ static void *video_grabber(void *data)
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");
+ if (priv->audio_insert_null_samples) {
+ pthread_mutex_lock(&priv->audio_mutex);
+ priv->dropped_frames_timeshift += delta;
+ pthread_mutex_unlock(&priv->audio_mutex);
+ }
}
} else {
if (priv->immediate_mode) {
@@ -1478,8 +1500,16 @@ static void *video_grabber(void *data)
// negative skew => there are more audio samples, increase interval
// positive skew => less samples, shorten the interval
priv->video_timebuffer[priv->video_tail] = interval - skew;
+ if (priv->audio_insert_null_samples && priv->video_timebuffer[priv->video_tail] > 0) {
+ pthread_mutex_lock(&priv->audio_mutex);
+ priv->video_timebuffer[priv->video_tail] +=
+ (priv->audio_null_blocks_inserted
+ - priv->dropped_frames_timeshift/priv->audio_usecs_per_block)
+ *priv->audio_usecs_per_block;
+ pthread_mutex_unlock(&priv->audio_mutex);
+ }
}
-
+
copy_frame(priv, priv->video_ringbuffer[priv->video_tail], priv->map[buf.index].addr);
priv->video_tail = (priv->video_tail+1)%priv->video_buffer_size_current;
priv->video_cnt++;
@@ -1585,7 +1615,7 @@ static void *audio_grabber(void *data)
current_time = (long long)1e6*tv.tv_sec + tv.tv_usec - priv->audio_start_time;
if (priv->audio_recv_blocks_total < priv->aud_skew_cnt*2) {
- start_time_avg += (long long)1e6*tv.tv_sec + tv.tv_usec - 1e6*priv->audio_secs_per_block*priv->audio_recv_blocks_total;
+ start_time_avg += (long long)1e6*tv.tv_sec + tv.tv_usec - priv->audio_usecs_per_block*priv->audio_recv_blocks_total;
priv->audio_start_time = start_time_avg/(priv->audio_recv_blocks_total+1);
}
@@ -1595,7 +1625,7 @@ static void *audio_grabber(void *data)
// put the current skew into the ring buffer
priv->audio_skew_total -= priv->audio_skew_buffer[audio_skew_ptr];
priv->audio_skew_buffer[audio_skew_ptr] = current_time
- - 1e6*priv->audio_secs_per_block*priv->audio_recv_blocks_total;
+ - priv->audio_usecs_per_block*priv->audio_recv_blocks_total;
priv->audio_skew_total += priv->audio_skew_buffer[audio_skew_ptr];
pthread_mutex_lock(&priv->skew_mutex);
@@ -1643,6 +1673,7 @@ static void *audio_grabber(void *data)
// fprintf(stderr, "audio_skew = %lf, delta = %lf\n", (double)priv->audio_skew/1e6, (double)priv->audio_skew_delta_total/1e6);
+ pthread_mutex_lock(&priv->audio_mutex);
if ((priv->audio_tail+1) % priv->audio_buffer_size == priv->audio_head) {
mp_msg(MSGT_TV, MSGL_ERR, "\ntoo bad - dropping audio frame !\n");
priv->audio_drop++;
@@ -1650,6 +1681,7 @@ static void *audio_grabber(void *data)
priv->audio_tail = (priv->audio_tail+1) % priv->audio_buffer_size;
priv->audio_cnt++;
}
+ pthread_mutex_unlock(&priv->audio_mutex);
}
return NULL;
}
@@ -1659,25 +1691,49 @@ static double grab_audio_frame(priv_t *priv, char *buffer, int len)
mp_dbg(MSGT_TV, MSGL_DBG2, "grab_audio_frame(priv=%p, buffer=%p, len=%d)\n",
priv, buffer, len);
- if (priv->first) {
- pthread_create(&priv->video_grabber_thread, NULL, video_grabber, priv);
- priv->first = 0;
+ // hack: if grab_audio_frame is called first, it means we are used by mplayer
+ // => switch to the mode which outputs audio immediately, even if
+ // it should be silence
+ if (priv->first) priv->audio_insert_null_samples = 1;
+
+ pthread_mutex_lock(&priv->audio_mutex);
+ while (priv->audio_insert_null_samples
+ && priv->dropped_frames_timeshift - priv->dropped_frames_compensated >= priv->audio_usecs_per_block) {
+ // some frames were dropped - drop the corresponding number of audio blocks
+ if (priv->audio_drop) {
+ priv->audio_drop--;
+ } else {
+ if (priv->audio_head == priv->audio_tail) break;
+ priv->audio_head = (priv->audio_head+1) % priv->audio_buffer_size;
+ }
+ priv->dropped_frames_compensated += priv->audio_usecs_per_block;
}
// compensate for dropped audio frames
if (priv->audio_drop && (priv->audio_head == priv->audio_tail)) {
priv->audio_drop--;
- priv->audio_sent_blocks_total++;
memset(buffer, 0, len);
- return (double)priv->audio_sent_blocks_total*priv->audio_secs_per_block;
+ goto out;
+ }
+
+ if (priv->audio_insert_null_samples && (priv->audio_head == priv->audio_tail)) {
+ // return silence to avoid desync and stuttering
+ memset(buffer, 0, len);
+ priv->audio_null_blocks_inserted++;
+ goto out;
}
+ pthread_mutex_unlock(&priv->audio_mutex);
while (priv->audio_head == priv->audio_tail) {
+ // this is mencoder => just wait until some audio is available
usleep(10000);
}
+// pthread_mutex_lock(&priv->audio_mutex);
memcpy(buffer, priv->audio_ringbuffer+priv->audio_head*priv->audio_in.blocksize, len);
priv->audio_head = (priv->audio_head+1) % priv->audio_buffer_size;
priv->audio_cnt--;
+out:
+ pthread_mutex_unlock(&priv->audio_mutex);
priv->audio_sent_blocks_total++;
return (double)priv->audio_sent_blocks_total*priv->audio_secs_per_block;
}