/* Constructor */ HbbtvDemuxer::HbbtvDemuxer(char *input_data, char* url, Bool dsmcc, Bool no_url,sPlayerInterface* player_interf) { Demuxts = NULL; Channels = gf_list_new(); Input_data = gf_strdup(input_data); user = player_interf; player_interf->Demuxer = this; ait_to_process = 0; nb_prog_pmt_received = 0; all_prog_pmt_received =0; No_URL = 0; Ignore_TS_URL = 0; if(dsmcc){ process_dsmcc = 1; }else{ process_dsmcc = 0; } if(no_url){ GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[HBBTVTerminal] No URL \n")); No_URL = 1; }else if(url){ GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[HBBTVTerminal] Forced URL %s \n",url)); Force_URL = gf_strdup(url); Ignore_TS_URL = 1; } nb_ait = 0; ts_demux_mutex = gf_mx_new("HBBTV_TS_Demux_Mutex"); ts_demux_thread = gf_th_new("HBBTV_TS_Demux_Thread"); }
void MPEGVS_Start(struct __input_device * dr) { MPEGVSCTX; rc->trd = gf_th_new("MPEG-V_IN"); gf_th_run(rc->trd, ThreadRun, dr); }
GF_InputService *NewM2TSReader() { M2TSIn *reader; GF_InputService *plug = gf_malloc(sizeof(GF_InputService)); memset(plug, 0, sizeof(GF_InputService)); GF_REGISTER_MODULE_INTERFACE(plug, GF_NET_CLIENT_INTERFACE, "GPAC MPEG-2 TS Reader", "gpac distribution") plug->CanHandleURL = M2TS_CanHandleURL; plug->CanHandleURLInService = M2TS_CanHandleURLInService; plug->ConnectService = M2TS_ConnectService; plug->CloseService = M2TS_CloseService; plug->GetServiceDescriptor = M2TS_GetServiceDesc; plug->ConnectChannel = M2TS_ConnectChannel; plug->DisconnectChannel = M2TS_DisconnectChannel; plug->ServiceCommand = M2TS_ServiceCommand; plug->RegisterMimeTypes = M2TS_RegisterMimeTypes; reader = gf_malloc(sizeof(M2TSIn)); memset(reader, 0, sizeof(M2TSIn)); plug->priv = reader; reader->ts = gf_m2ts_demux_new(); reader->ts->on_event = M2TS_OnEvent; reader->ts->user = reader; reader->ts->demux_and_play = 1; reader->ts->th = gf_th_new("MPEG-2 TS Demux"); reader->mx = gf_mx_new("MPEG2 Demux"); return plug; }
GF_Renderer *gf_sr_new(GF_User *user, Bool self_threaded, GF_Terminal *term) { GF_Renderer *tmp = SR_New(user); if (!tmp) return NULL; tmp->term = term; /**/ tmp->audio_renderer = gf_sr_ar_load(user); if (!tmp->audio_renderer) GF_USER_MESSAGE(user, "", "NO AUDIO RENDERER", GF_OK); gf_mx_p(tmp->mx); /*run threaded*/ if (self_threaded) { tmp->VisualThread = gf_th_new(); gf_th_run(tmp->VisualThread, SR_RenderRun, tmp); while (tmp->video_th_state!=1) { gf_sleep(10); if (tmp->video_th_state==3) { gf_mx_v(tmp->mx); gf_sr_del(tmp); return NULL; } } } /*set default size if owning output*/ if (!tmp->user->os_window_handler) { gf_sr_set_size(tmp, 320, 20); } gf_mx_v(tmp->mx); return tmp; }
GF_BaseDecoder *NewISCodec(u32 PL) { ISPriv *priv; GF_SceneDecoder *tmp; tmp = (GF_SceneDecoder*) malloc(sizeof(GF_SceneDecoder)); if (!tmp) return NULL; memset(tmp, 0, sizeof(GF_SceneDecoder)); priv = (ISPriv *) malloc(sizeof(ISPriv)); memset(priv, 0, sizeof(ISPriv)); priv->is_nodes = gf_list_new(); priv->ddf = gf_list_new(); tmp->privateStack = priv; tmp->AttachStream = IS_AttachStream; tmp->DetachStream = IS_DetachStream; tmp->GetCapabilities = IS_GetCapabilities; tmp->SetCapabilities = IS_SetCapabilities; tmp->ProcessData = IS_ProcessData; /*we don't use this...*/ tmp->AttachScene = NULL; GF_REGISTER_MODULE_INTERFACE(tmp, GF_SCENE_DECODER_INTERFACE, "GPAC InputSensor Decoder", "gpac distribution") #if GPAC_HTK_DEMO priv->th = gf_th_new(); #endif return (GF_BaseDecoder *) tmp; }
GF_InputService *RTP_Load() { RTPClient *priv; GF_InputService *plug; GF_SAFEALLOC(plug, GF_InputService); memset(plug, 0, sizeof(GF_InputService)); GF_REGISTER_MODULE_INTERFACE(plug, GF_NET_CLIENT_INTERFACE, "GPAC RTP/RTSP Client", "gpac distribution") plug->CanHandleURL = RP_CanHandleURL; plug->CanHandleURLInService = RP_CanHandleURLInService; plug->ConnectService = RP_ConnectService; plug->CloseService = RP_CloseService; plug->GetServiceDescriptor = RP_GetServiceDesc; plug->ConnectChannel = RP_ConnectChannel; plug->DisconnectChannel = RP_DisconnectChannel; plug->ServiceCommand = RP_ServiceCommand; plug->RegisterMimeTypes = RP_RegisterMimeTypes; /*PULL mode for embedded streams*/ plug->ChannelGetSLP = RP_ChannelGetSLP; plug->ChannelReleaseSLP = RP_ChannelReleaseSLP; GF_SAFEALLOC(priv, RTPClient); priv->sessions = gf_list_new(); priv->channels = gf_list_new(); plug->priv = priv; priv->time_out = 30000; priv->mx = gf_mx_new("RTPDemux"); priv->th = gf_th_new("RTPDemux"); return plug; }
void *New_FFMPEG_Demux() { FFDemux *priv; GF_InputService *ffd = gf_malloc(sizeof(GF_InputService)); memset(ffd, 0, sizeof(GF_InputService)); GF_SAFEALLOC(priv, FFDemux); GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[FFMPEG Demuxer] Registering all ffmpeg plugins...\n") ); /* register all codecs, demux and protocols */ av_register_all(); GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[FFMPEG Demuxer] Registering all ffmpeg plugins DONE.\n") ); ffd->RegisterMimeTypes = FFD_RegisterMimeTypes; ffd->CanHandleURL = FFD_CanHandleURL; ffd->CloseService = FFD_CloseService; ffd->ConnectChannel = FFD_ConnectChannel; ffd->ConnectService = FFD_ConnectService; ffd->DisconnectChannel = FFD_DisconnectChannel; ffd->GetServiceDescriptor = FFD_GetServiceDesc; ffd->ServiceCommand = FFD_ServiceCommand; ffd->CanHandleURLInService = FFD_CanHandleURLInService; priv->thread = gf_th_new("FFMPEG Demux"); priv->mx = gf_mx_new("FFMPEG Demux"); GF_REGISTER_MODULE_INTERFACE(ffd, GF_NET_CLIENT_INTERFACE, "FFMPEG Demuxer", "gpac distribution"); ffd->priv = priv; return ffd; }
GF_Err gf_term_init_scheduler(GF_Terminal *term, u32 threading_mode) { term->mm_mx = gf_mx_new("MediaManager"); term->codecs = gf_list_new(); term->frame_duration = 33; switch (threading_mode) { case GF_TERM_THREAD_SINGLE: term->flags |= GF_TERM_SINGLE_THREAD; break; case GF_TERM_THREAD_MULTI: term->flags |= GF_TERM_MULTI_THREAD; break; default: break; } if (term->user->init_flags & GF_TERM_NO_DECODER_THREAD) return GF_OK; term->mm_thread = gf_th_new("MediaManager"); term->flags |= GF_TERM_RUNNING; term->priority = GF_THREAD_PRIORITY_NORMAL; gf_th_run(term->mm_thread, MM_Loop, term); return GF_OK; }
void gf_mse_remove(GF_HTML_SourceBuffer *sb, double start, double end) { sb->remove_start = (u64)(start*sb->timescale); sb->remove_end = (u64)(end*sb->timescale); { GF_Thread *t = gf_th_new(NULL); gf_list_add(sb->threads, t); gf_th_run(t, gf_mse_source_buffer_remove, sb); } }
GF_HTML_SourceBuffer *gf_mse_source_buffer_new(GF_HTML_MediaSource *mediasource) { char name[256]; GF_HTML_SourceBuffer *source; GF_SAFEALLOC(source, GF_HTML_SourceBuffer); sprintf(name, "SourceBuffer_Thread_%p", source); source->mediasource = mediasource; source->buffered = gf_html_timeranges_new(1); source->input_buffer = gf_list_new(); source->tracks = gf_list_new(); source->threads = gf_list_new(); source->parser_thread = gf_th_new(name); source->remove_thread = gf_th_new(name); source->append_mode = MEDIA_SOURCE_APPEND_MODE_SEGMENTS; source->appendWindowStart = 0; source->appendWindowEnd = GF_MAX_DOUBLE; source->evt_target = gf_dom_event_target_new(GF_DOM_EVENT_TARGET_MSE_SOURCEBUFFER, source); source->timescale = 1; return source; }
GF_TermExt *avr_new() { GF_TermExt *dr; GF_AVRedirect *uir; dr = gf_malloc ( sizeof ( GF_TermExt ) ); memset ( dr, 0, sizeof ( GF_TermExt ) ); GF_REGISTER_MODULE_INTERFACE ( dr, GF_TERM_EXT_INTERFACE, "GPAC Output Recorder", "gpac distribution" ); GF_SAFEALLOC ( uir, GF_AVRedirect ); dr->process = avr_process; dr->udta = uir; uir->encodingMutex = gf_mx_new("RedirectAV_encodingMutex"); assert( uir->encodingMutex); uir->frameMutex = gf_mx_new("RedirectAV_frameMutex"); uir->encodingThread = gf_th_new("RedirectAV_EncodingThread"); uir->audioEncodingThread = gf_th_new("RedirectAV_AudioEncodingThread"); uir->encode = 1; uir->is_open = 0; uir->is_running = 0; return dr; }
void *SDL_NewVideo() { SDLVidCtx *ctx; GF_VideoOutput *driv; driv = gf_malloc(sizeof(GF_VideoOutput)); memset(driv, 0, sizeof(GF_VideoOutput)); GF_REGISTER_MODULE_INTERFACE(driv, GF_VIDEO_OUTPUT_INTERFACE, "SDL Video Output", "gpac distribution"); ctx = gf_malloc(sizeof(SDLVidCtx)); memset(ctx, 0, sizeof(SDLVidCtx)); #ifdef SDL_WINDOW_THREAD ctx->sdl_th = gf_th_new("SDLVideo"); #endif ctx->evt_mx = gf_mx_new("SDLEvents"); driv->opaque = ctx; driv->Setup = SDLVid_Setup; driv->Shutdown = SDLVid_Shutdown; driv->SetFullScreen = SDLVid_SetFullScreen; driv->Flush = SDLVid_Flush; driv->ProcessEvent = SDLVid_ProcessEvent; /*no offscreen opengl with SDL*/ driv->hw_caps |= GF_VIDEO_HW_OPENGL; /*no YUV hardware blitting in SDL (only overlays)*/ driv->hw_caps |= GF_VIDEO_HW_HAS_YUV_OVERLAY | GF_VIDEO_HW_HAS_RGB | GF_VIDEO_HW_HAS_RGBA; driv->Blit = SDL_Blit; driv->LockBackBuffer = SDLVid_LockBackBuffer; driv->LockOSContext = NULL; /*color keying with overlays are not supported in SDL ...*/ #if 0 /*get YUV overlay key*/ opt = gf_modules_get_option((GF_BaseInterface *)driv, "Video", "OverlayColorKey"); /*no set is the default*/ if (!opt) { opt = "0101FE"; gf_modules_set_option((GF_BaseInterface *)driv, "Video", "OverlayColorKey", "0101FE"); } sscanf(opt, "%06x", &driv->overlay_color_key); if (driv->overlay_color_key) driv->overlay_color_key |= 0xFF000000; GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[SDL Out] YUV Overlays enabled - ColorKey enabled: %s (key %x)\n", driv->overlay_color_key ? "Yes" : "No", driv->overlay_color_key )); #endif #ifndef SDL_TEXTINPUTEVENT_TEXT_SIZE SDL_EnableUNICODE(1); #else SDL_StartTextInput(); #endif /* SDL_TEXTINPUTEVENT_TEXT_SIZE */ return driv; }
GF_EXPORT GF_BaseInterface *LoadInterface(u32 InterfaceType) { GF_WiiMote *wii; GF_InputSensorDevice *plug; if (InterfaceType != GF_INPUT_DEVICE_INTERFACE) return NULL; GF_SAFEALLOC(plug, GF_InputSensorDevice); GF_REGISTER_MODULE_INTERFACE(plug, GF_INPUT_DEVICE_INTERFACE, "GPAC Wiimote InputSensor", "gpac distribution") plug->RegisterDevice = WII_RegisterDevice; plug->Start = WII_Start; plug->Stop = WII_Stop; GF_SAFEALLOC(wii, GF_WiiMote); plug->udta = wii; wii->th = gf_th_new("WiiMote"); return (GF_BaseInterface *)plug; }
GPAC_MODULE_EXPORT GF_BaseInterface *LoadInterface(u32 InterfaceType) { GF_InputSensorDevice *plug; GF_OpenCV *udta; if (InterfaceType != GF_INPUT_DEVICE_INTERFACE) return NULL; GF_SAFEALLOC(plug, GF_InputSensorDevice); GF_REGISTER_MODULE_INTERFACE(plug, GF_INPUT_DEVICE_INTERFACE, "GPAC Demo InputSensor", "gpac distribution") plug->RegisterDevice = OCV_RegisterDevice; plug->Start = OCV_Start; plug->Stop = OCV_Stop; GF_SAFEALLOC(udta, GF_OpenCV); plug->udta = udta; udta->th = gf_th_new("OpenCV"); return (GF_BaseInterface *)plug; }
void DD_SetupWindow(GF_VideoOutput *dr, u32 flags) { DDContext *ctx = (DDContext *)dr->opaque; if (ctx->os_hwnd) { /*override window proc*/ if (!(flags & GF_TERM_NO_WINDOWPROC_OVERRIDE) ) { ctx->orig_wnd_proc = GetWindowLong(ctx->os_hwnd, GWL_WNDPROC); SetWindowLong(ctx->os_hwnd, GWL_WNDPROC, (DWORD) DD_WindowProc); } } ctx->switch_res = flags; /*create our event thread - since we always have a dedicated window for fullscreen, we need that even when a window is passed to us*/ ctx->th = gf_th_new(); gf_th_run(ctx->th, DD_WindowThread, dr); while (!ctx->th_state) gf_sleep(2); if (!the_video_output) the_video_output = dr; }
void *New_FFMPEG_Demux() { GF_InputService *ffd; FFDemux *priv; GF_SAFEALLOC(ffd, GF_InputService); if (!ffd) return NULL; GF_SAFEALLOC(priv, FFDemux); if (!priv) { gf_free(ffd); return NULL; } GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[FFMPEG Demuxer] Registering all ffmpeg plugins...\n") ); /* register all codecs, demux and protocols */ av_register_all(); avformat_network_init(); GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[FFMPEG Demuxer] Registering all ffmpeg plugins DONE.\n") ); ffd->RegisterMimeTypes = FFD_RegisterMimeTypes; ffd->CanHandleURL = FFD_CanHandleURL; ffd->CloseService = FFD_CloseService; ffd->ConnectChannel = FFD_ConnectChannel; ffd->ConnectService = FFD_ConnectService; ffd->DisconnectChannel = FFD_DisconnectChannel; ffd->GetServiceDescriptor = FFD_GetServiceDesc; ffd->ServiceCommand = FFD_ServiceCommand; ffd->CanHandleURLInService = FFD_CanHandleURLInService; priv->thread = gf_th_new("FFMPEG Demux"); priv->mx = gf_mx_new("FFMPEG Demux"); if (!priv->thread || !priv->mx) { if (priv->thread) gf_th_del(priv->thread); if (priv->mx) gf_mx_del(priv->mx); gf_free(priv); return NULL; } GF_REGISTER_MODULE_INTERFACE(ffd, GF_NET_CLIENT_INTERFACE, "FFMPEG Demuxer", "gpac distribution"); ffd->priv = priv; return ffd; }
GF_DownloadSession *gf_dm_sess_new(GF_DownloadManager *dm, char *url, u32 dl_flags, gf_dm_user_io user_io, void *usr_cbk, GF_Err *e) { GF_DownloadSession *sess; *e = GF_OK; if (gf_dm_is_local(dm, url)) return NULL; if (!gf_dm_can_handle_url(dm, url)) { *e = GF_NOT_SUPPORTED; return NULL; } if (!user_io) { *e = GF_BAD_PARAM; return NULL; } sess = (GF_DownloadSession *)malloc(sizeof(GF_DownloadSession)); memset((void *)sess, 0, sizeof(GF_DownloadSession)); sess->flags = dl_flags; sess->user_proc = user_io; sess->usr_cbk = usr_cbk; sess->dm = dm; gf_list_add(dm->sessions, sess); *e = gf_dm_setup_from_url(sess, url); if (*e) { gf_dm_sess_del(sess); return NULL; } if (!(sess->flags & GF_NETIO_SESSION_NOT_THREADED) ) { sess->th = gf_th_new(); sess->mx = gf_mx_new(); gf_th_run(sess->th, gf_dm_session_thread, sess); } sess->num_retry = SESSION_RETRY_COUNT; return sess; }
void gf_mse_source_buffer_append_arraybuffer(GF_HTML_SourceBuffer *sb, GF_HTML_ArrayBuffer *buffer) { assert(sb->parser); gf_mse_source_buffer_set_update(sb, GF_TRUE); buffer->url = (char *)gf_malloc(256); sprintf(buffer->url, "gmem://%d@%p", buffer->length, buffer->data); buffer->reference_count++; #ifndef GPAC_DISABLE_ISOM buffer->is_init = (gf_isom_probe_file(buffer->url) == 2 ? GF_TRUE : GF_FALSE); #endif GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MSE] Appending segment %s to SourceBuffer %p\n", buffer->url, sb)); gf_list_add(sb->input_buffer, buffer); /* Call the parser (asynchronously) and return */ /* the updating attribute will be positioned back to 0 when the parser is done */ { GF_Thread *t = gf_th_new(NULL); gf_list_add(sb->threads, t); gf_th_run(t, gf_mse_parse_segment, sb); } }
static GF_Err SAF_ConnectService(GF_InputService *plug, GF_ClientService *serv, const char *url) { char szURL[2048]; char *ext; SAFIn *read = (SAFIn *)plug->priv; read->service = serv; if (read->dnload) gf_service_download_del(read->dnload); read->dnload = NULL; strcpy(szURL, url); ext = strrchr(szURL, '#'); if (ext) ext[0] = 0; read->needs_connection = 1; read->duration = 0; read->saf_type = SAF_FILE_LOCAL; /*remote fetch*/ if (strnicmp(url, "file://", 7) && strstr(url, "://")) { read->saf_type = SAF_FILE_REMOTE; SAF_DownloadFile(plug, (char *) szURL); return GF_OK; } read->stream = gf_f64_open(szURL, "rb"); if (!read->stream) { gf_service_connect_ack(serv, NULL, GF_URL_ERROR); return GF_OK; } SAF_CheckFile(read); read->th = gf_th_new("SAFDemux"); /*start playing for tune-in*/ gf_th_run(read->th, SAF_Run, read); return GF_OK; }
static GF_Err FM_FAKE_PULL_Connect(GF_HYBMEDIA *self, GF_ClientService *service, const char *url) { u32 i; if (!self) return GF_BAD_PARAM; if (!service) return GF_BAD_PARAM; self->owner = service; /*set audio preloaded data*/ assert(self->private_data); memset(self->private_data, 0, sizeof(FM_FAKE_PULL)); for (i=0; i<(FM_FAKE_PULL_FRAME_LEN*8)/FM_FAKE_PULL_BITS; i++) { if (((2*i)/(FM_FAKE_PULL_CHAN_NUM*100))%2) /*100Hz*/ *((FM_FAKE_PULL_TYPE*)((FM_FAKE_PULL*)self->private_data)->buffer10+i) = 1 << (FM_FAKE_PULL_BITS-1); } /*for hybrid scenarios: add an external media*/ if (1) { #ifdef EXT_MEDIA_LOAD_THREADED GF_Thread **th = &((FM_FAKE_PULL*)self->private_data)->media_th; assert(*th == NULL); //once at a time *th = gf_th_new("HYB-FM fake external media load thread"); gf_th_run(*th, ext_media_load_th, self); #else ext_media_load_th(self); #endif //wait for video to begin as late video creates desynchro. //gf_sleep(5000); } return GF_OK; }
GF_AbstractTSMuxer * ts_amux_new(GF_AVRedirect * avr, u32 videoBitrateInBitsPerSec, u32 width, u32 height, u32 audioBitRateInBitsPerSec) { GF_AbstractTSMuxer * ts = gf_malloc( sizeof(GF_AbstractTSMuxer)); memset( ts, 0, sizeof( GF_AbstractTSMuxer)); ts->oc = avformat_alloc_context(); ts->destination = avr->destination; av_register_all(); ts->oc->oformat = GUESS_FORMAT(NULL, avr->destination, NULL); if (!ts->oc->oformat) ts->oc->oformat = GUESS_FORMAT("mpegts", NULL, NULL); assert( ts->oc->oformat); #if REDIRECT_AV_AUDIO_ENABLED ts->audio_st = av_new_stream(ts->oc, avr->audioCodec->id); { AVCodecContext * c = ts->audio_st->codec; c->codec_id = avr->audioCodec->id; c->codec_type = AVMEDIA_TYPE_AUDIO; /* put sample parameters */ c->sample_fmt = SAMPLE_FMT_S16; c->bit_rate = audioBitRateInBitsPerSec; c->sample_rate = avr->audioSampleRate; c->channels = 2; c->time_base.num = 1; c->time_base.den = 1000; // some formats want stream headers to be separate if (ts->oc->oformat->flags & AVFMT_GLOBALHEADER) c->flags |= CODEC_FLAG_GLOBAL_HEADER; } #endif ts->video_st = av_new_stream(ts->oc, avr->videoCodec->id); { AVCodecContext * c = ts->video_st->codec; c->codec_id = avr->videoCodec->id; c->codec_type = AVMEDIA_TYPE_VIDEO; /* put sample parameters */ c->bit_rate = videoBitrateInBitsPerSec; /* resolution must be a multiple of two */ c->width = width; c->height = height; /* time base: this is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented. for fixed-fps content, timebase should be 1/framerate and timestamp increments should be identically 1. */ c->time_base.den = STREAM_FRAME_RATE; c->time_base.num = 1; c->gop_size = 12; /* emit one intra frame every twelve frames at most */ c->pix_fmt = STREAM_PIX_FMT; if (c->codec_id == CODEC_ID_MPEG2VIDEO) { /* just for testing, we also add B frames */ c->max_b_frames = 2; } if (c->codec_id == CODEC_ID_MPEG1VIDEO) { /* Needed to avoid using macroblocks in which some coeffs overflow. This does not happen with normal video, it just happens here as the motion of the chroma plane does not match the luma plane. */ c->mb_decision=2; } // some formats want stream headers to be separate if (ts->oc->oformat->flags & AVFMT_GLOBALHEADER) c->flags |= CODEC_FLAG_GLOBAL_HEADER; } //av_set_pts_info(ts->audio_st, 33, 1, audioBitRateInBitsPerSec); #ifndef AVIO_FLAG_WRITE /* set the output parameters (must be done even if no parameters). */ if (av_set_parameters(ts->oc, NULL) < 0) { fprintf(stderr, "Invalid output format parameters\n"); return NULL; } #endif dump_format(ts->oc, 0, avr->destination, 1); GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[AVRedirect] DUMPING to %s...\n", ts->destination)); #if (LIBAVCODEC_VERSION_MAJOR<55) if (avcodec_open(ts->video_st->codec, avr->videoCodec) < 0) { #else if (avcodec_open2(ts->video_st->codec, avr->videoCodec, NULL) < 0) { #endif GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[AVRedirect] failed to open video codec\n")); return NULL; } #if REDIRECT_AV_AUDIO_ENABLED #if (LIBAVCODEC_VERSION_MAJOR<55) if (avcodec_open(ts->audio_st->codec, avr->audioCodec) < 0) { #else if (avcodec_open2(ts->audio_st->codec, avr->audioCodec, NULL) < 0) { #endif GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[AVRedirect] failed to open audio codec\n")); return NULL; } ts->audioMx = gf_mx_new("TS_AudioMx"); #endif ts->videoMx = gf_mx_new("TS_VideoMx"); ts->tsEncodingThread = gf_th_new("ts_interleave_thread_run"); ts->encode = 1; ts->audioPackets = NULL; ts->videoPackets = NULL; gf_th_run(ts->tsEncodingThread, ts_interleave_thread_run, ts); return ts; } void ts_amux_del(GF_AbstractTSMuxer * muxerToDelete) { if (!muxerToDelete) return; muxerToDelete->encode = 0; gf_sleep(100); gf_th_stop(muxerToDelete->tsEncodingThread); muxerToDelete->tsEncodingThread = NULL; #if REDIRECT_AV_AUDIO_ENABLED gf_mx_del(muxerToDelete->audioMx); muxerToDelete->audioMx = NULL; #endif gf_mx_del(muxerToDelete->videoMx); muxerToDelete->videoMx = NULL; if (muxerToDelete->video_st) { avcodec_close(muxerToDelete->video_st->codec); muxerToDelete->video_st = NULL; } #if REDIRECT_AV_AUDIO_ENABLED if (muxerToDelete->audio_st) { avcodec_close(muxerToDelete->audio_st->codec); muxerToDelete->audio_st = NULL; } #endif /* write the trailer, if any. the trailer must be written * before you close the CodecContexts open when you wrote the * header; otherwise write_trailer may try to use memory that * was freed on av_codec_close() */ if (muxerToDelete->oc) { u32 i; /* free the streams */ for (i = 0; i < muxerToDelete->oc->nb_streams; i++) { av_freep(&muxerToDelete->oc->streams[i]->codec); av_freep(&muxerToDelete->oc->streams[i]); } /* free the stream */ av_free(muxerToDelete->oc); muxerToDelete->oc = NULL; } } Bool ts_encode_audio_frame(GF_AbstractTSMuxer * ts, uint8_t * data, int encoded, u64 pts) { AVPacketList *pl; AVPacket * pkt; if (!ts->encode) return 1; pl = gf_malloc(sizeof(AVPacketList)); pl->next = NULL; pkt = &(pl->pkt); av_init_packet(pkt); assert( ts->audio_st); assert( ts->audio_st->codec); pkt->flags = 0; if (ts->audio_st->codec->coded_frame) { if (ts->audio_st->codec->coded_frame->key_frame) pkt->flags = AV_PKT_FLAG_KEY; if (ts->audio_st->codec->coded_frame->pts != AV_NOPTS_VALUE) { pkt->pts = av_rescale_q(ts->audio_st->codec->coded_frame->pts, ts->audio_st->codec->time_base, ts->audio_st->time_base); } else { if (pts == AV_NOPTS_VALUE) pkt->pts = AV_NOPTS_VALUE; else { pkt->pts = av_rescale_q(pts, ts->audio_st->codec->time_base, ts->audio_st->time_base); } } } else { if (pts == AV_NOPTS_VALUE) pkt->pts = AV_NOPTS_VALUE; else pkt->pts = av_rescale_q(pts, ts->audio_st->codec->time_base, ts->audio_st->time_base); } pkt->stream_index= ts->audio_st->index; pkt->data = data; pkt->size = encoded; //fprintf(stderr, "AUDIO PTS="LLU" was: "LLU" (%p)\n", pkt->pts, pts, pl); gf_mx_p(ts->audioMx); if (!ts->audioPackets) ts->audioPackets = pl; else { AVPacketList * px = ts->audioPackets; while (px->next) px = px->next; px->next = pl; } gf_mx_v(ts->audioMx); return 0; } Bool ts_encode_video_frame(GF_AbstractTSMuxer* ts, uint8_t* data, int encoded) { AVPacketList *pl; AVPacket * pkt; if (!ts->encode) return 1; pl = gf_malloc(sizeof(AVPacketList)); pl->next = NULL; pkt = &(pl->pkt); av_init_packet(pkt); if (ts->video_st->codec->coded_frame->pts != AV_NOPTS_VALUE) { //pkt->pts= av_rescale_q(ts->video_st->codec->coded_frame->pts, ts->video_st->codec->time_base, ts->video_st->time_base); pkt->pts = ts->video_st->codec->coded_frame->pts * ts->video_st->time_base.den / ts->video_st->time_base.num / 1000; //pkt->pts = ts->video_st->codec->coded_frame->pts; } if (ts->video_st->codec->coded_frame->key_frame) pkt->flags |= AV_PKT_FLAG_KEY; pkt->stream_index= ts->video_st->index; pkt->data= data; pkt->size= encoded; //fprintf(stderr, "VIDEO PTS="LLU" was: "LLU" (%p)\n", pkt->pts, ts->video_st->codec->coded_frame->pts, pl); gf_mx_p(ts->videoMx); if (!ts->videoPackets) ts->videoPackets = pl; else { AVPacketList * px = ts->videoPackets; while (px->next) px = px->next; px->next = pl; } gf_mx_v(ts->videoMx); return 0; }
GF_AbstractTSMuxer * ts_amux_new(GF_AVRedirect * avr, u32 videoBitrateInBitsPerSec, u32 width, u32 height, u32 audioBitRateInBitsPerSec) { GF_AbstractTSMuxer * ts = gf_malloc( sizeof(GF_AbstractTSMuxer)); memset( ts, 0, sizeof( GF_AbstractTSMuxer)); ts->oc = avformat_alloc_context(); ts->destination = avr->destination; av_register_all(); ts->oc->oformat = GUESS_FORMAT(NULL, avr->destination, NULL); if (!ts->oc->oformat) ts->oc->oformat = GUESS_FORMAT("mpegts", NULL, NULL); assert( ts->oc->oformat); #if REDIRECT_AV_AUDIO_ENABLED ts->audio_st = av_new_stream(ts->oc, avr->audioCodec->id); { AVCodecContext * c = ts->audio_st->codec; c->codec_id = avr->audioCodec->id; c->codec_type = AVMEDIA_TYPE_AUDIO; /* put sample parameters */ c->sample_fmt = SAMPLE_FMT_S16; c->bit_rate = audioBitRateInBitsPerSec; c->sample_rate = avr->audioSampleRate; c->channels = 2; c->time_base.num = 1; c->time_base.den = 1000; // some formats want stream headers to be separate if (ts->oc->oformat->flags & AVFMT_GLOBALHEADER) c->flags |= CODEC_FLAG_GLOBAL_HEADER; } #endif ts->video_st = av_new_stream(ts->oc, avr->videoCodec->id); { AVCodecContext * c = ts->video_st->codec; c->codec_id = avr->videoCodec->id; c->codec_type = AVMEDIA_TYPE_VIDEO; /* put sample parameters */ c->bit_rate = videoBitrateInBitsPerSec; /* resolution must be a multiple of two */ c->width = width; c->height = height; /* time base: this is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented. for fixed-fps content, timebase should be 1/framerate and timestamp increments should be identically 1. */ c->time_base.den = STREAM_FRAME_RATE; c->time_base.num = 1; c->gop_size = 12; /* emit one intra frame every twelve frames at most */ c->pix_fmt = STREAM_PIX_FMT; if (c->codec_id == CODEC_ID_MPEG2VIDEO) { /* just for testing, we also add B frames */ c->max_b_frames = 2; } if (c->codec_id == CODEC_ID_MPEG1VIDEO) { /* Needed to avoid using macroblocks in which some coeffs overflow. This does not happen with normal video, it just happens here as the motion of the chroma plane does not match the luma plane. */ c->mb_decision=2; } // some formats want stream headers to be separate if (ts->oc->oformat->flags & AVFMT_GLOBALHEADER) c->flags |= CODEC_FLAG_GLOBAL_HEADER; } //av_set_pts_info(ts->audio_st, 33, 1, audioBitRateInBitsPerSec); #ifndef AVIO_FLAG_WRITE /* set the output parameters (must be done even if no parameters). */ if (av_set_parameters(ts->oc, NULL) < 0) { fprintf(stderr, "Invalid output format parameters\n"); return NULL; } #endif dump_format(ts->oc, 0, avr->destination, 1); GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[AVRedirect] DUMPING to %s...\n", ts->destination)); if (avcodec_open(ts->video_st->codec, avr->videoCodec) < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[AVRedirect] failed to open video codec\n")); return NULL; } #if REDIRECT_AV_AUDIO_ENABLED if (avcodec_open(ts->audio_st->codec, avr->audioCodec) < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[AVRedirect] failed to open audio codec\n")); return NULL; } ts->audioMx = gf_mx_new("TS_AudioMx"); #endif ts->videoMx = gf_mx_new("TS_VideoMx"); ts->tsEncodingThread = gf_th_new("ts_interleave_thread_run"); ts->encode = 1; ts->audioPackets = NULL; ts->videoPackets = NULL; gf_th_run(ts->tsEncodingThread, ts_interleave_thread_run, ts); return ts; }
int main(int argc, char **argv) { /* The ISO progressive reader */ ISOProgressiveReader reader; /* Error indicator */ GF_Err e; /* input file to be read in the data buffer */ FILE *input; /* number of bytes read from the file at each read operation */ u32 read_bytes; /* number of bytes read from the file (total) */ u64 total_read_bytes; /* size of the input file */ u64 file_size; /* number of bytes required to finish the current ISO Box reading (not used here)*/ u64 missing_bytes; /* Thread used to run the ISO parsing in */ GF_Thread *reading_thread; /* Return value for the program */ int ret = 0; /* Usage */ if (argc != 2) { fprintf(stdout, "Usage: %s filename\n", argv[0]); return 1; } /* Initializing GPAC framework */ /* Enables GPAC memory tracking in debug mode only */ #if defined(DEBUG) || defined(_DEBUG) gf_sys_init(GF_MemTrackerSimple); gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_WARNING); gf_log_set_tool_level(GF_LOG_MEMORY, GF_LOG_INFO); #else gf_sys_init(GF_MemTrackerNone); gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_WARNING); #endif /* This is an input file to read data from. Could be replaced by any other method to retrieve the data (e.g. JavaScript, socket, ...)*/ input = gf_fopen(argv[1], "rb"); if (!input) { fprintf(stdout, "Could not open file %s for reading.\n", argv[1]); gf_sys_close(); return 1; } gf_fseek(input, 0, SEEK_END); file_size = gf_ftell(input); gf_fseek(input, 0, SEEK_SET); /* Initializing the progressive reader */ memset(&reader, 0, sizeof(ISOProgressiveReader)); reading_thread = gf_th_new("ISO reading thread"); reader.mutex = gf_mx_new("ISO Segment"); reader.do_run = GF_TRUE; /* we want to parse the first track */ reader.track_id = 1; /* start the async parsing */ gf_th_run(reading_thread, iso_progressive_read_thread, &reader); /* start the data reading */ reader.data_size = BUFFER_BLOCK_SIZE; reader.data = (u8 *)gf_malloc(reader.data_size); reader.valid_data_size = 0; total_read_bytes = 0; while (1) { /* block the parser until we are done manipulating the data buffer */ gf_mx_p(reader.mutex); if (reader.valid_data_size + BUFFER_BLOCK_SIZE > MAX_BUFFER_SIZE) { /* regulate the reader to limit the max buffer size and let some time to the parser to release buffer data */ fprintf(stdout, "Buffer full (%d/%d)- waiting to read next data \r", reader.valid_data_size, reader.data_size); gf_mx_v(reader.mutex); //gf_sleep(10); } else { /* make sure we have enough space in the buffer to read the next bloc of data */ if (reader.valid_data_size + BUFFER_BLOCK_SIZE > reader.data_size) { reader.data = (u8 *)gf_realloc(reader.data, reader.data_size + BUFFER_BLOCK_SIZE); reader.data_size += BUFFER_BLOCK_SIZE; } /* read the next bloc of data and update the data buffer url */ read_bytes = fread(reader.data+reader.valid_data_size, 1, BUFFER_BLOCK_SIZE, input); total_read_bytes += read_bytes; fprintf(stdout, "Read "LLD" bytes of "LLD" bytes from input file %s (buffer status: %5d/%5d)\r", total_read_bytes, file_size, argv[1], reader.valid_data_size, reader.data_size); if (read_bytes) { reader.valid_data_size += read_bytes; sprintf(reader.data_url, "gmem://%d@%p", reader.valid_data_size, reader.data); } else { /* end of file we can quit */ gf_mx_v(reader.mutex); break; } /* if the file is not yet opened (no movie), open it in progressive mode (to update its data later on) */ if (!reader.movie) { /* let's initialize the parser */ e = gf_isom_open_progressive(reader.data_url, 0, 0, &reader.movie, &missing_bytes); if (reader.movie) { gf_isom_set_single_moof_mode(reader.movie, GF_TRUE); } /* we can let parser try to work now */ gf_mx_v(reader.mutex); if ((e == GF_OK || e == GF_ISOM_INCOMPLETE_FILE) && reader.movie) { /* nothing to do, this is normal */ } else { fprintf(stdout, "Error opening fragmented mp4 in progressive mode: %s (missing "LLD" bytes)\n", gf_error_to_string(e), missing_bytes); ret = 1; goto exit; } } else { /* let inform the parser that the buffer has been updated with new data */ e = gf_isom_refresh_fragmented(reader.movie, &missing_bytes, reader.data_url); /* we can let parser try to work now */ gf_mx_v(reader.mutex); if (e != GF_OK && e != GF_ISOM_INCOMPLETE_FILE) { fprintf(stdout, "Error refreshing fragmented mp4: %s (missing "LLD" bytes)\n", gf_error_to_string(e), missing_bytes); ret = 1; goto exit; } } //gf_sleep(1); } } exit: /* stop the parser */ reader.do_run = GF_FALSE; gf_th_stop(reading_thread); /* clean structures */ gf_th_del(reading_thread); gf_mx_del(reader.mutex); gf_free(reader.data); gf_isom_close(reader.movie); gf_fclose(input); gf_sys_close(); return ret; }
int main (const int argc, const char** argv) { GF_Err e; Bool run; /* location of the configuration file: 0 wait for config on a socket, 1 use the given file */ u32 config_flag; char config_file_name[MAX_BUF]; int dest_port; unsigned short tcp_port = 0; /* Should be fine on WIFI network */ unsigned short mtu_size = 1492; int debug = 0; TCP_Input *tcp_conf = NULL; GF_Thread *tcp_thread; GF_Err th_err_tcp; GF_Err th_err_rap; RAP_Input *rap_conf; GF_Thread *rap_thread; CONF_Data *conf; GF_Config *gf_config_file; GF_Err res; GF_Socket *UDP_feedback_socket; u32 socketType_for_updates; PNC_CallbackData * data; GF_RTPChannel * chan; GF_RTPHeader hdr; u32 timer = -1; GF_Mutex *carrousel_mutex; char sdp_fmt[5000]; tcp_thread = NULL; /* init gpac lib */ gf_sys_init(); gf_log_set_level(GF_LOG_ERROR); gf_log_set_tools(GF_LOG_NETWORK|GF_LOG_RTP|GF_LOG_SCENE|GF_LOG_PARSER|GF_LOG_AUTHOR|GF_LOG_CODING|GF_LOG_SCRIPT); GF_SAFEALLOC(conf, CONF_Data); tcp_port = config_flag = 0; socketType_for_updates = GF_SOCK_TYPE_UDP; if (command_line_parsing(argc, argv, &tcp_port, config_file_name, (int *) &config_flag, &mtu_size, &debug, &socketType_for_updates)){ print_usage(); return -1; } setDebugMode( debug ); gf_config_file = NULL; if (config_flag == 1) { char *cfg_path; char *cfg_fname; char *tmp; cfg_fname = config_file_name; cfg_path = config_file_name; tmp = strrchr(cfg_fname, GF_PATH_SEPARATOR); if (tmp) { cfg_fname = tmp+1; tmp[0] = 0; } else { cfg_path = "."; } gf_config_file = gf_cfg_new(cfg_path, cfg_fname); if (!gf_config_file) { fprintf(stderr, "Cannot open config file %s\n", config_file_name); return -1; } else { dprintf(DEBUG_broadcaster, "Using config file %s.\n", config_file_name); } if (parse_config(gf_config_file, conf, debug)) return -1; tcp_port = atoi(conf->config_input_port); } else { GF_SAFEALLOC(tcp_conf, TCP_Input); tcp_conf->config_flag = &config_flag; tcp_conf->RAPtimer = &timer; tcp_conf->port = tcp_port; tcp_conf->config = conf; tcp_thread = gf_th_new("TCPInterface"); /* Starting the thread which will write the received config in a temporary file */ th_err_tcp = gf_th_run(tcp_thread, tcp_server, tcp_conf); fprintf(stdout, "Waiting for configuration on port %d...\n", tcp_conf->port); while(config_flag == 0) { gf_sleep(1000); } fprintf(stdout, "Configuration File received. Starting Streaming ...\n"); } timer = atoi(conf->rap_timer); dest_port = atoi(conf->dest_port); res = PNC_InitRTP(&chan, (char *)conf->dest_ip, dest_port, mtu_size); if (res != 0) { fprintf(stderr, "Cannot initialize RTP output (error: %d)\n", res); exit(1); } carrousel_mutex = gf_mx_new("Carrousel"); data = PNC_Init_SceneGenerator(chan, &hdr, (char *) conf->scene_init_file, socketType_for_updates, (u16) atoi(conf->modif_input_port), debug); if (!data) { fprintf(stderr, "Cannot initialize Scene Generator\n"); exit(1); } data->carrousel_mutex = carrousel_mutex; data->RAPsent = 1; UDP_feedback_socket = gf_sk_new(GF_SOCK_TYPE_UDP); e = gf_sk_bind(UDP_feedback_socket, NULL, (u16)atoi(conf->feedback_port), (char*)conf->feedback_ip, (u16)atoi(conf->feedback_port), 0); if (e) { fprintf(stderr, "Cannot bind socket for bitrate feedback information (%s)\n", gf_error_to_string(e)); } else { e = gf_sk_set_block_mode(UDP_feedback_socket, 1); if (e) { fprintf(stderr, "Cannot set feedback socket block mode (%s)\n", gf_error_to_string(e)); } } data->feedback_socket = UDP_feedback_socket; PNC_InitPacketiser(data, sdp_fmt, mtu_size); PNC_SendInitScene(data); GF_SAFEALLOC(rap_conf, RAP_Input); rap_conf->RAPtimer = &timer; rap_conf->carrousel_mutex = carrousel_mutex; rap_conf->data = data; rap_thread = gf_th_new("RAPGenerator"); th_err_rap = gf_th_run(rap_thread, RAP_send, rap_conf); sdp_generator(data, (char *)conf->dest_ip, sdp_fmt); run = 1; while (run) { GF_Err e = PNC_processBIFSGenerator(data); if (e) { fprintf(stderr, "Cannot Process BIFS data (%s)\n", gf_error_to_string(e)); break; } if (has_input()) { char c = get_a_char(); switch (c) { case 'q': run = 0; break; } } gf_sleep(10); } /* waiting for termination of the RAP thread */ rap_conf->status = 0; while (rap_conf->status != 2) gf_sleep(0); gf_free(rap_conf); gf_th_del(rap_thread); /* waiting for termination of the TCP listening thread */ if (tcp_conf) { tcp_conf->status = 0; while (tcp_conf->status != 2) gf_sleep(0); gf_free(tcp_conf); gf_th_del(tcp_thread); } PNC_Close_SceneGenerator(data); gf_free(conf); if (gf_config_file) gf_cfg_del(gf_config_file); gf_mx_del(carrousel_mutex); gf_sys_close(); return 0; }
GF_AudioRenderer *gf_sc_ar_load(GF_User *user) { const char *sOpt; u32 i, count; u32 num_buffers, total_duration; GF_Err e; GF_AudioRenderer *ar; ar = (GF_AudioRenderer *) gf_malloc(sizeof(GF_AudioRenderer)); memset(ar, 0, sizeof(GF_AudioRenderer)); num_buffers = total_duration = 0; sOpt = gf_cfg_get_key(user->config, "Audio", "ForceConfig"); if (sOpt && !stricmp(sOpt, "yes")) { sOpt = gf_cfg_get_key(user->config, "Audio", "NumBuffers"); num_buffers = sOpt ? atoi(sOpt) : 6; sOpt = gf_cfg_get_key(user->config, "Audio", "TotalDuration"); total_duration = sOpt ? atoi(sOpt) : 400; } sOpt = gf_cfg_get_key(user->config, "Audio", "NoResync"); ar->disable_resync = (sOpt && !stricmp(sOpt, "yes")) ? GF_TRUE : GF_FALSE; sOpt = gf_cfg_get_key(user->config, "Audio", "DisableMultiChannel"); ar->disable_multichannel = (sOpt && !stricmp(sOpt, "yes")) ? GF_TRUE : GF_FALSE; ar->mixer = gf_mixer_new(ar); ar->user = user; sOpt = gf_cfg_get_key(user->config, "Audio", "Volume"); ar->volume = sOpt ? atoi(sOpt) : 75; sOpt = gf_cfg_get_key(user->config, "Audio", "Pan"); ar->pan = sOpt ? atoi(sOpt) : 50; if (! (user->init_flags & GF_TERM_NO_AUDIO) ) { /*get a prefered compositor*/ sOpt = gf_cfg_get_key(user->config, "Audio", "DriverName"); if (sOpt) { ar->audio_out = (GF_AudioOutput *) gf_modules_load_interface_by_name(user->modules, sOpt, GF_AUDIO_OUTPUT_INTERFACE); if (!ar->audio_out) { ar->audio_out = NULL; sOpt = NULL; } } if (!ar->audio_out) { GF_AudioOutput *raw_out = NULL; count = gf_modules_get_count(ar->user->modules); for (i=0; i<count; i++) { ar->audio_out = (GF_AudioOutput *) gf_modules_load_interface(ar->user->modules, i, GF_AUDIO_OUTPUT_INTERFACE); if (!ar->audio_out) continue; //in enum mode, only use raw out if everything else failed ... if (!stricmp(ar->audio_out->module_name, "Raw Audio Output")) { raw_out = ar->audio_out; ar->audio_out = NULL; continue; } GF_LOG(GF_LOG_DEBUG, GF_LOG_AUDIO, ("[AudioRender] Audio output module %s loaded\n", ar->audio_out->module_name)); /*check that's a valid audio compositor*/ if ((ar->audio_out->SelfThreaded && ar->audio_out->SetPriority) || ar->audio_out->WriteAudio) { /*remember the module we use*/ gf_cfg_set_key(user->config, "Audio", "DriverName", ar->audio_out->module_name); break; } gf_modules_close_interface((GF_BaseInterface *)ar->audio_out); ar->audio_out = NULL; } if (raw_out) { if (ar->audio_out) gf_modules_close_interface((GF_BaseInterface *)raw_out); else ar->audio_out = raw_out; } } /*if not init we run with a NULL audio compositor*/ if (ar->audio_out) { ar->audio_out->FillBuffer = gf_ar_fill_output; ar->audio_out->audio_renderer = ar; GF_LOG(GF_LOG_DEBUG, GF_LOG_AUDIO, ("[AudioRender] Setting up audio module %s\n", ar->audio_out->module_name)); e = ar->audio_out->Setup(ar->audio_out, ar->user->os_window_handler, num_buffers, total_duration); /*load main audio filter*/ gf_afc_load(&ar->filter_chain, user, (char*)gf_cfg_get_key(user->config, "Audio", "Filter")); if (e != GF_OK) { GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("Could not setup audio out %s\n", ar->audio_out->module_name)); gf_modules_close_interface((GF_BaseInterface *)ar->audio_out); ar->audio_out = NULL; } else { if (!ar->audio_out->SelfThreaded) { ar->th = gf_th_new("AudioRenderer"); gf_th_run(ar->th, gf_ar_proc, ar); } else { gf_ar_setup_output_format(ar); if (ar->audio_out->SetPriority) ar->audio_out->SetPriority(ar->audio_out, GF_THREAD_PRIORITY_REALTIME); } } } if (!ar->audio_out) { gf_cfg_set_key(user->config, "Audio", "DriverName", "No Audio Output Available"); } else { if (user->init_flags & GF_TERM_USE_AUDIO_HW_CLOCK) ar->clock_use_audio_out = GF_TRUE; } } /*init compositor timer*/ ar->start_time = gf_sys_clock_high_res(); ar->current_time = 0; return ar; }
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_set_threading(GF_Terminal *term, u32 mode) { u32 i; Bool thread_it, restart_it; CodecEntry *ce; switch (mode) { case GF_TERM_THREAD_SINGLE: if (term->flags & GF_TERM_SINGLE_THREAD) return; term->flags &= ~GF_TERM_MULTI_THREAD; term->flags |= GF_TERM_SINGLE_THREAD; break; case GF_TERM_THREAD_MULTI: if (term->flags & GF_TERM_MULTI_THREAD) return; term->flags &= ~GF_TERM_SINGLE_THREAD; term->flags |= GF_TERM_MULTI_THREAD; break; default: if (!(term->flags & (GF_TERM_MULTI_THREAD | GF_TERM_SINGLE_THREAD) ) ) return; term->flags &= ~GF_TERM_SINGLE_THREAD; term->flags &= ~GF_TERM_MULTI_THREAD; break; } gf_mx_p(term->mm_mx); i=0; while ((ce = (CodecEntry*)gf_list_enum(term->codecs, &i))) { thread_it = 0; /*free mode, decoder wants threading - do */ if ((mode == GF_TERM_THREAD_FREE) && (ce->flags & GF_MM_CE_REQ_THREAD)) thread_it = 1; else if (mode == GF_TERM_THREAD_MULTI) thread_it = 1; if (thread_it && (ce->flags & GF_MM_CE_THREADED)) continue; if (!thread_it && !(ce->flags & GF_MM_CE_THREADED)) continue; restart_it = 0; if (ce->flags & GF_MM_CE_RUNNING) { restart_it = 1; ce->flags &= ~GF_MM_CE_RUNNING; } if (ce->flags & GF_MM_CE_THREADED) { /*wait for thread to die*/ while (!(ce->flags & GF_MM_CE_DEAD)) gf_sleep(1); ce->flags &= ~GF_MM_CE_DEAD; gf_th_del(ce->thread); ce->thread = NULL; gf_mx_del(ce->mx); ce->mx = NULL; ce->flags &= ~GF_MM_CE_THREADED; } else { term->cumulated_priority -= ce->dec->Priority+1; } if (thread_it) { ce->flags |= GF_MM_CE_THREADED; ce->thread = gf_th_new(ce->dec->decio->module_name); ce->mx = gf_mx_new(ce->dec->decio->module_name); } if (restart_it) { 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; } } } gf_mx_v(term->mm_mx); }