123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428 |
- #include "main.h"
- #include "api__in_avi.h"
- #include "../nu/AutoLock.h"
- #include "../nu/SampleQueue.h"
- #include "../Winamp/wa_ipc.h"
- #include "interfaces.h"
- #include "../nsavi/nsavi.h"
- #include "../nu/ThreadName.h"
- #include "player.h"
- // {B6CB4A7C-A8D0-4c55-8E60-9F7A7A23DA0F}
- static const GUID playbackConfigGroupGUID =
- { 0xb6cb4a7c, 0xa8d0, 0x4c55, { 0x8e, 0x60, 0x9f, 0x7a, 0x7a, 0x23, 0xda, 0xf } };
- extern nsavi::HeaderList header_list;
- extern int video_stream_num;
- int width, height;
- extern IVideoOutput *video_output;
- static HANDLE video_thread=0;
- extern ifc_avivideodecoder *video_decoder;
- bool video_opened=false;
- static HANDLE coded_frames_event=0;
- static Nullsoft::Utility::LockGuard coded_frames_guard;
- uint64_t video_total_time=0;
- HANDLE video_break=0, video_flush=0, video_flush_done=0, video_resume=0, video_ready=0;
- 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;
- }
- void Video_Init()
- {
- video_opened=false;
- video_decoder=0;
- video_thread=0;
- width=0;
- height=0;
- video_total_time=0;
- if (coded_frames_event == 0)
- coded_frames_event = CreateEvent(NULL, FALSE, FALSE, NULL);
- /* video events */
- if (!video_break)
- video_break = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (!video_flush_done)
- video_flush_done = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (!video_flush)
- video_flush = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (!video_resume)
- video_resume = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (!video_ready)
- video_ready = CreateEvent(NULL, TRUE, FALSE, NULL);
- }
- struct FRAMEDATA
- {
- FRAMEDATA()
- {
- type = 0;
- data=0;
- length=0;
- }
- ~FRAMEDATA()
- {
- free(data);
- }
- void Reset()
- {
- free(data);
- data=0;
- length=0;
- type = 0;
- }
- void Set(uint16_t _type, void *_data, size_t _length)
- {
- type = _type;
- data = _data;
- length = _length;
- }
- void *data;
- size_t length;
- uint16_t type;
- };
- static SampleQueue<FRAMEDATA> coded_frames;
- extern int GetOutputTime();
- struct VideoContext
- {
- nsavi::avi_reader *reader;
- nsavi::Demuxer *demuxer;
- int video_stream_num;
- };
- static void DecodeVideo(FRAMEDATA *frame_data)
- {
- HANDLE handles[] = {killswitch, video_break};
- if (WaitForMultipleObjects(2, handles, FALSE, 0) == WAIT_TIMEOUT)
- {
- int decodeResult = video_decoder->DecodeChunk(frame_data->type, frame_data->data, frame_data->length);
- if (decodeResult == ifc_avivideodecoder::AVI_SUCCESS)
- {
- void *data, *decoder_data;
- while (video_decoder->GetPicture(&data, &decoder_data) == ifc_avivideodecoder::AVI_SUCCESS)
- {
- if (!video_opened)
- {
- int color_format;
- double aspect_ratio=1.0;
- int flip=0;
- if (video_decoder->GetOutputProperties(&width, &height, &color_format, &aspect_ratio, &flip) == ifc_avivideodecoder::AVI_SUCCESS)
- {
- nsavi::VPRP *vprp = header_list.stream_list[video_stream_num].video_properties;
- if (vprp)
- {
- uint32_t asp = vprp->aspect_ratio;
- uint32_t aspect_x = HIWORD(asp);
- uint32_t aspect_y = LOWORD(asp);
- aspect_ratio = (double)vprp->frame_width / (double)vprp->frame_height / ((double)aspect_x / (double)aspect_y);
- }
- else
- aspect_ratio = 1.0/aspect_ratio;
- video_output->extended(VIDUSER_SET_THREAD_SAFE, 1, 0);
- video_output->open(width, height, flip, aspect_ratio, color_format);
- video_opened=true;
- }
- }
- if (video_opened)
- {
- int timestamp=(int)(video_total_time*1000ULL/(uint64_t) header_list.stream_list[video_stream_num].stream_header->rate);
- again:
- int real_time =(int)GetOutputTime();
- if (timestamp > (real_time+5))
- {
- HANDLE handles[] = {killswitch, video_break};
- int ret=WaitForMultipleObjects(2, handles, FALSE, timestamp-real_time);
- if (ret != WAIT_TIMEOUT)
- {
- video_decoder->FreePicture(data, decoder_data);
- frame_data->Reset();
- return ;
- }
- goto again; // TODO: handle paused state a little better than this
- }
- RGB32 *palette=0;
- if (video_decoder->GetPalette(&palette) == ifc_avivideodecoder::AVI_SUCCESS)
- {
- video_output->extended(VIDUSER_SET_PALETTE, (INT_PTR)palette, 0);
- }
- video_output->draw(data);
- }
- video_total_time += header_list.stream_list[video_stream_num].stream_header->scale;
- video_decoder->FreePicture(data, decoder_data);
- }
- }
- }
- // frame_data->Reset();
- }
- static DWORD CALLBACK VideoProcedure(LPVOID param)
- {
- SetThreadName(-1,"AVI_VideoProcedure");
- HANDLE wait_handles[] = { killswitch, video_break, video_flush, video_resume, coded_frames_event };
- while (1)
- {
- int ret = WaitForMultipleObjects(5, wait_handles, FALSE, INFINITE);
- if (ret == WAIT_OBJECT_0)
- {
- break;
- }
- if (ret == WAIT_OBJECT_0 + 1) // video break
- {
- ResetEvent(coded_frames_event);
- ResetEvent(video_break);
- SetEvent(video_flush_done);
- }
- else if (ret == WAIT_OBJECT_0 + 2) // video flush
- {
- if (video_decoder)
- video_decoder->Flush();
- ResetEvent(video_flush);
- coded_frames.Trim();
- SetEvent(video_flush_done);
- }
- else if (ret == WAIT_OBJECT_0 + 3) // video resume
- {
- ResetEvent(video_resume);
- SetEvent(coded_frames_event);
- SetEvent(video_flush_done);
- }
- else if (ret == WAIT_OBJECT_0 + 4) // data from demuxer
- {
- FRAMEDATA *frame_data = 0;
- while (frame_data = coded_frames.PopProcessed())
- {
- DecodeVideo(frame_data);
- frame_data->Reset();
- coded_frames.PushFree(frame_data);
- }
- }
- };
- if (video_opened && video_output)
- video_output->close();
- video_opened=false;
- return 0;
- }
- static DWORD CALLBACK VideoReaderProcedure(LPVOID param)
- {
- VideoContext *ctx = (VideoContext *)param;
- nsavi::avi_reader *reader = ctx->reader;
- nsavi::Demuxer *demuxer = ctx->demuxer;
- SetThreadName(-1,"AVI_VideoProcedure");
- HANDLE wait_handles[] = { killswitch, video_break, video_flush, video_resume };
- int waitTime = 0;
- while (1)
- {
- int ret = WaitForMultipleObjects(4, wait_handles, FALSE, waitTime);
- if (ret == WAIT_OBJECT_0)
- {
- break;
- }
- if (ret == WAIT_OBJECT_0 + 1) // video break
- {
- ResetEvent(coded_frames_event);
- ResetEvent(video_break);
- SetEvent(video_flush_done);
- waitTime = INFINITE;
- }
- else if (ret == WAIT_OBJECT_0 + 2) // video flush
- {
- if (video_decoder)
- video_decoder->Flush();
- ResetEvent(video_flush);
- coded_frames.Trim();
- SetEvent(video_flush_done);
- waitTime = 0;
- }
- else if (ret == WAIT_OBJECT_0 + 3) // video resume
- {
- ResetEvent(video_resume);
- SetEvent(coded_frames_event);
- SetEvent(video_flush_done);
- waitTime = 0;
- }
- else if (ret == WAIT_TIMEOUT)
- {
- void *data=0;
- uint32_t data_size = 0;
- uint32_t data_type = 0;
- int ret = demuxer->GetNextMovieChunk(reader, &data, &data_size, &data_type, video_stream_num);
- if (ret != nsavi::READ_OK)
- {
- break;
- }
- int stream_number = GetStreamNumber(data_type);
- uint16_t type = (data_type>>16);
- if (stream_number == video_stream_num)
- {
- FRAMEDATA frame_data;
- frame_data.data = data;
- frame_data.length = data_size;
- frame_data.type = type;
- DecodeVideo(&frame_data);
- frame_data.Reset();
- }
- else
- free(data);
- }
- };
- if (video_opened && video_output)
- video_output->close();
- video_opened=false;
- free(ctx);
- return 0;
- }
- bool CreateVideoReaderThread(nsavi::Demuxer *demuxer, nsavi::avi_reader *video_reader)
- {
- if (!video_decoder || video_only)
- return false;
- VideoContext *context = (VideoContext *)calloc(1, sizeof(VideoContext));
- context->reader = video_reader;
- context->demuxer = demuxer;
- DWORD threadId = 0;
- video_thread = CreateThread(0, 0, VideoReaderProcedure, context, 0, &threadId);
- SetThreadPriority(video_thread, (INT)AGAVE_API_CONFIG->GetInt(playbackConfigGroupGUID, L"priority", THREAD_PRIORITY_HIGHEST));
- return true;
- }
- bool OnVideo(uint16_t type, void *data, size_t length)
- {
- if (!video_decoder)
- return false;
- if (!video_only && !video_thread)
- {
- DWORD threadId;
- video_thread = CreateThread(0, 0, VideoProcedure, 0, 0, &threadId);
- SetThreadPriority(video_thread, (INT)AGAVE_API_CONFIG->GetInt(playbackConfigGroupGUID, L"priority", THREAD_PRIORITY_HIGHEST));
- }
- if (video_thread)
- {
- FRAMEDATA *new_frame = coded_frames.PopFree();
- if (new_frame)
- {
- new_frame->Set(type, data, length);
- coded_frames.PushProcessed(new_frame);
- SetEvent(coded_frames_event);
- }
- return true;
- }
- else if (video_only)
- {
- FRAMEDATA *new_frame = coded_frames.PopFree();
- if (new_frame)
- {
- new_frame->Set(type, data, length);
- DecodeVideo(new_frame);
- new_frame->Reset();
- }
- return true;
- }
- return false;
- }
- void Video_Stop()
- {
- SetEvent(killswitch);
- if (video_only)
- {
- video_thread=0;
- ResetEvent(coded_frames_event);
- Nullsoft::Utility::AutoLock l(coded_frames_guard);
- coded_frames.Trim();
- if (video_opened && video_output)
- video_output->close();
- video_opened=false;
- }
- else
- {
- if (video_thread)
- WaitForSingleObject(video_thread, INFINITE);
- video_thread=0;
- ResetEvent(coded_frames_event);
- Nullsoft::Utility::AutoLock l(coded_frames_guard);
- coded_frames.Trim();
- }
- }
- void Video_Close()
- {
- video_opened=false;
- if (video_decoder)
- {
- video_decoder->Close();
- video_decoder=0;
- }
- }
- void Video_Break()
- {
- if (!video_only && video_decoder)
- {
- SetEvent(video_break);
- HANDLE events[2] = {video_flush_done, video_thread};
- WaitForMultipleObjects(2, events, FALSE, INFINITE);
- }
- }
- void Video_Flush()
- {
- if (video_decoder)
- {
- if (video_only)
- {
- video_decoder->Flush();
- }
- else
- {
- SetEvent(video_flush);
- HANDLE events[2] = {video_flush_done, video_thread};
- WaitForMultipleObjects(2, events, FALSE, INFINITE);
- }
- }
- }
- /*
- bool Video_DecoderReady()
- {
- if (!video_decoder)
- return true;
- return !!video_decoder->Ready();
- }
- */
|