player.c
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:109k
源码类别:

Windows CE

开发平台:

C/C++

  1. /*****************************************************************************
  2.  *
  3.  * This program is free software ; you can redistribute it and/or modify
  4.  * it under the terms of the GNU General Public License as published by
  5.  * the Free Software Foundation; either version 2 of the License, or
  6.  * (at your option) any later version.
  7.  *
  8.  * This program is distributed in the hope that it will be useful,
  9.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11.  * GNU General Public License for more details.
  12.  *
  13.  * You should have received a copy of the GNU General Public License
  14.  * along with this program; if not, write to the Free Software
  15.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  16.  *
  17.  * $Id: player.c 623 2006-02-01 13:19:15Z picard $
  18.  *
  19.  * The Core Pocket Media Player
  20.  * Copyright (c) 2004-2005 Gabor Kovacs
  21.  *
  22.  ****************************************************************************/
  23. #include "common.h"
  24. #include "playlist/m3u.h"
  25. #include "../config.h"
  26. #define VIDEO_STREAMING_UNDERRUN (256*1024)/BLOCKSIZE
  27. #define ALIGN_SIZE 4096
  28. #define PROBE_SIZE ALIGN_SIZE
  29. #define MAXSKIP 16
  30. typedef struct ref
  31. {
  32. node* Node;
  33. int RefCount;
  34. } ref;
  35. typedef struct item
  36. {
  37. tchar_t URL[MAXPATH];
  38. tchar_t Title[256];
  39. tick_t Length;
  40. bool_t Changed;
  41. } item;
  42. typedef struct player_base
  43. {
  44. player Player;
  45. bool_t BufferWarning;
  46. int BufferSize2; //in blocksize
  47. int MDBufferSize2; //in blocksize
  48. int CurrBufferSize2; //in blocksize
  49. bool_t SoftVolume;
  50. bool_t Background;
  51. bool_t Foreground;
  52. bool_t PowerOff;
  53. bool_t PowerOffReSync;
  54. bool_t FlowBackground;
  55. bool_t MicroDrive;
  56. bool_t Repeat;
  57. bool_t Shuffle;
  58. bool_t PlayAtOpen;
  59. bool_t PlayAtOpenFull;
  60. bool_t ExitAtEnd;
  61. bool_t KeepPlayVideo;
  62. bool_t KeepPlayAudio;
  63. bool_t ShowInBackground;
  64. bool_t SingleClickFullScreen;
  65. bool_t KeepList;
  66. tick_t MoveBack;
  67. tick_t MoveFFwd;
  68. int BurstStart; // in blocksize
  69. int UnderRun; // percent
  70. int AudioUnderRun; //kbyte
  71. fraction FullZoom;
  72. fraction SkinZoom;
  73. fraction Aspect;
  74. int FullDir;
  75. int SkinDir;
  76. int RelDir;
  77. bool_t SmoothZoom50;
  78. bool_t SmoothZoomAlways;
  79. bool_t VideoAccel;
  80. bool_t AutoPreRotate;
  81. int SkipAccelFrom;
  82. int AudioQuality;
  83. int VideoQuality;
  84. int AOutputId;
  85. int VOutputId;
  86. int AOutputIdMax;
  87. int VOutputIdMax;
  88. fraction SeekAfterSync;
  89. bool_t SeekAfterSyncPrevKey;
  90. fraction InSeekPos;
  91. fraction PlaySpeed;
  92. fraction FFwdSpeed;
  93. int Volume;
  94. int Pan;
  95. int PreAmp;
  96. bool_t Mute;
  97. bool_t TimerLeft;
  98. node* Color;
  99. node* Equalizer;
  100. bool_t Eq;
  101. // states
  102. notify ListNotify;
  103. notify Notify;
  104. rect SkinViewport;
  105. void* Wnd;
  106. bool_t DiscardList;
  107. bool_t FullScreen;
  108. bool_t Clipping;
  109. bool_t Rotating;
  110. rect Viewport;
  111. bool_t Primary;
  112. bool_t Overlay;
  113. bool_t HasHost;
  114. bool_t Streaming; // HasHost and filesize==-1
  115. bool_t Timing;
  116. bool_t TemporaryHidden; // hidden till next sync
  117. bool_t FullScreenAfterSync;
  118. int Stereo;
  119. int StreamNo;
  120. // current media
  121. bool_t PreRotate;
  122. int BufferMax;
  123. stream* Input;
  124. stream* InputBase;
  125. node* Timer;
  126. node* AOutput;
  127. node* VOutput;
  128. node* VIDCT;
  129. node* FlowBuffer;
  130. format* Format;
  131. int Selected[PACKET_MAX]; // stream numbers
  132. // threads and timings
  133. bool_t NoMoreInput;
  134. bool_t Play;
  135. bool_t FFwd;
  136. bool_t Sync;
  137. bool_t Fill;
  138. bool_t LoadMode;
  139. bool_t Bench;
  140. bool_t SaveMicroDrive;
  141. bool_t WaitForProcess;
  142. bool_t TimerPlay;
  143. bool_t InSeek;
  144. bool_t UpdateStreamsNeeded;
  145. tick_t Position;
  146. tick_t PosNotify;
  147. fraction Speed;
  148. tick_t PosNotifyStep;
  149. tick_t BenchTime;
  150. point BenchSrc;
  151. point BenchDst;
  152. int BenchStart;
  153. int IOError;
  154. int UsedEnough2; //in blocksize
  155. int MinBuffer; //in blocksize
  156. uint32_t RndSeed;
  157. bool_t RunInput;
  158. bool_t RunProcess;
  159. #ifdef MULTITHREAD
  160. int ProcessPriority;
  161. int InputPriority;
  162. int LockInputCount; // just hint to sleep in input thread so other other thread can lock it
  163. int LockProcessCount; // just hint to sleep in process thread so other other thread can lock it
  164. void* Lock;  // parameter read/write
  165. void* LockComment;
  166. void* LockInput;
  167. void* LockProcess;
  168. void* EventProcess; // ProcessThread has processed some packets (InputThread can continue)
  169. void* EventRunInput;
  170. void* EventRunProcess; 
  171. void* ProcessThread;
  172. void* InputThread;
  173. int ProcessLocked;
  174. int InputLocked;
  175. #endif
  176. // playlist
  177. int Current;
  178. bool_t CurrentChanged;
  179. int PlayListCount;
  180. item* PlayList;
  181. int* PlayIndex;
  182. // paint
  183. rgbval_t ColorKey; // colorkeybursh color
  184. void* ColorKeyBrush;
  185. void* BlackBrush;
  186. array Ref; // ref
  187. array Comment; // [Stream,Name,0,Value,0]
  188. bool_t StreamSkip[MAXSTREAM];
  189. tchar_t Title[256];
  190. tchar_t CurrentDir[MAXPATH];
  191. int CodecSkipCount;
  192. int CodecSkip[MAXSKIP];
  193. } player_base;
  194. static const datatable PlayerParams[] = 
  195. {
  196. { PLAYER_AUTOPREROTATE, TYPE_BOOL, DF_SETUP },
  197. { PLAYER_REPEAT, TYPE_BOOL, DF_SETUP|DF_HIDDEN },
  198. { PLAYER_SHUFFLE, TYPE_BOOL, DF_SETUP|DF_HIDDEN },
  199. { PLAYER_KEEPPLAY_AUDIO,TYPE_BOOL, DF_SETUP },
  200. { PLAYER_KEEPPLAY_VIDEO,TYPE_BOOL, DF_SETUP },
  201. { PLAYER_SHOWINBACKGROUND,TYPE_BOOL, DF_SETUP },
  202. { PLAYER_SINGLECLICKFULLSCREEN, TYPE_BOOL, DF_SETUP },
  203. { PLAYER_KEEPLIST, TYPE_BOOL, DF_SETUP },
  204. { PLAYER_PLAYATOPEN, TYPE_BOOL, DF_SETUP },
  205. { PLAYER_PLAYATOPEN_FULL,TYPE_BOOL, DF_SETUP },
  206. { PLAYER_EXIT_AT_END, TYPE_BOOL, DF_SETUP },
  207. { PLAYER_FULL_ZOOM, TYPE_FRACTION, DF_SETUP|DF_PERCENT|DF_HIDDEN },
  208. { PLAYER_SKIN_ZOOM, TYPE_FRACTION, DF_SETUP|DF_PERCENT|DF_HIDDEN },
  209. { PLAYER_PLAY_SPEED, TYPE_FRACTION, DF_SETUP|DF_PERCENT|DF_GAP },
  210. { PLAYER_FFWD_SPEED, TYPE_FRACTION, DF_SETUP|DF_PERCENT },
  211. { PLAYER_MOVEFFWD_STEP, TYPE_TICK, DF_SETUP|DF_MINMAX, 0, 600*TICKSPERSEC },
  212. { PLAYER_MOVEBACK_STEP, TYPE_TICK, DF_SETUP|DF_MINMAX, 0, 600*TICKSPERSEC },
  213. { PLAYER_BUFFER_SIZE, TYPE_INT, DF_SETUP|DF_KBYTE|DF_GAP|DF_HIDDEN, 512, 128*1024 },
  214. { PLAYER_UNDERRUN, TYPE_INT, DF_SETUP|DF_PERCENT|DF_HIDDEN,0,PERCENT_ONE },
  215. { PLAYER_AUDIO_UNDERRUN,TYPE_INT, DF_SETUP|DF_KBYTE|DF_HIDDEN,32,128*1024 },
  216. { PLAYER_MICRODRIVE, TYPE_BOOL, DF_SETUP|DF_GAP|DF_HIDDEN },
  217. { PLAYER_MD_BUFFER_SIZE,TYPE_INT, DF_SETUP|DF_KBYTE|DF_HIDDEN, 512, 128*1024 },
  218. { PLAYER_BURSTSTART, TYPE_INT, DF_SETUP|DF_KBYTE|DF_HIDDEN, 512, 128*1024 },
  219. { PLAYER_AOUTPUTID, TYPE_INT, DF_SETUP|DF_HIDDEN },
  220. { PLAYER_AOUTPUTID_MAX, TYPE_INT, DF_SETUP|DF_HIDDEN }, // should be after PLAYER_AOUTPUTID
  221. { PLAYER_VOUTPUTID, TYPE_INT, DF_SETUP|DF_HIDDEN },
  222. { PLAYER_VOUTPUTID_MAX, TYPE_INT, DF_SETUP|DF_HIDDEN }, // should be after PLAYER_VOUTPUTID
  223. { PLAYER_VIDEO_ACCEL, TYPE_BOOL, DF_SETUP|DF_HIDDEN },
  224. { PLAYER_LIST_COUNT, TYPE_INT, DF_SETUP|DF_HIDDEN },
  225. { PLAYER_LIST_CURRENT, TYPE_INT, DF_SETUP|DF_HIDDEN },
  226. { PLAYER_LIST_CURRIDX, TYPE_INT, DF_HIDDEN },
  227. { PLAYER_SMOOTH50, TYPE_BOOL, DF_SETUP|DF_HIDDEN },
  228. { PLAYER_SMOOTHALWAYS, TYPE_BOOL, DF_SETUP|DF_HIDDEN },
  229. { PLAYER_STEREO, TYPE_INT,  DF_SETUP|DF_HIDDEN },
  230. { PLAYER_ASPECT, TYPE_FRACTION, DF_SETUP|DF_HIDDEN },
  231. { PLAYER_FULL_DIR, TYPE_INT, DF_SETUP|DF_HIDDEN },
  232. { PLAYER_SKIN_DIR, TYPE_INT, DF_SETUP|DF_HIDDEN },
  233. { PLAYER_AUDIO_QUALITY, TYPE_INT, DF_SETUP|DF_ENUMSTRING|DF_HIDDEN, PLAYERQUALITY_ENUM },
  234. { PLAYER_VIDEO_QUALITY, TYPE_INT, DF_SETUP|DF_ENUMSTRING|DF_HIDDEN, PLAYERQUALITY_ENUM },
  235. { PLAYER_ASTREAM, TYPE_INT, DF_HIDDEN|DF_SETUP },
  236. { PLAYER_VSTREAM, TYPE_INT, DF_HIDDEN|DF_SETUP },
  237. { PLAYER_SUBSTREAM, TYPE_INT, DF_HIDDEN|DF_SETUP },
  238. { PLAYER_PERCENT, TYPE_FRACTION, DF_HIDDEN|DF_SETUP },
  239. { PLAYER_VOLUME, TYPE_INT, DF_MINMAX|DF_HIDDEN|DF_SETUP, 0, 100 },
  240. { PLAYER_PAN, TYPE_INT, DF_MINMAX|DF_HIDDEN|DF_SETUP, -100, 100 },
  241. { PLAYER_PREAMP, TYPE_INT, DF_MINMAX|DF_HIDDEN|DF_SETUP, -100, 100 },
  242. { PLAYER_MUTE, TYPE_BOOL, DF_HIDDEN|DF_SETUP },
  243. { PLAYER_TIMER_LEFT, TYPE_BOOL, DF_HIDDEN|DF_SETUP },
  244. { PLAYER_BACKGROUND, TYPE_BOOL, DF_HIDDEN },
  245. { PLAYER_FOREGROUND, TYPE_BOOL, DF_HIDDEN },
  246. { PLAYER_PLAY, TYPE_BOOL, DF_HIDDEN },
  247. { PLAYER_FFWD, TYPE_BOOL, DF_HIDDEN },
  248. { PLAYER_POSITION, TYPE_TICK, DF_HIDDEN },
  249. { PLAYER_DURATION, TYPE_TICK, DF_HIDDEN },
  250. { PLAYER_TIMER, TYPE_STRING, DF_HIDDEN },
  251. { PLAYER_TITLE, TYPE_STRING },
  252. { PLAYER_INPUT, TYPE_NODE, DF_HIDDEN, STREAM_CLASS },
  253. { PLAYER_FORMAT, TYPE_NODE, DF_HIDDEN, FORMAT_CLASS },
  254. { PLAYER_AOUTPUT, TYPE_NODE, DF_HIDDEN, AOUT_CLASS },
  255. { PLAYER_VOUTPUT, TYPE_NODE, DF_HIDDEN, VOUT_CLASS },
  256. { PLAYER_SKIN_VIEWPORT, TYPE_RECT, DF_HIDDEN },
  257. { PLAYER_CLIPPING, TYPE_BOOL, DF_HIDDEN },
  258. { PLAYER_FULLSCREEN, TYPE_BOOL, DF_HIDDEN },
  259. { PLAYER_LOADMODE, TYPE_BOOL, DF_HIDDEN | DF_RDONLY },
  260. { PLAYER_CURRENTDIR, TYPE_STRING, DF_SETUP|DF_HIDDEN },
  261. DATATABLE_END(PLAYER_ID)
  262. };
  263. static const datatable BufferParams[] = 
  264. {
  265. { PLAYER_BUFFER_SIZE, TYPE_INT, DF_SETUP|DF_KBYTE|DF_GAP, 512, 128*1024 },
  266. { PLAYER_UNDERRUN, TYPE_INT, DF_SETUP|DF_PERCENT,0,PERCENT_ONE },
  267. { PLAYER_AUDIO_UNDERRUN,TYPE_INT, DF_SETUP|DF_KBYTE,32,128*1024 },
  268. { PLAYER_MICRODRIVE, TYPE_BOOL, DF_SETUP|DF_GAP },
  269. { PLAYER_MD_BUFFER_SIZE,TYPE_INT, DF_SETUP|DF_KBYTE, 512, 128*1024 },
  270. { PLAYER_BURSTSTART, TYPE_INT, DF_SETUP|DF_KBYTE, 512, 128*1024 },
  271. DATATABLE_END(PLAYER_BUFFER_ID)
  272. };
  273. static int Enum(player_base* p, int* No, datadef* Param)
  274. {
  275. if (NodeEnumTable(No,Param,PlayerParams) == ERR_NONE)
  276. return ERR_NONE;
  277. if (*No<p->PlayListCount*3)
  278. {
  279. memset(Param,0,sizeof(datadef));
  280. if (*No >= 2*p->PlayListCount)
  281. {
  282. Param->No = PLAYER_LIST_LENGTH + (*No - 2*p->PlayListCount);
  283. Param->Type = TYPE_TICK;
  284. Param->Size = sizeof(tick_t);
  285. }
  286. else
  287. {
  288. if (*No >= p->PlayListCount)
  289. Param->No = PLAYER_LIST_TITLE + (*No - p->PlayListCount);
  290. else
  291. Param->No = PLAYER_LIST_URL + *No;
  292. Param->Type = TYPE_STRING;
  293. Param->Size = MAXDATA;
  294. }
  295. Param->Flags = DF_HIDDEN | DF_SETUP;
  296. Param->Class = PLAYER_ID;
  297. return ERR_NONE;
  298. }
  299. *No -= p->PlayListCount*3;
  300. return ERR_INVALID_PARAM;
  301. }
  302. static NOINLINE int UpdateSpeed(player_base* p)
  303. {
  304. if (p->Bench)
  305. {
  306. p->Speed.Num = 0;
  307. p->Speed.Den = 1;
  308. }
  309. else
  310. if (p->FFwd)
  311. p->Speed = p->FFwdSpeed;
  312. else
  313. p->Speed = p->PlaySpeed;
  314. p->PosNotifyStep = Scale(TICKSPERSEC,p->Speed.Num,p->Speed.Den);
  315. if (p->Timer)
  316. p->Timer->Set(p->Timer,TIMER_SPEED,&p->Speed,sizeof(p->Speed));
  317. return ERR_NONE;
  318. }
  319. static NOINLINE void NotifyList(player_base* p)
  320. {
  321. if (p->ListNotify.Func)
  322. p->ListNotify.Func(p->ListNotify.This,0,0);
  323. }
  324. static NOINLINE void Notify(player_base* p,int Id,int Value)
  325. {
  326. if (p->Notify.Func)
  327. p->Notify.Func(p->Notify.This,Id,Value);
  328. }
  329. static NOINLINE void UpdateListLength(player_base* p,tick_t Length)
  330. {
  331. if (p->Current < p->PlayListCount && !p->PlayList[p->Current].Changed && 
  332. p->PlayList[p->Current].Length != Length)
  333. {
  334. p->PlayList[p->Current].Length = Length;
  335. NotifyList(p);
  336. }
  337. }
  338. #define INVALID_COMMENT -2
  339. static INLINE int CommentStream(const uint8_t* p) { return *(tchar_t*)p; }
  340. static INLINE const tchar_t* CommentName(const uint8_t* p) { return (const tchar_t*)(p+sizeof(tchar_t)); }
  341. static INLINE const tchar_t* CommentValue(const uint8_t* p) { const tchar_t* i = CommentName(p); return i+tcslen(i)+1; }
  342. static const uint8_t* CommentNext(const uint8_t* p) { const tchar_t* i = CommentValue(p); return (const uint8_t*)(i+tcslen(i)+1); }
  343. static const tchar_t* GetFirstComment(player_base* p, int Id)
  344. {
  345. const uint8_t *i;
  346. const tchar_t* Name = PlayerComment(Id);
  347. for (i=ARRAYBEGIN(p->Comment,uint8_t);i!=ARRAYEND(p->Comment,uint8_t);i=CommentNext(i))
  348. if (CommentStream(i)!=INVALID_COMMENT && tcsicmp(CommentName(i),Name)==0)
  349. return CommentValue(i);
  350. return T("");
  351. }
  352. static void UpdateListTitle(player_base* p)
  353. {
  354. const tchar_t* Title;
  355. const tchar_t* Artist;
  356. LockEnter(p->LockComment);
  357. Title = GetFirstComment(p,COMMENT_TITLE);
  358. Artist = GetFirstComment(p,COMMENT_ARTIST);
  359. if (!Artist[0])
  360. Artist = GetFirstComment(p,COMMENT_AUTHOR);
  361. if (Artist[0] && Title[0])
  362. stprintf_s(p->Title,TSIZEOF(p->Title),T("%s - %s"),Artist,Title);
  363. else
  364. {
  365. if (!Title[0])
  366. Title = Artist;
  367. tcscpy_s(p->Title,TSIZEOF(p->Title),Title);
  368. }
  369. LockLeave(p->LockComment);
  370. Notify(p,PLAYER_TITLE,0);
  371. if (p->Current < p->PlayListCount && !p->PlayList[p->Current].Changed)
  372. {
  373. tcscpy_s(p->PlayList[p->Current].Title,TSIZEOF(p->PlayList[p->Current].Title),p->Title);
  374. NotifyList(p);
  375. }
  376. }
  377. static NOINLINE bool_t IsCoverArt(player_base* p)
  378. {
  379. int CoverArt = -2;
  380. if (p->Format)
  381. p->Format->Get(p->Format,FORMAT_COVERART,&CoverArt,sizeof(CoverArt));
  382. return CoverArt==p->Selected[PACKET_VIDEO];
  383. }
  384. static NOINLINE bool_t IsVideo(player_base* p)
  385. {
  386. return p->VOutput && !IsCoverArt(p);
  387. }
  388. static NOINLINE void UpdateTimeouts(player_base* p)
  389. {
  390. bool_t KeepProcess = (p->Play || p->FFwd) && p->Format;
  391. if (!KeepProcess || !p->Sync) // VOutput not neccessary updated till first sync is over
  392. SleepTimeout(KeepProcess,p->Bench || (p->Primary && IsVideo(p)));
  393. }
  394. static NOINLINE void UpdateRunInput(player_base* p)
  395. {
  396. // we don't want deadlocks so LoadMode will restart InputThread even with NoMoreInput
  397. p->RunInput = p->Format && p->Input && (!p->NoMoreInput || p->LoadMode);
  398. #ifdef MULTITHREAD
  399. if (p->RunInput)
  400. EventSet(p->EventRunInput);
  401. else
  402. EventReset(p->EventRunInput);
  403. #endif
  404. }
  405. static NOINLINE void UpdateRunProcess(player_base* p)
  406. {
  407. p->RunProcess = p->Format && p->Input && p->Timer && (((p->FFwd || p->Play) && !p->LoadMode) || p->Sync || p->Fill);
  408. #ifdef MULTITHREAD
  409. if (p->RunProcess)
  410. EventSet(p->EventRunProcess);
  411. else
  412. EventReset(p->EventRunProcess);
  413. #endif
  414. }
  415. static NOINLINE void UpdatePriority(player_base* p)
  416. {
  417. #ifdef MULTITHREAD
  418. if (p->InputThread && p->ProcessThread)
  419. {
  420. int Priority;
  421. Priority = (!p->TimerPlay || !QueryAdvanced(ADVANCED_PRIORITY))?0:1;
  422. if (p->ProcessPriority != Priority)
  423. {
  424. p->ProcessPriority = Priority;
  425. ThreadPriority(p->ProcessThread,Priority);
  426. }
  427. Priority = (((p->Play || p->FFwd) && !p->Sync) || p->LoadMode)?0:1;
  428. if (p->InputPriority != Priority)
  429. {
  430. p->InputPriority = Priority;
  431. ThreadPriority(p->InputThread,Priority);
  432. }
  433. }
  434. #endif
  435. }
  436. static NOINLINE void UpdatePlay(player_base* p)
  437. {
  438. p->TimerPlay = (p->Play || p->FFwd) && !p->InSeek && !p->Sync && !p->Fill && !p->LoadMode;
  439. UpdatePriority(p);
  440. p->Timer->Set(p->Timer,TIMER_PLAY,&p->TimerPlay,sizeof(bool_t));
  441. if (p->VOutput)
  442. p->VOutput->Set(p->VOutput,VOUT_PLAY,&p->TimerPlay,sizeof(bool_t));
  443. }
  444. static int CmpRef(const ref* a, const ref* b)
  445. {
  446. if (a->Node > b->Node) return 1;
  447. if (a->Node < b->Node) return -1;
  448. return 0;
  449. }
  450. static void Unlock(player_base* p, bool_t Input);
  451. static void Lock(player_base* p, bool_t Input);
  452. static NOINLINE bool_t Used(player_base* p,node* Node)
  453. {
  454. const ref *i;
  455. for (i=ARRAYBEGIN(p->Ref,ref);i!=ARRAYEND(p->Ref,ref);++i)
  456. if (i->Node == Node)
  457. return 1;
  458. return 0;
  459. }
  460. static NOINLINE void Flush(player_base* p)
  461. {
  462. const ref *i;
  463. node* Skip = NULL;
  464. if (IsCoverArt(p))
  465. Skip = p->FlowBuffer;
  466. for (i=ARRAYBEGIN(p->Ref,ref);i!=ARRAYEND(p->Ref,ref);++i)
  467. if (i->Node != Skip)
  468. i->Node->Set(i->Node,FLOW_FLUSH,NULL,0);
  469. if (p->FlowBuffer && p->FlowBuffer != Skip)
  470. p->FlowBuffer->Set(p->FlowBuffer,FLOW_FLUSH,NULL,0);
  471. }
  472. static NOINLINE int UpdateBackground(player_base* p)
  473. {
  474. bool_t b;
  475. #ifdef MULTITHREAD
  476. assert(p->ProcessLocked != ThreadId() && p->InputLocked != ThreadId());
  477. #endif
  478. LockEnter(p->Lock);
  479. b = p->Background && !p->ShowInBackground && !p->Play && !p->FFwd;
  480. #if !defined(TARGET_WINCE)
  481. if (p->PowerOff) b = 1;
  482. #endif
  483. if (b != p->FlowBackground)
  484. {
  485. bool_t Locked = 0;
  486. const ref *i;
  487. p->FlowBackground = b;
  488. for (i=ARRAYBEGIN(p->Ref,ref);i!=ARRAYEND(p->Ref,ref);++i)
  489. if (i->Node->Get(i->Node,FLOW_BACKGROUND,&b,sizeof(b))==ERR_NONE)
  490. {
  491. if (!Locked)
  492. {
  493. Lock(p,1);
  494. Locked = 1;
  495. }
  496. i->Node->Set(i->Node,FLOW_BACKGROUND,&p->FlowBackground,sizeof(p->FlowBackground));
  497. }
  498. if (Locked)
  499. Unlock(p,1);
  500. }
  501. LockLeave(p->Lock);
  502. return ERR_NONE;
  503. }
  504. static void ReSync(player_base* p,bool_t Seek);
  505. static int UpdateFormat(player_base* p,bool_t BufferChanged);
  506. static int SetPlay(player_base* p,bool_t Stop);
  507. static int SetPlayListCount(player_base* p, int Count);
  508. static void Paint(player_base* p,void* DC,int x0,int y0);
  509. static int UpdateVideoEx(player_base* p,node* VOutput,int ForceRefresh,bool_t Active)
  510. {
  511. int Caps;
  512. bool_t Dither;
  513. packetformat Mode;
  514. blitfx FX;
  515. bool_t FullScreen;
  516. bool_t Visible = (p->Foreground || p->ShowInBackground) && !p->Rotating && Active;
  517. bool_t Refresh;
  518. bool_t Updating;
  519. bool_t VOutVisible;
  520. bool_t Primary;
  521. bool_t Overlay;
  522. rect Viewport;
  523. int RelDir;
  524. if (VOutput)
  525. {
  526. VOutput->Get(VOutput,VOUT_PRIMARY,&Primary,sizeof(bool_t));
  527. Viewport = p->SkinViewport;
  528. FullScreen = p->FullScreen || !Primary;
  529. if (FullScreen && VOutput->Get(VOutput,OUT_OUTPUT|PIN_FORMAT,&Mode,sizeof(Mode))==ERR_NONE && Mode.Type == PACKET_VIDEO)
  530. PhyToVirt(NULL,&Viewport,&Mode.Format.Video);
  531. FX.Flags = 0;
  532. if (p->SmoothZoom50)
  533. FX.Flags |= BLITFX_ARITHSTRETCH50;
  534. if (p->SmoothZoomAlways)
  535. FX.Flags |= BLITFX_ARITHSTRETCHALWAYS;
  536. if (QueryAdvanced(ADVANCED_SLOW_VIDEO))
  537. FX.Flags |= BLITFX_ONLYDIFF;
  538. if (QueryAdvanced(ADVANCED_COLOR_LOOKUP))
  539. FX.Flags |= BLITFX_COLOR_LOOKUP;
  540. p->Color->Get(p->Color,COLOR_DITHER,&Dither,sizeof(Dither));
  541. if (Dither)
  542. FX.Flags |= BLITFX_DITHER;
  543. p->Color->Get(p->Color,COLOR_BRIGHTNESS,&FX.Brightness,sizeof(FX.Brightness));
  544. p->Color->Get(p->Color,COLOR_CONTRAST,&FX.Contrast,sizeof(FX.Contrast));
  545. p->Color->Get(p->Color,COLOR_SATURATION,&FX.Saturation,sizeof(FX.Saturation));
  546. p->Color->Get(p->Color,COLOR_R_ADJUST,&FX.RGBAdjust[0],sizeof(FX.RGBAdjust[0]));
  547. p->Color->Get(p->Color,COLOR_G_ADJUST,&FX.RGBAdjust[1],sizeof(FX.RGBAdjust[1]));
  548. p->Color->Get(p->Color,COLOR_B_ADJUST,&FX.RGBAdjust[2],sizeof(FX.RGBAdjust[2]));
  549. if (FullScreen)
  550. {
  551. FX.Direction = p->FullDir;
  552. FX.ScaleY = FX.ScaleX = Scale(SCALE_ONE,p->FullZoom.Num,p->FullZoom.Den);
  553. }
  554. else
  555. {
  556. FX.Direction = p->SkinDir;
  557. FX.ScaleY = FX.ScaleX = Scale(SCALE_ONE,p->SkinZoom.Num,p->SkinZoom.Den);
  558. }
  559. if (FX.Direction < 0)
  560. FX.Direction = 0;
  561. else
  562. if (Primary)
  563. FX.Direction = CombineDir(GetOrientation(),0,FX.Direction);
  564. RelDir = FX.Direction;
  565. VOutVisible = Visible && !p->TemporaryHidden;
  566. Updating = 1;
  567. VOutput->Set(VOutput,VOUT_UPDATING,&Updating,sizeof(bool_t));
  568. VOutput->Set(VOutput,VOUT_FULLSCREEN,&FullScreen,sizeof(bool_t));
  569. VOutput->Set(VOutput,VOUT_VIEWPORT,&Viewport,sizeof(rect));
  570. VOutput->Set(VOutput,VOUT_FX,&FX,sizeof(blitfx));
  571. VOutput->Set(VOutput,VOUT_ASPECT,&p->Aspect,sizeof(fraction));
  572. VOutput->Set(VOutput,VOUT_CLIPPING,&p->Clipping,sizeof(p->Clipping));
  573. VOutput->Set(VOutput,VOUT_VISIBLE,&VOutVisible,sizeof(VOutVisible));
  574. VOutput->Set(VOutput,VOUT_AUTOPREROTATE,&p->AutoPreRotate,sizeof(bool_t));
  575. Updating = 0;
  576. VOutput->Set(VOutput,VOUT_UPDATING,&Updating,sizeof(bool_t));
  577. VOutput->Get(VOutput,VOUT_OVERLAY,&Overlay,sizeof(bool_t));
  578. }
  579. else
  580. {
  581. Primary = 1;
  582. Overlay = 0;
  583. RelDir = 0;
  584. Viewport = p->SkinViewport;
  585. }
  586. if (Active)
  587. {
  588. p->RelDir = RelDir;
  589. p->Primary = Primary;
  590. p->Overlay = Overlay;
  591. p->Viewport = Viewport;
  592. #ifdef TARGET_PALMOS
  593. if (!p->Clipping && Visible)
  594. Paint(p,p->Wnd,0,0);
  595. #endif
  596. // try to redraw overlay
  597. Refresh = VOutput && ForceRefresh>=0 && !p->Sync;
  598. if (Refresh && p->FlowBuffer && !ForceRefresh)
  599. Refresh = p->FlowBuffer->Set(p->FlowBuffer,FLOW_RESEND,NULL,0) != ERR_NONE;
  600. if (Refresh && p->Format)
  601. ReSync(p,0); // redraw the hard way: resync
  602. if (!p->Wnd || !VOutput || VOutput->Get(VOutput,VOUT_CAPS,&Caps,sizeof(Caps))!=ERR_NONE)
  603. Caps = -1;
  604. p->Color->Set(p->Color,COLOR_CAPS,&Caps,sizeof(Caps));
  605. }
  606. return ERR_NONE;
  607. }
  608. static NOINLINE int UpdateVideo(player_base* p,int ForceRefresh)
  609. {
  610. return UpdateVideoEx(p,p->VOutput,ForceRefresh,1);
  611. }
  612. static NOINLINE int UpdateBuffer(player_base* p)
  613. {
  614. node* Node = p->AOutput;
  615. if (Node)
  616. {
  617. bool_t b = IsVideo(p);
  618. Node->Set(Node,AOUT_MODE,&b,sizeof(b));
  619. }
  620. p->MinBuffer = 0;
  621. if (p->Format)
  622. p->Format->Get(p->Format,FORMAT_MIN_BUFFER,&p->MinBuffer,sizeof(int));
  623. return ERR_NONE;
  624. }
  625. static NOINLINE player_base* RefreshAudio(player_base* p)
  626. {
  627. node* Node = p->AOutput;
  628. if (Node && QueryAdvanced(ADVANCED_SYSTEMVOLUME))
  629. {
  630. Node->Get(Node,AOUT_VOLUME,&p->Volume,sizeof(int));
  631. Node->Get(Node,AOUT_MUTE,&p->Mute,sizeof(bool_t));
  632. Node->Get(Node,AOUT_PAN,&p->Pan,sizeof(int));
  633. }
  634. return p;
  635. }
  636. static NOINLINE int UpdateAudioEx(player_base* p,node* Node)
  637. {
  638. if (Node)
  639. {
  640. Node->Set(Node,AOUT_STEREO,&p->Stereo,sizeof(int));
  641. Node->Set(Node,AOUT_QUALITY,&p->AudioQuality,sizeof(int));
  642. Node->Set(Node,AOUT_PREAMP,&p->PreAmp,sizeof(int));
  643. Node->Set(Node,AOUT_VOLUME,&p->Volume,sizeof(int));
  644. Node->Set(Node,AOUT_MUTE,&p->Mute,sizeof(bool_t));
  645. Node->Set(Node,AOUT_PAN,&p->Pan,sizeof(int));
  646. }
  647. return ERR_NONE;
  648. }
  649. static NOINLINE int UpdateAudio(player_base* p)
  650. {
  651. return UpdateAudioEx(p,p->AOutput);
  652. }
  653. static NOINLINE int UpdateVolume(player_base* p)
  654. {
  655. if (p->AOutput)
  656. p->AOutput->Set(p->AOutput,AOUT_VOLUME,&p->Volume,sizeof(int));
  657. return ERR_NONE;
  658. }
  659. static int UpdateStreams(player_base* p,int ForceRefresh,bool_t CodecSkip);
  660. static NOINLINE int UpdatePowerOff(player_base* p)
  661. {
  662. Notify(p,PLAYER_POWEROFF,p->PowerOff); // before poweroff is handled! (PalmOS may need to turn on clipping)
  663. #ifdef TARGET_WINCE
  664. if (p->PowerOff)
  665. {
  666. bool_t b;
  667. Lock(p,0);
  668. if (p->VOutput && p->VOutput->Get(p->VOutput,FLOW_BACKGROUND,&b,sizeof(b))==ERR_NONE)
  669. {
  670. int Old = p->VOutputId;
  671. bool_t OldAccel = p->VideoAccel;
  672. p->VOutputId = 0;
  673. UpdateStreams(p,-1,0);
  674. p->VOutputId = Old;
  675. p->VideoAccel = OldAccel;
  676. p->PowerOffReSync = 1;
  677. }
  678. if (p->Play || p->FFwd)
  679. {
  680. Lock(p,1);
  681. p->Play = 0;
  682. p->FFwd = 0;
  683. p->Fill = 1;
  684. SetPlay(p,0);
  685. Unlock(p,1);
  686. }
  687. Unlock(p,0);
  688. }
  689. else
  690. {
  691. if (p->PowerOffReSync)
  692. {
  693. p->PowerOffReSync = 0;
  694. UpdateStreams(p,-1,0);
  695. ReSync(p,1);
  696. }
  697. }
  698. #else
  699. if (p->PowerOff && (p->Play || p->FFwd || p->Fill))
  700. {
  701. Lock(p,1);
  702. p->Play = 0;
  703. p->FFwd = 0;
  704. p->Fill = 0; // do not fill, because acceleration devices could be turned off
  705. SetPlay(p,0); // calls UpdateBackground
  706. Unlock(p,1);
  707. }
  708. else
  709. if (!p->PowerOff && !p->Play && !p->FFwd && !p->Fill)
  710. {
  711. Lock(p,1);
  712. p->Fill = 1; // turn on fill
  713. SetPlay(p,0); // calls UpdateBackground
  714. Unlock(p,1);
  715. }
  716. else
  717. UpdateBackground(p);
  718. #endif
  719. return ERR_NONE;
  720. }
  721. static NOINLINE int UpdateForeground(player_base* p)
  722. {
  723. if (!p->Foreground)
  724. if ((IsVideo(p) && !p->KeepPlayVideo) ||
  725. (!IsVideo(p) && !p->KeepPlayAudio))
  726. {
  727. Lock(p,1);
  728. SetPlay(p,1);
  729. Unlock(p,1);
  730. }
  731. UpdateVideo(p,0);
  732. return ERR_NONE;
  733. }
  734. static int FindCurrentIndex(player_base* p)
  735. {
  736. int Index;
  737. for (Index=0;Index<p->PlayListCount;++Index)
  738. if (p->PlayIndex[Index] == p->Current)
  739. return Index;
  740. return 0;
  741. }
  742. static uint32_t Rand(player_base* p)
  743. p->RndSeed = p->RndSeed*0x8088405U + 0x251001U;
  744. return p->RndSeed;
  745. }
  746. static int RandomizePlayIndex(player_base* p,bool_t CurrentAsFirst)
  747. {
  748. int No,n;
  749. int* Index = p->PlayIndex;
  750. for (No=0;No<p->PlayListCount;++No)
  751. Index[No] = No;
  752. if (p->Shuffle)
  753. {
  754. for (n=0;n<4;++n)
  755. for (No=0;No<p->PlayListCount;++No)
  756. SwapInt(&Index[No],&Index[Rand(p) % p->PlayListCount]);
  757. if (CurrentAsFirst)
  758. {
  759. // make sure current media is the first
  760. // so the full range of playlist will be played before it's regenerated
  761. No = FindCurrentIndex(p);
  762. if (No>0)
  763. SwapInt(&Index[No],&Index[0]);
  764. }
  765. }
  766. return ERR_NONE;
  767. }
  768. static int SetPlayListCount(player_base* p, int Count)
  769. {
  770. int i,j;
  771. int* Index = p->PlayIndex;
  772. item* List = (item*)realloc(p->PlayList,sizeof(item)*Count);
  773. if (!List && Count)
  774. return ERR_OUT_OF_MEMORY;
  775. if (p->PlayListCount > Count)
  776. {
  777. // remove unwanted indexes
  778. for (i=0,j=0;i<p->PlayListCount;++i)
  779. if (Index[i]<Count)
  780. Index[j++] = Index[i];
  781. assert(j==Count);
  782. }
  783. // realloc index
  784. Index = (int*)realloc(Index,sizeof(int)*Count);
  785. if (!Index && Count)
  786. {
  787. SetPlayListCount(p,0);
  788. return ERR_OUT_OF_MEMORY;
  789. }
  790. // add new items
  791. for (i=p->PlayListCount;i<Count;++i)
  792. {
  793. memset(List+i,0,sizeof(item));
  794. List[i].Length = -1;
  795. List[i].Changed = 1;
  796. Index[i] = i;
  797. if (p->Shuffle)
  798. SwapInt(&Index[i],&Index[Rand(p) % (i+1)]);
  799. }
  800. p->PlayIndex = Index;
  801. p->PlayList = List;
  802. p->PlayListCount = Count;
  803. if (p->Current >= Count)
  804. {
  805. p->Current = 0;
  806. p->CurrentChanged = 1;
  807. }
  808. NotifyList(p);
  809. return ERR_NONE;
  810. }
  811. static void StopLoadMode(player_base* p)
  812. {
  813. if (p->LoadMode)
  814. {
  815. DEBUG_MSG(DEBUG_TEST,T("LoadMode Leaving"));
  816. p->LoadMode = 0;
  817. UpdatePlay(p); // UpdateInputPriority(p) called too
  818. UpdateRunProcess(p);
  819. UpdateRunInput(p);
  820. Notify(p,PLAYER_LOADMODE,p->LoadMode);
  821. }
  822. }
  823. static void StopBench(player_base* p)
  824. {
  825. p->BenchTime = Scale(GetTimeTick() - p->BenchStart,TICKSPERSEC,GetTimeFreq());
  826. p->Bench = 0;
  827. p->MicroDrive = p->SaveMicroDrive;
  828. p->BenchSrc.x = p->BenchSrc.y = 0;
  829. p->BenchDst.x = p->BenchDst.y = 0;
  830. if (p->VOutput)
  831. {
  832. rect Rect;
  833. packetformat Format;
  834. if (p->VOutput->Get(p->VOutput,OUT_INPUT|PIN_FORMAT,&Format,sizeof(Format))==ERR_NONE)
  835. {
  836. p->BenchSrc.x = Format.Format.Video.Width;
  837. p->BenchSrc.y = Format.Format.Video.Height;
  838. }
  839. if (p->VOutput->Get(p->VOutput,VOUT_OUTPUTRECT,&Rect,sizeof(Rect))==ERR_NONE)
  840. {
  841. p->BenchDst.x = Rect.Width;
  842. p->BenchDst.y = Rect.Height;
  843. }
  844. }
  845. UpdateFormat(p,0);
  846. UpdatePlay(p);
  847. UpdateSpeed(p);
  848. Flush(p);
  849. Notify(p,PLAYER_BENCHMARK,p->BenchTime);
  850. }
  851. static void UpdateKeepAlive(player_base* p)
  852. {
  853. bool_t KeepAlive = p->FFwd || p->Play;
  854. if (p->VOutput)
  855. p->VOutput->Set(p->VOutput,OUT_KEEPALIVE,&KeepAlive,sizeof(KeepAlive));
  856. if (p->AOutput)
  857. p->AOutput->Set(p->AOutput,OUT_KEEPALIVE,&KeepAlive,sizeof(KeepAlive));
  858. }
  859. static int SetPlay(player_base* p,bool_t Stop)
  860. {
  861. bool_t Refresh;
  862. if (Stop)
  863. {
  864. p->Play = 0;
  865. p->FFwd = 0;
  866. p->Fill = 0;
  867. p->Sync = 0;
  868. p->InSeek = 0;
  869. if (p->TemporaryHidden)
  870. {
  871. p->TemporaryHidden = 0;
  872. UpdateVideo(p,-1);
  873. }
  874. }
  875. DEBUG_MSG2(DEBUG_PLAYER,T("Play %d,%d"),p->Play,p->FFwd);
  876. StopLoadMode(p);
  877. if (p->Bench && !p->Play)
  878. StopBench(p);
  879. if (p->Format && p->Input && p->Timer)
  880. {
  881. if (p->NoMoreInput && (p->Play || p->FFwd) && p->IOError)
  882. {
  883. p->Fill = 1;
  884. p->NoMoreInput = 0;
  885. p->IOError = 0;
  886. UpdateRunInput(p);
  887. }
  888. if (p->TimerPlay)
  889. {
  890. UpdateKeepAlive(p);
  891. UpdatePlay(p);
  892. UpdateSpeed(p);
  893. }
  894. else
  895. {
  896. UpdateSpeed(p);
  897. UpdatePlay(p);
  898. UpdateKeepAlive(p);
  899. }
  900. UpdateRunProcess(p);
  901. // make sure current frame is show after pausing a dropping period
  902. Refresh = p->VOutput && !p->Play && !p->FFwd && !p->Sync && p->Fill;
  903. if (Refresh && p->FlowBuffer)
  904. Refresh = p->FlowBuffer->Set(p->FlowBuffer,FLOW_RESEND,NULL,0) != ERR_NONE;
  905. if (Refresh)
  906. ReSync(p,0);
  907. }
  908. else
  909. UpdateKeepAlive(p);
  910. UpdateTimeouts(p);
  911. UpdateBackground(p);
  912. Notify(p,PLAYER_PLAY,p->Play);
  913. return ERR_NONE;
  914. }
  915. static int Seek2(player_base* p,tick_t Time,const fraction* Percent,bool_t PrevKey)
  916. {
  917. tick_t Duration;
  918. int Result = ERR_INVALID_DATA;
  919. if (p->Format && p->Input && p->Timer)
  920. {
  921. int FileSize;
  922. int FilePos = -1;
  923. if (Percent)
  924. {
  925. if (p->Format->Get(p->Format,FORMAT_DURATION,&Duration,sizeof(Duration))==ERR_NONE)
  926. {
  927. Time = Scale(Duration,Percent->Num,Percent->Den);
  928. if (Time < 0)
  929. Time = 0;
  930. }
  931. else
  932. if (p->Input->Get(p->Input,STREAM_LENGTH,&FileSize,sizeof(FileSize))==ERR_NONE)
  933. {
  934. Time = -1;
  935. FilePos = Scale(FileSize,Percent->Num,Percent->Den);
  936. if (FilePos < 0)
  937. FilePos = 0;
  938. }
  939. else
  940. return ERR_NOT_SUPPORTED;
  941. }
  942. p->SeekAfterSync.Num = -1;
  943. DEBUG_MSG2(DEBUG_PLAYER,T("Sync time:%d filepos:%d"),Time,FilePos);
  944. Result = p->Format->Sync(p->Format,Time,FilePos,PrevKey);
  945. if (Result == ERR_LOADING_HEADER && p->Sync && Percent)
  946. {
  947. p->SeekAfterSync = *Percent;
  948. p->SeekAfterSyncPrevKey = PrevKey;
  949. Result = ERR_NONE;
  950. }
  951. else
  952. if (Result == ERR_NONE)
  953. {
  954. Flush(p);
  955. p->NoMoreInput = 0;
  956. p->BufferMax = p->CurrBufferSize2;
  957. p->Position = Time;
  958. p->Sync = 1;
  959. p->PosNotify = -1;
  960. StopLoadMode(p);
  961. UpdatePlay(p);
  962. UpdateRunProcess(p);
  963. UpdateRunInput(p);
  964. // wakeup input threads (if needed)
  965. #ifdef MULTITHREAD
  966. EventSet(p->EventProcess); 
  967. #else
  968. p->WaitForProcess = 0;
  969. #endif
  970. }
  971. Notify(p,PLAYER_PERCENT,0);
  972. }
  973. else
  974. if (!p->Wnd && Percent)
  975. {
  976. p->SeekAfterSync = *Percent;
  977. p->SeekAfterSyncPrevKey = 1;
  978. Result = ERR_NONE;
  979. }
  980. return Result;
  981. }
  982. static int InSeek(player_base* p,tick_t Time,const fraction* Percent,bool_t PrevKey)
  983. {
  984. int Result;
  985. #ifdef MULTITHREAD
  986. assert(p->ProcessLocked != ThreadId() && p->InputLocked != ThreadId());
  987. #endif
  988. LockEnter(p->Lock);
  989. if (p->InSeek)
  990. {
  991. tick_t Duration;
  992. fraction Pos;
  993. if (Percent)
  994. Pos = *Percent;
  995. else
  996. if (p->Format->Get(p->Format,FORMAT_DURATION,&Duration,sizeof(Duration))==ERR_NONE)
  997. {
  998. Pos.Num = Time;
  999. Pos.Den = Duration;
  1000. }
  1001. else
  1002. {
  1003. Pos.Num = -1;
  1004. Pos.Den = 0;
  1005. }
  1006. if (EqFrac(&p->InSeekPos,&Pos))
  1007. {
  1008. LockLeave(p->Lock);
  1009. return ERR_NONE;
  1010. }
  1011. p->InSeekPos = Pos;
  1012. if (p->InSeekPos.Num>=0 && (p->Sync || !IsVideo(p)))
  1013. {
  1014. p->SeekAfterSync = p->InSeekPos;
  1015. p->SeekAfterSyncPrevKey = PrevKey;
  1016. Notify(p,PLAYER_PERCENT,0);
  1017. LockLeave(p->Lock);
  1018. return ERR_NONE;
  1019. }
  1020. }
  1021. Lock(p,1);
  1022. Result = Seek2(p,Time,Percent,PrevKey);
  1023. Unlock(p,1);
  1024. LockLeave(p->Lock);
  1025. return Result;
  1026. }
  1027. static void ReSync(player_base* p,bool_t DoSeek)
  1028. {
  1029. if (p->Format)
  1030. {
  1031. if (DoSeek && p->Position>=0)
  1032. Seek2(p,p->Position,NULL,1);
  1033. else
  1034. if (p->Format->Sync(p->Format,-1,-1,0) == ERR_NONE)
  1035. {
  1036. p->Sync = 1;
  1037. p->PosNotify = -1;
  1038. StopLoadMode(p);
  1039. UpdatePlay(p);
  1040. UpdateRunProcess(p);
  1041. // wakeup input threads, just in case
  1042. #ifdef MULTITHREAD
  1043. EventSet(p->EventProcess); 
  1044. #else
  1045. p->WaitForProcess = 0;
  1046. #endif
  1047. }
  1048. }
  1049. }
  1050. static bool_t SupportVQNode(node* Node)
  1051. {
  1052. int Shift;
  1053. bool_t Buffered;
  1054. if (NodeIsClass(Node->Class,IDCT_CLASS))
  1055. {
  1056. if (Node->Get(Node,IDCT_SHIFT,&Shift,sizeof(Shift))!=ERR_NONE)
  1057. return 0;
  1058. }
  1059. else
  1060. if (Node->Get(Node,FLOW_BUFFERED,&Buffered,sizeof(Buffered))==ERR_NONE && Buffered)
  1061. return 0;
  1062. return 1;
  1063. }
  1064. static bool_t SupportVQ(player_base* p)
  1065. {
  1066. const ref *i;
  1067. for (i=ARRAYBEGIN(p->Ref,ref);i!=ARRAYEND(p->Ref,ref);++i)
  1068. if (!SupportVQNode(i->Node))
  1069. return 0;
  1070. if (p->FlowBuffer && !SupportVQNode(p->FlowBuffer)) // flowbuffer may not be in ref array (accel. idct)
  1071. return 0;
  1072. return 1;
  1073. }
  1074. static int UpdateVideoQuality(player_base* p,node* Node)
  1075. {
  1076. if (NodeIsClass(Node->Class,IDCT_CLASS))
  1077. {
  1078. int Shift = 2-p->VideoQuality;
  1079. Node->Set(Node,IDCT_SHIFT,&Shift,sizeof(Shift));
  1080. }
  1081. return ERR_NONE;
  1082. }
  1083. static void ClearStats(player_base* p)
  1084. {
  1085. int Zero=0;
  1086. if (p->VOutput)
  1087. {
  1088. p->VOutput->Set(p->VOutput,OUT_TOTAL,&Zero,sizeof(Zero));
  1089. p->VOutput->Set(p->VOutput,OUT_DROPPED,&Zero,sizeof(Zero));
  1090. }
  1091. if (p->AOutput)
  1092. {
  1093. p->AOutput->Set(p->AOutput,OUT_TOTAL,&Zero,sizeof(Zero));
  1094. p->AOutput->Set(p->AOutput,OUT_DROPPED,&Zero,sizeof(Zero));
  1095. }
  1096. }
  1097. static void StartBench(player_base* p)
  1098. {
  1099. int Used;
  1100. p->SaveMicroDrive = p->MicroDrive;
  1101. p->MicroDrive = 0;
  1102. p->InSeek = 0;
  1103. UpdateFormat(p,0);
  1104. if (!QueryAdvanced(ADVANCED_BENCHFROMPOS))
  1105. Seek2(p,0,NULL,0);
  1106. p->BufferMax = p->CurrBufferSize2;
  1107. while (p->Format->Read(p->Format,p->BufferMax,&Used) == ERR_NONE &&
  1108. Used < p->UsedEnough2);
  1109. ClearStats(p);
  1110. p->Bench = 1;
  1111. p->BenchStart = GetTimeTick();
  1112. p->Play = 1;
  1113. p->FFwd = 0;
  1114. p->Fill = 0;
  1115. SetPlay(p,0);
  1116. }
  1117. static void SetTimerNode(player_base* p,node* Timer,bool_t SaveTime)
  1118. {
  1119. tick_t Time = 0;
  1120. if (p->Timer && SaveTime)
  1121. p->Timer->Get(p->Timer,TIMER_TIME,&Time,sizeof(Time));
  1122. p->Timer = Timer;
  1123. if (p->Timer)
  1124. {
  1125. p->Timer->Set(p->Timer,TIMER_SPEED,&p->Speed,sizeof(p->Speed));
  1126. p->Timer->Set(p->Timer,TIMER_TIME,&Time,sizeof(Time));
  1127. UpdatePlay(p);
  1128. }
  1129. UpdateRunProcess(p);
  1130. }
  1131. static node* AddRef(player_base* p,node* Node);
  1132. static void ReleaseRef(player_base* p,node* Node);
  1133. static bool_t UpdateNode(player_base* p,node* Node);
  1134. static void ReleaseNode(player_base* p,node* Node);
  1135. static bool_t UpdateOutput(player_base* p,node* From,const datadef* FromDef,int* FoundFirst);
  1136. static NOINLINE void NullPin(node* p,int No)
  1137. {
  1138. pin Pin;
  1139. Pin.Node = NULL;
  1140. Pin.No = 0;
  1141. p->Set(p,No,&Pin,sizeof(Pin));
  1142. }
  1143. static void TryComment(player_base* p,node* From,const datadef* FromDef)
  1144. {
  1145. pin Pin;
  1146. Pin.Node = (node*)p;
  1147. Pin.No = PLAYER_COMMENT+p->StreamNo;
  1148. From->Set(From,FromDef->No,&Pin,sizeof(Pin));
  1149. }
  1150. static void ReleaseOutput(player_base* p,node* Node,datadef* DataDef)
  1151. {
  1152. node* Null = NULL;
  1153. pin Pin;
  1154. node* Ptr;
  1155. bool_t RdOnly = (DataDef->Flags & DF_RDONLY)!=0;
  1156. switch (DataDef->Type)
  1157. {
  1158. case TYPE_NODE:
  1159. if (Node->Get(Node,DataDef->No,&Ptr,sizeof(Ptr))==ERR_NONE && Ptr)
  1160. {
  1161. ReleaseNode(p,Ptr);
  1162. if (!RdOnly)
  1163. {
  1164. Node->Set(Node,DataDef->No,&Null,sizeof(Null));
  1165. ReleaseRef(p,Ptr);
  1166. }
  1167. }
  1168. break;
  1169. case TYPE_COMMENT:
  1170. if (!RdOnly)
  1171. NullPin(Node,DataDef->No);
  1172. break;
  1173. case TYPE_PACKET:
  1174. if (Node->Get(Node,DataDef->No,&Pin,sizeof(Pin))==ERR_NONE && Pin.Node)
  1175. {
  1176. ReleaseNode(p,Pin.Node);
  1177. if (!RdOnly)
  1178. {
  1179. Disconnect(Node,DataDef->No,Pin.Node,Pin.No);
  1180. ReleaseRef(p,Pin.Node);
  1181. }
  1182. }
  1183. }
  1184. }
  1185. static void ReleaseNode(player_base* p,node* Node)
  1186. {
  1187. if (Node)
  1188. {
  1189. bool_t False = 0;
  1190. datadef DataDef;
  1191. int No;
  1192. if (p->VOutput == Node)
  1193. {
  1194. p->VOutput = NULL;
  1195. p->VIDCT = NULL;
  1196. }
  1197. if (p->AOutput == Node)
  1198. {
  1199. SetTimerNode(p,NodeEnumObject(NULL,SYSTIMER_ID),1); // restore system timer
  1200. p->AOutput = NULL;
  1201. }
  1202. if (p->FlowBuffer == Node)
  1203. p->FlowBuffer = NULL;
  1204. Node->Set(Node,FLOW_BACKGROUND,&False,sizeof(bool_t));
  1205. for (No=0;NodeEnum(Node,No,&DataDef)==ERR_NONE;++No)
  1206. if (DataDef.Flags & DF_OUTPUT)
  1207. ReleaseOutput(p,Node,&DataDef);
  1208. }
  1209. }
  1210. static node* GetNode(player_base* p,int Class)
  1211. {
  1212. node* Node = NULL;
  1213. bool_t ReUse = 0;
  1214. bool_t IDCT = 0;
  1215. if (Class == (int)VOUT_IDCT_CLASS(p->VOutputId) && NodeIsClass(Class,IDCT_CLASS))
  1216. {
  1217. Class = p->VOutputId;
  1218. IDCT = 1;
  1219. }
  1220. if (Class == p->AOutputId || Class == p->VOutputId)
  1221. {
  1222. ref *i;
  1223. for (i=ARRAYBEGIN(p->Ref,ref);i!=ARRAYEND(p->Ref,ref);++i)
  1224. if (i->Node->Class == Class)
  1225. {
  1226. Node = i->Node;
  1227. ReUse = 1;
  1228. break;
  1229. }
  1230. }
  1231. if (!Node)
  1232. {
  1233. Node = NodeCreate(Class);
  1234. if (Node)
  1235. {
  1236. if (NodeIsClass(Class,VOUT_CLASS))
  1237. UpdateVideoEx(p,Node,-1,0);
  1238. if (NodeIsClass(Class,AOUT_CLASS))
  1239. UpdateAudioEx(p,Node);
  1240. UpdateVideoQuality(p,Node);
  1241. }
  1242. }
  1243. if (Node)
  1244. {
  1245. pin Pin;
  1246. if (IDCT)
  1247. {
  1248. node* i;
  1249. Node->Get(Node,VOUT_IDCT,&i,sizeof(i));
  1250. if (!i)
  1251. {
  1252. if (!ReUse) 
  1253. NodeDelete(Node);
  1254. return NULL;
  1255. }
  1256. Node = i;
  1257. }
  1258. Pin.No = PLAYER_NOT_SUPPORTED_DATA;
  1259. Pin.Node = (node*)p;
  1260. Node->Set(Node,FLOW_NOT_SUPPORTED,&Pin,sizeof(Pin));
  1261. AddRef(p,Node);
  1262. }
  1263. return Node;
  1264. }
  1265. static bool_t TryPin(player_base* p,node* From,int FromNo,int ToClass,int* FoundFirst,int Failed)
  1266. {
  1267. node* To;
  1268. if (ToClass == Failed)
  1269. return 0;
  1270. To = GetNode(p,ToClass);
  1271. if (To)
  1272. {
  1273. packetformat Format;
  1274. datadef ToDef;
  1275. int No;
  1276. int Result;
  1277. for (No=0;NodeEnum(To,No,&ToDef)==ERR_NONE;++No)
  1278. if (ToDef.Type == TYPE_PACKET && (ToDef.Flags & DF_INPUT) && !(ToDef.Flags & DF_RDONLY))
  1279. {
  1280. if (To->Get(To,ToDef.No|PIN_FORMAT,&Format,sizeof(Format))==ERR_NONE && Format.Type != PACKET_NONE)
  1281. continue; // already connected
  1282. Result = ConnectionUpdate(From,FromNo,To,ToDef.No);
  1283. if (Result == ERR_NOT_SUPPORTED && FoundFirst)
  1284. *FoundFirst = 2; // found codec, but this type is not supported
  1285. else
  1286. if (Result == ERR_NONE)
  1287. {
  1288. if (FoundFirst)
  1289. *FoundFirst = 1;
  1290. if (UpdateNode(p,To))
  1291. return 1;
  1292. }
  1293. Disconnect(From,FromNo,To,ToDef.No);
  1294. }
  1295. ReleaseRef(p,To);
  1296. }
  1297. return 0;
  1298. }
  1299. static bool_t IsCodecSkip(player_base* p,int Id)
  1300. {
  1301. int i;
  1302. for (i=0;i<p->CodecSkipCount;++i)
  1303. if (p->CodecSkip[i]==Id)
  1304. return 1;
  1305. return 0;
  1306. }
  1307. static bool_t UpdateOutput(player_base* p,node* From,const datadef* FromDef,int* FoundFirst)
  1308. {
  1309. packetformat Format;
  1310. bool_t EqMissing;
  1311. node* Null = NULL;
  1312. node* To;
  1313. node* Old = NULL;
  1314. int Force = 0;
  1315. int Skip = 0;
  1316. pin Pin;
  1317. bool_t RdOnly = (FromDef->Flags & DF_RDONLY)!=0;
  1318. int Failed = 0;
  1319. if (FoundFirst)
  1320. *FoundFirst = 0;
  1321. switch (FromDef->Type)
  1322. {
  1323. case TYPE_NODE:
  1324. if (!RdOnly)
  1325. switch (FromDef->Format1)
  1326. {
  1327. case IDCT_CLASS:
  1328. if (VOutIDCT(p->VOutputId))
  1329. {
  1330. int IDCT = VOUT_IDCT_CLASS(p->VOutputId);
  1331. if (p->VideoAccel && p->Timing && p->SkipAccelFrom != From->Class)
  1332. Force = IDCT;
  1333. else
  1334. Skip = IDCT;
  1335. }
  1336. break;
  1337. case VOUT_CLASS:
  1338. Force = p->VOutputId;
  1339. break;
  1340. case AOUT_CLASS:
  1341. Force = p->AOutputId;
  1342. break;
  1343. }
  1344. // already connected pointer?
  1345. if (From->Get(From,FromDef->No,&Old,sizeof(Old))==ERR_NONE && Old)
  1346. {
  1347. if (FoundFirst)
  1348. *FoundFirst = 1;
  1349. if ((!Force || Old->Class == Force) && (!Skip || Old->Class != Skip))
  1350. {
  1351. if (UpdateNode(p,Old))
  1352. return 1;
  1353. Failed = Old->Class;
  1354. }
  1355. else
  1356. ReleaseNode(p,Old);
  1357. }
  1358. if (RdOnly)
  1359. return 0;
  1360. if (Force)
  1361. {
  1362. To = GetNode(p,Force);
  1363. if (To && From->Set(From,FromDef->No,&To,sizeof(To))==ERR_NONE)
  1364. {
  1365. ReleaseRef(p,Old);
  1366. Old = To;
  1367. if (FoundFirst)
  1368. *FoundFirst = 1;
  1369. if (UpdateNode(p,To))
  1370. return 1;
  1371. }
  1372. else
  1373. ReleaseRef(p,To);
  1374. if (FromDef->Format1 == IDCT_CLASS)
  1375. p->SkipAccelFrom = From->Class;
  1376. if (Old && !Failed && UpdateNode(p,Old))
  1377. return 1;
  1378. }
  1379. if (FromDef->Format1 != VOUT_CLASS && FromDef->Format1 != AOUT_CLASS)
  1380. {
  1381. int* i;
  1382. array List;
  1383. NodeEnumClass(&List,FromDef->Format1);
  1384. for (i=ARRAYBEGIN(List,int);i!=ARRAYEND(List,int);++i)
  1385. if (Failed != *i && (To = GetNode(p,*i))!=NULL)
  1386. {
  1387. if (From->Set(From,FromDef->No,&To,sizeof(To))==ERR_NONE)
  1388. {
  1389. ReleaseRef(p,Old);
  1390. Old = To;
  1391. if (FoundFirst)
  1392. *FoundFirst = 1;
  1393. if (UpdateNode(p,To))
  1394. {
  1395. ArrayClear(&List);
  1396. return 1;
  1397. }
  1398. }
  1399. else
  1400. ReleaseRef(p,To);
  1401. }
  1402. ArrayClear(&List);
  1403. }
  1404. From->Set(From,FromDef->No,&Null,sizeof(Null));
  1405. ReleaseRef(p,Old);
  1406. break;
  1407. case TYPE_COMMENT:
  1408. if (!RdOnly)
  1409. TryComment(p,From,FromDef);
  1410. return 1;
  1411. case TYPE_PACKET:
  1412. EqMissing = p->Eq && !Used(p,p->Equalizer);
  1413. // already connected pin?
  1414. if (From->Get(From,FromDef->No,&Pin,sizeof(Pin))==ERR_NONE && Pin.Node)
  1415. {
  1416. if (!IsCodecSkip(p,Pin.Node->Class) && (!NodeIsClass(Pin.Node->Class,OUT_CLASS) || Pin.Node->Class == p->VOutputId || 
  1417. (Pin.Node->Class == p->AOutputId && !EqMissing)))
  1418. {
  1419. if (FoundFirst)
  1420. *FoundFirst = 1;
  1421. if (UpdateNode(p,Pin.Node))
  1422. return 1;
  1423. Failed = Pin.Node->Class; // don't try with class again
  1424. }
  1425. else
  1426. ReleaseNode(p,Pin.Node);
  1427. if (!RdOnly)
  1428. {
  1429. Disconnect(From,FromDef->No,Pin.Node,Pin.No);
  1430. ReleaseRef(p,Pin.Node);
  1431. }
  1432. }
  1433. if (RdOnly)
  1434. return 0;
  1435. if (From->Get(From,FromDef->No|PIN_FORMAT,&Format,sizeof(Format))==ERR_NONE)
  1436. {
  1437. array List;
  1438. const int *i;
  1439. if (Format.Type == PACKET_VIDEO)
  1440. {
  1441. if (!p->VOutputId)
  1442. {
  1443. if (FoundFirst)
  1444. *FoundFirst = 1;
  1445. return 0;
  1446. }
  1447. if (TryPin(p,From,FromDef->No,p->VOutputId,FoundFirst,Failed))
  1448. return 1;
  1449. }
  1450. if (Format.Type == PACKET_AUDIO && !EqMissing)
  1451. {
  1452. if (!p->AOutputId)
  1453. {
  1454. if (FoundFirst)
  1455. *FoundFirst = 1;
  1456. return 0;
  1457. }
  1458. if (TryPin(p,From,FromDef->No,p->AOutputId,FoundFirst,Failed))
  1459. return 1;
  1460. }
  1461. PacketFormatEnumClass(&List,&Format);
  1462. for (i=ARRAYBEGIN(List,int);i!=ARRAYEND(List,int);++i)
  1463. if (!IsCodecSkip(p,*i) && TryPin(p,From,FromDef->No,*i,FoundFirst,Failed))
  1464. {
  1465. ArrayClear(&List);
  1466. return 1;
  1467. }
  1468. if (Format.Type == PACKET_AUDIO && EqMissing)
  1469. {
  1470. if (!p->AOutputId)
  1471. {
  1472. if (FoundFirst)
  1473. *FoundFirst = 1;
  1474. return 0;
  1475. }
  1476. if (TryPin(p,From,FromDef->No,p->AOutputId,FoundFirst,Failed))
  1477. return 1;
  1478. }
  1479. ArrayClear(&List);
  1480. }
  1481. break;
  1482. }
  1483. return 0;
  1484. }
  1485. static node* AddRef(player_base* p,node* Node)
  1486. {
  1487. if (Node)
  1488. {
  1489. bool_t Found;
  1490. ref Ref;
  1491. int No;
  1492. Ref.RefCount = 1;
  1493. if (Node->Get(Node,NODE_PARTOF,&Ref.Node,sizeof(node*)) != ERR_NONE)
  1494. Ref.Node = Node;
  1495. No = ArrayFind(&p->Ref,ARRAYCOUNT(p->Ref,ref),sizeof(ref),&Ref,(arraycmp)CmpRef,&Found);
  1496. if (!Found)
  1497. ArrayAdd(&p->Ref,ARRAYCOUNT(p->Ref,ref),sizeof(ref),&Ref,(arraycmp)CmpRef,64);
  1498. else
  1499. ARRAYBEGIN(p->Ref,ref)[No].RefCount++;
  1500. }
  1501. return Node;
  1502. }
  1503. static void ReleaseRef(player_base* p,node* Node)
  1504. {
  1505. if (Node)
  1506. {
  1507. int No;
  1508. ref Ref;
  1509. bool_t Found;
  1510. if (Node->Get(Node,NODE_PARTOF,&Ref.Node,sizeof(node*)) != ERR_NONE)
  1511. Ref.Node = Node;
  1512. No = ArrayFind(&p->Ref,ARRAYCOUNT(p->Ref,ref),sizeof(ref),&Ref,(arraycmp)CmpRef,&Found);
  1513. if (Found && --(ARRAYBEGIN(p->Ref,ref)[No].RefCount)==0)
  1514. {
  1515. ArrayRemove(&p->Ref,ARRAYCOUNT(p->Ref,ref),sizeof(ref),&Ref,(arraycmp)CmpRef);
  1516. NodeDelete(Ref.Node);
  1517. }
  1518. }
  1519. }
  1520. static bool_t UpdateNode(player_base* p,node* Node)
  1521. {
  1522. bool_t Buffered;
  1523. assert(NodeIsClass(Node->Class,FLOW_CLASS));
  1524. if (!NodeIsClass(Node->Class,OUT_CLASS))
  1525. {
  1526. // update output pins
  1527. datadef DataDef;
  1528. int No;
  1529. for (No=0;NodeEnum(Node,No,&DataDef)==ERR_NONE;++No)
  1530. if (DataDef.Flags & DF_OUTPUT)
  1531. if (!UpdateOutput(p,Node,&DataDef,NULL))
  1532. {
  1533. ReleaseNode(p,Node);
  1534. return 0;
  1535. }
  1536. }
  1537. if (Node->Class == p->VOutputId)
  1538. {
  1539. p->VOutput = Node;
  1540. Node->Set(Node,VOUT_PLAY,&p->TimerPlay,sizeof(bool_t));
  1541. Node->Get(Node,VOUT_IDCT,&p->VIDCT,sizeof(p->VIDCT));
  1542. if (!p->VIDCT)
  1543. p->VideoAccel = 0;
  1544. if (p->FullScreenAfterSync && !p->FullScreen)
  1545. Notify(p,PLAYER_FULLSCREEN,1);
  1546. }
  1547. if (Node->Class == p->AOutputId)
  1548. {
  1549. node* Timer;
  1550. p->AOutput = Node;
  1551. if (Node->Get(Node,AOUT_TIMER,&Timer,sizeof(Timer))==ERR_NONE)
  1552. SetTimerNode(p,Timer,1);
  1553. }
  1554. if (Node->Get(Node,FLOW_BUFFERED,&Buffered,sizeof(Buffered))==ERR_NONE && Buffered)
  1555. p->FlowBuffer = Node;
  1556. return 1;
  1557. }
  1558. static int ReleaseStreamsNotify(player_base* p,int Param,int Param2)
  1559. {
  1560. datadef DataDef; 
  1561. int No;
  1562. for (No=0;NodeEnum((node*)p->Format,No,&DataDef)==ERR_NONE;++No)
  1563. {
  1564. if (DataDef.No >= FORMAT_COMMENT && DataDef.No < FORMAT_COMMENT+MAXSTREAM)
  1565. NullPin((node*)p->Format,DataDef.No);
  1566. if (DataDef.No >= FORMAT_STREAM && DataDef.No < FORMAT_STREAM+MAXSTREAM)
  1567. ReleaseOutput(p,(node*)p->Format,&DataDef);
  1568. }
  1569. return ERR_NONE;
  1570. }
  1571. static int UpdateStreamsMask(player_base* p)
  1572. {
  1573. int Result = UpdateStreams(p,1,0);
  1574. if (Result == ERR_NONE && p->Format)
  1575. {
  1576. tick_t Time;
  1577. p->Timer->Get(p->Timer,TIMER_TIME,&Time,sizeof(tick_t));
  1578. p->Format->Set(p->Format,FORMAT_UPDATEMASK,&Time,sizeof(tick_t));
  1579. }
  1580. return Result;
  1581. }
  1582. static int UpdateStreamsNotify(player_base* p,int Param,int Param2)
  1583. {
  1584. // called by process thread
  1585. // we are inside the LockProcess so Lock/Unlock not needed
  1586. // inputprocess doesn't bother us here
  1587. UpdateStreams(p,-1,0);
  1588. return ERR_NONE;
  1589. }
  1590. static void ReleaseFormat(player_base* p)
  1591. {
  1592. NullPin((node*)p->Format,FORMAT_GLOBAL_COMMENT);
  1593. p->Format->Set(p->Format,FORMAT_INPUT,NULL,0);
  1594. NodeDelete((node*)p->Format);
  1595. p->Format = NULL;
  1596. }
  1597. static void ErrorCodec(packetformat* Format)
  1598. {
  1599. tchar_t Name[64];
  1600. int Id = 0;
  1601. switch (Format->Type)
  1602. {
  1603. case PACKET_VIDEO: 
  1604. Id = PLAYER_VIDEO_NOT_FOUND; 
  1605. break;
  1606. case PACKET_AUDIO: 
  1607. #ifdef CONFIG_GPL
  1608. if (Format->Format.Audio.Format == AUDIOFMT_AAC)
  1609. Id = PLAYER_AUDIO_NOT_FOUND2;
  1610. else
  1611. #endif
  1612. Id = PLAYER_AUDIO_NOT_FOUND; 
  1613. break;
  1614. }
  1615. if (Id && PacketFormatName(Format,Name,TSIZEOF(Name)))
  1616. ShowError(PLAYER_ID,PLAYER_ID,Id,Name);
  1617. }
  1618. static int UpdateStreams(player_base* p,int ForceRefresh,bool_t CodecSkip)
  1619. {
  1620. packetformat Format;
  1621. datadef DataDef;
  1622. int FoundCodec;
  1623. int No;
  1624. p->UpdateStreamsNeeded = 0;
  1625. if (!p->Format)
  1626. return ERR_INVALID_PARAM;
  1627. // first release unused streams
  1628. for (No=0;NodeEnum((node*)p->Format,No,&DataDef)==ERR_NONE;++No)
  1629. if (DataDef.No >= FORMAT_STREAM && DataDef.No < FORMAT_STREAM+MAXSTREAM)
  1630. {
  1631. p->StreamNo = DataDef.No - FORMAT_STREAM;
  1632. if (!p->StreamSkip[p->StreamNo] && 
  1633. p->Format->Get(p->Format,DataDef.No|PIN_FORMAT,&Format,sizeof(Format))==ERR_NONE && 
  1634. Format.Type != PACKET_NONE && p->Selected[Format.Type]>=0 && p->Selected[Format.Type] != p->StreamNo)
  1635. ReleaseOutput(p,(node*)p->Format,&DataDef);
  1636. }
  1637. for (No=0;NodeEnum((node*)p->Format,No,&DataDef)==ERR_NONE;++No)
  1638. {
  1639. if (DataDef.No >= FORMAT_COMMENT && DataDef.No < FORMAT_COMMENT+MAXSTREAM)
  1640. {
  1641. p->StreamNo = DataDef.No - FORMAT_COMMENT;
  1642. TryComment(p,(node*)p->Format,&DataDef);
  1643. }
  1644. if (DataDef.No >= FORMAT_STREAM && DataDef.No < FORMAT_STREAM+MAXSTREAM)
  1645. {
  1646. p->StreamNo = DataDef.No - FORMAT_STREAM;
  1647. if (!p->StreamSkip[p->StreamNo] && 
  1648. p->Format->Get(p->Format,DataDef.No|PIN_FORMAT,&Format,sizeof(Format))==ERR_NONE && 
  1649. Format.Type != PACKET_NONE)
  1650. {
  1651. if (p->Selected[Format.Type]<0)
  1652. p->Selected[Format.Type] = p->StreamNo;
  1653. if (p->Selected[Format.Type] == p->StreamNo && 
  1654. !UpdateOutput(p,(node*)p->Format,&DataDef,&FoundCodec) && FoundCodec!=1)
  1655. {
  1656. if (!FoundCodec && !CodecSkip)
  1657. ErrorCodec(&Format);
  1658. p->Selected[Format.Type] = -1;
  1659. p->StreamSkip[p->StreamNo] = 1;
  1660. }
  1661. }
  1662. }
  1663. }
  1664. UpdateVideo(p,ForceRefresh);
  1665. UpdateTimeouts(p);
  1666. return ERR_NONE;
  1667. }
  1668. static int UpdateFormat(player_base* p,bool_t BufferChanged)
  1669. {
  1670. if (BufferChanged)
  1671. p->BufferWarning = 0;
  1672. p->CurrBufferSize2 = p->MicroDrive ? p->MDBufferSize2 : p->BufferSize2;
  1673. p->BufferMax = p->CurrBufferSize2;
  1674. if (p->Format)
  1675. p->Format->Set(p->Format,FORMAT_BUFFERSIZE,&p->CurrBufferSize2,sizeof(int));
  1676. return ERR_NONE;
  1677. }
  1678. static void RemoveFilter(player_base* p,node* Filter,int In,int Out)
  1679. {
  1680. pin InPin;
  1681. pin OutPin;
  1682. if (Filter->Get(Filter,In,&InPin,sizeof(InPin))==ERR_NONE && InPin.Node &&
  1683. Filter->Get(Filter,Out,&OutPin,sizeof(OutPin))==ERR_NONE && OutPin.Node)
  1684. {
  1685. if (ConnectionUpdate(InPin.Node,InPin.No,OutPin.Node,OutPin.No)==ERR_NONE)
  1686. {
  1687. ConnectionUpdate(NULL,0,Filter,Out);
  1688. ConnectionUpdate(Filter,In,NULL,0);
  1689. ReleaseRef(p,Filter);
  1690. }
  1691. else
  1692. {
  1693. ConnectionUpdate(InPin.Node,InPin.No,Filter,In);
  1694. ConnectionUpdate(Filter,Out,OutPin.Node,OutPin.No);
  1695. }
  1696. }
  1697. }
  1698. static void InsertFilter(player_base* p,node* Filter,int In,int Out,node* Output,int OutputIn)
  1699. {
  1700. pin Pin;
  1701. if (Output->Get(Output,OutputIn,&Pin,sizeof(Pin))==ERR_NONE && Pin.Node)
  1702. {
  1703. if (ConnectionUpdate(Pin.Node,Pin.No,Filter,In)==ERR_NONE &&
  1704. ConnectionUpdate(Filter,Out,Output,OutputIn)==ERR_NONE)
  1705. GetNode(p,Filter->Class);
  1706. else
  1707. {
  1708. ConnectionUpdate(Pin.Node,Pin.No,Output,OutputIn); //try restoring...
  1709. ConnectionUpdate(NULL,0,Filter,Out);
  1710. ConnectionUpdate(Filter,In,NULL,0);
  1711. }
  1712. }
  1713. }
  1714. static int UpdateEqualizer(player_base* p)
  1715. {
  1716. if (p->Equalizer)
  1717. p->Equalizer->Get(p->Equalizer,EQUALIZER_ENABLED,&p->Eq,sizeof(p->Eq));
  1718. if (!p->Eq && Used(p,p->Equalizer))
  1719. RemoveFilter(p,p->Equalizer,CODEC_INPUT,CODEC_OUTPUT);
  1720. else
  1721. if (p->Eq && !Used(p,p->Equalizer) && p->AOutput)
  1722. InsertFilter(p,p->Equalizer,CODEC_INPUT,CODEC_OUTPUT,p->AOutput,OUT_INPUT);
  1723. return ERR_NONE;
  1724. }
  1725. static void Unload(player_base* p,bool_t KeepPlay,bool_t KeepStreams,bool_t Refresh) 
  1726. {
  1727. p->Sync = 0;
  1728. p->Fill = 0;
  1729. p->InSeek = 0;
  1730. p->SeekAfterSync.Num = -1;
  1731. if (!KeepPlay)
  1732. SetPlay(p,1);
  1733. if (!KeepStreams || p->Format)
  1734. {
  1735. int i;
  1736. for (i=0;i<PACKET_MAX;++i)
  1737. p->Selected[i] = -1;
  1738. }
  1739. if (p->Format)
  1740. ReleaseFormat(p);
  1741. if (p->Input)
  1742. {
  1743. NodeDelete((node*)p->Input);
  1744. p->Input = NULL;
  1745. }
  1746. if (p->InputBase)
  1747. {
  1748. NodeDelete((node*)p->InputBase);
  1749. p->InputBase = NULL;
  1750. }
  1751. p->Title[0] = 0;
  1752. Notify(p,PLAYER_TITLE,1);
  1753. assert(ARRAYEMPTY(p->Ref));
  1754. ArrayClear(&p->Ref);
  1755. ArrayClear(&p->Comment);
  1756. p->Position = -1;
  1757. p->NoMoreInput = 0;
  1758. p->CurrentChanged = 1;
  1759. p->BufferWarning = 0;
  1760. p->CodecSkipCount = 0;
  1761. if (!KeepPlay)
  1762. UpdateTimeouts(p);
  1763. UpdateRunInput(p);
  1764. UpdateRunProcess(p);
  1765. if (Refresh)
  1766. Notify(p,PLAYER_PERCENT,1);
  1767. }
  1768. static void URLToTitle(tchar_t* Title, int TitleLen, const tchar_t* URL)
  1769. {
  1770. tchar_t Ext[MAXPATH];
  1771. tchar_t *i,*j;
  1772. bool_t HasHost;
  1773. i = (tchar_t*) GetMime(URL,NULL,0,&HasHost);
  1774. if (i==URL || !HasHost || tcschr(i,'/') || tcschr(i,'\'))
  1775. SplitURL(URL,NULL,0,NULL,0,Title,TitleLen,Ext,TSIZEOF(Ext));
  1776. else
  1777. tcscpy_s(Title,TitleLen,URL);
  1778. // replace %20 and '_' with space
  1779. for (j=i=Title;*i;++i)
  1780. {
  1781. if (*i=='_')
  1782. *j++ = ' ';
  1783. else
  1784. if (i[0]=='%' && i[1]=='2' && i[2]=='0')
  1785. {
  1786. *j++ = ' ';
  1787. i += 2;
  1788. }
  1789. else
  1790. *j++ = *i;
  1791. }
  1792. *j=0;
  1793. }
  1794. static bool_t LoadPlaylist(player* Player,const array* List,stream* Input,int* Index,const tchar_t* Path,const void* Probe,int ProbeSize)
  1795. {
  1796. int *i;
  1797. bool_t SeekHead = 0;
  1798. for (i=ARRAYBEGIN(*List,int);i!=ARRAYEND(*List,int);++i)
  1799. {
  1800. playlist* Playlist = (playlist*)NodeCreate(*i);
  1801. if (Playlist)
  1802. {
  1803. tchar_t Base[MAXPATH];
  1804. tchar_t Abs[MAXPATH];
  1805. tchar_t ItemPath[MAXPATH];
  1806. tchar_t ItemTitle[256];
  1807. tick_t ItemLength;
  1808. int Pos = *Index;
  1809. if (SeekHead)
  1810. {
  1811. Input->Seek(Input,ProbeSize,SEEK_SET);
  1812. SeekHead = 0;
  1813. }
  1814. if (Probe)
  1815. Playlist->Set(Playlist,PLAYLIST_DATAFEED,Probe,ProbeSize);
  1816. if (Playlist->Set(Playlist,PLAYLIST_STREAM,&Input,sizeof(Input)) == ERR_NONE)
  1817. {
  1818. SplitURL(Path,Base,TSIZEOF(Base),Base,TSIZEOF(Base),NULL,0,NULL,0);
  1819. while (Playlist->ReadList(Playlist,ItemPath,TSIZEOF(ItemPath),ItemTitle,TSIZEOF(ItemTitle),&ItemLength)==ERR_NONE)
  1820. {
  1821. AbsPath(Abs,TSIZEOF(Abs),ItemPath,Base);
  1822. Player->Set(Player,PLAYER_LIST_URL+Pos,Abs,sizeof(Abs));
  1823. Player->Set(Player,PLAYER_LIST_TITLE+Pos,ItemTitle,sizeof(ItemTitle));
  1824. Player->Set(Player,PLAYER_LIST_LENGTH+Pos,&ItemLength,sizeof(ItemLength));
  1825. ++Pos;
  1826. }
  1827. SeekHead = 1;
  1828. }
  1829. Playlist->Set(Playlist,PLAYLIST_STREAM,NULL,0);
  1830. NodeDelete((node*)Playlist);
  1831. if (Pos != *Index)
  1832. {
  1833. *Index = Pos;
  1834. return 1;
  1835. }
  1836. }
  1837. }
  1838. if (Probe) // restore file position
  1839. Input->Seek(Input,ProbeSize,SEEK_SET);
  1840. return 0;
  1841. }
  1842. static void ListSwap(player_base* p,int a,int b)
  1843. {
  1844. #ifdef MULTITHREAD
  1845. assert(p->ProcessLocked != ThreadId() && p->InputLocked != ThreadId());
  1846. #endif
  1847. LockEnter(p->Lock);
  1848. if (a < p->PlayListCount && b < p->PlayListCount && a!=b)
  1849. {
  1850. item Tmp;
  1851. Tmp = p->PlayList[a];
  1852. p->PlayList[a] = p->PlayList[b];
  1853. p->PlayList[b] = Tmp;
  1854. if (p->Current == a)
  1855. p->Current = b;
  1856. else
  1857. if (p->Current == b)
  1858. p->Current = a;
  1859. p->PlayList[a].Changed = 1;
  1860. p->PlayList[b].Changed = 1;
  1861. NotifyList(p);
  1862. }
  1863. LockLeave(p->Lock);
  1864. }
  1865. static int Load(player_base* p,bool_t Silent,bool_t OnlyLocal,bool_t Nested);
  1866. static bool_t ReDirect(player_base* p,const tchar_t* New,const tchar_t* Orig,bool_t Silent,bool_t OnlyLocal,bool_t Nested,int* Result)
  1867. {
  1868. tchar_t Base[MAXPATH];
  1869. tchar_t Target[MAXPATH];
  1870. SplitURL(Orig,Base,TSIZEOF(Base),Base,TSIZEOF(Base),NULL,0,NULL,0);
  1871. AbsPath(Target,TSIZEOF(Target),New,Base);
  1872. if (tcsicmp(Target,Orig)==0)
  1873. return 0;
  1874. p->Player.Set(p,PLAYER_LIST_URL+p->Current,Target,sizeof(Target));
  1875. *Result = Load(p,Silent,OnlyLocal,Nested);
  1876. return 1;
  1877. }
  1878. static int Load(player_base* p,bool_t Silent,bool_t OnlyLocal,bool_t Nested)
  1879. {
  1880. tchar_t ContentType[MAXPATH];
  1881. array List;
  1882. block Probe;
  1883. tchar_t* URL;
  1884. stream* Input;
  1885. int ProbeSize;
  1886. int Result;
  1887. int No;
  1888. bool_t PosPrevKey = p->SeekAfterSyncPrevKey;
  1889. fraction Pos = p->SeekAfterSync;
  1890. p->SeekAfterSync.Num = -1;
  1891. p->InSeek = 0;
  1892. p->TemporaryHidden = Pos.Num > 0;
  1893. if (p->CurrentChanged || p->PlayList[p->Current].Changed || p->IOError)
  1894. {
  1895. tchar_t Mime[MAXMIME];
  1896. int Length;
  1897. pin Comment;
  1898. bool_t Network;
  1899. if (p->Format)
  1900. Pos.Num = -1; // invalidate last SeekAfterSync
  1901. Unload(p,1,OnlyLocal,0);
  1902. // find input
  1903. URL = p->PlayList[p->Current].URL;
  1904. if (!URL[0])
  1905. {
  1906. if (!Silent)
  1907. UpdateTimeouts(p);
  1908. return ERR_NONE;
  1909. }
  1910. GetMime(URL,Mime,TSIZEOF(Mime),&p->HasHost);
  1911. Network = p->HasHost || (URL[0]=='\' && URL[1]=='\');
  1912. if (OnlyLocal && Network)
  1913. {
  1914. if (!Silent)
  1915. UpdateTimeouts(p);
  1916. return ERR_FILE_NOT_FOUND;
  1917. }
  1918. Input = GetStream(URL,Silent);
  1919. if (!Input)
  1920. {
  1921. if (!Silent)
  1922. UpdateTimeouts(p);
  1923. return ERR_NOT_SUPPORTED;
  1924. }
  1925. if (p->PlayList[p->Current].Title[0])
  1926. tcscpy_s(p->Title,TSIZEOF(p->Title),p->PlayList[p->Current].Title);
  1927. else
  1928. URLToTitle(p->Title,TSIZEOF(p->Title),URL);
  1929. memset(p->StreamSkip,0,sizeof(p->StreamSkip));
  1930. UpdateSpeed(p);
  1931. SetTimerNode(p,NodeEnumObject(NULL,SYSTIMER_ID),0); // restore system timer
  1932. p->Input = Input;
  1933. Comment.No = PLAYER_COMMENT;
  1934. Comment.Node = (node*)p;
  1935. p->Input->Set(p->Input,STREAM_COMMENT,&Comment,sizeof(pin));
  1936. p->Input->Set(p->Input,STREAM_SILENT,&Silent,sizeof(Silent));
  1937. Result = p->Input->Set(p->Input,STREAM_URL,URL,TSIZEOF(p->PlayList[p->Current].URL));
  1938. if (Result != ERR_NONE)
  1939. {
  1940. Unload(p,Silent,0,1);
  1941. return Result;
  1942. }
  1943. newstream:
  1944. if (p->Input->Get(p->Input,STREAM_LENGTH,&Length,sizeof(int))!=ERR_NONE)
  1945. Length = -1;
  1946. // find format
  1947. if (!AllocBlock(PROBE_SIZE,&Probe,0,HEAP_ANY))
  1948. {
  1949. Unload(p,Silent,0,1);
  1950. return ERR_OUT_OF_MEMORY;
  1951. }
  1952. ProbeSize = p->Input->ReadBlock(p->Input,&Probe,0,PROBE_SIZE);
  1953. // important: get content type after probe was read 
  1954. if (p->Input->Get(p->Input,STREAM_CONTENTTYPE,ContentType,sizeof(ContentType))!=ERR_NONE)
  1955. ContentType[0] = 0;
  1956. if (ProbeSize > 0)
  1957. int *i;
  1958. if (!p->InputBase)
  1959. {
  1960. node* Process = NULL;
  1961. NodeEnumClassEx(&List,STREAMPROCESS_CLASS,ContentType,URL,Probe.Ptr,ProbeSize);
  1962. for (i=ARRAYBEGIN(List,int);i!=ARRAYEND(List,int);++i)
  1963. {
  1964. Process = NodeCreate(*i);
  1965. if (Process)
  1966. {
  1967. Process->Set(Process,STREAM_COMMENT,&Comment,sizeof(pin));
  1968. Process->Set(Process,STREAM_SILENT,&Silent,sizeof(Silent));
  1969. if (Process->Set(Process,STREAMPROCESS_INPUT,&p->Input,sizeof(node*)) == ERR_NONE)
  1970. break;
  1971. NodeDelete(Process);
  1972. }
  1973. }
  1974. ArrayClear(&List);
  1975. if (Process)
  1976. {
  1977. p->InputBase = p->Input;
  1978. p->Input = (stream*)Process;
  1979. FreeBlock(&Probe);
  1980. goto newstream;
  1981. }
  1982. }
  1983. NodeEnumClassEx(&List,FORMAT_CLASS,ContentType,URL,Probe.Ptr,ProbeSize);
  1984. for (i=ARRAYBEGIN(List,int);i!=ARRAYEND(List,int);++i)
  1985. {
  1986. p->Format = (format*)NodeCreate(*i);
  1987. if (p->Format)
  1988. {
  1989. notify Notify;
  1990. int Align = p->HasHost?1:ALIGN_SIZE;
  1991. bool_t FindSubtitles = !p->HasHost;
  1992. UpdateFormat(p,0); // set buffersize as soon as possible
  1993. p->Format->Set(p->Format,FORMAT_AUTO_READSIZE,&Network,sizeof(bool_t));
  1994. p->Format->Set(p->Format,FORMAT_FILEALIGN,&Align,sizeof(Align));
  1995. p->Format->Set(p->Format,FORMAT_DATAFEED,Probe.Ptr,ProbeSize);
  1996. p->Format->Set(p->Format,FORMAT_FIND_SUBTITLES,&FindSubtitles,sizeof(FindSubtitles));
  1997. p->Format->Set(p->Format,FORMAT_GLOBAL_COMMENT,&Comment,sizeof(pin));
  1998. Notify.This = p;
  1999. Notify.Func = (notifyfunc)UpdateStreamsNotify;
  2000. p->Format->Set(p->Format,FORMAT_UPDATESTREAMS,&Notify,sizeof(Notify));
  2001. Notify.This = p;
  2002. Notify.Func = (notifyfunc)ReleaseStreamsNotify;
  2003. p->Format->Set(p->Format,FORMAT_RELEASESTREAMS,&Notify,sizeof(Notify));
  2004. if (p->Format->Set(p->Format,FORMAT_INPUT,&p->Input,sizeof(stream*)) == ERR_NONE)
  2005. break;
  2006. ReleaseFormat(p);
  2007. if (p->Input->Seek(p->Input,0,SEEK_CUR) > PROBE_SIZE) //maybe less if file smaller as PROBE_SIZE
  2008. p->Input->Seek(p->Input,PROBE_SIZE,SEEK_SET);
  2009. }
  2010. }
  2011. ArrayClear(&List);
  2012. if (!p->Format && !Nested)
  2013. {
  2014. NodeEnumClassEx(&List,PLAYLIST_CLASS,ContentType,URL,Probe.Ptr,ProbeSize);
  2015. if (!ARRAYEMPTY(List))
  2016. {
  2017. int Index = p->PlayListCount;
  2018. if (LoadPlaylist(&p->Player,&List,p->Input,&Index,URL,Probe.Ptr,ProbeSize))
  2019. {
  2020. FreeBlock(&Probe);
  2021. // remove this from playlist
  2022. for (No=p->Current+1;No<p->PlayListCount;++No)
  2023. ListSwap(p,No-1,No);
  2024. SetPlayListCount(p,p->PlayListCount-1);
  2025. return Load(p,Silent,OnlyLocal,1);
  2026. }
  2027. }
  2028. ArrayClear(&List);
  2029. }
  2030. }
  2031. FreeBlock(&Probe);
  2032. if (!p->Format)
  2033. {
  2034. Unload(p,0,0,1);
  2035. if (ProbeSize < 0)
  2036. ShowError(0,ERR_ID,ERR_FILE_NOT_FOUND,URL);
  2037. else
  2038. if (!CheckExts(URL,T("exe:P")))
  2039. ShowError(PLAYER_ID,PLAYER_ID,PLAYER_FORMAT_NOT_FOUND,URL);
  2040. return ERR_NOT_SUPPORTED;
  2041. }
  2042. if (p->Player.CommentByName(p,-1,PlayerComment(COMMENT_REDIRECT),ContentType,TSIZEOF(ContentType)) &&
  2043. ReDirect(p,ContentType,URL,Silent,OnlyLocal,Nested,&Result))
  2044. return Result;
  2045. // only after format initialized (may have reopened http connection with different pragma)
  2046. p->Streaming = p->HasHost && 
  2047. (p->Input->Get(p->Input,STREAM_LENGTH,&Length,sizeof(int))!=ERR_NONE || Length<0);
  2048. p->Timing = 1;
  2049. p->Format->Get(p->Format,FORMAT_TIMING,&p->Timing,sizeof(p->Timing));
  2050. p->SkipAccelFrom = 0;
  2051. p->PlayList[p->Current].Changed = 0;
  2052. p->CurrentChanged = p->HasHost; // force reload when example connection stops
  2053. p->NoMoreInput = 0;
  2054. p->Position = 0;
  2055. p->BufferMax = p->CurrBufferSize2;
  2056. p->Sync = 1; // start with syncing
  2057. p->PosNotify = -1;
  2058. p->MinBuffer = 0;
  2059. Notify(p,PLAYER_TITLE,1);
  2060. Flush(p);
  2061. if (Pos.Num > 0)
  2062. {
  2063. p->SeekAfterSync = Pos; // restore syncaftersync (now we are sure there will a synced event)
  2064. p->SeekAfterSyncPrevKey = PosPrevKey;
  2065. }
  2066. StopLoadMode(p);
  2067. UpdatePlay(p);
  2068. }
  2069. else
  2070. {
  2071. UpdateFormat(p,0);
  2072. UpdateStreams(p,0,0);
  2073. ClearStats(p);
  2074. if (Pos.Num > 0)
  2075. Result = Seek2(p,-1,&Pos,1);
  2076. else
  2077. Result = Seek2(p,0,NULL,0);
  2078. if (Result != ERR_NONE)
  2079. return Result;
  2080. }
  2081. UpdateRunInput(p);
  2082. UpdateRunProcess(p);
  2083. UpdateTimeouts(p);
  2084. #ifdef MULTITHREAD
  2085. EventSet(p->EventProcess); // wakeup input threads (if needed)
  2086. #else
  2087. p->WaitForProcess = 0;
  2088. #endif
  2089. return ERR_NONE;
  2090. }
  2091. static int InputThread(player_base* p);
  2092. static int ProcessThread(player_base* p);
  2093. static void Unlock(player_base* p, bool_t Input)
  2094. {
  2095. #ifdef MULTITHREAD
  2096. //DEBUG_MSG2(DEBUG_PLAYER,T("Unlocked %d %08x"),p->LockCount,GetCurrentThreadId());
  2097. if (Input) 
  2098. {
  2099. LockLeave(p->LockInput);
  2100. --p->LockInputCount;
  2101. assert(p->LockInputCount>=0);
  2102. }
  2103. LockLeave(p->LockProcess);
  2104. --p->LockProcessCount;
  2105. assert(p->LockProcessCount>=0);
  2106. LockLeave(p->Lock);
  2107. #endif
  2108. }
  2109. static void Lock(player_base* p, bool_t Input)
  2110. {
  2111. #ifdef MULTITHREAD
  2112. //DEBUG_MSG2(DEBUG_PLAYER,T("Locked Start %d %08x"),p->LockCount,GetCurrentThreadId());
  2113. assert(p->ProcessLocked != ThreadId() && p->InputLocked != ThreadId());
  2114. LockEnter(p->Lock);
  2115. p->LockProcessCount++;
  2116. LockEnter(p->LockProcess);
  2117. if (Input)
  2118. {
  2119. p->LockInputCount++;
  2120. LockEnter(p->LockInput);
  2121. }
  2122. //DEBUG_MSG(DEBUG_PLAYER,T("Locked End"));
  2123. #endif
  2124. }
  2125. static int UpdateWnd(player_base* p,void* Wnd)
  2126. {
  2127. if (Wnd != p->Wnd)
  2128. {
  2129. p->Wnd = Wnd;
  2130. if (p->Wnd)
  2131. {
  2132. #ifdef MULTITHREAD
  2133. p->InputThread = ThreadCreate(InputThread,p,25);
  2134. p->ProcessThread = ThreadCreate(ProcessThread,p,25);
  2135. p->InputPriority = 0;
  2136. p->ProcessPriority = 0;
  2137. #endif
  2138. Lock(p,1);
  2139. if (p->PlayListCount && !p->DiscardList)
  2140. Load(p,1,1,0);
  2141. else
  2142. {
  2143. SetPlayListCount(p,0);
  2144. p->SeekAfterSync.Num = -1;
  2145. }
  2146. Unlock(p,1);
  2147. }
  2148. else
  2149. {
  2150. Lock(p,1);
  2151. if (!p->KeepList)
  2152. SetPlayListCount(p,0);
  2153. #ifndef REGISTRY_GLOBAL
  2154. NodeRegSave((node*)p);
  2155. NodeRegSave(p->Color);
  2156. NodeRegSave(p->Equalizer);
  2157. #endif
  2158. Unlock(p,1);
  2159. #ifdef MULTITHREAD
  2160. p->RunProcess = 0;
  2161. ThreadPriority(p->ProcessThread,0);
  2162. EventSet(p->EventRunProcess);
  2163. ThreadTerminate(p->ProcessThread);
  2164. p->ProcessThread = NULL;
  2165. p->RunInput = 0;
  2166. ThreadPriority(p->InputThread,0);
  2167. EventSet(p->EventProcess);
  2168. EventSet(p->EventRunInput);
  2169. ThreadTerminate(p->InputThread);
  2170. p->InputThread = NULL;
  2171. #endif
  2172. Unload(p,0,0,0);
  2173. }
  2174. }
  2175. return ERR_NONE;
  2176. }
  2177. static int NextPrev(player_base* p,int Dir,bool_t StopIfEnd,bool_t NotTheSame)
  2178. {
  2179. if (p->PlayListCount > 0)
  2180. {
  2181. int Index = FindCurrentIndex(p);
  2182. int Tries;
  2183. for (Tries=NotTheSame?1:0;Tries<p->PlayListCount;++Tries)
  2184. {
  2185. Index += Dir;
  2186. if (Index >= p->PlayListCount || Index < 0)
  2187. {
  2188. if (StopIfEnd && p->ExitAtEnd)
  2189. Notify(p,PLAYER_EXIT_AT_END,0);
  2190. if (StopIfEnd && !p->Repeat)
  2191. {
  2192. SetPlay(p,1);
  2193. Notify(p,PLAYER_PERCENT,0);
  2194. return ERR_NONE;
  2195. }
  2196. RandomizePlayIndex(p,0);
  2197. Index -= Dir*p->PlayListCount;
  2198. }
  2199. if (p->Current != p->PlayIndex[Index])
  2200. {
  2201. p->Current = p->PlayIndex[Index];
  2202. p->CurrentChanged = 1;
  2203. }
  2204. if (Load(p,1,0,0) == ERR_NONE)
  2205. return ERR_NONE;
  2206. if (!Dir)
  2207. break;
  2208. }
  2209. SetPlay(p,1);
  2210. Notify(p,PLAYER_PERCENT,0);
  2211. }
  2212. else
  2213. Unload(p,0,0,1);
  2214. return ERR_NEED_MORE_DATA;
  2215. }
  2216. static int ProcessThread(player_base* p)
  2217. {
  2218. int Result = ERR_NONE;
  2219. #ifdef MULTITHREAD
  2220. SAFE_BEGIN
  2221. while (p->Wnd)
  2222. {
  2223. LockEnter(p->LockProcess);
  2224. #ifndef NDEBUG
  2225. p->ProcessLocked = ThreadId();
  2226. #endif
  2227. #endif
  2228. if (p->RunProcess)
  2229. {
  2230. processstate State;
  2231. State.Fill = p->Fill;
  2232. p->Timer->Get(p->Timer,TIMER_TIME,&State.Time,sizeof(tick_t));
  2233. //DEBUG_MSG1(DEBUG_PLAYER,T("Process Time:%d"),State.Time);
  2234. Result = p->Format->Process(p->Format,&State);
  2235. if (Result == ERR_SYNCED)
  2236. {
  2237. DEBUG_MSG3(DEBUG_PLAYER,T("Synced: %d (%d,%d)"),State.Time,p->SeekAfterSync.Num,p->SeekAfterSync.Den);
  2238. p->Sync = 0;
  2239. p->Position = State.Time;
  2240. if (State.Time < 0)
  2241. State.Time = 0;
  2242. p->Timer->Set(p->Timer,TIMER_TIME,&State.Time,sizeof(tick_t));
  2243. if (!p->Bench && p->SeekAfterSync.Num<0)
  2244. {
  2245. // enter fill mode (don't stop processing, even if playing if off)
  2246. p->Fill = 1;
  2247. }
  2248. UpdateBuffer(p);
  2249. UpdatePlay(p);
  2250. UpdateRunProcess(p);
  2251. UpdateTimeouts(p); // we are ready to check VOutput and update timeouts
  2252. }
  2253. else
  2254. if (p->Fill && (Result == ERR_END_OF_FILE || Result == ERR_BUFFER_FULL
  2255. || (Result == ERR_NEED_MORE_DATA && (p->NoMoreInput || State.BufferUsedAfter >= p->CurrBufferSize2-2))))
  2256. {
  2257. DEBUG_MSG1(DEBUG_PLAYER,T("Filled: %d"),State.Time);
  2258. if (Result == ERR_END_OF_FILE || Result == ERR_NEED_MORE_DATA)
  2259. Result = ERR_BUFFER_FULL;
  2260. p->Fill = 0;
  2261. UpdatePlay(p);
  2262. UpdateRunProcess(p);
  2263. }
  2264. if (Result == ERR_NEED_MORE_DATA)
  2265. {
  2266. p->BufferMax = p->CurrBufferSize2;
  2267. if (p->NoMoreInput)
  2268. {
  2269. // IOError (Format doesn't know about NoMoreInput)
  2270. Result = ERR_END_OF_FILE;
  2271. }
  2272. #ifdef MULTITHREAD
  2273. else
  2274. if (!p->LoadMode && (p->Play || p->FFwd) && !p->Bench && !p->Sync && !p->Fill)
  2275. {
  2276. if (State.BufferUsedAfter >= (p->CurrBufferSize2>>1))
  2277. {
  2278. if (!p->BufferWarning && State.BufferUsedAfter >= p->CurrBufferSize2-2)
  2279. {
  2280. p->BufferWarning = 1;
  2281. ShowError(PLAYER_ID,PLAYER_ID,PLAYER_BUFFER_WARNING);
  2282. }
  2283. }
  2284. else
  2285. {
  2286. DEBUG_MSG(DEBUG_TEST,T("LoadMode Enter"));
  2287. p->LoadMode = 1;
  2288. p->Fill = 1;
  2289. UpdatePlay(p); // UpdatetPriority(p) called too
  2290. UpdateRunProcess(p);
  2291. UpdateRunInput(p);
  2292. Notify(p,PLAYER_LOADMODE,p->LoadMode);
  2293. }
  2294. }
  2295. #endif
  2296. }
  2297. if (!p->Sync && p->Position>=0)
  2298. p->Position = State.Time;
  2299. #ifdef MULTITHREAD
  2300. LockLeave(p->LockProcess);
  2301. #ifndef NDEBUG
  2302. p->ProcessLocked = 0;
  2303. #endif
  2304. #endif
  2305. if (p->UpdateStreamsNeeded)
  2306. {
  2307. Lock(p,1);
  2308. UpdateStreams(p,-1,1);
  2309. Seek2(p,p->Position>=0?p->Position:0,NULL,0);
  2310. Unlock(p,1);
  2311. Result = ERR_NONE;
  2312. }
  2313. switch (Result)
  2314. {
  2315. case ERR_SYNCED:
  2316. Notify(p,PLAYER_TITLE,0);
  2317. if (p->Current < p->PlayListCount && !p->PlayList[p->Current].Changed && 
  2318. p->PlayList[p->Current].Length<0)
  2319. {
  2320. tick_t Duration;
  2321. Lock(p,0);
  2322. if (p->Format && p->Format->Get(p->Format,FORMAT_DURATION,&Duration,sizeof(Duration))==ERR_NONE)
  2323. UpdateListLength(p,Duration);
  2324. Unlock(p,0);
  2325. }
  2326. if (p->TemporaryHidden)
  2327. {
  2328. Lock(p,0);
  2329. p->TemporaryHidden = 0;
  2330. UpdateVideo(p,p->SeekAfterSync.Num>=0?-1:0);
  2331. Unlock(p,0);
  2332. }
  2333. if (!p->VOutput && p->FullScreen)
  2334. Notify(p,PLAYER_FULLSCREEN,0);
  2335. p->FullScreenAfterSync = 0;
  2336. p->PosNotify = State.Time;
  2337. if (p->SeekAfterSync.Num>=0)
  2338. {
  2339. Lock(p,1);
  2340. if (p->SeekAfterSync.Num>=0) // may have changed
  2341. {
  2342. fraction Pos;
  2343. Pos = p->SeekAfterSync;
  2344. p->SeekAfterSync.Num = -1;
  2345. Seek2(p,-1,&Pos,p->SeekAfterSyncPrevKey);
  2346. }
  2347. Unlock(p,1);
  2348. }
  2349. break;
  2350. case ERR_END_OF_FILE:
  2351. if ((p->Play || p->FFwd || p->Sync) && !p->InSeek)
  2352. {
  2353. Lock(p,1);
  2354. if (p->Bench || p->IOError)
  2355. SetPlay(p,1); // stop benchmarking and show results
  2356. else
  2357. {
  2358. tick_t Duration;
  2359. bool_t NotTheSame = p->Sync || 
  2360. (State.Time < TICKSPERSEC && p->Format &&
  2361. (p->Format->Get(p->Format,FORMAT_DURATION,&Duration,sizeof(Duration))!=ERR_NONE || Duration > TICKSPERSEC*2));
  2362. NextPrev(p,1,1,NotTheSame);
  2363. }
  2364. Unlock(p,1);
  2365. }
  2366. break;
  2367. case ERR_NEED_MORE_DATA:
  2368. //DEBUG_MSG(DEBUG_PLAYER,T("Process Needs More Data Sleep"));
  2369. #ifdef MULTITHREAD
  2370. if (p->InputPriority>0)
  2371. {
  2372. p->InputPriority = 0;
  2373. ThreadPriority(p->InputThread,p->InputPriority);
  2374. }
  2375. p->WaitForProcess = 0;
  2376. EventSet(p->EventProcess); // signal InputThread to coninue
  2377. ThreadSleep(p->Sync?4:25);
  2378. #else
  2379. p->WaitForProcess = 0;
  2380. InputThread(p);
  2381. Result = ERR_NONE; // should not return ERR_BUFFER_FULL
  2382. #endif
  2383. break;
  2384. case ERR_BUFFER_FULL: // no packets processed, we should wait
  2385. //DEBUG_MSG(DEBUG_PLAYER,T("Process Buffer Full Sleep"));
  2386. #ifdef MULTITHREAD
  2387. ThreadSleep(4); // this should be more intelligent...
  2388. #else
  2389. if (!p->WaitForProcess)
  2390. Result = InputThread(p);
  2391. #endif
  2392. break;
  2393. default:
  2394. #ifdef MULTITHREAD
  2395. if (p->WaitForProcess && State.BufferUsedAfter<State.BufferUsedBefore)
  2396. {
  2397. EventSet(p->EventProcess); // signal InputThread to coninue
  2398. if (p->Sync)
  2399. ThreadSleep(5); // invalid media could block everything (going through the file)
  2400. }
  2401. if (p->LockProcessCount > 0 || (!p->Sync && (State.BufferUsedAfter<p->UsedEnough2 || p->Clipping || !p->TimerPlay)))
  2402. {
  2403. DEBUG_MSG(DEBUG_PLAYER,T("Process Sleep"));
  2404. ThreadSleep(0);
  2405. }
  2406. #else
  2407. if (p->WaitForProcess && State.BufferUsedAfter<State.BufferUsedBefore)
  2408. p->WaitForProcess = 0;
  2409. if (!p->WaitForProcess && Result != ERR_DROPPING && !p->Sync && !p->Fill)
  2410. InputThread(p);
  2411. #endif
  2412. break;
  2413. }
  2414. if (State.Time >= 0 && State.Time >= p->PosNotify && !p->Sync && !p->Bench && p->SeekAfterSync.Num<0)
  2415. {
  2416. // should be last, because notify handler could call any player function (load,unload,etc...)
  2417. p->PosNotify = State.Time + p->PosNotifyStep;
  2418. Notify(p,PLAYER_PERCENT,1);
  2419. }
  2420. }
  2421. #ifdef MULTITHREAD
  2422. else
  2423. {
  2424. LockLeave(p->LockProcess);
  2425. #ifndef NDEBUG
  2426. p->ProcessLocked = 0;
  2427. #endif
  2428. EventWait(p->EventRunProcess,-1);
  2429. }
  2430. }
  2431. SAFE_END
  2432. return 0;
  2433. }
  2434. #else
  2435. else
  2436. {
  2437. if (p->RunInput && !p->WaitForProcess)
  2438. Result = InputThread(p); // no decoding process -> still read input in background
  2439. else
  2440. Result = ERR_STOPPED;
  2441. }
  2442. return Result;
  2443. }
  2444. #endif
  2445. static int InputThread(player_base* p)
  2446. {
  2447. int Result = ERR_NONE;
  2448. #ifdef MULTITHREAD
  2449. SAFE_BEGIN
  2450. p->IOError = 0;
  2451. while (p->Wnd)
  2452. {
  2453. LockEnter(p->LockInput);
  2454. #ifndef NDEBUG
  2455. p->InputLocked = ThreadId();
  2456. #endif
  2457. #else
  2458. if (!p->WaitForProcess)
  2459. #endif
  2460. if (p->RunInput)
  2461. {
  2462. int Used;
  2463. Result = p->Format->Read(p->Format,p->BufferMax,&Used);
  2464. if (Result == ERR_DEVICE_ERROR)
  2465. {
  2466. if (++p->IOError >= 20)
  2467. Result = ERR_END_OF_FILE;
  2468. }
  2469. else
  2470. p->IOError = 0;
  2471. if (Result == ERR_END_OF_FILE)
  2472. {
  2473. p->NoMoreInput = 1;
  2474. UpdateRunInput(p);
  2475. }
  2476. //DEBUG_MSG3(-1,T("Input read %d (%d) max:%d"),Used,Result,p->BufferMax);
  2477. #ifdef MULTITHREAD
  2478. LockLeave(p->LockInput);
  2479. #ifndef NDEBUG
  2480. p->InputLocked = 0;
  2481. #endif
  2482. #endif
  2483. switch (Result)
  2484. {
  2485. #ifdef MULTITHREAD
  2486. case ERR_DEVICE_ERROR:
  2487. ThreadSleep(100);
  2488. break;
  2489. #endif
  2490. case ERR_NEED_MORE_DATA:
  2491. ThreadSleep(2);
  2492. break;
  2493. case ERR_BUFFER_FULL:
  2494. if (p->LoadMode)
  2495. {
  2496. Lock(p,0);
  2497. StopLoadMode(p);
  2498. Unlock(p,0);
  2499. }
  2500. if (p->MicroDrive && p->BufferMax==p->CurrBufferSize2)
  2501. {
  2502. // buffer fully loaded, wait until it's almost empty
  2503. p->BufferMax = p->BurstStart;
  2504. //DEBUG_MSG1(-1,T("MicroDrive Full: new max:%d"),p->BufferMax);
  2505. }
  2506. DEBUG_MSG(DEBUG_PLAYER,T("Input waiting for process"));
  2507. p->WaitForProcess = 1;
  2508. #ifdef MULTITHREAD
  2509. EventWait(p->EventProcess,p->RunProcess?2000:-1);
  2510. p->WaitForProcess = 0;
  2511. DEBUG_MSG(DEBUG_PLAYER,T("Input waiting over"));
  2512. #endif
  2513. break;
  2514. case ERR_END_OF_FILE:
  2515. if (p->LoadMode)
  2516. {
  2517. Lock(p,0);
  2518. StopLoadMode(p);
  2519. Unlock(p,0);
  2520. }
  2521. Result = ERR_NONE;
  2522. //no break;
  2523. default:
  2524. if (p->BufferMax != p->CurrBufferSize2)
  2525. {
  2526. // microdrive started loading, change back to full buffer
  2527. //DEBUG_MSG(-1,T("MicroDrive needs data"));
  2528. p->BufferMax = p->CurrBufferSize2;
  2529. }
  2530. if (p->LoadMode && !p->Fill && Used >= (p->VOutput ? (p->Streaming ? VIDEO_STREAMING_UNDERRUN:((p->CurrBufferSize2 * p->UnderRun)/PERCENT_ONE)) : ((p->AudioUnderRun*1024)/BLOCKSIZE)))
  2531. {
  2532. Lock(p,0);
  2533. StopLoadMode(p);
  2534. Unlock(p,0);
  2535. }
  2536. #ifdef MULTITHREAD
  2537. if (p->MicroDrive && Used >= (MINBUFFER/BLOCKSIZE))
  2538. ThreadSleep(2); // try to give some time to ProcessThread during read bursts
  2539. else
  2540. if (p->LockInputCount > 0 || (Used>=p->UsedEnough2+p->MinBuffer*2))
  2541. ThreadSleep(0);
  2542. #endif
  2543. break;
  2544. }
  2545. }
  2546. #ifdef MULTITHREAD
  2547. else
  2548. {
  2549. LockLeave(p->LockInput);
  2550. #ifndef NDEBUG
  2551. p->InputLocked = 0;
  2552. #endif
  2553. EventWait(p->EventRunInput,-1);
  2554. }
  2555. }
  2556. SAFE_END
  2557. return 0;
  2558. }
  2559. #else
  2560. return Result;
  2561. }
  2562. #endif
  2563. static void AddComment(player_base* p,int Stream,const tchar_t* Comment)
  2564. {
  2565. const tchar_t* s = tcschr(Comment,'=');
  2566. if (s)
  2567. {
  2568. uint8_t *i;
  2569. tchar_t Null = 0;
  2570. size_t Name = s-Comment;
  2571. ++s;
  2572. LockEnter(p->LockComment);
  2573. for (i=ARRAYBEGIN(p->Comment,uint8_t);i!=ARRAYEND(p->Comment,uint8_t);i=(uint8_t*)CommentNext(i))
  2574. if (CommentStream(i) == Stream && Name==(int)tcslen(CommentName(i)) &&
  2575. tcsnicmp(CommentName(i),Comment,Name)==0)
  2576. {
  2577. const uint8_t* Next = CommentNext(i);
  2578. if (Next == ARRAYEND(p->Comment,uint8_t))
  2579. {
  2580. ArrayAppend(&p->Comment,NULL,i-Next,512); //shrink
  2581. break;
  2582. }
  2583. *(tchar_t*)i = (tchar_t)INVALID_COMMENT; //invalidate old comment
  2584. }
  2585. ArrayAppend(&p->Comment,&Stream,sizeof(tchar_t),512);
  2586. ArrayAppend(&p->Comment,Comment,sizeof(tchar_t)*Name,512);
  2587. ArrayAppend(&p->Comment,&Null,sizeof(tchar_t),512);
  2588. ArrayAppend(&p->Comment,s,sizeof(tchar_t)*(tcslen(s)+1),512);
  2589. LockLeave(p->LockComment);
  2590. if (tcsnicmp(Comment,PlayerComment(COMMENT_TITLE),Name)==0 || 
  2591. tcsnicmp(Comment,PlayerComment(COMMENT_ARTIST),Name)==0 ||
  2592. tcsnicmp(Comment,PlayerComment(COMMENT_AUTHOR),Name)==0)
  2593. UpdateListTitle(p);
  2594. }
  2595. }
  2596. static tick_t GetPosition(player_base* p,tick_t* OutDuration)
  2597. {
  2598. tick_t Duration = 1;
  2599. tick_t Time = p->Timing?p->Position:-1;
  2600. if (p->Format && p->Format->Get(p->Format,FORMAT_DURATION,&Duration,sizeof(Duration))==ERR_NONE && Duration>=0 && Time>=0)
  2601. {
  2602. if (p->InSeek && p->InSeekPos.Num>=0)
  2603. Time = Scale(Duration,p->InSeekPos.Num,p->InSeekPos.Den);
  2604. else
  2605. if (p->SeekAfterSync.Num>=0)
  2606. Time = Scale(Duration,p->SeekAfterSync.Num,p->SeekAfterSync.Den);
  2607. }
  2608. if (OutDuration)
  2609. *OutDuration = Duration;
  2610. return Time;
  2611. }
  2612. static int GetTimerString(player_base* p,tchar_t* Out,int OutLen)
  2613. {
  2614. tick_t Duration;
  2615. tick_t Time = GetPosition(p,&Duration);
  2616. if (Time<0)
  2617. Out[0] = 0;
  2618. else
  2619. {
  2620. if (p->TimerLeft)
  2621. {
  2622. Time = Time - Duration;
  2623. if (Time >= 0)
  2624. Time = -1;
  2625. }
  2626. TickToString(Out,OutLen,Time,0,0,0);
  2627. }
  2628. return ERR_NONE;
  2629. }
  2630. static int UpdateAllVideoQuality(player_base* p)
  2631. {
  2632. const ref *i;
  2633. for (i=ARRAYBEGIN(p->Ref,ref);i!=ARRAYEND(p->Ref,ref);++i)
  2634. UpdateVideoQuality(p,i->Node);
  2635. return ERR_NONE;
  2636. }
  2637. static int Get(player_base* p, int No, void* Data, int Size)
  2638. {
  2639. int Result = ERR_INVALID_PARAM;
  2640. #ifdef MULTITHREAD
  2641. assert(p->ProcessLocked != ThreadId() && p->InputLocked != ThreadId());
  2642. #endif
  2643. LockEnter(p->Lock);
  2644. if (No >= PLAYER_ARRAY)
  2645. {
  2646. if (No >= PLAYER_LIST_URL && No < PLAYER_LIST_URL+p->PlayListCount)
  2647. {
  2648. No -= PLAYER_LIST_URL;
  2649. tcscpy_s((tchar_t*)Data,Size/sizeof(tchar_t),p->PlayList[No].URL);
  2650. Result = ERR_NONE;
  2651. }
  2652. else
  2653. if (No >= PLAYER_LIST_TITLE && No < PLAYER_LIST_TITLE+p->PlayListCount)
  2654. {
  2655. No -= PLAYER_LIST_TITLE;
  2656. tcscpy_s((tchar_t*)Data,Size/sizeof(tchar_t),p->PlayList[No].Title);
  2657. Result = ERR_NONE;
  2658. }
  2659. else
  2660. if (No >= PLAYER_LIST_AUTOTITLE && No < PLAYER_LIST_AUTOTITLE+p->PlayListCount)
  2661. {
  2662. No -= PLAYER_LIST_AUTOTITLE;
  2663. if (p->PlayList[No].Title[0])
  2664. tcscpy_s((tchar_t*)Data,Size/sizeof(tchar_t),p->PlayList[No].Title);
  2665. else
  2666. URLToTitle((tchar_t*)Data,Size/sizeof(tchar_t),p->PlayList[No].URL);
  2667. Result = ERR_NONE;
  2668. }
  2669. else
  2670. if (No >= PLAYER_LIST_LENGTH && No < PLAYER_LIST_LENGTH+p->PlayListCount)
  2671. {
  2672. No -= PLAYER_LIST_LENGTH;
  2673. *(tick_t*)Data = p->PlayList[No].Length;
  2674. Result = ERR_NONE;
  2675. }
  2676. }
  2677. else
  2678. switch (No)
  2679. {
  2680. case PLAYER_VIDEO_OVERLAY: GETVALUE(p->Overlay,bool_t); break;
  2681. case PLAYER_BUFFER_SIZE: GETVALUE((p->BufferSize2*BLOCKSIZE)/1024,int); break;
  2682. case PLAYER_MD_BUFFER_SIZE: GETVALUE((p->MDBufferSize2*BLOCKSIZE)/1024,int); break;
  2683. case PLAYER_BURSTSTART: GETVALUE((p->BurstStart*BLOCKSIZE)/1024,int); break;
  2684. case PLAYER_MICRODRIVE: GETVALUE(p->MicroDrive,bool_t); break;
  2685. case PLAYER_UNDERRUN: GETVALUE(p->UnderRun,int); break;
  2686. case PLAYER_AUDIO_UNDERRUN: GETVALUE(p->AudioUnderRun,int); break;
  2687. case PLAYER_REPEAT: GETVALUE(p->Repeat,bool_t); break;
  2688. case PLAYER_SHUFFLE: GETVALUE(p->Shuffle,bool_t); break;
  2689. case PLAYER_PLAYATOPEN: GETVALUE(p->PlayAtOpen,bool_t); break;
  2690. case PLAYER_PLAYATOPEN_FULL: GETVALUE(p->PlayAtOpenFull,bool_t); break;
  2691. case PLAYER_EXIT_AT_END: GETVALUE(p->ExitAtEnd,bool_t); break;
  2692. case PLAYER_KEEPPLAY_VIDEO: GETVALUE(p->KeepPlayVideo,bool_t); break;
  2693. case PLAYER_SHOWINBACKGROUND: GETVALUE(p->ShowInBackground,bool_t); break;
  2694. case PLAYER_SINGLECLICKFULLSCREEN: GETVALUE(p->SingleClickFullScreen,bool_t); break;
  2695. case PLAYER_KEEPPLAY_AUDIO: GETVALUE(p->KeepPlayAudio,bool_t); break;
  2696. case PLAYER_KEEPLIST: GETVALUE(p->KeepList,bool_t); break;
  2697. case PLAYER_MOVEBACK_STEP: GETVALUE(p->MoveBack,tick_t); break;
  2698. case PLAYER_MOVEFFWD_STEP: GETVALUE(p->MoveFFwd,tick_t); break;
  2699. case PLAYER_PLAY: GETVALUE(p->Play,bool_t); break;
  2700. case PLAYER_FFWD: GETVALUE(p->FFwd,bool_t); break;
  2701. case PLAYER_PLAY_SPEED: GETVALUE(p->PlaySpeed,fraction); break;
  2702. case PLAYER_FFWD_SPEED: GETVALUE(p->FFwdSpeed,fraction); break;
  2703. case PLAYER_TITLE: GETSTRING(p->Title); break;
  2704. case PLAYER_INPUT: GETVALUE(p->Input,stream*); break;
  2705. case PLAYER_FORMAT: GETVALUE(p->Format,format*); break;
  2706. case PLAYER_AOUTPUTID: GETVALUE(p->AOutputId,int); break;
  2707. case PLAYER_VOUTPUTID: GETVALUE(p->VOutputId,int); break;
  2708. case PLAYER_AOUTPUTID_MAX: GETVALUE(p->AOutputIdMax,int); break;
  2709. case PLAYER_VOUTPUTID_MAX: GETVALUE(p->VOutputIdMax,int); break;
  2710. case PLAYER_AOUTPUT: GETVALUE(p->AOutput,node*); break;
  2711. case PLAYER_VOUTPUT: GETVALUE(p->VOutput,node*); break;
  2712. case PLAYER_LIST_COUNT: GETVALUE(p->PlayListCount,int); break;
  2713. case PLAYER_LIST_CURRENT: GETVALUE(p->Current,int); break;
  2714. case PLAYER_LIST_CURRIDX: GETVALUE(FindCurrentIndex(p),int); break;
  2715. case PLAYER_VIDEO_ACCEL: GETVALUE(p->VideoAccel,bool_t); break;
  2716. case PLAYER_AUDIO_QUALITY: GETVALUE(p->AudioQuality,int); break;
  2717. case PLAYER_FULLSCREEN: GETVALUE(p->FullScreen,bool_t); break;
  2718. case PLAYER_AUTOPREROTATE: GETVALUE(p->AutoPreRotate,bool_t); break;
  2719. case PLAYER_SKIN_VIEWPORT: GETVALUE(p->SkinViewport,rect); break;
  2720. case PLAYER_CLIPPING: GETVALUE(p->Clipping,bool_t); break;
  2721. case PLAYER_ASPECT: GETVALUE(p->Aspect,fraction); break;
  2722. case PLAYER_STEREO: GETVALUE(p->Stereo,int); break;
  2723. case PLAYER_FULL_ZOOM: GETVALUE(p->FullZoom,fraction); break;
  2724. case PLAYER_SKIN_ZOOM: GETVALUE(p->SkinZoom,fraction); break;
  2725. case PLAYER_SMOOTH50: GETVALUE(p->SmoothZoom50,bool_t); break;
  2726. case PLAYER_SMOOTHALWAYS: GETVALUE(p->SmoothZoomAlways,bool_t); break;
  2727. case PLAYER_FULL_DIR: GETVALUE(p->FullDir,int); break;
  2728. case PLAYER_SKIN_DIR: GETVALUE(p->SkinDir,int); break;
  2729. case PLAYER_REL_DIR: GETVALUE(p->RelDir,int); break;
  2730. case PLAYER_BENCHMARK_SRC: GETVALUE(p->BenchSrc,point); break;
  2731. case PLAYER_BENCHMARK_DST: GETVALUE(p->BenchDst,point); break;
  2732. case PLAYER_BENCHMARK: GETVALUECOND(p->BenchTime,tick_t,!p->Bench); break;
  2733. case PLAYER_POSITION: GETVALUECOND(GetPosition(p,NULL),tick_t,p->Position>=0); break;
  2734. case PLAYER_LOADMODE: GETVALUE(p->LoadMode,bool_t); break;
  2735. case PLAYER_NOTIFY: GETVALUE(p->Notify,notify); break;
  2736. case PLAYER_LIST_NOTIFY: GETVALUE(p->ListNotify,notify); break;
  2737. case PLAYER_VSTREAM: GETVALUE(p->Selected[PACKET_VIDEO],int); break;
  2738. case PLAYER_ASTREAM: GETVALUE(p->Selected[PACKET_AUDIO],int); break;
  2739. case PLAYER_SUBSTREAM: GETVALUE(p->Selected[PACKET_SUBTITLE],int); break;
  2740. case PLAYER_SYNCING: GETVALUE(p->Sync || !p->Format,bool_t); break;
  2741. case PLAYER_BACKGROUND: GETVALUE(p->Background,bool_t); break;
  2742. case PLAYER_FOREGROUND: GETVALUE(p->Foreground,bool_t); break;
  2743. case PLAYER_STREAMING: GETVALUE(p->Streaming,bool_t) break;
  2744. case PLAYER_INSEEK: GETVALUE(p->InSeek,bool_t); break;
  2745. case PLAYER_DISCARDLIST: GETVALUE(p->DiscardList,bool_t); break;
  2746. case PLAYER_VIDEO_QUALITY: GETVALUE(p->VideoQuality,int); if (!SupportVQ(p)) Result = ERR_NOT_SUPPORTED; break;
  2747. case PLAYER_PERCENT:
  2748. if (p->Format && p->Input)
  2749. {
  2750. fraction* Percent = (fraction*)Data;
  2751. tick_t Duration;
  2752. int FilePos;
  2753. int FileSize;
  2754. tick_t Position = p->Position;
  2755. if (p->InSeek && p->InSeekPos.Num>=0)
  2756. {
  2757. Percent->Num = p->InSeekPos.Num;
  2758. Percent->Den = p->InSeekPos.Den;
  2759. Result = ERR_NONE;
  2760. }
  2761. else
  2762. if (p->SeekAfterSync.Num>=0)
  2763. {
  2764. Percent->Num = p->SeekAfterSync.Num;
  2765. Percent->Den = p->SeekAfterSync.Den;
  2766. Result = ERR_NONE;
  2767. }
  2768. else
  2769. if (Position >= 0 && p->Format->Get(p->Format,FORMAT_DURATION,&Duration,sizeof(Duration))==ERR_NONE)
  2770. {
  2771. UpdateListLength(p,Duration);
  2772. Percent->Num = Position;
  2773. Percent->Den = Duration;
  2774. Result = ERR_NONE;
  2775. }
  2776. else
  2777. if (Position==0 && !p->Streaming && p->Timing)
  2778. {
  2779. Percent->Num = 0;
  2780. Percent->Den = 0;
  2781. Result = ERR_NONE;
  2782. }
  2783. else
  2784. if (p->Input->Get(p->Input,STREAM_LENGTH,&FileSize,sizeof(FileSize))==ERR_NONE &&
  2785. p->Format->Get(p->Format,FORMAT_FILEPOS,&FilePos,sizeof(FilePos))==ERR_NONE)
  2786. {
  2787. Percent->Num = FilePos;
  2788. Percent->Den = FileSize;
  2789. Result = ERR_NONE;
  2790. }
  2791. }
  2792. break;
  2793. case PLAYER_CURRENTDIR: GETSTRING(p->CurrentDir); break;
  2794. case PLAYER_MUTE: GETVALUE(RefreshAudio(p)->Mute,bool_t); break;
  2795. case PLAYER_VOLUME: GETVALUE(RefreshAudio(p)->Volume,int); break;
  2796. case PLAYER_PAN: GETVALUE(RefreshAudio(p)->Pan,int); break;
  2797. case PLAYER_PREAMP: GETVALUE(p->PreAmp,int); break;
  2798. case PLAYER_TIMER_LEFT: GETVALUE(p->TimerLeft,bool_t); break;
  2799. case PLAYER_TIMER: Result = GetTimerString(p,Data,Size/sizeof(tchar_t)); break;
  2800. case PLAYER_DURATION:
  2801. if (p->Format)
  2802. {
  2803. Result = p->Format->Get(p->Format,FORMAT_DURATION,Data,Size);
  2804. if (Result == ERR_NONE) 
  2805. UpdateListLength(p,*(tick_t*)Data);
  2806. }
  2807. break;
  2808. }
  2809. LockLeave(p->Lock);
  2810. return Result;
  2811. }
  2812. static int UpdateInSeek(player_base* p)
  2813. {
  2814. if (p->Format && p->Input && p->Timer)
  2815. {
  2816. fraction Pos = p->SeekAfterSync;
  2817. p->InSeekPos.Num = -1;
  2818. p->SeekAfterSync.Num = -1;
  2819. if (!p->InSeek)
  2820. {
  2821. if (Pos.Num>=0)
  2822. {
  2823. Lock(p,1);
  2824. Seek2(p,-1,&Pos,p->SeekAfterSyncPrevKey);
  2825. Unlock(p,1);
  2826. }
  2827. else
  2828. Notify(p,PLAYER_PERCENT,0);
  2829. }
  2830. UpdatePlay(p);
  2831. }
  2832. return ERR_NONE;
  2833. }
  2834. static int AddCodecSkip(player_base* p,const pin* Pin)
  2835. {
  2836. packetformat Format;
  2837. if (Pin->Node)
  2838. {
  2839. if (p->CodecSkipCount < MAXSKIP && 
  2840. Pin->Node->Get(Pin->Node,Pin->No|PIN_FORMAT,&Format,sizeof(Format))==ERR_NONE)
  2841. {
  2842. array List;
  2843. const int *i;
  2844. PacketFormatEnumClass(&List,&Format);
  2845. for (i=ARRAYBEGIN(List,int);i!=ARRAYEND(List,int);++i)
  2846. if (!IsCodecSkip(p,*i) && *i != Pin->Node->Class)
  2847. {
  2848. // found an alternative
  2849. ArrayClear(&List);
  2850. p->CodecSkip[p->CodecSkipCount++] = Pin->Node->Class;
  2851. p->UpdateStreamsNeeded = 1;
  2852. return ERR_NONE;
  2853. }
  2854. ArrayClear(&List);
  2855. }
  2856. else
  2857. {
  2858. datadef DataDef;
  2859. if (NodeDataDef(Pin->Node,Pin->No,&DataDef) && DataDef.Type==TYPE_NODE && DataDef.Format1==IDCT_CLASS &&
  2860. p->VideoAccel && p->SkipAccelFrom != Pin->Node->Class)
  2861. {
  2862. p->SkipAccelFrom = Pin->Node->Class;
  2863. p->UpdateStreamsNeeded = 1;
  2864. return ERR_NONE;
  2865. }
  2866. }
  2867. }
  2868. return ERR_NOT_SUPPORTED;
  2869. }
  2870. static int SetCurrent(player_base* p,int i,bool_t Index)
  2871. {
  2872. if (i>=p->PlayListCount)
  2873. return ERR_INVALID_PARAM;
  2874. if (i<0)
  2875. Unload(p,0,0,1);
  2876. else
  2877. {
  2878. if (p->Current != i)
  2879. {
  2880. p->Current = i;
  2881. p->CurrentChanged = 1;
  2882. if (Index)
  2883. RandomizePlayIndex(p,1);
  2884. }
  2885. if (p->Wnd)
  2886. {
  2887. int Result = Load(p,0,0,0);
  2888. if (Result == ERR_FILE_NOT_FOUND)
  2889. Result = NextPrev(p,1,1,1);
  2890. if (Result==ERR_NONE && p->Format && (p->Streaming || p->PlayAtOpen || p->PlayAtOpenFull))
  2891. {
  2892. p->FullScreenAfterSync = p->PlayAtOpenFull;
  2893. if (p->FullScreenAfterSync && IsVideo(p) && !p->FullScreen)
  2894. Notify(p,PLAYER_FULLSCREEN,1);
  2895. p->Play = 1;
  2896. p->FFwd = 0;
  2897. SetPlay(p,0);
  2898. }
  2899. }
  2900. }
  2901. return ERR_NONE;
  2902. }
  2903. static NOINLINE bool_t CloseTo(tick_t Prev,tick_t Chapter,tick_t Pos)
  2904. {
  2905. tick_t Limit;
  2906. if (Prev<0) return 0;
  2907. Limit = abs(Chapter-Prev)/32;
  2908. if (Limit>10*TICKSPERSEC)
  2909. Limit=10*TICKSPERSEC;
  2910. return abs(Pos-Chapter)<Limit;
  2911. }
  2912. static NOINLINE tick_t FindChapter(player_base* p,int Dir)
  2913. {
  2914. int No;
  2915. if (p->Position>=0)
  2916. {
  2917. if (Dir<0)
  2918. for (No=MAXCHAPTER-1;No>=0;--No)
  2919. {
  2920. tick_t Prev = PlayerGetChapter(&p->Player,No-1,NULL,0);
  2921. tick_t Chapter = PlayerGetChapter(&p->Player,No,NULL,0);
  2922. if (Chapter >= 0 && Chapter < p->Position && !CloseTo(Prev,Chapter,p->Position))
  2923. return Chapter;
  2924. }
  2925. else
  2926. {
  2927. tick_t Prev = -1;
  2928. for (No=1;No<MAXCHAPTER;++No)
  2929. {
  2930. tick_t Chapter = PlayerGetChapter(&p->Player,No,NULL,0);
  2931. if (Chapter >= 0 && Chapter > p->Position && !CloseTo(Prev,Chapter,p->Position))
  2932. return Chapter;
  2933. Prev = Chapter;
  2934. }
  2935. }
  2936. }
  2937. return -1;
  2938. }
  2939. static int UpdateShowInBackground(player_base* p)
  2940. {
  2941. UpdateBackground(p);
  2942. return UpdateVideo(p,0);
  2943. }
  2944. static void UpdateSoftVolume(player_base* p)
  2945. {
  2946. bool_t SoftVolume = QueryAdvanced(ADVANCED_SYSTEMVOLUME);
  2947. if (p->SoftVolume != SoftVolume)
  2948. {
  2949. p->SoftVolume = SoftVolume;
  2950. Lock(p,0);
  2951. UpdateAudio(p);
  2952. Unlock(p,0);
  2953. }
  2954. }
  2955. static int Set(player_base* p, int No, const void* Data, int Size)
  2956. {
  2957. tick_t t;
  2958. int New,Old;
  2959. int Result = ERR_INVALID_PARAM;
  2960. if (No >= PLAYER_COMMENT && No < PLAYER_COMMENT+MAXSTREAM)
  2961. {
  2962. AddComment(p,No-PLAYER_COMMENT,(const tchar_t*)Data);
  2963. return ERR_NONE;
  2964. }
  2965. switch (No)
  2966. {
  2967. case NODE_HIBERNATE:
  2968. return Result;
  2969. case NODE_CRASH:
  2970. #ifdef MULTITHREAD
  2971. p->RunProcess = 0;
  2972. p->RunInput = 0;
  2973. p->Lock = NULL;
  2974. p->LockInput = NULL;
  2975. p->LockProcess = NULL;
  2976. p->EventProcess = NULL;
  2977. p->EventRunInput = NULL;
  2978. p->EventRunProcess = NULL;
  2979. #ifndef NDEBUG
  2980. p->ProcessLocked = 0;
  2981. p->InputLocked = 0;
  2982. #endif
  2983. #endif
  2984. return ERR_NONE;
  2985. case PLAYER_NOT_SUPPORTED_DATA:
  2986. // called by process thread
  2987. assert(Size == sizeof(pin));
  2988. return AddCodecSkip(p,(const pin*)Data);
  2989. case NODE_SETTINGSCHANGED:
  2990. UpdateWnd(p,Context()->Wnd);
  2991. UpdatePriority(p);
  2992. UpdateEqualizer(p);
  2993. UpdateSoftVolume(p);
  2994. return ERR_NONE;
  2995. case PLAYER_PERCENT:
  2996. assert(Size == sizeof(fraction));
  2997. return InSeek(p,-1,(const fraction*)Data,1);
  2998. case PLAYER_POSITION:
  2999. assert(Size == sizeof(tick_t));
  3000. t = *(const tick_t*)Data;
  3001. if (t<0) t=0;
  3002. return InSeek(p,t,NULL,1);
  3003. case PLAYER_BACKGROUND: SETVALUECMP(p->Background,bool_t,UpdateBackground(p),EqBool); return Result;
  3004. case PLAYER_POWEROFF: SETVALUECMP(p->PowerOff,bool_t,UpdatePowerOff(p),EqBool); return Result;
  3005. }
  3006. Lock(p,0);
  3007. if (No >= PLAYER_LIST_URL && No <= PLAYER_LIST_URL+p->PlayListCount)
  3008. {
  3009. No -= PLAYER_LIST_URL;
  3010. if (No == p->PlayListCount)
  3011. SetPlayListCount(p,No+1);
  3012. if (No < p->PlayListCount)
  3013. {
  3014. if (!Size) Data = T("");
  3015. p->PlayList[No].Changed = 1;
  3016. tcscpy_s(p->PlayList[No].URL,TSIZEOF(p->PlayList[No].URL),(tchar_t*)Data);
  3017. NotifyList(p);
  3018. Result = ERR_NONE;
  3019. }
  3020. }
  3021. else
  3022. if (No >= PLAYER_LIST_TITLE && No <= PLAYER_LIST_TITLE+p->PlayListCount)
  3023. {
  3024. No -= PLAYER_LIST_TITLE;
  3025. if (No == p->PlayListCount)
  3026. SetPlayListCount(p,No+1);
  3027. if (No < p->PlayListCount)
  3028. {
  3029. if (!Size) Data = T("");
  3030. tcscpy_s(p->PlayList[No].Title,TSIZEOF(p->PlayList[No].Title),(tchar_t*)Data);
  3031. NotifyList(p);
  3032. Result = ERR_NONE;
  3033. }
  3034. }
  3035. else
  3036. if (No >= PLAYER_LIST_LENGTH && No <= PLAYER_LIST_LENGTH+p->PlayListCount)
  3037. {
  3038. No -= PLAYER_LIST_LENGTH;
  3039. if (No == p->PlayListCount)
  3040. SetPlayListCount(p,No+1);
  3041. if (No < p->PlayListCount)
  3042. {
  3043. p->PlayList[No].Length = *(tick_t*)Data;
  3044. NotifyList(p);
  3045. Result = ERR_NONE;
  3046. }
  3047. }
  3048. else
  3049. switch (No)
  3050. {
  3051. case PLAYER_TIMER_LEFT: SETVALUE(p->TimerLeft,bool_t,ERR_NONE); break;
  3052. case PLAYER_PLAY_SPEED: SETVALUE(p->PlaySpeed,fraction,UpdateSpeed(p)); break;
  3053. case PLAYER_FFWD_SPEED: SETVALUE(p->FFwdSpeed,fraction,UpdateSpeed(p)); break;
  3054. case PLAYER_REPEAT: SETVALUE(p->Repeat,bool_t,ERR_NONE); break;
  3055. case PLAYER_PLAYATOPEN: SETVALUE(p->PlayAtOpen,bool_t,ERR_NONE); break;
  3056. case PLAYER_PLAYATOPEN_FULL: SETVALUE(p->PlayAtOpenFull,bool_t,ERR_NONE); break;
  3057. case PLAYER_EXIT_AT_END: SETVALUE(p->ExitAtEnd,bool_t,ERR_NONE); break;
  3058. case PLAYER_KEEPPLAY_AUDIO: SETVALUE(p->KeepPlayAudio,bool_t,ERR_NONE); break;
  3059. case PLAYER_KEEPPLAY_VIDEO: SETVALUE(p->KeepPlayVideo,bool_t,ERR_NONE); break;
  3060. case PLAYER_SHOWINBACKGROUND: SETVALUE(p->ShowInBackground,bool_t,UpdateShowInBackground(p)); break;
  3061. case PLAYER_SINGLECLICKFULLSCREEN: SETVALUE(p->SingleClickFullScreen,bool_t,ERR_NONE); break;
  3062. case PLAYER_KEEPLIST: SETVALUE(p->KeepList,bool_t,ERR_NONE); break;
  3063. case PLAYER_MOVEBACK_STEP: SETVALUE(p->MoveBack,tick_t,ERR_NONE); break;
  3064. case PLAYER_MOVEFFWD_STEP: SETVALUE(p->MoveFFwd,tick_t,ERR_NONE); break;
  3065. case PLAYER_SHUFFLE: SETVALUE(p->Shuffle,bool_t,RandomizePlayIndex(p,1)); break;
  3066. case PLAYER_AUDIO_QUALITY: SETVALUECMP(p->AudioQuality,int,UpdateAudio(p),EqInt); break;
  3067. case PLAYER_VIDEO_QUALITY: SETVALUE(p->VideoQuality,int,UpdateAllVideoQuality(p)); break;
  3068. case PLAYER_FULLSCREEN: SETVALUECMP(p->FullScreen,bool_t,ERR_NONE,EqBool); break;
  3069. case PLAYER_AUTOPREROTATE: SETVALUECMP(p->AutoPreRotate,bool_t,UpdateVideo(p,0),EqBool); break;
  3070. case PLAYER_SKIN_VIEWPORT: SETVALUECMP(p->SkinViewport,rect,ERR_NONE,EqRect); break;
  3071. case PLAYER_CLIPPING: SETVALUECMP(p->Clipping,bool_t,UpdateVideo(p,0),EqBool); break;
  3072. case PLAYER_ASPECT: SETVALUECMP(p->Aspect,fraction,UpdateVideo(p,0),EqFrac); break;
  3073. case PLAYER_STEREO: SETVALUECMP(p->Stereo,int,UpdateAudio(p),EqInt); break;
  3074. case PLAYER_FULL_ZOOM: SETVALUECMP(p->FullZoom,fraction,UpdateVideo(p,0),EqFrac); break;
  3075. case PLAYER_SKIN_ZOOM: SETVALUECMP(p->SkinZoom,fraction,UpdateVideo(p,0),EqFrac); break;
  3076. case PLAYER_SMOOTH50: SETVALUECMP(p->SmoothZoom50,bool_t,UpdateVideo(p,0),EqBool); break;
  3077. case PLAYER_SMOOTHALWAYS: SETVALUECMP(p->SmoothZoomAlways,bool_t,UpdateVideo(p,0),EqBool); break;
  3078. case PLAYER_FULL_DIR: SETVALUECMP(p->FullDir,int,UpdateVideo(p,0),EqInt); break;
  3079. case PLAYER_SKIN_DIR: SETVALUECMP(p->SkinDir,int,UpdateVideo(p,0),EqInt); break;
  3080. case PLAYER_VIDEO_ACCEL: SETVALUE(p->VideoAccel,bool_t,ERR_NONE); break;
  3081. case PLAYER_VSTREAM: SETVALUECMP(p->Selected[PACKET_VIDEO],int,UpdateStreamsMask(p),EqInt); break;
  3082. case PLAYER_ASTREAM: SETVALUECMP(p->Selected[PACKET_AUDIO],int,UpdateStreamsMask(p),EqInt); break;
  3083. case PLAYER_SUBSTREAM: SETVALUECMP(p->Selected[PACKET_SUBTITLE],int,UpdateStreamsMask(p),EqInt); break;
  3084. case PLAYER_NOTIFY: SETVALUENULL(p->Notify,notify,ERR_NONE,p->Notify.Func=NULL); break;
  3085. case PLAYER_LIST_NOTIFY: SETVALUENULL(p->ListNotify,notify,ERR_NONE,p->ListNotify.Func=NULL); break;
  3086. case PLAYER_FOREGROUND: SETVALUECMP(p->Foreground,bool_t,UpdateForeground(p),EqBool); break;
  3087. case PLAYER_INSEEK: SETVALUECMP(p->InSeek,bool_t,UpdateInSeek(p),EqBool); break;
  3088. case PLAYER_MUTE: SETVALUECMP(p->Mute,bool_t,UpdateAudio(p),EqBool); break;
  3089. case PLAYER_CURRENTDIR: SETSTRING(p->CurrentDir); break;
  3090. case PLAYER_DISCARDLIST: SETVALUE(p->DiscardList,bool_t,ERR_NONE); break;
  3091. case PLAYER_PREAMP: SETVALUECMP(p->PreAmp,int,UpdateAudio(p),EqInt); break;
  3092. case PLAYER_PAN: SETVALUECMP(p->Pan,int,UpdateAudio(p),EqInt); break;
  3093. case PLAYER_VOLUME: SETVALUECMP(p->Volume,int,UpdateVolume(p),EqInt); break; // need process locking for software win32 waveout pausing
  3094. case PLAYER_UPDATEVIDEO: 
  3095. Result = UpdateVideo(p,0);
  3096. break;
  3097. case PLAYER_ROTATEEND: 
  3098. p->Rotating = 0;
  3099. Result = UpdateVideo(p,0); 
  3100. break;
  3101. case PLAYER_RESETVIDEO:
  3102. if (p->VOutput)
  3103. p->VOutput->Set(p->VOutput,VOUT_RESET,NULL,0);
  3104. break;
  3105. case PLAYER_ROTATEBEGIN:
  3106. p->Rotating = 1;
  3107. if (p->VOutput)
  3108. {
  3109. bool_t Visible = 0;
  3110. p->VOutput->Set(p->VOutput,VOUT_VISIBLE,&Visible,sizeof(Visible));
  3111. }
  3112. break;
  3113. case PLAYER_VOUTPUTID: 
  3114. assert(Size==sizeof(int));
  3115. Old = p->VOutputId;
  3116. New = *(int*)Data;
  3117. if (New && !NodeEnumClass(NULL,New)) // old driver removed
  3118. {
  3119. New = p->VOutputIdMax;
  3120. p->VideoAccel = VOutIDCT(New);
  3121. }
  3122. p->VOutputId = New;
  3123. p->SkipAccelFrom = 0;
  3124. if (!VOutIDCT(New))
  3125. p->VideoAccel = 0;
  3126. UpdateStreams(p,Old==0,0);
  3127. break;
  3128. case PLAYER_AOUTPUTID: 
  3129. assert(Size==sizeof(int));
  3130. Old = p->AOutputId;
  3131. New = *(int*)Data;
  3132. if (New && !NodeEnumClass(NULL,New)) // old driver removed
  3133. New = p->AOutputIdMax;
  3134. p->AOutputId = New;
  3135. UpdateStreams(p,Old==0,0);
  3136. break;
  3137. case PLAYER_UPDATEEQUALIZER:
  3138. Result = UpdateEqualizer(p);
  3139. break;
  3140. case PLAYER_VOUTPUTID_MAX: 
  3141. assert(Size==sizeof(int));
  3142. if (p->VOutputIdMax != *(int*)Data && p->VOutputId && p->VOutputIdMax && p->VOutputId != p->VOutputIdMax)
  3143. {
  3144. // new highest priority video driver added. use it
  3145. p->VOutputId = p->VOutputIdMax;
  3146. p->VideoAccel = VOutIDCT(p->VOutputId);
  3147. UpdateStreams(p,0,0);
  3148. }
  3149. Result = ERR_NONE;
  3150. break;
  3151. case PLAYER_AOUTPUTID_MAX: 
  3152. assert(Size==sizeof(int));
  3153. if (p->AOutputIdMax != *(int*)Data && p->AOutputId && p->AOutputIdMax && p->AOutputId != p->AOutputIdMax)
  3154. {
  3155. // new highest priority audio driver added. use it
  3156. p->AOutputId = p->AOutputIdMax;
  3157. UpdateStreams(p,0,0);
  3158. }
  3159. Result = ERR_NONE;
  3160. break;
  3161. case PLAYER_MOVEBACK:
  3162. case PLAYER_MOVEFFWD:
  3163. if (p->Format && p->Input)
  3164. {
  3165. int FilePos;
  3166. int FileSize;
  3167. tick_t Position = GetPosition(p,NULL);
  3168. fraction Percent;
  3169. if (Position >= 0)
  3170. {
  3171. if (No == PLAYER_MOVEBACK)
  3172. Position -= p->MoveBack;
  3173. else
  3174. Position += p->MoveFFwd;
  3175. if (Position<0)
  3176. Position=0;
  3177. Result = InSeek(p,Position,NULL,No == PLAYER_MOVEBACK);
  3178. }
  3179. else
  3180. if (p->Input->Get(p->Input,STREAM_LENGTH,&FileSize,sizeof(FileSize))==ERR_NONE &&
  3181. p->Format->Get(p->Format,FORMAT_FILEPOS,&FilePos,sizeof(FilePos))==ERR_NONE)
  3182. {
  3183. if (No == PLAYER_MOVEBACK)
  3184. FilePos -= FileSize/256;
  3185. else
  3186. FilePos += FileSize/256;
  3187. Percent.Num = FilePos;
  3188. Percent.Den = FileSize;
  3189. if (Percent.Num<0)
  3190. Percent.Num=0;
  3191. Result = InSeek(p,-1,&Percent,No == PLAYER_MOVEBACK);
  3192. }
  3193. else
  3194. Result = p->Player.Set(&p->Player,No == PLAYER_MOVEBACK?PLAYER_PREV:PLAYER_NEXT,NULL,0);
  3195. }
  3196. break; 
  3197. default:
  3198. // inputthread locking needed for these
  3199. Lock(p,1);
  3200. switch (No)
  3201. {
  3202. case PLAYER_BUFFER_SIZE:
  3203. assert(Size==sizeof(int));
  3204. p->BufferSize2 = (*(int*)Data *1024)/BLOCKSIZE;
  3205. if (p->BufferSize2 < MINBUFFER/BLOCKSIZE)
  3206. p->BufferSize2 = MINBUFFER/BLOCKSIZE;
  3207. Result = UpdateFormat(p,1); 
  3208. break;
  3209. case PLAYER_MD_BUFFER_SIZE: 
  3210. assert(Size==sizeof(int));
  3211. p->MDBufferSize2 = (*(int*)Data *1024)/BLOCKSIZE;
  3212. if (p->MDBufferSize2 < MINBUFFER/BLOCKSIZE)
  3213. p->MDBufferSize2 = MINBUFFER/BLOCKSIZE;
  3214. Result = UpdateFormat(p,1); 
  3215. break;
  3216. case PLAYER_BURSTSTART:
  3217. assert(Size==sizeof(int));
  3218. p->BurstStart = (*(int*)Data *1024)/BLOCKSIZE;
  3219. if (p->BurstStart < MINBUFFER/BLOCKSIZE)
  3220. p->BurstStart = MINBUFFER/BLOCKSIZE;
  3221. Result = ERR_NONE; 
  3222. break;
  3223. case PLAYER_BENCHMARK:
  3224. if (p->Format && p->Input)
  3225. StartBench(p);
  3226. break;
  3227. case PLAYER_PLAY:
  3228. if (Size == sizeof(bool_t))
  3229. {
  3230. if (*(bool_t*)Data)
  3231. {
  3232. if (!p->Format && p->Wnd && p->PlayListCount)
  3233. {
  3234. if (Load(p,0,0,0) == ERR_FILE_NOT_FOUND)
  3235. NextPrev(p,1,1,1);
  3236. }
  3237. if (!p->Format)
  3238. {
  3239. Result = ERR_INVALID_DATA;
  3240. break;
  3241. }
  3242. p->Play = 1;
  3243. p->FFwd = 0;
  3244. }
  3245. else
  3246. {
  3247. p->Play = 0;
  3248. p->FFwd = 0;
  3249. p->Fill = 1;
  3250. }
  3251. Result = SetPlay(p,0);
  3252. }
  3253. break;
  3254. case PLAYER_FFWD:
  3255. if (Size == sizeof(bool_t))
  3256. {
  3257. if (*(bool_t*)Data)
  3258. {
  3259. if (!p->Format && p->Wnd && p->PlayListCount)
  3260. Load(p,0,0,0);
  3261. if (!p->Format)
  3262. {
  3263. Result = ERR_INVALID_DATA;
  3264. break;
  3265. }
  3266. p->FFwd = 1;
  3267. }
  3268. else
  3269. {
  3270. p->FFwd = 0;
  3271. if (!p->Play && !p->Bench) 
  3272. p->Fill = 1;
  3273. }
  3274. Result = SetPlay(p,0);
  3275. }
  3276. break;
  3277. case PLAYER_LIST_COUNT:
  3278. assert(Size == sizeof(int));
  3279. Result = SetPlayListCount(p,*(int*)Data);
  3280. break;
  3281. case PLAYER_LIST_CURRIDX:
  3282. assert(Size == sizeof(int));
  3283. if (*(int*)Data<p->PlayListCount && *(int*)Data>=0)
  3284. Result = SetCurrent(p,p->PlayIndex[*(int*)Data],0);
  3285. break;
  3286. case PLAYER_LIST_CURRENT:
  3287. assert(Size == sizeof(int));
  3288. Result = SetCurrent(p,*(int*)Data,1);
  3289. break;
  3290. case PLAYER_NEXT:
  3291. t = FindChapter(p,1);
  3292. if (t >= 0)
  3293. Result = Seek2(p,t,NULL,1);
  3294. else
  3295. Result = NextPrev(p,1,0,0);
  3296. break;
  3297. case PLAYER_PREV:
  3298. t = FindChapter(p,-1);
  3299. if (t >= 0)
  3300. Result = Seek2(p,t,NULL,1);
  3301. else
  3302. if (Size>0 && p->Timing && p->Position > TICKSPERSEC*2 && Seek2(p,0,NULL,0)==ERR_NONE)
  3303. {
  3304. ClearStats(p);
  3305. Result = ERR_NONE;
  3306. }
  3307. else
  3308. Result = NextPrev(p,-1,0,0);
  3309. break;
  3310. case PLAYER_STOP:
  3311. SetPlay(p,1);
  3312. if (!Size)
  3313. {
  3314. if (p->Streaming)
  3315. Unload(p,0,0,1);
  3316. else
  3317. NextPrev(p,0,0,0);
  3318. }
  3319. break;
  3320. case PLAYER_RESYNC:
  3321. ReSync(p,1);
  3322. Result = ERR_NONE;
  3323. break;
  3324. case PLAYER_MICRODRIVE: SETVALUE(p->MicroDrive,bool_t,UpdateFormat(p,1)); break;
  3325. case PLAYER_UNDERRUN: SETVALUE(p->UnderRun,int,ERR_NONE); break;
  3326. case PLAYER_AUDIO_UNDERRUN: SETVALUE(p->AudioUnderRun,int,ERR_NONE); break;
  3327. }
  3328. Unlock(p,1);
  3329. break;
  3330. }
  3331. Unlock(p,0);
  3332. return Result;
  3333. }
  3334. static bool_t CmdComment(player_base* p,int Stream,const tchar_t* Name,tchar_t* Value,int ValueLen)
  3335. {
  3336. bool_t Result = 0;
  3337. const uint8_t *i;
  3338. LockEnter(p->LockComment);
  3339. for (i=ARRAYBEGIN(p->Comment,uint8_t);i!=ARRAYEND(p->Comment,uint8_t);i=CommentNext(i))
  3340. if (CommentStream(i)!=INVALID_COMMENT &&
  3341. (Stream<0 || CommentStream(i) == Stream) && tcsicmp(CommentName(i),Name)==0)
  3342. {
  3343. if (Result)
  3344. {
  3345. Result = 0;
  3346. break;
  3347. }
  3348. if (Value)
  3349. tcscpy_s(Value,ValueLen,CommentValue(i));
  3350. Result = 1;
  3351. if (Stream>=0)
  3352. break;
  3353. }
  3354. LockLeave(p->LockComment);
  3355. return Result;
  3356. }
  3357. static void Paint(player_base* p,void* DC,int x0,int y0)
  3358. {
  3359. rect re;
  3360. rect r;
  3361. rect* Exclude = NULL;
  3362. rgbval_t ColorKey;
  3363. #ifdef MULTITHREAD
  3364. assert(p->ProcessLocked != ThreadId() && p->InputLocked != ThreadId());
  3365. #endif
  3366. LockEnter(p->Lock);
  3367. if (p->Primary)
  3368. {
  3369. if (p->VOutput && p->VOutput->Get(p->VOutput,VOUT_OUTPUTRECT,&re,sizeof(re))==ERR_NONE && 
  3370. re.Width>0 && re.Height>0 && !p->TemporaryHidden)
  3371. {
  3372. re.x -= x0;
  3373. re.y -= y0;
  3374. if (p->VOutput->Get(p->VOutput,VOUT_COLORKEY,&ColorKey,sizeof(ColorKey)) == ERR_NONE)
  3375. {
  3376. if (ColorKey != p->ColorKey)
  3377. {
  3378. BrushDelete(p->ColorKeyBrush);
  3379. p->ColorKey = ColorKey;
  3380. p->ColorKeyBrush = BrushCreate(ColorKey);
  3381. }
  3382. WinFill(DC,&re,NULL,p->ColorKeyBrush);
  3383. Exclude = &re;
  3384. }
  3385. else
  3386. if (!p->Clipping && !p->Overlay)
  3387. Exclude = &re;
  3388. }
  3389. r = p->Viewport;
  3390. }
  3391. else
  3392. r = p->SkinViewport;
  3393. LockLeave(p->Lock);
  3394. r.x -= x0;
  3395. r.y -= y0;
  3396. WinFill(DC,&r,Exclude,p->BlackBrush);
  3397. }
  3398. static int Create(player_base* p)
  3399. {
  3400. int i;
  3401. int Model;
  3402. video Desktop;
  3403. QueryDesktop(&Desktop);
  3404. Model = QueryPlatform(PLATFORM_MODEL);
  3405. // default values
  3406. if (QueryPlatform(PLATFORM_TYPENO) == TYPE_SMARTPHONE)
  3407. {
  3408. p->UsedEnough2 = (256*1024)/BLOCKSIZE;
  3409. p->BufferSize2 = (600*1024)/BLOCKSIZE;
  3410. }
  3411. else
  3412. {
  3413. p->UsedEnough2 = (512*1024)/BLOCKSIZE;
  3414. p->BufferSize2 = (2400*1024)/BLOCKSIZE;
  3415. #ifdef TARGET_WINCE
  3416. if (QueryPlatform(PLATFORM_VER) < 421)
  3417. p->BufferSize2 = (1200*1024)/BLOCKSIZE;;
  3418. #endif
  3419. #ifdef TARGET_PALMOS
  3420. p->UsedEnough2 = (256*1024)/BLOCKSIZE;
  3421. p->BufferSize2 = (2000*1024)/BLOCKSIZE;
  3422. #endif
  3423. }
  3424. p->RndSeed = (uint32_t)(GetTimeTick()+GetTimeDate());
  3425. p->Color = NodeEnumObject(NULL,COLOR_ID);
  3426. p->Equalizer = NodeEnumObject(NULL,EQUALIZER_ID);
  3427. p->Player.Enum = (nodeenum)Enum;
  3428. p->Player.Get = (nodeget)Get;
  3429. p->Player.Set = (nodeset)Set;
  3430. p->Player.Paint = (playerpaint)Paint;
  3431. p->Player.CommentByName = (playercomment)CmdComment;
  3432. p->Player.ListSwap = (playerswap)ListSwap;
  3433. p->Player.Process = (playerprocess)ProcessThread;
  3434. p->MDBufferSize2 = (16000*1024)/BLOCKSIZE;
  3435. p->BurstStart = (1500*1024)/BLOCKSIZE;
  3436. p->UnderRun = PERCENT_ONE*7/10;
  3437. p->AudioUnderRun = 64;
  3438. p->MoveFFwd = p->MoveBack = TICKSPERSEC*10;
  3439. p->PlayAtOpen = 0;
  3440. p->PlayAtOpenFull = 0;
  3441. p->KeepList = 1;
  3442. p->KeepPlayAudio = 1;
  3443. #if defined(TARGET_WIN32)
  3444. p->SingleClickFullScreen = 0;
  3445. p->KeepPlayVideo = 1;
  3446. p->ShowInBackground = 1;
  3447. p->AutoPreRotate = 0;
  3448. #else
  3449. p->SingleClickFullScreen = 1;
  3450. p->KeepPlayVideo = 0;
  3451. p->ShowInBackground = 0;
  3452. p->AutoPreRotate = Desktop.Width != Desktop.Height;
  3453. #endif
  3454. p->FullZoom.Den = 1;
  3455. p->FullZoom.Num = 0;
  3456. p->SkinZoom.Den = 1;
  3457. p->SkinZoom.Num = 0;
  3458. p->VideoQuality = 2;
  3459. #if !defined(SH3) && !defined(MIPS)
  3460. p->AudioQuality = 2;
  3461. p->SmoothZoom50 = 1;
  3462. p->SmoothZoomAlways = 0;
  3463. #else
  3464. p->AudioQuality = 1;
  3465. p->SmoothZoom50 = 0;
  3466. p->SmoothZoomAlways = 0;
  3467. #if defined(SH3)
  3468. p->FullZoom.Num = p->SkinZoom.Num = 1;
  3469. #endif
  3470. #endif
  3471. #ifdef TARGET_SYMBIAN
  3472. p->Volume = 50;
  3473. #else
  3474. p->Volume = 90;
  3475. #endif
  3476. p->Repeat = 1;
  3477. #ifdef TARGET_WIN32
  3478. p->Aspect.Num = 0;
  3479. #else
  3480. p->Aspect.Num = 1;
  3481. #ifdef ARM
  3482. // use aspect with hardware scaler overlay drivers...
  3483. if (NodeEnumClass(NULL,FOURCC('A','T','I','4')) ||
  3484. NodeEnumClass(NULL,FOURCC('G','E','2','D')) ||
  3485. NodeEnumClass(NULL,FOURCC('A','H','I','_')) ||
  3486. NodeEnumClass(NULL,FOURCC('2','7','0','G')))
  3487. p->Aspect.Num = 0;
  3488. #endif
  3489. #endif
  3490. p->Aspect.Den = 1;
  3491. p->PlaySpeed.Num = 1;
  3492. p->PlaySpeed.Den = 1;
  3493. p->FFwdSpeed.Num = 2;
  3494. p->FFwdSpeed.Den = 1;
  3495. p->SeekAfterSync.Num = -1;
  3496. p->Primary = 1;
  3497. p->SkinDir = -1;
  3498. p->Foreground = 1;
  3499. if (Model==MODEL_TUNGSTEN_T3)
  3500. p->FullDir = -1; // special case because it can be slided into square format
  3501. else
  3502. {
  3503. p->FullDir = GetOrientation();
  3504. if (Desktop.Width < Desktop.Height)
  3505. {
  3506. if (GetHandedness())
  3507. p->FullDir = CombineDir(p->FullDir,DIR_SWAPXY | DIR_MIRRORLEFTRIGHT,0);
  3508. else
  3509. p->FullDir = CombineDir(p->FullDir,DIR_SWAPXY | DIR_MIRRORUPDOWN,0);
  3510. }
  3511. }
  3512. for (i=0;i<PACKET_MAX;++i)
  3513. p->Selected[i] = -1;
  3514. p->CurrentChanged = 1;
  3515. p->Position = -1;
  3516. p->AOutputIdMax = p->AOutputId = NodeEnumClass(NULL,AOUT_CLASS);
  3517. p->VOutputIdMax = p->VOutputId = NodeEnumClass(NULL,VOUT_CLASS);
  3518. p->VideoAccel = VOutIDCT(p->VOutputId);
  3519. #ifdef MULTITHREAD
  3520. p->LockProcessCount = 0;
  3521. p->LockInputCount = 0;
  3522. p->LockComment = LockCreate();
  3523. p->Lock = LockCreate();
  3524. p->LockInput = LockCreate();
  3525. p->LockProcess = LockCreate();
  3526. p->EventProcess = EventCreate(0,0);
  3527. p->EventRunProcess = EventCreate(1,0);
  3528. p->EventRunInput = EventCreate(1,0);
  3529. #endif
  3530. p->ColorKey = RGB_NULL;
  3531. p->ColorKeyBrush = NULL;
  3532. p->BlackBrush = BrushCreate(0);
  3533. UpdateFormat(p,0);
  3534. UpdateRunProcess(p);
  3535. UpdateRunInput(p);
  3536. return ERR_NONE;
  3537. }
  3538. static void Delete(player_base* p)
  3539. {
  3540. UpdateWnd(p,NULL);
  3541. #ifdef MULTITHREAD
  3542. EventClose(p->EventRunInput);
  3543. EventClose(p->EventRunProcess);
  3544. EventClose(p->EventProcess);
  3545. LockDelete(p->Lock);
  3546. LockDelete(p->LockInput);
  3547. LockDelete(p->LockProcess);
  3548. LockDelete(p->LockComment);
  3549. #endif
  3550. BrushDelete(p->ColorKeyBrush);
  3551. BrushDelete(p->BlackBrush);
  3552. free(p->PlayList);
  3553. free(p->PlayIndex);
  3554. }
  3555. void PlayerSaveList(player* Player,const tchar_t* Path,int Class)
  3556. {
  3557. playlist* Playlist = (playlist*)NodeCreate(Class);
  3558. if (Playlist)
  3559. {
  3560. if (Playlist->WriteList)
  3561. {
  3562. stream* Input = GetStream(Path,0);
  3563. if (Input)
  3564. {
  3565. bool_t b = 1;
  3566. if (Input->Set(Input,STREAM_CREATE,&b,sizeof(b)) == ERR_NONE &&
  3567. Input->Set(Input,STREAM_URL,Path,sizeof(tchar_t)*(tcslen(Path)+1)) == ERR_NONE &&
  3568. Playlist->Set(Playlist,PLAYLIST_STREAM,&Input,sizeof(Input)) == ERR_NONE)
  3569. {
  3570. tchar_t Base[MAXPATH];
  3571. tchar_t Rel[MAXPATH];
  3572. tchar_t URL[MAXPATH];
  3573. tchar_t Title[256];
  3574. tick_t Length;
  3575. int No,Count;
  3576. SplitURL(Path,Base,TSIZEOF(Base),Base,TSIZEOF(Base),NULL,0,NULL,0);
  3577. Player->Get(Player,PLAYER_LIST_COUNT,&Count,sizeof(Count));
  3578. for (No=0;No<Count;++No)
  3579. {
  3580. if (Player->Get(Player,PLAYER_LIST_URL+No,URL,sizeof(URL))==ERR_NONE)
  3581. {
  3582. RelPath(Rel,TSIZEOF(Rel),URL,Base);
  3583. Title[0] = 0;
  3584. Length = -1;
  3585. Player->Get(Player,PLAYER_LIST_TITLE+No,Title,sizeof(Title));
  3586. Player->Get(Player,PLAYER_LIST_LENGTH+No,&Length,sizeof(Length));
  3587. Playlist->WriteList(Playlist,Rel,Title,Length);
  3588. }
  3589. }
  3590. Playlist->WriteList(Playlist,NULL,NULL,0);
  3591. Playlist->Set(Playlist,PLAYLIST_STREAM,NULL,0);
  3592. }
  3593. Input->Set(Input,STREAM_URL,NULL,0);
  3594. NodeDelete((node*)Input);
  3595. }
  3596. }
  3597. Playlist->Set(Playlist,PLAYLIST_STREAM,NULL,0);
  3598. NodeDelete((node*)Playlist);
  3599. }
  3600. }
  3601. int PlayerAddDir(player* Player,int Index, const tchar_t* Path, const tchar_t* Exts, bool_t ExtFilter, int Deep)
  3602. {
  3603. streamdir DirItem;
  3604. stream* Stream;
  3605. if (Deep < MAXDIRDEEP) // fail safe
  3606. {
  3607. Stream = GetStream(Path,1);
  3608. if (Stream)
  3609. {
  3610. tchar_t Base[MAXPATH];
  3611. int Result = Stream->EnumDir(Stream,Path,Exts,ExtFilter,&DirItem);
  3612. if (Result == ERR_NONE)
  3613. {
  3614. tcscpy_s(Base,TSIZEOF(Base),Path);
  3615. Stream->Get(Stream,STREAM_BASE,Base,sizeof(Base));
  3616. }
  3617. while (Result == ERR_NONE)
  3618. {
  3619. tchar_t PathItem[MAXPATH];
  3620. AbsPath(PathItem,TSIZEOF(PathItem),DirItem.FileName,Base);
  3621. if (tcsncmp(PathItem,Base,tcslen(Base))==0) // don't go to other sites with http
  3622. {
  3623. if (DirItem.Size < 0)
  3624. Index = PlayerAddDir(Player,Index,PathItem,Exts,ExtFilter,Deep+1);
  3625. else
  3626. Index = PlayerAdd(Player,Index,PathItem,DirItem.DisplayName);
  3627. }
  3628. Result = Stream->EnumDir(Stream,NULL,NULL,0,&DirItem);
  3629. }
  3630. NodeDelete((node*)Stream);
  3631. }
  3632. }
  3633. return Index;
  3634. }
  3635. int PlayerAdd(player* Player,int Index, const tchar_t* Path, const tchar_t* Title)
  3636. {
  3637. stream* Input;
  3638. array List;
  3639. // process playlist files
  3640. NodeEnumClassEx(&List,PLAYLIST_CLASS,NULL,Path,NULL,0);
  3641. if (!ARRAYEMPTY(List) && (Input = GetStream(Path,0))!=NULL)
  3642. {
  3643. if (Input->Set(Input,STREAM_URL,Path,sizeof(tchar_t)*(tcslen(Path)+1)) == ERR_NONE &&
  3644. LoadPlaylist(Player,&List,Input,&Index,Path,NULL,0))
  3645. Path = NULL;
  3646. Input->Set(Input,STREAM_URL,NULL,0);
  3647. NodeDelete((node*)Input);
  3648. }
  3649. ArrayClear(&List);
  3650. if (Path)
  3651. {
  3652. Player->Set(Player,PLAYER_LIST_URL+Index,Path,sizeof(tchar_t)*(tcslen(Path)+1));
  3653. Player->Set(Player,PLAYER_LIST_TITLE+Index,Title,Title?sizeof(tchar_t)*(tcslen(Title)+1):0);
  3654. ++Index;
  3655. }
  3656. return Index;
  3657. }
  3658. const tchar_t* PlayerComment(int Code)
  3659. {
  3660. switch (Code)
  3661. {
  3662. case COMMENT_TITLE: return T("TITLE");
  3663. case COMMENT_ARTIST: return T("ARTIST");
  3664. case COMMENT_ALBUM: return T("ALBUM");
  3665. case COMMENT_GENRE: return T("GENRE");
  3666. case COMMENT_LANGUAGE: return T("LANGUAGE");
  3667. case COMMENT_AUTHOR: return T("AUTHOR");
  3668. case COMMENT_COPYRIGHT: return T("COPYRIGHT");
  3669. case COMMENT_PRIORITY: return T("PRIORITY");
  3670. case COMMENT_YEAR: return T("YEAR");
  3671. case COMMENT_TRACK: return T("TRACK");
  3672. case COMMENT_COMMENT: return T("COMMENT");
  3673. case COMMENT_COVER: return T("COVER");
  3674. case COMMENT_REDIRECT: return T("REDIRECT");
  3675. }
  3676. return NULL;
  3677. }
  3678. tick_t PlayerGetChapter(player* p,int No,tchar_t* OutName,int OutNameLen)
  3679. {
  3680. tchar_t Chapter[64];
  3681. tchar_t s[64];
  3682. int Hour,Min,Sec,MSec=0;
  3683. if (No>0)
  3684. {
  3685. stprintf_s(Chapter,TSIZEOF(Chapter),T("CHAPTER%02d"),No);
  3686. if (p->CommentByName(p,-1,Chapter,s,TSIZEOF(s)) && 
  3687. stscanf(s,T("%d:%d:%d.%d"),&Hour,&Min,&Sec,&MSec)>=3)
  3688. {
  3689. if (OutName)
  3690. {
  3691. stprintf_s(Chapter,TSIZEOF(Chapter),T("CHAPTER%02dNAME"),No);
  3692. if (!p->CommentByName(p,-1,Chapter,OutName,OutNameLen))
  3693. stprintf_s(OutName,OutNameLen,T("%d"),No);
  3694. }
  3695. return Scale(((Hour*60+Min)*60+Sec)*1000+MSec,TICKSPERSEC,1000);
  3696. }
  3697. }
  3698. return -1;
  3699. }
  3700. bool_t PlayerGetStream(player* Player,int No,packetformat* OutFormat,tchar_t* OutName,int OutNameLen,int* OutPri)
  3701. {
  3702. tchar_t s[256];
  3703. node* Format;
  3704. packetformat PacketFormat;
  3705. int i;
  3706. if (Player->Get(Player,PLAYER_FORMAT,&Format,sizeof(Format))==ERR_NONE && Format)
  3707. {
  3708. int Count[PACKET_MAX];
  3709. memset(Count,0,sizeof(Count));
  3710. for (i=0;Format->Get(Format,(FORMAT_STREAM+i)|PIN_FORMAT,&PacketFormat,sizeof(PacketFormat))==ERR_NONE;++i)
  3711. {
  3712. ++Count[PacketFormat.Type];
  3713. if (i==No)
  3714. {
  3715. if (OutPri)
  3716. {
  3717. if (Player->CommentByName(Player,i,PlayerComment(COMMENT_PRIORITY),s,TSIZEOF(s)))
  3718. *OutPri = StringToInt(s,0);
  3719. else
  3720. *OutPri = 0;
  3721. }
  3722. if (OutName)
  3723. {
  3724. if (Player->CommentByName(Player,i,PlayerComment(COMMENT_LANGUAGE),s,TSIZEOF(s)) ||
  3725. Player->CommentByName(Player,i,PlayerComment(COMMENT_TITLE),s,TSIZEOF(s)))
  3726. tcscpy_s(OutName,OutNameLen,s);
  3727. else
  3728. stprintf_s(OutName,OutNameLen,T("%s %d"),LangStr(PLAYER_ID,STREAM_NAME+PacketFormat.Type),Count[PacketFormat.Type]);
  3729. }
  3730. if (OutFormat)
  3731. *OutFormat = PacketFormat;
  3732. return 1;
  3733. }
  3734. }
  3735. }
  3736. return 0;
  3737. }
  3738. static const nodedef Player =
  3739. {
  3740. sizeof(player_base)|CF_GLOBAL|CF_SETTINGS,
  3741. PLAYER_ID,
  3742. NODE_CLASS,
  3743. PRI_MAXIMUM+600,
  3744. (nodecreate)Create,
  3745. (nodedelete)Delete,
  3746. };
  3747. typedef struct playerbuffer
  3748. {
  3749. node Node;
  3750. node* Player;
  3751. } playerbuffer;
  3752. static int BufferEnum(playerbuffer* p, int* No, datadef* Param)
  3753. {
  3754. int Result = NodeEnumTable(No,Param,BufferParams);
  3755. if (Result == ERR_NONE)
  3756. Param->Name = LangStr(PLAYER_ID,Param->No);
  3757. return Result;
  3758. }
  3759. static int BufferGet(playerbuffer* p, int No, void* Data, int Size)
  3760. {
  3761. return p->Player->Get(p->Player,No,Data,Size);
  3762. }
  3763. static int BufferSet(playerbuffer* p, int No, const void* Data, int Size)
  3764. {
  3765. return p->Player->Set(p->Player,No,Data,Size);
  3766. }
  3767. static int BufferCreate(playerbuffer* p)
  3768. {
  3769. p->Player = Context()->Player;
  3770. p->Node.Enum = (nodeenum)BufferEnum;
  3771. p->Node.Get = (nodeget)BufferGet;
  3772. p->Node.Set = (nodeset)BufferSet;
  3773. return ERR_NONE;
  3774. }
  3775. static const nodedef Buffer =
  3776. {
  3777. sizeof(playerbuffer)|CF_GLOBAL|CF_SETTINGS,
  3778. PLAYER_BUFFER_ID,
  3779. NODE_CLASS,
  3780. PRI_MAXIMUM+60,
  3781. (nodecreate)BufferCreate
  3782. };
  3783. void Player_Init()
  3784. {
  3785. NodeRegisterClass(&Player);
  3786. Context()->Player = NodeEnumObject(NULL,PLAYER_ID);
  3787. NodeRegisterClass(&Buffer);
  3788. }
  3789. void Player_Done()
  3790. {
  3791. Context()->Player = NULL;
  3792. NodeUnRegisterClass(PLAYER_ID);
  3793. NodeUnRegisterClass(PLAYER_BUFFER_ID);
  3794. }