📄 renderer.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / Scene Rendering sub-project * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <gpac/internal/renderer_dev.h>/*for user and terminal API (options and InputSensor)*/#include <gpac/terminal.h>#include <gpac/options.h>#ifndef GPAC_DISABLE_SVG#include <gpac/nodes_svg_da.h>#include <gpac/scenegraph_svg.h>#ifdef GPAC_ENABLE_SVG_SA#include <gpac/nodes_svg_sa.h>#endif#ifdef GPAC_ENABLE_SVG_SANI#include <gpac/nodes_svg_sani.h>#endif#endif/*macro for size event format/send*/#define GF_USER_SETSIZE(_user, _w, _h) \ { \ GF_Event evt; \ if (_user->EventProc) { \ evt.type = GF_EVENT_SIZE; \ evt.size.width = _w; \ evt.size.height = _h; \ _user->EventProc(_user->opaque, &evt); \ } \ }void gf_sr_simulation_tick(GF_Renderer *sr);GF_Err gf_sr_set_output_size(GF_Renderer *sr, u32 Width, u32 Height){ GF_Err e; gf_sr_lock(sr, 1); /*FIXME: need to check for max resolution*/ sr->width = Width; sr->height = Height; e = sr->visual_renderer->RecomputeAR(sr->visual_renderer); sr->draw_next_frame = 1; gf_sr_lock(sr, 0); return e;}static void gf_sr_set_fullscreen(GF_Renderer *sr){ GF_Err e; if (!sr->video_out->SetFullScreen) return; GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render] Switching fullscreen %s\n", sr->fullscreen ? "off" : "on")); /*move to FS*/ sr->fullscreen = !sr->fullscreen; e = sr->video_out->SetFullScreen(sr->video_out, sr->fullscreen, &sr->width, &sr->height); if (e) { GF_USER_MESSAGE(sr->user, "VideoRenderer", "Cannot switch to fullscreen", e); sr->fullscreen = 0; e = sr->video_out->SetFullScreen(sr->video_out, 0, &sr->width, &sr->height); } GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render] recomputing aspect ratio\n")); e = sr->visual_renderer->RecomputeAR(sr->visual_renderer); /*force signaling graphics reset*/ sr->reset_graphics = 1;}/*this is needed for:- audio: since the audio renderer may not be threaded, it must be reconfigured by another thread otherwise we lock the audio module- video: this is typical to OpenGL&co: multithreaded is forbidden, so resizing/fullscreen MUST be done by the same thread accessing the HW ressources*/static void gf_sr_reconfig_task(GF_Renderer *sr){ GF_Event evt; u32 width,height; /*reconfig audio if needed (non-threaded renderers)*/ if (sr->audio_renderer && !sr->audio_renderer->th) gf_sr_ar_reconfig(sr->audio_renderer); if (sr->msg_type) { sr->msg_type |= GF_SR_IN_RECONFIG; /*scene size has been overriden*/ if (sr->msg_type & GF_SR_CFG_OVERRIDE_SIZE) { assert(!(sr->override_size_flags & 2)); sr->override_size_flags |= 2; width = sr->scene_width; height = sr->scene_height; sr->has_size_info = 1; gf_sr_set_size(sr, width, height); GF_USER_SETSIZE(sr->user, width, height); } /*size changed from scene cfg: resize window first*/ if (sr->msg_type & GF_SR_CFG_SET_SIZE) { u32 fs_width, fs_height; Bool restore_fs = sr->fullscreen; GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render] Changing display size to %d x %d\n", sr->new_width, sr->new_height)); fs_width = fs_height = 0; if (restore_fs) { //gf_sr_set_fullscreen(sr); fs_width = sr->width; fs_height = sr->height; } evt.type = GF_EVENT_SIZE; evt.size.width = sr->new_width; evt.size.height = sr->new_height; /*send resize event*/ if (!(sr->msg_type & GF_SR_CFG_WINDOWSIZE_NOTIF)) { sr->video_out->ProcessEvent(sr->video_out, &evt); } if (restore_fs) { //gf_sr_set_fullscreen(sr); sr->width = fs_width; sr->height = fs_height; sr->visual_renderer->RecomputeAR(sr->visual_renderer); } else { gf_sr_set_output_size(sr, evt.size.width, evt.size.height); } sr->reset_graphics = 1; // if (!sr->user->os_window_handler) // GF_USER_SENDEVENT(sr->user, &evt); } /*aspect ratio modif*/ if (sr->msg_type & GF_SR_CFG_AR) { sr->visual_renderer->RecomputeAR(sr->visual_renderer); } /*fullscreen on/off request*/ if (sr->msg_type & GF_SR_CFG_FULLSCREEN) { gf_sr_set_fullscreen(sr); sr->draw_next_frame = 1; } sr->new_width = sr->new_height = 0; sr->msg_type = 0; } /*3D driver changed message, recheck extensions*/ if (sr->reset_graphics) { sr->visual_renderer->GraphicsReset(sr->visual_renderer); evt.type = GF_EVENT_SYS_COLORS; if (sr->user->EventProc && sr->user->EventProc(sr->user->opaque, &evt) ) { u32 i; for (i=0; i<28; i++) { sr->sys_colors[i] = evt.sys_cols.sys_colors[i] & 0x00FFFFFF; } } }}Bool gf_sr_render_frame(GF_Renderer *sr){ /*render*/ gf_sr_simulation_tick(sr); return sr->draw_next_frame;}u32 SR_RenderRun(void *par){ GF_Renderer *sr = (GF_Renderer *) par; sr->video_th_state = 1; GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[Renderer] Entering thread ID %d\n", gf_th_id() )); while (sr->video_th_state == 1) { /*sleep or render*/ if (sr->is_hidden) gf_sleep(sr->frame_duration); else gf_sr_simulation_tick(sr); } /*destroy video out here if w're using openGL, to avoid threading issues*/ sr->video_out->Shutdown(sr->video_out); gf_modules_close_interface((GF_BaseInterface *)sr->video_out); sr->video_out = NULL; sr->video_th_state = 3; return 0;}/*forces graphics redraw*/GF_EXPORTvoid gf_sr_reset_graphics(GF_Renderer *sr){ if (sr) { gf_sr_lock(sr, 1); sr->reset_graphics = 1; gf_sr_lock(sr, 0); }}void SR_ResetFrameRate(GF_Renderer *sr){ u32 i; for (i=0; i<GF_SR_FPS_COMPUTE_SIZE; i++) sr->frame_time[i] = 0; sr->current_frame = 0;}void SR_SetFontEngine(GF_Renderer *sr);static void gf_sr_on_event(void *cbck, GF_Event *event);static Bool check_graphics2D_driver(GF_Raster2D *ifce){ /*check base*/ if (!ifce->stencil_new || !ifce->surface_new) return 0; /*if these are not set we cannot draw*/ if (!ifce->surface_clear || !ifce->surface_set_path || !ifce->surface_fill) return 0; /*check we can init a surface with the current driver (the rest is optional)*/ if (ifce->surface_attach_to_buffer) return 1; return 0;}static GF_Renderer *SR_New(GF_User *user){ const char *sOpt; GF_VisualRenderer *vrend; GF_GLConfig cfg, *gl_cfg; Bool forced = 1; GF_Renderer *tmp; GF_SAFEALLOC(tmp, GF_Renderer); if (!tmp) return NULL; tmp->user = user; /*load renderer to check for GL flag*/ if (! (user->init_flags & (GF_TERM_FORCE_2D | GF_TERM_FORCE_3D)) ) { sOpt = gf_cfg_get_key(user->config, "Rendering", "RendererName"); if (sOpt) { tmp->visual_renderer = (GF_VisualRenderer *) gf_modules_load_interface_by_name(user->modules, sOpt, GF_RENDERER_INTERFACE); if (!tmp->visual_renderer) sOpt = NULL; } forced = 0; } if (!tmp->visual_renderer) { u32 i, count; count = gf_modules_get_count(user->modules); for (i=0; i<count; i++) { tmp->visual_renderer = (GF_VisualRenderer *) gf_modules_load_interface(user->modules, i, GF_RENDERER_INTERFACE); if (tmp->visual_renderer) { if ((tmp->visual_renderer->bNeedsGL && (user->init_flags & GF_TERM_FORCE_2D)) || (!tmp->visual_renderer->bNeedsGL && (user->init_flags & GF_TERM_FORCE_3D)) ) { GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Renderer] Renderer %s loaded but not matching init flags %08x\n", tmp->visual_renderer->module_name, user->init_flags)); gf_modules_close_interface((GF_BaseInterface *)tmp->visual_renderer); tmp->visual_renderer = NULL; continue; } break; } } if (!forced && tmp->visual_renderer) gf_cfg_set_key(user->config, "Rendering", "RendererName", tmp->visual_renderer->module_name); } if (!tmp->visual_renderer) { GF_LOG(GF_LOG_ERROR, GF_LOG_RENDER, ("[Renderer] Cannot load any visual renderer - aborting\n")); free(tmp); return NULL; } memset(&cfg, 0, sizeof(cfg)); cfg.double_buffered = 1; gl_cfg = tmp->visual_renderer->bNeedsGL ? &cfg : NULL; vrend = tmp->visual_renderer; tmp->visual_renderer = NULL; /*load video out*/ sOpt = gf_cfg_get_key(user->config, "Video", "DriverName"); if (sOpt) { tmp->video_out = (GF_VideoOutput *) gf_modules_load_interface_by_name(user->modules, sOpt, GF_VIDEO_OUTPUT_INTERFACE); if (tmp->video_out) { tmp->video_out->evt_cbk_hdl = tmp; tmp->video_out->on_event = gf_sr_on_event; /*init hw*/ if (tmp->video_out->Setup(tmp->video_out, user->os_window_handler, user->os_display, user->init_flags, gl_cfg) != GF_OK) { gf_modules_close_interface((GF_BaseInterface *)tmp->video_out); tmp->video_out = NULL; } } else { sOpt = NULL; } } if (!tmp->video_out) { u32 i, count; count = gf_modules_get_count(user->modules); for (i=0; i<count; i++) { tmp->video_out = (GF_VideoOutput *) gf_modules_load_interface(user->modules, i, GF_VIDEO_OUTPUT_INTERFACE); if (!tmp->video_out) continue; tmp->video_out->evt_cbk_hdl = tmp; tmp->video_out->on_event = gf_sr_on_event; /*init hw*/ if (tmp->video_out->Setup(tmp->video_out, user->os_window_handler, user->os_display, user->init_flags, gl_cfg)==GF_OK) { gf_cfg_set_key(user->config, "Video", "DriverName", tmp->video_out->module_name); break; } gf_modules_close_interface((GF_BaseInterface *)tmp->video_out); tmp->video_out = NULL; } } tmp->visual_renderer = vrend; if (!tmp->video_out ) { gf_modules_close_interface((GF_BaseInterface *)tmp->visual_renderer); free(tmp); return NULL; } /*try to load a raster driver*/ sOpt = gf_cfg_get_key(user->config, "Rendering", "Raster2D"); if (sOpt) { tmp->r2d = (GF_Raster2D *) gf_modules_load_interface_by_name(user->modules, sOpt, GF_RASTER_2D_INTERFACE); if (!tmp->r2d) { sOpt = NULL; } else if (!check_graphics2D_driver(tmp->r2d)) { gf_modules_close_interface((GF_BaseInterface *)tmp->r2d); tmp->r2d = NULL; sOpt = NULL; } } if (!tmp->r2d) { u32 i, count; count = gf_modules_get_count(user->modules); for (i=0; i<count; i++) { tmp->r2d = (GF_Raster2D *) gf_modules_load_interface(user->modules, i, GF_RASTER_2D_INTERFACE); if (!tmp->r2d) continue; if (check_graphics2D_driver(tmp->r2d)) break; gf_modules_close_interface((GF_BaseInterface *)tmp->r2d); tmp->r2d = NULL; } if (tmp->r2d) gf_cfg_set_key(user->config, "Rendering", "Raster2D", tmp->r2d->module_name); } /*and init*/ if (tmp->visual_renderer->LoadRenderer(tmp->visual_renderer, tmp) != GF_OK) { gf_modules_close_interface((GF_BaseInterface *)tmp->visual_renderer); tmp->video_out->Shutdown(tmp->video_out); gf_modules_close_interface((GF_BaseInterface *)tmp->video_out); free(tmp); return NULL; } tmp->mx = gf_mx_new(); tmp->textures = gf_list_new(); tmp->frame_rate = 30.0; tmp->frame_duration = 33; tmp->time_nodes = gf_list_new();#ifdef GF_SR_EVENT_QUEUE tmp->events = gf_list_new(); tmp->ev_mx = gf_mx_new();#endif SR_ResetFrameRate(tmp); /*set font engine if any*/ SR_SetFontEngine(tmp); tmp->extra_scenes = gf_list_new(); tmp->interaction_level = GF_INTERACT_NORMAL | GF_INTERACT_INPUT_SENSOR | GF_INTERACT_NAVIGATION; return tmp;}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;}void gf_sr_del(GF_Renderer *sr){ if (!sr) return; GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render] Destroying Renderer\n")); gf_sr_lock(sr, 1); if (sr->VisualThread) { sr->video_th_state = 2; while (sr->video_th_state!=3) gf_sleep(10); gf_th_del(sr->VisualThread); } if (sr->video_out) { GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render] Closing video output\n")); sr->video_out->Shutdown(sr->video_out); gf_modules_close_interface((GF_BaseInterface *)sr->video_out); } GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render] Closing visual renderer\n")); sr->visual_renderer->UnloadRenderer(sr->visual_renderer); GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render] Unloading visual renderer module\n")); gf_modules_close_interface((GF_BaseInterface *)sr->visual_renderer); GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render] visual renderer module unloaded\n")); if (sr->audio_renderer) gf_sr_ar_del(sr->audio_renderer);#ifdef GF_SR_EVENT_QUEUE gf_mx_p(sr->ev_mx); while (gf_list_count(sr->events)) { GF_Event *ev = (GF_Event *)gf_list_get(sr->events, 0); gf_list_rem(sr->events, 0); free(ev); } gf_mx_v(sr->ev_mx); gf_mx_del(sr->ev_mx); gf_list_del(sr->events);#endif if (sr->font_engine) { GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render] Closing font engine\n")); sr->font_engine->shutdown_font_engine(sr->font_engine); gf_modules_close_interface((GF_BaseInterface *)sr->font_engine); } gf_list_del(sr->textures); gf_list_del(sr->time_nodes); gf_list_del(sr->extra_scenes); gf_sr_lock(sr, 0); gf_mx_del(sr->mx); free(sr); GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render] Renderer destroyed\n"));}void gf_sr_set_fps(GF_Renderer *sr, Double fps){ if (fps) { sr->frame_rate = fps; sr->frame_duration = (u32) (1000 / fps); SR_ResetFrameRate(sr); }}u32 gf_sr_get_audio_buffer_length(GF_Renderer *sr){ if (!sr || !sr->audio_renderer || !sr->audio_renderer->audio_out) return 0; return sr->audio_renderer->audio_out->GetTotalBufferTime(sr->audio_renderer->audio_out);}static void gf_sr_pause(GF_Renderer *sr, u32 PlayState){ if (!sr || !sr->audio_renderer) return; if (!sr->paused && !PlayState) return; if (sr->paused && (PlayState==GF_STATE_PAUSED)) return; /*step mode*/ if (PlayState==GF_STATE_STEP_PAUSE) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -