diff options
author | Reinhard Nißl <rnissl@gmx.de> | 2009-04-12 17:47:06 +0200 |
---|---|---|
committer | Reinhard Nißl <rnissl@gmx.de> | 2009-04-12 17:47:06 +0200 |
commit | 065344253a1c3c8ddbbfb673712e9a11656f29bc (patch) | |
tree | 6e855fad093d57a9b600967f3592da3c5762f2ce | |
parent | 63cfee97af9525eaa147e62801ca50493d7ceb2f (diff) | |
download | xine-lib-065344253a1c3c8ddbbfb673712e9a11656f29bc.tar.gz xine-lib-065344253a1c3c8ddbbfb673712e9a11656f29bc.tar.bz2 |
Prepare input_vdr for VDR 1.7.5's requirements on returned STC.
VDR 1.7.5 requires that STC should be near to a previously transmitted PTS
value. We cannot hold this requirement immediately after a discontinuity
as the currently displayed image's vpts time (which originated before the
discontinuity) will be transformed to STC by applying the new vpts offset
established at discontinuity.
Therefore, a queue of vpts offset pairs is created and at discontinuity
the current offset is stored there in combination with the vpts value
up to which it has to be used. When retrieving a STC value, we lookup
the offset to use from current vpts and therefore get a STC near to an
originating PTS value.
As VDR requires this quality of STC values also for its trickspeed modes,
it is nolonger possible to simply set PTS of incoming frames to 0 to
schedule them just after the previous frame. Therefore a discontinuity is
generated for each frame in trickspeed mode, which allows us to schedule
each frame immediately after the previous one while there may be gaps in
PTS values. As a result the above mentioned code will take care to provide
proper STC values even in VDR's trickspeed modes.
-rw-r--r-- | include/xine/vdr.h | 4 | ||||
-rw-r--r-- | src/vdr/input_vdr.c | 381 |
2 files changed, 340 insertions, 45 deletions
diff --git a/include/xine/vdr.h b/include/xine/vdr.h index 1f253cdbe..77a7a41f8 100644 --- a/include/xine/vdr.h +++ b/include/xine/vdr.h @@ -22,7 +22,7 @@ #define __VDR_H -#define XINE_VDR_VERSION 900 +#define XINE_VDR_VERSION 901 enum funcs @@ -441,6 +441,7 @@ result_grab_image_t; typedef struct __attribute__((packed)) data_get_pts_s { data_header_t header; + int32_t ms_timeout; } data_get_pts_t; @@ -451,6 +452,7 @@ typedef struct __attribute__((packed)) result_get_pts_s result_header_t header; int64_t pts; + int8_t queued; } result_get_pts_t; diff --git a/src/vdr/input_vdr.c b/src/vdr/input_vdr.c index e28858c52..76be59564 100644 --- a/src/vdr/input_vdr.c +++ b/src/vdr/input_vdr.c @@ -82,6 +82,16 @@ typedef struct vdr_osd_s vdr_osd_t; +typedef struct vdr_vpts_offset_s vdr_vpts_offset_t; + +struct vdr_vpts_offset_s +{ + vdr_vpts_offset_t *next; + int64_t vpts; + int64_t offset; +}; + + struct vdr_input_plugin_s { input_plugin_t input_plugin; @@ -126,6 +136,14 @@ struct vdr_input_plugin_s pthread_cond_t rpc_thread_shutdown_cond; int startup_phase; + pthread_t metronom_thread; + pthread_mutex_t metronom_thread_lock; + int64_t metronom_thread_request; + int metronom_thread_reply; + pthread_cond_t metronom_thread_request_cond; + pthread_cond_t metronom_thread_reply_cond; + pthread_mutex_t metronom_thread_call_lock; + xine_event_queue_t *event_queue; xine_event_queue_t *event_queue_external; @@ -140,6 +158,12 @@ struct vdr_input_plugin_s vdr_metronom_t metronom; int last_disc_type; + + vdr_vpts_offset_t *vpts_offset_queue; + vdr_vpts_offset_t *vpts_offset_queue_tail; + pthread_mutex_t vpts_offset_queue_lock; + pthread_cond_t vpts_offset_queue_changed_cond; + int vpts_offset_queue_changes; }; @@ -308,7 +332,7 @@ static void adjust_zoom(vdr_input_plugin_t *this) && this->image16_9_zoom_x && this->image16_9_zoom_y) { int ratio = (int)(10000 * this->frame_size.r + 0.5); -fprintf(stderr, "ratio: %d\n", ratio); + /* fprintf(stderr, "ratio: %d\n", ratio); */ if (13332 <= ratio && ratio <= 13334) { xine_set_param(this->stream, XINE_PARAM_VO_ZOOM_X, this->image4_3_zoom_x); @@ -324,6 +348,29 @@ fprintf(stderr, "ratio: %d\n", ratio); pthread_mutex_unlock(&this->adjust_zoom_lock); } + +static void vdr_vpts_offset_queue_process(vdr_input_plugin_t *this, int64_t vpts) +{ + while (this->vpts_offset_queue + && this->vpts_offset_queue->vpts <= vpts) + { + vdr_vpts_offset_t *curr = this->vpts_offset_queue; + this->vpts_offset_queue = curr->next; + + free(curr); + } + + if (!this->vpts_offset_queue) + this->vpts_offset_queue_tail = 0; +} + + +static void vdr_vpts_offset_queue_purge(vdr_input_plugin_t *this) +{ + vdr_vpts_offset_queue_process(this, 1ll << 62); +} + + static off_t vdr_execute_rpc_command(vdr_input_plugin_t *this) { data_union_t data_union; @@ -489,7 +536,7 @@ static off_t vdr_execute_rpc_command(vdr_input_plugin_t *this) { READ_DATA_OR_FAIL(osd_draw_bitmap, LOG_OSD(lprintf("got OSDDRAWBITMAP\n"))); /* - fprintf(stderr, "vdr: osddrawbitmap %d\n", data->window); + fprintf(stderr, "vdr: osddrawbitmap %d, %d, %d, %d, %d, %d\n", data->window, data->x, data->y, data->width, data->height, data->argb); */ if (this->osd_buffer_size < this->cur_size) { @@ -650,7 +697,7 @@ static off_t vdr_execute_rpc_command(vdr_input_plugin_t *this) int orig_speed = xine_get_param(this->stream, XINE_PARAM_FINE_SPEED); if (orig_speed <= 0) xine_set_param(this->stream, XINE_PARAM_FINE_SPEED, XINE_FINE_SPEED_NORMAL); -fprintf(stderr, "+++ CLEAR(%d%c): sync point: %02x\n", data->n, data->s ? 'b' : 'a', data->i); +/* fprintf(stderr, "+++ CLEAR(%d%c): sync point: %02x\n", data->n, data->s ? 'b' : 'a', data->i); */ if (!data->s) { pthread_mutex_lock(&this->find_sync_point_lock); @@ -662,16 +709,16 @@ fprintf(stderr, "+++ CLEAR(%d%c): sync point: %02x\n", data->n, data->s ? 'b' : xine_set_param(this->stream, XINE_PARAM_AUDIO_VOLUME, 0); */ _x_demux_flush_engine(this->stream); -fprintf(stderr, "=== CLEAR(%d.1)\n", data->n); +/* fprintf(stderr, "=== CLEAR(%d.1)\n", data->n); */ _x_demux_control_start(this->stream); -fprintf(stderr, "=== CLEAR(%d.2)\n", data->n); +/* fprintf(stderr, "=== CLEAR(%d.2)\n", data->n); */ _x_demux_seek(this->stream, 0, 0, 0); -fprintf(stderr, "=== CLEAR(%d.3)\n", data->n); +/* fprintf(stderr, "=== CLEAR(%d.3)\n", data->n); */ _x_stream_info_reset(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE); -fprintf(stderr, "=== CLEAR(%d.4)\n", data->n); +/* fprintf(stderr, "=== CLEAR(%d.4)\n", data->n); */ _x_meta_info_reset(this->stream, XINE_META_INFO_AUDIOCODEC); -fprintf(stderr, "=== CLEAR(%d.5)\n", data->n); +/* fprintf(stderr, "=== CLEAR(%d.5)\n", data->n); */ _x_trigger_relaxed_frame_drop_mode(this->stream); /* _x_reset_relaxed_frame_drop_mode(this->stream); */ @@ -679,7 +726,7 @@ fprintf(stderr, "=== CLEAR(%d.5)\n", data->n); if (!this->dont_change_xine_volume) xine_set_param(this->stream, XINE_PARAM_AUDIO_VOLUME, this->last_volume); */ -fprintf(stderr, "--- CLEAR(%d%c)\n", data->n, data->s ? 'b' : 'a'); +/* fprintf(stderr, "--- CLEAR(%d%c)\n", data->n, data->s ? 'b' : 'a'); */ if (orig_speed <= 0) xine_set_param(this->stream, XINE_PARAM_FINE_SPEED, orig_speed); } @@ -765,7 +812,7 @@ fprintf(stderr, "--- CLEAR(%d%c)\n", data->n, data->s ? 'b' : 'a'); event.type = XINE_EVENT_VDR_TRICKSPEEDMODE; event.data = 0; - event.data_length = this->trick_speed_mode; + event.data_length = 0; /* this->trick_speed_mode; */ /* fprintf(stderr, "************************: %p, %d\n", event.data, event.data_length); */ xine_event_send(this->stream, &event); } @@ -849,7 +896,7 @@ fprintf(stderr, "--- CLEAR(%d%c)\n", data->n, data->s ? 'b' : 'a'); } _t2 = _now(); - fprintf(stderr, "vdr: flush: n: %d, %.1lf\n", _n, _t2 - _t1); + /* fprintf(stderr, "vdr: flush: n: %d, %.1lf\n", _n, _t2 - _t1); */ xprintf(this->stream->xine , XINE_VERBOSITY_LOG @@ -884,8 +931,9 @@ fprintf(stderr, "--- CLEAR(%d%c)\n", data->n, data->s ? 'b' : 'a'); case func_set_volume: { +double t3, t2, t1, t0; READ_DATA_OR_FAIL(set_volume, lprintf("got SETVOLUME\n")); - +t0 = _now(); { int change_volume = (this->volume_mode != XINE_VDR_VOLUME_IGNORE); int do_mute = (this->last_volume != 0 && 0 == data->volume); @@ -918,12 +966,14 @@ fprintf(stderr, "--- CLEAR(%d%c)\n", data->n, data->s ? 'b' : 'a'); return -1; }; } +t1 = _now(); if (change_volume) { report_change = 1; xine_set_param(this->stream, param_volume, this->last_volume); } +t2 = _now(); if (report_change && this->volume_mode != XINE_VDR_VOLUME_CHANGE_SW) { @@ -935,6 +985,7 @@ fprintf(stderr, "--- CLEAR(%d%c)\n", data->n, data->s ? 'b' : 'a'); = xine_get_param(this->stream, param_volume); data.mute = xine_get_param(this->stream, param_mute); +t3 = _now(); event.type = XINE_EVENT_AUDIO_LEVEL; event.data = &data; @@ -943,6 +994,7 @@ fprintf(stderr, "--- CLEAR(%d%c)\n", data->n, data->s ? 'b' : 'a'); xine_event_send(this->stream, &event); } } +/* fprintf(stderr, "volume: %6.3lf ms, %6.3lf ms, %6.3lf ms\n", t1 - t0, t2 - t1, t3 - t2); */ } break; @@ -1074,13 +1126,80 @@ fprintf(stderr, "--- CLEAR(%d%c)\n", data->n, data->s ? 'b' : 'a'); case func_get_pts: { READ_DATA_OR_FAIL(get_pts, lprintf("got GETPTS\n")); - + { result_get_pts_t result_get_pts; result_get_pts.header.func = data->header.func; result_get_pts.header.len = sizeof (result_get_pts); + + pthread_mutex_lock(&this->vpts_offset_queue_lock); + + while (this->vpts_offset_queue_changes) + pthread_cond_wait(&this->vpts_offset_queue_changed_cond, &this->vpts_offset_queue_lock); + + if (this->last_disc_type == DISC_STREAMSTART + && data->ms_timeout > 0) + { + struct timespec abstime; + { + struct timeval now; + gettimeofday(&now, 0); + + abstime.tv_sec = now.tv_sec + data->ms_timeout / 1000; + abstime.tv_nsec = now.tv_usec * 1000 + (data->ms_timeout % 1000) * 1e6; - result_get_pts.pts = (this->last_disc_type == DISC_STREAMSTART) ? -2 : (xine_get_current_vpts(this->stream) - this->stream->metronom->get_option(this->stream->metronom, METRONOM_VPTS_OFFSET)); + if (abstime.tv_nsec > 1e9) + { + abstime.tv_nsec -= 1e9; + abstime.tv_sec++; + } + } + + while (this->last_disc_type == DISC_STREAMSTART + || this->vpts_offset_queue_changes) + { + if (0 != pthread_cond_timedwait(&this->vpts_offset_queue_changed_cond, &this->vpts_offset_queue_lock, &abstime)) + break; + } + } + + if (this->last_disc_type == DISC_STREAMSTART + || this->vpts_offset_queue_changes) + { + result_get_pts.pts = -1; + result_get_pts.queued = 0; + } + else + { + int64_t offset, vpts = xine_get_current_vpts(this->stream); + + vdr_vpts_offset_queue_process(this, vpts); + +/* if(this->vpts_offset_queue) */ +if(0) + { +fprintf(stderr, "C ---------------------------------------------\n"); + vdr_vpts_offset_t *p = this->vpts_offset_queue; + while (p) + { + fprintf(stderr, "C now: %12"PRId64", vpts: %12"PRId64", offset: %12"PRId64"\n", xine_get_current_vpts(this->stream), p->vpts, p->offset); + p = p->next; + } +fprintf(stderr, "C =============================================\n"); + } + + if (this->vpts_offset_queue) + offset = this->vpts_offset_queue->offset; + else + offset = this->stream->metronom->get_option(this->stream->metronom, METRONOM_VPTS_OFFSET); + + result_get_pts.pts = (vpts - offset) & ((1ll << 33) - 1); + result_get_pts.queued = !!this->vpts_offset_queue; +/* fprintf(stderr, "vpts: %12ld, stc: %12ld, offset: %12ld\n", vpts, result_get_pts.pts, offset); */ + } + + pthread_mutex_unlock(&this->vpts_offset_queue_lock); + if (sizeof (result_get_pts) != vdr_write(this->fh_result, &result_get_pts, sizeof (result_get_pts))) return -1; } @@ -1142,13 +1261,13 @@ fprintf(stderr, "--- CLEAR(%d%c)\n", data->n, data->s ? 'b' : 'a'); result_video_size.width = this->frame_size.w; result_video_size.height = this->frame_size.h; } -//fprintf(stderr, "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n"); +/* fprintf(stderr, "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\n"); */ result_video_size.zoom_x = xine_get_param(this->stream, XINE_PARAM_VO_ZOOM_X); result_video_size.zoom_y = xine_get_param(this->stream, XINE_PARAM_VO_ZOOM_Y); -//fprintf(stderr, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n"); +/* fprintf(stderr, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n"); */ if (sizeof (result_video_size) != vdr_write(this->fh_result, &result_video_size, sizeof (result_video_size))) return -1; -//fprintf(stderr, "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\n"); +/* fprintf(stderr, "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\n"); */ } } break; @@ -1194,7 +1313,7 @@ fprintf(stderr, "--- CLEAR(%d%c)\n", data->n, data->s ? 'b' : 'a'); } _t2 = _now(); - fprintf(stderr, "vdr: reset_audio: n: %d, %.1lf\n", _n, _t2 - _t1); + /* fprintf(stderr, "vdr: reset_audio: n: %d, %.1lf\n", _n, _t2 - _t1); */ xine_set_param(this->stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL, -1); @@ -1459,7 +1578,7 @@ static off_t vdr_plugin_read(input_plugin_t *this_gen, if (buf[3] == 0xbe && buf[4] == 0xff) { -//fprintf(stderr, "------- seen sync point: %02x, waiting for: %02x\n", buf[5], this->find_sync_point); +/* fprintf(stderr, "------- seen sync point: %02x, waiting for: %02x\n", buf[5], this->find_sync_point); */ if (buf[5] == this->find_sync_point) { this->find_sync_point = 0; @@ -1644,6 +1763,35 @@ static void vdr_plugin_dispose(input_plugin_t *this_gen) pthread_cond_destroy(&this->rpc_thread_shutdown_cond); pthread_mutex_destroy(&this->rpc_thread_shutdown_lock); + if (this->metronom_thread) + { + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("%s: joining metronom thread ...\n"), LOG_MODULE); + + pthread_mutex_lock(&this->metronom_thread_call_lock); + + pthread_mutex_lock(&this->metronom_thread_lock); + this->metronom_thread_request = -1; + this->metronom_thread_reply = 0; + pthread_cond_broadcast(&this->metronom_thread_request_cond); +/* + pthread_mutex_unlock(&this->metronom_thread_lock); + + pthread_mutex_lock(&this->metronom_thread_lock); + if (!this->metronom_thread_reply) +*/ + pthread_cond_wait(&this->metronom_thread_reply_cond, &this->metronom_thread_lock); + pthread_mutex_unlock(&this->metronom_thread_lock); + + pthread_mutex_unlock(&this->metronom_thread_call_lock); + + pthread_join(this->metronom_thread, 0); + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("%s: metronom thread joined.\n"), LOG_MODULE); + } + + pthread_mutex_destroy(&this->metronom_thread_lock); + pthread_cond_destroy(&this->metronom_thread_request_cond); + pthread_cond_destroy(&this->metronom_thread_reply_cond); + pthread_mutex_destroy(&this->find_sync_point_lock); pthread_mutex_destroy(&this->adjust_zoom_lock); @@ -1678,6 +1826,10 @@ static void vdr_plugin_dispose(input_plugin_t *this_gen) this->stream->metronom = this->metronom.stream_metronom; this->metronom.stream_metronom = 0; + vdr_vpts_offset_queue_purge(this); + pthread_cond_destroy(&this->vpts_offset_queue_changed_cond); + pthread_mutex_destroy(&this->vpts_offset_queue_lock); + free(this); } @@ -1928,6 +2080,33 @@ static int vdr_plugin_open_socket_mrl(input_plugin_t *this_gen) return 1; } +static void *vdr_metronom_thread_loop(void *arg) +{ + vdr_input_plugin_t *this = (vdr_input_plugin_t *)arg; + int run = 1; + + pthread_mutex_lock(&this->metronom_thread_lock); + + while (run) + { + if (this->metronom_thread_request == 0) + pthread_cond_wait(&this->metronom_thread_request_cond, &this->metronom_thread_lock); + + if (this->metronom_thread_request == -1) + run = 0; + else + this->metronom.metronom.handle_audio_discontinuity(&this->metronom.metronom, DISC_ABSOLUTE, this->metronom_thread_request); + + this->metronom_thread_request = 0; + this->metronom_thread_reply = 1; + pthread_cond_broadcast(&this->metronom_thread_reply_cond); + } + + pthread_mutex_unlock(&this->metronom_thread_lock); + + return 0; +} + static int vdr_plugin_open(input_plugin_t *this_gen) { vdr_input_plugin_t *this = (vdr_input_plugin_t *)this_gen; @@ -1956,13 +2135,23 @@ static int vdr_plugin_open(input_plugin_t *this_gen) return 0; } + if ((err = pthread_create(&this->metronom_thread, NULL, + vdr_metronom_thread_loop, (void *)this)) != 0) + { + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + _("%s: can't create new thread (%s)\n"), LOG_MODULE, + strerror(err)); + + return 0; + } + this->rpc_thread_shutdown = 0; /* let this thread handle rpc commands in startup phase */ this->startup_phase = 1; if (0 == vdr_rpc_thread_loop(this)) return 0; - +/* fprintf(stderr, "####################################################\n"); */ if ((err = pthread_create(&this->rpc_thread, NULL, vdr_rpc_thread_loop, (void *)this)) != 0) { @@ -2023,7 +2212,7 @@ static void event_handler(void *user_data, const xine_event_t *event) event.type = XINE_EVENT_VDR_TRICKSPEEDMODE; event.data = 0; - event.data_length = this->trick_speed_mode; + event.data_length = 0; /* this->trick_speed_mode; */ xine_event_send(this->stream, &event); } @@ -2114,34 +2303,74 @@ static void event_handler(void *user_data, const xine_event_t *event) } -static void vdr_metronom_set_audio_rate(metronom_t *self, int64_t pts_per_smpls) +static int64_t vdr_vpts_offset_queue_change_begin(vdr_input_plugin_t *this, int type) { - vdr_metronom_t *this = (vdr_metronom_t *)self; - this->stream_metronom->set_audio_rate(this->stream_metronom, pts_per_smpls); -} + pthread_mutex_lock(&this->vpts_offset_queue_lock); + this->vpts_offset_queue_changes++; + pthread_mutex_unlock(&this->vpts_offset_queue_lock); -static void vdr_metronom_got_video_frame(metronom_t *self, vo_frame_t *frame) -{ - vdr_metronom_t *this = (vdr_metronom_t *)self; - this->stream_metronom->got_video_frame(this->stream_metronom, frame); + return this->metronom.metronom.get_option(&this->metronom.metronom, METRONOM_VPTS_OFFSET); } -static int64_t vdr_metronom_got_audio_samples(metronom_t *self, int64_t pts, int nsamples) +static void vdr_vpts_offset_queue_change_end(vdr_input_plugin_t *this, int type, int64_t disc_off, int64_t vpts_offset) { - vdr_metronom_t *this = (vdr_metronom_t *)self; - return this->stream_metronom->got_audio_samples(this->stream_metronom, pts, nsamples); -} + pthread_mutex_lock(&this->vpts_offset_queue_lock); -static int64_t vdr_metronom_got_spu_packet(metronom_t *self, int64_t pts) -{ - vdr_metronom_t *this = (vdr_metronom_t *)self; - return this->stream_metronom->got_spu_packet(this->stream_metronom, pts); -} +if(0) + { +fprintf(stderr, "A ---------------------------------------------\n"); + vdr_vpts_offset_t *p = this->vpts_offset_queue; + while (p) + { + fprintf(stderr, "A now: %12"PRId64", vpts: %12"PRId64", offset: %12"PRId64"\n", xine_get_current_vpts(this->stream), p->vpts, p->offset); + p = p->next; + } +fprintf(stderr, "A =============================================\n"); + } + + if (type == DISC_ABSOLUTE) + { + int64_t vpts = this->stream->metronom->get_option(this->stream->metronom, METRONOM_VPTS_OFFSET) + disc_off; + + if (!this->vpts_offset_queue + || this->vpts_offset_queue_tail->vpts < vpts) + { + vdr_vpts_offset_t *curr = (vdr_vpts_offset_t *)calloc(1, sizeof (vdr_vpts_offset_t)); + curr->vpts = vpts; + curr->offset = vpts_offset; + + if (!this->vpts_offset_queue) + this->vpts_offset_queue = this->vpts_offset_queue_tail = curr; + else + { + this->vpts_offset_queue_tail->next = curr; + this->vpts_offset_queue_tail = curr; + } + } + } + else + vdr_vpts_offset_queue_purge(this); + +if(0) + { +fprintf(stderr, "B ---------------------------------------------\n"); + vdr_vpts_offset_t *p = this->vpts_offset_queue; + while (p) + { + fprintf(stderr, "B now: %12"PRId64", vpts: %12"PRId64", offset: %12"PRId64"\n", xine_get_current_vpts(this->stream), p->vpts, p->offset); + p = p->next; + } +fprintf(stderr, "B =============================================\n"); + } + + this->vpts_offset_queue_changes--; + pthread_cond_broadcast(&this->vpts_offset_queue_changed_cond); -static void vdr_handle_discontinuity(vdr_input_plugin_t *this, int type) -{ this->last_disc_type = type; + pthread_mutex_unlock(&this->vpts_offset_queue_lock); + + if (!this->trick_speed_mode) { xine_event_t event; @@ -2156,15 +2385,71 @@ static void vdr_handle_discontinuity(vdr_input_plugin_t *this, int type) static void vdr_metronom_handle_audio_discontinuity(metronom_t *self, int type, int64_t disc_off) { vdr_metronom_t *this = (vdr_metronom_t *)self; + int64_t vpts_offset = vdr_vpts_offset_queue_change_begin(this->input, type); +/* fprintf(stderr, "had A: %d, %"PRId64", %"PRId64", %"PRId64"\n", type, disc_off, xine_get_current_vpts(this->input->stream), this->stream_metronom->get_option(this->stream_metronom, METRONOM_VPTS_OFFSET)); */ this->stream_metronom->handle_audio_discontinuity(this->stream_metronom, type, disc_off); - vdr_handle_discontinuity(this->input, type); +/* fprintf(stderr, "had B: %d, %"PRId64", %"PRId64", %"PRId64"\n", type, disc_off, xine_get_current_vpts(this->input->stream), this->stream_metronom->get_option(this->stream_metronom, METRONOM_VPTS_OFFSET)); */ + vdr_vpts_offset_queue_change_end(this->input, type, disc_off, vpts_offset); } static void vdr_metronom_handle_video_discontinuity(metronom_t *self, int type, int64_t disc_off) { vdr_metronom_t *this = (vdr_metronom_t *)self; + int64_t vpts_offset = vdr_vpts_offset_queue_change_begin(this->input, type); +/* fprintf(stderr, "hvd A: %d, %"PRId64", %"PRId64", %"PRId64"\n", type, disc_off, xine_get_current_vpts(this->input->stream), this->stream_metronom->get_option(this->stream_metronom, METRONOM_VPTS_OFFSET)); */ this->stream_metronom->handle_video_discontinuity(this->stream_metronom, type, disc_off); - vdr_handle_discontinuity(this->input, type); +/* fprintf(stderr, "hvd B: %d, %"PRId64", %"PRId64", %"PRId64"\n", type, disc_off, xine_get_current_vpts(this->input->stream), this->stream_metronom->get_option(this->stream_metronom, METRONOM_VPTS_OFFSET)); */ + vdr_vpts_offset_queue_change_end(this->input, type, disc_off, vpts_offset); +} + +static void vdr_metronom_got_video_frame(metronom_t *self, vo_frame_t *frame) +{ + vdr_metronom_t *this = (vdr_metronom_t *)self; + + if (this->input->trick_speed_mode && frame->pts) + { + pthread_mutex_lock(&this->input->metronom_thread_call_lock); + + pthread_mutex_lock(&this->input->metronom_thread_lock); + this->input->metronom_thread_request = frame->pts; + this->input->metronom_thread_reply = 0; + pthread_cond_broadcast(&this->input->metronom_thread_request_cond); + pthread_mutex_unlock(&this->input->metronom_thread_lock); + + vdr_metronom_handle_video_discontinuity(self, DISC_ABSOLUTE, frame->pts); + + pthread_mutex_lock(&this->input->metronom_thread_lock); + if (!this->input->metronom_thread_reply) + pthread_cond_wait(&this->input->metronom_thread_reply_cond, &this->input->metronom_thread_lock); + pthread_mutex_unlock(&this->input->metronom_thread_lock); + + pthread_mutex_unlock(&this->input->metronom_thread_call_lock); + } + + this->stream_metronom->got_video_frame(this->stream_metronom, frame); + + if (this->input->trick_speed_mode && frame->pts) + { +/* fprintf(stderr, "vpts: %12ld, pts: %12ld, offset: %12ld\n", frame->vpts, frame->pts, this->stream_metronom->get_option(this->stream_metronom, METRONOM_VPTS_OFFSET)); */ + } +} + +static int64_t vdr_metronom_got_audio_samples(metronom_t *self, int64_t pts, int nsamples) +{ + vdr_metronom_t *this = (vdr_metronom_t *)self; + return this->stream_metronom->got_audio_samples(this->stream_metronom, pts, nsamples); +} + +static int64_t vdr_metronom_got_spu_packet(metronom_t *self, int64_t pts) +{ + vdr_metronom_t *this = (vdr_metronom_t *)self; + return this->stream_metronom->got_spu_packet(this->stream_metronom, pts); +} + +static void vdr_metronom_set_audio_rate(metronom_t *self, int64_t pts_per_smpls) +{ + vdr_metronom_t *this = (vdr_metronom_t *)self; + this->stream_metronom->set_audio_rate(this->stream_metronom, pts_per_smpls); } static void vdr_metronom_set_option(metronom_t *self, int option, int64_t value) @@ -2269,8 +2554,13 @@ static input_plugin_t *vdr_class_get_instance(input_class_t *cls_gen, xine_strea this->event_queue_external = 0; pthread_mutex_init(&this->rpc_thread_shutdown_lock, 0); - pthread_cond_init(&this->rpc_thread_shutdown_cond, 0); - + pthread_cond_init(&this->rpc_thread_shutdown_cond, 0); + + pthread_mutex_init(&this->metronom_thread_lock, 0); + pthread_cond_init(&this->metronom_thread_request_cond, 0); + pthread_cond_init(&this->metronom_thread_reply_cond, 0); + pthread_mutex_init(&this->metronom_thread_call_lock, 0); + pthread_mutex_init(&this->find_sync_point_lock, 0); pthread_mutex_init(&this->adjust_zoom_lock, 0); this->image4_3_zoom_x = 0; @@ -2297,6 +2587,9 @@ static input_plugin_t *vdr_class_get_instance(input_class_t *cls_gen, xine_strea this->metronom.stream_metronom = stream->metronom; stream->metronom = &this->metronom.metronom; + pthread_mutex_init(&this->vpts_offset_queue_lock, 0); + pthread_cond_init(&this->vpts_offset_queue_changed_cond, 0); + return &this->input_plugin; } |