]> git.vomp.tv Git - vompclient.git/blob - videowin.cc
0.2.7 readiness patches for Windows
[vompclient.git] / videowin.cc
1 /*
2     Copyright 2004-2005 Chris Tallon
3
4     This file is part of VOMP.
5
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.
10
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.
15
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
19 */
20
21 #include "videowin.h"
22 #include "log.h"
23 #include "dssourcefilter.h"
24 #include "dsallocator.h"
25 #include "vdr.h"
26 #include "osdwin.h"
27 #include "audiowin.h"
28 #include "vtabsviewman.h"
29 #include "wwinvideofilter.h"
30 #include "wtabbar.h"
31 #include "i18n.h"
32
33 void AdjustWindow();
34
35
36
37 VideoWin::VideoWin()
38 {
39   dsinited=false;
40   dsgraphbuilder=NULL;
41   dsmediacontrol=NULL;
42   dsvmrrenderer=NULL;
43   dsrefclock=NULL;
44   dsmediafilter=NULL;
45   dsbasicaudio=NULL;
46   sourcefilter=NULL;
47   allocatorvmr=NULL;
48   cr_time=0;
49   lastaudiomode=MPTYPE_MPEG_AUDIO;
50   //lastaudiomode=MPTYPE_AC3;
51   dsvmrsurfnotify=NULL;
52   filtermutex=CreateMutex(NULL,FALSE,NULL);
53   offsetnotset=true;
54   offsetvideonotset=true;
55   offsetaudionotset=true;
56   startoffset=0;
57   lastrefaudiotime=0;
58   lastrefvideotime=0;
59   lastreftimeRT=0;
60   lastreftimePTS=0;
61   firstsynched=false;
62   cur_audio_media_sample=NULL;
63   cur_video_media_sample=NULL;
64   videoon=true;
65   audioon=true;
66   audiovolume=0;
67   pseudotvsize=0;
68   videoposx=0;
69   videoposy=0;
70   aud_type=Audio::MPEG2_PES;
71   iframemode=false;//We are not in Iframe mode at begining
72
73   videofilterselected=-1;
74
75
76
77
78 }
79
80 VideoWin::~VideoWin()
81 {
82   CleanupDS();
83   CloseHandle(filtermutex);
84   int i;
85   for (i=0;i<videofilterlist.size();i++)
86   {
87    if (videofilterlist[i].displayname) delete [] videofilterlist[i].displayname;
88    if (videofilterlist[i].friendlyname) delete [] videofilterlist[i].friendlyname;
89   }
90   videofilterlist.clear();
91
92
93
94
95   instance = NULL;
96 }
97
98 int VideoWin::init(UCHAR tformat)
99 {
100   if (initted) return 0;
101
102   initted = 1;
103   tvsize=Video::ASPECT16X9; //Internally Vomp should think we are a 16:9 TV
104   videoposx=0;
105   videoposy=0;
106   initFilterDatabase();
107
108   if (!setFormat(tformat)){ shutdown(); return 0; }
109   return 1;
110 }
111
112
113
114 int VideoWin::setTVsize(UCHAR ttvsize)
115 {
116   pseudotvsize=ttvsize;
117   return 1;
118 }
119
120 int VideoWin::setDefaultAspect()
121 {
122   return setAspectRatio(Video::ASPECT4X3);
123 }
124
125 int VideoWin::shutdown()
126 {
127   if (!initted) return 0;
128   initted = 0;
129   return 1;
130 }
131
132 int VideoWin::setFormat(UCHAR tformat)
133 {
134   if (!initted) return 0;
135   if ((tformat != PAL) && (tformat != NTSC)) return 0;
136   format = tformat;
137   if (format == NTSC)
138   {
139     screenWidth = 720;
140     screenHeight = 480;
141   }
142   if (format == PAL)
143   {
144     screenWidth = 720;
145     screenHeight = 576;
146   }
147
148   return 1;
149 }
150
151 int VideoWin::setConnection(UCHAR tconnection)
152 {
153   if (!initted) return 0;
154   if ((tconnection != COMPOSITERGB) && (tconnection != SVIDEO)) return 0;
155   connection = tconnection;
156
157   return 1;
158 }
159
160 int VideoWin::setAspectRatio(UCHAR taspectRatio)
161 {
162   if (!initted) return 0;
163   if ((taspectRatio != ASPECT4X3) && (taspectRatio != ASPECT16X9)) return 0;
164   aspectRatio = taspectRatio;
165   AdjustWindow();
166   return 1;
167 }
168
169 int VideoWin::setMode(UCHAR tmode)
170 {
171   if (!initted) return 0;
172
173   //if ((tmode == LETTERBOX) && (tvsize == ASPECT16X9)) return 0; // invalid mode
174
175   if ((tmode != NORMAL) && (tmode != LETTERBOX) && (tmode != UNKNOWN2) && (tmode != QUARTER) && (tmode != EIGHTH)
176       && (tmode != ZOOM) && (tmode != UNKNOWN6)) return 0;
177   mode = tmode;
178   videoposx=0;
179   videoposy=0;
180   AdjustWindow();
181
182   return 1;
183 }
184
185 int VideoWin::signalOff()
186 {
187   return 1;
188 }
189
190 int VideoWin::signalOn()
191 {
192   return 1;
193 }
194
195 int VideoWin::setSource()
196 {
197   if (!initted) return 0;
198
199   return 1;
200 }
201
202 int VideoWin::setPosition(int x, int y)
203 {
204   if (!initted) return 0;
205   if (mode==QUARTER || mode==EIGHTH) {
206   videoposx=x;
207   videoposy=y;
208   }
209   return 1;
210 }
211
212 int VideoWin::sync()
213 {
214   if (!initted) return 0;
215
216   return 1;
217 }
218 void VideoWin::initFilterDatabase()
219 {
220     /* This method should determine all availiable DirectShow Filters */
221     IFilterMapper2* filtmap=NULL;
222     HRESULT result;
223     result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC,
224                 IID_IFilterMapper2,(void**)&filtmap);
225     if (result != S_OK)
226     {
227         Log::getInstance()->log("VideoWin", Log::ERR , "Unable to create FilterMapper!");
228         return;
229     }
230     /* Wishlist, what Mediatypes do we want */
231     GUID mtypesin[]={MEDIATYPE_Video,MEDIASUBTYPE_MPEG2_VIDEO};
232     IEnumMoniker *myenum;
233     result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1,
234                     TRUE,1,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL);
235     if (result != S_OK)
236     {
237         filtmap->Release();
238         Log::getInstance()->log("VideoWin", Log::ERR , "Unable to enum Filters!");
239         return;
240     }
241     ULONG gethowmany;
242     IMoniker * moni;
243     while(myenum->Next(1,&moni,&gethowmany)==S_OK)
244     {
245         VideoFilterDesc desc;
246         ZeroMemory(&desc,sizeof(desc));
247    
248         LPOLESTR string;
249         moni->GetDisplayName(0,0,&string);
250         desc.displayname=new char[wcslen(string)+1];
251         wcstombs(desc.displayname,string,wcslen(string)+1);
252         CoTaskMemFree(string);
253         IPropertyBag *bag;
254         if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK)
255         {
256             VARIANT vari;
257             VariantInit(&vari);
258             result = bag->Read(L"FriendlyName",&vari,NULL);
259             if (result == S_OK)
260             {
261                 desc.friendlyname=new char[wcslen(vari.bstrVal)+1];
262                 wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1);
263             }
264             VariantClear(&vari);
265             bag->Release();
266
267         }
268         
269        
270         videofilterlist.push_back(desc);
271        
272
273         
274         moni->Release();
275        // bctx->Release();
276     }
277     int i;
278     videofilterselected=-1;
279     
280     
281   
282     myenum->Release();
283
284
285
286     filtmap->Release();
287 }
288
289 bool VideoWin::loadOptionsfromServer(VDR* vdr)
290 {
291     char *name=vdr->configLoad("DirectShow","VideoFilter");
292     
293     if (name != NULL) 
294     {
295         for (int i = 0;i <videofilterlist.size();i++)
296         {
297             if (strcmp(name,videofilterlist[i].displayname)==0)
298             {
299                 videofilterselected = i;
300                 break;
301             }
302         }
303    }
304    return true;
305
306 }
307
308 bool VideoWin::saveOptionstoServer()
309 {
310     VDR::getInstance()->configSave("DirectShow",
311         "VideoFilter",videofilterlist[videofilterselected].displayname);
312     return true;
313 }
314
315 IBaseFilter *VideoWin::getVideoFilter()
316 {
317     IBaseFilter *curfilter= NULL;
318     if (videofilterselected == -1)
319     {
320         int i;
321         for (i = 0;i <videofilterlist.size();i++)
322         {
323             
324             if (videofilterlist[i].vmr9tested == true)
325             {
326                 if (videofilterlist[i].vmr9 == true)
327                 {
328                     videofilterselected = i;
329                     break;
330                 } 
331                 else
332                 {
333                     continue;
334                 }
335             }
336             else
337             {
338                 IMoniker * moni=NULL;
339                 IBindCtx *bindctx=NULL;
340                 if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;
341                 LPCOLESTR name=(LPCOLESTR)new WCHAR[strlen(videofilterlist[i].displayname)+1];
342                 mbstowcs((wchar_t*)name,videofilterlist[i].displayname,strlen(videofilterlist[i].displayname)+1);
343                 ULONG eater=0;
344                 
345
346                 if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)
347                 {
348                     if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)
349                     {
350                         IAMDecoderCaps* desccaps=NULL;
351                         if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)
352                         {
353                             DWORD caps;
354                             desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);
355                             if (caps == DECODER_CAP_SUPPORTED)
356                             {
357                                 videofilterlist[i].vmr9tested =  true;
358                                 videofilterlist[i].vmr9 = true;
359                                 videofilterselected = i;
360                             } 
361                             else
362                             {
363                                 videofilterlist[i].vmr9tested =  true;
364                                 videofilterlist[i].vmr9 = false;
365                                 
366                                 curfilter->Release();
367                                 curfilter=NULL;
368                             }
369                         }
370                         desccaps->Release();
371                     }
372                     moni->Release();
373                 } 
374                 delete [] name;
375                 bindctx->Release();
376             }
377             if (videofilterlist[i].vmr9) break;
378             
379         }
380         if (curfilter != NULL)
381         {
382             VDR *vdr=VDR::getInstance();
383             if (vdr != NULL)
384             {
385                 vdr->configSave("DirectShow","VideoFilter",
386                     videofilterlist[videofilterselected].displayname);
387             }
388             return curfilter;
389         }
390     } 
391     else
392     {
393         IBindCtx *bindctx=NULL;
394         if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;
395         IMoniker * moni=NULL;
396         LPCOLESTR name=new WCHAR[strlen(videofilterlist[videofilterselected].displayname)+1];
397         mbstowcs((wchar_t*)name,videofilterlist[videofilterselected].displayname,
398             strlen(videofilterlist[videofilterselected].displayname)+1);
399         ULONG eater;
400         if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)
401         {
402             if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)
403             {
404                     IAMDecoderCaps* desccaps=NULL;
405                     if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)
406                     {
407                         DWORD caps;
408                         desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);
409                         if (caps == DECODER_CAP_SUPPORTED)
410                         {
411                             videofilterlist[videofilterselected].vmr9tested =  true;
412                             videofilterlist[videofilterselected].vmr9 = true;
413                         } 
414                         else
415                         {
416                             videofilterlist[videofilterselected].vmr9tested =  true;
417                             videofilterlist[videofilterselected].vmr9 = false;
418                             Log::getInstance()->log("VideoWin", Log::WARN ,"Filter does not support VMR9, but is selected, manual selection!");
419                         }
420                     }
421                     moni->Release();
422                     delete [] name;
423                     bindctx->Release();
424                     return curfilter;
425              } 
426             moni->Release();
427         }
428         bindctx->Release();
429         delete [] name;
430         return NULL;         
431     }
432     return NULL;
433     
434 }
435
436
437 #ifdef DS_DEBUG // This stuff would not included in vomp due to lincemse restrcitions
438 #include "dshelper.h"
439 #endif
440
441 #define DO_VIDEO
442
443 int VideoWin::play()
444 {
445   if (!initted) return 0;
446   return 1;
447 }
448
449 bool VideoWin::addOptionPagesToWTB(WTabBar *wtb)
450 {
451     Boxx *box=new WWinVideoFilter();
452     wtb->addTab(tr("Video Filter"), box);
453     return true;
454 }
455
456 const VideoFilterDescList *VideoWin::getVideoFilterList(int &selected)
457 {
458     selected=videofilterselected;
459     return &videofilterlist;
460 }
461
462 bool VideoWin::selectVideoFilter(int filter)
463 {
464     IBindCtx *bindctx=NULL;
465     if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;
466     IMoniker * moni=NULL;
467     LPCOLESTR name=new WCHAR[strlen(videofilterlist[filter].displayname)+1];
468     mbstowcs((wchar_t*)name,videofilterlist[filter].displayname,
469     strlen(videofilterlist[filter].displayname)+1);
470     ULONG eater;
471     bool success=false;
472     if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)
473     {
474         IBaseFilter* curfilter=NULL;
475         if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)
476         {
477             IAMDecoderCaps* desccaps=NULL;
478             if (curfilter->QueryInterface(IID_IAMDecoderCaps,(void**) &desccaps)==S_OK)
479             {
480                 DWORD caps;
481                 HRESULT hres=desccaps->GetDecoderCaps(AM_GETDECODERCAP_QUERY_VMR9_SUPPORT,&caps);
482                 if (caps == DECODER_CAP_SUPPORTED)
483                 {
484                     videofilterlist[filter].vmr9tested =  true;
485                     videofilterlist[filter].vmr9 = true;
486                     success=true;
487                 } 
488                 else
489                 {
490                     videofilterlist[filter].vmr9tested =  true;
491                     videofilterlist[filter].vmr9 = false;
492                     success=false;
493                  }
494                 desccaps->Release();
495             } else {
496                 videofilterlist[filter].vmr9tested =  true;
497                 videofilterlist[filter].vmr9 = false;
498                 success=false;
499             }
500
501              curfilter->Release();
502              
503         } 
504         moni->Release();
505     }
506     bindctx->Release();
507     delete [] name;
508     if (success) 
509     {
510         videofilterselected=filter;
511         return true;
512     } 
513     else
514     {
515         return false;
516     }
517 }
518
519
520 int VideoWin::dsInitVideoFilter()
521 {
522     #ifdef DO_VIDEO
523     HRESULT hres;
524     if (videoon) {
525     //We alloc the vmr9 as next step
526         if (hres=CoCreateInstance(CLSID_VideoMixingRenderer9,0,
527             CLSCTX_INPROC_SERVER,IID_IBaseFilter,(void**) &dsvmrrenderer)!=S_OK) 
528         {
529             Log::getInstance()->log("VideoWin", Log::WARN ,"Failed creating VMR9 renderer!");
530                 ReleaseMutex(filtermutex);
531             CleanupDS();
532         }
533         /*VMR 9 stuff**/
534         if (hres=dsgraphbuilder->AddFilter(dsvmrrenderer,L"VMR9")!=S_OK)
535         {
536             ReleaseMutex(filtermutex);
537             CleanupDS();
538             Log::getInstance()->log("VideoWin", Log::WARN ,"Failed adding VMR9 renderer!");
539             return 0;
540         }
541         IVMRFilterConfig9* vmrfilconfig;
542         if (dsvmrrenderer->QueryInterface(IID_IVMRFilterConfig9,(void**)&vmrfilconfig)!=S_OK)
543         {
544             ReleaseMutex(filtermutex);
545             CleanupDS();
546             Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Filterconfig interface!");
547             return 0;
548         }
549         vmrfilconfig->SetRenderingMode(VMR9Mode_Renderless);
550         vmrfilconfig->Release();
551
552         if (dsvmrrenderer->QueryInterface(IID_IVMRSurfaceAllocatorNotify9,
553             (void**)& dsvmrsurfnotify) != S_OK)
554         {
555             ReleaseMutex(filtermutex);
556                 CleanupDS();
557             Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Surface Allocator interface!");
558             return 0;
559         }
560         allocatorvmr=new DsAllocator();
561         dsvmrsurfnotify->AdviseSurfaceAllocator(NULL,allocatorvmr);
562         allocatorvmr->AdviseNotify(dsvmrsurfnotify);
563        /*VMR 9 stuff end */
564         IFilterGraph2*fg2=NULL;
565         if (dsgraphbuilder->QueryInterface(IID_IFilterGraph2,(void**)&fg2)!= S_OK)
566         {
567             Log::getInstance()->log("VideoWin", Log::WARN , "Failed querying for FilterGraph2 Interface!");
568             ReleaseMutex(filtermutex);
569                 CleanupDS();
570             return 0;
571         }
572 /*#ifndef NEW_DS_MECHANISMENS
573         
574         if (hres=fg2->RenderEx((IPin*)sourcefilter->GetVideoPin()/*video*,
575             AM_RENDEREX_RENDERTOEXISTINGRENDERERS,NULL) != S_OK) 
576         {
577             Log::getInstance()->log("VideoWin", Log::WARN , "Failed rendering Video!");
578                 fg2->Release();
579                 ReleaseMutex(filtermutex);
580                 CleanupDS();
581             return 0;
582         }
583         
584 #else*/
585         IBaseFilter*videofilter=getVideoFilter();
586         if (hres=dsgraphbuilder->AddFilter(videofilter,NULL) != S_OK) 
587         {
588             Log::getInstance()->log("VideoWin", Log::WARN , "Failed adding Video Filter!");
589             ReleaseMutex(filtermutex);
590             CleanupDS();
591             return 0;
592         }
593         IEnumPins *pinenum=NULL;
594         bool error=false;
595         if (videofilter->EnumPins(&pinenum) == S_OK)
596         {
597             IPin *current=NULL;
598             ULONG fetch=0;
599             bool firststep=false;
600
601             while (pinenum->Next(1,&current,&fetch)==S_OK)
602             {
603                 PIN_DIRECTION dir;
604                 if (current->QueryDirection(&dir)==S_OK)
605                 {
606                     if (dir == PINDIR_INPUT)
607                     {
608                         if (sourcefilter->GetVideoPin()->Connect(current,NULL)==S_OK)
609                         {
610                             current->Release();
611                             firststep=true;
612                             break;
613                         }
614                     }
615                 }
616                 current->Release();
617             }
618             if (firststep==false)
619             {
620                 Log::getInstance()->log("VideoWin", Log::WARN , "Video Filter has no suitable input!");
621                 videofilter->Release();
622                 ReleaseMutex(filtermutex);
623                 CleanupDS();
624                 return 0;
625             }
626             bool secondstep=false;
627             pinenum->Reset();
628             while (pinenum->Next(1,&current,&fetch)==S_OK)
629             {
630                 PIN_DIRECTION dir;
631                 if (current->QueryDirection(&dir)==S_OK)
632                 {
633                     if (dir == PINDIR_OUTPUT)
634                     {
635                         
636                         if (fg2->RenderEx((IPin*)current/*video*/,
637                                 AM_RENDEREX_RENDERTOEXISTINGRENDERERS,NULL) ==S_OK)
638                         {
639                             current->Release();
640                             secondstep=true;
641                             break;
642                         }
643                     }
644                 }
645                 current->Release();
646             }
647             if (secondstep==false)
648             {
649                 Log::getInstance()->log("VideoWin", Log::WARN , "Video Filter has no suitable output!");
650                 videofilter->Release();
651                 ReleaseMutex(filtermutex);
652                 CleanupDS();
653                 return 0;
654             }
655             
656             videofilter->Release();
657             pinenum->Release();
658
659         }
660
661
662
663         fg2->Release();
664         return 1;
665     }
666 #endif 
667
668 }
669
670 int VideoWin::setAudioStreamType(UCHAR type)
671 {
672   aud_type=type;
673   if (!initted) return 0;
674   return 1;
675 }
676
677 int VideoWin::dsplay()
678 {
679     if (!initted) return 0;
680     CleanupDS();
681     
682     //Build filter graph
683     HRESULT hres;
684     //So this is the real code, this prevents the feeder from calling noexisting objects!
685     WaitForSingleObject(filtermutex,INFINITE);
686     if (hres=CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,
687         IID_IGraphBuilder,(void**)&dsgraphbuilder) != S_OK) 
688     {
689         ReleaseMutex(filtermutex);
690         return 0;
691     }
692    #ifdef DS_DEBUG
693    AddToRot(dsgraphbuilder,&graphidentifier);
694    #endif
695    
696    firstsynched=false;
697    if (aud_type==Audio::MP3) {
698        lastaudiomode=MPTYPE_MPEG_AUDIO_LAYER3;
699    } else {
700        lastaudiomode=MPTYPE_MPEG_AUDIO;
701    }
702    //lastaudiomode=MPTYPE_AC3;
703    sourcefilter=new DsSourceFilter(); //Creating our Source filter for pushing Data
704    // to DirectShow
705    if (hres=dsgraphbuilder->AddFilter(sourcefilter,L"Vomp Win Source Filter") != S_OK) 
706    {
707        Log::getInstance()->log("VideoWin", Log::WARN , "Failed adding Vomp Source Filter!");
708        ReleaseMutex(filtermutex);
709        CleanupDS();
710        return 0;
711    }
712    sourcefilter->GetAudioPin()->SetPinMode(lastaudiomode);
713    /*if (hres=dsgraphbuilder->Render((IPin*)sourcefilter->GetAudioPin()/*audio*)!=S_OK) 
714    {
715        Log::getInstance()->log("VideoWin", Log::WARN , "Failed rendering audio!");
716            ReleaseMutex(filtermutex);
717        CleanupDS();
718        return 0;
719    }*/
720    if (((AudioWin*)Audio::getInstance())->dsInitAudioFilter(dsgraphbuilder)==0)
721    {
722        Log::getInstance()->log("VideoWin", Log::WARN , "Failed rendering audio!");
723            ReleaseMutex(filtermutex);
724        CleanupDS();
725        return 0;
726    }
727
728
729     if (dsInitVideoFilter()==0)
730     { 
731         return 0;
732     }
733
734     if (hres=CoCreateInstance(CLSID_SystemClock,NULL,CLSCTX_INPROC_SERVER,
735         IID_IReferenceClock,(void**)&dsrefclock)!=S_OK) 
736     {
737         return 0;
738     }
739     dsgraphbuilder->QueryInterface(IID_IMediaFilter,(void **) &dsmediafilter);
740     HRESULT hresdeb = dsmediafilter->SetSyncSource(dsrefclock);
741
742     dsgraphbuilder->QueryInterface(IID_IMediaControl,(void **) &dsmediacontrol);
743     dsgraphbuilder->QueryInterface(IID_IBasicAudio,(void **) &dsbasicaudio);    
744     if (dsbasicaudio) 
745        dsbasicaudio->put_Volume(audiovolume);
746     dsinited=true;
747    //MILLISLEEP(100);
748
749     hresdeb=dsmediacontrol->Run();
750     iframemode=false;//exit iframe mode
751     ReleaseMutex(filtermutex);
752     return 1;
753 }
754
755 int VideoWin::EnterIframePlayback()
756 {
757         if (!initted) return 0;
758         CleanupDS();
759         //So this is the real code, this prevents the feeder from calling noexisting objects!
760    WaitForSingleObject(filtermutex,INFINITE);
761         iframemode=true;//enter iframe mode
762         //Build filter graph
763         HRESULT hres;
764         if (hres=CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,
765                  IID_IGraphBuilder,(void**)&dsgraphbuilder)!=S_OK) {
766                          ReleaseMutex(filtermutex);
767                          return 0;
768         }
769 #ifdef DS_DEBUG
770         AddToRot(dsgraphbuilder,&graphidentifier);
771 #endif
772    
773    //firstsynched=false;
774    sourcefilter=new DsSourceFilter(); //Creating our Source filter for pushing Data
775    // to DirectShow
776    if (hres=dsgraphbuilder->AddFilter(sourcefilter,L"Vomp Win Source Filter")!=S_OK) {
777    Log::getInstance()->log("VideoWin", Log::WARN , "Failed adding Vomp Source Filter!");
778      ReleaseMutex(filtermutex);  
779      CleanupDS();
780      return 0;
781    }
782 #ifdef DO_VIDEO
783     if (videoon) {
784         dsInitVideoFilter();
785    }
786 #endif
787 /*   if (hres=CoCreateInstance(CLSID_SystemClock,NULL,CLSCTX_INPROC_SERVER,
788     IID_IReferenceClock,(void**)&dsrefclock)!=S_OK) {
789       return 0;
790    }*/
791
792    dsgraphbuilder->QueryInterface(IID_IMediaFilter,(void **) &dsmediafilter);
793    dsmediafilter->SetSyncSource(/*dsrefclock*/NULL); //Run as fast as you can!
794
795    dsgraphbuilder->QueryInterface(IID_IMediaControl,(void **) &dsmediacontrol);
796    dsgraphbuilder->QueryInterface(IID_IBasicAudio,(void **) &dsbasicaudio);     
797   dsinited=true;
798   
799
800    dsmediacontrol->Run();
801    ReleaseMutex(filtermutex);
802   return 1;
803
804 }
805
806 int VideoWin::dsstop()
807 {
808   if (!initted) return 0;
809
810   CleanupDS();
811
812
813   return 1;
814 }
815
816 int VideoWin::stop()
817 {
818   if (!initted) return 0;
819
820
821   return 1;
822 }
823
824 int VideoWin::reset()
825 {
826   if (!initted) return 0;
827   
828
829   return 1;
830 }
831
832 int VideoWin::dsreset()
833 {
834   if (!initted) return 0;
835   videoposx=0;
836   videoposy=0;
837   iframemode=false;//exit iframe mode
838   CleanupDS();
839
840   return 1;
841 }
842
843 int VideoWin::dspause()
844 {
845   if (!initted) return 0;
846   WaitForSingleObject(filtermutex,INFINITE);
847   if (dsmediacontrol) dsmediacontrol->Pause();
848   ReleaseMutex(filtermutex);
849   return 1;
850 }
851
852 int VideoWin::pause()
853 {
854   if (!initted) return 0;
855   
856   return 1;
857 }
858
859 int VideoWin::unPause() // FIXME get rid - same as play!!
860 {//No on windows this is not the same, I don't get rid of!
861   if (!initted) return 0;
862   return 1;
863 }
864
865 int VideoWin::dsunPause() // FIXME get rid - same as play!!
866 {//No on windows this is not the same, I don't get rid of!
867   if (!initted) return 0;
868   WaitForSingleObject(filtermutex,INFINITE);
869   if (dsmediacontrol) dsmediacontrol->Run();
870   ReleaseMutex(filtermutex);
871
872   return 1;
873 }
874
875 int VideoWin::fastForward()
876 {
877   if (!initted) return 0;
878
879   return 1;
880 }
881
882 int VideoWin::unFastForward()
883 {
884   if (!initted) return 0;
885   
886   return 1;
887 }
888
889 int VideoWin::attachFrameBuffer()
890 {
891   if (!initted) return 0;
892   return 1;
893 }
894
895 int VideoWin::blank(void)
896 {
897   ((OsdWin*)Osd::getInstance())->Blank();
898   return 1;
899 }
900
901 ULLONG VideoWin::getCurrentTimestamp()
902 {
903         REFERENCE_TIME startoffset;
904         REFERENCE_TIME ncr_time;
905   if (iframemode) return 0; //Not in iframe mode!
906   if (!dsrefclock || !sourcefilter) return 0;
907         FILTER_STATE state;
908         sourcefilter->GetState(10,&state);
909
910         if (state==State_Running) dsrefclock->GetTime(&cr_time);
911         ncr_time=cr_time;
912   startoffset=sourcefilter->getStartOffset();
913         ncr_time-=startoffset;
914         ncr_time-=lastreftimeRT;
915  /* ULLONG result=frameNumberToTimecode(
916     VDR::getInstance()->frameNumberFromPosition(lastreftimeBYTE));*/
917         ULLONG result=lastreftimePTS;
918         result+=(ULLONG)(ncr_time/10000LL*90LL);
919   return result;
920
921 }
922
923 ULONG VideoWin::timecodeToFrameNumber(ULLONG timecode)
924 {
925   if (format == PAL) return (ULONG)(((double)timecode / (double)90000) * (double)25);
926   else               return (ULONG)(((double)timecode / (double)90000) * (double)30);
927 }
928
929 ULLONG VideoWin::frameNumberToTimecode(ULONG framenumber)
930 {
931   if (format == PAL) return (ULLONG)(((double)framenumber * (double)90000) / (double)25);
932   else               return (ULLONG)(((double)framenumber * (double)90000) / (double)30);
933 }
934
935 void VideoWin::CleanupDS()
936 {
937   WaitForSingleObject(filtermutex,INFINITE);
938   dsinited=false;
939   if (dsmediacontrol)dsmediacontrol->Stop();
940   if (cur_audio_media_sample) {
941     cur_audio_media_sample->Release();
942     cur_audio_media_sample=NULL;
943   }
944   if (cur_video_media_sample) {
945     cur_video_media_sample->Release();
946     cur_video_media_sample=NULL;
947   }
948   if (dsbasicaudio) {
949           dsbasicaudio->Release();
950           dsbasicaudio=NULL;
951   }
952   if (dsvmrsurfnotify) {
953     dsvmrsurfnotify->Release();
954     dsvmrsurfnotify=NULL;
955   }
956   if (dsvmrrenderer) {
957     dsvmrrenderer->Release();
958     dsvmrrenderer=NULL;
959   }
960
961   if (allocatorvmr) {
962     allocatorvmr->Release();
963     allocatorvmr=NULL;
964   }
965
966   if (dsrefclock) {
967     dsrefclock->Release();
968     dsrefclock=NULL;
969   }
970   if (dsmediafilter) {
971     dsmediafilter->Release();
972     dsmediafilter=NULL;
973   }
974
975
976
977   if (dsmediacontrol) {
978     dsmediacontrol->Stop();
979     dsmediacontrol->Release();
980     dsmediacontrol=NULL;
981   }
982   if (dsgraphbuilder){
983 #ifdef DS_DEBUG
984     RemoveFromRot(graphidentifier);
985 #endif
986         dsgraphbuilder->Release();
987     dsgraphbuilder=NULL;
988         
989     sourcefilter=NULL; //The Graph Builder destroys our SourceFilter
990   }
991   ReleaseMutex(filtermutex);
992
993 }
994
995 void VideoWin::PrepareMediaSample(const MediaPacketList& mplist,
996      UINT samplepos)
997 {
998   mediapacket = mplist.front();
999 }
1000
1001 UINT VideoWin::DeliverMediaSample(const UCHAR* buffer, UINT *samplepos)
1002 {
1003   DeliverMediaPacket(mediapacket, buffer, samplepos);
1004   if (*samplepos == mediapacket.length) {
1005     *samplepos = 0;
1006     return 1;
1007   }
1008   else return 0;
1009 }
1010
1011 UINT VideoWin::DeliverMediaPacket(MediaPacket packet,
1012      const UCHAR* buffer,
1013      UINT *samplepos)
1014 {
1015     
1016   /*First Check, if we have an audio sample*/
1017         if (!isdsinited()) return 0;
1018 #ifdef DO_VIDEO
1019         if (!videoon) {
1020           *samplepos+=packet.length;
1021        MILLISLEEP(0); //yet not implemented//bad idea
1022        return packet.length;
1023         }
1024   /*First Check, if we have an audio sample*/
1025   if (iframemode) {
1026                 samplepos=0;
1027                 MILLISLEEP(10);
1028                 return 0; //Not in iframe mode!
1029   }
1030   IMediaSample* ms=NULL;
1031   REFERENCE_TIME reftime1=0;
1032   REFERENCE_TIME reftime2=0;
1033
1034   UINT headerstrip=0;
1035   if (packet.disconti) {
1036     firstsynched=false;
1037     DeliverVideoMediaSample();
1038
1039   }
1040   /*Inspect PES-Header */
1041
1042   if (*samplepos==0) {//stripheader
1043     headerstrip=buffer[packet.pos_buffer+8]+9/*is this right*/;
1044     *samplepos+=headerstrip;
1045     if ( packet.synched ) {
1046       DeliverVideoMediaSample();//write out old data
1047    /*   if (packet.presentation_time<0) { //Preroll?
1048         *samplepos=packet.length;//if we have not processed at least one
1049         return packet.length;//synched packet ignore it!
1050       }*/
1051
1052       reftime1=packet.presentation_time;
1053       reftime2=reftime1+1;
1054       firstsynched=true;
1055     } else {
1056       if (!firstsynched) {//
1057         *samplepos=packet.length;//if we have not processed at least one
1058         return packet.length;//synched packet ignore it!
1059       }
1060     }
1061   }
1062   BYTE *ms_buf;
1063   UINT ms_length;
1064   UINT ms_pos;
1065   UINT haveToCopy;
1066   
1067   if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
1068     samplepos=0;
1069     MILLISLEEP(10);
1070     return 0;
1071   }
1072   ms_pos=ms->GetActualDataLength();
1073   ms_length=ms->GetSize();
1074   haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
1075   if ((ms_length-ms_pos)<1) {
1076     DeliverVideoMediaSample(); //we are full!
1077     if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
1078       samplepos=0;
1079       MILLISLEEP(10);
1080       return 0;
1081     }
1082     ms_pos=ms->GetActualDataLength();
1083     ms_length=ms->GetSize();
1084     haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
1085   }
1086   ms->GetPointer(&ms_buf);
1087
1088
1089   if (ms_pos==0) {//will only be changed on first packet
1090     if (packet.disconti) {
1091       ms->SetDiscontinuity(TRUE);
1092     } else {
1093       ms->SetDiscontinuity(FALSE);
1094     }
1095     if (packet.synched) {
1096       ms->SetSyncPoint(TRUE);
1097       ms->SetTime(&reftime1,&reftime2);
1098       //ms->SetTime(NULL,NULL);
1099       ms->SetMediaTime(NULL, NULL);
1100     if (reftime1<0) ms->SetPreroll(TRUE);
1101     else ms->SetPreroll(FALSE);
1102     /*Timecode handling*/
1103     lastreftimeRT=reftime1;
1104         lastreftimePTS=packet.pts;
1105
1106     }else {
1107       ms->SetSyncPoint(FALSE);
1108       ms->SetTime(NULL,NULL);
1109       ms->SetMediaTime(NULL, NULL);
1110       ms->SetPreroll(FALSE);
1111
1112     //  ms->SetSyncPoint(TRUE);
1113     }
1114   }
1115
1116
1117   memcpy(ms_buf+ms_pos,buffer+packet.pos_buffer+*samplepos,haveToCopy);
1118     ms->SetActualDataLength(haveToCopy+ms_pos);
1119
1120   *samplepos+=haveToCopy;
1121
1122   return haveToCopy+headerstrip;
1123
1124 #else
1125
1126        *samplepos+=packet.length;
1127       MILLISLEEP(0); //yet not implemented//bad idea
1128        return packet.length;
1129 #endif
1130 }
1131
1132 int VideoWin::getCurrentAudioMediaSample(IMediaSample** ms)
1133 {
1134   //WaitForSingleObject(filtermutex,INFINITE);
1135   if (!sourcefilter){
1136   //  ReleaseMutex(filtermutex);
1137     return 0;
1138   }
1139   if (cur_audio_media_sample) {
1140     *ms=cur_audio_media_sample;//already open
1141     return 1;
1142   }
1143   if (!sourcefilter->getCurrentAudioMediaSample(ms)) {
1144   //  ReleaseMutex(filtermutex);
1145   }
1146   if (*ms) (*ms)->SetActualDataLength(0);
1147   cur_audio_media_sample=*ms;
1148   //Don't release the mutex before deliver
1149   return 1;
1150 }
1151
1152 int VideoWin::getCurrentVideoMediaSample(IMediaSample** ms)
1153 {
1154   //WaitForSingleObject(filtermutex,INFINITE);
1155   if (!sourcefilter){
1156   //  ReleaseMutex(filtermutex);
1157     return 0;
1158   }
1159   if (cur_video_media_sample) {
1160     *ms=cur_video_media_sample;//already open
1161     return 1;
1162   }
1163   if (!sourcefilter->getCurrentVideoMediaSample(ms)) {
1164   //  ReleaseMutex(filtermutex);
1165   }
1166   if (*ms) (*ms)->SetActualDataLength(0);
1167
1168   cur_video_media_sample=*ms;
1169   //Don't release the mutex before deliver
1170   return 1;
1171 }
1172
1173 int VideoWin::DeliverAudioMediaSample(){
1174   if (cur_audio_media_sample) {
1175     sourcefilter->DeliverAudioMediaSample(cur_audio_media_sample);
1176     cur_audio_media_sample=NULL;
1177   }
1178   //ReleaseMutex(filtermutex);
1179   return 1;
1180 }
1181
1182 int VideoWin::DeliverVideoMediaSample(){
1183   if (cur_video_media_sample) {
1184     sourcefilter->DeliverVideoMediaSample(cur_video_media_sample);
1185     cur_video_media_sample=NULL;
1186   }
1187   //ReleaseMutex(filtermutex);
1188   return 1;
1189 }
1190
1191 long long VideoWin::SetStartOffset(long long curreftime, bool *rsync)
1192 {
1193   *rsync=false;
1194   if (offsetnotset) {
1195     startoffset=curreftime;//offset is set for audio
1196     offsetnotset=false;
1197     offsetvideonotset=false;
1198
1199
1200   } else {
1201     if (offsetvideonotset) {
1202       offsetvideonotset=false;
1203       *rsync=true;
1204     } else {
1205       if ( (curreftime-lastrefvideotime)>10000000LL
1206         || (curreftime-lastrefvideotime)<-10000000LL) {//if pts jumps to big resync
1207         startoffset+=curreftime-lastrefvideotime;
1208         lastrefaudiotime+=curreftime-lastrefvideotime;
1209         //*rsync=true;
1210         offsetaudionotset=true;
1211
1212       }
1213     }
1214
1215   }
1216
1217   lastrefvideotime=curreftime;
1218   
1219   return startoffset;
1220
1221 }
1222
1223 long long VideoWin::SetStartAudioOffset(long long curreftime, bool *rsync)
1224 {
1225   *rsync=false;
1226   if (offsetnotset) {
1227     startoffset=curreftime;
1228     offsetnotset=false;
1229     offsetaudionotset=false;
1230   }else {
1231     if (offsetaudionotset) {
1232       offsetaudionotset=false;
1233       *rsync=true;
1234     } else {
1235       if ( (curreftime-lastrefaudiotime)>10000000LL
1236         || (curreftime-lastrefaudiotime)<-10000000LL) {//if pts jumps to big resync
1237         startoffset+=curreftime-lastrefaudiotime;
1238         lastrefvideotime+=curreftime-lastrefaudiotime;
1239         //*rsync=true;
1240         offsetvideonotset=true;
1241
1242       }
1243     }
1244
1245   }
1246   lastrefaudiotime=curreftime;
1247   return startoffset;
1248
1249 }
1250 void VideoWin::ResetTimeOffsets() {
1251   offsetnotset=true; //called from demuxer
1252   offsetvideonotset=true;
1253   offsetaudionotset=true;
1254   startoffset=0;
1255   lastrefaudiotime=0;
1256   lastrefvideotime=0;
1257   lastreftimeRT=0;
1258   lastreftimePTS=0;
1259
1260
1261 }
1262
1263 void VideoWin::SetAudioVolume(long volume)
1264 {
1265     audiovolume=volume;
1266         if (dsbasicaudio) dsbasicaudio->put_Volume(volume);
1267 }
1268
1269 void VideoWin::displayIFrame(const UCHAR* buffer, UINT length)
1270 {
1271         if (!iframemode) EnterIframePlayback();
1272
1273         if (!isdsinited()) return ;
1274 #ifdef DO_VIDEO
1275   IMediaSample* ms=NULL;
1276   REFERENCE_TIME reftime1=0;
1277   REFERENCE_TIME reftime2=0;
1278   if (!videoon) return;
1279
1280   if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
1281     MILLISLEEP(10);
1282     return ;
1283   }
1284   BYTE *ms_buf;
1285   DWORD ms_length;
1286   ms->GetPointer(&ms_buf);
1287   ms_length=ms->GetSize();
1288   
1289   /*First Check, if we have an video sample*/
1290   DWORD read_pos = 0, write_pos = 0;
1291   DWORD pattern, packet_length;
1292   DWORD headerstrip=0;
1293   bool first=true;
1294   if (length < 4) return ;
1295   //Now we strip the pes header
1296   pattern = (buffer[0] << 16) | (buffer[1] << 8) | (buffer[2]);
1297   while (read_pos + 7 <= length)
1298   {
1299     pattern = ((pattern << 8) & 0xFFFFFFFF) | buffer[read_pos+3];
1300     if (pattern < 0x000001E0 || pattern > 0x000001EF)
1301       read_pos++;
1302     else
1303     {
1304           headerstrip=buffer[read_pos+8]+9/*is this right*/;
1305       packet_length = ((buffer[read_pos+4] << 8) | (buffer[read_pos+5])) + 6;
1306       if (read_pos + packet_length > length)
1307         read_pos = length;
1308       else
1309       {
1310                   if ((write_pos+packet_length-headerstrip)>ms_length) {
1311                           if (first) {
1312                   ms->SetSyncPoint(TRUE);
1313                   ms->SetDiscontinuity(TRUE);
1314                   first=false;
1315               } else ms->SetSyncPoint(FALSE);
1316                           ms->SetTime(NULL,NULL);
1317                           ms->SetMediaTime(NULL, NULL);
1318                           ms->SetActualDataLength(write_pos);
1319                           DeliverVideoMediaSample();
1320
1321                           if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
1322                                 MILLISLEEP(10);
1323                                 return ;
1324                           }
1325                           write_pos=0;
1326                           ms_length=ms->GetSize();
1327                           ms->GetPointer(&ms_buf);
1328                   }
1329                   if (packet_length>headerstrip) {
1330                         memcpy(ms_buf+write_pos, buffer+read_pos+headerstrip, packet_length-headerstrip);
1331                         write_pos += packet_length-headerstrip;
1332                   }
1333                   read_pos += packet_length;
1334                   
1335                   pattern = (buffer[read_pos] << 16) | (buffer[read_pos+1] << 8)
1336                                         | (buffer[read_pos+2]);
1337       }
1338     }
1339   }
1340
1341   if (first) {ms->SetSyncPoint(TRUE);first=false;} 
1342   else ms->SetSyncPoint(FALSE);
1343   ms->SetTime(NULL,NULL);
1344   ms->SetMediaTime(NULL, NULL);
1345   ms->SetActualDataLength(write_pos);
1346   DeliverVideoMediaSample();
1347
1348 #else
1349
1350     //   *samplepos+=packet.length;
1351       MILLISLEEP(0); //yet not implemented//bad idea
1352        return ;
1353 #endif
1354 }
1355
1356 bool VideoWin::supportsAc3(){
1357     if (sourcefilter != NULL) {
1358         return sourcefilter->supportsAc3();
1359     } else {
1360         return false;
1361     }
1362 }
1363
1364 bool VideoWin::changeAType(int type,IMediaSample* ms){
1365     if (sourcefilter!= NULL) {
1366         lastaudiomode=type;
1367         return sourcefilter->changeAType(type,ms);
1368     }
1369     else 
1370     {
1371         return false;
1372     }
1373 }
1374
1375 #ifdef DEV
1376 int VideoWin::test()
1377 {
1378   return 0;
1379 }
1380
1381 int VideoWin::test2()
1382 {
1383   return 0;
1384 }
1385 #endif
1386
1387
1388
1389