123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964 |
- #include "main.h"
- #include "api__in_avi.h"
- #include "../nsavi/nsavi.h"
- #include "interfaces.h"
- #include "../nu/AudioOutput.h"
- #include "../Winamp/wa_ipc.h"
- #include <api/service/waservicefactory.h>
- #include "VideoThread.h"
- #include "win32_avi_reader.h"
- #include "http_avi_reader.h"
- #include "StreamSelector.h"
- #include <shlwapi.h>
- #include <strsafe.h>
- #include <map>
- nsavi::HeaderList header_list;
- int video_stream_num, audio_stream_num;
- ifc_avivideodecoder *video_decoder=0;
- IVideoOutput *video_output=0;
- HANDLE audio_break=0, audio_resume=0, audio_break_done=0;
- static Streams streams;
- static bool checked_in_dshow=false;
- extern int GetOutputTime();
- class StatsFOURCC
- {
- public:
- uint32_t GetAudioStat()
- {
- uint32_t fourcc=0;
- uint32_t max=0;
- for (Stats::iterator itr = audio_types.begin();itr!=audio_types.end();itr++)
- {
- if (itr->second > max)
- {
- max = itr->second;
- fourcc = itr->first;
- }
- }
- return fourcc;
- }
- uint32_t GetVideoStat()
- {
- uint32_t fourcc=0;
- uint32_t max=0;
- for (Stats::iterator itr = video_fourccs.begin();itr!=video_fourccs.end();itr++)
- {
- if (itr->second > max)
- {
- max = itr->second;
- fourcc = itr->first;
- }
- }
- return fourcc;
- }
- typedef std::map<uint32_t, uint32_t> Stats;
- Stats audio_types;
- Stats video_fourccs;
- };
- static StatsFOURCC stats;
- class AVIWait
- {
- public:
- int WaitOrAbort(int time_in_ms)
- {
- HANDLE events[] = {killswitch, seek_event};
- int ret = WaitForMultipleObjects(2, events, FALSE, time_in_ms);
- if (ret == WAIT_TIMEOUT)
- return 0;
- else if (ret == WAIT_OBJECT_0)
- return 1;
- else if (ret == WAIT_OBJECT_0+1)
- return 2;
- return -1;
- }
- };
- static bool audio_opened=false;
- static ifc_aviaudiodecoder *audio_decoder=0;
- static char audio_output[65536];
- static nu::AudioOutput<AVIWait> out(&plugin);
- // {B6CB4A7C-A8D0-4c55-8E60-9F7A7A23DA0F}
- static const GUID playbackConfigGroupGUID =
- {
- 0xb6cb4a7c, 0xa8d0, 0x4c55, { 0x8e, 0x60, 0x9f, 0x7a, 0x7a, 0x23, 0xda, 0xf }
- };
- static int GetStreamNumber( uint32_t id )
- {
- char *stream_data = (char *)( &id );
- if ( !isxdigit( stream_data[ 0 ] ) || !isxdigit( stream_data[ 1 ] ) )
- return -1;
- stream_data[ 2 ] = 0;
- int stream_number = strtoul( stream_data, 0, 16 );
- return stream_number;
- }
- static ifc_aviaudiodecoder *FindAudioDecoder( const nsavi::AVIH *avi_header, const nsavi::STRL &stream )
- {
- unsigned int bits_per_sample = (unsigned int)AGAVE_API_CONFIG->GetUnsigned( playbackConfigGroupGUID, L"bits", 16 );
- if ( bits_per_sample >= 24 ) bits_per_sample = 24;
- else bits_per_sample = 16;
- unsigned int max_channels;
- // get max channels
- if ( AGAVE_API_CONFIG->GetBool( playbackConfigGroupGUID, L"surround", true ) )
- max_channels = 6;
- else if ( AGAVE_API_CONFIG->GetBool( playbackConfigGroupGUID, L"mono", false ) )
- max_channels = 1;
- else
- max_channels = 2;
- size_t n = 0;
- waServiceFactory *sf = 0;
- while ( sf = plugin.service->service_enumService( WaSvc::AVIDECODER, n++ ) )
- {
- svc_avidecoder *dec = static_cast<svc_avidecoder *>( sf->getInterface() );
- if ( dec )
- {
- ifc_aviaudiodecoder *decoder = 0;
- if ( dec->CreateAudioDecoder( avi_header, stream.stream_header, stream.stream_format, stream.stream_data,
- bits_per_sample, max_channels, false,
- &decoder ) == svc_avidecoder::CREATEDECODER_SUCCESS )
- {
- sf->releaseInterface( dec );
- return decoder;
- }
- sf->releaseInterface( dec );
- }
- }
- return 0;
- }
- static ifc_avivideodecoder *FindVideoDecoder(const nsavi::AVIH *avi_header, const nsavi::STRL &stream)
- {
- size_t n = 0;
- waServiceFactory *sf = 0;
- while (sf = plugin.service->service_enumService(WaSvc::AVIDECODER, n++))
- {
- svc_avidecoder *dec = static_cast<svc_avidecoder *>(sf->getInterface());
- if (dec)
- {
- ifc_avivideodecoder *decoder=0;
- if (dec->CreateVideoDecoder(avi_header, stream.stream_header, stream.stream_format, stream.stream_data, &decoder) == svc_avidecoder::CREATEDECODER_SUCCESS)
- {
- sf->releaseInterface(dec);
- return decoder;
- }
- sf->releaseInterface(dec);
- }
- }
- return 0;
- }
- static bool OnAudio( uint16_t type, const void **input_buffer, uint32_t *input_buffer_bytes )
- {
- uint32_t output_len = sizeof( audio_output );
- int ret = audio_decoder->DecodeChunk( type, input_buffer, input_buffer_bytes, audio_output, &output_len );
- //if (*input_buffer_bytes != 0)
- //DebugBreak();
- if ( ( ret == ifc_aviaudiodecoder::AVI_SUCCESS || ret == ifc_aviaudiodecoder::AVI_NEED_MORE_INPUT ) && output_len )
- {
- if ( !audio_opened )
- {
- unsigned int sample_rate, channels, bps;
- bool is_float;
- if ( audio_decoder->GetOutputProperties( &sample_rate, &channels, &bps, &is_float ) == ifc_aviaudiodecoder::AVI_SUCCESS )
- {
- audio_opened = out.Open( 0, channels, sample_rate, bps );
- if ( !audio_opened )
- return false;
- }
- else
- {
- // TODO: buffer audio. can nu::AudioOutput handle this for us?
- }
- }
- if ( audio_opened )
- out.Write( audio_output, output_len );
- }
- return true;
- }
- static bool CheckDSHOW()
- {
- if (!checked_in_dshow)
- {
- LPCWSTR pluginsDir = (LPCWSTR)SendMessage(plugin.hMainWindow, WM_WA_IPC, 0, IPC_GETPLUGINDIRECTORYW);
- wchar_t in_dshow_path[MAX_PATH] = {0};
- PathCombine(in_dshow_path, pluginsDir, L"in_dshow.dll");
- in_dshow = LoadLibrary(in_dshow_path);
- checked_in_dshow = true;
- }
- return !!in_dshow;
- }
- static void CALLBACK DSHOWAPC( ULONG_PTR param )
- {
- In_Module *dshow_mod_local = 0;
- wchar_t *playFile = (wchar_t *)param;
- if ( in_dshow )
- {
- typedef In_Module *( *MODULEGETTER )( );
- MODULEGETTER moduleGetter = (MODULEGETTER)GetProcAddress( in_dshow, "winampGetInModule2" );
- if ( moduleGetter )
- dshow_mod_local = moduleGetter();
- }
- if ( dshow_mod_local )
- {
- dshow_mod_local->outMod = plugin.outMod;
- if ( dshow_mod_local->Play( playFile ) )
- dshow_mod_local = 0;
- }
- free( playFile );
- if ( !dshow_mod_local )
- {
- if ( WaitForSingleObject( killswitch, 200 ) != WAIT_OBJECT_0 )
- PostMessage( plugin.hMainWindow, WM_WA_MPEG_EOF, 0, 0 );
- }
- else
- dshow_mod = dshow_mod_local;
- }
- /* --- Video Window text info --- */
- void SetVideoInfoText()
- {
- wchar_t audio_name[128] = {0}, audio_properties[256] = {0};
- wchar_t video_name[128] = {0}, video_properties[256] = {0};
- wchar_t video_info[512] = {0};
- if (audio_decoder && video_decoder)
- {
- GetAudioCodecName(audio_name, sizeof(audio_name)/sizeof(*audio_name), header_list.stream_list[audio_stream_num].stream_format);
- GetAudioCodecDescription(audio_properties, sizeof(audio_properties)/sizeof(*audio_properties), header_list.stream_list[audio_stream_num].stream_format);
- GetVideoCodecName(video_name, sizeof(video_name)/sizeof(*video_name), header_list.stream_list[video_stream_num].stream_format);
- GetVideoCodecDescription(video_properties, sizeof(video_properties)/sizeof(*video_properties), header_list.stream_list[video_stream_num].stream_format);
- StringCbPrintf(video_info, sizeof(video_info), L"AVI: %s (%s), %s (%s)", audio_name, audio_properties, video_name, video_properties);
- video_output->extended(VIDUSER_SET_INFOSTRINGW,(INT_PTR)video_info,0);
- }
- else if (audio_decoder)
- {
- GetAudioCodecName(audio_name, sizeof(audio_name)/sizeof(*audio_name), header_list.stream_list[audio_stream_num].stream_format);
- GetAudioCodecDescription(audio_properties, sizeof(audio_properties)/sizeof(*audio_properties), header_list.stream_list[audio_stream_num].stream_format);
- StringCbPrintf(video_info, sizeof(video_info), L"AVI: %s (%s)", audio_name, audio_properties);
- video_output->extended(VIDUSER_SET_INFOSTRINGW,(INT_PTR)video_info,0);
- }
- else if (video_decoder)
- {
- GetVideoCodecName(video_name, sizeof(video_name)/sizeof(*video_name), header_list.stream_list[video_stream_num].stream_format);
- GetVideoCodecDescription(video_properties, sizeof(video_properties)/sizeof(*video_properties), header_list.stream_list[video_stream_num].stream_format);
- StringCbPrintf(video_info, sizeof(video_info), L"AVI: %s (%s)", video_name, video_properties);
- video_output->extended(VIDUSER_SET_INFOSTRINGW,(INT_PTR)video_info,0);
- }
- }
- void Streams::Reset()
- {
- num_audio_streams = 0;
- num_video_streams = 0;
-
- current_audio_stream = 0;
- }
- void Streams::AddAudioStream(int stream_num)
- {
- audio_streams[num_audio_streams++]=stream_num;
- }
- void Streams::AddVideoStream(int stream_num)
- {
- video_streams[num_video_streams++]=stream_num;
- }
- void Streams::SetAudioStream(int stream_num)
- {
- for (int i=0;i<num_audio_streams;i++)
- {
- if (audio_streams[i] == stream_num)
- current_audio_stream=i;
- }
- }
- void Streams::SetVideoStream(int stream_num)
- {
- for (int i=0;i<num_video_streams;i++)
- {
- if (video_streams[i] == stream_num)
- current_video_stream=i;
- }
- }
- int Streams::getNumAudioTracks()
- {
- return num_audio_streams;
- }
- void Streams::enumAudioTrackName(int n, char *buf, int size)
- {
- StringCchPrintfA(buf, size, "Audio Stream %d", n);
- }
- int Streams::getCurAudioTrack()
- {
- return current_audio_stream;
- }
- int Streams::getNumVideoTracks()
- {
- return num_video_streams;
- }
- void Streams::enumVideoTrackName(int n, char *buf, int size)
- {
- StringCchPrintfA(buf, size, "Video Stream %d", n);
- }
- int Streams::getCurVideoTrack()
- {
- return current_video_stream;
- }
- void Streams::setAudioTrack(int n)
- {
- SetEvent(audio_break);
- WaitForSingleObject(audio_break_done, INFINITE);
- int i = audio_streams[n];
- const nsavi::STRL &stream = header_list.stream_list[i];
- if (audio_decoder)
- {
- audio_decoder->Close();
- audio_decoder=0;
- }
- audio_decoder = FindAudioDecoder(header_list.avi_header, stream);
- if (audio_decoder)
- {
- current_audio_stream = n;
- audio_stream_num = i;
- video_only=0; // TODO! need to do more to get this to work if we are switching FROM video_only
- }
- else
- {
- video_only; // TODO! need to do more to get this to work here
- }
- SetEvent(audio_resume);
- WaitForSingleObject(audio_break_done, INFINITE);
- SetVideoInfoText();
- }
- void Streams::setVideoTrack(int n)
- {
- // TODO: need to VideoBreak, destroy decoder, create new one and update video_stream_num
- }
- bool SingleReaderLoop(nsavi::Demuxer &demuxer, nsavi::avi_reader *reader, nsavi::SeekTable *&audio_seek_table, nsavi::SeekTable *&video_seek_table)
- {
- const void *input_buffer = 0;
- uint16_t type = 0;
- uint32_t input_buffer_bytes = 0;
- bool idx1_searched=false;
- HANDLE events[] = { killswitch, seek_event, audio_break, audio_resume };
- void *data;
- uint32_t data_size;
- uint32_t data_type;
- int waitTime = 0;
- for (;;)
- {
- int ret = WaitForMultipleObjects(4, events, FALSE, waitTime);
- if (ret == WAIT_OBJECT_0)
- {
- break;
- }
- else if (ret == WAIT_OBJECT_0+1)
- {
- volatile LONG _this_seek_position;
- do
- {
- InterlockedExchange(&_this_seek_position, seek_position);
- if (_this_seek_position != -1)
- {
- int this_seek_position = _this_seek_position;
- ResetEvent(seek_event); // reset this first so nothing aborts on it
- if (!idx1_searched)
- {
- nsavi::IDX1 *index;
- ret = demuxer.GetSeekTable(&index);
- if (ret == nsavi::READ_OK)
- {
- if (video_seek_table)
- video_seek_table->AddIndex(index);
- if (audio_seek_table)
- audio_seek_table->AddIndex(index);
- }
- idx1_searched=true;
- }
- uint64_t index_position, start_time;
- while (video_seek_table && video_seek_table->GetIndexLocation(this_seek_position, &index_position, &start_time))
- {
- nsavi::INDX *next_index=0;
- if (demuxer.GetIndexChunk(&next_index, index_position) == 0)
- {
- video_seek_table->AddIndex(next_index, start_time); // seek table takes ownership
- free(next_index);
- }
- }
- while (audio_seek_table && audio_seek_table->GetIndexLocation(this_seek_position, &index_position, &start_time))
- {
- nsavi::INDX *next_index=0;
- if (demuxer.GetIndexChunk(&next_index, index_position) == 0)
- {
- audio_seek_table->AddIndex(next_index, start_time); // seek table takes ownership
- free(next_index);
- }
- }
- if (video_seek_table)
- {
- int curr_time = GetOutputTime();
- int direction = (curr_time < this_seek_position)?nsavi::SeekTable::SEEK_FORWARD:nsavi::SeekTable::SEEK_BACKWARD;
- const nsavi::SeekEntry *video_seek_entry=video_seek_table->GetSeekPoint(this_seek_position, curr_time, direction);
- if (video_seek_entry)
- {
- Video_Break();
- if (video_only)
- {
- demuxer.Seek(video_seek_entry->file_position, video_seek_entry->absolute, reader);
- video_clock.Seek(this_seek_position);
- }
- else if (audio_seek_table)
- {
- const nsavi::SeekEntry *audio_seek_entry=audio_seek_table->GetSeekPoint(this_seek_position);
- if (audio_seek_entry)
- {
- if (audio_seek_entry->file_position < video_seek_entry->file_position)
- demuxer.Seek(audio_seek_entry->file_position, audio_seek_entry->absolute, reader);
- else
- demuxer.Seek(video_seek_entry->file_position, video_seek_entry->absolute, reader);
- audio_decoder->Flush();
- out.Flush(this_seek_position);
- }
- }
- video_total_time = video_seek_entry->stream_time;
- Video_Flush();
- }
- }
- else if (audio_seek_table)
- {
- int curr_time = GetOutputTime();
- int direction = (curr_time < this_seek_position)?nsavi::SeekTable::SEEK_FORWARD:nsavi::SeekTable::SEEK_BACKWARD;
- const nsavi::SeekEntry *audio_seek_entry=audio_seek_table->GetSeekPoint(this_seek_position, curr_time, direction);
- if (audio_seek_entry)
- {
- demuxer.Seek(audio_seek_entry->file_position, audio_seek_entry->absolute, reader);
- audio_decoder->Flush();
- out.Flush(this_seek_position);
- }
- }
- }
- } while (InterlockedCompareExchange(&seek_position, -1, _this_seek_position) != _this_seek_position); // loop again if seek point changed
- }
- else if (ret == WAIT_OBJECT_0+2)
- { // audio break
- ResetEvent(audio_break);
- SetEvent(audio_break_done);
- waitTime = INFINITE;
- continue;
- }
- else if (ret == WAIT_OBJECT_0+3)
- { // audio resume
- ResetEvent(audio_resume);
- SetEvent(audio_break_done);
- waitTime = 0;
- continue;
- }
- else if (ret != WAIT_TIMEOUT)
- {
- break;
- }
- if (input_buffer_bytes) // TODO: read ahead in situation where there is one giant audio chunk for the entire movie
- {
- if (!OnAudio(type, &input_buffer, &input_buffer_bytes))
- {
- return false;
- }
- if (input_buffer_bytes == 0)
- {
- free(data);
- data = NULL;
- }
- }
- else
- {
- ret = demuxer.GetNextMovieChunk(reader, &data, &data_size, &data_type);
- if (ret != nsavi::READ_OK)
- {
- break;
- }
- int stream_number = GetStreamNumber(data_type);
- type = (data_type>>16);
- if (stream_number == audio_stream_num)
- {
- input_buffer = (const void *)data;
- input_buffer_bytes = data_size;
- if (!OnAudio(type, &input_buffer, &input_buffer_bytes))
- {
- return false;
- }
- if (input_buffer_bytes == 0)
- {
- free(data);
- data = NULL;
- }
- }
- else if (stream_number == video_stream_num)
- {
- OnVideo(type, data, data_size);
- data = NULL;
- }
- else
- {
- free(data);
- data = NULL;
- }
- }
- }
- return true;
- }
- bool MultiReaderLoop(nsavi::Demuxer &demuxer, nsavi::avi_reader *reader, nsavi::avi_reader *video_reader, nsavi::SeekTable *&audio_seek_table, nsavi::SeekTable *&video_seek_table)
- {
- demuxer.SeekToMovieChunk(video_reader);
- CreateVideoReaderThread(&demuxer, video_reader);
- const void *input_buffer = 0;
- uint16_t type = 0;
- uint32_t input_buffer_bytes = 0;
- bool idx1_searched=false;
- HANDLE events[] = { killswitch, seek_event, audio_break, audio_resume};
- void *data;
- uint32_t data_size;
- uint32_t data_type;
- int waitTime=0;
- for (;;)
- {
- int ret = WaitForMultipleObjects(4, events, FALSE, waitTime);
- if (ret == WAIT_OBJECT_0)
- {
- break;
- }
- else if (ret == WAIT_OBJECT_0+1)
- {
- volatile LONG _this_seek_position;
- do
- {
- InterlockedExchange(&_this_seek_position, seek_position);
- if (_this_seek_position != -1)
- {
- int this_seek_position = _this_seek_position;
- ResetEvent(seek_event); // reset this first so nothing aborts on it
- if (!idx1_searched)
- {
- nsavi::IDX1 *index;
- ret = demuxer.GetSeekTable(&index);
- if (ret == nsavi::READ_OK)
- {
- video_seek_table->AddIndex(index);
- audio_seek_table->AddIndex(index);
- }
- idx1_searched=true;
- }
- uint64_t index_position, start_time;
- while (video_seek_table->GetIndexLocation(this_seek_position, &index_position, &start_time))
- {
- nsavi::INDX *next_index=0;
- if (demuxer.GetIndexChunk(&next_index, index_position) == 0)
- {
- video_seek_table->AddIndex(next_index, start_time); // seek table takes ownership
- free(next_index);
- }
- }
- while (audio_seek_table->GetIndexLocation(this_seek_position, &index_position, &start_time))
- {
- nsavi::INDX *next_index=0;
- if (demuxer.GetIndexChunk(&next_index, index_position) == 0)
- {
- audio_seek_table->AddIndex(next_index, start_time); // seek table takes ownership
- free(next_index);
- }
- }
- int curr_time = GetOutputTime();
- int direction = (curr_time < this_seek_position)?nsavi::SeekTable::SEEK_FORWARD:nsavi::SeekTable::SEEK_BACKWARD;
- const nsavi::SeekEntry *video_seek_entry=video_seek_table->GetSeekPoint(this_seek_position, curr_time, direction);
- if (video_seek_entry)
- {
- Video_Break();
- demuxer.Seek(video_seek_entry->file_position, video_seek_entry->absolute, video_reader);
- const nsavi::SeekEntry *audio_seek_entry=audio_seek_table->GetSeekPoint(this_seek_position);
- if (audio_seek_entry)
- {
- demuxer.Seek(audio_seek_entry->file_position, audio_seek_entry->absolute, reader);
- audio_decoder->Flush();
- out.Flush(this_seek_position);
- }
- video_total_time = video_seek_entry->stream_time;
- Video_Flush();
- }
- }
- } while (InterlockedCompareExchange(&seek_position, -1, _this_seek_position) != _this_seek_position); // loop again if seek point changed
- }
- else if (ret == WAIT_OBJECT_0+2)
- { // audio break
- ResetEvent(audio_break);
- SetEvent(audio_break_done);
- waitTime = INFINITE;
- continue;
- }
- else if (ret == WAIT_OBJECT_0+3)
- { // audio resume
- ResetEvent(audio_resume);
- SetEvent(audio_break_done);
- waitTime = 0;
- continue;
- }
- else if (ret != WAIT_TIMEOUT)
- {
- break;
- }
- if (input_buffer_bytes) // TODO: read ahead in situation where there is one giant audio chunk for the entire movie
- {
- if (!OnAudio(type, &input_buffer, &input_buffer_bytes))
- {
- return false;
- }
- if (input_buffer_bytes == 0)
- {
- free(data);
- data = NULL;
- }
- }
- else
- {
- ret = demuxer.GetNextMovieChunk(reader, &data, &data_size, &data_type, audio_stream_num);
- if (ret != nsavi::READ_OK)
- {
- break;
- }
- int stream_number = GetStreamNumber(data_type);
- type = (data_type>>16);
- if (stream_number == audio_stream_num && type != 0x7869) // ignore 'ix'
- {
- input_buffer = (const void *)data;
- input_buffer_bytes = data_size;
- if (!OnAudio(type, &input_buffer, &input_buffer_bytes))
- {
- return false;
- }
- if (input_buffer_bytes == 0)
- {
- free(data);
- data = NULL;
- }
- }
- else
- {
- free(data);
- data = NULL;
- }
- }
- }
- return true;
- }
- void PlayLoop(nsavi::avi_reader *reader, bool multiple_readers)
- {
- AVIReaderWin32 video_reader;
- uint32_t riff_type;
- audio_decoder=0;
- video_decoder=0;
- nsavi::SeekTable *video_seek_table = 0, *audio_seek_table = 0;
- nsavi::Demuxer demuxer(reader);
- audio_opened=false;
- int audio_bitrate=0;
- streams.Reset();
- out.Init(plugin.outMod);
- if (!video_output)
- video_output = (IVideoOutput *)SendMessage(plugin.hMainWindow, WM_WA_IPC, 0, IPC_GET_IVIDEOOUTPUT);
- audio_stream_num = 65536;
- video_stream_num=65536; // purposefully too big value
- Video_Init();
- if (demuxer.GetRIFFType(&riff_type) == nsavi::READ_OK)
- {
- bool audio_no_decoder=false;
- bool video_no_decoder=false;
- if (demuxer.GetHeaderList(&header_list) == nsavi::READ_OK)
- {
- // find available codecs
- for (uint32_t i=0;i!=header_list.stream_list_size;i++)
- {
- const nsavi::STRL &stream = header_list.stream_list[i];
- if (stream.stream_header)
- {
- if (stream.stream_header->stream_type == nsavi::stream_type_audio)
- {
- nsavi::audio_format *f = (nsavi::audio_format *)stream.stream_format;
- if (f)
- {
- stats.audio_types[f->format]++;
- streams.AddAudioStream(i);
- if (!audio_decoder)
- { // TODO: check priority
- audio_decoder = FindAudioDecoder(header_list.avi_header, stream);
- if (audio_decoder)
- {
- streams.SetAudioStream(i);
- audio_stream_num = i;
- video_only=0;
- }
- else
- audio_no_decoder = true;
- if (stream.stream_header->length && !stream.stream_header->sample_size && stream.stream_header->rate)
- g_duration = (uint64_t)stream.stream_header->length * (uint64_t)stream.stream_header->scale * 1000ULL / (uint64_t)stream.stream_header->rate;
- audio_bitrate = MulDiv(f->average_bytes_per_second, 8, 1000);
- plugin.SetInfo(audio_bitrate, -1, -1, -1);
- }
- }
- }
- else if (stream.stream_header->stream_type == nsavi::stream_type_video)
- {
- nsavi::video_format *f = (nsavi::video_format *)stream.stream_format;
- if (f)
- {
- stats.video_fourccs[f->compression]++;
- streams.AddVideoStream(i);
- if (!video_decoder)
- { // TODO: check priority
- video_decoder = FindVideoDecoder(header_list.avi_header, stream);
- if (video_decoder)
- {
- video_stream_num = i;
- streams.SetVideoStream(i);
- }
- else
- video_no_decoder = true;
- if (g_duration == -1 && stream.stream_header->rate)
- g_duration = (uint64_t)stream.stream_header->length * (uint64_t)stream.stream_header->scale * 1000ULL / (uint64_t)stream.stream_header->rate;
- }
- }
- }
- }
- }
- }
- if (AGAVE_API_STATS)
- {
- uint32_t audio_format = stats.GetAudioStat();
- uint32_t video_format = stats.GetVideoStat();
- AGAVE_API_STATS->SetStat(api_stats::AVI_AUDIO_FORMAT, audio_format);
- AGAVE_API_STATS->SetStat(api_stats::AVI_VIDEO_FOURCC, video_format);
- }
- if ((audio_no_decoder || video_no_decoder) && CheckDSHOW())
- {
- // use in_dshow to play this one
- HANDLE mainThread = WASABI_API_APP->main_getMainThreadHandle();
- if (mainThread)
- {
- Video_Stop();
- if (audio_decoder)
- {
- audio_decoder->Close();
- audio_decoder=0;
- }
- Video_Close();
- delete video_seek_table;
- delete audio_seek_table;
- wchar_t *fn = (wchar_t *)calloc(1024, sizeof(wchar_t *));
- reader->GetFilename(fn, 1024);
- QueueUserAPC(DSHOWAPC, mainThread, (ULONG_PTR)fn);
- CloseHandle(mainThread);
- return ;
- }
- }
- if (!audio_decoder && !video_decoder)
- {
- goto btfo;
- }
- if (!audio_decoder)
- {
- video_only=1;
- video_clock.Start();
- }
- }
- else
- {
- goto btfo;
- }
- SetVideoInfoText();
- video_output->extended(VIDUSER_SET_TRACKSELINTERFACE, (INT_PTR)&streams, 0);
- if (video_stream_num != 65536)
- video_seek_table = new nsavi::SeekTable(video_stream_num, !!video_decoder, &header_list);
- if (audio_stream_num != 65536)
- audio_seek_table = new nsavi::SeekTable(audio_stream_num, false, &header_list);
- uint64_t content_length = reader->GetContentLength();
- if (content_length && g_duration)
- {
- int total_bitrate = (int)(8ULL * content_length / (uint64_t)g_duration);
- plugin.SetInfo(total_bitrate, -1, -1, -1);
- }
- else if (header_list.avi_header->max_bytes_per_second)
- {
- int total_bitrate = MulDiv(header_list.avi_header->max_bytes_per_second, 8, 1000);
- plugin.SetInfo(total_bitrate, -1, -1, -1);
- }
- else
- {
- // use seek table for bitrate?
- }
- if (demuxer.FindMovieChunk() != nsavi::READ_OK)
- {
- goto btfo;
- }
- if (multiple_readers && video_decoder && !video_only)
- {
- wchar_t fn[MAX_PATH] = {0};
- reader->GetFilename(fn, MAX_PATH);
- if (video_reader.Open(fn) == nsavi::READ_OK)
- {
- MultiReaderLoop(demuxer, reader, &video_reader, audio_seek_table, video_seek_table);
- }
- else
- SingleReaderLoop(demuxer, reader, audio_seek_table, video_seek_table);
- }
- else
- SingleReaderLoop(demuxer, reader, audio_seek_table, video_seek_table);
- if (audio_opened && WaitForSingleObject(killswitch, 0) == WAIT_TIMEOUT)
- {
- out.Write(0, 0);
- out.WaitWhilePlaying();
- }
- btfo:
- if (WaitForSingleObject(killswitch, 0) == WAIT_TIMEOUT)
- PostMessage(plugin.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
- Video_Stop();
- if (audio_decoder)
- {
- audio_decoder->Close();
- audio_decoder=0;
- if (audio_opened)
- out.Close();
- }
- Video_Close();
- video_reader.Close();
- delete video_seek_table;
- delete audio_seek_table;
- }
- DWORD CALLBACK AVIPlayThread(LPVOID param)
- {
- if (!audio_break)
- audio_break = CreateEvent(0, TRUE, FALSE, 0);
- if (!audio_resume)
- audio_resume = CreateEvent(0, TRUE, FALSE, 0);
- if (!audio_break_done)
- audio_break_done = CreateEvent(0, FALSE, FALSE, 0);
- wchar_t *filename = (wchar_t *)param;
- if (PathIsURLW(filename))
- {
- AVIReaderHTTP reader(killswitch, seek_event);
- if (reader.Open(filename) != nsavi::READ_OK || reader.Connect() != nsavi::READ_OK)
- {
- if (WaitForSingleObject(killswitch, 200) == WAIT_TIMEOUT)
- PostMessage(plugin.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
- }
- else
- {
- PlayLoop(&reader, false);
- reader.Close();
- }
- }
- else
- {
- AVIReaderWin32 reader;
- if (reader.Open(filename) != nsavi::READ_OK)
- {
- if (WaitForSingleObject(killswitch, 200) == WAIT_TIMEOUT)
- PostMessage(plugin.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
- }
- else
- {
- wchar_t root[4] = {0};
- StringCchCopy(root, 4, filename);
- UINT drive_type = GetDriveType(root);
- if (drive_type == DRIVE_CDROM)
- PlayLoop(&reader, false);
- else
- PlayLoop(&reader, true);
- reader.Close();
- }
- }
- free(filename);
- return 0;
- }
|