2 Copyright 2004-2005 Chris Tallon
\r
4 This file is part of VOMP.
\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
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
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
\r
21 #include "audiowin.h"
\r
22 #include "videowin.h"
\r
24 #include "wtabbar.h"
\r
25 #include "wwinaudiofilter.h"
\r
26 #include "wwinmp3audiofilter.h"
\r
32 AudioWin::AudioWin()
\r
38 audiofilterselected=-1;
\r
39 mp3audiofilterselected=-1;
\r
40 aud_type=Audio::MPEG2_PES;
\r
44 AudioWin::~AudioWin()
\r
48 for (i=0;i<audiofilterlist.size();i++)
\r
50 if (audiofilterlist[i].displayname) delete [] audiofilterlist[i].displayname;
\r
51 if (audiofilterlist[i].friendlyname) delete [] audiofilterlist[i].friendlyname;
\r
53 audiofilterlist.clear();
\r
55 for (i=0;i<mp3audiofilterlist.size();i++)
\r
57 if (mp3audiofilterlist[i].displayname) delete [] mp3audiofilterlist[i].displayname;
\r
58 if (mp3audiofilterlist[i].friendlyname) delete [] mp3audiofilterlist[i].friendlyname;
\r
60 mp3audiofilterlist.clear();
\r
64 int AudioWin::init(UCHAR tstreamType)
\r
66 if (initted) return 0;
\r
67 initFilterDatabase();
\r
68 initMp3FilterDatabase();
\r
73 int AudioWin::shutdown()
\r
75 if (!initted) return 0;
\r
80 int AudioWin::write(char *buf, int len)
\r
82 return 0; //write(fdAudio, buf, len);
\r
85 int AudioWin::setStreamType(UCHAR type)
\r
87 ((VideoWin*)VideoWin::getInstance())->setAudioStreamType(type);
\r
89 if (!initted) return 0;
\r
93 int AudioWin::setChannel()
\r
95 if (!initted) return 0;
\r
99 int AudioWin::setSource()
\r
101 if (!initted) return 0;
\r
105 int AudioWin::sync()
\r
107 if (!initted) return 0;
\r
111 int AudioWin::play()
\r
113 if (!initted) return 0;
\r
114 firstsynched=false;
\r
115 return ((VideoWin*)Video::getInstance())->dsplay();
\r
119 int AudioWin::stop()
\r
121 if (!initted) return 0;
\r
122 return ((VideoWin*)Video::getInstance())->dsstop();
\r
125 int AudioWin::pause()
\r
127 if (!initted) return 0;
\r
128 return ((VideoWin*)Video::getInstance())->dspause();
\r
131 int AudioWin::unPause()
\r
133 if (!initted) return 0;
\r
134 return ((VideoWin*)Video::getInstance())->dsunPause();
\r
137 int AudioWin::reset()
\r
140 if (!initted){return 0;}
\r
141 return ((VideoWin*)Video::getInstance())->dsreset();
\r
144 int AudioWin::setVolume(int tvolume)
\r
146 // parameter: 0 for silence, 20 for full
\r
147 if ((tvolume < 0) || (tvolume > 20)) return 0;
\r
148 winvolume=((tvolume-20)*100*30)/20;
\r
149 if (tvolume==0) winvolume=-10000;
\r
150 ((VideoWin*)Video::getInstance())->SetAudioVolume(winvolume);
\r
156 int AudioWin::mute()
\r
158 if (!initted) return 0;
\r
159 ((VideoWin*)Video::getInstance())->SetAudioState(false);
\r
160 ((VideoWin*)Video::getInstance())->SetAudioVolume(-10000);
\r
164 int AudioWin::unMute()
\r
166 if (!initted) return 0;
\r
167 ((VideoWin*)Video::getInstance())->SetAudioState(true);
\r
168 ((VideoWin*)Video::getInstance())->SetAudioVolume(winvolume);
\r
172 void AudioWin::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos)
\r
174 mediapacket = mplist.front();
\r
177 void AudioWin::initFilterDatabase()
\r
179 /* This method should determine all availiable DirectShow Filters */
\r
180 IFilterMapper2* filtmap=NULL;
\r
182 result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC,
\r
183 IID_IFilterMapper2,(void**)&filtmap);
\r
184 if (result != S_OK)
\r
186 Log::getInstance()->log("AudioWin", Log::ERR , "Unable to create FilterMapper!");
\r
189 /* Wishlist, what Mediatypes do we want */
\r
190 GUID mtypesin[]={MEDIATYPE_Audio,MEDIASUBTYPE_MPEG2_AUDIO,
\r
191 /*MEDIATYPE_Audio,MEDIASUBTYPE_MPEG1Payload,*/
\r
192 MEDIATYPE_Audio,MEDIASUBTYPE_DOLBY_AC3,
\r
193 MEDIATYPE_Audio, MEDIASUBTYPE_DOLBY_AC3_SPDIF};
\r
194 IEnumMoniker *myenum;
\r
195 result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1,
\r
196 TRUE,3,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL);
\r
197 if (result != S_OK)
\r
199 filtmap->Release();
\r
200 Log::getInstance()->log("AudioWin", Log::ERR , "Unable to enum Filters!");
\r
205 while(myenum->Next(1,&moni,&gethowmany)==S_OK)
\r
207 AudioFilterDesc desc;
\r
208 ZeroMemory(&desc,sizeof(desc));
\r
211 moni->GetDisplayName(0,0,&string);
\r
212 desc.displayname=new char[wcslen(string)+1];
\r
213 wcstombs(desc.displayname,string,wcslen(string)+1);
\r
214 CoTaskMemFree(string);
\r
216 if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK)
\r
219 VariantInit(&vari);
\r
220 result = bag->Read(L"FriendlyName",&vari,NULL);
\r
221 if (result == S_OK)
\r
223 desc.friendlyname=new char[wcslen(vari.bstrVal)+1];
\r
224 wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1);
\r
226 VariantClear(&vari);
\r
232 audiofilterlist.push_back(desc);
\r
237 // bctx->Release();
\r
240 audiofilterselected=-1;
\r
242 filtmap->Release();
\r
245 void AudioWin::initMp3FilterDatabase()
\r
247 /* This method should determine all availiable DirectShow Filters */
\r
248 IFilterMapper2* filtmap=NULL;
\r
250 result = CoCreateInstance(CLSID_FilterMapper2,NULL,CLSCTX_INPROC,
\r
251 IID_IFilterMapper2,(void**)&filtmap);
\r
252 if (result != S_OK)
\r
254 Log::getInstance()->log("AudioWin", Log::ERR , "Unable to create FilterMapper!");
\r
257 /* Wishlist, what Mediatypes do we want */
\r
258 GUID mtypesin[]={MEDIATYPE_Audio,MEDIATYPE_WaveFmt_Mpeg1Layer3,
\r
259 MEDIATYPE_Audio,MEDIASUBTYPE_MPEG2_AUDIO};
\r
260 IEnumMoniker *myenum;
\r
261 result = filtmap->EnumMatchingFilters(&myenum,0,TRUE,MERIT_DO_NOT_USE+1,
\r
262 TRUE,3,mtypesin,NULL,NULL,FALSE,TRUE,0,NULL,NULL,NULL);
\r
263 if (result != S_OK)
\r
265 filtmap->Release();
\r
266 Log::getInstance()->log("AudioWin", Log::ERR , "Unable to enum Filters!");
\r
271 while(myenum->Next(1,&moni,&gethowmany)==S_OK)
\r
273 AudioFilterDesc desc;
\r
274 ZeroMemory(&desc,sizeof(desc));
\r
277 moni->GetDisplayName(0,0,&string);
\r
278 desc.displayname=new char[wcslen(string)+1];
\r
279 wcstombs(desc.displayname,string,wcslen(string)+1);
\r
280 CoTaskMemFree(string);
\r
282 if (moni->BindToStorage(0,0,IID_IPropertyBag,(void**)&bag) == S_OK)
\r
285 VariantInit(&vari);
\r
286 result = bag->Read(L"FriendlyName",&vari,NULL);
\r
287 if (result == S_OK)
\r
289 desc.friendlyname=new char[wcslen(vari.bstrVal)+1];
\r
290 wcstombs(desc.friendlyname,vari.bstrVal,wcslen(vari.bstrVal)+1);
\r
292 VariantClear(&vari);
\r
298 mp3audiofilterlist.push_back(desc);
\r
303 // bctx->Release();
\r
306 mp3audiofilterselected=-1;
\r
308 filtmap->Release();
\r
311 bool AudioWin::loadOptionsfromServer(VDR* vdr)
\r
313 char *name=vdr->configLoad("DirectShow","AudioFilter");
\r
317 for (int i = 0;i <audiofilterlist.size();i++)
\r
319 if (strcmp(name,audiofilterlist[i].displayname)==0)
\r
321 audiofilterselected = i;
\r
326 name=vdr->configLoad("DirectShow","Mp3AudioFilter");
\r
330 for (int i = 0;i <mp3audiofilterlist.size();i++)
\r
332 if (strcmp(name,mp3audiofilterlist[i].displayname)==0)
\r
334 mp3audiofilterselected = i;
\r
343 bool AudioWin::saveOptionstoServer()
\r
345 if (audiofilterselected!=-1) {
\r
346 VDR::getInstance()->configSave("DirectShow",
\r
347 "AudioFilter",audiofilterlist[audiofilterselected].displayname);
\r
349 if (mp3audiofilterselected!=-1) {
\r
350 VDR::getInstance()->configSave("DirectShow",
\r
351 "Mp3AudioFilter",mp3audiofilterlist[mp3audiofilterselected].displayname);
\r
356 UINT AudioWin::DeliverMediaSample(UCHAR* buffer, UINT *samplepos)
\r
358 DeliverMediaPacket(mediapacket, buffer, samplepos);
\r
359 if (*samplepos == mediapacket.length) {
\r
366 UINT AudioWin::DeliverMediaPacket(const MediaPacket packet,
\r
371 /*First Check, if we have an audio sample*/
\r
372 VideoWin *vw=(VideoWin*)Video::getInstance();
\r
373 if (!vw->isdsinited()) return 0;
\r
374 if (vw->InIframemode()) {
\r
377 return 0; //Not in iframe mode!
\r
379 IMediaSample* ms=NULL;
\r
380 REFERENCE_TIME reftime1=0;
\r
381 REFERENCE_TIME reftime2=0;
\r
383 UINT headerstrip=0;
\r
384 if (packet.disconti) {
\r
385 firstsynched=false;
\r
386 vw->DeliverAudioMediaSample();
\r
389 if (packet.type!=vw->lastAType()){//Format Change //Push data out !
\r
390 firstsynched=false;
\r
391 vw->DeliverAudioMediaSample();
\r
396 /*Inspect PES-Header */
\r
397 /* UINT header_length=buffer[(packet.pos_buffer+8)%bufferlength]+8/*is this right*;
\r
399 if (*samplepos==0 && packet.type!=MPTYPE_MPEG_AUDIO_LAYER3) {//stripheader
\r
400 headerstrip=buffer[packet.pos_buffer+8]+9;
\r
401 if (packet.type == MPTYPE_AC3) headerstrip+=4; //skip ac3 bytes
\r
402 *samplepos+=headerstrip;
\r
403 if ( packet.synched ) {
\r
404 vw->DeliverAudioMediaSample();//write out old data
\r
405 reftime1=packet.presentation_time;
\r
406 reftime2=reftime1+1;
\r
409 if (!firstsynched) {//
\r
410 *samplepos=packet.length;//if we have not processed at least one
\r
411 return packet.length;//synched packet ignore it!
\r
419 if (!vw->getCurrentAudioMediaSample(&ms) || ms==NULL) {// get the current sample
\r
424 ms_pos=ms->GetActualDataLength();
\r
425 ms_length=ms->GetSize();
\r
426 haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
\r
427 if ((ms_length-ms_pos)<1) {
\r
428 vw->DeliverAudioMediaSample(); //we are full!
\r
429 if (!vw->getCurrentAudioMediaSample(&ms) || ms==NULL) {// get the current sample
\r
434 ms_pos=ms->GetActualDataLength();
\r
435 ms_length=ms->GetSize();
\r
436 haveToCopy=min(ms_length-ms_pos,packet.length-*samplepos);
\r
438 ms->GetPointer(&ms_buf);
\r
441 if (ms_pos==0) {//will only be changed on first packet
\r
442 if (packet.disconti) {
\r
443 ms->SetDiscontinuity(TRUE);
\r
445 ms->SetDiscontinuity(FALSE);
\r
447 if (packet.synched) {
\r
448 ms->SetSyncPoint(TRUE);
\r
449 ms->SetTime(&reftime1,&reftime2);
\r
451 //ms->SetTime(NULL,NULL);
\r
452 ms->SetMediaTime(NULL, NULL);
\r
453 if (reftime1<0) ms->SetPreroll(TRUE);
\r
454 else ms->SetPreroll(FALSE);
\r
456 ms->SetSyncPoint(FALSE);
\r
457 ms->SetTime(NULL,NULL);
\r
458 ms->SetMediaTime(NULL, NULL);
\r
459 ms->SetPreroll(FALSE);
\r
460 // ms->SetSyncPoint(TRUE);
\r
463 if (packet.type!=vw->lastAType()) {
\r
464 vw->changeAType(packet.type,ms);
\r
465 ms->SetDiscontinuity(TRUE);
\r
469 memcpy(ms_buf+ms_pos,buffer+packet.pos_buffer+*samplepos,haveToCopy);
\r
471 ms->SetActualDataLength(haveToCopy+ms_pos);
\r
473 *samplepos+=haveToCopy;
\r
475 return haveToCopy+headerstrip;
\r
479 int AudioWin::dsInitAudioFilter(IGraphBuilder* dsgraphbuilder)
\r
482 IFilterGraph2*fg2=NULL;
\r
483 VideoWin *vw=(VideoWin*)Video::getInstance();
\r
484 if (dsgraphbuilder->QueryInterface(IID_IFilterGraph2,(void**)&fg2)!= S_OK)
\r
486 Log::getInstance()->log("AudiooWin", Log::WARN , "Failed querying for FilterGraph2 Interface!");
\r
489 IBaseFilter*audiofilter;
\r
490 if (aud_type!=Audio::MP3) {
\r
491 audiofilter = getAudioFilter();
\r
493 audiofilter = getMp3AudioFilter();
\r
495 if (dsgraphbuilder->AddFilter(audiofilter,NULL) != S_OK)
\r
497 Log::getInstance()->log("AudioWin", Log::WARN , "Failed adding Video Filter!");
\r
500 IEnumPins *pinenum=NULL;
\r
502 if (audiofilter->EnumPins(&pinenum) == S_OK)
\r
504 IPin *current=NULL;
\r
506 bool firststep=false;
\r
507 while (pinenum->Next(1,¤t,&fetch)==S_OK)
\r
510 if (current->QueryDirection(&dir)==S_OK)
\r
512 if (dir == PINDIR_INPUT)
\r
514 if (vw->getSourceFilter()->GetAudioPin()->Connect(current,NULL)==S_OK)
\r
516 current->Release();
\r
522 current->Release();
\r
524 if (firststep==false)
\r
526 Log::getInstance()->log("AudioWin", Log::WARN , "Audio Filter has no suitable input!");
\r
527 audiofilter->Release();
\r
530 bool secondstep=false;
\r
532 while (pinenum->Next(1,¤t,&fetch)==S_OK)
\r
535 if (current->QueryDirection(&dir)==S_OK)
\r
537 if (dir == PINDIR_OUTPUT)
\r
540 if (fg2->RenderEx((IPin*)current/*video*/,
\r
543 current->Release();
\r
549 current->Release();
\r
551 if (secondstep==false)
\r
553 Log::getInstance()->log("AudioWin", Log::WARN , "Audio Filter has no suitable output!");
\r
554 audiofilter->Release();
\r
559 audiofilter->Release();
\r
560 pinenum->Release();
\r
571 IBaseFilter *AudioWin::getAudioFilter()
\r
573 IBaseFilter *curfilter= NULL;
\r
575 if (audiofilterselected == -1)
\r
578 for (i = 0;i <audiofilterlist.size();i++)
\r
580 audiofilterselected = i;
\r
585 IBindCtx *bindctx=NULL;
\r
586 if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;
\r
587 IMoniker * moni=NULL;
\r
588 LPCOLESTR name=new WCHAR[strlen(audiofilterlist[audiofilterselected].displayname)+1];
\r
589 mbstowcs((wchar_t*)name,audiofilterlist[audiofilterselected].displayname,
\r
590 strlen(audiofilterlist[audiofilterselected].displayname)+1);
\r
592 if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)
\r
594 if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)
\r
596 if (curfilter != NULL && notset)
\r
598 VDR *vdr=VDR::getInstance();
\r
601 vdr->configSave("DirectShow","AudioFilter",
\r
602 audiofilterlist[audiofilterselected].displayname);
\r
608 bindctx->Release();
\r
611 bindctx->Release();
\r
618 IBaseFilter *AudioWin::getMp3AudioFilter()
\r
620 IBaseFilter *curfilter= NULL;
\r
622 if (mp3audiofilterselected == -1)
\r
625 for (i = 0;i <mp3audiofilterlist.size();i++)
\r
627 mp3audiofilterselected = i;
\r
632 IBindCtx *bindctx=NULL;
\r
633 if (CreateBindCtx(0,&bindctx)!=S_OK) return NULL;
\r
634 IMoniker * moni=NULL;
\r
635 LPCOLESTR name=new WCHAR[strlen(mp3audiofilterlist[mp3audiofilterselected].displayname)+1];
\r
636 mbstowcs((wchar_t*)name,mp3audiofilterlist[mp3audiofilterselected].displayname,
\r
637 strlen(mp3audiofilterlist[mp3audiofilterselected].displayname)+1);
\r
639 if (MkParseDisplayName(bindctx,name,&eater,&moni)==S_OK)
\r
641 if (moni->BindToObject(0,0,IID_IBaseFilter,(void**)&curfilter) == S_OK)
\r
643 if (curfilter != NULL && notset)
\r
645 VDR *vdr=VDR::getInstance();
\r
648 vdr->configSave("DirectShow","Mp3AudioFilter",
\r
649 mp3audiofilterlist[mp3audiofilterselected].displayname);
\r
655 bindctx->Release();
\r
658 bindctx->Release();
\r
666 bool AudioWin::addOptionPagesToWTB(WTabBar *wtb)
\r
668 Boxx *box=new WWinAudioFilter();
\r
669 wtb->addTab(tr("Audio Filter"), box);
\r
672 box=new WWinMp3AudioFilter();
\r
673 wtb->addTab(tr("Mp3 Audio Filter"), box);
\r
679 const AudioFilterDescList *AudioWin::getAudioFilterList(int &selected)
\r
681 selected=audiofilterselected;
\r
682 return &audiofilterlist;
\r
685 const AudioFilterDescList *AudioWin::getMp3AudioFilterList(int &selected)
\r
687 selected=mp3audiofilterselected;
\r
688 return &mp3audiofilterlist;
\r
690 bool AudioWin::selectMp3AudioFilter(int filter)
\r
692 mp3audiofilterselected=filter;
\r
697 bool AudioWin::selectAudioFilter(int filter)
\r
699 audiofilterselected=filter;
\r
704 long long AudioWin::SetStartOffset(long long curreftime, bool *rsync){
\r
705 VideoWin *vw=(VideoWin*)Video::getInstance();
\r
706 return vw->SetStartAudioOffset(curreftime,rsync);
\r
709 void AudioWin::ResetTimeOffsets() {
\r
710 VideoWin *vw=(VideoWin*)Video::getInstance();
\r
711 vw->ResetTimeOffsets();
\r
714 bool AudioWin::supportsAc3(){
\r
715 VideoWin *vw=(VideoWin*)Video::getInstance();
\r
716 return vw->supportsAc3();
\r
720 int AudioWin::test()
\r