GF_EXPORT GF_Err gf_th_run(GF_Thread *t, u32 (*Run)(void *param), void *param) { TBuf<32> threadName; const TUint KThreadMinHeapSize = 0x1000; const TUint KThreadMaxHeapSize = 0x10000; if (!t || t->Run || t->_signal) return GF_BAD_PARAM; t->Run = Run; t->args = param; t->_signal = gf_sema_new(1, 0); if (! t->_signal) { GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] Unable to create thread start-up semaphore\n")); t->status = GF_THREAD_STATUS_DEAD; return GF_IO_ERR; } threadName.Format(_L("GTH%d"), (u32) t); t->threadH = new RThread(); if ( t->threadH->Create(threadName, (TThreadFunction)RunThread, KDefaultStackSize, KThreadMinHeapSize, KThreadMaxHeapSize, (void *)t, EOwnerProcess) != KErrNone) { GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] Unable to create thread\n")); t->status = GF_THREAD_STATUS_DEAD; return GF_IO_ERR; } t->threadH->Resume(); /*wait for the child function to call us - do NOT return before, otherwise the thread status would be unknown*/ //GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[Core] Waiting for thread to start\n")); gf_sema_wait(t->_signal); gf_sema_del(t->_signal); t->_signal = NULL; return GF_OK; }
NPT_Result GPAC_GenericDevice::OnAction(PLT_ActionReference& action, const PLT_HttpRequestContext& context) { NPT_COMPILER_UNUSED(context); #ifdef GPAC_HAS_SPIDERMONKEY gf_mx_p(m_pMutex); #endif PLT_ActionDesc &act_desc = action->GetActionDesc(); NPT_String name = act_desc.GetName(); #ifdef GPAC_HAS_SPIDERMONKEY assert(!m_pSema); #endif GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[UPnP] Action %s called (thread %d)\n", (char *) name, gf_th_id() )); #ifdef GPAC_HAS_SPIDERMONKEY if (JSVAL_IS_NULL(act_proc)) { gf_mx_v(m_pMutex); return NPT_SUCCESS; } jsval argv[2]; m_pUPnP->LockJavascript(GF_TRUE); JSObject *js_action = JS_NewObject(m_pUPnP->m_pJSCtx, &m_pUPnP->upnpDeviceClass._class, 0, 0); argv[0] = OBJECT_TO_JSVAL(js_action); SMJS_SET_PRIVATE(m_pUPnP->m_pJSCtx, js_action, this); act_ref = action; JS_DefineProperty(m_pUPnP->m_pJSCtx, js_action, "Name", STRING_TO_JSVAL( JS_NewStringCopyZ(m_pUPnP->m_pJSCtx, name) ), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); GPAC_Service *service = (GPAC_Service *) act_desc.GetService(); JS_DefineProperty(m_pUPnP->m_pJSCtx, js_action, "Service", service->m_pObj ? OBJECT_TO_JSVAL( service->m_pObj) : JSVAL_NULL, 0, 0, JSPROP_READONLY | JSPROP_PERMANENT); JS_DefineFunction(m_pUPnP->m_pJSCtx, js_action, "GetArgument", upnp_action_get_argument, 1, 0); JS_DefineFunction(m_pUPnP->m_pJSCtx, js_action, "SendReply", upnp_action_send_reply, 1, 0); /*create a semaphore*/ m_pSema = gf_sema_new(1, 0); jsval rval; JS_CallFunctionValue(m_pUPnP->m_pJSCtx, obj, act_proc, 1, argv, &rval); SMJS_SET_PRIVATE(m_pUPnP->m_pJSCtx, js_action, NULL); m_pUPnP->LockJavascript(GF_FALSE); if (JSVAL_IS_INT(rval) && (JSVAL_TO_INT(rval) != 0)) { action->SetError(JSVAL_TO_INT(rval), "Action Failed"); } /*wait on the semaphore*/ if (!gf_sema_wait_for(m_pSema, 10000)) { GF_LOG(GF_LOG_WARNING, GF_LOG_NETWORK, ("[UPnP] Reply processing to action %s timeout - sending incomplete reply)\n", (char *) name)); } gf_sema_del(m_pSema); m_pSema = NULL; gf_mx_v(m_pMutex); #endif return NPT_SUCCESS; }
void dc_circular_buffer_create(CircularBuffer *circular_buf, u32 size, LockMode mode, int max_num_consumers) { u32 i; circular_buf->size = size; circular_buf->list = (Node*)gf_malloc(size * sizeof(Node)); circular_buf->mode = mode; circular_buf->max_num_consumers = max_num_consumers; for (i=0; i<size; i++) { circular_buf->list[i].num_producers = 0; circular_buf->list[i].num_consumers = 0; circular_buf->list[i].num_consumers_accessed = 0; circular_buf->list[i].marked = 0; circular_buf->list[i].num_consumers_waiting = 0; circular_buf->list[i].consumers_semaphore = gf_sema_new(1000, 0); circular_buf->list[i].producers_semaphore = gf_sema_new(1000, 0); circular_buf->list[i].mutex = gf_mx_new("Circular Buffer Mutex"); } }
GF_EXPORT GF_Err gf_th_run(GF_Thread *t, u32 (*Run)(void *param), void *param) { #ifdef WIN32 DWORD id; #else pthread_attr_t att; #endif if (!t || t->Run || t->_signal) return GF_BAD_PARAM; t->Run = Run; t->args = param; t->_signal = gf_sema_new(1, 0); #ifdef WIN32 t->threadH = CreateThread(NULL, t->stackSize, &(RunThread), (void *)t, 0, &id); if (t->threadH != NULL) { #ifdef _MSC_VER /*add thread name for the msvc debugger*/ #pragma pack(push,8) typedef struct { DWORD dwType; LPCSTR szName; DWORD dwThreadID; DWORD dwFlags; } THREADNAME_INFO; #pragma pack(pop) THREADNAME_INFO info; info.dwType = 0x1000; info.szName = t->log_name; info.dwThreadID = id; info.dwFlags = 0; __try { RaiseException(0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info); } __except (EXCEPTION_CONTINUE_EXECUTION) { } #endif } else { #else if ( pthread_attr_init(&att) != 0 ) return GF_IO_ERR;
GF_Err gf_codec_add_channel(GF_Codec *codec, GF_Channel *ch) { GF_Err e; GF_NetworkCommand com; GF_Channel *a_ch; char *dsi; u32 dsiSize, CUsize, i; GF_CodecCapability cap; u32 min, max; /*only for valid codecs (eg not OCR)*/ if (codec->decio) { com.get_dsi.dsi = NULL; dsi = NULL; dsiSize = 0; if (ch->esd->decoderConfig->upstream) codec->flags |= GF_ESM_CODEC_HAS_UPSTREAM; if (ch->esd->decoderConfig->decoderSpecificInfo) { dsi = ch->esd->decoderConfig->decoderSpecificInfo->data; dsiSize = ch->esd->decoderConfig->decoderSpecificInfo->dataLength; } /*For objects declared in OD stream, override with network DSI if any*/ if (ch->service && !(ch->odm->flags & GF_ODM_NOT_IN_OD_STREAM) ) { com.command_type = GF_NET_CHAN_GET_DSI; com.base.on_channel = ch; e = gf_term_service_command(ch->service, &com); if (!e && com.get_dsi.dsi) { dsi = com.get_dsi.dsi; dsiSize = com.get_dsi.dsi_len; if (ch->esd->decoderConfig->decoderSpecificInfo->data) gf_free(ch->esd->decoderConfig->decoderSpecificInfo->data); ch->esd->decoderConfig->decoderSpecificInfo->data = com.get_dsi.dsi; ch->esd->decoderConfig->decoderSpecificInfo->dataLength = com.get_dsi.dsi_len; } } GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[Codec] Attaching stream %d to codec %s\n", ch->esd->ESID, codec->decio->module_name)); /*lock the channel before setup in case we are using direct_decode */ gf_mx_p(ch->mx); e = codec->decio->AttachStream(codec->decio, ch->esd); gf_mx_v(ch->mx); if (ch->esd->decoderConfig && ch->esd->decoderConfig->rvc_config) { gf_odf_desc_del((GF_Descriptor *)ch->esd->decoderConfig->rvc_config); ch->esd->decoderConfig->rvc_config = NULL; } if (e) { GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[Codec] Attach Stream failed %s\n", gf_error_to_string(e) )); return e; } /*ask codec for desired output capacity - note this may be 0 if stream is not yet configured*/ cap.CapCode = GF_CODEC_OUTPUT_SIZE; gf_codec_get_capability(codec, &cap); if (codec->CB && (cap.cap.valueInt != codec->CB->UnitSize)) { gf_cm_del(codec->CB); codec->CB = NULL; } CUsize = cap.cap.valueInt; /*get desired amount of units and minimal fullness (used for scheduling)*/ switch(codec->type) { case GF_STREAM_VISUAL: case GF_STREAM_AUDIO: cap.CapCode = GF_CODEC_BUFFER_MIN; gf_codec_get_capability(codec, &cap); min = cap.cap.valueInt; cap.CapCode = GF_CODEC_BUFFER_MAX; gf_codec_get_capability(codec, &cap); max = cap.cap.valueInt; break; case GF_STREAM_ND_SUBPIC: max = 1; min = 0; break; default: min = max = 0; } if ((codec->type==GF_STREAM_AUDIO) && (max<2)) max = 2; /*setup CB*/ if (!codec->CB && max) { if (codec->flags & GF_ESM_CODEC_IS_RAW_MEDIA) { max = 1; /*create a semaphore in non-notified stage*/ codec->odm->raw_frame_sema = gf_sema_new(1, 0); } GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[ODM] Creating composition buffer for codec %s - %d units %d bytes each\n", codec->decio->module_name, max, CUsize)); codec->CB = gf_cm_new(CUsize, max, (codec->flags & GF_ESM_CODEC_IS_RAW_MEDIA) ? 1 : 0); codec->CB->Min = min; codec->CB->odm = codec->odm; } if (codec->CB) { /*check re-ordering - set by default on all codecs*/ codec->is_reordering = 1; cap.CapCode = GF_CODEC_REORDER; if (gf_codec_get_capability(codec, &cap) == GF_OK) codec->is_reordering = cap.cap.valueInt; } if (codec->flags & GF_ESM_CODEC_IS_RAW_MEDIA) { ch->is_raw_channel = 1; } /*setup net channel config*/ if (ch->service) { memset(&com, 0, sizeof(GF_NetworkCommand)); com.command_type = GF_NET_CHAN_CONFIG; com.base.on_channel = ch; com.cfg.priority = ch->esd->streamPriority; com.cfg.sync_id = ch->clock->clockID; memcpy(&com.cfg.sl_config, ch->esd->slConfig, sizeof(GF_SLConfig)); /*get the frame duration if audio (used by some network stack)*/ if (ch->odm->codec && (ch->odm->codec->type==GF_STREAM_AUDIO) ) { cap.CapCode = GF_CODEC_SAMPLERATE; gf_codec_get_capability(ch->odm->codec, &cap); com.cfg.sample_rate = cap.cap.valueInt; cap.CapCode = GF_CODEC_CU_DURATION; gf_codec_get_capability(ch->odm->codec, &cap); com.cfg.frame_duration = cap.cap.valueInt; } gf_term_service_command(ch->service, &com); ch->carousel_type = GF_ESM_CAROUSEL_NONE; if (com.cfg.use_m2ts_sections) { ch->carousel_type = GF_ESM_CAROUSEL_MPEG2; } else { switch (ch->esd->decoderConfig->streamType) { case GF_STREAM_OD: case GF_STREAM_SCENE: ch->carousel_type = ch->esd->slConfig->AUSeqNumLength ? GF_ESM_CAROUSEL_MPEG4 : GF_ESM_CAROUSEL_NONE; break; } } } } /*assign the first base layer as the codec clock by default, or current channel clock if no clock set Also assign codec priority here*/ if (!ch->esd->dependsOnESID || !codec->ck) { codec->ck = ch->clock; codec->Priority = ch->esd->streamPriority; /*insert base layer first - note we are sure this is a stream of the same type as the codec (other streams - OCI, MPEG7, MPEGJ - are not added that way)*/ return gf_list_insert(codec->inChannels, ch, 0); } else { /*make sure all channels are in order*/ i=0; while ((a_ch = (GF_Channel*)gf_list_enum(codec->inChannels, &i))) { if (ch->esd->dependsOnESID == a_ch->esd->ESID) { return gf_list_insert(codec->inChannels, ch, i); } if (a_ch->esd->dependsOnESID == ch->esd->ESID) { return gf_list_insert(codec->inChannels, ch, i-1); } } /*by default append*/ return gf_list_add(codec->inChannels, ch); } }
GF_Err gf_th_run(GF_Thread *t, u32 (*Run)(void *param), void *param) { #ifdef WIN32 DWORD id; #else pthread_attr_t att; #endif if (!t || t->Run || t->_signal) return GF_BAD_PARAM; t->Run = Run; t->args = param; t->_signal = gf_sema_new(1, 0); #ifdef WIN32 t->threadH = CreateThread(NULL, t->stackSize, &(RunThread), (void *)t, 0, &id); if (t->threadH == NULL) { #else if ( pthread_attr_init(&att) != 0 ) return GF_IO_ERR; pthread_attr_setdetachstate(&att, PTHREAD_CREATE_JOINABLE); if ( pthread_create(&t->threadH, &att, RunThread, t) != 0 ) { #endif t->status = GF_THREAD_STATUS_DEAD; return GF_IO_ERR; } /*wait for the child function to call us - do NOT return before, otherwise the thread status would be unknown*/ gf_sema_wait(t->_signal); gf_sema_del(t->_signal); t->_signal = NULL; return GF_OK; } /* Stops a thread. If Destroy is not 0, thread is destroyed DANGEROUS as no cleanup */ void Thread_Stop(GF_Thread *t, Bool Destroy) { if (gf_th_status(t) == GF_THREAD_STATUS_RUN) { #ifdef WIN32 if (Destroy) { DWORD dw = 1; BOOL ret = TerminateThread(t->threadH, dw); if (!ret) { DWORD err = GetLastError(); GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Thread %s] Couldn't stop thread ID 0x%08x, error code %d\n", t->log_name, t->id, err)); } t->threadH = NULL; } else { WaitForSingleObject(t->threadH, INFINITE); } #else if (Destroy) { #ifdef GPAC_ANDROID if (pthread_kill(t->threadH, SIGQUIT)) #else if (pthread_cancel(t->threadH)) #endif GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Thread %s] Couldn't kill thread ID 0x%08x\n", t->log_name, t->id)); t->threadH = 0; } else { /*gracefully wait for Run to finish*/ if (pthread_join(t->threadH, NULL)) GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Thread %s] pthread_join() returned an error with thread ID 0x%08x\n", t->log_name, t->id)); } #endif } t->status = GF_THREAD_STATUS_DEAD; } void gf_th_stop(GF_Thread *t) { Thread_Stop(t, 0); }