Bool gf_term_lock_codec(GF_Codec *codec, Bool lock, Bool trylock) { Bool res = 1; CodecEntry *ce; GF_Terminal *term = codec->odm->term; ce = mm_get_codec(term->codecs, codec); if (!ce) return 0; if (ce->mx) { if (lock) { if (trylock) { res = gf_mx_try_lock(ce->mx); } else { res = gf_mx_p(ce->mx); } } else gf_mx_v(ce->mx); } else { if (lock) { if (trylock) { res = gf_mx_try_lock(term->mm_mx); } else { res = gf_mx_p(term->mm_mx); } } else gf_mx_v(term->mm_mx); } return res; }
void gf_term_stop_codec(GF_Codec *codec, Bool is_pause) { GF_CodecCapability cap; Bool locked = 0; CodecEntry *ce; GF_Terminal *term = codec->odm->term; ce = mm_get_codec(term->codecs, codec); if (!ce) return; if (ce->mx) gf_mx_p(ce->mx); /*We must make sure: 1- media codecs are synchrounously stop otherwise we could destroy the composition memory while the codec writes to it 2- prevent deadlock for other codecs waiting for the scene graph */ else if (codec->CB) { locked = 1; gf_mx_p(term->mm_mx); } else { locked = gf_mx_try_lock(term->mm_mx); } if (!is_pause) { cap.CapCode = GF_CODEC_ABORT; cap.cap.valueInt = 0; gf_codec_set_capability(codec, cap); if (codec->decio && codec->odm->mo && (codec->odm->mo->flags & GF_MO_DISPLAY_REMOVE) ) { cap.CapCode = GF_CODEC_SHOW_SCENE; cap.cap.valueInt = 0; gf_codec_set_capability(codec, cap); codec->odm->mo->flags &= ~GF_MO_DISPLAY_REMOVE; } } /*set status directly and don't touch CB state*/ codec->Status = GF_ESM_CODEC_STOP; /*don't wait for end of thread since this can be triggered within the decoding thread*/ if (ce->flags & GF_MM_CE_RUNNING) { ce->flags &= ~GF_MM_CE_RUNNING; if (!ce->thread) term->cumulated_priority -= codec->Priority+1; } if (codec->CB) gf_cm_abort_buffering(codec->CB); if (ce->mx) gf_mx_v(ce->mx); /*cf note above*/ else if (locked) gf_mx_v(term->mm_mx); }
/*NOTE: when starting/stoping a decoder we only lock the decoder mutex, NOT the media manager. This avoids deadlocking in case a system codec waits for the scene graph and the compositor requests a stop/start on a media*/ void gf_term_start_codec(GF_Codec *codec, Bool is_resume) { GF_CodecCapability cap; CodecEntry *ce; GF_Terminal *term = codec->odm->term; if (!gf_list_count(codec->odm->channels)) return; ce = mm_get_codec(term->codecs, codec); if (!ce) return; /*lock dec*/ if (ce->mx) gf_mx_p(ce->mx); /*clean decoder memory and wait for RAP*/ if (codec->CB) gf_cm_reset(codec->CB); if (!is_resume) { cap.CapCode = GF_CODEC_WAIT_RAP; gf_codec_set_capability(codec, cap); if (codec->decio && (codec->decio->InterfaceType == GF_SCENE_DECODER_INTERFACE)) { cap.CapCode = GF_CODEC_SHOW_SCENE; cap.cap.valueInt = 1; gf_codec_set_capability(codec, cap); } } gf_codec_set_status(codec, GF_ESM_CODEC_PLAY); if (!(ce->flags & GF_MM_CE_RUNNING)) { ce->flags |= GF_MM_CE_RUNNING; if (ce->thread) { gf_th_run(ce->thread, RunSingleDec, ce); gf_th_set_priority(ce->thread, term->priority); } else { term->cumulated_priority += ce->dec->Priority+1; } } /*unlock dec*/ if (ce->mx) gf_mx_v(ce->mx); }
void gf_term_add_codec(GF_Terminal *term, GF_Codec *codec) { u32 i, count; Bool locked; Bool threaded; CodecEntry *cd; CodecEntry *ptr, *next; GF_CodecCapability cap; assert(codec); GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Registering codec %s\n", codec->decio ? codec->decio->module_name : "RAW")); /*caution: the mutex can be grabbed by a decoder waiting for a mutex owned by the calling thread this happens when several scene codecs are running concurently and triggering play/pause on media*/ locked = gf_mx_try_lock(term->mm_mx); cd = mm_get_codec(term->codecs, codec); if (cd) goto exit; GF_SAFEALLOC(cd, CodecEntry); cd->dec = codec; if (!cd->dec->Priority) cd->dec->Priority = 1; /*we force audio codecs to be threaded in free mode, so that we avoid waiting in the audio renderer if another decoder is locking the main mutex this can happen when the audio decoder is running late*/ if (codec->type==GF_STREAM_AUDIO) { threaded = 1; } else { cap.CapCode = GF_CODEC_WANTS_THREAD; cap.cap.valueInt = 0; gf_codec_get_capability(codec, &cap); threaded = cap.cap.valueInt; } if (threaded) cd->flags |= GF_MM_CE_REQ_THREAD; if (term->flags & GF_TERM_MULTI_THREAD) { if ((codec->type==GF_STREAM_AUDIO) || (codec->type==GF_STREAM_VISUAL)) threaded = 1; } else if (term->flags & GF_TERM_SINGLE_THREAD) { threaded = 0; } if (codec->flags & GF_ESM_CODEC_IS_RAW_MEDIA) threaded = 0; if (threaded) { cd->thread = gf_th_new(cd->dec->decio->module_name); cd->mx = gf_mx_new(cd->dec->decio->module_name); cd->flags |= GF_MM_CE_THREADED; gf_list_add(term->codecs, cd); goto exit; } //add codec 1- per priority 2- per type, audio being first //priorities inherits from Systems (5bits) so range from 0 to 31 //we sort from MAX to MIN count = gf_list_count(term->codecs); for (i=0; i<count; i++) { ptr = (CodecEntry*)gf_list_get(term->codecs, i); if (ptr->flags & GF_MM_CE_THREADED) continue; //higher priority, continue if (ptr->dec->Priority > codec->Priority) continue; //same priority, put audio first if (ptr->dec->Priority == codec->Priority) { //we insert audio (0x05) before video (0x04) if (ptr->dec->type < codec->type) { gf_list_insert(term->codecs, cd, i); goto exit; } //same prior, same type: insert after if (ptr->dec->type == codec->type) { if (i+1==count) { gf_list_add(term->codecs, cd); } else { gf_list_insert(term->codecs, cd, i+1); } goto exit; } //we insert video (0x04) after audio (0x05) if next is not audio //last one if (i+1 == count) { gf_list_add(term->codecs, cd); goto exit; } next = (CodecEntry*)gf_list_get(term->codecs, i+1); //# priority level, insert if ((next->flags & GF_MM_CE_THREADED) || (next->dec->Priority != codec->Priority)) { gf_list_insert(term->codecs, cd, i+1); goto exit; } //same priority level and at least one after : continue continue; } gf_list_insert(term->codecs, cd, i); goto exit; } //if we got here, first in list gf_list_add(term->codecs, cd); exit: if (locked) gf_mx_v(term->mm_mx); return; }
void gf_term_stop_codec(GF_Codec *codec, Bool is_pause) { GF_CodecCapability cap; Bool locked = 0; CodecEntry *ce; GF_Terminal *term = codec->odm->term; ce = mm_get_codec(term->codecs, codec); if (!ce) return; if (ce->mx) gf_mx_p(ce->mx); /*We must make sure: 1- media codecs are synchrounously stop otherwise we could destroy the composition memory while the codec writes to it 2- prevent deadlock for other codecs waiting for the scene graph */ else if (codec->CB) { locked = 1; gf_mx_p(term->mm_mx); } else { locked = gf_mx_try_lock(term->mm_mx); } if (!is_pause) { cap.CapCode = GF_CODEC_ABORT; cap.cap.valueInt = 0; gf_codec_set_capability(codec, cap); if (codec->decio && codec->odm->mo && (codec->odm->mo->flags & GF_MO_DISPLAY_REMOVE) ) { cap.CapCode = GF_CODEC_SHOW_SCENE; cap.cap.valueInt = 0; gf_codec_set_capability(codec, cap); codec->odm->mo->flags &= ~GF_MO_DISPLAY_REMOVE; } } /*for audio codec force CB to stop state to discard any pending AU. Not doing so would lead to a wrong estimation of the clock drift when resuming the object*/ if (codec->type==GF_STREAM_AUDIO) { gf_codec_set_status(codec, GF_ESM_CODEC_STOP); } //if video is in a dynamic scene, reset the CB if user stop (eg codec was not in EOS). Otherwise (bifs,svg) we may want to keep the last decoded image else if ((codec->Status<GF_ESM_CODEC_EOS) && codec->odm && codec->odm->parentscene && codec->odm->parentscene->is_dynamic_scene && codec->CB && (codec->CB->Capacity>1)) { gf_codec_set_status(codec, GF_ESM_CODEC_STOP); } /*otherwise set status directly and don't touch CB state*/ else { codec->Status = GF_ESM_CODEC_STOP; } /*don't wait for end of thread since this can be triggered within the decoding thread*/ if (ce->flags & GF_MM_CE_RUNNING) { ce->flags &= ~GF_MM_CE_RUNNING; if (!ce->thread) term->cumulated_priority -= codec->Priority+1; } if (codec->CB) gf_cm_abort_buffering(codec->CB); if (ce->mx) gf_mx_v(ce->mx); /*cf note above*/ else if (locked) gf_mx_v(term->mm_mx); }