PlayThread.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964
  1. #include "main.h"
  2. #include "api__in_avi.h"
  3. #include "../nsavi/nsavi.h"
  4. #include "interfaces.h"
  5. #include "../nu/AudioOutput.h"
  6. #include "../Winamp/wa_ipc.h"
  7. #include <api/service/waservicefactory.h>
  8. #include "VideoThread.h"
  9. #include "win32_avi_reader.h"
  10. #include "http_avi_reader.h"
  11. #include "StreamSelector.h"
  12. #include <shlwapi.h>
  13. #include <strsafe.h>
  14. #include <map>
  15. nsavi::HeaderList header_list;
  16. int video_stream_num, audio_stream_num;
  17. ifc_avivideodecoder *video_decoder=0;
  18. IVideoOutput *video_output=0;
  19. HANDLE audio_break=0, audio_resume=0, audio_break_done=0;
  20. static Streams streams;
  21. static bool checked_in_dshow=false;
  22. extern int GetOutputTime();
  23. class StatsFOURCC
  24. {
  25. public:
  26. uint32_t GetAudioStat()
  27. {
  28. uint32_t fourcc=0;
  29. uint32_t max=0;
  30. for (Stats::iterator itr = audio_types.begin();itr!=audio_types.end();itr++)
  31. {
  32. if (itr->second > max)
  33. {
  34. max = itr->second;
  35. fourcc = itr->first;
  36. }
  37. }
  38. return fourcc;
  39. }
  40. uint32_t GetVideoStat()
  41. {
  42. uint32_t fourcc=0;
  43. uint32_t max=0;
  44. for (Stats::iterator itr = video_fourccs.begin();itr!=video_fourccs.end();itr++)
  45. {
  46. if (itr->second > max)
  47. {
  48. max = itr->second;
  49. fourcc = itr->first;
  50. }
  51. }
  52. return fourcc;
  53. }
  54. typedef std::map<uint32_t, uint32_t> Stats;
  55. Stats audio_types;
  56. Stats video_fourccs;
  57. };
  58. static StatsFOURCC stats;
  59. class AVIWait
  60. {
  61. public:
  62. int WaitOrAbort(int time_in_ms)
  63. {
  64. HANDLE events[] = {killswitch, seek_event};
  65. int ret = WaitForMultipleObjects(2, events, FALSE, time_in_ms);
  66. if (ret == WAIT_TIMEOUT)
  67. return 0;
  68. else if (ret == WAIT_OBJECT_0)
  69. return 1;
  70. else if (ret == WAIT_OBJECT_0+1)
  71. return 2;
  72. return -1;
  73. }
  74. };
  75. static bool audio_opened=false;
  76. static ifc_aviaudiodecoder *audio_decoder=0;
  77. static char audio_output[65536];
  78. static nu::AudioOutput<AVIWait> out(&plugin);
  79. // {B6CB4A7C-A8D0-4c55-8E60-9F7A7A23DA0F}
  80. static const GUID playbackConfigGroupGUID =
  81. {
  82. 0xb6cb4a7c, 0xa8d0, 0x4c55, { 0x8e, 0x60, 0x9f, 0x7a, 0x7a, 0x23, 0xda, 0xf }
  83. };
  84. static int GetStreamNumber( uint32_t id )
  85. {
  86. char *stream_data = (char *)( &id );
  87. if ( !isxdigit( stream_data[ 0 ] ) || !isxdigit( stream_data[ 1 ] ) )
  88. return -1;
  89. stream_data[ 2 ] = 0;
  90. int stream_number = strtoul( stream_data, 0, 16 );
  91. return stream_number;
  92. }
  93. static ifc_aviaudiodecoder *FindAudioDecoder( const nsavi::AVIH *avi_header, const nsavi::STRL &stream )
  94. {
  95. unsigned int bits_per_sample = (unsigned int)AGAVE_API_CONFIG->GetUnsigned( playbackConfigGroupGUID, L"bits", 16 );
  96. if ( bits_per_sample >= 24 ) bits_per_sample = 24;
  97. else bits_per_sample = 16;
  98. unsigned int max_channels;
  99. // get max channels
  100. if ( AGAVE_API_CONFIG->GetBool( playbackConfigGroupGUID, L"surround", true ) )
  101. max_channels = 6;
  102. else if ( AGAVE_API_CONFIG->GetBool( playbackConfigGroupGUID, L"mono", false ) )
  103. max_channels = 1;
  104. else
  105. max_channels = 2;
  106. size_t n = 0;
  107. waServiceFactory *sf = 0;
  108. while ( sf = plugin.service->service_enumService( WaSvc::AVIDECODER, n++ ) )
  109. {
  110. svc_avidecoder *dec = static_cast<svc_avidecoder *>( sf->getInterface() );
  111. if ( dec )
  112. {
  113. ifc_aviaudiodecoder *decoder = 0;
  114. if ( dec->CreateAudioDecoder( avi_header, stream.stream_header, stream.stream_format, stream.stream_data,
  115. bits_per_sample, max_channels, false,
  116. &decoder ) == svc_avidecoder::CREATEDECODER_SUCCESS )
  117. {
  118. sf->releaseInterface( dec );
  119. return decoder;
  120. }
  121. sf->releaseInterface( dec );
  122. }
  123. }
  124. return 0;
  125. }
  126. static ifc_avivideodecoder *FindVideoDecoder(const nsavi::AVIH *avi_header, const nsavi::STRL &stream)
  127. {
  128. size_t n = 0;
  129. waServiceFactory *sf = 0;
  130. while (sf = plugin.service->service_enumService(WaSvc::AVIDECODER, n++))
  131. {
  132. svc_avidecoder *dec = static_cast<svc_avidecoder *>(sf->getInterface());
  133. if (dec)
  134. {
  135. ifc_avivideodecoder *decoder=0;
  136. if (dec->CreateVideoDecoder(avi_header, stream.stream_header, stream.stream_format, stream.stream_data, &decoder) == svc_avidecoder::CREATEDECODER_SUCCESS)
  137. {
  138. sf->releaseInterface(dec);
  139. return decoder;
  140. }
  141. sf->releaseInterface(dec);
  142. }
  143. }
  144. return 0;
  145. }
  146. static bool OnAudio( uint16_t type, const void **input_buffer, uint32_t *input_buffer_bytes )
  147. {
  148. uint32_t output_len = sizeof( audio_output );
  149. int ret = audio_decoder->DecodeChunk( type, input_buffer, input_buffer_bytes, audio_output, &output_len );
  150. //if (*input_buffer_bytes != 0)
  151. //DebugBreak();
  152. if ( ( ret == ifc_aviaudiodecoder::AVI_SUCCESS || ret == ifc_aviaudiodecoder::AVI_NEED_MORE_INPUT ) && output_len )
  153. {
  154. if ( !audio_opened )
  155. {
  156. unsigned int sample_rate, channels, bps;
  157. bool is_float;
  158. if ( audio_decoder->GetOutputProperties( &sample_rate, &channels, &bps, &is_float ) == ifc_aviaudiodecoder::AVI_SUCCESS )
  159. {
  160. audio_opened = out.Open( 0, channels, sample_rate, bps );
  161. if ( !audio_opened )
  162. return false;
  163. }
  164. else
  165. {
  166. // TODO: buffer audio. can nu::AudioOutput handle this for us?
  167. }
  168. }
  169. if ( audio_opened )
  170. out.Write( audio_output, output_len );
  171. }
  172. return true;
  173. }
  174. static bool CheckDSHOW()
  175. {
  176. if (!checked_in_dshow)
  177. {
  178. LPCWSTR pluginsDir = (LPCWSTR)SendMessage(plugin.hMainWindow, WM_WA_IPC, 0, IPC_GETPLUGINDIRECTORYW);
  179. wchar_t in_dshow_path[MAX_PATH] = {0};
  180. PathCombine(in_dshow_path, pluginsDir, L"in_dshow.dll");
  181. in_dshow = LoadLibrary(in_dshow_path);
  182. checked_in_dshow = true;
  183. }
  184. return !!in_dshow;
  185. }
  186. static void CALLBACK DSHOWAPC( ULONG_PTR param )
  187. {
  188. In_Module *dshow_mod_local = 0;
  189. wchar_t *playFile = (wchar_t *)param;
  190. if ( in_dshow )
  191. {
  192. typedef In_Module *( *MODULEGETTER )( );
  193. MODULEGETTER moduleGetter = (MODULEGETTER)GetProcAddress( in_dshow, "winampGetInModule2" );
  194. if ( moduleGetter )
  195. dshow_mod_local = moduleGetter();
  196. }
  197. if ( dshow_mod_local )
  198. {
  199. dshow_mod_local->outMod = plugin.outMod;
  200. if ( dshow_mod_local->Play( playFile ) )
  201. dshow_mod_local = 0;
  202. }
  203. free( playFile );
  204. if ( !dshow_mod_local )
  205. {
  206. if ( WaitForSingleObject( killswitch, 200 ) != WAIT_OBJECT_0 )
  207. PostMessage( plugin.hMainWindow, WM_WA_MPEG_EOF, 0, 0 );
  208. }
  209. else
  210. dshow_mod = dshow_mod_local;
  211. }
  212. /* --- Video Window text info --- */
  213. void SetVideoInfoText()
  214. {
  215. wchar_t audio_name[128] = {0}, audio_properties[256] = {0};
  216. wchar_t video_name[128] = {0}, video_properties[256] = {0};
  217. wchar_t video_info[512] = {0};
  218. if (audio_decoder && video_decoder)
  219. {
  220. GetAudioCodecName(audio_name, sizeof(audio_name)/sizeof(*audio_name), header_list.stream_list[audio_stream_num].stream_format);
  221. GetAudioCodecDescription(audio_properties, sizeof(audio_properties)/sizeof(*audio_properties), header_list.stream_list[audio_stream_num].stream_format);
  222. GetVideoCodecName(video_name, sizeof(video_name)/sizeof(*video_name), header_list.stream_list[video_stream_num].stream_format);
  223. GetVideoCodecDescription(video_properties, sizeof(video_properties)/sizeof(*video_properties), header_list.stream_list[video_stream_num].stream_format);
  224. StringCbPrintf(video_info, sizeof(video_info), L"AVI: %s (%s), %s (%s)", audio_name, audio_properties, video_name, video_properties);
  225. video_output->extended(VIDUSER_SET_INFOSTRINGW,(INT_PTR)video_info,0);
  226. }
  227. else if (audio_decoder)
  228. {
  229. GetAudioCodecName(audio_name, sizeof(audio_name)/sizeof(*audio_name), header_list.stream_list[audio_stream_num].stream_format);
  230. GetAudioCodecDescription(audio_properties, sizeof(audio_properties)/sizeof(*audio_properties), header_list.stream_list[audio_stream_num].stream_format);
  231. StringCbPrintf(video_info, sizeof(video_info), L"AVI: %s (%s)", audio_name, audio_properties);
  232. video_output->extended(VIDUSER_SET_INFOSTRINGW,(INT_PTR)video_info,0);
  233. }
  234. else if (video_decoder)
  235. {
  236. GetVideoCodecName(video_name, sizeof(video_name)/sizeof(*video_name), header_list.stream_list[video_stream_num].stream_format);
  237. GetVideoCodecDescription(video_properties, sizeof(video_properties)/sizeof(*video_properties), header_list.stream_list[video_stream_num].stream_format);
  238. StringCbPrintf(video_info, sizeof(video_info), L"AVI: %s (%s)", video_name, video_properties);
  239. video_output->extended(VIDUSER_SET_INFOSTRINGW,(INT_PTR)video_info,0);
  240. }
  241. }
  242. void Streams::Reset()
  243. {
  244. num_audio_streams = 0;
  245. num_video_streams = 0;
  246. current_audio_stream = 0;
  247. }
  248. void Streams::AddAudioStream(int stream_num)
  249. {
  250. audio_streams[num_audio_streams++]=stream_num;
  251. }
  252. void Streams::AddVideoStream(int stream_num)
  253. {
  254. video_streams[num_video_streams++]=stream_num;
  255. }
  256. void Streams::SetAudioStream(int stream_num)
  257. {
  258. for (int i=0;i<num_audio_streams;i++)
  259. {
  260. if (audio_streams[i] == stream_num)
  261. current_audio_stream=i;
  262. }
  263. }
  264. void Streams::SetVideoStream(int stream_num)
  265. {
  266. for (int i=0;i<num_video_streams;i++)
  267. {
  268. if (video_streams[i] == stream_num)
  269. current_video_stream=i;
  270. }
  271. }
  272. int Streams::getNumAudioTracks()
  273. {
  274. return num_audio_streams;
  275. }
  276. void Streams::enumAudioTrackName(int n, char *buf, int size)
  277. {
  278. StringCchPrintfA(buf, size, "Audio Stream %d", n);
  279. }
  280. int Streams::getCurAudioTrack()
  281. {
  282. return current_audio_stream;
  283. }
  284. int Streams::getNumVideoTracks()
  285. {
  286. return num_video_streams;
  287. }
  288. void Streams::enumVideoTrackName(int n, char *buf, int size)
  289. {
  290. StringCchPrintfA(buf, size, "Video Stream %d", n);
  291. }
  292. int Streams::getCurVideoTrack()
  293. {
  294. return current_video_stream;
  295. }
  296. void Streams::setAudioTrack(int n)
  297. {
  298. SetEvent(audio_break);
  299. WaitForSingleObject(audio_break_done, INFINITE);
  300. int i = audio_streams[n];
  301. const nsavi::STRL &stream = header_list.stream_list[i];
  302. if (audio_decoder)
  303. {
  304. audio_decoder->Close();
  305. audio_decoder=0;
  306. }
  307. audio_decoder = FindAudioDecoder(header_list.avi_header, stream);
  308. if (audio_decoder)
  309. {
  310. current_audio_stream = n;
  311. audio_stream_num = i;
  312. video_only=0; // TODO! need to do more to get this to work if we are switching FROM video_only
  313. }
  314. else
  315. {
  316. video_only; // TODO! need to do more to get this to work here
  317. }
  318. SetEvent(audio_resume);
  319. WaitForSingleObject(audio_break_done, INFINITE);
  320. SetVideoInfoText();
  321. }
  322. void Streams::setVideoTrack(int n)
  323. {
  324. // TODO: need to VideoBreak, destroy decoder, create new one and update video_stream_num
  325. }
  326. bool SingleReaderLoop(nsavi::Demuxer &demuxer, nsavi::avi_reader *reader, nsavi::SeekTable *&audio_seek_table, nsavi::SeekTable *&video_seek_table)
  327. {
  328. const void *input_buffer = 0;
  329. uint16_t type = 0;
  330. uint32_t input_buffer_bytes = 0;
  331. bool idx1_searched=false;
  332. HANDLE events[] = { killswitch, seek_event, audio_break, audio_resume };
  333. void *data;
  334. uint32_t data_size;
  335. uint32_t data_type;
  336. int waitTime = 0;
  337. for (;;)
  338. {
  339. int ret = WaitForMultipleObjects(4, events, FALSE, waitTime);
  340. if (ret == WAIT_OBJECT_0)
  341. {
  342. break;
  343. }
  344. else if (ret == WAIT_OBJECT_0+1)
  345. {
  346. volatile LONG _this_seek_position;
  347. do
  348. {
  349. InterlockedExchange(&_this_seek_position, seek_position);
  350. if (_this_seek_position != -1)
  351. {
  352. int this_seek_position = _this_seek_position;
  353. ResetEvent(seek_event); // reset this first so nothing aborts on it
  354. if (!idx1_searched)
  355. {
  356. nsavi::IDX1 *index;
  357. ret = demuxer.GetSeekTable(&index);
  358. if (ret == nsavi::READ_OK)
  359. {
  360. if (video_seek_table)
  361. video_seek_table->AddIndex(index);
  362. if (audio_seek_table)
  363. audio_seek_table->AddIndex(index);
  364. }
  365. idx1_searched=true;
  366. }
  367. uint64_t index_position, start_time;
  368. while (video_seek_table && video_seek_table->GetIndexLocation(this_seek_position, &index_position, &start_time))
  369. {
  370. nsavi::INDX *next_index=0;
  371. if (demuxer.GetIndexChunk(&next_index, index_position) == 0)
  372. {
  373. video_seek_table->AddIndex(next_index, start_time); // seek table takes ownership
  374. free(next_index);
  375. }
  376. }
  377. while (audio_seek_table && audio_seek_table->GetIndexLocation(this_seek_position, &index_position, &start_time))
  378. {
  379. nsavi::INDX *next_index=0;
  380. if (demuxer.GetIndexChunk(&next_index, index_position) == 0)
  381. {
  382. audio_seek_table->AddIndex(next_index, start_time); // seek table takes ownership
  383. free(next_index);
  384. }
  385. }
  386. if (video_seek_table)
  387. {
  388. int curr_time = GetOutputTime();
  389. int direction = (curr_time < this_seek_position)?nsavi::SeekTable::SEEK_FORWARD:nsavi::SeekTable::SEEK_BACKWARD;
  390. const nsavi::SeekEntry *video_seek_entry=video_seek_table->GetSeekPoint(this_seek_position, curr_time, direction);
  391. if (video_seek_entry)
  392. {
  393. Video_Break();
  394. if (video_only)
  395. {
  396. demuxer.Seek(video_seek_entry->file_position, video_seek_entry->absolute, reader);
  397. video_clock.Seek(this_seek_position);
  398. }
  399. else if (audio_seek_table)
  400. {
  401. const nsavi::SeekEntry *audio_seek_entry=audio_seek_table->GetSeekPoint(this_seek_position);
  402. if (audio_seek_entry)
  403. {
  404. if (audio_seek_entry->file_position < video_seek_entry->file_position)
  405. demuxer.Seek(audio_seek_entry->file_position, audio_seek_entry->absolute, reader);
  406. else
  407. demuxer.Seek(video_seek_entry->file_position, video_seek_entry->absolute, reader);
  408. audio_decoder->Flush();
  409. out.Flush(this_seek_position);
  410. }
  411. }
  412. video_total_time = video_seek_entry->stream_time;
  413. Video_Flush();
  414. }
  415. }
  416. else if (audio_seek_table)
  417. {
  418. int curr_time = GetOutputTime();
  419. int direction = (curr_time < this_seek_position)?nsavi::SeekTable::SEEK_FORWARD:nsavi::SeekTable::SEEK_BACKWARD;
  420. const nsavi::SeekEntry *audio_seek_entry=audio_seek_table->GetSeekPoint(this_seek_position, curr_time, direction);
  421. if (audio_seek_entry)
  422. {
  423. demuxer.Seek(audio_seek_entry->file_position, audio_seek_entry->absolute, reader);
  424. audio_decoder->Flush();
  425. out.Flush(this_seek_position);
  426. }
  427. }
  428. }
  429. } while (InterlockedCompareExchange(&seek_position, -1, _this_seek_position) != _this_seek_position); // loop again if seek point changed
  430. }
  431. else if (ret == WAIT_OBJECT_0+2)
  432. { // audio break
  433. ResetEvent(audio_break);
  434. SetEvent(audio_break_done);
  435. waitTime = INFINITE;
  436. continue;
  437. }
  438. else if (ret == WAIT_OBJECT_0+3)
  439. { // audio resume
  440. ResetEvent(audio_resume);
  441. SetEvent(audio_break_done);
  442. waitTime = 0;
  443. continue;
  444. }
  445. else if (ret != WAIT_TIMEOUT)
  446. {
  447. break;
  448. }
  449. if (input_buffer_bytes) // TODO: read ahead in situation where there is one giant audio chunk for the entire movie
  450. {
  451. if (!OnAudio(type, &input_buffer, &input_buffer_bytes))
  452. {
  453. return false;
  454. }
  455. if (input_buffer_bytes == 0)
  456. {
  457. free(data);
  458. data = NULL;
  459. }
  460. }
  461. else
  462. {
  463. ret = demuxer.GetNextMovieChunk(reader, &data, &data_size, &data_type);
  464. if (ret != nsavi::READ_OK)
  465. {
  466. break;
  467. }
  468. int stream_number = GetStreamNumber(data_type);
  469. type = (data_type>>16);
  470. if (stream_number == audio_stream_num)
  471. {
  472. input_buffer = (const void *)data;
  473. input_buffer_bytes = data_size;
  474. if (!OnAudio(type, &input_buffer, &input_buffer_bytes))
  475. {
  476. return false;
  477. }
  478. if (input_buffer_bytes == 0)
  479. {
  480. free(data);
  481. data = NULL;
  482. }
  483. }
  484. else if (stream_number == video_stream_num)
  485. {
  486. OnVideo(type, data, data_size);
  487. data = NULL;
  488. }
  489. else
  490. {
  491. free(data);
  492. data = NULL;
  493. }
  494. }
  495. }
  496. return true;
  497. }
  498. bool MultiReaderLoop(nsavi::Demuxer &demuxer, nsavi::avi_reader *reader, nsavi::avi_reader *video_reader, nsavi::SeekTable *&audio_seek_table, nsavi::SeekTable *&video_seek_table)
  499. {
  500. demuxer.SeekToMovieChunk(video_reader);
  501. CreateVideoReaderThread(&demuxer, video_reader);
  502. const void *input_buffer = 0;
  503. uint16_t type = 0;
  504. uint32_t input_buffer_bytes = 0;
  505. bool idx1_searched=false;
  506. HANDLE events[] = { killswitch, seek_event, audio_break, audio_resume};
  507. void *data;
  508. uint32_t data_size;
  509. uint32_t data_type;
  510. int waitTime=0;
  511. for (;;)
  512. {
  513. int ret = WaitForMultipleObjects(4, events, FALSE, waitTime);
  514. if (ret == WAIT_OBJECT_0)
  515. {
  516. break;
  517. }
  518. else if (ret == WAIT_OBJECT_0+1)
  519. {
  520. volatile LONG _this_seek_position;
  521. do
  522. {
  523. InterlockedExchange(&_this_seek_position, seek_position);
  524. if (_this_seek_position != -1)
  525. {
  526. int this_seek_position = _this_seek_position;
  527. ResetEvent(seek_event); // reset this first so nothing aborts on it
  528. if (!idx1_searched)
  529. {
  530. nsavi::IDX1 *index;
  531. ret = demuxer.GetSeekTable(&index);
  532. if (ret == nsavi::READ_OK)
  533. {
  534. video_seek_table->AddIndex(index);
  535. audio_seek_table->AddIndex(index);
  536. }
  537. idx1_searched=true;
  538. }
  539. uint64_t index_position, start_time;
  540. while (video_seek_table->GetIndexLocation(this_seek_position, &index_position, &start_time))
  541. {
  542. nsavi::INDX *next_index=0;
  543. if (demuxer.GetIndexChunk(&next_index, index_position) == 0)
  544. {
  545. video_seek_table->AddIndex(next_index, start_time); // seek table takes ownership
  546. free(next_index);
  547. }
  548. }
  549. while (audio_seek_table->GetIndexLocation(this_seek_position, &index_position, &start_time))
  550. {
  551. nsavi::INDX *next_index=0;
  552. if (demuxer.GetIndexChunk(&next_index, index_position) == 0)
  553. {
  554. audio_seek_table->AddIndex(next_index, start_time); // seek table takes ownership
  555. free(next_index);
  556. }
  557. }
  558. int curr_time = GetOutputTime();
  559. int direction = (curr_time < this_seek_position)?nsavi::SeekTable::SEEK_FORWARD:nsavi::SeekTable::SEEK_BACKWARD;
  560. const nsavi::SeekEntry *video_seek_entry=video_seek_table->GetSeekPoint(this_seek_position, curr_time, direction);
  561. if (video_seek_entry)
  562. {
  563. Video_Break();
  564. demuxer.Seek(video_seek_entry->file_position, video_seek_entry->absolute, video_reader);
  565. const nsavi::SeekEntry *audio_seek_entry=audio_seek_table->GetSeekPoint(this_seek_position);
  566. if (audio_seek_entry)
  567. {
  568. demuxer.Seek(audio_seek_entry->file_position, audio_seek_entry->absolute, reader);
  569. audio_decoder->Flush();
  570. out.Flush(this_seek_position);
  571. }
  572. video_total_time = video_seek_entry->stream_time;
  573. Video_Flush();
  574. }
  575. }
  576. } while (InterlockedCompareExchange(&seek_position, -1, _this_seek_position) != _this_seek_position); // loop again if seek point changed
  577. }
  578. else if (ret == WAIT_OBJECT_0+2)
  579. { // audio break
  580. ResetEvent(audio_break);
  581. SetEvent(audio_break_done);
  582. waitTime = INFINITE;
  583. continue;
  584. }
  585. else if (ret == WAIT_OBJECT_0+3)
  586. { // audio resume
  587. ResetEvent(audio_resume);
  588. SetEvent(audio_break_done);
  589. waitTime = 0;
  590. continue;
  591. }
  592. else if (ret != WAIT_TIMEOUT)
  593. {
  594. break;
  595. }
  596. if (input_buffer_bytes) // TODO: read ahead in situation where there is one giant audio chunk for the entire movie
  597. {
  598. if (!OnAudio(type, &input_buffer, &input_buffer_bytes))
  599. {
  600. return false;
  601. }
  602. if (input_buffer_bytes == 0)
  603. {
  604. free(data);
  605. data = NULL;
  606. }
  607. }
  608. else
  609. {
  610. ret = demuxer.GetNextMovieChunk(reader, &data, &data_size, &data_type, audio_stream_num);
  611. if (ret != nsavi::READ_OK)
  612. {
  613. break;
  614. }
  615. int stream_number = GetStreamNumber(data_type);
  616. type = (data_type>>16);
  617. if (stream_number == audio_stream_num && type != 0x7869) // ignore 'ix'
  618. {
  619. input_buffer = (const void *)data;
  620. input_buffer_bytes = data_size;
  621. if (!OnAudio(type, &input_buffer, &input_buffer_bytes))
  622. {
  623. return false;
  624. }
  625. if (input_buffer_bytes == 0)
  626. {
  627. free(data);
  628. data = NULL;
  629. }
  630. }
  631. else
  632. {
  633. free(data);
  634. data = NULL;
  635. }
  636. }
  637. }
  638. return true;
  639. }
  640. void PlayLoop(nsavi::avi_reader *reader, bool multiple_readers)
  641. {
  642. AVIReaderWin32 video_reader;
  643. uint32_t riff_type;
  644. audio_decoder=0;
  645. video_decoder=0;
  646. nsavi::SeekTable *video_seek_table = 0, *audio_seek_table = 0;
  647. nsavi::Demuxer demuxer(reader);
  648. audio_opened=false;
  649. int audio_bitrate=0;
  650. streams.Reset();
  651. out.Init(plugin.outMod);
  652. if (!video_output)
  653. video_output = (IVideoOutput *)SendMessage(plugin.hMainWindow, WM_WA_IPC, 0, IPC_GET_IVIDEOOUTPUT);
  654. audio_stream_num = 65536;
  655. video_stream_num=65536; // purposefully too big value
  656. Video_Init();
  657. if (demuxer.GetRIFFType(&riff_type) == nsavi::READ_OK)
  658. {
  659. bool audio_no_decoder=false;
  660. bool video_no_decoder=false;
  661. if (demuxer.GetHeaderList(&header_list) == nsavi::READ_OK)
  662. {
  663. // find available codecs
  664. for (uint32_t i=0;i!=header_list.stream_list_size;i++)
  665. {
  666. const nsavi::STRL &stream = header_list.stream_list[i];
  667. if (stream.stream_header)
  668. {
  669. if (stream.stream_header->stream_type == nsavi::stream_type_audio)
  670. {
  671. nsavi::audio_format *f = (nsavi::audio_format *)stream.stream_format;
  672. if (f)
  673. {
  674. stats.audio_types[f->format]++;
  675. streams.AddAudioStream(i);
  676. if (!audio_decoder)
  677. { // TODO: check priority
  678. audio_decoder = FindAudioDecoder(header_list.avi_header, stream);
  679. if (audio_decoder)
  680. {
  681. streams.SetAudioStream(i);
  682. audio_stream_num = i;
  683. video_only=0;
  684. }
  685. else
  686. audio_no_decoder = true;
  687. if (stream.stream_header->length && !stream.stream_header->sample_size && stream.stream_header->rate)
  688. g_duration = (uint64_t)stream.stream_header->length * (uint64_t)stream.stream_header->scale * 1000ULL / (uint64_t)stream.stream_header->rate;
  689. audio_bitrate = MulDiv(f->average_bytes_per_second, 8, 1000);
  690. plugin.SetInfo(audio_bitrate, -1, -1, -1);
  691. }
  692. }
  693. }
  694. else if (stream.stream_header->stream_type == nsavi::stream_type_video)
  695. {
  696. nsavi::video_format *f = (nsavi::video_format *)stream.stream_format;
  697. if (f)
  698. {
  699. stats.video_fourccs[f->compression]++;
  700. streams.AddVideoStream(i);
  701. if (!video_decoder)
  702. { // TODO: check priority
  703. video_decoder = FindVideoDecoder(header_list.avi_header, stream);
  704. if (video_decoder)
  705. {
  706. video_stream_num = i;
  707. streams.SetVideoStream(i);
  708. }
  709. else
  710. video_no_decoder = true;
  711. if (g_duration == -1 && stream.stream_header->rate)
  712. g_duration = (uint64_t)stream.stream_header->length * (uint64_t)stream.stream_header->scale * 1000ULL / (uint64_t)stream.stream_header->rate;
  713. }
  714. }
  715. }
  716. }
  717. }
  718. }
  719. if (AGAVE_API_STATS)
  720. {
  721. uint32_t audio_format = stats.GetAudioStat();
  722. uint32_t video_format = stats.GetVideoStat();
  723. AGAVE_API_STATS->SetStat(api_stats::AVI_AUDIO_FORMAT, audio_format);
  724. AGAVE_API_STATS->SetStat(api_stats::AVI_VIDEO_FOURCC, video_format);
  725. }
  726. if ((audio_no_decoder || video_no_decoder) && CheckDSHOW())
  727. {
  728. // use in_dshow to play this one
  729. HANDLE mainThread = WASABI_API_APP->main_getMainThreadHandle();
  730. if (mainThread)
  731. {
  732. Video_Stop();
  733. if (audio_decoder)
  734. {
  735. audio_decoder->Close();
  736. audio_decoder=0;
  737. }
  738. Video_Close();
  739. delete video_seek_table;
  740. delete audio_seek_table;
  741. wchar_t *fn = (wchar_t *)calloc(1024, sizeof(wchar_t *));
  742. reader->GetFilename(fn, 1024);
  743. QueueUserAPC(DSHOWAPC, mainThread, (ULONG_PTR)fn);
  744. CloseHandle(mainThread);
  745. return ;
  746. }
  747. }
  748. if (!audio_decoder && !video_decoder)
  749. {
  750. goto btfo;
  751. }
  752. if (!audio_decoder)
  753. {
  754. video_only=1;
  755. video_clock.Start();
  756. }
  757. }
  758. else
  759. {
  760. goto btfo;
  761. }
  762. SetVideoInfoText();
  763. video_output->extended(VIDUSER_SET_TRACKSELINTERFACE, (INT_PTR)&streams, 0);
  764. if (video_stream_num != 65536)
  765. video_seek_table = new nsavi::SeekTable(video_stream_num, !!video_decoder, &header_list);
  766. if (audio_stream_num != 65536)
  767. audio_seek_table = new nsavi::SeekTable(audio_stream_num, false, &header_list);
  768. uint64_t content_length = reader->GetContentLength();
  769. if (content_length && g_duration)
  770. {
  771. int total_bitrate = (int)(8ULL * content_length / (uint64_t)g_duration);
  772. plugin.SetInfo(total_bitrate, -1, -1, -1);
  773. }
  774. else if (header_list.avi_header->max_bytes_per_second)
  775. {
  776. int total_bitrate = MulDiv(header_list.avi_header->max_bytes_per_second, 8, 1000);
  777. plugin.SetInfo(total_bitrate, -1, -1, -1);
  778. }
  779. else
  780. {
  781. // use seek table for bitrate?
  782. }
  783. if (demuxer.FindMovieChunk() != nsavi::READ_OK)
  784. {
  785. goto btfo;
  786. }
  787. if (multiple_readers && video_decoder && !video_only)
  788. {
  789. wchar_t fn[MAX_PATH] = {0};
  790. reader->GetFilename(fn, MAX_PATH);
  791. if (video_reader.Open(fn) == nsavi::READ_OK)
  792. {
  793. MultiReaderLoop(demuxer, reader, &video_reader, audio_seek_table, video_seek_table);
  794. }
  795. else
  796. SingleReaderLoop(demuxer, reader, audio_seek_table, video_seek_table);
  797. }
  798. else
  799. SingleReaderLoop(demuxer, reader, audio_seek_table, video_seek_table);
  800. if (audio_opened && WaitForSingleObject(killswitch, 0) == WAIT_TIMEOUT)
  801. {
  802. out.Write(0, 0);
  803. out.WaitWhilePlaying();
  804. }
  805. btfo:
  806. if (WaitForSingleObject(killswitch, 0) == WAIT_TIMEOUT)
  807. PostMessage(plugin.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
  808. Video_Stop();
  809. if (audio_decoder)
  810. {
  811. audio_decoder->Close();
  812. audio_decoder=0;
  813. if (audio_opened)
  814. out.Close();
  815. }
  816. Video_Close();
  817. video_reader.Close();
  818. delete video_seek_table;
  819. delete audio_seek_table;
  820. }
  821. DWORD CALLBACK AVIPlayThread(LPVOID param)
  822. {
  823. if (!audio_break)
  824. audio_break = CreateEvent(0, TRUE, FALSE, 0);
  825. if (!audio_resume)
  826. audio_resume = CreateEvent(0, TRUE, FALSE, 0);
  827. if (!audio_break_done)
  828. audio_break_done = CreateEvent(0, FALSE, FALSE, 0);
  829. wchar_t *filename = (wchar_t *)param;
  830. if (PathIsURLW(filename))
  831. {
  832. AVIReaderHTTP reader(killswitch, seek_event);
  833. if (reader.Open(filename) != nsavi::READ_OK || reader.Connect() != nsavi::READ_OK)
  834. {
  835. if (WaitForSingleObject(killswitch, 200) == WAIT_TIMEOUT)
  836. PostMessage(plugin.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
  837. }
  838. else
  839. {
  840. PlayLoop(&reader, false);
  841. reader.Close();
  842. }
  843. }
  844. else
  845. {
  846. AVIReaderWin32 reader;
  847. if (reader.Open(filename) != nsavi::READ_OK)
  848. {
  849. if (WaitForSingleObject(killswitch, 200) == WAIT_TIMEOUT)
  850. PostMessage(plugin.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
  851. }
  852. else
  853. {
  854. wchar_t root[4] = {0};
  855. StringCchCopy(root, 4, filename);
  856. UINT drive_type = GetDriveType(root);
  857. if (drive_type == DRIVE_CDROM)
  858. PlayLoop(&reader, false);
  859. else
  860. PlayLoop(&reader, true);
  861. reader.Close();
  862. }
  863. }
  864. free(filename);
  865. return 0;
  866. }