]> git.vomp.tv Git - vompclient.git/blob - videowin.cc
Windows port. New sync code. Various other bug fixes.
[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 "dssourcefilter.h"
23
24
25
26
27
28 VideoWin::VideoWin()
29 {
30   dsgraphbuilder=NULL;
31   dsmediacontrol=NULL;
32   sourcefilter=NULL;
33   filtermutex=CreateMutex(NULL,FALSE,NULL);
34   offsetnotset=true;
35   offsetvideonotset=true;
36   offsetaudionotset=true;
37   startoffset=0;
38   lastrefaudiotime=0;
39   lastrefvideotime=0;
40   firstsynched=false;
41   cur_audio_media_sample=NULL;
42   cur_video_media_sample=NULL;
43   videoon=true;
44   audioon=true;
45
46
47 }
48
49 VideoWin::~VideoWin()
50 {
51   CleanupDS();
52   CloseHandle(filtermutex);
53
54
55   instance = NULL;
56 }
57
58 int VideoWin::init(UCHAR tformat)
59 {
60   if (initted) return 0;
61
62   initted = 1;
63   if (!setFormat(tformat)){ shutdown(); return 0; }
64   return 1;
65 }
66
67 int VideoWin::setTVsize(UCHAR ttvsize)
68 {
69   return 1;
70 }
71
72 int VideoWin::setDefaultAspect()
73 {
74   return setAspectRatio(tvsize);
75 }
76
77 int VideoWin::shutdown()
78 {
79   if (!initted) return 0;
80   initted = 0;
81   return 1;
82 }
83
84 int VideoWin::setFormat(UCHAR tformat)
85 {
86   if (!initted) return 0;
87   if ((tformat != PAL) && (tformat != NTSC)) return 0;
88   format = tformat;
89   if (format == NTSC)
90   {
91     screenWidth = 720;
92     screenHeight = 480;
93   }
94   if (format == PAL)
95   {
96     screenWidth = 720;
97     screenHeight = 576;
98   }
99
100   return 1;
101 }
102
103 int VideoWin::setConnection(UCHAR tconnection)
104 {
105   if (!initted) return 0;
106   if ((tconnection != COMPOSITERGB) && (tconnection != SVIDEO)) return 0;
107   connection = tconnection;
108
109   return 1;
110 }
111
112 int VideoWin::setAspectRatio(UCHAR taspectRatio)
113 {
114   if (!initted) return 0;
115   if ((taspectRatio != ASPECT4X3) && (taspectRatio != ASPECT16X9)) return 0;
116   aspectRatio = taspectRatio;
117
118   return 1;
119 }
120
121 int VideoWin::setMode(UCHAR tmode)
122 {
123   if (!initted) return 0;
124
125   if ((tmode == LETTERBOX) && (tvsize == ASPECT16X9)) return 0; // invalid mode
126
127   if ((tmode != NORMAL) && (tmode != LETTERBOX) && (tmode != UNKNOWN2) && (tmode != QUARTER) && (tmode != EIGHTH)
128       && (tmode != ZOOM) && (tmode != UNKNOWN6)) return 0;
129   mode = tmode;
130
131   return 1;
132 }
133
134 int VideoWin::signalOff()
135 {
136   return 1;
137 }
138
139 int VideoWin::signalOn()
140 {
141   return 1;
142 }
143
144 int VideoWin::setSource()
145 {
146   if (!initted) return 0;
147
148   return 1;
149 }
150
151 int VideoWin::setPosition(int x, int y)
152 {
153   if (!initted) return 0;
154
155   return 1;
156 }
157
158 int VideoWin::sync()
159 {
160   if (!initted) return 0;
161
162   return 1;
163 }
164
165 #ifdef DS_DEBUG // This stuff would not included in vomp due to lincemse restrcitions
166 #include "dshelper.h"
167 #endif
168
169 #define DO_VIDEO
170
171 int VideoWin::play()
172 {
173   if (!initted) return 0;
174
175   //Build filter graph
176   HRESULT hres;
177   if (hres=CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,
178     IID_IGraphBuilder,(void**)&dsgraphbuilder)!=S_OK) {
179       return 0;
180    }
181    #ifdef DS_DEBUG
182    AddToRot(dsgraphbuilder,&graphidentifier);
183    #endif
184    //This is just a try to see if building the graph works
185 //   dsgraphbuilder->RenderFile(L"D:\\Projekte\\VTP Client\\test.mpa" ,NULL);
186    //So this is the real code, this prevents the feeder from calling noexisting objects!
187    WaitForSingleObject(filtermutex,INFINITE);
188    offsetnotset=true;
189    offsetvideonotset=true;
190    offsetaudionotset=true;
191    firstsynched=false;
192    sourcefilter=new DsSourceFilter(); //Creating our Source filter for pushing Data
193    // to DirectShow
194    if (hres=dsgraphbuilder->AddFilter(sourcefilter,L"Vomp Win Source Filter")!=S_OK) {
195      CleanupDS();
196      ReleaseMutex(filtermutex);
197      return 0;
198    }
199    if (audioon) {
200      if (hres=dsgraphbuilder->Render(sourcefilter->GetPin(0)/*audio*/)!=S_OK) {
201        CleanupDS();
202        ReleaseMutex(filtermutex);
203        return 0;
204      }
205    }
206 #ifdef DO_VIDEO
207    if (videoon) {
208      if (hres=dsgraphbuilder->Render(sourcefilter->GetPin(1)/*video*/)!=S_OK) {
209        CleanupDS();
210        ReleaseMutex(filtermutex);
211        return 0;
212      }
213    }
214 #endif
215
216
217
218    dsgraphbuilder->QueryInterface(IID_IMediaControl,(void **) &dsmediacontrol);
219    dsmediacontrol->Run();
220    ReleaseMutex(filtermutex);
221   return 1;
222 }
223
224 int VideoWin::stop()
225 {
226   if (!initted) return 0;
227
228   CleanupDS();
229
230
231   return 1;
232 }
233
234 int VideoWin::reset()
235 {
236   if (!initted) return 0;
237
238   return 1;
239 }
240
241 int VideoWin::pause()
242 {
243   if (!initted) return 0;
244   if (dsmediacontrol) dsmediacontrol->Pause();
245   return 1;
246 }
247
248 int VideoWin::unPause() // FIXME get rid - same as play!!
249 {//No on windows this is not the same, I don't get rid of!
250   if (!initted) return 0;
251   if (dsmediacontrol) dsmediacontrol->Run();
252   return 1;
253 }
254
255 int VideoWin::fastForward()
256 {
257   if (!initted) return 0;
258   return 1;
259 }
260
261 int VideoWin::unFastForward()
262 {
263   if (!initted) return 0;
264   return 1;
265 }
266
267 int VideoWin::attachFrameBuffer()
268 {
269   if (!initted) return 0;
270   return 1;
271 }
272
273 int VideoWin::blank(void)
274 {
275   return 1;
276 }
277
278 int VideoWin::getFD()
279 {
280   if (!initted) return 0;
281
282   return fdVideo;
283 }
284
285 ULLONG VideoWin::getCurrentTimestamp()
286 {
287   return 0;
288 }
289
290 ULONG VideoWin::timecodeToFrameNumber(ULLONG timecode)
291 {
292   if (format == PAL) return (ULONG)(((double)timecode / (double)90000) * (double)25);
293   else               return (ULONG)(((double)timecode / (double)90000) * (double)30);
294 }
295
296 void VideoWin::CleanupDS()
297 {
298   WaitForSingleObject(filtermutex,INFINITE);
299   if (cur_audio_media_sample) {
300     cur_audio_media_sample->Release();
301     cur_audio_media_sample=NULL;
302   }
303   if (cur_video_media_sample) {
304     cur_video_media_sample->Release();
305     cur_video_media_sample=NULL;
306   }
307
308   if (dsmediacontrol) {
309     dsmediacontrol->Stop();
310     dsmediacontrol->Release();
311     dsmediacontrol=NULL;
312   }
313   if (dsgraphbuilder){
314 #ifdef DS_DEBUG
315     RemoveFromRot(graphidentifier);
316 #endif
317     dsgraphbuilder->Release();
318     dsgraphbuilder=NULL;
319     sourcefilter=NULL; //The Graph Builder destroys our SourceFilter
320   }
321   ReleaseMutex(filtermutex);
322
323 }
324
325
326 UINT VideoWin::DeliverMediaSample(MediaPacket packet,
327      UCHAR* buffer,
328      UINT *samplepos)
329 {
330   /*First Check, if we have an audio sample*/
331 #ifdef DO_VIDEO
332   /*First Check, if we have an audio sample*/
333
334   IMediaSample* ms=NULL;
335   REFERENCE_TIME reftime1=0;
336   REFERENCE_TIME reftime2=0;
337
338   UINT headerstrip=0;
339   if (packet.disconti) {
340     firstsynched=false;
341     DeliverVideoMediaSample();
342
343   }
344
345
346   /*Inspect PES-Header */
347
348   if (*samplepos==0) {//stripheader
349     headerstrip=buffer[packet.pos_buffer+8]+9/*is this right*/;
350     *samplepos+=headerstrip;
351     if ( packet.synched ) {
352       DeliverVideoMediaSample();//write out old data
353       if (packet.presentation_time<0) { //Preroll?
354         *samplepos=packet.length;//if we have not processed at least one
355         return packet.length;//synched packet ignore it!
356       }
357
358       reftime1=packet.presentation_time;
359       reftime2=reftime1+1;
360       firstsynched=true;
361     } else {
362       if (!firstsynched) {//
363         *samplepos=packet.length;//if we have not processed at least one
364         return packet.length;//synched packet ignore it!
365       }
366     }
367   }
368   BYTE *ms_buf;
369   UINT ms_length;
370   UINT ms_pos;
371   UINT haveToCopy;
372   if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
373     samplepos=0;
374     MILLISLEEP(10);
375     return 0;
376   }
377   ms_pos=ms->GetActualDataLength();
378   ms_length=ms->GetSize();
379   haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
380   if ((ms_length-ms_pos)<1) {
381     DeliverVideoMediaSample(); //we are full!
382     if (!getCurrentVideoMediaSample(&ms) || ms==NULL) {// get the current sample
383       samplepos=0;
384       MILLISLEEP(10);
385       return 0;
386     }
387     ms_pos=ms->GetActualDataLength();
388     ms_length=ms->GetSize();
389     haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
390   }
391   ms->GetPointer(&ms_buf);
392
393
394   if (ms_pos==0) {//will only be changed on first packet
395     if (packet.disconti) {
396       ms->SetDiscontinuity(TRUE);
397     } else {
398       ms->SetDiscontinuity(FALSE);
399     }
400     if (packet.synched) {
401       ms->SetSyncPoint(TRUE);
402       ms->SetTime(&reftime1,&reftime2);
403       //ms->SetTime(NULL,NULL);
404       ms->SetMediaTime(NULL, NULL);
405     }else {
406       ms->SetSyncPoint(FALSE);
407       ms->SetTime(NULL,NULL);
408       ms->SetMediaTime(NULL, NULL);
409       ms->SetSyncPoint(TRUE);
410     }
411   }
412
413
414   memcpy(ms_buf+ms_pos,buffer+packet.pos_buffer+*samplepos,haveToCopy);
415     ms->SetActualDataLength(haveToCopy+ms_pos);
416
417   *samplepos+=haveToCopy;
418
419   return haveToCopy+headerstrip;
420
421 #else
422
423        *samplepos+=packet.length;
424       MILLISLEEP(0); //yet not implemented//bad idea
425        return packet.length;
426 #endif
427 }
428
429 int VideoWin::getCurrentAudioMediaSample(IMediaSample** ms)
430 {
431   //WaitForSingleObject(filtermutex,INFINITE);
432   if (!sourcefilter){
433   //  ReleaseMutex(filtermutex);
434     return 0;
435   }
436   if (cur_audio_media_sample) {
437     *ms=cur_audio_media_sample;//already open
438     return 1;
439   }
440   if (!sourcefilter->getCurrentAudioMediaSample(ms)) {
441   //  ReleaseMutex(filtermutex);
442   }
443   if (*ms) (*ms)->SetActualDataLength(0);
444   cur_audio_media_sample=*ms;
445   //Don't release the mutex before deliver
446   return 1;
447 }
448
449 int VideoWin::getCurrentVideoMediaSample(IMediaSample** ms)
450 {
451   //WaitForSingleObject(filtermutex,INFINITE);
452   if (!sourcefilter){
453   //  ReleaseMutex(filtermutex);
454     return 0;
455   }
456   if (cur_video_media_sample) {
457     *ms=cur_video_media_sample;//already open
458     return 1;
459   }
460   if (!sourcefilter->getCurrentVideoMediaSample(ms)) {
461   //  ReleaseMutex(filtermutex);
462   }
463   if (*ms) (*ms)->SetActualDataLength(0);
464
465   cur_video_media_sample=*ms;
466   //Don't release the mutex before deliver
467   return 1;
468 }
469
470 int VideoWin::DeliverAudioMediaSample(){
471   if (cur_audio_media_sample) {
472     sourcefilter->DeliverAudioMediaSample(cur_audio_media_sample);
473     cur_audio_media_sample=NULL;
474   }
475   //ReleaseMutex(filtermutex);
476   return 1;
477 }
478
479 int VideoWin::DeliverVideoMediaSample(){
480   if (cur_video_media_sample) {
481     sourcefilter->DeliverVideoMediaSample(cur_video_media_sample);
482     cur_video_media_sample=NULL;
483   }
484   //ReleaseMutex(filtermutex);
485   return 1;
486 }
487
488 long long VideoWin::SetStartOffset(long long curreftime, bool *rsync)
489 {
490   *rsync=false;
491   if (offsetnotset) {
492     startoffset=curreftime;//offset is set for audio
493     offsetnotset=false;
494     offsetvideonotset=false;
495   } else {
496     if (offsetvideonotset) {
497       offsetvideonotset=false;
498       *rsync=true;
499     } else {
500       if ( (curreftime-lastrefvideotime)>10000000LL
501         || (curreftime-lastrefvideotime)<-10000000LL) {//if pts jumps to big resync
502         startoffset+=curreftime-lastrefvideotime;
503         //lastrefaudiotime+=curreftime-lastrefvideotime;
504         *rsync=true;
505         offsetaudionotset=true;
506
507       }
508     }
509
510   }
511   lastrefvideotime=curreftime;
512   return startoffset;
513
514 }
515
516 long long VideoWin::SetStartAudioOffset(long long curreftime, bool *rsync)
517 {
518   *rsync=false;
519   if (offsetnotset) {
520     startoffset=curreftime;
521     offsetnotset=false;
522     offsetaudionotset=false;
523   } else {
524     if (offsetaudionotset) {
525       offsetaudionotset=false;
526       *rsync=true;
527     } else {
528       if ( (curreftime-lastrefaudiotime)>10000000LL
529         || (curreftime-lastrefaudiotime)<-10000000LL) {//if pts jumps to big resync
530         startoffset+=curreftime-lastrefaudiotime;
531         lastrefvideotime+=curreftime-lastrefaudiotime;
532         *rsync=true;
533         offsetvideonotset=true;
534
535       }
536     }
537
538   }
539   lastrefaudiotime=curreftime;
540   return startoffset;
541
542 }
543
544
545
546 #ifdef DEV
547 int VideoWin::test()
548 {
549   return 0;
550 }
551
552 int VideoWin::test2()
553 {
554   return 0;
555 }
556 #endif