]> git.vomp.tv Git - vompclient.git/blob - dssourcepin.cc
Windows updates
[vompclient.git] / dssourcepin.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 #include "dssourcepin.h"
21 #include "dssourcefilter.h"
22 #include <Dvdmedia.h>
23 #include <mmreg.h>
24
25
26 class DsSFEnumMediaTypes: public IEnumMediaTypes {
27 public:
28   DsSFEnumMediaTypes(DsSourcePin* papa,ULONG pos=0);
29   virtual ~DsSFEnumMediaTypes();
30   virtual HRESULT STDMETHODCALLTYPE Next(ULONG nummedia,  AM_MEDIA_TYPE **pins,ULONG *fetched);
31   virtual HRESULT STDMETHODCALLTYPE Skip(ULONG numpin);
32   virtual HRESULT STDMETHODCALLTYPE Reset();
33   virtual HRESULT STDMETHODCALLTYPE Clone(IEnumMediaTypes **enuma);
34   virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id,void ** object);
35   virtual ULONG STDMETHODCALLTYPE AddRef();
36     virtual ULONG STDMETHODCALLTYPE Release();
37 protected:
38   DsSourcePin* parent;
39   ULONG curpos;
40   volatile long refs;
41 };
42
43 DsSFEnumMediaTypes::DsSFEnumMediaTypes(DsSourcePin* papa,ULONG pos){
44   parent=papa;
45   curpos=pos;
46   parent->AddRef();
47   refs=0;
48 }
49
50 DsSFEnumMediaTypes::~DsSFEnumMediaTypes(){
51   parent->Release();
52 }
53
54 HRESULT STDMETHODCALLTYPE DsSFEnumMediaTypes::Next(ULONG numpin, AM_MEDIA_TYPE **pins,ULONG *fetched) {
55   int i;
56
57   if (pins==NULL) return E_POINTER;
58   if (numpin!=1 && fetched==NULL) return E_INVALIDARG;
59   *fetched=0;
60
61   for (i=0;(i<numpin);i++) {
62     pins[i]=(AM_MEDIA_TYPE*)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
63         if (parent->GetMediaType(curpos+i,pins[i])!=S_OK) {
64                 CoTaskMemFree(pins[i]);
65                 pins[i]=NULL;
66                 return S_FALSE;
67         }    curpos++;
68     if (fetched!=NULL)  (*fetched)++;
69   }
70   return S_OK;
71 }
72
73 HRESULT STDMETHODCALLTYPE   DsSFEnumMediaTypes::Skip(ULONG numpin){
74   curpos+=numpin;
75   if (curpos>1) return S_FALSE;
76   return S_OK;
77 }
78 HRESULT STDMETHODCALLTYPE DsSFEnumMediaTypes::Reset(){
79   curpos=0;
80   return S_OK;
81 }
82 HRESULT STDMETHODCALLTYPE DsSFEnumMediaTypes::Clone(IEnumMediaTypes **enuma){
83   if (enuma==NULL) return E_POINTER;
84   *enuma=new DsSFEnumMediaTypes(parent,curpos);
85   (*enuma)->AddRef();
86   return S_OK;
87 }
88
89 HRESULT STDMETHODCALLTYPE  DsSFEnumMediaTypes::QueryInterface(REFIID id,void ** object){
90   if (object==NULL) return E_POINTER;
91   if (id==IID_IUnknown ||id == IID_IEnumMediaTypes) {
92     *object=(IUnknown*)this;
93     ((IUnknown*)object)->AddRef();
94     return NOERROR;
95   } else {
96     *object=NULL;
97     return E_NOINTERFACE;
98   }
99 }
100
101
102
103 ULONG STDMETHODCALLTYPE DsSFEnumMediaTypes::AddRef(){
104   InterlockedIncrement(&refs);
105   long tempref=refs;
106   if (tempref>1) return tempref;
107   else return 1;
108 }
109
110 ULONG STDMETHODCALLTYPE DsSFEnumMediaTypes::Release(){
111   long tempref=InterlockedDecrement(&refs);
112
113   if (tempref==0) {
114     refs++;
115     delete this;
116     return NULL;
117   } else {
118     if (tempref>1) return tempref;
119     else return 1;
120   }
121 }
122
123
124 void CopyMType(AM_MEDIA_TYPE* dest,const AM_MEDIA_TYPE*source) {
125   memcpy(dest,source,sizeof(AM_MEDIA_TYPE));
126   if (source->pbFormat!=NULL) {
127     dest->pbFormat=(BYTE*)CoTaskMemAlloc(dest->cbFormat);
128     memcpy(dest->pbFormat,source->pbFormat,dest->cbFormat);
129   }
130 }
131 void ReleaseMType(AM_MEDIA_TYPE* free) {
132   if (free->cbFormat!=NULL) CoTaskMemFree(free->pbFormat);
133   free->pbFormat=NULL;
134 }
135
136 DsSourcePin::DsSourcePin(DsSourceFilter *pFilter,
137              HRESULT *phr,LPCWSTR pName,bool audio)
138 {
139   isaudiopin=audio;
140   m_pFilter=pFilter;
141   connected=NULL;
142   connectedinput=NULL;
143   allocator=NULL;
144
145
146
147 }
148
149 DsSourcePin::~DsSourcePin()
150 {
151
152
153
154 }
155
156 HRESULT STDMETHODCALLTYPE DsSourcePin::QueryInterface(REFIID id,void ** object){
157   if (object==NULL) return E_POINTER;
158   if (id==IID_IUnknown) {
159     *object=(IUnknown*)this;
160     ((IUnknown*)object)->AddRef();
161     return NOERROR;
162   } else if (id==IID_IPin) {
163     *object=(IPin*)this;
164     ((IPin*)object)->AddRef();
165     return NOERROR;
166   } else {
167     *object=NULL;
168     return E_NOINTERFACE;
169   }
170 }
171
172 ULONG STDMETHODCALLTYPE DsSourcePin::AddRef(){
173   return m_pFilter->AddRef();
174
175 }
176 ULONG STDMETHODCALLTYPE DsSourcePin::Release(){
177   return m_pFilter->Release();
178 }
179
180
181 /*IPin*/
182 HRESULT STDMETHODCALLTYPE DsSourcePin::Connect(IPin *pinempf,const AM_MEDIA_TYPE *mtype) {
183   if (pinempf==NULL) return E_POINTER;
184   EnterCriticalSection(&m_pFilter->filterlock);
185
186   if (connected!=NULL) {LeaveCriticalSection(&m_pFilter->filterlock);return VFW_E_ALREADY_CONNECTED;}
187   if (m_pFilter->mystate!=State_Stopped) {LeaveCriticalSection(&m_pFilter->filterlock);return VFW_E_NOT_STOPPED;}
188
189
190   bool gotmt=false;
191
192   if (mtype!=NULL) {
193     if (CheckMediaType(mtype)==S_OK){
194       pinempf->AddRef();
195       if (pinempf->ReceiveConnection((IPin*)this,mtype)==S_OK) {
196         CopyMType(&medtype,mtype);
197         LeaveCriticalSection(&m_pFilter->filterlock);
198       } else {
199         LeaveCriticalSection(&m_pFilter->filterlock);
200   if (mtype->pbFormat!=NULL) CoTaskMemFree(mtype->pbFormat);
201         pinempf->Release();
202         return VFW_E_TYPE_NOT_ACCEPTED;
203       }
204
205     } else {
206       LeaveCriticalSection(&m_pFilter->filterlock);
207  if (mtype->pbFormat!=NULL) CoTaskMemFree(mtype->pbFormat);
208       return VFW_E_TYPE_NOT_ACCEPTED;
209     }
210     CoTaskMemFree(mtype->pbFormat);
211   }else {
212     IEnumMediaTypes * emt;
213     EnumMediaTypes(&emt);
214     AM_MEDIA_TYPE  * emtype;
215     ULONG fetched=0;
216     pinempf->AddRef();
217     while (emt->Next(1,&emtype,&fetched)==S_OK) {
218       if (CheckMediaType(emtype)==S_OK){
219 /*      PIN_INFO pini;
220         pinempf->QueryPinInfo(&pini);
221         if (pini.pFilter!=NULL) {
222                 FILTER_INFO filti;
223                 pini.pFilter->QueryFilterInfo(&filti);
224
225                 if (filti.pGraph!=NULL) filti.pGraph->Release();
226                 char buffer[MAX_FILTER_NAME*2];
227                 wcstombs(buffer,filti.achName,MAX_FILTER_NAME*2);
228                 MessageBox(0,buffer,"Filter",0);
229                 pini.pFilter->Release();
230         }*/
231
232         if (pinempf->ReceiveConnection((IPin*)this,emtype)==S_OK) {
233           connected=pinempf;
234           CopyMType(&medtype,emtype);
235  if (emtype->pbFormat!=NULL) CoTaskMemFree(emtype->pbFormat);
236                  
237                   CoTaskMemFree(emtype);
238           gotmt=true;
239           break;
240         }
241
242       }
243  if (emtype->pbFormat!=NULL) CoTaskMemFree(emtype->pbFormat);
244           CoTaskMemFree(emtype);
245     }
246     emt->Release();
247     if (gotmt==false) {
248       pinempf->EnumMediaTypes(&emt);
249       while (emt->Next(1,&emtype,&fetched)==S_OK) {
250         if (CheckMediaType(emtype)==S_OK){
251           if (pinempf->ReceiveConnection((IPin*)this,emtype)==S_OK) {
252             connected=pinempf;
253             CopyMType(&medtype,emtype);
254             if (emtype->pbFormat!=NULL) CoTaskMemFree(emtype->pbFormat);
255                                                 CoTaskMemFree(emtype);
256             gotmt=true;
257             break;
258           }
259
260         }
261         if (emtype->pbFormat!=NULL) CoTaskMemFree(emtype->pbFormat);
262                 CoTaskMemFree(emtype);
263       }
264       emt->Release();
265       if (gotmt==false) {
266         pinempf->Release();
267         LeaveCriticalSection(&m_pFilter->filterlock);
268         return VFW_E_NO_ACCEPTABLE_TYPES;
269       }
270     }
271   }
272
273   if (pinempf->QueryInterface(IID_IMemInputPin,(void**)&connectedinput)!=S_OK) {
274     LeaveCriticalSection(&m_pFilter->filterlock);
275     connected->Release();
276     connected=NULL;
277   /*  connectedinput->Release();
278     connectedinput=NULL;*/
279     return VFW_E_NO_TRANSPORT;
280   }
281   ALLOCATOR_PROPERTIES eigenall;
282   ZeroMemory(&eigenall,sizeof(eigenall));
283   connectedinput->GetAllocatorRequirements(&eigenall);
284   if (eigenall.cbAlign==0) eigenall.cbAlign=1;
285   connectedinput->GetAllocator(&allocator);
286   if (DecideBufferSize(allocator,&eigenall)==S_OK) {
287     if (connectedinput->NotifyAllocator(allocator,FALSE)==S_OK){
288       connected=pinempf;
289       LeaveCriticalSection(&m_pFilter->filterlock);
290       return S_OK;
291     }
292   }
293   if (allocator!=NULL) allocator->Release();
294   allocator=NULL;
295
296   if (CoCreateInstance(CLSID_MemoryAllocator,0,CLSCTX_INPROC_SERVER,
297     IID_IMemAllocator,(void **)allocator)==S_OK) {
298       if (DecideBufferSize(allocator,&eigenall)==S_OK) {
299         if (connectedinput->NotifyAllocator(allocator,FALSE)==S_OK){
300           connected=pinempf;
301           LeaveCriticalSection(&m_pFilter->filterlock);
302         return S_OK;
303       }
304     }
305   }
306   if (allocator!=NULL) allocator->Release();
307   allocator=NULL;
308   connected->Release();
309   connected=NULL;
310   connectedinput->Release();
311   connectedinput=NULL;
312   LeaveCriticalSection(&m_pFilter->filterlock);
313   return VFW_E_NO_TRANSPORT;
314
315
316
317
318 }
319 HRESULT STDMETHODCALLTYPE DsSourcePin::ReceiveConnection(IPin *connect,
320                              const AM_MEDIA_TYPE *mtype){
321      return VFW_E_TYPE_NOT_ACCEPTED; //We have only output pins
322 }
323  HRESULT STDMETHODCALLTYPE DsSourcePin::Disconnect() {
324    EnterCriticalSection(&m_pFilter->filterlock);
325    if (connected!=NULL) {
326      if (m_pFilter->mystate!=State_Stopped) {LeaveCriticalSection(&m_pFilter->filterlock);return VFW_E_NOT_STOPPED;}
327      /*TODO: Decommit allocator*/
328      allocator->Decommit();
329      allocator->Release();
330      allocator=NULL;
331      ReleaseMType(&medtype);
332      connectedinput->Release();
333      connectedinput=NULL;
334      connected->Release();
335      connected=NULL;
336      LeaveCriticalSection(&m_pFilter->filterlock);
337      return S_OK;
338    }
339    LeaveCriticalSection(&m_pFilter->filterlock);
340    return S_FALSE;
341  }
342
343  HRESULT STDMETHODCALLTYPE DsSourcePin::ConnectedTo(IPin **pin){
344    if (pin==NULL) return E_POINTER;
345    IPin* pinn=connected;
346    *pin=pinn;
347    if (pinn!=NULL) {
348      pinn->AddRef();
349      return S_OK;
350    } else {
351      return VFW_E_NOT_CONNECTED;
352    }
353  }
354  HRESULT STDMETHODCALLTYPE  DsSourcePin::ConnectionMediaType(AM_MEDIA_TYPE *mtype){
355    if (mtype==NULL) return E_POINTER;
356    if (connected!=NULL){
357     CopyMType(mtype,&medtype);
358     return S_OK;
359    } else {
360      ZeroMemory(mtype,sizeof(*mtype));
361      return VFW_E_NOT_CONNECTED;
362    }
363  }
364  HRESULT STDMETHODCALLTYPE DsSourcePin::QueryPinInfo(PIN_INFO *info){
365    if (info==NULL) return E_POINTER;
366    info->dir=PINDIR_OUTPUT;
367    info->pFilter=(IBaseFilter*)m_pFilter;
368    if (m_pFilter) m_pFilter->AddRef();
369    if (isaudiopin) wcscpy(info->achName,L"Audio");
370    else wcscpy(info->achName,L"Video");
371    return S_OK;
372  }
373
374  HRESULT STDMETHODCALLTYPE  DsSourcePin::QueryDirection(PIN_DIRECTION *dir){
375    if (dir==NULL) return E_POINTER;
376    *dir=PINDIR_OUTPUT;
377    return S_OK;
378  }
379  HRESULT STDMETHODCALLTYPE DsSourcePin::QueryId(LPWSTR *id){
380    if (id==NULL) return E_POINTER;
381    *id=(LPWSTR)CoTaskMemAlloc(12);
382    if (*id==NULL) return E_OUTOFMEMORY;
383
384
385    if (isaudiopin) wcscpy(*id,L"Audio");
386     else  wcscpy(*id, L"Video");
387     return S_OK;
388  }
389  HRESULT STDMETHODCALLTYPE  DsSourcePin::QueryAccept(const AM_MEDIA_TYPE *mtype) {
390    if (mtype==NULL) return S_FALSE;
391    if (CheckMediaType(mtype)==S_OK) return S_OK;
392    else return S_FALSE;
393  }
394  HRESULT STDMETHODCALLTYPE DsSourcePin::EnumMediaTypes(IEnumMediaTypes **enuma){
395 if (enuma==NULL) return E_POINTER;
396   *enuma=new DsSFEnumMediaTypes( this);
397   (*enuma)->AddRef();
398   return S_OK;
399 }
400
401 HRESULT STDMETHODCALLTYPE DsSourcePin::QueryInternalConnections(IPin **pin,ULONG *numpin){
402   return E_NOTIMPL;
403 }
404 HRESULT STDMETHODCALLTYPE DsSourcePin::EndOfStream(){
405   return E_UNEXPECTED; //we are a output pin!
406 }
407
408 HRESULT STDMETHODCALLTYPE DsSourcePin::NewSegment(REFERENCE_TIME start,REFERENCE_TIME stop,double rate){
409   return E_UNEXPECTED;//we are a output pin!
410 }
411
412 HRESULT DsSourcePin::getCurrentMediaSample(IMediaSample**ms){
413   if (allocator!=NULL) return allocator->GetBuffer(ms,NULL,NULL,0);
414   else return E_NOINTERFACE;
415 }
416
417 HRESULT DsSourcePin::deliver(IMediaSample * ms){
418   //EnterCriticalSection(&m_pFilter->filterlock);
419   HRESULT hres;
420   if (connectedinput!=NULL)hres= connectedinput->Receive(ms);
421   else hres= VFW_E_NOT_CONNECTED;
422   //LeaveCriticalSection(&m_pFilter->filterlock);
423   return hres;
424
425 }
426
427 HRESULT DsSourcePin::GetMediaType(int iPosition, AM_MEDIA_TYPE *pmt)
428 {
429   HRESULT hr;
430
431   if (isaudiopin){
432     if (iPosition==0) {
433       ZeroMemory(pmt,sizeof(*pmt));
434       pmt->lSampleSize = 1;
435       pmt->bFixedSizeSamples = TRUE;
436       pmt->majortype=MEDIATYPE_Audio;
437       MPEG1WAVEFORMAT wfe;
438       ZeroMemory(&wfe,sizeof(wfe));
439       wfe.wfx.cbSize=22;
440       wfe.wfx.nSamplesPerSec=48000;
441       wfe.wfx.nChannels=2;
442       wfe.wfx.nAvgBytesPerSec=32000;
443       wfe.wfx.nBlockAlign=768;
444       wfe.wfx.wFormatTag=WAVE_FORMAT_MPEG;
445           wfe.wfx.wBitsPerSample=0;
446       wfe.fwHeadLayer=2;
447       wfe.dwHeadBitrate=256000;
448       wfe.fwHeadMode=ACM_MPEG_STEREO;
449       wfe.fwHeadModeExt=1;
450       wfe.wHeadEmphasis=1;
451       wfe.fwHeadFlags=ACM_MPEG_ID_MPEG1 |ACM_MPEG_ORIGINALHOME | ACM_MPEG_PROTECTIONBIT;
452       pmt->subtype=MEDIASUBTYPE_MPEG2_AUDIO;
453       pmt->formattype=FORMAT_WaveFormatEx;
454       pmt->cbFormat=sizeof(wfe);
455       pmt->pbFormat=(BYTE*)CoTaskMemAlloc(sizeof(wfe));
456       memcpy(pmt->pbFormat,&wfe,sizeof(wfe));
457       pmt->lSampleSize=0;
458       hr=S_OK;
459
460
461         } else  {
462       hr=VFW_S_NO_MORE_ITEMS ;
463     }
464   } else {
465     if (iPosition == 0) {
466       ZeroMemory(pmt,sizeof(*pmt));
467       pmt->lSampleSize = 1;
468       pmt->bFixedSizeSamples = TRUE;
469       pmt->majortype=MEDIATYPE_Video;
470       hr=S_OK;
471       pmt->subtype=MEDIASUBTYPE_MPEG2_VIDEO;
472             pmt->formattype=FORMAT_MPEG2Video;
473
474             MPEG2VIDEOINFO hdr;
475             ZeroMemory(&hdr,sizeof(hdr));
476             hdr.dwProfile=AM_MPEG2Profile_Main;
477             hdr.dwLevel=AM_MPEG2Level_Main;
478             hdr.hdr.bmiHeader.biSize = sizeof(hdr.hdr.bmiHeader);
479             hdr.hdr.bmiHeader.biWidth = 720;
480             hdr.hdr.bmiHeader.biHeight = 568;
481       pmt->cbFormat=sizeof(hdr);
482       pmt->pbFormat=(BYTE*)CoTaskMemAlloc(sizeof(hdr));
483       memcpy(pmt->pbFormat,&hdr,sizeof(hdr));
484
485     } else {
486       hr=VFW_S_NO_MORE_ITEMS;
487     }
488   }
489   return hr ;
490 }
491
492 HRESULT DsSourcePin::Inactive() {
493   if (allocator!=NULL) return allocator->Decommit();
494   return VFW_E_NO_ALLOCATOR;
495 }
496
497 HRESULT DsSourcePin::Active() {
498   if (allocator!=NULL) return allocator->Commit();
499   return VFW_E_NO_ALLOCATOR;
500 }
501
502
503 HRESULT DsSourcePin::Run(REFERENCE_TIME reftime){
504   return NOERROR;
505 }
506
507 // No description
508 HRESULT DsSourcePin::CheckMediaType(const AM_MEDIA_TYPE *pmt)
509 {
510     HRESULT res;
511
512     if (isaudiopin) {
513         bool subtype=false;
514 #if 0 /* For future demands ac3 */
515     subtype=pmt->subtype==(MEDIASUBTYPE_DOLBY_AC3);
516 #endif
517     subtype=(pmt->subtype==(MEDIASUBTYPE_MPEG2_AUDIO));
518         if (pmt->majortype==MEDIATYPE_Audio && subtype) {
519       res = S_OK ;
520         } else {
521             res = S_FALSE ;
522         }
523     } else {
524         if (pmt->majortype==MEDIATYPE_Video &&
525                   pmt-> subtype==MEDIASUBTYPE_MPEG2_VIDEO) {
526       res = S_OK ;
527         } else {
528             res = S_FALSE ;
529         }
530     }
531     return res;
532 }
533
534 HRESULT DsSourcePin::DecideBufferSize(IMemAllocator *pa,ALLOCATOR_PROPERTIES *all_pp){
535   HRESULT hr;
536
537     if (pa==NULL)return E_POINTER;
538     if (all_pp==NULL) return E_POINTER;
539   if (isaudiopin) {
540     if (all_pp->cBuffers*all_pp->cbBuffer < 300*64*1024)
541     {
542       //all_pp->cBuffers = 300;//old
543       all_pp->cBuffers = 10;
544       all_pp->cbBuffer = 64*1024;
545     }
546   } else {
547     if (all_pp->cBuffers*all_pp->cbBuffer < 300*64*1024)
548     {
549       //all_pp->cBuffers = 300;//old
550       all_pp->cBuffers = 30;
551       all_pp->cbBuffer = 64*1024;
552     }
553   }
554
555     ALLOCATOR_PROPERTIES all_pp_cur;
556     hr =pa->SetProperties(all_pp,&all_pp_cur);
557     if (FAILED(hr))
558     {
559         return hr;
560     }
561     if (all_pp_cur.cbBuffer*all_pp_cur.cBuffers < all_pp->cBuffers*all_pp->cbBuffer)
562     {
563         return E_FAIL;
564     }
565
566     return S_OK;
567 }
568
569