| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 | 
							- #include "main.h"
 
- #include "VideoThread.h"
 
- #include "../Winamp/wa_ipc.h"
 
- VideoSample *video_sample=0;
 
- IVideoOutput *videoOutput=0;
 
- static bool video_reopen=false;
 
- static int height=0;
 
- static int width=0;
 
- static bool video_opened=false;
 
- static int consecutive_early_frames;
 
- HANDLE video_flush = 0, video_start_flushing=0, video_flush_done = 0, video_resume = 0;
 
- static HANDLE video_thread = 0;
 
- MP4SampleId nextVideoSampleId=1; // set in conjunction with video_flush
 
- static void OpenVideo()
 
- {
 
- 	if (!video_opened || video_reopen)
 
- 	{
 
- 		consecutive_early_frames = 0;
 
- 		if (!videoOutput)
 
- 			videoOutput = (IVideoOutput *)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GET_IVIDEOOUTPUT);
 
- 		int color_format;
 
- 		double aspect_ratio=1.0;
 
- 		if (video && video->GetOutputFormat(&width, &height, &color_format, &aspect_ratio) == MP4_VIDEO_SUCCESS)
 
- 		{
 
- 			videoOutput->extended(VIDUSER_SET_THREAD_SAFE, 1, 0);
 
- 			videoOutput->open(width, height, 0, 1.0/aspect_ratio, color_format);
 
- 			video_opened = true;
 
- 			video_reopen = false;
 
- 		}
 
- 	}
 
- }
 
- static DecodedVideoSample *GetNextPicture()
 
- {
 
- 	void *data, *decoder_data;
 
- 	MP4Timestamp timestamp=video_sample?(video_sample->timestamp):0;
 
- 	switch(video->GetPicture(&data, &decoder_data, ×tamp))
 
- 	{
 
- 	case MP4_VIDEO_OUTPUT_FORMAT_CHANGED:
 
- 		video_reopen=true;
 
- 		// fall through
 
- 	case MP4_VIDEO_SUCCESS:
 
- 		DecodedVideoSample *decoded = new DecodedVideoSample;
 
- 		decoded->decoder = video;
 
- 		decoded->decoder_data = decoder_data;
 
- 		decoded->timestamp = timestamp;
 
- 		decoded->output = data;
 
- 		return decoded;
 
- 	}
 
- 	return 0;
 
- }
 
- static void OutputPicture(DecodedVideoSample *decoded_video_sample)
 
- {
 
- 	if (decoded_video_sample)
 
- 	{
 
- 		int outputTime = (int)((decoded_video_sample->timestamp*1000ULL)/(uint64_t)m_video_timescale);
 
- again:
 
- 		MP4Duration realTime = GetClock();	
 
- 		int time_diff = outputTime - realTime;
 
- 		if (time_diff > 12 && consecutive_early_frames)  // plenty of time, go ahead and turn off frame dropping
 
- 		{
 
- 			if (--consecutive_early_frames == 0)
 
- 				video->HurryUp(0);
 
- 		}
 
- 		else if (time_diff < -50) // shit we're way late, start dropping frames
 
- 		{
 
- 			video->HurryUp(1);
 
- 			consecutive_early_frames += 3;
 
- 		}
 
- 		if (time_diff > 3)
 
- 		{
 
- 			HANDLE handles[] = {killEvent, video_start_flushing};
 
- 			if (WaitForMultipleObjects(2, handles, FALSE, outputTime-realTime) != WAIT_TIMEOUT)
 
- 			{
 
- 				delete decoded_video_sample;
 
- 				decoded_video_sample=0;
 
- 				return;
 
- 			}
 
- 			goto again; // TODO: handle paused state a little better than this
 
- 		}
 
- 		OpenVideo(); // open video if we havn't already
 
- 		videoOutput->draw(decoded_video_sample->output);
 
- 		delete decoded_video_sample;
 
- 		decoded_video_sample=0;
 
- 	/* TODO: probably want separate audio and video done flags
 
- 	if (temp->sampleId == numSamples) // done!
 
- 	done = true;
 
- 	*/
 
- 	}
 
- }
 
- static bool ReadNextVideoSample()
 
- {
 
- 	while (nextVideoSampleId <= numVideoSamples)
 
- 	{
 
- 		VideoSample &sample=*video_sample;
 
- 		unsigned __int32 buffer_size = sample.inputSize;
 
- 		bool isSync=false;
 
- 		MP4Duration duration, offset;
 
- 		play_mp4_guard.Lock();
 
- 		bool sample_read=MP4ReadSample(MP4hFile, video_track, nextVideoSampleId++, (unsigned __int8 **)&sample.input, &buffer_size, &sample.timestamp, &duration, &offset, &isSync);
 
- 		play_mp4_guard.Unlock();
 
- 		if (sample_read)
 
- 		{
 
- 			// some buggy movies store signed int32 offsets, so let's deal with it
 
- 			offset = (uint32_t)offset;
 
- 			int32_t signed_offset = (int32_t)offset;
 
- 			sample.timestamp += signed_offset; 
 
- 			//int outputTime = (int)((sample.timestamp*1000ULL) /(uint64_t)m_video_timescale);
 
- 			sample.inputValid = buffer_size;
 
- 			return true;
 
- 		}
 
- 	}
 
- 	return false;
 
- }
 
- static DWORD WINAPI VideoPlayThread(LPVOID parameter)
 
- {
 
- 	DWORD waitTime = 0;
 
- 	HANDLE handles[] = {killEvent, video_flush, video_start_flushing, video_resume};
 
- 	while (1)
 
- 	{
 
- 		int ret = WaitForMultipleObjects(4, handles, FALSE, waitTime);
 
- 		if (ret == WAIT_OBJECT_0) // kill
 
- 			break;
 
- 		else if (ret == WAIT_OBJECT_0+1)  // flush
 
- 		{
 
- 			if (video)
 
- 				video->Flush();
 
- 			ResetEvent(video_flush);
 
- 			waitTime = 0;
 
- 			SetEvent(video_flush_done);
 
- 		}
 
- 		else if (ret == WAIT_OBJECT_0+2) // start flushing
 
- 		{
 
- 			waitTime = INFINITE; // this will stop us from decoding samples for a while
 
- 			ResetEvent(video_start_flushing);
 
- 			SetEvent(video_flush_done);
 
- 		}
 
- 		else if (ret == WAIT_OBJECT_0+3) // resume playback (like flush but don't flush the decoder)
 
- 		{
 
- 			ResetEvent(video_resume);
 
- 			waitTime = 0;
 
- 			SetEvent(video_flush_done);
 
- 		}
 
- 		else if (ret == WAIT_TIMEOUT)
 
- 		{
 
- 			if (ReadNextVideoSample())
 
- 			{
 
- 				int ret = video->DecodeSample(video_sample->input, video_sample->inputValid, video_sample->timestamp);
 
- 				if (ret == MP4_VIDEO_OUTPUT_FORMAT_CHANGED)
 
- 					video_reopen=true;
 
- 				if (ret == MP4_VIDEO_AGAIN)
 
- 					nextVideoSampleId--;
 
- 				DecodedVideoSample *picture = 0;
 
- 				while (picture = GetNextPicture())
 
- 				{
 
- 					OutputPicture(picture);
 
- 				}
 
- 				waitTime = 0;
 
- 			}
 
- 			else
 
- 			{
 
- 				// TODO: tell decoder end-of-file and get any buffers in queue
 
- 				if (!audio)
 
- 					PostMessage(mod.hMainWindow, WM_WA_MPEG_EOF, 0, 0);
 
- 				waitTime = INFINITE; // out of stuff to do, wait for kill or flush
 
- 			}
 
- 		}
 
- 		else // error
 
- 			break;
 
- 	}
 
- 	if (videoOutput)
 
- 		videoOutput->close();
 
- 	return 0;
 
- }
 
- void Video_Init()
 
- {
 
- 	width=0;
 
- 	height=0;
 
- 	video_reopen=false;
 
- 	video_opened=false;
 
- 	video_flush = CreateEvent(NULL, TRUE, FALSE, NULL);
 
- 	video_start_flushing = CreateEvent(NULL, TRUE, FALSE, NULL);
 
- 	video_flush_done = CreateEvent(NULL, FALSE, FALSE, NULL);
 
- 	video_resume = CreateEvent(NULL, TRUE, FALSE, NULL);	
 
- 	video_thread = CreateThread(0, 0, VideoPlayThread, 0, 0, 0);
 
- }
 
- void Video_Close()
 
- {
 
- 	WaitForSingleObject(video_thread, INFINITE);
 
- 	CloseHandle(video_thread);
 
- 	video_thread = 0;
 
- 	CloseHandle(video_start_flushing);
 
- 	video_start_flushing=0;
 
- 	CloseHandle(video_flush);
 
- 	video_flush=0;
 
- 	CloseHandle(video_resume);
 
- 	video_resume=0;
 
- 	CloseHandle(video_flush_done);
 
- 	video_flush_done = 0;	
 
- 	
 
- 	delete video_sample;
 
- 	video_sample=0;
 
- }
 
 
  |