]> git.vomp.tv Git - vompclient-marten.git/blob - audiowin.cc
Fix bug in demuxer widescreen signaling
[vompclient-marten.git] / audiowin.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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 #include "audiowin.h"
22 #include "videowin.h"
23 #include "vdr.h"
24 #include "wtabbar.h"
25 #include "wwinaudiofilter.h"
26 #include "wwinmp3audiofilter.h"
27 #include "i18n.h"
28
29
30
31
32 AudioWin::AudioWin()
33 {
34   initted = 0;
35   firstsynched=false;
36   winvolume=0;
37   volume=20;
38 audiofilterselected=-1;
39   mp3audiofilterselected=-1;
40   aud_type=Audio::MPEG2_PES;
41
42 }
43
44 AudioWin::~AudioWin()
45 {
46
47   int i;
48   for (i=0;i<audiofilterlist.size();i++)
49   {
50    if (audiofilterlist[i].displayname) delete [] audiofilterlist[i].displayname;
51    if (audiofilterlist[i].friendlyname) delete [] audiofilterlist[i].friendlyname;
52   }
53   audiofilterlist.clear();
54
55   for (i=0;i<mp3audiofilterlist.size();i++)
56   {
57    if (mp3audiofilterlist[i].displayname) delete [] mp3audiofilterlist[i].displayname;
58    if (mp3audiofilterlist[i].friendlyname) delete [] mp3audiofilterlist[i].friendlyname;
59   }
60   mp3audiofilterlist.clear();
61
62 }
63
64 int AudioWin::init(UCHAR tstreamType)
65 {
66   if (initted) return 0;
67   initFilterDatabase();
68   initMp3FilterDatabase();
69   initted = 1;
70   return 1;
71 }
72
73 int AudioWin::shutdown()
74 {
75   if (!initted) return 0;
76   initted = 0;
77   return 1;
78 }
79
80 int AudioWin::write(char *buf, int len)
81 {
82   return 0; //write(fdAudio, buf, len);
83 }
84
85 int AudioWin::setStreamType(UCHAR type)
86 {
87   ((VideoWin*)VideoWin::getInstance())->setAudioStreamType(type);
88   aud_type=type;
89   if (!initted) return 0;
90   return 1;
91 }
92
93 int AudioWin::setChannel()
94 {
95   if (!initted) return 0;
96   return 1;
97 }
98
99 int AudioWin::setSource()
100 {
101   if (!initted) return 0;
102   return 1;
103 }
104
105 int AudioWin::sync()
106 {
107   if (!initted) return 0;
108   return 1;
109 }
110
111 int AudioWin::play()
112 {
113   if (!initted) return 0;
114   firstsynched=false;
115   return ((VideoWin*)Video::getInstance())->dsplay();
116
117 }
118
119 int AudioWin::stop()
120 {
121   if (!initted) return 0;
122   return ((VideoWin*)Video::getInstance())->dsstop();
123 }
124
125 int AudioWin::pause()
126 {
127   if (!initted) return 0;
128   return ((VideoWin*)Video::getInstance())->dspause();
129 }
130
131 int AudioWin::unPause()
132 {
133   if (!initted) return 0;
134   return ((VideoWin*)Video::getInstance())->dsunPause();
135 }
136
137 int AudioWin::reset()
138 {
139   
140   if (!initted){return 0;}
141   return ((VideoWin*)Video::getInstance())->dsreset();
142 }
143
144 int AudioWin::setVolume(int tvolume)
145 {
146   // parameter: 0 for silence, 20 for full
147   if ((tvolume < 0) || (tvolume > 20)) return 0;
148   winvolume=((tvolume-20)*100*30)/20;
149   if (tvolume==0) winvolume=-10000;
150   ((VideoWin*)Video::getInstance())->SetAudioVolume(winvolume);
151
152
153   return 1;
154 }
155
156 int AudioWin::mute()
157 {
158   if (!initted) return 0;
159   ((VideoWin*)Video::getInstance())->SetAudioState(false);
160   ((VideoWin*)Video::getInstance())->SetAudioVolume(-10000);
161   return 1;
162 }
163
164 int AudioWin::unMute()
165 {
166   if (!initted) return 0;
167   ((VideoWin*)Video::getInstance())->SetAudioState(true);
168   ((VideoWin*)Video::getInstance())->SetAudioVolume(winvolume);
169   return 1;
170 }
171
172 void AudioWin::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos)
173 {
174   mediapacket = mplist.front();
175 }
176
177 void AudioWin::initFilterDatabase()
178 {
179      /* This method should determine all availiable DirectShow Filters */
180     IFilterMapper2* filtmap=NULL;
181     HRESULT result;
182     result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC,
183                 IID_IFilterMapper2,(void**)&filtmap);
184     if (result != S_OK)
185     {
186         Log::getInstance()->log("AudioWin", Log::ERR , "Unable to create FilterMapper!");
187         return;
188     }
189     /* Wishlist, what Mediatypes do we want */
190     GUID mtypesin[]={MEDIATYPE_Audio,MEDIASUBTYPE_MPEG2_AUDIO,
191     /*MEDIATYPE_Audio,MEDIASUBTYPE_MPEG1Payload,*/
192     MEDIATYPE_Audio,MEDIASUBTYPE_DOLBY_AC3,
193      MEDIATYPE_Audio, MEDIASUBTYPE_DOLBY_AC3_SPDIF};
194     IEnumMoniker *myenum;
195     result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1,
196                     TRUE,3,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL);
197     if (result != S_OK)
198     {
199         filtmap->Release();
200         Log::getInstance()->log("AudioWin", Log::ERR , "Unable to enum Filters!");
201         return;
202     }
203     ULONG gethowmany;
204     IMoniker * moni;
205     while(myenum->Next(1,&moni,&gethowmany)==S_OK)
206     {
207         AudioFilterDesc desc;
208         ZeroMemory(&desc,sizeof(desc));
209    
210         LPOLESTR string;
211         moni->GetDisplayName(0,0,&string);
212         desc.displayname=new char[wcslen(string)+1];
213         wcstombs(desc.displayname,string,wcslen(string)+1);
214         CoTaskMemFree(string);
215         IPropertyBag *bag;
216         if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK)
217         {
218             VARIANT vari;
219             VariantInit(&vari);
220             result = bag->Read(L"FriendlyName",&vari,NULL);
221             if (result == S_OK)
222             {
223                 desc.friendlyname=new char[wcslen(vari.bstrVal)+1];
224                 wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1);
225             }
226             VariantClear(&vari);
227             bag->Release();
228
229         }
230         
231        
232         audiofilterlist.push_back(desc);
233        
234
235         
236         moni->Release();
237        // bctx->Release();
238     }
239     int i;
240     audiofilterselected=-1;
241     myenum->Release();
242     filtmap->Release();
243 }
244
245 void AudioWin::initMp3FilterDatabase()
246 {
247      /* This method should determine all availiable DirectShow Filters */
248     IFilterMapper2* filtmap=NULL;
249     HRESULT result;
250     result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC,
251                 IID_IFilterMapper2,(void**)&filtmap);
252     if (result != S_OK)
253     {
254         Log::getInstance()->log("AudioWin", Log::ERR , "Unable to create FilterMapper!");
255         return;
256     }
257     /* Wishlist, what Mediatypes do we want */
258     GUID mtypesin[]={MEDIATYPE_Audio,MEDIATYPE_WaveFmt_Mpeg1Layer3,
259                     MEDIATYPE_Audio,MEDIASUBTYPE_MPEG2_AUDIO};
260     IEnumMoniker *myenum;
261     result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1,
262                     TRUE,3,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL);
263     if (result != S_OK)
264     {
265         filtmap->Release();
266         Log::getInstance()->log("AudioWin", Log::ERR , "Unable to enum Filters!");
267         return;
268     }
269     ULONG gethowmany;
270     IMoniker * moni;
271     while(myenum->Next(1,&moni,&gethowmany)==S_OK)
272     {
273         AudioFilterDesc desc;
274         ZeroMemory(&desc,sizeof(desc));
275    
276         LPOLESTR string;
277         moni->GetDisplayName(0,0,&string);
278         desc.displayname=new char[wcslen(string)+1];
279         wcstombs(desc.displayname,string,wcslen(string)+1);
280         CoTaskMemFree(string);
281         IPropertyBag *bag;
282         if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK)
283         {
284             VARIANT vari;
285             VariantInit(&vari);
286             result = bag->Read(L"FriendlyName",&vari,NULL);
287             if (result == S_OK)
288             {
289                 desc.friendlyname=new char[wcslen(vari.bstrVal)+1];
290                 wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1);
291             }
292             VariantClear(&vari);
293             bag->Release();
294
295         }
296         
297        
298         mp3audiofilterlist.push_back(desc);
299        
300
301         
302         moni->Release();
303        // bctx->Release();
304     }
305     int i;
306     mp3audiofilterselected=-1;
307     myenum->Release();
308     filtmap->Release();
309 }
310
311 bool AudioWin::loadOptionsfromServer(VDR* vdr)
312 {
313     char *name=vdr->configLoad("DirectShow","AudioFilter");
314     
315     if (name != NULL) 
316     {
317         for (int i = 0;i <audiofilterlist.size();i++)
318         {
319             if (strcmp(name,audiofilterlist[i].displayname)==0)
320             {
321                 audiofilterselected = i;
322                 break;
323             }
324         }
325    }
326     name=vdr->configLoad("DirectShow","Mp3AudioFilter");
327     
328     if (name != NULL) 
329     {
330         for (int i = 0;i <mp3audiofilterlist.size();i++)
331         {
332             if (strcmp(name,mp3audiofilterlist[i].displayname)==0)
333             {
334                 mp3audiofilterselected = i;
335                 break;
336             }
337         }
338    }
339    return true;
340
341 }
342
343 bool AudioWin::saveOptionstoServer()
344 {
345     if (audiofilterselected!=-1) {
346         VDR::getInstance()->configSave("DirectShow",
347             "AudioFilter",audiofilterlist[audiofilterselected].displayname);
348     }
349     if (mp3audiofilterselected!=-1) {
350         VDR::getInstance()->configSave("DirectShow",
351             "Mp3AudioFilter",mp3audiofilterlist[mp3audiofilterselected].displayname);
352     }
353     return true;
354 }
355
356 UINT AudioWin::DeliverMediaSample(UCHAR* buffer, UINT *samplepos)
357 {
358   DeliverMediaPacket(mediapacket, buffer, samplepos);
359   if (*samplepos == mediapacket.length) {
360     *samplepos = 0;
361     return 1;
362   }
363   else return 0;
364 }
365
366 UINT AudioWin::DeliverMediaPacket(const MediaPacket packet,
367      UCHAR* buffer,
368      UINT *samplepos)
369 {
370
371   /*First Check, if we have an audio sample*/
372   VideoWin *vw=(VideoWin*)Video::getInstance();
373  if (!vw->isdsinited()) return 0;
374   if (vw->InIframemode()) {
375                 samplepos=0;
376                 MILLISLEEP(10);
377                 return 0; //Not in iframe mode!
378   }
379   IMediaSample* ms=NULL;
380   REFERENCE_TIME reftime1=0;
381   REFERENCE_TIME reftime2=0;
382
383   UINT headerstrip=0;
384   if (packet.disconti) {
385     firstsynched=false;
386     vw->DeliverAudioMediaSample();
387   }
388
389   if (packet.type!=vw->lastAType()){//Format Change //Push data out !
390       firstsynched=false;
391       vw->DeliverAudioMediaSample();
392   }
393
394
395
396   /*Inspect PES-Header */
397 /*  UINT header_length=buffer[(packet.pos_buffer+8)%bufferlength]+8/*is this right*;
398 */
399   if (*samplepos==0 && packet.type!=MPTYPE_MPEG_AUDIO_LAYER3) {//stripheader
400       headerstrip=buffer[packet.pos_buffer+8]+9;
401     if (packet.type == MPTYPE_AC3) headerstrip+=4; //skip ac3 bytes
402     *samplepos+=headerstrip;
403     if ( packet.synched ) {
404       vw->DeliverAudioMediaSample();//write out old data
405       reftime1=packet.presentation_time;
406       reftime2=reftime1+1;
407       firstsynched=true;
408     } else {
409       if (!firstsynched) {//
410         *samplepos=packet.length;//if we have not processed at least one
411         return packet.length;//synched packet ignore it!
412       }
413     }
414   }
415   BYTE *ms_buf;
416   UINT ms_length;
417   UINT ms_pos;
418   UINT haveToCopy;
419   if (!vw->getCurrentAudioMediaSample(&ms) || ms==NULL) {// get the current sample
420     //samplepos=0;
421     //MILLISLEEP(10);
422     return *samplepos;
423   }
424   ms_pos=ms->GetActualDataLength();
425   ms_length=ms->GetSize();
426   haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
427   if ((ms_length-ms_pos)<1) {
428     vw->DeliverAudioMediaSample(); //we are full!
429     if (!vw->getCurrentAudioMediaSample(&ms) || ms==NULL) {// get the current sample
430       //samplepos=0;
431       //MILLISLEEP(10);
432       return *samplepos;
433     }
434     ms_pos=ms->GetActualDataLength();
435     ms_length=ms->GetSize();
436     haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
437   }
438   ms->GetPointer(&ms_buf);
439
440
441   if (ms_pos==0) {//will only be changed on first packet
442     if (packet.disconti) {
443       ms->SetDiscontinuity(TRUE);
444     } else {
445       ms->SetDiscontinuity(FALSE);
446     }
447     if (packet.synched) {
448       ms->SetSyncPoint(TRUE);
449       ms->SetTime(&reftime1,&reftime2);
450
451       //ms->SetTime(NULL,NULL);
452       ms->SetMediaTime(NULL, NULL);
453     if (reftime1<0) ms->SetPreroll(TRUE);
454     else ms->SetPreroll(FALSE);
455     }else {
456       ms->SetSyncPoint(FALSE);
457       ms->SetTime(NULL,NULL);
458       ms->SetMediaTime(NULL, NULL);
459     ms->SetPreroll(FALSE);
460     //  ms->SetSyncPoint(TRUE);
461     }
462   }
463   if (packet.type!=vw->lastAType()) {
464       vw->changeAType(packet.type,ms);
465       ms->SetDiscontinuity(TRUE);
466   }
467
468
469   memcpy(ms_buf+ms_pos,buffer+packet.pos_buffer+*samplepos,haveToCopy);
470
471     ms->SetActualDataLength(haveToCopy+ms_pos);
472
473   *samplepos+=haveToCopy;
474
475   return haveToCopy+headerstrip;
476
477 }
478
479 int AudioWin::dsInitAudioFilter(IGraphBuilder* dsgraphbuilder)
480 {
481     HRESULT hres;
482     IFilterGraph2*fg2=NULL;
483     VideoWin *vw=(VideoWin*)Video::getInstance();
484     if (dsgraphbuilder->QueryInterface(IID_IFilterGraph2,(void**)&fg2)!= S_OK)
485     {
486         Log::getInstance()->log("AudiooWin", Log::WARN , "Failed querying for FilterGraph2 Interface!");
487         return 0;
488     }
489     IBaseFilter*audiofilter;
490     if (aud_type!=Audio::MP3) {
491         audiofilter = getAudioFilter();
492     } else {
493         audiofilter = getMp3AudioFilter();
494     }
495     if (dsgraphbuilder->AddFilter(audiofilter,NULL) != S_OK)
496     {
497         Log::getInstance()->log("AudioWin", Log::WARN , "Failed adding Video Filter!");
498         return 0;
499     }
500     IEnumPins *pinenum=NULL;
501     bool error=false;
502     if (audiofilter->EnumPins(&pinenum) == S_OK)
503     {
504         IPin *current=NULL;
505         ULONG fetch=0;
506         bool firststep=false;
507         while (pinenum->Next(1,&current,&fetch)==S_OK)
508         {
509             PIN_DIRECTION dir;
510             if (current->QueryDirection(&dir)==S_OK)
511             {
512                 if (dir == PINDIR_INPUT)
513                 {
514                     if (vw->getSourceFilter()->GetAudioPin()->Connect(current,NULL)==S_OK)
515                     {
516                         current->Release();
517                         firststep=true;
518                             break;
519                     }
520                 }
521             }
522             current->Release();
523         }
524         if (firststep==false)
525         {
526             Log::getInstance()->log("AudioWin", Log::WARN , "Audio Filter has no suitable input!");
527             audiofilter->Release();
528             return 0;
529         }
530         bool secondstep=false;
531         pinenum->Reset();
532         while (pinenum->Next(1,&current,&fetch)==S_OK)
533         {
534             PIN_DIRECTION dir;
535             if (current->QueryDirection(&dir)==S_OK)
536             {
537                 if (dir == PINDIR_OUTPUT)
538                 {
539                    
540                     if (fg2->RenderEx((IPin*)current/*video*/,
541                                 0,NULL) ==S_OK)
542                     {
543                         current->Release();
544                         secondstep=true;
545                         break;
546                     }
547                 }
548             }
549             current->Release();
550         }
551         if (secondstep==false)
552         {
553            Log::getInstance()->log("AudioWin", Log::WARN , "Audio Filter has no suitable output!");
554            audiofilter->Release();
555            
556            return 0;
557         }
558             
559         audiofilter->Release();
560         pinenum->Release();
561
562     }
563
564
565
566     fg2->Release();
567     return 1;
568 }
569
570
571 IBaseFilter *AudioWin::getAudioFilter()
572 {
573     IBaseFilter *curfilter= NULL;
574     bool notset=false;
575     if (audiofilterselected == -1)
576     {
577         int i;
578         for (i = 0;i <audiofilterlist.size();i++)
579         {
580             audiofilterselected = i;
581             notset=true;
582             break;
583         }
584     }
585     IBindCtx *bindctx=NULL;
586     if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;
587     IMoniker * moni=NULL;
588     LPCOLESTR name=new WCHAR[strlen(audiofilterlist[audiofilterselected].displayname)+1];
589     mbstowcs((wchar_t*)name,audiofilterlist[audiofilterselected].displayname,
590     strlen(audiofilterlist[audiofilterselected].displayname)+1);
591     ULONG eater;
592     if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)
593     {
594         if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)
595         {
596             if (curfilter != NULL && notset)
597             {
598                 VDR *vdr=VDR::getInstance();
599                 if (vdr != NULL)
600                 {
601                     vdr->configSave("DirectShow","AudioFilter",
602                         audiofilterlist[audiofilterselected].displayname);
603                 }
604             }
605                     
606             moni->Release();
607             delete [] name;
608             bindctx->Release();
609             return curfilter; 
610         }
611         bindctx->Release();
612         delete [] name;
613         return NULL;         
614     }
615     return NULL; 
616 }
617
618 IBaseFilter *AudioWin::getMp3AudioFilter()
619 {
620     IBaseFilter *curfilter= NULL;
621     bool notset=false;
622     if (mp3audiofilterselected == -1)
623     {
624         int i;
625         for (i = 0;i <mp3audiofilterlist.size();i++)
626         {
627             mp3audiofilterselected = i;
628             notset=true;
629             break;
630         }
631     }
632     IBindCtx *bindctx=NULL;
633     if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;
634     IMoniker * moni=NULL;
635     LPCOLESTR name=new WCHAR[strlen(mp3audiofilterlist[mp3audiofilterselected].displayname)+1];
636     mbstowcs((wchar_t*)name,mp3audiofilterlist[mp3audiofilterselected].displayname,
637     strlen(mp3audiofilterlist[mp3audiofilterselected].displayname)+1);
638     ULONG eater;
639     if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)
640     {
641         if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)
642         {
643             if (curfilter != NULL && notset)
644             {
645                 VDR *vdr=VDR::getInstance();
646                 if (vdr != NULL)
647                 {
648                     vdr->configSave("DirectShow","Mp3AudioFilter",
649                         mp3audiofilterlist[mp3audiofilterselected].displayname);
650                 }
651             }
652                     
653             moni->Release();
654             delete [] name;
655             bindctx->Release();
656             return curfilter; 
657         }
658         bindctx->Release();
659         delete [] name;
660         return NULL;         
661     }
662     return NULL; 
663 }
664
665
666 bool AudioWin::addOptionPagesToWTB(WTabBar *wtb)
667 {
668     Boxx *box=new WWinAudioFilter();
669     wtb->addTab(tr("Audio Filter"), box);
670
671     
672     box=new WWinMp3AudioFilter();
673     wtb->addTab(tr("Mp3 Audio Filter"), box);
674     
675
676     return true;
677 }
678
679 const AudioFilterDescList *AudioWin::getAudioFilterList(int &selected)
680 {
681     selected=audiofilterselected;
682     return &audiofilterlist;
683 }
684
685 const AudioFilterDescList *AudioWin::getMp3AudioFilterList(int &selected)
686 {
687     selected=mp3audiofilterselected;
688     return &mp3audiofilterlist;
689 }
690 bool AudioWin::selectMp3AudioFilter(int filter)
691 {
692     mp3audiofilterselected=filter;
693     return true;
694     
695 }
696
697 bool AudioWin::selectAudioFilter(int filter)
698 {
699     audiofilterselected=filter;
700     return true;
701     
702 }
703
704 long long AudioWin::SetStartOffset(long long curreftime, bool *rsync){
705   VideoWin *vw=(VideoWin*)Video::getInstance();
706   return vw->SetStartAudioOffset(curreftime,rsync);
707 }
708
709 void AudioWin::ResetTimeOffsets() {
710   VideoWin *vw=(VideoWin*)Video::getInstance();
711   vw->ResetTimeOffsets();
712 }
713
714 bool AudioWin::supportsAc3(){
715     VideoWin *vw=(VideoWin*)Video::getInstance();
716     return vw->supportsAc3();
717 }
718
719 #ifdef DEV
720 int AudioWin::test()
721 {
722   return 0;
723 }
724 #endif
725
726
727