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;
49 cur_audio_media_sample=NULL;
50 cur_video_media_sample=NULL;
62 CloseHandle(filtermutex);
69 int VideoWin::init(UCHAR tformat)
71 if (initted) return 0;
74 tvsize=Video::ASPECT16X9; //Internally Vomp should think we are a 16:9 TV
76 if (!setFormat(tformat)){ shutdown(); return 0; }
80 int VideoWin::setTVsize(UCHAR ttvsize)
86 int VideoWin::setDefaultAspect()
88 return setAspectRatio(Video::ASPECT4X3);
91 int VideoWin::shutdown()
93 if (!initted) return 0;
98 int VideoWin::setFormat(UCHAR tformat)
100 if (!initted) return 0;
101 if ((tformat != PAL) && (tformat != NTSC)) return 0;
117 int VideoWin::setConnection(UCHAR tconnection)
119 if (!initted) return 0;
120 if ((tconnection != COMPOSITERGB) && (tconnection != SVIDEO)) return 0;
121 connection = tconnection;
126 int VideoWin::setAspectRatio(UCHAR taspectRatio)
128 if (!initted) return 0;
129 if ((taspectRatio != ASPECT4X3) && (taspectRatio != ASPECT16X9)) return 0;
130 aspectRatio = taspectRatio;
135 int VideoWin::setMode(UCHAR tmode)
137 if (!initted) return 0;
139 //if ((tmode == LETTERBOX) && (tvsize == ASPECT16X9)) return 0; // invalid mode
141 if ((tmode != NORMAL) && (tmode != LETTERBOX) && (tmode != UNKNOWN2) && (tmode != QUARTER) && (tmode != EIGHTH)
142 && (tmode != ZOOM) && (tmode != UNKNOWN6)) return 0;
149 int VideoWin::signalOff()
154 int VideoWin::signalOn()
159 int VideoWin::setSource()
161 if (!initted) return 0;
166 int VideoWin::setPosition(int x, int y)
168 if (!initted) return 0;
175 if (!initted) return 0;
180 #ifdef DS_DEBUG // This stuff would not included in vomp due to lincemse restrcitions
181 #include "dshelper.h"
188 if (!initted) return 0;
193 if (hres=CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,
194 IID_IGraphBuilder,(void**)&dsgraphbuilder)!=S_OK) {
198 AddToRot(dsgraphbuilder,&graphidentifier);
200 //This is just a try to see if building the graph works
201 // dsgraphbuilder->RenderFile(L"D:\\Projekte\\VTP Client\\test.mpa" ,NULL);
202 //So this is the real code, this prevents the feeder from calling noexisting objects!
203 WaitForSingleObject(filtermutex,INFINITE);
205 sourcefilter=new DsSourceFilter(); //Creating our Source filter for pushing Data
207 if (hres=dsgraphbuilder->AddFilter(sourcefilter,L"Vomp Win Source Filter")!=S_OK) {
208 Log::getInstance()->log("VideoWin", Log::WARN , "Failed adding Vomp Source Filter!");
210 ReleaseMutex(filtermutex);
214 if (hres=dsgraphbuilder->Render(sourcefilter->GetPin(0)/*audio*/)!=S_OK) {
215 Log::getInstance()->log("VideoWin", Log::WARN , "Failed rendering audio!");
217 ReleaseMutex(filtermutex);
223 //We alloc the vmr9 as next step
224 if (hres=CoCreateInstance(CLSID_VideoMixingRenderer9,0,
225 CLSCTX_INPROC_SERVER,IID_IBaseFilter,(void**) &dsvmrrenderer)!=S_OK) {
226 Log::getInstance()->log("VideoWin", Log::WARN ,"Failed creating VMR9 renderer!");
228 ReleaseMutex(filtermutex);
231 if (hres=dsgraphbuilder->AddFilter(dsvmrrenderer,L"VMR9")!=S_OK) {
233 Log::getInstance()->log("VideoWin", Log::WARN ,"Failed adding VMR9 renderer!");
234 ReleaseMutex(filtermutex);
237 IVMRFilterConfig9* vmrfilconfig;
238 if (dsvmrrenderer->QueryInterface(IID_IVMRFilterConfig9,(void**)&vmrfilconfig)!=S_OK) {
240 Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Filterconfig interface!");
241 ReleaseMutex(filtermutex);
244 vmrfilconfig->SetRenderingMode(VMR9Mode_Renderless);
245 vmrfilconfig->Release();
247 if (dsvmrrenderer->QueryInterface(IID_IVMRSurfaceAllocatorNotify9,(void**)& dsvmrsurfnotify)!=S_OK) {
249 Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Surface Allocator interface!");
250 ReleaseMutex(filtermutex);
253 allocatorvmr=new DsAllocator();
254 dsvmrsurfnotify->AdviseSurfaceAllocator(NULL,allocatorvmr);
255 allocatorvmr->AdviseNotify(dsvmrsurfnotify);
260 IFilterGraph2*fg2=NULL;
261 if (dsgraphbuilder->QueryInterface(IID_IFilterGraph2,(void**)&fg2)!=S_OK) {
262 Log::getInstance()->log("VideoWin", Log::WARN , "Failed querying for FilterGraph2 Interface!");
264 ReleaseMutex(filtermutex);
267 if (hres=fg2->RenderEx(sourcefilter->GetPin(1)/*video*/,
268 AM_RENDEREX_RENDERTOEXISTINGRENDERERS,NULL)!=S_OK) {
269 Log::getInstance()->log("VideoWin", Log::WARN , "Failed rendering Video!");
271 ReleaseMutex(filtermutex);
276 if (hres=CoCreateInstance(CLSID_SystemClock,NULL,CLSCTX_INPROC_SERVER,
277 IID_IReferenceClock,(void**)&dsrefclock)!=S_OK) {
281 dsgraphbuilder->QueryInterface(IID_IMediaFilter,(void **) &dsmediafilter);
282 dsmediafilter->SetSyncSource(dsrefclock);
284 dsgraphbuilder->QueryInterface(IID_IMediaControl,(void **) &dsmediacontrol);
286 dsmediacontrol->Run();
287 ReleaseMutex(filtermutex);
293 if (!initted) return 0;
301 int VideoWin::reset()
303 if (!initted) return 0;
309 int VideoWin::pause()
311 if (!initted) return 0;
312 if (dsmediacontrol) dsmediacontrol->Pause();
316 int VideoWin::unPause() // FIXME get rid - same as play!!
317 {//No on windows this is not the same, I don't get rid of!
318 if (!initted) return 0;
319 if (dsmediacontrol) dsmediacontrol->Run();
323 int VideoWin::fastForward()
325 if (!initted) return 0;
329 int VideoWin::unFastForward()
331 if (!initted) return 0;
335 int VideoWin::attachFrameBuffer()
337 if (!initted) return 0;
341 int VideoWin::blank(void)
346 int VideoWin::getFD()
348 if (!initted) return 0;
353 ULLONG VideoWin::getCurrentTimestamp()
355 REFERENCE_TIME cr_time,startoffset;
357 if (!dsrefclock || !sourcefilter) return 0;
359 dsrefclock->GetTime(&cr_time);
360 startoffset=sourcefilter->getStartOffset();
361 cr_time-=startoffset;
362 cr_time-=lastreftimeRT;
363 ULLONG result=frameNumberToTimecode(
364 VDR::getInstance()->frameNumberFromPosition(lastreftimeBYTE));
365 result+=(ULLONG)(cr_time/10000LL*90LL);
370 ULONG VideoWin::timecodeToFrameNumber(ULLONG timecode)
372 if (format == PAL) return (ULONG)(((double)timecode / (double)90000) * (double)25);
373 else return (ULONG)(((double)timecode / (double)90000) * (double)30);
376 ULLONG VideoWin::frameNumberToTimecode(ULONG framenumber)
378 if (format == PAL) return (ULLONG)(((double)framenumber * (double)90000) / (double)25);
379 else return (ULLONG)(((double)framenumber * (double)90000) / (double)30);
382 void VideoWin::CleanupDS()
384 WaitForSingleObject(filtermutex,INFINITE);
385 if (cur_audio_media_sample) {
386 cur_audio_media_sample->Release();
387 cur_audio_media_sample=NULL;
389 if (cur_video_media_sample) {
390 cur_video_media_sample->Release();
391 cur_video_media_sample=NULL;
393 if (dsvmrsurfnotify) {
394 dsvmrsurfnotify->Release();
395 dsvmrsurfnotify=NULL;
398 dsvmrrenderer->Release();
403 allocatorvmr->Release();
408 dsrefclock->Release();
412 dsmediafilter->Release();
416 if (dsmediacontrol) {
417 dsmediacontrol->Stop();
418 dsmediacontrol->Release();
423 RemoveFromRot(graphidentifier);
425 dsgraphbuilder->Release();
427 sourcefilter=NULL; //The Graph Builder destroys our SourceFilter
429 ReleaseMutex(filtermutex);
434 UINT VideoWin::DeliverMediaSample(MediaPacket packet,
438 /*First Check, if we have an audio sample*/
440 /*First Check, if we have an audio sample*/
442 IMediaSample* ms=NULL;
443 REFERENCE_TIME reftime1=0;
444 REFERENCE_TIME reftime2=0;
447 if (packet.disconti) {
449 DeliverVideoMediaSample();
454 /*Inspect PES-Header */
456 if (*samplepos==0) {//stripheader
457 headerstrip=buffer[packet.pos_buffer+8]+9/*is this right*/;
458 *samplepos+=headerstrip;
459 if ( packet.synched ) {
460 DeliverVideoMediaSample();//write out old data
461 /* if (packet.presentation_time<0) { //Preroll?
462 *samplepos=packet.length;//if we have not processed at least one
463 return packet.length;//synched packet ignore it!
466 reftime1=packet.presentation_time;
470 if (!firstsynched) {//
471 *samplepos=packet.length;//if we have not processed at least one
472 return packet.length;//synched packet ignore it!
480 if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
485 ms_pos=ms->GetActualDataLength();
486 ms_length=ms->GetSize();
487 haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
488 if ((ms_length-ms_pos)<1) {
489 DeliverVideoMediaSample(); //we are full!
490 if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
495 ms_pos=ms->GetActualDataLength();
496 ms_length=ms->GetSize();
497 haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
499 ms->GetPointer(&ms_buf);
502 if (ms_pos==0) {//will only be changed on first packet
503 if (packet.disconti) {
504 ms->SetDiscontinuity(TRUE);
506 ms->SetDiscontinuity(FALSE);
508 if (packet.synched) {
509 ms->SetSyncPoint(TRUE);
510 ms->SetTime(&reftime1,&reftime2);
511 //ms->SetTime(NULL,NULL);
512 ms->SetMediaTime(NULL, NULL);
513 if (reftime1<0) ms->SetPreroll(TRUE);
514 else ms->SetPreroll(FALSE);
515 /*Timecode handling*/
516 lastreftimeRT=reftime1;
517 lastreftimeBYTE=packet.recording_byte_pos;
520 ms->SetSyncPoint(FALSE);
521 ms->SetTime(NULL,NULL);
522 ms->SetMediaTime(NULL, NULL);
523 ms->SetPreroll(FALSE);
525 // ms->SetSyncPoint(TRUE);
530 memcpy(ms_buf+ms_pos,buffer+packet.pos_buffer+*samplepos,haveToCopy);
531 ms->SetActualDataLength(haveToCopy+ms_pos);
533 *samplepos+=haveToCopy;
535 return haveToCopy+headerstrip;
539 *samplepos+=packet.length;
540 MILLISLEEP(0); //yet not implemented//bad idea
541 return packet.length;
545 int VideoWin::getCurrentAudioMediaSample(IMediaSample** ms)
547 //WaitForSingleObject(filtermutex,INFINITE);
549 // ReleaseMutex(filtermutex);
552 if (cur_audio_media_sample) {
553 *ms=cur_audio_media_sample;//already open
556 if (!sourcefilter->getCurrentAudioMediaSample(ms)) {
557 // ReleaseMutex(filtermutex);
559 if (*ms) (*ms)->SetActualDataLength(0);
560 cur_audio_media_sample=*ms;
561 //Don't release the mutex before deliver
565 int VideoWin::getCurrentVideoMediaSample(IMediaSample** ms)
567 //WaitForSingleObject(filtermutex,INFINITE);
569 // ReleaseMutex(filtermutex);
572 if (cur_video_media_sample) {
573 *ms=cur_video_media_sample;//already open
576 if (!sourcefilter->getCurrentVideoMediaSample(ms)) {
577 // ReleaseMutex(filtermutex);
579 if (*ms) (*ms)->SetActualDataLength(0);
581 cur_video_media_sample=*ms;
582 //Don't release the mutex before deliver
586 int VideoWin::DeliverAudioMediaSample(){
587 if (cur_audio_media_sample) {
588 sourcefilter->DeliverAudioMediaSample(cur_audio_media_sample);
589 cur_audio_media_sample=NULL;
591 //ReleaseMutex(filtermutex);
595 int VideoWin::DeliverVideoMediaSample(){
596 if (cur_video_media_sample) {
597 sourcefilter->DeliverVideoMediaSample(cur_video_media_sample);
598 cur_video_media_sample=NULL;
600 //ReleaseMutex(filtermutex);
604 long long VideoWin::SetStartOffset(long long curreftime, bool *rsync)
608 startoffset=curreftime;//offset is set for audio
610 offsetvideonotset=false;
614 if (offsetvideonotset) {
615 offsetvideonotset=false;
618 if ( (curreftime-lastrefvideotime)>10000000LL
619 || (curreftime-lastrefvideotime)<-10000000LL) {//if pts jumps to big resync
620 startoffset+=curreftime-lastrefvideotime;
621 lastrefaudiotime+=curreftime-lastrefvideotime;
623 offsetaudionotset=true;
629 lastrefvideotime=curreftime;
634 long long VideoWin::SetStartAudioOffset(long long curreftime, bool *rsync)
638 startoffset=curreftime;
640 offsetaudionotset=false;
642 if (offsetaudionotset) {
643 offsetaudionotset=false;
646 if ( (curreftime-lastrefaudiotime)>10000000LL
647 || (curreftime-lastrefaudiotime)<-10000000LL) {//if pts jumps to big resync
648 startoffset+=curreftime-lastrefaudiotime;
649 lastrefvideotime+=curreftime-lastrefaudiotime;
651 offsetvideonotset=true;
657 lastrefaudiotime=curreftime;
661 void VideoWin::ResetTimeOffsets() {
662 offsetnotset=true; //called from demuxer
663 offsetvideonotset=true;
664 offsetaudionotset=true;
677 int VideoWin::test2()