webpopup_result_t * webpopup_create(const char *url, const char *title, const char *trap) { webpopup_t *wp = calloc(1, sizeof(webpopup_t)); webpopup_result_t *wr = &wp->wp_wr; hts_cond_init(&wp->wp_cond, &gdk_mutex); wp->wp_wr.wr_resultcode = -1; wp->wp_url = strdup(url); wp->wp_title = strdup(title); wp->wp_trap = strdup(trap); hts_mutex_lock(&gdk_mutex); LIST_INSERT_HEAD(&pending_open, wp, wp_link); g_main_context_wakeup(g_main_context_default()); while(wp->wp_wr.wr_resultcode == -1) hts_cond_wait(&wp->wp_cond, &gdk_mutex); gdk_threads_leave(); webpopup_finalize_result(wr); free(wp->wp_url); free(wp->wp_title); free(wp->wp_trap); return wr; }
void omx_wait_command(omx_component_t *oc) { hts_mutex_lock(&oc->oc_event_mtx); while(!oc->oc_cmd_done) hts_cond_wait(&oc->oc_event_cond, &oc->oc_event_mtx); hts_mutex_unlock(&oc->oc_event_mtx); }
void omx_wait_buffers(omx_component_t *oc) { hts_mutex_lock(oc->oc_mtx); while(oc->oc_inflight_buffers) hts_cond_wait(oc->oc_avail_cond, oc->oc_mtx); hts_mutex_unlock(oc->oc_mtx); }
int omx_wait_fill_buffer(omx_component_t *oc, OMX_BUFFERHEADERTYPE *buf) { hts_mutex_lock(oc->oc_mtx); while(oc->oc_filled == NULL) hts_cond_wait(oc->oc_avail_cond, oc->oc_mtx); hts_mutex_unlock(oc->oc_mtx); return 0; }
OMX_BUFFERHEADERTYPE * omx_get_buffer_locked(omx_component_t *oc) { OMX_BUFFERHEADERTYPE *buf; while((buf = oc->oc_avail) == NULL) hts_cond_wait(oc->oc_avail_cond, oc->oc_avail_mtx); oc->oc_avail = buf->pAppPrivate; oc->oc_inflight_buffers++; return buf; }
static void end_sequence_and_wait(vdec_decoder_t *vdd) { TRACE(TRACE_DEBUG, "VDEC", "Waiting for end sequence"); vdd->sequence_done = 0; vdec_end_sequence(vdd->handle); hts_mutex_lock(&vdd->mtx); while(vdd->sequence_done == 0) hts_cond_wait(&vdd->seqdone, &vdd->mtx); hts_mutex_unlock(&vdd->mtx); TRACE(TRACE_DEBUG, "VDEC", "Waiting for end sequence -> done"); }
event_t * mp_dequeue_event(media_pipe_t *mp) { event_t *e; hts_mutex_lock(&mp->mp_mutex); while((e = TAILQ_FIRST(&mp->mp_eq)) == NULL) hts_cond_wait(&mp->mp_backpressure, &mp->mp_mutex); TAILQ_REMOVE(&mp->mp_eq, e, e_link); hts_mutex_unlock(&mp->mp_mutex); return e; }
static void web_shutdown(void *opaque, int retcode) { hts_mutex_lock(&web_mutex); if(browser_open) { TRACE(TRACE_DEBUG, "WEB", "Browser open on shutdown, forcing close"); int r = webBrowserDestroy(); TRACE(TRACE_DEBUG, "WEB", "Browser force code:0x%x", r); while(browser_open) hts_cond_wait(&web_cond,&web_mutex); } hts_mutex_unlock(&web_mutex); }
static fa_handle_t * es_fap_open(struct fa_protocol *fap, const char *url, char *errbuf, size_t errsize, int flags, struct fa_open_extra *foe) { es_fa_handle_t *fah = calloc(1, sizeof(es_fa_handle_t)); fah->fah_size = -1; es_fap_t *ef = fap->fap_opaque; fah->fh.fh_proto = fap; fah->fah_ef = ef; es_resource_retain(&ef->super); fah->fah_url = strdup(url); fah->fah_errbuf = errbuf; fah->fah_errsize = errsize; fah->fah_flags = flags; atomic_set(&fah->fah_refcount, 2); // One to return, one for task hts_mutex_lock(&es_fa_mutex); fah->fah_status = ES_FA_WORKING; task_run(es_fa_open, fah); while(fah->fah_status == ES_FA_WORKING) hts_cond_wait(&es_fa_cond, &es_fa_mutex); fah->fah_errbuf = NULL; fah->fah_errsize = 0; hts_mutex_unlock(&es_fa_mutex); switch(fah->fah_status) { case ES_FA_OK: return &fah->fh; case ES_FA_CANCELLED: snprintf(errbuf, errsize, "Cancelled"); // FALLTHRU case ES_FA_ERROR: fah_release(fah); break; } return NULL; }
webpopup_result_t * webpopup_create(const char *url, const char *title, const char *traps) { hts_mutex_lock(&web_mutex); if(start_browser(url)) { hts_mutex_unlock(&web_mutex); return NULL; } while(browser_open != 2) hts_cond_wait(&web_cond, &web_mutex); hts_mutex_unlock(&web_mutex); return NULL; }
static void es_fap_close(fa_handle_t *fh) { es_fa_handle_t *fah = (es_fa_handle_t *)fh; hts_mutex_lock(&es_fa_mutex); fah->fah_status = ES_FA_WORKING; task_run(es_fa_close, fah_retain(fah)); while(fah->fah_status == ES_FA_WORKING) hts_cond_wait(&es_fa_cond, &es_fa_mutex); hts_mutex_unlock(&es_fa_mutex); fah_release(fah); }
static int start_browser(const char *url) { // only one guy at the time while(browser_open) hts_cond_wait(&web_cond, &web_mutex); webBrowserConfig(&webcfg, 0x20000); // V2 webBrowserConfigSetFunction(&webcfg, 0x20 | 0x40); webBrowserConfigSetHeapSize(&webcfg, 48*1024*1024); webBrowserConfigSetTabCount(&webcfg, 1); webcfg.x = 200; webcfg.y = 200; webcfg.width = 800; webcfg.height = 600; webcfg.resolution_factor = 1; int mc_size; webBrowserEstimate(&webcfg, &mc_size); TRACE(TRACE_DEBUG, "WEB", "Required memory for browser: %d", mc_size); int r = lv2MemContinerCreate(&memcontainer, mc_size); if(r) { TRACE(TRACE_ERROR, "WEB", "Unable to alloc mem for browser -- 0x%x", r); return r; } webBrowserSetRequestHook(&webcfg, OPD32(nav_callback), NULL); r = webBrowserInitialize(OPD32(web_sys_callback), memcontainer); if(r) { TRACE(TRACE_ERROR, "WEB", "Unable to alloc mem for browser -- 0x%x", r); return r; } TRACE(TRACE_DEBUG, "WEB", "Browser opening %s", url); webcfg.request_cb = (intptr_t)OPD32(nav_callback); webBrowserCreate(&webcfg, url); browser_open = 1; return 0; }
static int es_fap_stat(struct fa_protocol *fap, const char *url, struct fa_stat *buf, int flags, char *errbuf, size_t errsize) { es_fa_handle_t *fah = calloc(1, sizeof(es_fa_handle_t)); es_fap_t *ef = fap->fap_opaque; fah->fah_url = strdup(url); fah->fh.fh_proto = fap; fah->fah_ef = ef; es_resource_retain(&ef->super); atomic_set(&fah->fah_refcount, 2); fah->fah_errbuf = errbuf; fah->fah_errsize = errsize; fah->fah_status = ES_FA_WORKING; task_run(es_fa_stat, fah); hts_mutex_lock(&es_fa_mutex); while(fah->fah_status == ES_FA_WORKING) hts_cond_wait(&es_fa_cond, &es_fa_mutex); fah->fah_errbuf = NULL; fah->fah_errsize = 0; hts_mutex_unlock(&es_fa_mutex); int r = fah->fah_return_value; if(!r) { buf->fs_size = fah->fah_size; buf->fs_type = fah->fah_type; buf->fs_mtime = fah->fah_mtime; } fah_release(fah); return r; }
static int es_fap_read(fa_handle_t *fh, void *buf, size_t size) { es_fa_handle_t *fah = (es_fa_handle_t *)fh; fah->fah_readbuf = buf; fah->fah_readlen = size; hts_mutex_lock(&es_fa_mutex); fah->fah_status = ES_FA_WORKING; task_run(es_fa_read, fah_retain(fah)); while(fah->fah_status == ES_FA_WORKING) hts_cond_wait(&es_fa_cond, &es_fa_mutex); hts_mutex_unlock(&es_fa_mutex); es_fap_t *ef = fah->fah_ef; es_context_t *ec = ef->super.er_ctx; duk_context *ctx = ec->ec_duk; es_context_begin(ec); es_push_root(ctx, fah->fah_readbuf); duk_config_buffer(ctx, -1, NULL, 0); es_root_unregister(ctx, fah->fah_readbuf); es_context_end(ec, 0); switch(fah->fah_status) { case ES_FA_OK: fah->fah_fpos += fah->fah_return_value; return fah->fah_return_value; case ES_FA_CANCELLED: case ES_FA_ERROR: return -1; } return 0; }
static void * omx_clk_thread(void *aux) { omx_clk_cmd_t *cmd; omx_clk_t *clk = aux; int run = 1; hts_mutex_lock(&clk->mp->mp_mutex); while(run) { while((cmd = TAILQ_FIRST(&clk->q)) == NULL) { hts_cond_wait(&clk->cond, &clk->mp->mp_mutex); continue; } TAILQ_REMOVE(&clk->q, cmd, link); hts_mutex_unlock(&clk->mp->mp_mutex); switch(cmd->cmd) { case OMX_CLK_QUIT: run = 0; break; case OMX_CLK_PAUSE: omx_clk_set_speed(clk, 0); break; case OMX_CLK_PLAY: omx_clk_set_speed(clk, 1 << 16); break; } free(cmd); hts_mutex_lock(&clk->mp->mp_mutex); } hts_mutex_unlock(&clk->mp->mp_mutex); return NULL; }
JNIEXPORT void JNICALL Java_com_showtimemediacenter_showtime_STCore_glwDestroy(JNIEnv *env, jobject obj, jint id) { android_glw_root_t *agr = (android_glw_root_t *)id; glw_root_t *gr = &agr->gr; TRACE(TRACE_DEBUG, "GLW", "GLW %p destroying", agr); glw_lock(gr); while(agr->agr_running == 1) hts_cond_wait(&agr->agr_runcond, &gr->gr_mutex); glw_unlock(gr); TRACE(TRACE_DEBUG, "GLW", "GLW %p destroyed", agr); (*env)->DeleteGlobalRef(env, agr->agr_vrp); glw_unload_universe(gr); glw_fini(gr); free(gr); }
void glw_cond_wait(glw_root_t *gr, hts_cond_t *c) { hts_cond_wait(c, &gr->gr_mutex); }
static void * dummy_audio_thread(void *aux) { audio_decoder_t *ad = aux; media_pipe_t *mp = ad->ad_mp; media_queue_t *mq = &mp->mp_audio; media_buf_t *mb; int hold = 0; int run = 1; int64_t rt = 0; int64_t base = AV_NOPTS_VALUE; hts_mutex_lock(&mp->mp_mutex); while(run) { if((mb = TAILQ_FIRST(&mq->mq_q)) == NULL) { hts_cond_wait(&mq->mq_avail, &mp->mp_mutex); continue; } if(mb->mb_data_type == MB_AUDIO && hold && mb->mb_skip == 0) { hts_cond_wait(&mq->mq_avail, &mp->mp_mutex); continue; } TAILQ_REMOVE(&mq->mq_q, mb, mb_link); mq->mq_packets_current--; mp->mp_buffer_current -= mb->mb_size; mq_update_stats(mp, mq); hts_cond_signal(&mp->mp_backpressure); hts_mutex_unlock(&mp->mp_mutex); switch(mb->mb_data_type) { case MB_CTRL_EXIT: run = 0; break; case MB_CTRL_PAUSE: hold = 1; break; case MB_CTRL_PLAY: hold = 0; base = AV_NOPTS_VALUE; break; case MB_FLUSH: base = AV_NOPTS_VALUE; break; case MB_AUDIO: if(mb->mb_skip || mb->mb_stream != mq->mq_stream) break; if(mb->mb_pts != AV_NOPTS_VALUE) { audio_set_clock(mp, mb->mb_pts, 0, mb->mb_epoch); if(base == AV_NOPTS_VALUE) { base = mb->mb_pts; rt = showtime_get_ts(); } else { int64_t d = mb->mb_pts - base; if(d > 0) { int sleeptime = rt + d - showtime_get_ts(); if(sleeptime > 0) usleep(sleeptime); } } } break; default: abort(); } hts_mutex_lock(&mp->mp_mutex); media_buf_free_locked(mp, mb); } hts_mutex_unlock(&mp->mp_mutex); return NULL; }
static htsmsg_t * htsp_reqreply(htsp_connection_t *hc, htsmsg_t *m) { void *buf; size_t len; uint32_t seq; int r; tcpcon_t *tc = hc->hc_tc; uint32_t noaccess; htsmsg_t *reply; htsp_msg_t *hm = NULL; int retry = 0; char id[100]; char *username; char *password; sha1_decl(shactx); uint8_t d[20]; if(tc == NULL) return NULL; /* Generate a sequence number for our message */ seq = atomic_add(&hc->hc_seq_generator, 1); htsmsg_add_u32(m, "seq", seq); again: snprintf(id, sizeof(id), "htsp://%s:%d", hc->hc_hostname, hc->hc_port); r = keyring_lookup(id, &username, &password, NULL, NULL, "TV client", "Access denied", (retry ? KEYRING_QUERY_USER : 0) | KEYRING_SHOW_REMEMBER_ME | KEYRING_REMEMBER_ME_SET); if(r == -1) { /* User rejected */ return NULL; } if(r == 0) { /* Got auth credentials */ htsmsg_delete_field(m, "username"); htsmsg_delete_field(m, "digest"); if(username != NULL) htsmsg_add_str(m, "username", username); if(password != NULL) { sha1_init(shactx); sha1_update(shactx, (const uint8_t *)password, strlen(password)); sha1_update(shactx, hc->hc_challenge, 32); sha1_final(shactx, d); htsmsg_add_bin(m, "digest", d, 20); } free(username); free(password); } if(htsmsg_binary_serialize(m, &buf, &len, -1) < 0) { htsmsg_destroy(m); return NULL; } if(hc->hc_is_async) { /* Async, set up a struct that will be signalled when we get a reply */ hm = malloc(sizeof(htsp_msg_t)); hm->hm_msg = NULL; hm->hm_seq = seq; hm->hm_error = 0; hts_mutex_lock(&hc->hc_rpc_mutex); TAILQ_INSERT_TAIL(&hc->hc_rpc_queue, hm, hm_link); hts_mutex_unlock(&hc->hc_rpc_mutex); } if(tc->write(tc, buf, len)) { free(buf); htsmsg_destroy(m); if(hm != NULL) { hts_mutex_lock(&hc->hc_rpc_mutex); TAILQ_REMOVE(&hc->hc_rpc_queue, hm, hm_link); hts_mutex_unlock(&hc->hc_rpc_mutex); free(hm); } return NULL; } free(buf); if(hm != NULL) { hts_mutex_lock(&hc->hc_rpc_mutex); while(1) { if(hm->hm_error != 0) { r = hm->hm_error; TAILQ_REMOVE(&hc->hc_rpc_queue, hm, hm_link); hts_mutex_unlock(&hc->hc_rpc_mutex); free(hm); htsmsg_destroy(m); return NULL; } if(hm->hm_msg != NULL) break; hts_cond_wait(&hc->hc_rpc_cond, &hc->hc_rpc_mutex); } TAILQ_REMOVE(&hc->hc_rpc_queue, hm, hm_link); hts_mutex_unlock(&hc->hc_rpc_mutex); reply = hm->hm_msg; free(hm); } else { if((reply = htsp_recv(hc)) == NULL) { htsmsg_destroy(m); return NULL; } } if(!htsmsg_get_u32(reply, "noaccess", &noaccess) && noaccess) { retry++; goto again; } htsmsg_destroy(m); /* Destroy original message */ return reply; }
void * audio_decode_thread(void *aux) { audio_decoder_t *ad = aux; const audio_class_t *ac = ad->ad_ac; int run = 1; media_pipe_t *mp = ad->ad_mp; media_queue_t *mq = &mp->mp_audio; media_buf_t *mb; int blocked = 0; if(ac->ac_init != NULL) ac->ac_init(ad); ad->ad_discontinuity = 1; hts_mutex_lock(&mp->mp_mutex); while(run) { int avail; if(ad->ad_spdif_muxer != NULL) { avail = ad->ad_spdif_frame_size; } else { avail = ad->ad_avr != NULL ? avresample_available(ad->ad_avr) : 0; } media_buf_t *data = TAILQ_FIRST(&mq->mq_q_data); media_buf_t *ctrl = TAILQ_FIRST(&mq->mq_q_ctrl); if(avail >= ad->ad_tile_size && blocked == 0 && !ad->ad_paused && !ctrl) { assert(avail != 0); int samples = MIN(ad->ad_tile_size, avail); int r; if(ac->ac_deliver_locked != NULL) { r = ac->ac_deliver_locked(ad, samples, ad->ad_pts, ad->ad_epoch); if(r) { hts_cond_wait(&mq->mq_avail, &mp->mp_mutex); continue; } } else { hts_mutex_unlock(&mp->mp_mutex); r = ac->ac_deliver_unlocked(ad, samples, ad->ad_pts, ad->ad_epoch); hts_mutex_lock(&mp->mp_mutex); } if(r) { blocked = 1; } else { ad->ad_pts = AV_NOPTS_VALUE; } continue; } if(ctrl != NULL) { TAILQ_REMOVE(&mq->mq_q_ctrl, ctrl, mb_link); mb = ctrl; } else if(data != NULL && avail < ad->ad_tile_size) { TAILQ_REMOVE(&mq->mq_q_data, data, mb_link); mb = data; } else { hts_cond_wait(&mq->mq_avail, &mp->mp_mutex); continue; } mq->mq_packets_current--; mp->mp_buffer_current -= mb->mb_size; mq_update_stats(mp, mq); hts_cond_signal(&mp->mp_backpressure); if(mb->mb_data_type == MB_CTRL_UNBLOCK) { assert(blocked); blocked = 0; } else if(ad->ad_mode == AUDIO_MODE_CODED && ac->ac_deliver_coded_locked != NULL && mb->mb_data_type == MB_AUDIO) { ac->ac_deliver_coded_locked(ad, mb->mb_data, mb->mb_size, mb->mb_pts, mb->mb_epoch); } else { hts_mutex_unlock(&mp->mp_mutex); switch(mb->mb_data_type) { case MB_AUDIO: audio_process_audio(ad, mb); break; case MB_SET_PROP_STRING: prop_set_string(mb->mb_prop, (void *)mb->mb_data); break; case MB_CTRL_SET_VOLUME_MULTIPLIER: ad->ad_vol_scale = mb->mb_float; if(ac->ac_set_volume != NULL) ac->ac_set_volume(ad, ad->ad_vol_scale); break; case MB_CTRL_PAUSE: ad->ad_paused = 1; if(ac->ac_pause) ac->ac_pause(ad); break; case MB_CTRL_PLAY: ad->ad_paused = 0; if(ac->ac_play) ac->ac_play(ad); break; case MB_CTRL_FLUSH: // Reset some error reporting filters ad->ad_channel_layout_fail = 0; ad->ad_sample_rate_fail = 0; if(ac->ac_flush) ac->ac_flush(ad); ad->ad_pts = AV_NOPTS_VALUE; if(mp->mp_seek_audio_done != NULL) mp->mp_seek_audio_done(mp); ad->ad_discontinuity = 1; if(ad->ad_avr != NULL) { avresample_read(ad->ad_avr, NULL, avresample_available(ad->ad_avr)); assert(avresample_available(ad->ad_avr) == 0); } break; case MB_CTRL_EXIT: run = 0; break; default: abort(); } hts_mutex_lock(&mp->mp_mutex); } media_buf_free_locked(mp, mb); } hts_mutex_unlock(&mp->mp_mutex); if(ac->ac_fini != NULL) ac->ac_fini(ad); return NULL; }
static void * ad_thread(void *aux) { audio_decoder_t *ad = aux; media_pipe_t *mp = ad->ad_mp; media_queue_t *mq = &mp->mp_audio; media_buf_t *mb; int hold = 0; int run = 1; int64_t silence_start_pts = AV_NOPTS_VALUE; uint64_t silence_start_realtime = 0; hts_mutex_lock(&mp->mp_mutex); while(run) { if((mb = TAILQ_FIRST(&mq->mq_q)) == NULL) { hts_cond_wait(&mq->mq_avail, &mp->mp_mutex); continue; } if(mb->mb_data_type == MB_AUDIO && hold && mb->mb_skip == 0) { hts_cond_wait(&mq->mq_avail, &mp->mp_mutex); continue; } TAILQ_REMOVE(&mq->mq_q, mb, mb_link); mq->mq_packets_current--; mp->mp_buffer_current -= mb->mb_size; mq_update_stats(mp, mq); hts_cond_signal(&mp->mp_backpressure); hts_mutex_unlock(&mp->mp_mutex); switch(mb->mb_data_type) { case MB_CTRL_EXIT: run = 0; break; case MB_CTRL_PAUSE: /* Copy back any pending audio in the output fifo */ audio_fifo_purge(thefifo, ad, &ad->ad_hold_queue); hold = 1; break; case MB_CTRL_PLAY: hold = 0; break; case MB_FLUSH: ad->ad_do_flush = 1; /* Flush any pending audio in the output fifo */ audio_fifo_purge(thefifo, ad, NULL); audio_decoder_flush(ad); break; case MB_AUDIO: if(mb->mb_skip != 0) break; if(mq->mq_stream == -1) { if(mb->mb_pts == AV_NOPTS_VALUE) break; if(silence_start_pts == AV_NOPTS_VALUE) { silence_start_pts = mb->mb_pts; silence_start_realtime = showtime_get_ts(); } else { int64_t d = mb->mb_pts - silence_start_pts; if(d > 0) { int64_t sleeptime = silence_start_realtime + d - showtime_get_ts(); if(sleeptime > 0) usleep(sleeptime); } } break; } if(mb->mb_stream != mq->mq_stream) break; ad_decode_buf(ad, mp, mq, mb); silence_start_pts = AV_NOPTS_VALUE; break; case MB_END: mp_set_current_time(mp, AV_NOPTS_VALUE); break; default: abort(); } hts_mutex_lock(&mp->mp_mutex); media_buf_free_locked(mp, mb); } hts_mutex_unlock(&mp->mp_mutex); audio_fifo_purge(thefifo, ad, NULL); return NULL; }
void * audio_decode_thread(void *aux) { audio_decoder_t *ad = aux; const audio_class_t *ac = ad->ad_ac; int run = 1; media_pipe_t *mp = ad->ad_mp; media_queue_t *mq = &mp->mp_audio; media_buf_t *mb; int blocked = 0; if(ac->ac_init != NULL) ac->ac_init(ad); hts_mutex_lock(&mp->mp_mutex); while(run) { int avail = ad->ad_avr != NULL ? avresample_available(ad->ad_avr) : 0; media_buf_t *data = TAILQ_FIRST(&mq->mq_q_data); media_buf_t *ctrl = TAILQ_FIRST(&mq->mq_q_ctrl); if(avail >= ad->ad_tile_size && blocked == 0 && !ad->ad_paused) { assert(avail != 0); assert(ad->ad_avr != NULL); int samples = MIN(ad->ad_tile_size, avail); int r; if(ac->ac_deliver_locked != NULL) { r = ac->ac_deliver_locked(ad, samples, ad->ad_pts, ad->ad_epoch); if(r) { hts_cond_wait(&mq->mq_avail, &mp->mp_mutex); continue; } ad->ad_pts = AV_NOPTS_VALUE; continue; } else { hts_mutex_unlock(&mp->mp_mutex); r = ac->ac_deliver_unlocked(ad, samples, ad->ad_pts, ad->ad_epoch); hts_mutex_lock(&mp->mp_mutex); } if(r) { blocked = 1; continue; } else { ad->ad_pts = AV_NOPTS_VALUE; } continue; } if(ctrl != NULL) { TAILQ_REMOVE(&mq->mq_q_ctrl, ctrl, mb_link); mb = ctrl; } else if(data != NULL && avail < 16384) { TAILQ_REMOVE(&mq->mq_q_data, data, mb_link); mb = data; } else { hts_cond_wait(&mq->mq_avail, &mp->mp_mutex); continue; } mq->mq_packets_current--; mp->mp_buffer_current -= mb->mb_size; mq_update_stats(mp, mq); hts_cond_signal(&mp->mp_backpressure); if(mb->mb_data_type == MB_CTRL_UNBLOCK) { assert(blocked); blocked = 0; } else { hts_mutex_unlock(&mp->mp_mutex); switch(mb->mb_data_type) { case MB_AUDIO: audio_process_audio(ad, mb); break; case MB_CTRL_PAUSE: ad->ad_paused = 1; if(ac->ac_pause) ac->ac_pause(ad); break; case MB_CTRL_PLAY: ad->ad_paused = 0; if(ac->ac_play) ac->ac_play(ad); break; case MB_CTRL_FLUSH: if(ac->ac_flush) ac->ac_flush(ad); ad->ad_pts = AV_NOPTS_VALUE; break; case MB_CTRL_EXIT: run = 0; break; default: abort(); } hts_mutex_lock(&mp->mp_mutex); } media_buf_free_locked(mp, mb); } hts_mutex_unlock(&mp->mp_mutex); if(ac->ac_fini != NULL) ac->ac_fini(ad); return NULL; }
/** * Video decoder thread */ static void * vd_thread(void *aux) { video_decoder_t *vd = aux; media_pipe_t *mp = vd->vd_mp; media_queue_t *mq = &mp->mp_video; media_buf_t *mb; media_codec_t *mc; int run = 1; int reqsize = -1; int reinit = 0; int size; vd->vd_frame = avcodec_alloc_frame(); hts_mutex_lock(&mp->mp_mutex); while(run) { if((mb = TAILQ_FIRST(&mq->mq_q)) == NULL) { hts_cond_wait(&mq->mq_avail, &mp->mp_mutex); continue; } if(mb->mb_data_type == MB_VIDEO && vd->vd_hold && vd->vd_skip == 0 && mb->mb_skip == 0) { hts_cond_wait(&mq->mq_avail, &mp->mp_mutex); continue; } TAILQ_REMOVE(&mq->mq_q, mb, mb_link); mq->mq_packets_current--; mp->mp_buffer_current -= mb->mb_size; mq_update_stats(mp, mq); hts_cond_signal(&mp->mp_backpressure); hts_mutex_unlock(&mp->mp_mutex); mc = mb->mb_cw; switch(mb->mb_data_type) { case MB_CTRL_EXIT: run = 0; break; case MB_CTRL_PAUSE: vd->vd_hold = 1; break; case MB_CTRL_PLAY: vd->vd_hold = 0; break; case MB_FLUSH: vd_init_timings(vd); vd->vd_do_flush = 1; vd->vd_interlaced = 0; video_overlay_flush(vd, 1); break; case MB_VIDEO: if(reinit) { reinit = 0; if(mc->reinit != NULL) mc->reinit(mc); } if(mb->mb_skip == 2) vd->vd_skip = 1; size = mb->mb_size; if(mc->decode) mc->decode(mc, vd, mq, mb, reqsize); else vd_decode_video(vd, mq, mb); update_vbitrate(mp, mq, size, vd); reqsize = -1; break; case MB_REQ_OUTPUT_SIZE: reqsize = mb->mb_data32; break; case MB_REINITIALIZE: reinit = 1; break; #ifdef CONFIG_DVD case MB_DVD_HILITE: case MB_DVD_RESET_SPU: case MB_DVD_CLUT: case MB_DVD_PCI: case MB_DVD_SPU: dvdspu_decoder_dispatch(vd, mb, mp); break; #endif case MB_SUBTITLE: if(vd->vd_ext_subtitles == NULL && mb->mb_stream == mq->mq_stream2) video_overlay_decode(vd, mb); break; case MB_END: break; case MB_BLACKOUT: vd->vd_frame_deliver(FRAME_BUFFER_TYPE_BLACKOUT, NULL, NULL, vd->vd_opaque); break; case MB_FLUSH_SUBTITLES: video_overlay_flush(vd, 1); break; case MB_EXT_SUBTITLE: if(vd->vd_ext_subtitles != NULL) subtitles_destroy(vd->vd_ext_subtitles); // Steal subtitle from the media_buf vd->vd_ext_subtitles = mb->mb_data; mb->mb_data = NULL; video_overlay_flush(vd, 1); break; default: abort(); } hts_mutex_lock(&mp->mp_mutex); media_buf_free_locked(mp, mb); } hts_mutex_unlock(&mp->mp_mutex); if(vd->vd_ext_subtitles != NULL) subtitles_destroy(vd->vd_ext_subtitles); /* Free ffmpeg frame */ av_free(vd->vd_frame); return NULL; }
static void * omx_clk_thread(void *aux) { omx_clk_cmd_t *cmd; omx_clk_t *clk = aux; int run = 1; hts_mutex_lock(&clk->mp->mp_mutex); while(run) { while((cmd = TAILQ_FIRST(&clk->q)) == NULL) { #if 0 if(hts_cond_wait_timeout(&clk->cond, &clk->mp->mp_mutex, 1000)) { hts_mutex_unlock(&clk->mp->mp_mutex); int64_t ts = omx_get_media_time(clk->c); hts_mutex_lock(&clk->mp->mp_mutex); } #else hts_cond_wait(&clk->cond, &clk->mp->mp_mutex); #endif continue; } TAILQ_REMOVE(&clk->q, cmd, link); hts_mutex_unlock(&clk->mp->mp_mutex); switch(cmd->cmd) { case OMX_CLK_QUIT: run = 0; break; case OMX_CLK_INIT: omx_clk_init(clk, cmd->arg); break; case OMX_CLK_PAUSE: omx_clk_set_speed(clk, 0); break; case OMX_CLK_PLAY: omx_clk_set_speed(clk, 1 << 16); break; case OMX_CLK_BEGIN_SEEK: omx_clk_begin_seek(clk); break; case OMX_CLK_SEEK_AUDIO_DONE: omx_clk_seek_done(clk); break; case OMX_CLK_SEEK_VIDEO_DONE: omx_clk_seek_done(clk); break; } free(cmd); hts_mutex_lock(&clk->mp->mp_mutex); } hts_mutex_unlock(&clk->mp->mp_mutex); return NULL; }
static pixmap_t * rpi_pixmap_decode(pixmap_t *pm, const image_meta_t *im, char *errbuf, size_t errlen) { if(pm->pm_type != PIXMAP_JPEG) return NULL; #ifdef TIMING int64_t ts = showtime_get_ts(), ts2; #endif rpi_pixmap_decoder_t *rpd = pixmap_decoder_create(OMX_IMAGE_CodingJPEG); if(rpd == NULL) return NULL; rpd->rpd_im = im; #ifdef NOCOPY #error check rpd->rpd_decoder->oc_stream_corrupt OMX_PARAM_PORTDEFINITIONTYPE portdef; memset(&portdef, 0, sizeof(portdef)); portdef.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE); portdef.nVersion.nVersion = OMX_VERSION; portdef.nPortIndex = rpd->rpd_decoder->oc_inport; omxchk(OMX_GetParameter(rpd->rpd_decoder->oc_handle, OMX_IndexParamPortDefinition, &portdef)); omx_send_command(rpd->rpd_decoder, OMX_CommandPortEnable, rpd->rpd_decoder->oc_inport, NULL, 0); OMX_BUFFERHEADERTYPE *buf; for(int i = 0; i < portdef.nBufferCountActual; i++) { omxchk(OMX_UseBuffer(rpd->rpd_decoder->oc_handle, &buf, rpd->rpd_decoder->oc_inport, NULL, pm->pm_size, pm->pm_data)); } // Waits for the OMX_CommandPortEnable command omx_wait_command(rpd->rpd_decoder); omx_set_state(rpd->rpd_decoder, OMX_StateExecuting); CHECKPOINT("Initialized"); buf->nOffset = 0; buf->nFilledLen = pm->pm_size; buf->nFlags |= OMX_BUFFERFLAG_EOS; rpd->rpd_decoder->oc_inflight_buffers++; omxchk(OMX_EmptyThisBuffer(rpd->rpd_decoder->oc_handle, buf)); hts_mutex_lock(&rpd->rpd_mtx); while(rpd->rpd_change == 0) hts_cond_wait(&rpd->rpd_cond, &rpd->rpd_mtx); hts_mutex_unlock(&rpd->rpd_mtx); CHECKPOINT("Setup tunnel"); setup_tunnel(rpd); #else const void *data = pm->pm_data; size_t len = pm->pm_size; hts_mutex_lock(&rpd->rpd_mtx); while(len > 0) { OMX_BUFFERHEADERTYPE *buf; if(rpd->rpd_decoder->oc_stream_corrupt) break; if(rpd->rpd_change == 1) { rpd->rpd_change = 2; hts_mutex_unlock(&rpd->rpd_mtx); setup_tunnel(rpd); hts_mutex_lock(&rpd->rpd_mtx); continue; } if(rpd->rpd_decoder->oc_avail == NULL) { hts_cond_wait(&rpd->rpd_cond, &rpd->rpd_mtx); continue; } buf = rpd->rpd_decoder->oc_avail; rpd->rpd_decoder->oc_avail = buf->pAppPrivate; rpd->rpd_decoder->oc_inflight_buffers++; hts_mutex_unlock(&rpd->rpd_mtx); buf->nOffset = 0; buf->nFilledLen = MIN(len, buf->nAllocLen); memcpy(buf->pBuffer, data, buf->nFilledLen); buf->nFlags = 0; if(len <= buf->nAllocLen) buf->nFlags |= OMX_BUFFERFLAG_EOS; data += buf->nFilledLen; len -= buf->nFilledLen; omxchk(OMX_EmptyThisBuffer(rpd->rpd_decoder->oc_handle, buf)); hts_mutex_lock(&rpd->rpd_mtx); } if(rpd->rpd_decoder->oc_stream_corrupt) { hts_mutex_unlock(&rpd->rpd_mtx); goto err; } if(rpd->rpd_change != 2) { while(rpd->rpd_change == 0 && !rpd->rpd_decoder->oc_stream_corrupt) hts_cond_wait(&rpd->rpd_cond, &rpd->rpd_mtx); hts_mutex_unlock(&rpd->rpd_mtx); if(rpd->rpd_decoder->oc_stream_corrupt) goto err; setup_tunnel(rpd); } else { hts_mutex_unlock(&rpd->rpd_mtx); } #endif omx_wait_fill_buffer(rpd->rpd_resizer, rpd->rpd_buf); CHECKPOINT("Got buffer"); err: omx_flush_port(rpd->rpd_decoder, rpd->rpd_decoder->oc_inport); omx_flush_port(rpd->rpd_decoder, rpd->rpd_decoder->oc_outport); omx_flush_port(rpd->rpd_resizer, rpd->rpd_resizer->oc_inport); omx_flush_port(rpd->rpd_resizer, rpd->rpd_resizer->oc_outport); if(rpd->rpd_tunnel != NULL) { omx_tunnel_destroy(rpd->rpd_tunnel); rpd->rpd_tunnel = NULL; } omx_set_state(rpd->rpd_decoder, OMX_StateIdle); omx_set_state(rpd->rpd_resizer, OMX_StateIdle); if(rpd->rpd_buf != NULL) { omxchk(OMX_FreeBuffer(rpd->rpd_resizer->oc_handle, rpd->rpd_resizer->oc_outport, rpd->rpd_buf)); } omx_release_buffers(rpd->rpd_decoder, rpd->rpd_decoder->oc_inport); omx_set_state(rpd->rpd_resizer, OMX_StateLoaded); omx_set_state(rpd->rpd_decoder, OMX_StateLoaded); omx_component_destroy(rpd->rpd_resizer); omx_component_destroy(rpd->rpd_decoder); hts_cond_destroy(&rpd->rpd_cond); hts_mutex_destroy(&rpd->rpd_mtx); pixmap_t *out = rpd->rpd_pm; if(out) { pixmap_release(pm); } else { snprintf(errbuf, errlen, "Load error"); } free(rpd); CHECKPOINT("All done"); return out; }
/** * Video decoder thread */ static void * vd_thread(void *aux) { video_decoder_t *vd = aux; media_pipe_t *mp = vd->vd_mp; media_queue_t *mq = &mp->mp_video; media_buf_t *mb; media_buf_t *cur = NULL; media_codec_t *mc, *mc_current = NULL; int run = 1; int reqsize = -1; int size; int reinit = 0; const media_buf_meta_t *mbm = NULL; vd->vd_frame = av_frame_alloc(); hts_mutex_lock(&mp->mp_mutex); while(run) { if(mbm != vd->vd_reorder_current) { mbm = vd->vd_reorder_current; hts_mutex_unlock(&mp->mp_mutex); vd->vd_estimated_duration = mbm->mbm_duration; video_decoder_set_current_time(vd, mbm->mbm_pts, mbm->mbm_epoch, mbm->mbm_delta); hts_mutex_lock(&mp->mp_mutex); continue; } media_buf_t *ctrl = TAILQ_FIRST(&mq->mq_q_ctrl); media_buf_t *data = TAILQ_FIRST(&mq->mq_q_data); media_buf_t *aux = TAILQ_FIRST(&mq->mq_q_aux); if(ctrl != NULL) { TAILQ_REMOVE(&mq->mq_q_ctrl, ctrl, mb_link); mb = ctrl; } else if(aux != NULL && aux->mb_pts < vd->vd_subpts + 1000000LL) { if(vd->vd_hold) { hts_cond_wait(&mq->mq_avail, &mp->mp_mutex); continue; } TAILQ_REMOVE(&mq->mq_q_aux, aux, mb_link); mb = aux; } else if(cur != NULL) { if(vd->vd_hold) { hts_cond_wait(&mq->mq_avail, &mp->mp_mutex); continue; } mb = cur; goto retry_current; } else if(data != NULL) { if(vd->vd_hold) { hts_cond_wait(&mq->mq_avail, &mp->mp_mutex); continue; } TAILQ_REMOVE(&mq->mq_q_data, data, mb_link); mp_check_underrun(mp); mb = data; } else { hts_cond_wait(&mq->mq_avail, &mp->mp_mutex); continue; } mq->mq_packets_current--; mp->mp_buffer_current -= mb->mb_size; mq_update_stats(mp, mq); hts_cond_signal(&mp->mp_backpressure); retry_current: mc = mb->mb_cw; if(mb->mb_data_type == MB_VIDEO && mc->decode_locked != NULL) { if(mc != mc_current) { if(mc_current != NULL) media_codec_deref(mc_current); mc_current = media_codec_ref(mc); prop_set_int(mq->mq_prop_too_slow, 0); } size = mb->mb_size; mq->mq_no_data_interest = 1; if(mc->decode_locked(mc, vd, mq, mb)) { cur = mb; hts_cond_wait(&mq->mq_avail, &mp->mp_mutex); continue; } mq->mq_no_data_interest = 0; cur = NULL; update_vbitrate(mp, mq, size, vd); media_buf_free_locked(mp, mb); continue; } hts_mutex_unlock(&mp->mp_mutex); switch(mb->mb_data_type) { case MB_CTRL_EXIT: run = 0; break; case MB_CTRL_PAUSE: vd->vd_hold = 1; break; case MB_CTRL_PLAY: vd->vd_hold = 0; break; case MB_CTRL_FLUSH: if(cur != NULL) { media_buf_free_unlocked(mp, cur); mq->mq_no_data_interest = 0; cur = NULL; } vd_init_timings(vd); vd->vd_interlaced = 0; hts_mutex_lock(&mp->mp_overlay_mutex); video_overlay_flush_locked(mp, 1); dvdspu_flush_locked(mp); hts_mutex_unlock(&mp->mp_overlay_mutex); mp->mp_video_frame_deliver(NULL, mp->mp_video_frame_opaque); if(mc_current != NULL) { mc_current->flush(mc_current, vd); media_codec_deref(mc_current); mc_current = NULL; } mp->mp_video_frame_deliver(NULL, mp->mp_video_frame_opaque); if(mp->mp_seek_video_done != NULL) mp->mp_seek_video_done(mp); break; case MB_VIDEO: if(mc != mc_current) { if(mc_current != NULL) media_codec_deref(mc_current); mc_current = media_codec_ref(mc); prop_set_int(mq->mq_prop_too_slow, 0); } if(reinit) { if(mc->reinit != NULL) mc->reinit(mc); reinit = 0; } size = mb->mb_size; mc->decode(mc, vd, mq, mb, reqsize); update_vbitrate(mp, mq, size, vd); reqsize = -1; break; case MB_CTRL_REQ_OUTPUT_SIZE: reqsize = mb->mb_data32; break; case MB_CTRL_REINITIALIZE: reinit = 1; break; case MB_CTRL_RECONFIGURE: mb->mb_cw->reconfigure(mc, mb->mb_frame_info); break; #if ENABLE_DVD case MB_DVD_RESET_SPU: hts_mutex_lock(&mp->mp_overlay_mutex); vd->vd_spu_curbut = 1; dvdspu_flush_locked(mp); hts_mutex_unlock(&mp->mp_overlay_mutex); break; case MB_CTRL_DVD_HILITE: vd->vd_spu_curbut = mb->mb_data32; vd->vd_spu_repaint = 1; break; case MB_DVD_PCI: memcpy(&vd->vd_pci, mb->mb_data, sizeof(pci_t)); vd->vd_spu_repaint = 1; event_payload_t *ep = event_create(EVENT_DVD_PCI, sizeof(event_t) + sizeof(pci_t)); memcpy(ep->payload, mb->mb_data, sizeof(pci_t)); mp_enqueue_event(mp, &ep->h); event_release(&ep->h); break; case MB_DVD_CLUT: dvdspu_decode_clut(vd->vd_dvd_clut, (void *)mb->mb_data); break; case MB_DVD_SPU: dvdspu_enqueue(mp, mb->mb_data, mb->mb_size, vd->vd_dvd_clut, 0, 0, mb->mb_pts); break; #endif case MB_CTRL_DVD_SPU2: dvdspu_enqueue(mp, mb->mb_data+72, mb->mb_size-72, (void *)mb->mb_data, ((const uint32_t *)mb->mb_data)[16], ((const uint32_t *)mb->mb_data)[17], mb->mb_pts); break; case MB_SUBTITLE: if(vd->vd_ext_subtitles == NULL && mb->mb_stream == mq->mq_stream2) video_overlay_decode(mp, mb); break; case MB_CTRL_FLUSH_SUBTITLES: hts_mutex_lock(&mp->mp_overlay_mutex); video_overlay_flush_locked(mp, 1); hts_mutex_unlock(&mp->mp_overlay_mutex); break; case MB_CTRL_EXT_SUBTITLE: if(vd->vd_ext_subtitles != NULL) subtitles_destroy(vd->vd_ext_subtitles); // Steal subtitle from the media_buf vd->vd_ext_subtitles = (void *)mb->mb_data; mb->mb_data = NULL; hts_mutex_lock(&mp->mp_overlay_mutex); video_overlay_flush_locked(mp, 1); hts_mutex_unlock(&mp->mp_overlay_mutex); break; default: abort(); } hts_mutex_lock(&mp->mp_mutex); media_buf_free_locked(mp, mb); } if(cur != NULL) media_buf_free_locked(mp, cur); mq->mq_no_data_interest = 0; hts_mutex_unlock(&mp->mp_mutex); if(mc_current != NULL) media_codec_deref(mc_current); if(vd->vd_ext_subtitles != NULL) subtitles_destroy(vd->vd_ext_subtitles); av_frame_free(&vd->vd_frame); return NULL; }