1 // GPAC.cpp : Defines the class behaviors for the application.
2 //
3 
4 #include "stdafx.h"
5 #include "Osmo4.h"
6 #include <gpac/network.h>
7 #include <direct.h>
8 #include "MainFrm.h"
9 #include "OpenUrl.h"
10 #include "resource.h"
11 
12 #ifdef _DEBUG
13 #define new DEBUG_NEW
14 #undef THIS_FILE
15 static char THIS_FILE[] = __FILE__;
16 #endif
17 
18 /////////////////////////////////////////////////////////////////////////////
19 // Osmo4
20 
BEGIN_MESSAGE_MAP(Osmo4,CWinApp)21 BEGIN_MESSAGE_MAP(Osmo4, CWinApp)
22 	//{{AFX_MSG_MAP(Osmo4)
23 	ON_COMMAND(ID_OPEN_FILE, OnOpenFile)
24 	ON_COMMAND(ID_FILE_STEP, OnFileStep)
25 	ON_COMMAND(ID_OPEN_URL, OnOpenUrl)
26 	ON_COMMAND(ID_FILE_RELOAD, OnFileReload)
27 	ON_COMMAND(ID_CONFIG_RELOAD, OnConfigReload)
28 	ON_COMMAND(ID_FILE_PLAY, OnFilePlay)
29 	ON_UPDATE_COMMAND_UI(ID_FILE_PLAY, OnUpdateFilePlay)
30 	ON_UPDATE_COMMAND_UI(ID_FILE_STEP, OnUpdateFileStep)
31 	ON_COMMAND(ID_FILE_STOP, OnFileStop)
32 	ON_UPDATE_COMMAND_UI(ID_FILE_STOP, OnUpdateFileStop)
33 	ON_COMMAND(ID_SWITCH_RENDER, OnSwitchRender)
34 	ON_UPDATE_COMMAND_UI(ID_FILE_RELOAD, OnUpdateFileStop)
35 	ON_COMMAND(ID_H_ABOUT, OnAbout)
36 	ON_COMMAND(ID_FILE_MIGRATE, OnFileMigrate)
37 	//}}AFX_MSG_MAP
38 END_MESSAGE_MAP()
39 
40 /////////////////////////////////////////////////////////////////////////////
41 // Osmo4 construction
42 
43 Osmo4::Osmo4()
44 {
45 }
46 
47 /////////////////////////////////////////////////////////////////////////////
48 // The one and only Osmo4 object
49 
50 Osmo4 theApp;
51 
52 
53 
54 class UserPassDialog : public CDialog
55 {
56 // Construction
57 public:
58 	UserPassDialog(CWnd* pParent = NULL);   // standard constructor
59 
60 	Bool GetPassword(const char *site_url, char *user, char *password);
61 
62 // Dialog Data
63 	//{{AFX_DATA(UserPassDialog)
64 	enum { IDD = IDD_PASSWD };
65 	CStatic	m_SiteURL;
66 	CEdit m_User;
67 	CEdit m_Pass;
68 	//}}AFX_DATA
69 
70 	void SetSelection(u32 sel);
71 	char cur_ext[200], cur_mime[200];
72 
73 // Overrides
74 	// ClassWizard generated virtual function overrides
75 	//{{AFX_VIRTUAL(UserPassDialog)
76 protected:
77 	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
78 	//}}AFX_VIRTUAL
79 
80 // Implementation
81 protected:
82 	const char *m_site_url;
83 	char *m_user, *m_password;
84 
85 	// Generated message map functions
86 	//{{AFX_MSG(UserPassDialog)
87 	virtual BOOL OnInitDialog();
88 	afx_msg void OnClose();
89 	//}}AFX_MSG
90 };
91 
UserPassDialog(CWnd * pParent)92 UserPassDialog::UserPassDialog(CWnd* pParent /*=NULL*/)
93 	: CDialog(UserPassDialog::IDD, pParent)
94 {
95 	//{{AFX_DATA_INIT(COptStream)
96 	//}}AFX_DATA_INIT
97 }
98 
DoDataExchange(CDataExchange * pDX)99 void UserPassDialog::DoDataExchange(CDataExchange* pDX)
100 {
101 	CDialog::DoDataExchange(pDX);
102 	//{{AFX_DATA_MAP(UserPassDialog)
103 	DDX_Control(pDX, IDC_TXT_SITE, m_SiteURL);
104 	DDX_Control(pDX, IDC_EDIT_USER, m_User);
105 	DDX_Control(pDX, IDC_EDIT_PASSWORD, m_Pass);
106 	//}}AFX_DATA_MAP
107 }
108 
OnInitDialog()109 BOOL UserPassDialog::OnInitDialog()
110 {
111 	CDialog::OnInitDialog();
112 	m_SiteURL.SetWindowText(m_site_url);
113 	m_User.SetWindowText(m_user);
114 	m_Pass.SetWindowText("");
115 	return TRUE;
116 }
117 
OnClose()118 void UserPassDialog::OnClose()
119 {
120 	m_User.GetWindowText(m_user, 50);
121 	m_Pass.GetWindowText(m_password, 50);
122 }
123 
GetPassword(const char * site_url,char * user,char * password)124 Bool UserPassDialog::GetPassword(const char *site_url, char *user, char *password)
125 {
126 	m_site_url = site_url;
127 	m_user = user;
128 	if (DoModal() != IDOK) return GF_FALSE;
129 	return GF_TRUE;
130 }
131 
132 
Osmo4_progress_cbk(const void * usr,const char * title,u64 done,u64 total)133 static void Osmo4_progress_cbk(const void *usr, const char *title, u64 done, u64 total)
134 {
135 	if (!total) return;
136 	CMainFrame *pFrame = (CMainFrame *) ((Osmo4 *) usr)->m_pMainWnd;
137 	s32 prog = (s32) ( (100 * (u64)done) / total);
138 	if (pFrame->m_last_prog < prog) {
139 		pFrame->console_err = GF_OK;
140 		pFrame->m_last_prog = prog;
141 		pFrame->console_message.Format("%s %02d %%", title, prog);
142 		pFrame->PostMessage(WM_CONSOLEMSG, 0, 0);
143 		if (done==total) pFrame->m_last_prog = -1;
144 	}
145 }
146 
147 #define W32_MIN_WIDTH 120
148 
log_msg(char * msg)149 static void log_msg(char *msg)
150 {
151 	::MessageBox(NULL, msg, "GPAC", MB_OK);
152 }
Osmo4_EventProc(void * priv,GF_Event * evt)153 Bool Osmo4_EventProc(void *priv, GF_Event *evt)
154 {
155 	u32 dur;
156 	Osmo4 *gpac = (Osmo4 *) priv;
157 	CMainFrame *pFrame = (CMainFrame *) gpac->m_pMainWnd;
158 	/*shutdown*/
159 	if (!pFrame) return GF_FALSE;
160 
161 	switch (evt->type) {
162 	case GF_EVENT_DURATION:
163 		dur = (u32) (1000 * evt->duration.duration);
164 		//if (dur<1100) dur = 0;
165 		pFrame->m_pPlayList->SetDuration((u32) evt->duration.duration );
166 		gpac->max_duration = dur;
167 		gpac->can_seek = evt->duration.can_seek;
168 		if (!gpac->can_seek) {
169 			pFrame->m_Sliders.m_PosSlider.EnableWindow(FALSE);
170 		} else {
171 			pFrame->m_Sliders.m_PosSlider.EnableWindow(TRUE);
172 			pFrame->m_Sliders.m_PosSlider.SetRangeMin(0);
173 			pFrame->m_Sliders.m_PosSlider.SetRangeMax(dur);
174 		}
175 		break;
176 
177 	case GF_EVENT_MESSAGE:
178 		if (!evt->message.service || !strcmp(evt->message.service, (LPCSTR) pFrame->m_pPlayList->GetURL() )) {
179 			pFrame->console_service = "main service";
180 		} else {
181 			pFrame->console_service = evt->message.service;
182 		}
183 		if (evt->message.error!=GF_OK) {
184 			if (evt->message.error<GF_OK || !gpac->m_NoConsole) {
185 				pFrame->console_err = evt->message.error;
186 				pFrame->console_message = evt->message.message;
187 				gpac->m_pMainWnd->PostMessage(WM_CONSOLEMSG, 0, 0);
188 
189 				/*any error before connection confirm is a service connection error*/
190 				if (!gpac->m_isopen) pFrame->m_pPlayList->SetDead();
191 			}
192 			return GF_FALSE;
193 		}
194 		if (gpac->m_NoConsole) return GF_FALSE;
195 
196 		/*process user message*/
197 		pFrame->console_err = GF_OK;
198 		pFrame->console_message = evt->message.message;
199 		gpac->m_pMainWnd->PostMessage(WM_CONSOLEMSG, 0, 0);
200 		break;
201 	case GF_EVENT_PROGRESS:
202 		char *szType;
203 		if (evt->progress.progress_type==0) szType = "Buffer ";
204 		else if (evt->progress.progress_type==1) szType = "Download ";
205 		else if (evt->progress.progress_type==2) szType = "Import ";
206 		gf_set_progress(szType, evt->progress.done, evt->progress.total);
207 		break;
208 	case GF_EVENT_NAVIGATE_INFO:
209 		pFrame->console_message = evt->navigate.to_url;
210 		gpac->m_pMainWnd->PostMessage(WM_CONSOLEMSG, 1000, 0);
211 		break;
212 
213 	case GF_EVENT_SCENE_SIZE:
214 		if (evt->size.width && evt->size.height) {
215 			gpac->orig_width = evt->size.width;
216 			gpac->orig_height = evt->size.height;
217 			if (gpac->m_term && !pFrame->m_bFullScreen)
218 				pFrame->PostMessage(WM_SETSIZE, evt->size.width, evt->size.height);
219 		}
220 		break;
221 		/*don't resize on win32 msg notif*/
222 #if 0
223 	case GF_EVENT_SIZE:
224 		if (/*gpac->m_term && !pFrame->m_bFullScreen && */gpac->orig_width && (evt->size.width < W32_MIN_WIDTH) )
225 			pFrame->PostMessage(WM_SETSIZE, W32_MIN_WIDTH, (W32_MIN_WIDTH*gpac->orig_height) / gpac->orig_width);
226 		else
227 			pFrame->PostMessage(WM_SETSIZE, evt->size.width, evt->size.height);
228 		break;
229 #endif
230 
231 	case GF_EVENT_CONNECT:
232 //		if (pFrame->m_bStartupFile) return 0;
233 
234 		pFrame->BuildStreamList(GF_TRUE);
235 		if (evt->connect.is_connected) {
236 			pFrame->BuildChapterList(GF_FALSE);
237 			gpac->m_isopen = GF_TRUE;
238 			//resetting sliders when opening a new file creates a deadlock on the window thread which is disconnecting
239 			pFrame->m_wndToolBar.SetButtonInfo(5, ID_FILE_PLAY, TBBS_BUTTON, gpac->m_isopen ? 4 : 3);
240 			pFrame->m_Sliders.m_PosSlider.SetPos(0);
241 			pFrame->SetProgTimer(GF_TRUE);
242 		} else {
243 			gpac->max_duration = 0;
244 			gpac->m_isopen = GF_FALSE;
245 			pFrame->BuildChapterList(GF_TRUE);
246 		}
247 		if (!pFrame->m_bFullScreen) {
248 			pFrame->SetFocus();
249 			pFrame->SetForegroundWindow();
250 		}
251 		break;
252 
253 	case GF_EVENT_QUIT:
254 		pFrame->PostMessage(WM_CLOSE, 0L, 0L);
255 		break;
256 	case GF_EVENT_MIGRATE:
257 	{
258 	}
259 	break;
260 	case GF_EVENT_KEYDOWN:
261 		gf_term_process_shortcut(gpac->m_term, evt);
262 		/*update volume control*/
263 		pFrame->m_Sliders.SetVolume();
264 
265 		switch (evt->key.key_code) {
266 		case GF_KEY_HOME:
267 			gf_term_set_option(gpac->m_term, GF_OPT_NAVIGATION_TYPE, 1);
268 			break;
269 		case GF_KEY_ESCAPE:
270 			pFrame->PostMessage(WM_COMMAND, ID_VIEW_FULLSCREEN);
271 			break;
272 		case GF_KEY_MEDIANEXTTRACK:
273 			pFrame->m_pPlayList->PlayNext();
274 			break;
275 		case GF_KEY_MEDIAPREVIOUSTRACK:
276 			pFrame->m_pPlayList->PlayPrev();
277 			break;
278 		case GF_KEY_H:
279 			if ((evt->key.flags & GF_KEY_MOD_CTRL) && gpac->m_isopen)
280 				gf_term_switch_quality(gpac->m_term, GF_TRUE);
281 			break;
282 		case GF_KEY_L:
283 			if ((evt->key.flags & GF_KEY_MOD_CTRL) && gpac->m_isopen)
284 				gf_term_switch_quality(gpac->m_term, GF_FALSE);
285 			break;
286 		case GF_KEY_LEFT:
287 		case GF_KEY_RIGHT:
288 			if (gpac->m_isopen && (gf_term_get_option(gpac->m_term, GF_OPT_NAVIGATION) == GF_NAVIGATE_NONE)) {
289 				if (evt->key.flags & GF_KEY_MOD_CTRL) {
290 					if (evt->key.key_code==GF_KEY_LEFT) pFrame->m_pPlayList->PlayPrev();
291 					else if (evt->key.key_code==GF_KEY_RIGHT) pFrame->m_pPlayList->PlayNext();
292 				}
293 				else if (gpac->can_seek && (evt->key.flags & GF_KEY_MOD_ALT)) {
294 					u32 duration = gpac->max_duration;
295 					s32 current_time = gf_term_get_time_in_ms(gpac->m_term);
296 
297 					if (evt->key.key_code==GF_KEY_LEFT) {
298 						current_time -= 5*duration/100;
299 						if (current_time<0) current_time=0;
300 						gf_term_play_from_time(gpac->m_term, (u64) current_time, 0);
301 					}
302 					else if (evt->key.key_code==GF_KEY_RIGHT) {
303 						current_time += 5*duration/100;
304 						if ((u32) current_time < duration) {
305 							gf_term_play_from_time(gpac->m_term, (u64) current_time, 0);
306 						}
307 					}
308 				}
309 			}
310 			break;
311 		}
312 		break;
313 	case GF_EVENT_NAVIGATE:
314 		/*fixme - a proper browser would require checking mime type & co*/
315 		/*store URL since it may be destroyed, and post message*/
316 		gpac->m_navigate_url = evt->navigate.to_url;
317 		pFrame->PostMessage(WM_NAVIGATE, NULL, NULL);
318 		return GF_TRUE;
319 	case GF_EVENT_VIEWPOINTS:
320 		pFrame->BuildViewList();
321 		return GF_FALSE;
322 	case GF_EVENT_STREAMLIST:
323 		pFrame->BuildStreamList(GF_FALSE);
324 		return GF_FALSE;
325 	case GF_EVENT_SET_CAPTION:
326 		pFrame->SetWindowText(evt->caption.caption);
327 		break;
328 	case GF_EVENT_DBLCLICK:
329 		pFrame->PostMessage(WM_COMMAND, ID_VIEW_FULLSCREEN);
330 		return GF_FALSE;
331 	case GF_EVENT_AUTHORIZATION:
332 	{
333 		UserPassDialog passdlg;
334 		return passdlg.GetPassword(evt->auth.site_url, evt->auth.user, evt->auth.password);
335 	}
336 	}
337 	return GF_FALSE;
338 }
339 
340 
341 /*here's the trick: use a storage section shared among all processes for the wnd handle and for the command line
342 NOTE: this has to be static memory of course, don't try to alloc anything there...*/
343 #pragma comment(linker, "/SECTION:.shr,RWS")
344 #pragma data_seg(".shr")
345 HWND static_gpac_hwnd = NULL;
346 char static_szCmdLine[MAX_PATH] = "";
347 #pragma data_seg()
348 
static_gpac_get_url()349 const char *static_gpac_get_url()
350 {
351 	return (const char *) static_szCmdLine;
352 }
353 
osmo4_do_log(void * cbk,GF_LOG_Level level,GF_LOG_Tool tool,const char * fmt,va_list list)354 static void osmo4_do_log(void *cbk, GF_LOG_Level level, GF_LOG_Tool tool, const char *fmt, va_list list)
355 {
356 	FILE *logs = (FILE *) cbk;
357 	vfprintf(logs, fmt, list);
358 	fflush(logs);
359 }
360 
InitInstance()361 BOOL Osmo4::InitInstance()
362 {
363 	CCommandLineInfo cmdInfo;
364 
365 	afxAmbientActCtx = FALSE;
366 
367 	m_logs = NULL;
368 
369 	m_term = NULL;
370 
371 	memset(&m_user, 0, sizeof(GF_User));
372 
373 	/*get Osmo4.exe path*/
374 	strcpy((char *) szApplicationPath, AfxGetApp()->m_pszHelpFilePath);
375 	while (szApplicationPath[strlen((char *) szApplicationPath)-1] != '\\') szApplicationPath[strlen((char *) szApplicationPath)-1] = 0;
376 	if (szApplicationPath[strlen((char *) szApplicationPath)-1] != '\\') strcat(szApplicationPath, "\\");
377 
378 	gf_sys_init(GF_MemTrackerNone);
379 
380 	/*setup user*/
381 	memset(&m_user, 0, sizeof(GF_User));
382 
383 	Bool first_launch = GF_FALSE;
384 	/*init config and modules*/
385 	m_user.config = gf_cfg_init(NULL, &first_launch);
386 	if (!m_user.config) {
387 		MessageBox(NULL, "GPAC Configuration file not found", "Fatal Error", MB_OK);
388 		m_pMainWnd->PostMessage(WM_CLOSE);
389 	}
390 
391 	char *name = gf_cfg_get_filename(m_user.config);
392 	char *sep = strrchr(name, '\\');
393 	if (sep) sep[0] = 0;
394 	strcpy(szUserPath, name);
395 	if (sep) sep[0] = '\\';
396 
397 	const char *opt = gf_cfg_get_key(m_user.config, "General", "SingleInstance");
398 	m_SingleInstance = (opt && !stricmp(opt, "yes")) ? GF_TRUE : GF_FALSE;
399 
400 	m_hMutex = NULL;
401 	if (m_SingleInstance) {
402 		m_hMutex = CreateMutex(NULL, FALSE, "Osmo4_GPAC_INSTANCE");
403 		if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
404 			char szDIR[1024];
405 			if (m_hMutex) CloseHandle(m_hMutex);
406 			m_hMutex = NULL;
407 
408 			if (!static_gpac_hwnd || !IsWindow(static_gpac_hwnd) ) {
409 				::MessageBox(NULL, "Osmo4 ghost process detected", "Error at last shutdown" , MB_OK);
410 			} else {
411 				::SetForegroundWindow(static_gpac_hwnd);
412 
413 				if (m_lpCmdLine && strlen(m_lpCmdLine)) {
414 					DWORD_PTR res;
415 					size_t len;
416 					char *the_url, *cmd;
417 					GetCurrentDirectory(1024, szDIR);
418 					if (szDIR[strlen(szDIR)-1] != '\\') strcat(szDIR, "\\");
419 					cmd = (char *)(const char *) m_lpCmdLine;
420 					strcpy(static_szCmdLine, "");
421 					if (cmd[0]=='"') cmd+=1;
422 
423 					if (!strnicmp(cmd, "-queue ", 7)) {
424 						strcat(static_szCmdLine, "-queue ");
425 						cmd += 7;
426 					}
427 					the_url = gf_url_concatenate(szDIR, cmd);
428 					if (!the_url) {
429 						strcat(static_szCmdLine, cmd);
430 					} else {
431 						strcat(static_szCmdLine, the_url);
432 						gf_free(the_url);
433 					}
434 					while ( (len = strlen(static_szCmdLine)) ) {
435 						char s = static_szCmdLine[len-1];
436 						if ((s==' ') || (s=='"')) static_szCmdLine[len-1]=0;
437 						else break;
438 					}
439 					::SendMessageTimeout(static_gpac_hwnd, WM_NEWINSTANCE, 0, 0, 0, 1000, &res);
440 				}
441 			}
442 
443 			return FALSE;
444 		}
445 	}
446 
447 #if 0
448 	// Standard initialization
449 #ifdef _AFXDLL
450 	Enable3dControls();			// Call this when using MFC in a shared DLL
451 #else
452 	Enable3dControlsStatic();	// Call this when linking to MFC statically
453 #endif
454 
455 #endif
456 
457 	SetRegistryKey(_T("GPAC"));
458 	CMainFrame* pFrame = new CMainFrame;
459 	m_pMainWnd = pFrame;
460 	pFrame->LoadFrame(IDR_MAINFRAME, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL, NULL);
461 	pFrame->LoadAccelTable( MAKEINTRESOURCE(IDR_MAINACCEL));
462 
463 	m_pMainWnd->DragAcceptFiles();
464 
465 	if (m_SingleInstance) static_gpac_hwnd = m_pMainWnd->m_hWnd;
466 
467 	m_user.modules = gf_modules_new(NULL, m_user.config);
468 	if (!m_user.modules || ! gf_modules_get_count(m_user.modules) ) {
469 		MessageBox(NULL, "No modules available - system cannot work", "Fatal Error", MB_OK);
470 		m_pMainWnd->PostMessage(WM_CLOSE);
471 	}
472 	else if (first_launch) {
473 		/*first launch, register all files ext*/
474 		u32 i;
475 		for (i=0; i<gf_modules_get_count(m_user.modules); i++) {
476 			GF_InputService *ifce = (GF_InputService *) gf_modules_load_interface(m_user.modules, i, GF_NET_CLIENT_INTERFACE);
477 			if (!ifce) continue;
478 			if (ifce) {
479 				ifce->CanHandleURL(ifce, "test.test");
480 				gf_modules_close_interface((GF_BaseInterface *)ifce);
481 			}
482 		}
483 		/*set some shortcuts*/
484 		gf_cfg_set_key(m_user.config, "Shortcuts", "VolumeUp", "ctrl+Up");
485 		gf_cfg_set_key(m_user.config, "Shortcuts", "VolumeDown", "ctrl+Down");
486 		gf_cfg_set_key(m_user.config, "Shortcuts", "FastRewind", "ctrl+Left");
487 		gf_cfg_set_key(m_user.config, "Shortcuts", "FastForward", "ctrl+Right");
488 		gf_cfg_set_key(m_user.config, "Shortcuts", "Play", "ctrl+ ");
489 	}
490 
491 	/*check log file*/
492 	const char *str = gf_cfg_get_key(m_user.config, "General", "LogFile");
493 	if (str) {
494 		m_logs = gf_fopen(str, "wt");
495 		gf_log_set_callback(m_logs, osmo4_do_log);
496 	}
497 	else m_logs = NULL;
498 
499 	/*set log level*/
500 	if (gf_log_set_tools_levels(gf_cfg_get_key(m_user.config, "General", "Logs")) != GF_OK)
501 		fprintf(stdout, "osmo4: invalid log level specified\n");
502 
503 	m_user.opaque = this;
504 	m_user.os_window_handler = pFrame->m_pWndView->m_hWnd;
505 	m_user.EventProc = Osmo4_EventProc;
506 
507 	m_reset = GF_FALSE;
508 	orig_width = 320;
509 	orig_height = 240;
510 
511 	gf_set_progress_callback(this, Osmo4_progress_cbk);
512 
513 	m_term = gf_term_new(&m_user);
514 	if (! m_term) {
515 		MessageBox(NULL, "Cannot load GPAC Terminal", "Fatal Error", MB_OK);
516 		m_pMainWnd->PostMessage(WM_CLOSE);
517 		return TRUE;
518 	}
519 	SetOptions();
520 	UpdateRenderSwitch();
521 
522 	pFrame->SendMessage(WM_SETSIZE, orig_width, orig_height);
523 	pFrame->m_Address.ReloadURLs();
524 
525 	pFrame->m_Sliders.SetVolume();
526 
527 	m_reconnect_time = 0;
528 
529 
530 	ParseCommandLine(cmdInfo);
531 
532 	start_mode = 0;
533 
534 	if (! cmdInfo.m_strFileName.IsEmpty()) {
535 		pFrame->m_pPlayList->QueueURL(cmdInfo.m_strFileName);
536 		pFrame->m_pPlayList->RefreshList();
537 		pFrame->m_pPlayList->PlayNext();
538 	} else {
539 		char sPL[MAX_PATH];
540 		strcpy((char *) sPL, szUserPath);
541 		strcat(sPL, "gpac_pl.m3u");
542 		pFrame->m_pPlayList->OpenPlayList(sPL);
543 		const char *sOpt = gf_cfg_get_key(GetApp()->m_user.config, "General", "PLEntry");
544 		if (sOpt) {
545 			s32 count = (s32)gf_list_count(pFrame->m_pPlayList->m_entries);
546 			pFrame->m_pPlayList->m_cur_entry = atoi(sOpt);
547 			if (pFrame->m_pPlayList->m_cur_entry>=count)
548 				pFrame->m_pPlayList->m_cur_entry = count-1;
549 		} else {
550 			pFrame->m_pPlayList->m_cur_entry = -1;
551 		}
552 #if 0
553 		if (pFrame->m_pPlayList->m_cur_entry>=0) {
554 			start_mode = 1;
555 			pFrame->m_pPlayList->Play();
556 		}
557 #endif
558 
559 		sOpt = gf_cfg_get_key(m_user.config, "General", "StartupFile");
560 		if (sOpt && !strstr(sOpt, "gui") ) gf_term_connect(m_term, sOpt);
561 
562 		sOpt = gf_cfg_get_key(m_user.config, "General", "PlaylistLoop");
563 		m_Loop = (sOpt && !strcmp(sOpt, "yes")) ? GF_TRUE : GF_FALSE;
564 	}
565 	pFrame->SetFocus();
566 	pFrame->SetForegroundWindow();
567 	return TRUE;
568 }
569 
ExitInstance()570 int Osmo4::ExitInstance()
571 {
572 	if (m_term) gf_term_del(m_term);
573 	if (m_user.modules) gf_modules_del(m_user.modules);
574 	if (m_user.config) gf_cfg_del(m_user.config);
575 	gf_sys_close();
576 	/*last instance*/
577 	if (m_hMutex) {
578 		CloseHandle(m_hMutex);
579 		static_gpac_hwnd = NULL;
580 	}
581 	if (m_logs) gf_fclose(m_logs);
582 	return CWinApp::ExitInstance();
583 }
584 
585 
586 
587 /////////////////////////////////////////////////////////////////////////////
588 // Osmo4 message handlers
589 
590 
591 
592 
593 
594 /////////////////////////////////////////////////////////////////////////////
595 // CAboutDlg dialog used for App About
596 
597 class CAboutDlg : public CDialog
598 {
599 public:
600 	CAboutDlg();
601 
602 // Dialog Data
603 	//{{AFX_DATA(CAboutDlg)
604 	enum { IDD = IDD_ABOUTBOX };
605 	//}}AFX_DATA
606 
607 	// ClassWizard generated virtual function overrides
608 	//{{AFX_VIRTUAL(CAboutDlg)
609 protected:
610 	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
611 	//}}AFX_VIRTUAL
612 
613 // Implementation
614 protected:
615 	//{{AFX_MSG(CAboutDlg)
616 	virtual BOOL OnInitDialog();
617 	afx_msg void OnGogpac();
618 	//}}AFX_MSG
619 	DECLARE_MESSAGE_MAP()
620 };
621 
CAboutDlg()622 CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
623 {
624 	//{{AFX_DATA_INIT(CAboutDlg)
625 	//}}AFX_DATA_INIT
626 }
627 
DoDataExchange(CDataExchange * pDX)628 void CAboutDlg::DoDataExchange(CDataExchange* pDX)
629 {
630 	CDialog::DoDataExchange(pDX);
631 	//{{AFX_DATA_MAP(CAboutDlg)
632 	//}}AFX_DATA_MAP
633 }
634 
BEGIN_MESSAGE_MAP(CAboutDlg,CDialog)635 BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
636 	//{{AFX_MSG_MAP(CAboutDlg)
637 	ON_BN_CLICKED(IDC_GOGPAC, OnGogpac)
638 	//}}AFX_MSG_MAP
639 END_MESSAGE_MAP()
640 
641 void Osmo4::OnAbout()
642 {
643 	CAboutDlg aboutDlg;
644 	aboutDlg.DoModal();
645 }
646 
OnInitDialog()647 BOOL CAboutDlg::OnInitDialog()
648 {
649 	CDialog::OnInitDialog();
650 	CString str = "GPAC/Osmo4 - version " GPAC_FULL_VERSION;
651 	SetWindowText(str);
652 	return TRUE;
653 }
654 
OnGogpac()655 void CAboutDlg::OnGogpac()
656 {
657 	ShellExecute(NULL, "open", "http://gpac.io", NULL, NULL, SW_SHOWNORMAL);
658 }
659 
660 /////////////////////////////////////////////////////////////////////////////
661 // Osmo4 message handlers
662 
663 
SetOptions()664 void Osmo4::SetOptions()
665 {
666 	const char *sOpt = gf_cfg_get_key(m_user.config, "General", "Loop");
667 	m_Loop = (sOpt && !stricmp(sOpt, "yes")) ? GF_TRUE : GF_FALSE;
668 	sOpt = gf_cfg_get_key(m_user.config, "General", "LookForSubtitles");
669 	m_LookForSubtitles = (sOpt && !stricmp(sOpt, "yes")) ? GF_TRUE : GF_FALSE;
670 	sOpt = gf_cfg_get_key(m_user.config, "General", "ConsoleOff");
671 	m_NoConsole = (sOpt && !stricmp(sOpt, "yes")) ? GF_TRUE : GF_FALSE;
672 	sOpt = gf_cfg_get_key(m_user.config, "General", "ViewXMT");
673 	m_ViewXMTA  = (sOpt && !stricmp(sOpt, "yes")) ? GF_TRUE : GF_FALSE;
674 	sOpt = gf_cfg_get_key(m_user.config, "General", "NoMIMETypeFetch");
675 	m_NoMimeFetch = (!sOpt || !stricmp(sOpt, "yes")) ? GF_TRUE : GF_FALSE;
676 }
677 
678 
OnOpenUrl()679 void Osmo4::OnOpenUrl()
680 {
681 	COpenUrl url;
682 	if (url.DoModal() != IDOK) return;
683 
684 	CMainFrame *pFrame = (CMainFrame *) m_pMainWnd;
685 	pFrame->m_pPlayList->Truncate();
686 	pFrame->m_pPlayList->QueueURL(url.m_url);
687 	pFrame->m_pPlayList->RefreshList();
688 	pFrame->m_pPlayList->PlayNext();
689 }
690 
691 
GetFileFilter()692 CString Osmo4::GetFileFilter()
693 {
694 	u32 keyCount, i;
695 	CString sFiles;
696 	CString sExts;
697 	CString supportedFiles;
698 
699 	/*force MP4 and 3GP files at beginning to make sure they are selected (Win32 bug with too large filters)*/
700 	supportedFiles = "All Known Files|*.m3u;*.pls;*.mp4;*.3gp;*.3g2";
701 
702 	sExts = "";
703 	sFiles = "";
704 	keyCount = gf_cfg_get_key_count(m_user.config, "MimeTypes");
705 	for (i=0; i<keyCount; i++) {
706 		const char *sMime;
707 		Bool first;
708 		char *sKey;
709 		const char *opt;
710 		char szKeyList[1000], sDesc[1000];
711 		sMime = gf_cfg_get_key_name(m_user.config, "MimeTypes", i);
712 		if (!sMime) continue;
713 		CString sOpt;
714 		opt = gf_cfg_get_key(m_user.config, "MimeTypes", sMime);
715 		/*remove module name*/
716 		strcpy(szKeyList, opt+1);
717 		sKey = strrchr(szKeyList, '\"');
718 		if (!sKey) continue;
719 		sKey[0] = 0;
720 		/*get description*/
721 		sKey = strrchr(szKeyList, '\"');
722 		if (!sKey) continue;
723 		strcpy(sDesc, sKey+1);
724 		sKey[0] = 0;
725 		sKey = strrchr(szKeyList, '\"');
726 		if (!sKey) continue;
727 		sKey[0] = 0;
728 
729 		/*if same description for # mime types skip (means an old mime syntax)*/
730 		if (sFiles.Find(sDesc)>=0) continue;
731 		/*if same extensions for # mime types skip (don't polluate the file list)*/
732 		if (sExts.Find(szKeyList)>=0) continue;
733 
734 		sExts += szKeyList;
735 		sExts += " ";
736 		sFiles += sDesc;
737 		sFiles += "|";
738 
739 		first = GF_TRUE;
740 
741 		sOpt = CString(szKeyList);
742 		while (1) {
743 
744 			int pos = sOpt.Find(' ');
745 			CString ext = (pos==-1) ? sOpt : sOpt.Left(pos);
746 			/*WATCHOUT: we do have some "double" ext , eg .wrl.gz - these are NOT supported by windows*/
747 			if (ext.Find(".")<0) {
748 				if (!first) {
749 					sFiles += ";";
750 				} else {
751 					first = GF_FALSE;
752 				}
753 				sFiles += "*.";
754 				sFiles += ext;
755 
756 				CString sext = ext;
757 				sext += ";";
758 				if (supportedFiles.Find(sext)<0) {
759 					supportedFiles += ";*.";
760 					supportedFiles += ext;
761 				}
762 			}
763 
764 			if (sOpt==ext) break;
765 			CString rem;
766 			rem.Format("%s ", (LPCTSTR) ext);
767 			sOpt.Replace((LPCTSTR) rem, "");
768 		}
769 		sFiles += "|";
770 	}
771 	supportedFiles += "|";
772 	supportedFiles += sFiles;
773 	supportedFiles += "M3U Playlists|*.m3u|ShoutCast Playlists|*.pls|All Files |*.*|";
774 	return supportedFiles;
775 }
776 
OnOpenFile()777 void Osmo4::OnOpenFile()
778 {
779 	CString sFiles = GetFileFilter();
780 	u32 nb_items;
781 
782 	/*looks like there's a bug here, main filter isn't used correctly while the others are*/
783 	CFileDialog fd(TRUE,NULL,NULL, OFN_ALLOWMULTISELECT | OFN_HIDEREADONLY | OFN_FILEMUSTEXIST , sFiles);
784 	fd.m_ofn.nMaxFile = 25000;
785 	fd.m_ofn.lpstrFile = (char *) gf_malloc(sizeof(char) * fd.m_ofn.nMaxFile);
786 	fd.m_ofn.lpstrFile[0] = 0;
787 
788 	if (fd.DoModal()!=IDOK) {
789 		gf_free(fd.m_ofn.lpstrFile);
790 		return;
791 	}
792 
793 	CMainFrame *pFrame = (CMainFrame *) m_pMainWnd;
794 
795 	nb_items = 0;
796 	POSITION pos = fd.GetStartPosition();
797 	while (pos) {
798 		CString file = fd.GetNextPathName(pos);
799 		nb_items++;
800 	}
801 	/*if several items, act as playlist (replace playlist), otherwise as browser (lost all "next" context)*/
802 	if (nb_items==1)
803 		pFrame->m_pPlayList->Truncate();
804 	else
805 		pFrame->m_pPlayList->Clear();
806 
807 	pos = fd.GetStartPosition();
808 	while (pos) {
809 		CString file = fd.GetNextPathName(pos);
810 		pFrame->m_pPlayList->QueueURL(file);
811 	}
812 	gf_free(fd.m_ofn.lpstrFile);
813 	pFrame->m_pPlayList->RefreshList();
814 	pFrame->m_pPlayList->PlayNext();
815 }
816 
817 
Pause()818 void Osmo4::Pause()
819 {
820 	if (!m_isopen) return;
821 	gf_term_set_option(m_term, GF_OPT_PLAY_STATE, (gf_term_get_option(m_term, GF_OPT_PLAY_STATE)==GF_STATE_PLAYING) ? GF_STATE_PAUSED : GF_STATE_PLAYING);
822 }
823 
OnMainPause()824 void Osmo4::OnMainPause()
825 {
826 	Pause();
827 }
828 
OnFileStep()829 void Osmo4::OnFileStep()
830 {
831 	gf_term_set_option(m_term, GF_OPT_PLAY_STATE, GF_STATE_STEP_PAUSE);
832 	((CMainFrame *) m_pMainWnd)->m_wndToolBar.SetButtonInfo(5, ID_FILE_PLAY, TBBS_BUTTON, 3);
833 }
OnUpdateFileStep(CCmdUI * pCmdUI)834 void Osmo4::OnUpdateFileStep(CCmdUI* pCmdUI)
835 {
836 	pCmdUI->Enable(m_isopen && !m_reset);
837 }
838 
PlayFromTime(u32 time)839 void Osmo4::PlayFromTime(u32 time)
840 {
841 	Bool do_pause;
842 	if (start_mode==1) do_pause = GF_TRUE;
843 	else if (start_mode==2) do_pause = GF_FALSE;
844 	else do_pause = /*!m_AutoPlay*/GF_FALSE;
845 	gf_term_play_from_time(m_term, time, do_pause);
846 	m_reset = GF_FALSE;
847 }
848 
849 
OnFileReload()850 void Osmo4::OnFileReload()
851 {
852 	gf_term_disconnect(m_term);
853 	m_pMainWnd->PostMessage(WM_OPENURL);
854 }
855 
OnFileMigrate()856 void Osmo4::OnFileMigrate()
857 {
858 }
859 
OnConfigReload()860 void Osmo4::OnConfigReload()
861 {
862 	gf_term_set_option(m_term, GF_OPT_RELOAD_CONFIG, 1);
863 }
864 
UpdatePlayButton(Bool force_play)865 void Osmo4::UpdatePlayButton(Bool force_play)
866 {
867 	if (!force_play && gf_term_get_option(m_term, GF_OPT_PLAY_STATE)==GF_STATE_PLAYING) {
868 		((CMainFrame *) m_pMainWnd)->m_wndToolBar.SetButtonInfo(5, ID_FILE_PLAY, TBBS_BUTTON, 4);
869 	} else {
870 		((CMainFrame *) m_pMainWnd)->m_wndToolBar.SetButtonInfo(5, ID_FILE_PLAY, TBBS_BUTTON, 3);
871 	}
872 }
873 
OnFilePlay()874 void Osmo4::OnFilePlay()
875 {
876 	if (m_isopen) {
877 		if (m_reset) {
878 			m_reset = GF_FALSE;
879 			PlayFromTime(0);
880 			((CMainFrame *)m_pMainWnd)->SetProgTimer(GF_TRUE);
881 		} else {
882 			Pause();
883 		}
884 		UpdatePlayButton();
885 	} else {
886 		((CMainFrame *) m_pMainWnd)->m_pPlayList->Play();
887 	}
888 }
889 
OnUpdateFilePlay(CCmdUI * pCmdUI)890 void Osmo4::OnUpdateFilePlay(CCmdUI* pCmdUI)
891 {
892 	if (m_isopen) {
893 		pCmdUI->Enable(TRUE);
894 		if (pCmdUI->m_nID==ID_FILE_PLAY) {
895 			if (!m_isopen) {
896 				pCmdUI->SetText("Play/Pause\tCtrl+P");
897 			} else if (gf_term_get_option(m_term, GF_OPT_PLAY_STATE)==GF_STATE_PLAYING) {
898 				pCmdUI->SetText("Pause\tCtrl+P");
899 			} else {
900 				pCmdUI->SetText("Resume\tCtrl+P");
901 			}
902 		}
903 	} else {
904 		pCmdUI->Enable(((CMainFrame *)m_pMainWnd)->m_pPlayList->HasValidEntries() );
905 		pCmdUI->SetText("Play\tCtrl+P");
906 	}
907 }
908 
OnFileStop()909 void Osmo4::OnFileStop()
910 {
911 	CMainFrame *pFrame = (CMainFrame *) m_pMainWnd;
912 	if (m_reset) return;
913 	if (gf_term_get_option(m_term, GF_OPT_PLAY_STATE)==GF_STATE_PLAYING) Pause();
914 	m_reset = GF_TRUE;
915 	pFrame->m_Sliders.m_PosSlider.SetPos(0);
916 	pFrame->SetProgTimer(GF_FALSE);
917 	pFrame->m_wndToolBar.SetButtonInfo(5, ID_FILE_PLAY, TBBS_BUTTON, 3);
918 	start_mode = 2;
919 }
920 
OnUpdateFileStop(CCmdUI * pCmdUI)921 void Osmo4::OnUpdateFileStop(CCmdUI* pCmdUI)
922 {
923 //	pCmdUI->Enable(m_isopen);
924 }
925 
OnSwitchRender()926 void Osmo4::OnSwitchRender()
927 {
928 	const char *opt = gf_cfg_get_key(m_user.config, "Compositor", "OpenGLMode");
929 	Bool use_gl = (opt && !stricmp(opt, "always")) ? GF_TRUE : GF_FALSE;
930 	gf_cfg_set_key(m_user.config, "Compositor", "OpenGLMode", use_gl ? "disable" : "always");
931 
932 	gf_term_set_option(m_term, GF_OPT_USE_OPENGL, !use_gl);
933 
934 	UpdateRenderSwitch();
935 }
936 
UpdateRenderSwitch()937 void Osmo4::UpdateRenderSwitch()
938 {
939 	const char *opt = gf_cfg_get_key(m_user.config, "Compositor", "OpenGLMode");
940 	if (opt && !stricmp(opt, "disable"))
941 		((CMainFrame *) m_pMainWnd)->m_wndToolBar.SetButtonInfo(12, ID_SWITCH_RENDER, TBBS_BUTTON, 10);
942 	else
943 		((CMainFrame *) m_pMainWnd)->m_wndToolBar.SetButtonInfo(12, ID_SWITCH_RENDER, TBBS_BUTTON, 9);
944 }
945