static void demux_demuxers_seek(demuxer_t *demuxer,float rel_seek_secs,float audio_delay,int flags) { dd_priv_t* priv; float pos; priv=demuxer->priv; priv->ad->stream->eof = 0; priv->sd->stream->eof = 0; // Seek video demux_seek(priv->vd,rel_seek_secs,audio_delay,flags); // Get the new pos pos = demuxer->video->pts; if (!pos) { demux_fill_buffer(priv->vd, demuxer->video); if (demuxer->video->first) pos = demuxer->video->first->pts; } if(priv->ad != priv->vd && demuxer->audio->sh) { sh_audio_t* sh = demuxer->audio->sh; demux_seek(priv->ad,pos,audio_delay,1); // In case the demuxer don't set pts if(!demuxer->audio->pts) demuxer->audio->pts = pos-((ds_tell_pts(demuxer->audio)-sh->a_in_buffer_len)/(float)sh->i_bps); } if(priv->sd != priv->vd) demux_seek(priv->sd,pos,audio_delay,1); }
static void reinit_subdec(struct MPContext *mpctx, struct track *track, struct dec_sub *dec_sub) { struct MPOpts *opts = mpctx->opts; if (sub_is_initialized(dec_sub)) return; struct sh_video *sh_video = mpctx->d_video ? mpctx->d_video->header->video : NULL; int w = sh_video ? sh_video->disp_w : 0; int h = sh_video ? sh_video->disp_h : 0; float fps = sh_video ? sh_video->fps : 25; init_sub_renderer(mpctx); sub_set_video_res(dec_sub, w, h); sub_set_video_fps(dec_sub, fps); sub_set_ass_renderer(dec_sub, mpctx->ass_library, mpctx->ass_renderer, &mpctx->ass_lock); sub_init_from_sh(dec_sub, track->stream); // Don't do this if the file has video/audio streams. Don't do it even // if it has only sub streams, because reading packets will change the // demuxer position. if (!track->preloaded && track->is_external && !opts->sub_clear_on_seek) { demux_seek(track->demuxer, 0, SEEK_ABSOLUTE); track->preloaded = sub_read_all_packets(dec_sub, track->stream); if (track->preloaded) demux_stop_thread(track->demuxer); } }
static void demux_demuxers_seek(demuxer_t *demuxer,float rel_seek_secs,float audio_delay,int flags) { dd_priv_t* priv; float pos; priv=demuxer->priv; priv->ad->stream->eof = 0; priv->sd->stream->eof = 0; // Seek video demux_seek(priv->vd,rel_seek_secs,audio_delay,flags); // Get the new pos pos = demuxer->video->pts; if (!pos) { // since the video demuxer might provide multiple // streams (e.g. subs) we might have to call // demux_fill_buffer multiple times. int limit = 10; do { demux_fill_buffer(priv->vd, demuxer->video); } while (--limit && !demuxer->video->first); if (demuxer->video->first) pos = demuxer->video->first->pts; } if(priv->ad != priv->vd && demuxer->audio->sh) { sh_audio_t* sh = demuxer->audio->sh; demux_seek(priv->ad,pos,audio_delay,1); // In case the demuxer don't set pts if(!demuxer->audio->pts) demuxer->audio->pts = pos-((ds_tell_pts(demuxer->audio)-sh->a_in_buffer_len)/(float)sh->i_bps); } if(priv->sd != priv->vd) demux_seek(priv->sd,pos,audio_delay,1); }
static void get_disc_lang(struct stream *stream, struct sh_stream *sh) { struct stream_lang_req req = {.type = sh->type, .id = sh->demuxer_id}; if (stream->uncached_type == STREAMTYPE_DVD && sh->type == STREAM_SUB) req.id = req.id & 0x1F; // mpeg ID to index stream_control(stream, STREAM_CTRL_GET_LANG, &req); if (req.name[0]) sh->lang = talloc_strdup(sh, req.name); } static void add_dvd_streams(demuxer_t *demuxer) { struct priv *p = demuxer->priv; struct stream *stream = demuxer->stream; if (stream->uncached_type != STREAMTYPE_DVD) return; struct stream_dvd_info_req info; if (stream_control(stream, STREAM_CTRL_GET_DVD_INFO, &info) > 0) { for (int n = 0; n < MPMIN(32, info.num_subs); n++) { struct sh_stream *sh = demux_alloc_sh_stream(STREAM_SUB); sh->demuxer_id = n + 0x20; sh->codec->codec = "dvd_subtitle"; get_disc_lang(stream, sh); // p->streams _must_ match with p->slave->streams, so we can't add // it yet - it has to be done when the real stream appears, which // could be right on start, or any time later. p->dvd_subs[n] = sh; // emulate the extradata struct mp_csp_params csp = MP_CSP_PARAMS_DEFAULTS; struct mp_cmat cmatrix; mp_get_csp_matrix(&csp, &cmatrix); char *s = talloc_strdup(sh, ""); s = talloc_asprintf_append(s, "palette: "); for (int i = 0; i < 16; i++) { int color = info.palette[i]; int y[3] = {(color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff}; int c[3]; mp_map_fixp_color(&cmatrix, 8, y, 8, c); color = (c[2] << 16) | (c[1] << 8) | c[0]; if (i != 0) s = talloc_asprintf_append(s, ", "); s = talloc_asprintf_append(s, "%06x", color); } s = talloc_asprintf_append(s, "\n"); sh->codec->extradata = s; sh->codec->extradata_size = strlen(s); demux_add_sh_stream(demuxer, sh); } } } static void add_streams(demuxer_t *demuxer) { struct priv *p = demuxer->priv; for (int n = p->num_streams; n < demux_get_num_stream(p->slave); n++) { struct sh_stream *src = demux_get_stream(p->slave, n); if (src->type == STREAM_SUB) { struct sh_stream *sub = NULL; if (src->demuxer_id >= 0x20 && src->demuxer_id <= 0x3F) sub = p->dvd_subs[src->demuxer_id - 0x20]; if (sub) { assert(p->num_streams == n); // directly mapped MP_TARRAY_APPEND(p, p->streams, p->num_streams, sub); continue; } } struct sh_stream *sh = demux_alloc_sh_stream(src->type); assert(p->num_streams == n); // directly mapped MP_TARRAY_APPEND(p, p->streams, p->num_streams, sh); // Copy all stream fields that might be relevant *sh->codec = *src->codec; sh->demuxer_id = src->demuxer_id; if (src->type == STREAM_VIDEO) { double ar; if (stream_control(demuxer->stream, STREAM_CTRL_GET_ASPECT_RATIO, &ar) == STREAM_OK) { struct mp_image_params f = {.w = src->codec->disp_w, .h = src->codec->disp_h}; mp_image_params_set_dsize(&f, 1728 * ar, 1728); sh->codec->par_w = f.p_w; sh->codec->par_h = f.p_h; } } get_disc_lang(demuxer->stream, sh); demux_add_sh_stream(demuxer, sh); } reselect_streams(demuxer); } static void d_seek(demuxer_t *demuxer, double rel_seek_secs, int flags) { struct priv *p = demuxer->priv; if (demuxer->stream->uncached_type == STREAMTYPE_CDDA) { demux_seek(p->slave, rel_seek_secs, flags); return; } double pts = p->seek_pts; if (flags & SEEK_ABSOLUTE) pts = 0.0f; double base_pts = pts; // to what pts is relative if (flags & SEEK_FACTOR) { double tmp = 0; stream_control(demuxer->stream, STREAM_CTRL_GET_TIME_LENGTH, &tmp); pts += tmp * rel_seek_secs; } else { pts += rel_seek_secs; } MP_VERBOSE(demuxer, "seek to: %f\n", pts); double seek_arg[] = {pts, base_pts, flags}; stream_control(demuxer->stream, STREAM_CTRL_SEEK_TO_TIME, seek_arg); demux_control(p->slave, DEMUXER_CTRL_RESYNC, NULL); p->seek_pts = pts; p->seek_reinit = true; } static void reset_pts(demuxer_t *demuxer) { struct priv *p = demuxer->priv; double base; if (stream_control(demuxer->stream, STREAM_CTRL_GET_CURRENT_TIME, &base) < 1) base = 0; MP_VERBOSE(demuxer, "reset to time: %f\n", base); p->base_dts = p->last_dts = MP_NOPTS_VALUE; p->base_time = base; p->seek_reinit = false; } static int d_fill_buffer(demuxer_t *demuxer) { struct priv *p = demuxer->priv; struct demux_packet *pkt = demux_read_any_packet(p->slave); if (!pkt) return 0; demux_update(p->slave); if (p->seek_reinit) reset_pts(demuxer); add_streams(demuxer); if (pkt->stream >= p->num_streams) { // out of memory? talloc_free(pkt); return 0; } struct sh_stream *sh = p->streams[pkt->stream]; if (!demux_stream_is_selected(sh)) { talloc_free(pkt); return 1; } if (demuxer->stream->uncached_type == STREAMTYPE_CDDA) { demux_add_packet(sh, pkt); return 1; } MP_TRACE(demuxer, "ipts: %d %f %f\n", sh->type, pkt->pts, pkt->dts); if (sh->type == STREAM_SUB) { if (p->base_dts == MP_NOPTS_VALUE) MP_WARN(demuxer, "subtitle packet along PTS reset\n"); } else if (pkt->dts != MP_NOPTS_VALUE) { // Use the very first DTS to rebase the start time of the MPEG stream // to the playback time. if (p->base_dts == MP_NOPTS_VALUE) p->base_dts = pkt->dts; if (p->last_dts == MP_NOPTS_VALUE) p->last_dts = pkt->dts; if (fabs(p->last_dts - pkt->dts) >= DTS_RESET_THRESHOLD) { MP_WARN(demuxer, "PTS discontinuity: %f->%f\n", p->last_dts, pkt->dts); p->base_time += p->last_dts - p->base_dts; p->base_dts = pkt->dts - pkt->duration; } p->last_dts = pkt->dts; } if (p->base_dts != MP_NOPTS_VALUE) { double delta = -p->base_dts + p->base_time; if (pkt->pts != MP_NOPTS_VALUE) pkt->pts += delta; if (pkt->dts != MP_NOPTS_VALUE) pkt->dts += delta; } MP_TRACE(demuxer, "opts: %d %f %f\n", sh->type, pkt->pts, pkt->dts); if (pkt->pts != MP_NOPTS_VALUE) p->seek_pts = pkt->pts; demux_add_packet(sh, pkt); return 1; } static void add_stream_chapters(struct demuxer *demuxer) { int num = 0; if (stream_control(demuxer->stream, STREAM_CTRL_GET_NUM_CHAPTERS, &num) < 1) return; for (int n = 0; n < num; n++) { double p = n; if (stream_control(demuxer->stream, STREAM_CTRL_GET_CHAPTER_TIME, &p) < 1) continue; demuxer_add_chapter(demuxer, "", p, 0); } }
void video_callback(mvp_widget_t *widget, char key) { int jump; long long offset, size; pts_sync_data_t async, vsync; av_state_t state; /* printf("**SSDEBUG: In video_callback and got key %d \n",key); */ if (!video_playing) return; if(showing_guide) { if(mvp_tvguide_callback(widget, key) == 1) return; } if ( video_functions->key != NULL ) { if ( video_functions->key(key) == 1 ) { return; } } switch (key) { case MVPW_KEY_GO: case MVPW_KEY_GUIDE: if(showing_guide == 0 && showing_guide == 0) { printf("In %s showing guide %d \n",__FUNCTION__, key); showing_guide = 1; mvp_tvguide_video_topright(1); mvp_tvguide_show(mythtv_livetv_program_list, mythtv_livetv_description, mythtv_livetv_clock); break; } /* if the guide button is pressed while guide is active fall through to go back to remove guide and return to TV */ case MVPW_KEY_TV: if(showing_guide == 1) { printf("In %s hiding guide %d \n", __FUNCTION__, key); showing_guide = 0; mvp_tvguide_video_topright(0); mvp_tvguide_hide(mythtv_livetv_program_list, mythtv_livetv_description, mythtv_livetv_clock); } break; case MVPW_KEY_STOP: case MVPW_KEY_EXIT: back_to_guide_menu(); new_live_tv = 0; break; case MVPW_KEY_PAUSE: if (av_pause()) { mvpw_show(pause_widget); mvpw_hide(ffwd_widget); paused = 1; if (pause_osd && !display_on && (display_on_alt < 2)) { display_on_alt = 2; enable_osd(); } screensaver_enable(); } else { if (pause_osd && !display_on && (display_on_alt == 2)) { display_on_alt = 0; disable_osd(); mvpw_expose(root); } av_get_state(&state); if (state.mute) mvpw_show(mute_widget); else mvpw_hide(mute_widget); mvpw_hide(pause_widget); paused = 0; screensaver_disable(); } break; case MVPW_KEY_PLAY: if ( paused ) { /* * play key can be used to un-pause */ av_pause(); if (pause_osd && !display_on && (display_on_alt == 2)) { display_on_alt = 0; disable_osd(); mvpw_expose(root); } mvpw_hide(pause_widget); mvpw_hide(mute_widget); paused = 0; screensaver_disable(); } break; case MVPW_KEY_REPLAY: seek_by(-30); timed_osd(seek_osd_timeout*1000); break; case MVPW_KEY_REWIND: seek_by(-10); timed_osd(seek_osd_timeout*1000); break; case MVPW_KEY_SKIP: if (mythtv_seek_amount == 0 ) { seek_by(30); } else if (mythtv_seek_amount == 1 ) { seek_by(60); } else { seek_by(30); } timed_osd(seek_osd_timeout*1000); break; case MVPW_KEY_FFWD: if (av_ffwd() == 0) { demux_flush(handle); demux_seek(handle); av_get_state(&state); av_stop(); av_reset(); if (state.mute) { av_set_mute(1); } av_play(); mvpw_hide(ffwd_widget); } else { av_get_state(&state); mvpw_show(ffwd_widget); mvpw_hide(pause_widget); screensaver_disable(); } timed_osd(seek_osd_timeout*1000); break; case MVPW_KEY_LEFT: if (video_functions->seek) { size = video_functions->size(); jump_target = -1; jumping = 1; if (video_write_thread) { pthread_kill(video_write_thread, SIGURG); } if (audio_write_thread) { pthread_kill(audio_write_thread, SIGURG); } offset = video_functions->seek(0, SEEK_CUR); jump_target = ((-size / 100.0) + offset); pthread_cond_broadcast(&video_cond); } break; case MVPW_KEY_RIGHT: if (video_functions->seek) { size = video_functions->size(); jump_target = -1; jumping = 1; if (video_write_thread) { pthread_kill(video_write_thread, SIGURG); } if (audio_write_thread) { pthread_kill(audio_write_thread, SIGURG); } offset = video_functions->seek(0, SEEK_CUR); jump_target = ((size / 100.0) + offset); pthread_cond_broadcast(&video_cond); timed_osd(seek_osd_timeout*1000); } break; case MVPW_KEY_ZERO ... MVPW_KEY_NINE: if(new_live_tv) { printf("In %s showing guide %d \n",__FUNCTION__, key); showing_guide = 1; mvp_tvguide_video_topright(1); mvp_tvguide_show(mythtv_livetv_program_list, mythtv_livetv_description, mythtv_livetv_clock); mvp_tvguide_callback(widget, key); } else if (mythtv_livetv) { back_to_guide_menu(); mythtv_key_callback(mythtv_browser, key); } else { size = video_functions->size(); jump_target = -1; jumping = 1; if (video_write_thread) { pthread_kill(video_write_thread, SIGURG); } if (audio_write_thread) { pthread_kill(audio_write_thread, SIGURG); } jump = key; jump_target = size * (jump / 10.0); pthread_cond_broadcast(&video_cond); timed_osd(seek_osd_timeout*1000); } break; case MVPW_KEY_MENU: mvpw_show(popup_menu); mvpw_focus(popup_menu); break; case MVPW_KEY_MUTE: if (mvpw_visible(ffwd_widget)) { mvpw_hide(mute_widget); break; } if (av_mute() == 1) { mvpw_show(mute_widget); } else { mvpw_hide(mute_widget); } break; case MVPW_KEY_BLANK: case MVPW_KEY_OK: if (display_on || display_on_alt) { disable_osd(); mvpw_expose(root); display_on = 1; display_on_alt = 0; } else { enable_osd(); } display_on = !display_on; break; case MVPW_KEY_FULL: case MVPW_KEY_PREV_CHAN: if(IS_4x3(av_get_tv_aspect())) { if(av_get_tv_aspect() == AV_TV_ASPECT_4x3_CCO) av_set_tv_aspect(AV_TV_ASPECT_4x3); else av_set_tv_aspect(AV_TV_ASPECT_4x3_CCO); } break; case MVPW_KEY_CHAN_UP: case MVPW_KEY_UP: if (mythtv_livetv) mythtv_channel_up(); break; case MVPW_KEY_CHAN_DOWN: case MVPW_KEY_DOWN: if (mythtv_livetv) mythtv_channel_down(); break; case MVPW_KEY_RECORD: /* * XXX: This is a temporary hack until we figure out how * to tell when the audio and video are out of sync, * and correct it automatically. */ av_get_audio_sync(&async); av_get_video_sync(&vsync); printf("PRE SYNC: a 0x%"PRIx64" 0x%"PRIx64" v 0x%"PRIx64" 0x%"PRIx64"\n", async.stc, async.pts, vsync.stc, vsync.pts); av_delay_video(1000); av_get_audio_sync(&async); av_get_video_sync(&vsync); printf("POST SYNC: a 0x%"PRIx64" 0x%"PRIx64" v 0x%"PRIx64" 0x%"PRIx64"\n", async.stc, async.pts, vsync.stc, vsync.pts); break; case MVPW_KEY_VOL_UP: case MVPW_KEY_VOL_DOWN: volume_key_callback(volume_dialog, key); mvpw_show(volume_dialog); mvpw_set_timer(volume_dialog, timer_hide, 3000); break; default: PRINTF("button %d\n", key); break; } }
void* video_read_start(void *arg) { pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int ret; int n = 0, len = 0, reset = 1; int sent_idle_notify; demux_attr_t *attr; video_info_t *vi; int set_aspect = 1; char *inbuf = inbuf_static; char *tsbuf; int tslen; int tsmode = TS_MODE_UNKNOWN; av_state_t state; pthread_mutex_lock(&mutex); printf("mpeg read thread started (pid %d)\n", getpid()); pthread_cond_wait(&video_cond, &mutex); while (1) { sent_idle_notify = 0; while (!video_playing) { demux_reset(handle); ts_demux_reset(tshandle); demux_seek(handle); vid_event_discontinuity_possible(); if ( !(sent_idle_notify) ) { if ( video_functions != NULL && video_functions->notify != NULL ) { video_functions->notify(MVP_READ_THREAD_IDLE); } printf("mpeg read thread sleeping...\n"); sent_idle_notify = 1; } pthread_cond_wait(&video_cond, &mutex); TRC("%s: past pthread_cond_wait(&video_cond, &mutex)\n", __FUNCTION__); } #ifdef STREAM_TEST if ( stream_test_started == 0 ) { stream_test_started = 1; //Get start time gettimeofday(&start_tv, NULL); } #endif if (video_reopen) { vid_event_clear(); if (video_functions->open() == 0) { /* Jump to the start of the new file */ jump_target = 0; jumping = 1; video_reopen = 0; tsmode = TS_MODE_UNKNOWN; } else { fprintf(stderr, "video open failed!\n"); video_playing = 0; continue; } len = 0; reset = 1; set_aspect = 1; } if ((seeking && reset) || jumping) { demux_reset(handle); ts_demux_reset(tshandle); demux_seek(handle); av_get_state(&state); av_reset(); av_reset_stc(); vid_event_discontinuity_possible(); if (seeking) reset = 0; if (state.mute) av_set_mute(1); if (paused) { av_play(); paused = 0; mvpw_hide(pause_widget); screensaver_disable(); } pcm_decoded = 0; ac3len = 0; len = 0; if (jumping) { while (jump_target < 0) usleep(1000); video_functions->seek(jump_target, SEEK_SET); } jumping = 0; } if ( !video_playing ) { continue; } if (len == 0) { if ( video_functions->read_dynb != NULL ){ tslen = video_functions->read_dynb(&tsbuf, 1024 * 256); } else { tsbuf = tsbuf_static; do { tslen = video_functions->read(tsbuf, sizeof(tsbuf_static)); } while ( tslen==-1 && errno==EAGAIN); } thruput_count += tslen; inbuf = inbuf_static; if (tsmode == TS_MODE_UNKNOWN) { if (tslen > 0) { tsmode = ts_demux_is_ts(tshandle, tsbuf, tslen); printf("auto detection transport stream returned %d\n", tsmode); if (tsmode == TS_MODE_NO) len = tslen; } } else if (tsmode == TS_MODE_NO) { len = tslen; } else { len = ts_demux_transform(tshandle, tsbuf, tslen, inbuf, sizeof(inbuf_static)); int resyncs = ts_demux_resync_count(tshandle); if (resyncs > 50) { printf("resync count = %d, switch back to unknown mode\n", resyncs); tsmode = TS_MODE_UNKNOWN; ts_demux_reset(tshandle); } } n = 0; if (len == 0 && playlist ) { video_reopen = 2; playlist_next(); } } if ( !video_playing ) { continue; } #ifdef STREAM_TEST stream_test_cnt += len; len = 0; if ( stream_test_cnt > 1024*1024*20 ) { unsigned int delta_ms; gettimeofday(&done_tv, NULL); if ( done_tv.tv_usec < start_tv.tv_usec ) { done_tv.tv_usec += 1000000; done_tv.tv_sec -= 1; } delta_ms = (done_tv.tv_sec - start_tv.tv_sec) * 1000; delta_ms += (done_tv.tv_usec - start_tv.tv_usec) / 1000; printf("Test Done\n"); printf("Bytes transferred: %u\n", stream_test_cnt); printf("Elapsed time %u mS\n", delta_ms); while ( 1 ) { sleep(10); printf("Test Done....\n"); } } continue; #else if (tsmode == TS_MODE_YES) ret = DEMUX_PUT(handle, inbuf+n, len-n); else ret = DEMUX_PUT(handle, tsbuf+n, len-n); #endif if ((ret <= 0) && (!seeking)) { pthread_cond_broadcast(&video_cond); usleep(1000); continue; } if (seeking) { if (do_seek()) { len = 0; continue; } else { reset = 1; } } n += ret; if (n == len) len = 0; pthread_cond_broadcast(&video_cond); attr = demux_get_attr(handle); vi = &attr->video.stats.info.video; if (attr->audio.type != audio_type) { audio_type = attr->audio.type; switch (audio_type) { case AUDIO_MODE_AC3: if (audio_output_mode == AUD_OUTPUT_PASSTHRU ) { if (av_set_audio_output(AV_AUDIO_AC3) < 0) { /* revert to downmixing */ audio_output_mode = AUD_OUTPUT_STEREO; // fall through to PCM } else { // don't set audio_type audio_output = AV_AUDIO_AC3; printf("switch to AC3 Passthru\n"); break; } } case AUDIO_MODE_PCM: audio_output = AV_AUDIO_PCM; printf("switch to PCM audio output device\n"); break; default: av_set_audio_type(audio_type); audio_output = AV_AUDIO_MPEG; printf("switch to MPEG audio output device\n"); break; } av_set_audio_output(audio_output); } else { if (audio_type==AUDIO_MODE_AC3){ sync_ac3_audio(); } } } //while return NULL; }
int file_open(void) { seeking = 1; audio_selected = 0; audio_checks = 0; if ( http_playing == HTTP_FILE_CLOSED ) { if (video_reopen == 1) audio_clear(); close(fd); fd = -1; } if (video_write_thread) { pthread_kill(video_write_thread, SIGURG); } if (audio_write_thread) { pthread_kill(audio_write_thread, SIGURG); } if ( http_playing == HTTP_FILE_CLOSED ) { if (gui_state != MVPMC_STATE_EMULATE) { fd=open(current, O_RDONLY|O_LARGEFILE); } else { fd = open("/tmp/FIFO", O_RDONLY); } if (fd < 0) { printf("Open failed errno %d file %s\n", errno, current); video_reopen = 0; return -1; } printf("opened %s\n", current); } else { printf("http opened %s\n", current); } if (video_reopen == 1) { av_set_audio_output(AV_AUDIO_MPEG); fd_audio = av_get_audio_fd(); av_play(); demux_reset(handle); ts_demux_reset(tshandle); demux_attr_reset(handle); demux_seek(handle); vid_event_discontinuity_possible(); if (gui_state == MVPMC_STATE_EMULATE || http_playing == HTTP_VIDEO_FILE_MPG) { video_thumbnail(AV_THUMBNAIL_OFF, 0); } else { video_thumbnail(AV_THUMBNAIL_EIGTH, 0); } av_play(); } zoomed = 0; display_on = 0; seeking = 0; jumping = 0; audio_type = 0; pcm_decoded = 0; ac3len = 0; video_reopen = 0; pthread_cond_broadcast(&video_cond); printf("write threads released\n"); return 0; }
static int do_seek(void) { demux_attr_t *attr; int seconds, new_seek_Bps; long long offset; struct timeval now, delta; static int count = 0; count++; attr = demux_get_attr(handle); gettimeofday(&now, NULL); timersub(&now, &seek_timeval, &delta); /* * Give up after 2 seconds */ if ((delta.tv_sec >= 2) && seeking) { seeking = 0; printf("SEEK ABORTED (%lu.%.2lu) %d\n", delta.tv_sec, delta.tv_usec/10000, count); count = 0; return 0; } if (!attr->gop_valid) { if ( --seek_attempts > 0 ) { PRINTF("GOP retry\n"); return -1; } printf("SEEK RETRY due to lack of GOP\n"); demux_flush(handle); demux_seek(handle); seek_attempts = 16; return -1; } if (pts_seek_attempts > 0) { seconds = attr->gop.pts/PTS_HZ; } else if (gop_seek_attempts > 0) { seconds = (attr->gop.hour * 3600) + (attr->gop.minute * 60) + attr->gop.second; } else { seconds = 0; } /* * Recompute Bps from actual time and position differences * provided the time difference is big enough */ if ( abs(seconds - seek_start_seconds) > SEEK_FUDGE ) { offset = video_functions->seek(0, SEEK_CUR); new_seek_Bps = (offset - seek_start_pos) / (seconds - seek_start_seconds); if ( new_seek_Bps > 10000 ) /* Sanity check */ seek_Bps = new_seek_Bps; } PRINTF("New Bps %d\n", seek_Bps); if ( abs(seconds - seek_seconds) <= SEEK_FUDGE ) { seeking = 0; printf("SEEK DONE: to %d at %d (%lu.%.2lu) %d\n", seek_seconds, seconds, delta.tv_sec, delta.tv_usec/10000, count); } else { offset = video_functions->seek(0, SEEK_CUR); PRINTF("RESEEK: From %lld + %d\n", offset, seek_Bps * (seek_seconds-seconds)); offset = video_functions->seek(seek_Bps * (seek_seconds-seconds), SEEK_CUR); demux_flush(handle); demux_seek(handle); seek_attempts--; PRINTF("SEEKING 1: %d/%d %lld\n", seconds, seek_seconds, offset); return -1; } count = 0; return 0; }
void reinit_subs(struct MPContext *mpctx) { struct MPOpts *opts = mpctx->opts; struct track *track = mpctx->current_track[STREAM_SUB]; assert(!(mpctx->initialized_flags & INITIALIZED_SUB)); init_demux_stream(mpctx, STREAM_SUB); struct sh_stream *sh = mpctx->sh[STREAM_SUB]; // No track selected, or lazily added DVD track (will actually be created // on first sub packet) if (!sh) return; if (!sh->sub->dec_sub) { assert(!mpctx->d_sub); sh->sub->dec_sub = sub_create(mpctx->global); } assert(!mpctx->d_sub || sh->sub->dec_sub == mpctx->d_sub); // The decoder is kept in the stream header in order to make ordered // chapters work well. mpctx->d_sub = sh->sub->dec_sub; mpctx->initialized_flags |= INITIALIZED_SUB; struct dec_sub *dec_sub = mpctx->d_sub; assert(dec_sub); if (!sub_is_initialized(dec_sub)) { struct sh_video *sh_video = mpctx->d_video ? mpctx->d_video->header->video : NULL; int w = sh_video ? sh_video->disp_w : 0; int h = sh_video ? sh_video->disp_h : 0; float fps = sh_video ? sh_video->fps : 25; set_dvdsub_fake_extradata(dec_sub, track->demuxer->stream, w, h); sub_set_video_res(dec_sub, w, h); sub_set_video_fps(dec_sub, fps); sub_set_ass_renderer(dec_sub, mpctx->ass_library, mpctx->ass_renderer); sub_init_from_sh(dec_sub, sh); // Don't do this if the file has video/audio streams. Don't do it even // if it has only sub streams, because reading packets will change the // demuxer position. if (!track->preloaded && track->is_external) { demux_seek(track->demuxer, 0, SEEK_ABSOLUTE); track->preloaded = sub_read_all_packets(dec_sub, sh); } } mpctx->osd->dec_sub = dec_sub; // Decides whether to use OSD path or normal subtitle rendering path. mpctx->osd->render_bitmap_subs = opts->ass_enabled || !sub_has_get_text(dec_sub); reset_subtitles(mpctx); }