]> git.vomp.tv Git - vompclient.git/blob - videowin.cc
Windows memory leak fix
[vompclient.git] / videowin.cc
1 /*\r
2     Copyright 2004-2005 Chris Tallon\r
3 \r
4     This file is part of VOMP.\r
5 \r
6     VOMP is free software; you can redistribute it and/or modify\r
7     it under the terms of the GNU General Public License as published by\r
8     the Free Software Foundation; either version 2 of the License, or\r
9     (at your option) any later version.\r
10 \r
11     VOMP is distributed in the hope that it will be useful,\r
12     but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14     GNU General Public License for more details.\r
15 \r
16     You should have received a copy of the GNU General Public License\r
17     along with VOMP; if not, write to the Free Software\r
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
19 */\r
20 \r
21 #include "videowin.h"\r
22 #include "log.h"\r
23 #include "dssourcefilter.h"\r
24 #include "dsallocator.h"\r
25 #include "vdr.h"\r
26 #include "osdwin.h"\r
27 \r
28 void AdjustWindow();\r
29 \r
30 \r
31 \r
32 VideoWin::VideoWin()\r
33 {\r
34   dsgraphbuilder=NULL;\r
35   dsmediacontrol=NULL;\r
36   dsvmrrenderer=NULL;\r
37   dsrefclock=NULL;\r
38   dsmediafilter=NULL;\r
39   dsbasicaudio=NULL;\r
40   sourcefilter=NULL;\r
41   allocatorvmr=NULL;\r
42   cr_time=0;\r
43   dsvmrsurfnotify=NULL;\r
44   filtermutex=CreateMutex(NULL,FALSE,NULL);\r
45   offsetnotset=true;\r
46   offsetvideonotset=true;\r
47   offsetaudionotset=true;\r
48   startoffset=0;\r
49   lastrefaudiotime=0;\r
50   lastrefvideotime=0;\r
51   lastreftimeRT=0;\r
52   lastreftimePTS=0;\r
53   firstsynched=false;\r
54   cur_audio_media_sample=NULL;\r
55   cur_video_media_sample=NULL;\r
56   videoon=true;\r
57   audioon=true;\r
58   pseudotvsize=0;\r
59   videoposx=0;\r
60   videoposy=0;\r
61 \r
62 \r
63 \r
64 }\r
65 \r
66 VideoWin::~VideoWin()\r
67 {\r
68   CleanupDS();\r
69   CloseHandle(filtermutex);\r
70 \r
71 \r
72 \r
73   instance = NULL;\r
74 }\r
75 \r
76 int VideoWin::init(UCHAR tformat)\r
77 {\r
78   if (initted) return 0;\r
79 \r
80   initted = 1;\r
81   tvsize=Video::ASPECT16X9; //Internally Vomp should think we are a 16:9 TV\r
82   videoposx=0;\r
83   videoposy=0;\r
84 \r
85   if (!setFormat(tformat)){ shutdown(); return 0; }\r
86   return 1;\r
87 }\r
88 \r
89 int VideoWin::setTVsize(UCHAR ttvsize)\r
90 {\r
91   pseudotvsize=ttvsize;\r
92   return 1;\r
93 }\r
94 \r
95 int VideoWin::setDefaultAspect()\r
96 {\r
97   return setAspectRatio(Video::ASPECT4X3);\r
98 }\r
99 \r
100 int VideoWin::shutdown()\r
101 {\r
102   if (!initted) return 0;\r
103   initted = 0;\r
104   return 1;\r
105 }\r
106 \r
107 int VideoWin::setFormat(UCHAR tformat)\r
108 {\r
109   if (!initted) return 0;\r
110   if ((tformat != PAL) && (tformat != NTSC)) return 0;\r
111   format = tformat;\r
112   if (format == NTSC)\r
113   {\r
114     screenWidth = 720;\r
115     screenHeight = 480;\r
116   }\r
117   if (format == PAL)\r
118   {\r
119     screenWidth = 720;\r
120     screenHeight = 576;\r
121   }\r
122 \r
123   return 1;\r
124 }\r
125 \r
126 int VideoWin::setConnection(UCHAR tconnection)\r
127 {\r
128   if (!initted) return 0;\r
129   if ((tconnection != COMPOSITERGB) && (tconnection != SVIDEO)) return 0;\r
130   connection = tconnection;\r
131 \r
132   return 1;\r
133 }\r
134 \r
135 int VideoWin::setAspectRatio(UCHAR taspectRatio)\r
136 {\r
137   if (!initted) return 0;\r
138   if ((taspectRatio != ASPECT4X3) && (taspectRatio != ASPECT16X9)) return 0;\r
139   aspectRatio = taspectRatio;\r
140   AdjustWindow();\r
141   return 1;\r
142 }\r
143 \r
144 int VideoWin::setMode(UCHAR tmode)\r
145 {\r
146   if (!initted) return 0;\r
147 \r
148   //if ((tmode == LETTERBOX) && (tvsize == ASPECT16X9)) return 0; // invalid mode\r
149 \r
150   if ((tmode != NORMAL) && (tmode != LETTERBOX) && (tmode != UNKNOWN2) && (tmode != QUARTER) && (tmode != EIGHTH)\r
151       && (tmode != ZOOM) && (tmode != UNKNOWN6)) return 0;\r
152   mode = tmode;\r
153   videoposx=0;\r
154   videoposy=0;\r
155   AdjustWindow();\r
156 \r
157   return 1;\r
158 }\r
159 \r
160 int VideoWin::signalOff()\r
161 {\r
162   return 1;\r
163 }\r
164 \r
165 int VideoWin::signalOn()\r
166 {\r
167   return 1;\r
168 }\r
169 \r
170 int VideoWin::setSource()\r
171 {\r
172   if (!initted) return 0;\r
173 \r
174   return 1;\r
175 }\r
176 \r
177 int VideoWin::setPosition(int x, int y)\r
178 {\r
179   if (!initted) return 0;\r
180   if (mode==QUARTER || mode==EIGHTH) {\r
181   videoposx=x;\r
182   videoposy=y;\r
183   }\r
184   return 1;\r
185 }\r
186 \r
187 int VideoWin::sync()\r
188 {\r
189   if (!initted) return 0;\r
190 \r
191   return 1;\r
192 }\r
193 \r
194 #ifdef DS_DEBUG // This stuff would not included in vomp due to lincemse restrcitions\r
195 #include "dshelper.h"\r
196 #endif\r
197 \r
198 #define DO_VIDEO\r
199 \r
200 int VideoWin::play()\r
201 {\r
202   if (!initted) return 0;\r
203   return 1;\r
204 }\r
205 \r
206 int VideoWin::dsplay()\r
207 {\r
208   if (!initted) return 0;\r
209  CleanupDS();\r
210   //Build filter graph\r
211   HRESULT hres;\r
212 \r
213   if (hres=CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,\r
214     IID_IGraphBuilder,(void**)&dsgraphbuilder)!=S_OK) {\r
215       return 0;\r
216    }\r
217    #ifdef DS_DEBUG\r
218    AddToRot(dsgraphbuilder,&graphidentifier);\r
219    #endif\r
220    //This is just a try to see if building the graph works\r
221 //   dsgraphbuilder->RenderFile(L"D:\\Projekte\\VTP Client\\test.mpa" ,NULL);\r
222    //So this is the real code, this prevents the feeder from calling noexisting objects!\r
223    WaitForSingleObject(filtermutex,INFINITE);\r
224    firstsynched=false;\r
225    sourcefilter=new DsSourceFilter(); //Creating our Source filter for pushing Data\r
226    // to DirectShow\r
227    if (hres=dsgraphbuilder->AddFilter(sourcefilter,L"Vomp Win Source Filter")!=S_OK) {\r
228    Log::getInstance()->log("VideoWin", Log::WARN , "Failed adding Vomp Source Filter!");\r
229      CleanupDS();\r
230      ReleaseMutex(filtermutex);\r
231      return 0;\r
232    }\r
233    //if (audioon) {\r
234      if (hres=dsgraphbuilder->Render(sourcefilter->GetPin(0)/*audio*/)!=S_OK) {\r
235      Log::getInstance()->log("VideoWin", Log::WARN , "Failed rendering audio!");\r
236        CleanupDS();\r
237        ReleaseMutex(filtermutex);\r
238        return 0;\r
239      }\r
240    //}\r
241 #ifdef DO_VIDEO\r
242     if (videoon) {\r
243     //We alloc the vmr9 as next step\r
244     if (hres=CoCreateInstance(CLSID_VideoMixingRenderer9,0,\r
245       CLSCTX_INPROC_SERVER,IID_IBaseFilter,(void**) &dsvmrrenderer)!=S_OK) {\r
246       Log::getInstance()->log("VideoWin", Log::WARN ,"Failed creating VMR9 renderer!");\r
247       CleanupDS();\r
248       ReleaseMutex(filtermutex);\r
249     }\r
250       /*VMR 9 stuff**/\r
251     if (hres=dsgraphbuilder->AddFilter(dsvmrrenderer,L"VMR9")!=S_OK) {\r
252       CleanupDS();\r
253       Log::getInstance()->log("VideoWin", Log::WARN ,"Failed adding VMR9 renderer!");\r
254       ReleaseMutex(filtermutex);\r
255       return 0;\r
256     }\r
257     IVMRFilterConfig9* vmrfilconfig;\r
258     if (dsvmrrenderer->QueryInterface(IID_IVMRFilterConfig9,(void**)&vmrfilconfig)!=S_OK) {\r
259       CleanupDS();\r
260       Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Filterconfig interface!");\r
261       ReleaseMutex(filtermutex);\r
262       return 0;\r
263     }\r
264     vmrfilconfig->SetRenderingMode(VMR9Mode_Renderless);\r
265     vmrfilconfig->Release();\r
266 \r
267     if (dsvmrrenderer->QueryInterface(IID_IVMRSurfaceAllocatorNotify9,(void**)& dsvmrsurfnotify)!=S_OK) {\r
268       CleanupDS();\r
269       Log::getInstance()->log("VideoWin", Log::WARN ,"Failed getting VMR9 Surface Allocator interface!");\r
270       ReleaseMutex(filtermutex);\r
271       return 0;\r
272     }\r
273     allocatorvmr=new DsAllocator();\r
274     dsvmrsurfnotify->AdviseSurfaceAllocator(NULL,allocatorvmr);\r
275     allocatorvmr->AdviseNotify(dsvmrsurfnotify);\r
276         \r
277 \r
278 \r
279 \r
280     /*VMR 9 stuff end */\r
281     IFilterGraph2*fg2=NULL;\r
282     if (dsgraphbuilder->QueryInterface(IID_IFilterGraph2,(void**)&fg2)!=S_OK) {\r
283       Log::getInstance()->log("VideoWin", Log::WARN , "Failed querying for FilterGraph2 Interface!");\r
284       CleanupDS();\r
285       ReleaseMutex(filtermutex);\r
286       return 0;\r
287     }\r
288     if (hres=fg2->RenderEx(sourcefilter->GetPin(1)/*video*/,\r
289         AM_RENDEREX_RENDERTOEXISTINGRENDERERS,NULL)!=S_OK) {\r
290       Log::getInstance()->log("VideoWin", Log::WARN , "Failed rendering Video!");\r
291           fg2->Release();\r
292       CleanupDS();\r
293       ReleaseMutex(filtermutex);\r
294       return 0;\r
295     }\r
296         fg2->Release();\r
297    }\r
298 #endif\r
299    if (hres=CoCreateInstance(CLSID_SystemClock,NULL,CLSCTX_INPROC_SERVER,\r
300     IID_IReferenceClock,(void**)&dsrefclock)!=S_OK) {\r
301       return 0;\r
302    }\r
303 \r
304    dsgraphbuilder->QueryInterface(IID_IMediaFilter,(void **) &dsmediafilter);\r
305    dsmediafilter->SetSyncSource(dsrefclock);\r
306 \r
307    dsgraphbuilder->QueryInterface(IID_IMediaControl,(void **) &dsmediacontrol);\r
308    dsgraphbuilder->QueryInterface(IID_IBasicAudio,(void **) &dsbasicaudio);     \r
309 \r
310    dsmediacontrol->Run();\r
311    ReleaseMutex(filtermutex);\r
312   return 1;\r
313 }\r
314 \r
315 int VideoWin::dsstop()\r
316 {\r
317   if (!initted) return 0;\r
318 \r
319   CleanupDS();\r
320 \r
321 \r
322   return 1;\r
323 }\r
324 \r
325 int VideoWin::stop()\r
326 {\r
327   if (!initted) return 0;\r
328 \r
329 \r
330   return 1;\r
331 }\r
332 \r
333 int VideoWin::reset()\r
334 {\r
335   if (!initted) return 0;\r
336   \r
337 \r
338   return 1;\r
339 }\r
340 \r
341 int VideoWin::dsreset()\r
342 {\r
343   if (!initted) return 0;\r
344   videoposx=0;\r
345   videoposy=0;\r
346   CleanupDS();\r
347 \r
348   return 1;\r
349 }\r
350 \r
351 int VideoWin::dspause()\r
352 {\r
353   if (!initted) return 0;\r
354   if (dsmediacontrol) dsmediacontrol->Pause();\r
355   return 1;\r
356 }\r
357 \r
358 int VideoWin::pause()\r
359 {\r
360   if (!initted) return 0;\r
361   \r
362   return 1;\r
363 }\r
364 \r
365 int VideoWin::unPause() // FIXME get rid - same as play!!\r
366 {//No on windows this is not the same, I don't get rid of!\r
367   if (!initted) return 0;\r
368   return 1;\r
369 }\r
370 \r
371 int VideoWin::dsunPause() // FIXME get rid - same as play!!\r
372 {//No on windows this is not the same, I don't get rid of!\r
373   if (!initted) return 0;\r
374   if (dsmediacontrol) dsmediacontrol->Run();\r
375   return 1;\r
376 }\r
377 \r
378 int VideoWin::fastForward()\r
379 {\r
380   if (!initted) return 0;\r
381 \r
382   return 1;\r
383 }\r
384 \r
385 int VideoWin::unFastForward()\r
386 {\r
387   if (!initted) return 0;\r
388   \r
389   return 1;\r
390 }\r
391 \r
392 int VideoWin::attachFrameBuffer()\r
393 {\r
394   if (!initted) return 0;\r
395   return 1;\r
396 }\r
397 \r
398 int VideoWin::blank(void)\r
399 {\r
400   ((OsdWin*)Osd::getInstance())->Blank();\r
401   return 1;\r
402 }\r
403 \r
404 ULLONG VideoWin::getCurrentTimestamp()\r
405 {\r
406         REFERENCE_TIME startoffset;\r
407         REFERENCE_TIME ncr_time;\r
408 \r
409   if (!dsrefclock || !sourcefilter) return 0;\r
410         FILTER_STATE state;\r
411         sourcefilter->GetState(10,&state);\r
412 \r
413         if (state==State_Running) dsrefclock->GetTime(&cr_time);\r
414         ncr_time=cr_time;\r
415   startoffset=sourcefilter->getStartOffset();\r
416         ncr_time-=startoffset;\r
417         ncr_time-=lastreftimeRT;\r
418  /* ULLONG result=frameNumberToTimecode(\r
419     VDR::getInstance()->frameNumberFromPosition(lastreftimeBYTE));*/\r
420         ULLONG result=lastreftimePTS;\r
421         result+=(ULLONG)(ncr_time/10000LL*90LL);\r
422   return result;\r
423 \r
424 }\r
425 \r
426 ULONG VideoWin::timecodeToFrameNumber(ULLONG timecode)\r
427 {\r
428   if (format == PAL) return (ULONG)(((double)timecode / (double)90000) * (double)25);\r
429   else               return (ULONG)(((double)timecode / (double)90000) * (double)30);\r
430 }\r
431 \r
432 ULLONG VideoWin::frameNumberToTimecode(ULONG framenumber)\r
433 {\r
434   if (format == PAL) return (ULLONG)(((double)framenumber * (double)90000) / (double)25);\r
435   else               return (ULLONG)(((double)framenumber * (double)90000) / (double)30);\r
436 }\r
437 \r
438 void VideoWin::CleanupDS()\r
439 {\r
440   WaitForSingleObject(filtermutex,INFINITE);\r
441   if (dsmediacontrol)dsmediacontrol->Stop();\r
442   if (cur_audio_media_sample) {\r
443     cur_audio_media_sample->Release();\r
444     cur_audio_media_sample=NULL;\r
445   }\r
446   if (cur_video_media_sample) {\r
447     cur_video_media_sample->Release();\r
448     cur_video_media_sample=NULL;\r
449   }\r
450   if (dsbasicaudio) {\r
451           dsbasicaudio->Release();\r
452           dsbasicaudio=NULL;\r
453   }\r
454   if (dsvmrsurfnotify) {\r
455     dsvmrsurfnotify->Release();\r
456     dsvmrsurfnotify=NULL;\r
457   }\r
458   if (dsvmrrenderer) {\r
459     dsvmrrenderer->Release();\r
460     dsvmrrenderer=NULL;\r
461   }\r
462 \r
463   if (allocatorvmr) {\r
464     allocatorvmr->Release();\r
465     allocatorvmr=NULL;\r
466   }\r
467 \r
468   if (dsrefclock) {\r
469     dsrefclock->Release();\r
470     dsrefclock=NULL;\r
471   }\r
472   if (dsmediafilter) {\r
473     dsmediafilter->Release();\r
474     dsmediafilter=NULL;\r
475   }\r
476 \r
477 \r
478 \r
479   if (dsmediacontrol) {\r
480     dsmediacontrol->Stop();\r
481     dsmediacontrol->Release();\r
482     dsmediacontrol=NULL;\r
483   }\r
484   if (dsgraphbuilder){\r
485 #ifdef DS_DEBUG\r
486     RemoveFromRot(graphidentifier);\r
487 #endif\r
488     dsgraphbuilder->Release();\r
489     dsgraphbuilder=NULL;\r
490     sourcefilter=NULL; //The Graph Builder destroys our SourceFilter\r
491   }\r
492   ReleaseMutex(filtermutex);\r
493 \r
494 }\r
495 \r
496 void VideoWin::PrepareMediaSample(const MediaPacketList& mplist,\r
497      UINT samplepos)\r
498 {\r
499   mediapacket = mplist.front();\r
500 }\r
501 \r
502 UINT VideoWin::DeliverMediaSample(const UCHAR* buffer, UINT *samplepos)\r
503 {\r
504   DeliverMediaPacket(mediapacket, buffer, samplepos);\r
505   if (*samplepos == mediapacket.length) {\r
506     *samplepos = 0;\r
507     return 1;\r
508   }\r
509   else return 0;\r
510 }\r
511 \r
512 UINT VideoWin::DeliverMediaPacket(MediaPacket packet,\r
513      const UCHAR* buffer,\r
514      UINT *samplepos)\r
515 {\r
516   /*First Check, if we have an audio sample*/\r
517 #ifdef DO_VIDEO\r
518   /*First Check, if we have an audio sample*/\r
519 \r
520   IMediaSample* ms=NULL;\r
521   REFERENCE_TIME reftime1=0;\r
522   REFERENCE_TIME reftime2=0;\r
523 \r
524   UINT headerstrip=0;\r
525   if (packet.disconti) {\r
526     firstsynched=false;\r
527     DeliverVideoMediaSample();\r
528 \r
529   }\r
530 \r
531 \r
532   /*Inspect PES-Header */\r
533 \r
534   if (*samplepos==0) {//stripheader\r
535     headerstrip=buffer[packet.pos_buffer+8]+9/*is this right*/;\r
536     *samplepos+=headerstrip;\r
537     if ( packet.synched ) {\r
538       DeliverVideoMediaSample();//write out old data\r
539    /*   if (packet.presentation_time<0) { //Preroll?\r
540         *samplepos=packet.length;//if we have not processed at least one\r
541         return packet.length;//synched packet ignore it!\r
542       }*/\r
543 \r
544       reftime1=packet.presentation_time;\r
545       reftime2=reftime1+1;\r
546       firstsynched=true;\r
547     } else {\r
548       if (!firstsynched) {//\r
549         *samplepos=packet.length;//if we have not processed at least one\r
550         return packet.length;//synched packet ignore it!\r
551       }\r
552     }\r
553   }\r
554   BYTE *ms_buf;\r
555   UINT ms_length;\r
556   UINT ms_pos;\r
557   UINT haveToCopy;\r
558   if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample\r
559     samplepos=0;\r
560     MILLISLEEP(10);\r
561     return 0;\r
562   }\r
563   ms_pos=ms->GetActualDataLength();\r
564   ms_length=ms->GetSize();\r
565   haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);\r
566   if ((ms_length-ms_pos)<1) {\r
567     DeliverVideoMediaSample(); //we are full!\r
568     if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample\r
569       samplepos=0;\r
570       MILLISLEEP(10);\r
571       return 0;\r
572     }\r
573     ms_pos=ms->GetActualDataLength();\r
574     ms_length=ms->GetSize();\r
575     haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);\r
576   }\r
577   ms->GetPointer(&ms_buf);\r
578 \r
579 \r
580   if (ms_pos==0) {//will only be changed on first packet\r
581     if (packet.disconti) {\r
582       ms->SetDiscontinuity(TRUE);\r
583     } else {\r
584       ms->SetDiscontinuity(FALSE);\r
585     }\r
586     if (packet.synched) {\r
587       ms->SetSyncPoint(TRUE);\r
588       ms->SetTime(&reftime1,&reftime2);\r
589       //ms->SetTime(NULL,NULL);\r
590       ms->SetMediaTime(NULL, NULL);\r
591     if (reftime1<0) ms->SetPreroll(TRUE);\r
592     else ms->SetPreroll(FALSE);\r
593     /*Timecode handling*/\r
594     lastreftimeRT=reftime1;\r
595         lastreftimePTS=packet.pts;\r
596 \r
597     }else {\r
598       ms->SetSyncPoint(FALSE);\r
599       ms->SetTime(NULL,NULL);\r
600       ms->SetMediaTime(NULL, NULL);\r
601     ms->SetPreroll(FALSE);\r
602 \r
603     //  ms->SetSyncPoint(TRUE);\r
604     }\r
605   }\r
606 \r
607 \r
608   memcpy(ms_buf+ms_pos,buffer+packet.pos_buffer+*samplepos,haveToCopy);\r
609     ms->SetActualDataLength(haveToCopy+ms_pos);\r
610 \r
611   *samplepos+=haveToCopy;\r
612 \r
613   return haveToCopy+headerstrip;\r
614 \r
615 #else\r
616 \r
617        *samplepos+=packet.length;\r
618       MILLISLEEP(0); //yet not implemented//bad idea\r
619        return packet.length;\r
620 #endif\r
621 }\r
622 \r
623 int VideoWin::getCurrentAudioMediaSample(IMediaSample** ms)\r
624 {\r
625   //WaitForSingleObject(filtermutex,INFINITE);\r
626   if (!sourcefilter){\r
627   //  ReleaseMutex(filtermutex);\r
628     return 0;\r
629   }\r
630   if (cur_audio_media_sample) {\r
631     *ms=cur_audio_media_sample;//already open\r
632     return 1;\r
633   }\r
634   if (!sourcefilter->getCurrentAudioMediaSample(ms)) {\r
635   //  ReleaseMutex(filtermutex);\r
636   }\r
637   if (*ms) (*ms)->SetActualDataLength(0);\r
638   cur_audio_media_sample=*ms;\r
639   //Don't release the mutex before deliver\r
640   return 1;\r
641 }\r
642 \r
643 int VideoWin::getCurrentVideoMediaSample(IMediaSample** ms)\r
644 {\r
645   //WaitForSingleObject(filtermutex,INFINITE);\r
646   if (!sourcefilter){\r
647   //  ReleaseMutex(filtermutex);\r
648     return 0;\r
649   }\r
650   if (cur_video_media_sample) {\r
651     *ms=cur_video_media_sample;//already open\r
652     return 1;\r
653   }\r
654   if (!sourcefilter->getCurrentVideoMediaSample(ms)) {\r
655   //  ReleaseMutex(filtermutex);\r
656   }\r
657   if (*ms) (*ms)->SetActualDataLength(0);\r
658 \r
659   cur_video_media_sample=*ms;\r
660   //Don't release the mutex before deliver\r
661   return 1;\r
662 }\r
663 \r
664 int VideoWin::DeliverAudioMediaSample(){\r
665   if (cur_audio_media_sample) {\r
666     sourcefilter->DeliverAudioMediaSample(cur_audio_media_sample);\r
667     cur_audio_media_sample=NULL;\r
668   }\r
669   //ReleaseMutex(filtermutex);\r
670   return 1;\r
671 }\r
672 \r
673 int VideoWin::DeliverVideoMediaSample(){\r
674   if (cur_video_media_sample) {\r
675     sourcefilter->DeliverVideoMediaSample(cur_video_media_sample);\r
676     cur_video_media_sample=NULL;\r
677   }\r
678   //ReleaseMutex(filtermutex);\r
679   return 1;\r
680 }\r
681 \r
682 long long VideoWin::SetStartOffset(long long curreftime, bool *rsync)\r
683 {\r
684   *rsync=false;\r
685   if (offsetnotset) {\r
686     startoffset=curreftime;//offset is set for audio\r
687     offsetnotset=false;\r
688     offsetvideonotset=false;\r
689 \r
690 \r
691   } else {\r
692     if (offsetvideonotset) {\r
693       offsetvideonotset=false;\r
694       *rsync=true;\r
695     } else {\r
696       if ( (curreftime-lastrefvideotime)>10000000LL\r
697         || (curreftime-lastrefvideotime)<-10000000LL) {//if pts jumps to big resync\r
698         startoffset+=curreftime-lastrefvideotime;\r
699         lastrefaudiotime+=curreftime-lastrefvideotime;\r
700         //*rsync=true;\r
701         offsetaudionotset=true;\r
702 \r
703       }\r
704     }\r
705 \r
706   }\r
707 \r
708   lastrefvideotime=curreftime;\r
709   \r
710   return startoffset;\r
711 \r
712 }\r
713 \r
714 long long VideoWin::SetStartAudioOffset(long long curreftime, bool *rsync)\r
715 {\r
716   *rsync=false;\r
717   if (offsetnotset) {\r
718     startoffset=curreftime;\r
719     offsetnotset=false;\r
720     offsetaudionotset=false;\r
721   }else {\r
722     if (offsetaudionotset) {\r
723       offsetaudionotset=false;\r
724       *rsync=true;\r
725     } else {\r
726       if ( (curreftime-lastrefaudiotime)>10000000LL\r
727         || (curreftime-lastrefaudiotime)<-10000000LL) {//if pts jumps to big resync\r
728         startoffset+=curreftime-lastrefaudiotime;\r
729         lastrefvideotime+=curreftime-lastrefaudiotime;\r
730         //*rsync=true;\r
731         offsetvideonotset=true;\r
732 \r
733       }\r
734     }\r
735 \r
736   }\r
737   lastrefaudiotime=curreftime;\r
738   return startoffset;\r
739 \r
740 }\r
741 void VideoWin::ResetTimeOffsets() {\r
742   offsetnotset=true; //called from demuxer\r
743   offsetvideonotset=true;\r
744   offsetaudionotset=true;\r
745   startoffset=0;\r
746   lastrefaudiotime=0;\r
747   lastrefvideotime=0;\r
748   lastreftimeRT=0;\r
749   lastreftimePTS=0;\r
750 \r
751 \r
752 }\r
753 \r
754 void VideoWin::SetAudioVolume(long volume)\r
755 {\r
756         if (dsbasicaudio) dsbasicaudio->put_Volume(volume);\r
757 }\r
758 \r
759 #ifdef DEV\r
760 int VideoWin::test()\r
761 {\r
762   return 0;\r
763 }\r
764 \r
765 int VideoWin::test2()\r
766 {\r
767   return 0;\r
768 }\r
769 #endif\r
770 \r
771 \r