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"
45 filtermutex=CreateMutex(NULL,FALSE,NULL);
47 offsetvideonotset=true;
48 offsetaudionotset=true;
55 cur_audio_media_sample=NULL;
56 cur_video_media_sample=NULL;
62 iframemode=false;//We are not in Iframe mode at begining
71 CloseHandle(filtermutex);
78 int VideoWin::init(UCHAR tformat)
80 if (initted) return 0;
83 tvsize=Video::ASPECT16X9; //Internally Vomp should think we are a 16:9 TV
87 if (!setFormat(tformat)){ shutdown(); return 0; }
91 int VideoWin::setTVsize(UCHAR ttvsize)
97 int VideoWin::setDefaultAspect()
99 return setAspectRatio(Video::ASPECT4X3);
102 int VideoWin::shutdown()
104 if (!initted) return 0;
109 int VideoWin::setFormat(UCHAR tformat)
111 if (!initted) return 0;
112 if ((tformat != PAL) && (tformat != NTSC)) return 0;
128 int VideoWin::setConnection(UCHAR tconnection)
130 if (!initted) return 0;
131 if ((tconnection != COMPOSITERGB) && (tconnection != SVIDEO)) return 0;
132 connection = tconnection;
137 int VideoWin::setAspectRatio(UCHAR taspectRatio)
139 if (!initted) return 0;
140 if ((taspectRatio != ASPECT4X3) && (taspectRatio != ASPECT16X9)) return 0;
141 aspectRatio = taspectRatio;
146 int VideoWin::setMode(UCHAR tmode)
148 if (!initted) return 0;
150 //if ((tmode == LETTERBOX) && (tvsize == ASPECT16X9)) return 0; // invalid mode
152 if ((tmode != NORMAL) && (tmode != LETTERBOX) && (tmode != UNKNOWN2) && (tmode != QUARTER) && (tmode != EIGHTH)
153 && (tmode != ZOOM) && (tmode != UNKNOWN6)) return 0;
162 int VideoWin::signalOff()
167 int VideoWin::signalOn()
172 int VideoWin::setSource()
174 if (!initted) return 0;
179 int VideoWin::setPosition(int x, int y)
181 if (!initted) return 0;
182 if (mode==QUARTER || mode==EIGHTH) {
191 if (!initted) return 0;
196 #ifdef DS_DEBUG // This stuff would not included in vomp due to lincemse restrcitions
197 #include "dshelper.h"
204 if (!initted) return 0;
208 int VideoWin::dsplay()
210 if (!initted) return 0;
215 //So this is the real code, this prevents the feeder from calling noexisting objects!
216 WaitForSingleObject(filtermutex,INFINITE);
217 if (hres=CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,
218 IID_IGraphBuilder,(void**)&dsgraphbuilder)!=S_OK) {
219 ReleaseMutex(filtermutex);
223 AddToRot(dsgraphbuilder,&graphidentifier);
225 //This is just a try to see if building the graph works
226 // dsgraphbuilder->RenderFile(L"D:\\Projekte\\VTP Client\\test.mpa" ,NULL);
229 sourcefilter=new DsSourceFilter(); //Creating our Source filter for pushing Data
231 if (hres=dsgraphbuilder->AddFilter(sourcefilter,L"Vomp Win Source Filter")!=S_OK) {
232 Log::getInstance()->log("VideoWin", Log::WARN , "Failed adding Vomp Source Filter!");
233 ReleaseMutex(filtermutex);
238 if (hres=dsgraphbuilder->Render((IPin*)sourcefilter->GetAudioPin()/*audio*/)!=S_OK) {
239 Log::getInstance()->log("VideoWin", Log::WARN , "Failed rendering audio!");
240 ReleaseMutex(filtermutex);
247 //We alloc the vmr9 as next step
248 if (hres=CoCreateInstance(CLSID_VideoMixingRenderer9,0,
249 CLSCTX_INPROC_SERVER,IID_IBaseFilter,(void**) &dsvmrrenderer)!=S_OK) {
250 Log::getInstance()->log("VideoWin", Log::WARN ,"Failed creating VMR9 renderer!");
251 ReleaseMutex(filtermutex);
256 if (hres=dsgraphbuilder->AddFilter(dsvmrrenderer,L"VMR9")!=S_OK) {
257 ReleaseMutex(filtermutex);
259 Log::getInstance()->log("VideoWin", Log::WARN ,"Failed adding VMR9 renderer!");
263 IVMRFilterConfig9* vmrfilconfig;
264 if (dsvmrrenderer->QueryInterface(IID_IVMRFilterConfig9,(void**)&vmrfilconfig)!=S_OK) {
265 ReleaseMutex(filtermutex);
267 Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Filterconfig interface!");
270 vmrfilconfig->SetRenderingMode(VMR9Mode_Renderless);
271 vmrfilconfig->Release();
273 if (dsvmrrenderer->QueryInterface(IID_IVMRSurfaceAllocatorNotify9,(void**)& dsvmrsurfnotify)!=S_OK) {
274 ReleaseMutex(filtermutex);
276 Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Surface Allocator interface!");
280 allocatorvmr=new DsAllocator();
281 dsvmrsurfnotify->AdviseSurfaceAllocator(NULL,allocatorvmr);
282 allocatorvmr->AdviseNotify(dsvmrsurfnotify);
288 IFilterGraph2*fg2=NULL;
289 if (dsgraphbuilder->QueryInterface(IID_IFilterGraph2,(void**)&fg2)!=S_OK) {
290 Log::getInstance()->log("VideoWin", Log::WARN , "Failed querying for FilterGraph2 Interface!");
291 ReleaseMutex(filtermutex);
295 if (hres=fg2->RenderEx((IPin*)sourcefilter->GetVideoPin()/*video*/,
296 AM_RENDEREX_RENDERTOEXISTINGRENDERERS,NULL)!=S_OK) {
297 Log::getInstance()->log("VideoWin", Log::WARN , "Failed rendering Video!");
299 ReleaseMutex(filtermutex);
306 if (hres=CoCreateInstance(CLSID_SystemClock,NULL,CLSCTX_INPROC_SERVER,
307 IID_IReferenceClock,(void**)&dsrefclock)!=S_OK) {
311 dsgraphbuilder->QueryInterface(IID_IMediaFilter,(void **) &dsmediafilter);
312 HRESULT hresdeb=dsmediafilter->SetSyncSource(dsrefclock);
314 dsgraphbuilder->QueryInterface(IID_IMediaControl,(void **) &dsmediacontrol);
315 dsgraphbuilder->QueryInterface(IID_IBasicAudio,(void **) &dsbasicaudio);
319 hresdeb=dsmediacontrol->Run();
320 iframemode=false;//exit iframe mode
321 ReleaseMutex(filtermutex);
325 int VideoWin::EnterIframePlayback()
327 if (!initted) return 0;
329 //So this is the real code, this prevents the feeder from calling noexisting objects!
330 WaitForSingleObject(filtermutex,INFINITE);
331 iframemode=true;//enter iframe mode
334 if (hres=CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,
335 IID_IGraphBuilder,(void**)&dsgraphbuilder)!=S_OK) {
336 ReleaseMutex(filtermutex);
340 AddToRot(dsgraphbuilder,&graphidentifier);
343 //firstsynched=false;
344 sourcefilter=new DsSourceFilter(); //Creating our Source filter for pushing Data
346 if (hres=dsgraphbuilder->AddFilter(sourcefilter,L"Vomp Win Source Filter")!=S_OK) {
347 Log::getInstance()->log("VideoWin", Log::WARN , "Failed adding Vomp Source Filter!");
348 ReleaseMutex(filtermutex);
354 //We alloc the vmr9 as next step
355 if (hres=CoCreateInstance(CLSID_VideoMixingRenderer9,0,
356 CLSCTX_INPROC_SERVER,IID_IBaseFilter,(void**) &dsvmrrenderer)!=S_OK) {
357 Log::getInstance()->log("VideoWin", Log::WARN ,"Failed creating VMR9 renderer!");
358 ReleaseMutex(filtermutex);
363 if (hres=dsgraphbuilder->AddFilter(dsvmrrenderer,L"VMR9")!=S_OK) {
364 Log::getInstance()->log("VideoWin", Log::WARN ,"Failed adding VMR9 renderer!");
365 ReleaseMutex(filtermutex);
369 IVMRFilterConfig9* vmrfilconfig;
370 if (dsvmrrenderer->QueryInterface(IID_IVMRFilterConfig9,(void**)&vmrfilconfig)!=S_OK) {
371 ReleaseMutex(filtermutex);
373 Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Filterconfig interface!");
377 vmrfilconfig->SetRenderingMode(VMR9Mode_Renderless);
378 vmrfilconfig->Release();
380 if (dsvmrrenderer->QueryInterface(IID_IVMRSurfaceAllocatorNotify9,(void**)& dsvmrsurfnotify)!=S_OK) {
381 Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Surface Allocator interface!");
382 ReleaseMutex(filtermutex);
386 allocatorvmr=new DsAllocator();
387 dsvmrsurfnotify->AdviseSurfaceAllocator(NULL,allocatorvmr);
388 allocatorvmr->AdviseNotify(dsvmrsurfnotify);
391 IFilterGraph2*fg2=NULL;
392 if (dsgraphbuilder->QueryInterface(IID_IFilterGraph2,(void**)&fg2)!=S_OK) {
393 Log::getInstance()->log("VideoWin", Log::WARN , "Failed querying for FilterGraph2 Interface!");
394 ReleaseMutex(filtermutex);
398 if (hres=fg2->RenderEx((IPin*)sourcefilter->GetVideoPin()/*video*/,
399 AM_RENDEREX_RENDERTOEXISTINGRENDERERS,NULL)!=S_OK) {
400 Log::getInstance()->log("VideoWin", Log::WARN , "Failed rendering Video!");
402 ReleaseMutex(filtermutex);
409 /* if (hres=CoCreateInstance(CLSID_SystemClock,NULL,CLSCTX_INPROC_SERVER,
410 IID_IReferenceClock,(void**)&dsrefclock)!=S_OK) {
414 dsgraphbuilder->QueryInterface(IID_IMediaFilter,(void **) &dsmediafilter);
415 dsmediafilter->SetSyncSource(/*dsrefclock*/NULL); //Run as fast as you can!
417 dsgraphbuilder->QueryInterface(IID_IMediaControl,(void **) &dsmediacontrol);
418 dsgraphbuilder->QueryInterface(IID_IBasicAudio,(void **) &dsbasicaudio);
422 dsmediacontrol->Run();
423 ReleaseMutex(filtermutex);
428 int VideoWin::dsstop()
430 if (!initted) return 0;
440 if (!initted) return 0;
446 int VideoWin::reset()
448 if (!initted) return 0;
454 int VideoWin::dsreset()
456 if (!initted) return 0;
459 iframemode=false;//exit iframe mode
465 int VideoWin::dspause()
467 if (!initted) return 0;
468 WaitForSingleObject(filtermutex,INFINITE);
469 if (dsmediacontrol) dsmediacontrol->Pause();
470 ReleaseMutex(filtermutex);
474 int VideoWin::pause()
476 if (!initted) return 0;
481 int VideoWin::unPause() // FIXME get rid - same as play!!
482 {//No on windows this is not the same, I don't get rid of!
483 if (!initted) return 0;
487 int VideoWin::dsunPause() // FIXME get rid - same as play!!
488 {//No on windows this is not the same, I don't get rid of!
489 if (!initted) return 0;
490 WaitForSingleObject(filtermutex,INFINITE);
491 if (dsmediacontrol) dsmediacontrol->Run();
492 ReleaseMutex(filtermutex);
497 int VideoWin::fastForward()
499 if (!initted) return 0;
504 int VideoWin::unFastForward()
506 if (!initted) return 0;
511 int VideoWin::attachFrameBuffer()
513 if (!initted) return 0;
517 int VideoWin::blank(void)
519 ((OsdWin*)Osd::getInstance())->Blank();
523 ULLONG VideoWin::getCurrentTimestamp()
525 REFERENCE_TIME startoffset;
526 REFERENCE_TIME ncr_time;
527 if (iframemode) return 0; //Not in iframe mode!
528 if (!dsrefclock || !sourcefilter) return 0;
530 sourcefilter->GetState(10,&state);
532 if (state==State_Running) dsrefclock->GetTime(&cr_time);
534 startoffset=sourcefilter->getStartOffset();
535 ncr_time-=startoffset;
536 ncr_time-=lastreftimeRT;
537 /* ULLONG result=frameNumberToTimecode(
538 VDR::getInstance()->frameNumberFromPosition(lastreftimeBYTE));*/
539 ULLONG result=lastreftimePTS;
540 result+=(ULLONG)(ncr_time/10000LL*90LL);
545 ULONG VideoWin::timecodeToFrameNumber(ULLONG timecode)
547 if (format == PAL) return (ULONG)(((double)timecode / (double)90000) * (double)25);
548 else return (ULONG)(((double)timecode / (double)90000) * (double)30);
551 ULLONG VideoWin::frameNumberToTimecode(ULONG framenumber)
553 if (format == PAL) return (ULLONG)(((double)framenumber * (double)90000) / (double)25);
554 else return (ULLONG)(((double)framenumber * (double)90000) / (double)30);
557 void VideoWin::CleanupDS()
559 WaitForSingleObject(filtermutex,INFINITE);
561 if (dsmediacontrol)dsmediacontrol->Stop();
562 if (cur_audio_media_sample) {
563 cur_audio_media_sample->Release();
564 cur_audio_media_sample=NULL;
566 if (cur_video_media_sample) {
567 cur_video_media_sample->Release();
568 cur_video_media_sample=NULL;
571 dsbasicaudio->Release();
574 if (dsvmrsurfnotify) {
575 dsvmrsurfnotify->Release();
576 dsvmrsurfnotify=NULL;
579 dsvmrrenderer->Release();
584 allocatorvmr->Release();
589 dsrefclock->Release();
593 dsmediafilter->Release();
599 if (dsmediacontrol) {
600 dsmediacontrol->Stop();
601 dsmediacontrol->Release();
606 RemoveFromRot(graphidentifier);
608 dsgraphbuilder->Release();
611 sourcefilter=NULL; //The Graph Builder destroys our SourceFilter
613 ReleaseMutex(filtermutex);
617 void VideoWin::PrepareMediaSample(const MediaPacketList& mplist,
620 mediapacket = mplist.front();
623 UINT VideoWin::DeliverMediaSample(const UCHAR* buffer, UINT *samplepos)
625 DeliverMediaPacket(mediapacket, buffer, samplepos);
626 if (*samplepos == mediapacket.length) {
633 UINT VideoWin::DeliverMediaPacket(MediaPacket packet,
637 /*First Check, if we have an audio sample*/
638 if (!isdsinited()) return 0;
641 *samplepos+=packet.length;
642 MILLISLEEP(0); //yet not implemented//bad idea
643 return packet.length;
645 /*First Check, if we have an audio sample*/
649 return 0; //Not in iframe mode!
651 IMediaSample* ms=NULL;
652 REFERENCE_TIME reftime1=0;
653 REFERENCE_TIME reftime2=0;
656 if (packet.disconti) {
658 DeliverVideoMediaSample();
663 /*Inspect PES-Header */
665 if (*samplepos==0) {//stripheader
666 headerstrip=buffer[packet.pos_buffer+8]+9/*is this right*/;
667 *samplepos+=headerstrip;
668 if ( packet.synched ) {
669 DeliverVideoMediaSample();//write out old data
670 /* if (packet.presentation_time<0) { //Preroll?
671 *samplepos=packet.length;//if we have not processed at least one
672 return packet.length;//synched packet ignore it!
675 reftime1=packet.presentation_time;
679 if (!firstsynched) {//
680 *samplepos=packet.length;//if we have not processed at least one
681 return packet.length;//synched packet ignore it!
690 if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
695 ms_pos=ms->GetActualDataLength();
696 ms_length=ms->GetSize();
697 haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
698 if ((ms_length-ms_pos)<1) {
699 DeliverVideoMediaSample(); //we are full!
700 if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
705 ms_pos=ms->GetActualDataLength();
706 ms_length=ms->GetSize();
707 haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
709 ms->GetPointer(&ms_buf);
712 if (ms_pos==0) {//will only be changed on first packet
713 if (packet.disconti) {
714 ms->SetDiscontinuity(TRUE);
716 ms->SetDiscontinuity(FALSE);
718 if (packet.synched) {
719 ms->SetSyncPoint(TRUE);
720 ms->SetTime(&reftime1,&reftime2);
721 //ms->SetTime(NULL,NULL);
722 ms->SetMediaTime(NULL, NULL);
723 if (reftime1<0) ms->SetPreroll(TRUE);
724 else ms->SetPreroll(FALSE);
725 /*Timecode handling*/
726 lastreftimeRT=reftime1;
727 lastreftimePTS=packet.pts;
730 ms->SetSyncPoint(FALSE);
731 ms->SetTime(NULL,NULL);
732 ms->SetMediaTime(NULL, NULL);
733 ms->SetPreroll(FALSE);
735 // ms->SetSyncPoint(TRUE);
740 memcpy(ms_buf+ms_pos,buffer+packet.pos_buffer+*samplepos,haveToCopy);
741 ms->SetActualDataLength(haveToCopy+ms_pos);
743 *samplepos+=haveToCopy;
745 return haveToCopy+headerstrip;
749 *samplepos+=packet.length;
750 MILLISLEEP(0); //yet not implemented//bad idea
751 return packet.length;
755 int VideoWin::getCurrentAudioMediaSample(IMediaSample** ms)
757 //WaitForSingleObject(filtermutex,INFINITE);
759 // ReleaseMutex(filtermutex);
762 if (cur_audio_media_sample) {
763 *ms=cur_audio_media_sample;//already open
766 if (!sourcefilter->getCurrentAudioMediaSample(ms)) {
767 // ReleaseMutex(filtermutex);
769 if (*ms) (*ms)->SetActualDataLength(0);
770 cur_audio_media_sample=*ms;
771 //Don't release the mutex before deliver
775 int VideoWin::getCurrentVideoMediaSample(IMediaSample** ms)
777 //WaitForSingleObject(filtermutex,INFINITE);
779 // ReleaseMutex(filtermutex);
782 if (cur_video_media_sample) {
783 *ms=cur_video_media_sample;//already open
786 if (!sourcefilter->getCurrentVideoMediaSample(ms)) {
787 // ReleaseMutex(filtermutex);
789 if (*ms) (*ms)->SetActualDataLength(0);
791 cur_video_media_sample=*ms;
792 //Don't release the mutex before deliver
796 int VideoWin::DeliverAudioMediaSample(){
797 if (cur_audio_media_sample) {
798 sourcefilter->DeliverAudioMediaSample(cur_audio_media_sample);
799 cur_audio_media_sample=NULL;
801 //ReleaseMutex(filtermutex);
805 int VideoWin::DeliverVideoMediaSample(){
806 if (cur_video_media_sample) {
807 sourcefilter->DeliverVideoMediaSample(cur_video_media_sample);
808 cur_video_media_sample=NULL;
810 //ReleaseMutex(filtermutex);
814 long long VideoWin::SetStartOffset(long long curreftime, bool *rsync)
818 startoffset=curreftime;//offset is set for audio
820 offsetvideonotset=false;
824 if (offsetvideonotset) {
825 offsetvideonotset=false;
828 if ( (curreftime-lastrefvideotime)>10000000LL
829 || (curreftime-lastrefvideotime)<-10000000LL) {//if pts jumps to big resync
830 startoffset+=curreftime-lastrefvideotime;
831 lastrefaudiotime+=curreftime-lastrefvideotime;
833 offsetaudionotset=true;
840 lastrefvideotime=curreftime;
846 long long VideoWin::SetStartAudioOffset(long long curreftime, bool *rsync)
850 startoffset=curreftime;
852 offsetaudionotset=false;
854 if (offsetaudionotset) {
855 offsetaudionotset=false;
858 if ( (curreftime-lastrefaudiotime)>10000000LL
859 || (curreftime-lastrefaudiotime)<-10000000LL) {//if pts jumps to big resync
860 startoffset+=curreftime-lastrefaudiotime;
861 lastrefvideotime+=curreftime-lastrefaudiotime;
863 offsetvideonotset=true;
869 lastrefaudiotime=curreftime;
873 void VideoWin::ResetTimeOffsets() {
874 offsetnotset=true; //called from demuxer
875 offsetvideonotset=true;
876 offsetaudionotset=true;
886 void VideoWin::SetAudioVolume(long volume)
888 if (dsbasicaudio) dsbasicaudio->put_Volume(volume);
891 void VideoWin::displayIFrame(const UCHAR* buffer, UINT length)
893 if (!iframemode) EnterIframePlayback();
895 if (!isdsinited()) return ;
897 IMediaSample* ms=NULL;
898 REFERENCE_TIME reftime1=0;
899 REFERENCE_TIME reftime2=0;
900 if (!videoon) return;
902 if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
908 ms->GetPointer(&ms_buf);
909 ms_length=ms->GetSize();
911 /*First Check, if we have an video sample*/
912 DWORD read_pos = 0, write_pos = 0;
913 DWORD pattern, packet_length;
916 if (length < 4) return ;
917 //Now we strip the pes header
918 pattern = (buffer[0] << 16) | (buffer[1] << 8) | (buffer[2]);
919 while (read_pos + 7 <= length)
921 pattern = ((pattern << 8) & 0xFFFFFFFF) | buffer[read_pos+3];
922 if (pattern < 0x000001E0 || pattern > 0x000001EF)
926 headerstrip=buffer[read_pos+8]+9/*is this right*/;
927 packet_length = ((buffer[read_pos+4] << 8) | (buffer[read_pos+5])) + 6;
928 if (read_pos + packet_length > length)
932 if ((write_pos+packet_length-headerstrip)>ms_length) {
933 if (first) {ms->SetSyncPoint(TRUE);first=false;}
934 else ms->SetSyncPoint(FALSE);
935 ms->SetTime(NULL,NULL);
936 ms->SetMediaTime(NULL, NULL);
937 ms->SetActualDataLength(write_pos);
938 DeliverVideoMediaSample();
940 if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
945 ms_length=ms->GetSize();
946 ms->GetPointer(&ms_buf);
948 if (packet_length-headerstrip>0) {
949 memcpy(ms_buf+write_pos, buffer+read_pos+headerstrip, packet_length-headerstrip);
950 write_pos += packet_length-headerstrip;
952 read_pos += packet_length;
954 pattern = (buffer[read_pos] << 16) | (buffer[read_pos+1] << 8)
955 | (buffer[read_pos+2]);
960 if (first) {ms->SetSyncPoint(TRUE);first=false;}
961 else ms->SetSyncPoint(FALSE);
962 ms->SetTime(NULL,NULL);
963 ms->SetMediaTime(NULL, NULL);
964 ms->SetActualDataLength(write_pos);
965 DeliverVideoMediaSample();
969 // *samplepos+=packet.length;
970 MILLISLEEP(0); //yet not implemented//bad idea
982 int VideoWin::test2()