2 Copyright 2004-2005 Chris Tallon
\r
4 This file is part of VOMP.
\r
6 VOMP is free software; you can redistribute it and/or modify
\r
7 it under the terms of the GNU General Public License as published by
\r
8 the Free Software Foundation; either version 2 of the License, or
\r
9 (at your option) any later version.
\r
11 VOMP is distributed in the hope that it will be useful,
\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 GNU General Public License for more details.
\r
16 You should have received a copy of the GNU General Public License
\r
17 along with VOMP; if not, write to the Free Software
\r
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
21 #include "videowin.h"
\r
23 #include "dssourcefilter.h"
\r
24 #include "dsallocator.h"
\r
28 void AdjustWindow();
\r
32 VideoWin::VideoWin()
\r
34 dsgraphbuilder=NULL;
\r
35 dsmediacontrol=NULL;
\r
43 dsvmrsurfnotify=NULL;
\r
44 filtermutex=CreateMutex(NULL,FALSE,NULL);
\r
46 offsetvideonotset=true;
\r
47 offsetaudionotset=true;
\r
54 cur_audio_media_sample=NULL;
\r
55 cur_video_media_sample=NULL;
\r
66 VideoWin::~VideoWin()
\r
69 CloseHandle(filtermutex);
\r
76 int VideoWin::init(UCHAR tformat)
\r
78 if (initted) return 0;
\r
81 tvsize=Video::ASPECT16X9; //Internally Vomp should think we are a 16:9 TV
\r
85 if (!setFormat(tformat)){ shutdown(); return 0; }
\r
89 int VideoWin::setTVsize(UCHAR ttvsize)
\r
91 pseudotvsize=ttvsize;
\r
95 int VideoWin::setDefaultAspect()
\r
97 return setAspectRatio(Video::ASPECT4X3);
\r
100 int VideoWin::shutdown()
\r
102 if (!initted) return 0;
\r
107 int VideoWin::setFormat(UCHAR tformat)
\r
109 if (!initted) return 0;
\r
110 if ((tformat != PAL) && (tformat != NTSC)) return 0;
\r
112 if (format == NTSC)
\r
115 screenHeight = 480;
\r
120 screenHeight = 576;
\r
126 int VideoWin::setConnection(UCHAR tconnection)
\r
128 if (!initted) return 0;
\r
129 if ((tconnection != COMPOSITERGB) && (tconnection != SVIDEO)) return 0;
\r
130 connection = tconnection;
\r
135 int VideoWin::setAspectRatio(UCHAR taspectRatio)
\r
137 if (!initted) return 0;
\r
138 if ((taspectRatio != ASPECT4X3) && (taspectRatio != ASPECT16X9)) return 0;
\r
139 aspectRatio = taspectRatio;
\r
144 int VideoWin::setMode(UCHAR tmode)
\r
146 if (!initted) return 0;
\r
148 //if ((tmode == LETTERBOX) && (tvsize == ASPECT16X9)) return 0; // invalid mode
\r
150 if ((tmode != NORMAL) && (tmode != LETTERBOX) && (tmode != UNKNOWN2) && (tmode != QUARTER) && (tmode != EIGHTH)
\r
151 && (tmode != ZOOM) && (tmode != UNKNOWN6)) return 0;
\r
160 int VideoWin::signalOff()
\r
165 int VideoWin::signalOn()
\r
170 int VideoWin::setSource()
\r
172 if (!initted) return 0;
\r
177 int VideoWin::setPosition(int x, int y)
\r
179 if (!initted) return 0;
\r
180 if (mode==QUARTER || mode==EIGHTH) {
\r
187 int VideoWin::sync()
\r
189 if (!initted) return 0;
\r
194 #ifdef DS_DEBUG // This stuff would not included in vomp due to lincemse restrcitions
\r
195 #include "dshelper.h"
\r
200 int VideoWin::play()
\r
202 if (!initted) return 0;
\r
204 //Build filter graph
\r
207 if (hres=CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,
\r
208 IID_IGraphBuilder,(void**)&dsgraphbuilder)!=S_OK) {
\r
212 AddToRot(dsgraphbuilder,&graphidentifier);
\r
214 //This is just a try to see if building the graph works
\r
215 // dsgraphbuilder->RenderFile(L"D:\\Projekte\\VTP Client\\test.mpa" ,NULL);
\r
216 //So this is the real code, this prevents the feeder from calling noexisting objects!
\r
217 WaitForSingleObject(filtermutex,INFINITE);
\r
218 firstsynched=false;
\r
219 sourcefilter=new DsSourceFilter(); //Creating our Source filter for pushing Data
\r
221 if (hres=dsgraphbuilder->AddFilter(sourcefilter,L"Vomp Win Source Filter")!=S_OK) {
\r
222 Log::getInstance()->log("VideoWin", Log::WARN , "Failed adding Vomp Source Filter!");
\r
224 ReleaseMutex(filtermutex);
\r
228 if (hres=dsgraphbuilder->Render(sourcefilter->GetPin(0)/*audio*/)!=S_OK) {
\r
229 Log::getInstance()->log("VideoWin", Log::WARN , "Failed rendering audio!");
\r
231 ReleaseMutex(filtermutex);
\r
237 //We alloc the vmr9 as next step
\r
238 if (hres=CoCreateInstance(CLSID_VideoMixingRenderer9,0,
\r
239 CLSCTX_INPROC_SERVER,IID_IBaseFilter,(void**) &dsvmrrenderer)!=S_OK) {
\r
240 Log::getInstance()->log("VideoWin", Log::WARN ,"Failed creating VMR9 renderer!");
\r
242 ReleaseMutex(filtermutex);
\r
245 if (hres=dsgraphbuilder->AddFilter(dsvmrrenderer,L"VMR9")!=S_OK) {
\r
247 Log::getInstance()->log("VideoWin", Log::WARN ,"Failed adding VMR9 renderer!");
\r
248 ReleaseMutex(filtermutex);
\r
251 IVMRFilterConfig9* vmrfilconfig;
\r
252 if (dsvmrrenderer->QueryInterface(IID_IVMRFilterConfig9,(void**)&vmrfilconfig)!=S_OK) {
\r
254 Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Filterconfig interface!");
\r
255 ReleaseMutex(filtermutex);
\r
258 vmrfilconfig->SetRenderingMode(VMR9Mode_Renderless);
\r
259 vmrfilconfig->Release();
\r
261 if (dsvmrrenderer->QueryInterface(IID_IVMRSurfaceAllocatorNotify9,(void**)& dsvmrsurfnotify)!=S_OK) {
\r
263 Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Surface Allocator interface!");
\r
264 ReleaseMutex(filtermutex);
\r
267 allocatorvmr=new DsAllocator();
\r
268 dsvmrsurfnotify->AdviseSurfaceAllocator(NULL,allocatorvmr);
\r
269 allocatorvmr->AdviseNotify(dsvmrsurfnotify);
\r
273 /*VMR 9 stuff end */
\r
274 IFilterGraph2*fg2=NULL;
\r
275 if (dsgraphbuilder->QueryInterface(IID_IFilterGraph2,(void**)&fg2)!=S_OK) {
\r
276 Log::getInstance()->log("VideoWin", Log::WARN , "Failed querying for FilterGraph2 Interface!");
\r
278 ReleaseMutex(filtermutex);
\r
281 if (hres=fg2->RenderEx(sourcefilter->GetPin(1)/*video*/,
\r
282 AM_RENDEREX_RENDERTOEXISTINGRENDERERS,NULL)!=S_OK) {
\r
283 Log::getInstance()->log("VideoWin", Log::WARN , "Failed rendering Video!");
\r
285 ReleaseMutex(filtermutex);
\r
290 if (hres=CoCreateInstance(CLSID_SystemClock,NULL,CLSCTX_INPROC_SERVER,
\r
291 IID_IReferenceClock,(void**)&dsrefclock)!=S_OK) {
\r
295 dsgraphbuilder->QueryInterface(IID_IMediaFilter,(void **) &dsmediafilter);
\r
296 dsmediafilter->SetSyncSource(dsrefclock);
\r
298 dsgraphbuilder->QueryInterface(IID_IMediaControl,(void **) &dsmediacontrol);
\r
299 dsgraphbuilder->QueryInterface(IID_IBasicAudio,(void **) &dsbasicaudio);
\r
301 dsmediacontrol->Run();
\r
302 ReleaseMutex(filtermutex);
\r
306 int VideoWin::stop()
\r
308 if (!initted) return 0;
\r
316 int VideoWin::reset()
\r
318 if (!initted) return 0;
\r
326 int VideoWin::pause()
\r
328 if (!initted) return 0;
\r
329 if (dsmediacontrol) dsmediacontrol->Pause();
\r
333 int VideoWin::unPause() // FIXME get rid - same as play!!
\r
334 {//No on windows this is not the same, I don't get rid of!
\r
335 if (!initted) return 0;
\r
336 if (dsmediacontrol) dsmediacontrol->Run();
\r
340 int VideoWin::fastForward()
\r
342 if (!initted) return 0;
\r
347 int VideoWin::unFastForward()
\r
349 if (!initted) return 0;
\r
354 int VideoWin::attachFrameBuffer()
\r
356 if (!initted) return 0;
\r
360 int VideoWin::blank(void)
\r
362 ((OsdWin*)Osd::getInstance())->Blank();
\r
366 ULLONG VideoWin::getCurrentTimestamp()
\r
368 REFERENCE_TIME startoffset;
\r
369 REFERENCE_TIME ncr_time;
\r
371 if (!dsrefclock || !sourcefilter) return 0;
\r
372 FILTER_STATE state;
\r
373 sourcefilter->GetState(10,&state);
\r
375 if (state==State_Running) dsrefclock->GetTime(&cr_time);
\r
377 startoffset=sourcefilter->getStartOffset();
\r
378 ncr_time-=startoffset;
\r
379 ncr_time-=lastreftimeRT;
\r
380 ULLONG result=frameNumberToTimecode(
\r
381 VDR::getInstance()->frameNumberFromPosition(lastreftimeBYTE));
\r
382 result+=(ULLONG)(ncr_time/10000LL*90LL);
\r
387 ULONG VideoWin::timecodeToFrameNumber(ULLONG timecode)
\r
389 if (format == PAL) return (ULONG)(((double)timecode / (double)90000) * (double)25);
\r
390 else return (ULONG)(((double)timecode / (double)90000) * (double)30);
\r
393 ULLONG VideoWin::frameNumberToTimecode(ULONG framenumber)
\r
395 if (format == PAL) return (ULLONG)(((double)framenumber * (double)90000) / (double)25);
\r
396 else return (ULLONG)(((double)framenumber * (double)90000) / (double)30);
\r
399 void VideoWin::CleanupDS()
\r
401 WaitForSingleObject(filtermutex,INFINITE);
\r
402 if (cur_audio_media_sample) {
\r
403 cur_audio_media_sample->Release();
\r
404 cur_audio_media_sample=NULL;
\r
406 if (cur_video_media_sample) {
\r
407 cur_video_media_sample->Release();
\r
408 cur_video_media_sample=NULL;
\r
410 if (dsbasicaudio) {
\r
411 dsbasicaudio->Release();
\r
414 if (dsvmrsurfnotify) {
\r
415 dsvmrsurfnotify->Release();
\r
416 dsvmrsurfnotify=NULL;
\r
418 if (dsvmrrenderer) {
\r
419 dsvmrrenderer->Release();
\r
420 dsvmrrenderer=NULL;
\r
423 if (allocatorvmr) {
\r
424 allocatorvmr->Release();
\r
429 dsrefclock->Release();
\r
432 if (dsmediafilter) {
\r
433 dsmediafilter->Release();
\r
434 dsmediafilter=NULL;
\r
438 if (dsmediacontrol) {
\r
439 dsmediacontrol->Stop();
\r
440 dsmediacontrol->Release();
\r
441 dsmediacontrol=NULL;
\r
443 if (dsgraphbuilder){
\r
445 RemoveFromRot(graphidentifier);
\r
447 dsgraphbuilder->Release();
\r
448 dsgraphbuilder=NULL;
\r
449 sourcefilter=NULL; //The Graph Builder destroys our SourceFilter
\r
451 ReleaseMutex(filtermutex);
\r
456 UINT VideoWin::DeliverMediaSample(MediaPacket packet,
\r
460 /*First Check, if we have an audio sample*/
\r
462 /*First Check, if we have an audio sample*/
\r
464 IMediaSample* ms=NULL;
\r
465 REFERENCE_TIME reftime1=0;
\r
466 REFERENCE_TIME reftime2=0;
\r
468 UINT headerstrip=0;
\r
469 if (packet.disconti) {
\r
470 firstsynched=false;
\r
471 DeliverVideoMediaSample();
\r
476 /*Inspect PES-Header */
\r
478 if (*samplepos==0) {//stripheader
\r
479 headerstrip=buffer[packet.pos_buffer+8]+9/*is this right*/;
\r
480 *samplepos+=headerstrip;
\r
481 if ( packet.synched ) {
\r
482 DeliverVideoMediaSample();//write out old data
\r
483 /* if (packet.presentation_time<0) { //Preroll?
\r
484 *samplepos=packet.length;//if we have not processed at least one
\r
485 return packet.length;//synched packet ignore it!
\r
488 reftime1=packet.presentation_time;
\r
489 reftime2=reftime1+1;
\r
492 if (!firstsynched) {//
\r
493 *samplepos=packet.length;//if we have not processed at least one
\r
494 return packet.length;//synched packet ignore it!
\r
502 if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
\r
507 ms_pos=ms->GetActualDataLength();
\r
508 ms_length=ms->GetSize();
\r
509 haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
\r
510 if ((ms_length-ms_pos)<1) {
\r
511 DeliverVideoMediaSample(); //we are full!
\r
512 if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
\r
517 ms_pos=ms->GetActualDataLength();
\r
518 ms_length=ms->GetSize();
\r
519 haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
\r
521 ms->GetPointer(&ms_buf);
\r
524 if (ms_pos==0) {//will only be changed on first packet
\r
525 if (packet.disconti) {
\r
526 ms->SetDiscontinuity(TRUE);
\r
528 ms->SetDiscontinuity(FALSE);
\r
530 if (packet.synched) {
\r
531 ms->SetSyncPoint(TRUE);
\r
532 ms->SetTime(&reftime1,&reftime2);
\r
533 //ms->SetTime(NULL,NULL);
\r
534 ms->SetMediaTime(NULL, NULL);
\r
535 if (reftime1<0) ms->SetPreroll(TRUE);
\r
536 else ms->SetPreroll(FALSE);
\r
537 /*Timecode handling*/
\r
538 lastreftimeRT=reftime1;
\r
539 lastreftimeBYTE=packet.recording_byte_pos;
\r
542 ms->SetSyncPoint(FALSE);
\r
543 ms->SetTime(NULL,NULL);
\r
544 ms->SetMediaTime(NULL, NULL);
\r
545 ms->SetPreroll(FALSE);
\r
547 // ms->SetSyncPoint(TRUE);
\r
552 memcpy(ms_buf+ms_pos,buffer+packet.pos_buffer+*samplepos,haveToCopy);
\r
553 ms->SetActualDataLength(haveToCopy+ms_pos);
\r
555 *samplepos+=haveToCopy;
\r
557 return haveToCopy+headerstrip;
\r
561 *samplepos+=packet.length;
\r
562 MILLISLEEP(0); //yet not implemented//bad idea
\r
563 return packet.length;
\r
567 int VideoWin::getCurrentAudioMediaSample(IMediaSample** ms)
\r
569 //WaitForSingleObject(filtermutex,INFINITE);
\r
570 if (!sourcefilter){
\r
571 // ReleaseMutex(filtermutex);
\r
574 if (cur_audio_media_sample) {
\r
575 *ms=cur_audio_media_sample;//already open
\r
578 if (!sourcefilter->getCurrentAudioMediaSample(ms)) {
\r
579 // ReleaseMutex(filtermutex);
\r
581 if (*ms) (*ms)->SetActualDataLength(0);
\r
582 cur_audio_media_sample=*ms;
\r
583 //Don't release the mutex before deliver
\r
587 int VideoWin::getCurrentVideoMediaSample(IMediaSample** ms)
\r
589 //WaitForSingleObject(filtermutex,INFINITE);
\r
590 if (!sourcefilter){
\r
591 // ReleaseMutex(filtermutex);
\r
594 if (cur_video_media_sample) {
\r
595 *ms=cur_video_media_sample;//already open
\r
598 if (!sourcefilter->getCurrentVideoMediaSample(ms)) {
\r
599 // ReleaseMutex(filtermutex);
\r
601 if (*ms) (*ms)->SetActualDataLength(0);
\r
603 cur_video_media_sample=*ms;
\r
604 //Don't release the mutex before deliver
\r
608 int VideoWin::DeliverAudioMediaSample(){
\r
609 if (cur_audio_media_sample) {
\r
610 sourcefilter->DeliverAudioMediaSample(cur_audio_media_sample);
\r
611 cur_audio_media_sample=NULL;
\r
613 //ReleaseMutex(filtermutex);
\r
617 int VideoWin::DeliverVideoMediaSample(){
\r
618 if (cur_video_media_sample) {
\r
619 sourcefilter->DeliverVideoMediaSample(cur_video_media_sample);
\r
620 cur_video_media_sample=NULL;
\r
622 //ReleaseMutex(filtermutex);
\r
626 long long VideoWin::SetStartOffset(long long curreftime, bool *rsync)
\r
629 if (offsetnotset) {
\r
630 startoffset=curreftime;//offset is set for audio
\r
631 offsetnotset=false;
\r
632 offsetvideonotset=false;
\r
636 if (offsetvideonotset) {
\r
637 offsetvideonotset=false;
\r
640 if ( (curreftime-lastrefvideotime)>10000000LL
\r
641 || (curreftime-lastrefvideotime)<-10000000LL) {//if pts jumps to big resync
\r
642 startoffset+=curreftime-lastrefvideotime;
\r
643 lastrefaudiotime+=curreftime-lastrefvideotime;
\r
645 offsetaudionotset=true;
\r
652 lastrefvideotime=curreftime;
\r
654 return startoffset;
\r
658 long long VideoWin::SetStartAudioOffset(long long curreftime, bool *rsync)
\r
661 if (offsetnotset) {
\r
662 startoffset=curreftime;
\r
663 offsetnotset=false;
\r
664 offsetaudionotset=false;
\r
666 if (offsetaudionotset) {
\r
667 offsetaudionotset=false;
\r
670 if ( (curreftime-lastrefaudiotime)>10000000LL
\r
671 || (curreftime-lastrefaudiotime)<-10000000LL) {//if pts jumps to big resync
\r
672 startoffset+=curreftime-lastrefaudiotime;
\r
673 lastrefvideotime+=curreftime-lastrefaudiotime;
\r
675 offsetvideonotset=true;
\r
681 lastrefaudiotime=curreftime;
\r
682 return startoffset;
\r
685 void VideoWin::ResetTimeOffsets() {
\r
686 offsetnotset=true; //called from demuxer
\r
687 offsetvideonotset=true;
\r
688 offsetaudionotset=true;
\r
690 lastrefaudiotime=0;
\r
691 lastrefvideotime=0;
\r
698 void VideoWin::SetAudioVolume(long volume)
\r
700 if (dsbasicaudio) dsbasicaudio->put_Volume(volume);
\r
704 int VideoWin::test()
\r
709 int VideoWin::test2()
\r