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