2 Copyright 2004-2005 Chris Tallon
4 This file is part of VOMP.
6 VOMP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 VOMP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with VOMP; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "dssourcefilter.h"
24 #include "dsallocator.h"
41 filtermutex=CreateMutex(NULL,FALSE,NULL);
43 offsetvideonotset=true;
44 offsetaudionotset=true;
51 cur_audio_media_sample=NULL;
52 cur_video_media_sample=NULL;
66 CloseHandle(filtermutex);
73 int VideoWin::init(UCHAR tformat)
75 if (initted) return 0;
78 tvsize=Video::ASPECT16X9; //Internally Vomp should think we are a 16:9 TV
82 if (!setFormat(tformat)){ shutdown(); return 0; }
86 int VideoWin::setTVsize(UCHAR ttvsize)
92 int VideoWin::setDefaultAspect()
94 return setAspectRatio(Video::ASPECT4X3);
97 int VideoWin::shutdown()
99 if (!initted) return 0;
104 int VideoWin::setFormat(UCHAR tformat)
106 if (!initted) return 0;
107 if ((tformat != PAL) && (tformat != NTSC)) return 0;
123 int VideoWin::setConnection(UCHAR tconnection)
125 if (!initted) return 0;
126 if ((tconnection != COMPOSITERGB) && (tconnection != SVIDEO)) return 0;
127 connection = tconnection;
132 int VideoWin::setAspectRatio(UCHAR taspectRatio)
134 if (!initted) return 0;
135 if ((taspectRatio != ASPECT4X3) && (taspectRatio != ASPECT16X9)) return 0;
136 aspectRatio = taspectRatio;
141 int VideoWin::setMode(UCHAR tmode)
143 if (!initted) return 0;
145 //if ((tmode == LETTERBOX) && (tvsize == ASPECT16X9)) return 0; // invalid mode
147 if ((tmode != NORMAL) && (tmode != LETTERBOX) && (tmode != UNKNOWN2) && (tmode != QUARTER) && (tmode != EIGHTH)
148 && (tmode != ZOOM) && (tmode != UNKNOWN6)) return 0;
157 int VideoWin::signalOff()
162 int VideoWin::signalOn()
167 int VideoWin::setSource()
169 if (!initted) return 0;
174 int VideoWin::setPosition(int x, int y)
176 if (!initted) return 0;
177 if (mode==QUARTER || mode==EIGHTH) {
186 if (!initted) return 0;
191 #ifdef DS_DEBUG // This stuff would not included in vomp due to lincemse restrcitions
192 #include "dshelper.h"
199 if (!initted) return 0;
204 if (hres=CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,
205 IID_IGraphBuilder,(void**)&dsgraphbuilder)!=S_OK) {
209 AddToRot(dsgraphbuilder,&graphidentifier);
211 //This is just a try to see if building the graph works
212 // dsgraphbuilder->RenderFile(L"D:\\Projekte\\VTP Client\\test.mpa" ,NULL);
213 //So this is the real code, this prevents the feeder from calling noexisting objects!
214 WaitForSingleObject(filtermutex,INFINITE);
216 sourcefilter=new DsSourceFilter(); //Creating our Source filter for pushing Data
218 if (hres=dsgraphbuilder->AddFilter(sourcefilter,L"Vomp Win Source Filter")!=S_OK) {
219 Log::getInstance()->log("VideoWin", Log::WARN , "Failed adding Vomp Source Filter!");
221 ReleaseMutex(filtermutex);
225 if (hres=dsgraphbuilder->Render(sourcefilter->GetPin(0)/*audio*/)!=S_OK) {
226 Log::getInstance()->log("VideoWin", Log::WARN , "Failed rendering audio!");
228 ReleaseMutex(filtermutex);
234 //We alloc the vmr9 as next step
235 if (hres=CoCreateInstance(CLSID_VideoMixingRenderer9,0,
236 CLSCTX_INPROC_SERVER,IID_IBaseFilter,(void**) &dsvmrrenderer)!=S_OK) {
237 Log::getInstance()->log("VideoWin", Log::WARN ,"Failed creating VMR9 renderer!");
239 ReleaseMutex(filtermutex);
242 if (hres=dsgraphbuilder->AddFilter(dsvmrrenderer,L"VMR9")!=S_OK) {
244 Log::getInstance()->log("VideoWin", Log::WARN ,"Failed adding VMR9 renderer!");
245 ReleaseMutex(filtermutex);
248 IVMRFilterConfig9* vmrfilconfig;
249 if (dsvmrrenderer->QueryInterface(IID_IVMRFilterConfig9,(void**)&vmrfilconfig)!=S_OK) {
251 Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Filterconfig interface!");
252 ReleaseMutex(filtermutex);
255 vmrfilconfig->SetRenderingMode(VMR9Mode_Renderless);
256 vmrfilconfig->Release();
258 if (dsvmrrenderer->QueryInterface(IID_IVMRSurfaceAllocatorNotify9,(void**)& dsvmrsurfnotify)!=S_OK) {
260 Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Surface Allocator interface!");
261 ReleaseMutex(filtermutex);
264 allocatorvmr=new DsAllocator();
265 dsvmrsurfnotify->AdviseSurfaceAllocator(NULL,allocatorvmr);
266 allocatorvmr->AdviseNotify(dsvmrsurfnotify);
271 IFilterGraph2*fg2=NULL;
272 if (dsgraphbuilder->QueryInterface(IID_IFilterGraph2,(void**)&fg2)!=S_OK) {
273 Log::getInstance()->log("VideoWin", Log::WARN , "Failed querying for FilterGraph2 Interface!");
275 ReleaseMutex(filtermutex);
278 if (hres=fg2->RenderEx(sourcefilter->GetPin(1)/*video*/,
279 AM_RENDEREX_RENDERTOEXISTINGRENDERERS,NULL)!=S_OK) {
280 Log::getInstance()->log("VideoWin", Log::WARN , "Failed rendering Video!");
282 ReleaseMutex(filtermutex);
287 if (hres=CoCreateInstance(CLSID_SystemClock,NULL,CLSCTX_INPROC_SERVER,
288 IID_IReferenceClock,(void**)&dsrefclock)!=S_OK) {
292 dsgraphbuilder->QueryInterface(IID_IMediaFilter,(void **) &dsmediafilter);
293 dsmediafilter->SetSyncSource(dsrefclock);
295 dsgraphbuilder->QueryInterface(IID_IMediaControl,(void **) &dsmediacontrol);
297 dsmediacontrol->Run();
298 ReleaseMutex(filtermutex);
304 if (!initted) return 0;
312 int VideoWin::reset()
314 if (!initted) return 0;
321 int VideoWin::pause()
323 if (!initted) return 0;
324 if (dsmediacontrol) dsmediacontrol->Pause();
328 int VideoWin::unPause() // FIXME get rid - same as play!!
329 {//No on windows this is not the same, I don't get rid of!
330 if (!initted) return 0;
331 if (dsmediacontrol) dsmediacontrol->Run();
335 int VideoWin::fastForward()
337 if (!initted) return 0;
341 int VideoWin::unFastForward()
343 if (!initted) return 0;
347 int VideoWin::attachFrameBuffer()
349 if (!initted) return 0;
353 int VideoWin::blank(void)
358 int VideoWin::getFD()
360 if (!initted) return 0;
365 ULLONG VideoWin::getCurrentTimestamp()
367 REFERENCE_TIME cr_time,startoffset;
369 if (!dsrefclock || !sourcefilter) return 0;
371 dsrefclock->GetTime(&cr_time);
372 startoffset=sourcefilter->getStartOffset();
373 cr_time-=startoffset;
374 cr_time-=lastreftimeRT;
375 ULLONG result=frameNumberToTimecode(
376 VDR::getInstance()->frameNumberFromPosition(lastreftimeBYTE));
377 result+=(ULLONG)(cr_time/10000LL*90LL);
382 ULONG VideoWin::timecodeToFrameNumber(ULLONG timecode)
384 if (format == PAL) return (ULONG)(((double)timecode / (double)90000) * (double)25);
385 else return (ULONG)(((double)timecode / (double)90000) * (double)30);
388 ULLONG VideoWin::frameNumberToTimecode(ULONG framenumber)
390 if (format == PAL) return (ULLONG)(((double)framenumber * (double)90000) / (double)25);
391 else return (ULLONG)(((double)framenumber * (double)90000) / (double)30);
394 void VideoWin::CleanupDS()
396 WaitForSingleObject(filtermutex,INFINITE);
397 if (cur_audio_media_sample) {
398 cur_audio_media_sample->Release();
399 cur_audio_media_sample=NULL;
401 if (cur_video_media_sample) {
402 cur_video_media_sample->Release();
403 cur_video_media_sample=NULL;
405 if (dsvmrsurfnotify) {
406 dsvmrsurfnotify->Release();
407 dsvmrsurfnotify=NULL;
410 dsvmrrenderer->Release();
415 allocatorvmr->Release();
420 dsrefclock->Release();
424 dsmediafilter->Release();
428 if (dsmediacontrol) {
429 dsmediacontrol->Stop();
430 dsmediacontrol->Release();
435 RemoveFromRot(graphidentifier);
437 dsgraphbuilder->Release();
439 sourcefilter=NULL; //The Graph Builder destroys our SourceFilter
441 ReleaseMutex(filtermutex);
446 UINT VideoWin::DeliverMediaSample(MediaPacket packet,
450 /*First Check, if we have an audio sample*/
452 /*First Check, if we have an audio sample*/
454 IMediaSample* ms=NULL;
455 REFERENCE_TIME reftime1=0;
456 REFERENCE_TIME reftime2=0;
459 if (packet.disconti) {
461 DeliverVideoMediaSample();
466 /*Inspect PES-Header */
468 if (*samplepos==0) {//stripheader
469 headerstrip=buffer[packet.pos_buffer+8]+9/*is this right*/;
470 *samplepos+=headerstrip;
471 if ( packet.synched ) {
472 DeliverVideoMediaSample();//write out old data
473 /* if (packet.presentation_time<0) { //Preroll?
474 *samplepos=packet.length;//if we have not processed at least one
475 return packet.length;//synched packet ignore it!
478 reftime1=packet.presentation_time;
482 if (!firstsynched) {//
483 *samplepos=packet.length;//if we have not processed at least one
484 return packet.length;//synched packet ignore it!
492 if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
497 ms_pos=ms->GetActualDataLength();
498 ms_length=ms->GetSize();
499 haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
500 if ((ms_length-ms_pos)<1) {
501 DeliverVideoMediaSample(); //we are full!
502 if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
507 ms_pos=ms->GetActualDataLength();
508 ms_length=ms->GetSize();
509 haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
511 ms->GetPointer(&ms_buf);
514 if (ms_pos==0) {//will only be changed on first packet
515 if (packet.disconti) {
516 ms->SetDiscontinuity(TRUE);
518 ms->SetDiscontinuity(FALSE);
520 if (packet.synched) {
521 ms->SetSyncPoint(TRUE);
522 ms->SetTime(&reftime1,&reftime2);
523 //ms->SetTime(NULL,NULL);
524 ms->SetMediaTime(NULL, NULL);
525 if (reftime1<0) ms->SetPreroll(TRUE);
526 else ms->SetPreroll(FALSE);
527 /*Timecode handling*/
528 lastreftimeRT=reftime1;
529 lastreftimeBYTE=packet.recording_byte_pos;
532 ms->SetSyncPoint(FALSE);
533 ms->SetTime(NULL,NULL);
534 ms->SetMediaTime(NULL, NULL);
535 ms->SetPreroll(FALSE);
537 // ms->SetSyncPoint(TRUE);
542 memcpy(ms_buf+ms_pos,buffer+packet.pos_buffer+*samplepos,haveToCopy);
543 ms->SetActualDataLength(haveToCopy+ms_pos);
545 *samplepos+=haveToCopy;
547 return haveToCopy+headerstrip;
551 *samplepos+=packet.length;
552 MILLISLEEP(0); //yet not implemented//bad idea
553 return packet.length;
557 int VideoWin::getCurrentAudioMediaSample(IMediaSample** ms)
559 //WaitForSingleObject(filtermutex,INFINITE);
561 // ReleaseMutex(filtermutex);
564 if (cur_audio_media_sample) {
565 *ms=cur_audio_media_sample;//already open
568 if (!sourcefilter->getCurrentAudioMediaSample(ms)) {
569 // ReleaseMutex(filtermutex);
571 if (*ms) (*ms)->SetActualDataLength(0);
572 cur_audio_media_sample=*ms;
573 //Don't release the mutex before deliver
577 int VideoWin::getCurrentVideoMediaSample(IMediaSample** ms)
579 //WaitForSingleObject(filtermutex,INFINITE);
581 // ReleaseMutex(filtermutex);
584 if (cur_video_media_sample) {
585 *ms=cur_video_media_sample;//already open
588 if (!sourcefilter->getCurrentVideoMediaSample(ms)) {
589 // ReleaseMutex(filtermutex);
591 if (*ms) (*ms)->SetActualDataLength(0);
593 cur_video_media_sample=*ms;
594 //Don't release the mutex before deliver
598 int VideoWin::DeliverAudioMediaSample(){
599 if (cur_audio_media_sample) {
600 sourcefilter->DeliverAudioMediaSample(cur_audio_media_sample);
601 cur_audio_media_sample=NULL;
603 //ReleaseMutex(filtermutex);
607 int VideoWin::DeliverVideoMediaSample(){
608 if (cur_video_media_sample) {
609 sourcefilter->DeliverVideoMediaSample(cur_video_media_sample);
610 cur_video_media_sample=NULL;
612 //ReleaseMutex(filtermutex);
616 long long VideoWin::SetStartOffset(long long curreftime, bool *rsync)
620 startoffset=curreftime;//offset is set for audio
622 offsetvideonotset=false;
626 if (offsetvideonotset) {
627 offsetvideonotset=false;
630 if ( (curreftime-lastrefvideotime)>10000000LL
631 || (curreftime-lastrefvideotime)<-10000000LL) {//if pts jumps to big resync
632 startoffset+=curreftime-lastrefvideotime;
633 lastrefaudiotime+=curreftime-lastrefvideotime;
635 offsetaudionotset=true;
641 lastrefvideotime=curreftime;
646 long long VideoWin::SetStartAudioOffset(long long curreftime, bool *rsync)
650 startoffset=curreftime;
652 offsetaudionotset=false;
654 if (offsetaudionotset) {
655 offsetaudionotset=false;
658 if ( (curreftime-lastrefaudiotime)>10000000LL
659 || (curreftime-lastrefaudiotime)<-10000000LL) {//if pts jumps to big resync
660 startoffset+=curreftime-lastrefaudiotime;
661 lastrefvideotime+=curreftime-lastrefaudiotime;
663 offsetvideonotset=true;
669 lastrefaudiotime=curreftime;
673 void VideoWin::ResetTimeOffsets() {
674 offsetnotset=true; //called from demuxer
675 offsetvideonotset=true;
676 offsetaudionotset=true;
693 int VideoWin::test2()