BaseClass.pas 487 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582
  1. (*********************************************************************
  2. * DSPack 2.3.3 *
  3. * DirectShow BaseClass *
  4. * *
  5. * home page : http://www.progdigy.com *
  6. * email : hgourvest@progdigy.com *
  7. * *
  8. * date : 21-02-2003 *
  9. * *
  10. * The contents of this file are used with permission, subject to *
  11. * the Mozilla Public License Version 1.1 (the "License"); you may *
  12. * not use this file except in compliance with the License. You may *
  13. * obtain a copy of the License at *
  14. * http://www.mozilla.org/MPL/MPL-1.1.html *
  15. * *
  16. * Software distributed under the License is distributed on an *
  17. * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or *
  18. * implied. See the License for the specific language governing *
  19. * rights and limitations under the License. *
  20. * *
  21. * Contributor(s) *
  22. * Andriy Nevhasymyy <a.n@email.com> *
  23. * Milenko Mitrovic <dcoder@dsp-worx.de> *
  24. * Michael Andersen <michael@mechdata.dk> *
  25. * Martin Offenwanger <coder@dsplayer.de> *
  26. * *
  27. *********************************************************************)
  28. {.$DEFINE DEBUG} // Debug Log
  29. {.$DEFINE TRACE} // Trace Criteral Section (DEBUG must be ON)
  30. {.$DEFINE MESSAGE} // Use OutputDebugString instead of a File (DEBUG must be ON)
  31. {.$DEFINE PERF} // Show Performace Counter
  32. {.$DEFINE VTRANSPERF} // Show additional TBCVideoTransformFilter Performace Counter (PERF must be ON)
  33. {$MINENUMSIZE 4}
  34. {$ALIGN ON}
  35. unit BaseClass;
  36. {$IFDEF VER150}
  37. {$WARN UNSAFE_CODE OFF}
  38. {$WARN UNSAFE_TYPE OFF}
  39. {$WARN UNSAFE_CAST OFF}
  40. {$ENDIF}
  41. interface
  42. uses Windows, SysUtils, Classes, Math, ActiveX, Forms, Messages, Controls,
  43. DirectShow9, dialogs, ComObj, mmsystem, DSUtil;
  44. const
  45. OATRUE = -1;
  46. OAFALSE = 0;
  47. DEFAULTCACHE = 10; // Default node object cache size
  48. type
  49. TBCCritSec = class
  50. private
  51. FCritSec : TRTLCriticalSection;
  52. {$IFDEF DEBUG}
  53. FcurrentOwner: Longword;
  54. FlockCount : Longword;
  55. {$ENDIF}
  56. public
  57. constructor Create;
  58. destructor Destroy; override;
  59. procedure Lock;
  60. procedure UnLock;
  61. function CritCheckIn: boolean;
  62. function CritCheckOut: boolean;
  63. end;
  64. TBCBaseObject = class(TObJect)
  65. private
  66. FName: string;
  67. public
  68. constructor Create(Name: string);
  69. destructor Destroy; override;
  70. class function NewInstance: TObject; override;
  71. procedure FreeInstance; override;
  72. class function ObjectsActive: integer;
  73. end;
  74. TBCClassFactory = Class;
  75. TBCUnknown = class(TBCBaseObject, IUnKnown)
  76. private
  77. FRefCount: integer;
  78. FOwner : Pointer;
  79. protected
  80. function IUnknown.QueryInterface = NonDelegatingQueryInterface;
  81. function IUnknown._AddRef = NonDelegatingAddRef;
  82. function IUnknown._Release = NonDelegatingRelease;
  83. function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  84. public
  85. function _AddRef: Integer; stdcall;
  86. function _Release: Integer; stdcall;
  87. constructor Create(name: string; Unk: IUnknown);
  88. constructor CreateFromFactory(Factory: TBCClassFactory; const Controller: IUnknown); virtual;
  89. function NonDelegatingQueryInterface(const IID: TGUID; out Obj): HResult; virtual; stdcall;
  90. function NonDelegatingAddRef: Integer; virtual; stdcall;
  91. function NonDelegatingRelease: Integer; virtual; stdcall;
  92. function GetOwner: IUnKnown;
  93. end;
  94. TBCUnknownClass = Class of TBCUnknown;
  95. TFormPropertyPage = class;
  96. TFormPropertyPageClass = class of TFormPropertyPage;
  97. TBCBaseFilter = class;
  98. TBCBaseFilterClass = class of TBCBaseFilter;
  99. TBCClassFactory = class(TObject, IUnKnown, IClassFactory)
  100. private
  101. FNext : TBCClassFactory;
  102. FComClass : TBCUnknownClass;
  103. FPropClass: TFormPropertyPageClass;
  104. FName : String;
  105. FClassID : TGUID;
  106. FCategory : TGUID;
  107. FMerit : LongWord;
  108. FPinCount : Cardinal;
  109. FPins : PRegFilterPins;
  110. function RegisterFilter(FilterMapper: IFilterMapper; Register: Boolean): boolean; overload;
  111. function RegisterFilter(FilterMapper: IFilterMapper2; Register: Boolean): boolean; overload;
  112. procedure UpdateRegistry(Register: Boolean); overload;
  113. protected
  114. function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  115. function _AddRef: Integer; stdcall;
  116. function _Release: Integer; stdcall;
  117. function CreateInstance(const UnkOuter: IUnknown; const IID: TGUID;
  118. out Obj): HResult; stdcall;
  119. function LockServer(fLock: BOOL): HResult; stdcall;
  120. public
  121. constructor CreateFilter(ComClass: TBCUnknownClass; Name: string;
  122. const ClassID: TGUID; const Category: TGUID; Merit: LongWord;
  123. PinCount: Cardinal; Pins: PRegFilterPins);
  124. constructor CreatePropertyPage(ComClass: TFormPropertyPageClass; const ClassID: TGUID);
  125. property Name: String read FName;
  126. property ClassID: TGUID read FClassID;
  127. end;
  128. TBCFilterTemplate = class
  129. private
  130. FFactoryList : TBCClassFactory;
  131. procedure AddObjectFactory(Factory: TBCClassFactory);
  132. public
  133. constructor Create;
  134. destructor Destroy; override;
  135. function RegisterServer(Register: Boolean): boolean;
  136. function GetFactoryFromClassID(const CLSID: TGUID): TBCClassFactory;
  137. end;
  138. TBCMediaType = object
  139. MediaType: PAMMediaType;
  140. function Equal(mt: TBCMediaType): boolean; overload;
  141. function Equal(mt: PAMMediaType): boolean; overload;
  142. function MatchesPartial(Partial: PAMMediaType): boolean;
  143. function IsPartiallySpecified: boolean;
  144. function IsValid: boolean;
  145. procedure InitMediaType;
  146. function FormatLength: Cardinal;
  147. end;
  148. TBCBasePin = class;
  149. TBCBaseFilter = class(TBCUnknown, IBaseFilter, IAMovieSetup)
  150. protected
  151. FState : TFilterState; // current state: running, paused
  152. FClock : IReferenceClock; // this graph's ref clock
  153. FStart : TReferenceTime; // offset from stream time to reference time
  154. FCLSID : TGUID; // This filters clsid used for serialization
  155. FLock : TBCCritSec; // Object we use for locking
  156. FFilterName : WideString; // Full filter name
  157. FGraph : IFilterGraph; // Graph we belong to
  158. FSink : IMediaEventSink; // Called with notify events
  159. FPinVersion: Integer; // Current pin version
  160. public
  161. constructor Create(Name: string; // Object description
  162. Unk : IUnKnown; // IUnknown of delegating object
  163. Lock: TBCCritSec; // Object who maintains lock
  164. const clsid: TGUID // The clsid to be used to serialize this filter
  165. ); overload;
  166. constructor Create(Name: string; // Object description
  167. Unk : IUnKnown; // IUnknown of delegating object
  168. Lock: TBCCritSec; // Object who maintains lock
  169. const clsid: TGUID; // The clsid to be used to serialize this filter
  170. out hr: HRESULT // General OLE return code
  171. ); overload;
  172. constructor CreateFromFactory(Factory: TBCClassFactory; const Controller: IUnknown); override;
  173. destructor destroy; override;
  174. // --- IPersist method ---
  175. function GetClassID(out classID: TCLSID): HResult; stdcall;
  176. // --- IMediaFilter methods ---
  177. // override Stop and Pause so we can activate the pins.
  178. // Note that Run will call Pause first if activation needed.
  179. // Override these if you want to activate your filter rather than
  180. // your pins.
  181. function Stop: HRESULT; virtual; stdcall;
  182. function Pause: HRESULT; virtual; stdcall;
  183. // the start parameter is the difference to be added to the
  184. // sample's stream time to get the reference time for
  185. // its presentation
  186. function Run(tStart: TReferenceTime): HRESULT; virtual; stdcall;
  187. function GetState(dwMilliSecsTimeout: DWORD; out State: TFilterState): HRESULT; virtual; stdcall;
  188. function SetSyncSource(pClock: IReferenceClock): HRESULT; stdcall;
  189. function GetSyncSource(out pClock: IReferenceClock): HRESULT; stdcall;
  190. // --- helper methods ---
  191. // return the current stream time - ie find out what
  192. // stream time should be appearing now
  193. function StreamTime(out rtStream: TReferenceTime): HRESULT; virtual;
  194. // Is the filter currently active?
  195. function IsActive: boolean;
  196. // Is this filter stopped (without locking)
  197. function IsStopped: boolean;
  198. // --- IBaseFilter methods ---
  199. // pin enumerator
  200. function EnumPins(out ppEnum: IEnumPins): HRESULT; stdcall;
  201. // default behaviour of FindPin assumes pin ids are their names
  202. function FindPin(Id: PWideChar; out Pin: IPin): HRESULT; virtual; stdcall;
  203. function QueryFilterInfo(out pInfo: TFilterInfo): HRESULT; stdcall;
  204. // milenko start (added virtual to be able to override it in the renderers)
  205. function JoinFilterGraph(pGraph: IFilterGraph; pName: PWideChar): HRESULT; virtual; stdcall;
  206. // milenko end
  207. // return a Vendor information string. Optional - may return E_NOTIMPL.
  208. // memory returned should be freed using CoTaskMemFree
  209. // default implementation returns E_NOTIMPL
  210. function QueryVendorInfo(out pVendorInfo: PWideChar): HRESULT; stdcall;
  211. // --- helper methods ---
  212. // send an event notification to the filter graph if we know about it.
  213. // returns S_OK if delivered, S_FALSE if the filter graph does not sink
  214. // events, or an error otherwise.
  215. function NotifyEvent(EventCode, EventParam1, EventParam2: LongInt): HRESULT;
  216. // return the filter graph we belong to
  217. function GetFilterGraph: IFilterGraph;
  218. // Request reconnect
  219. // pPin is the pin to reconnect
  220. // pmt is the type to reconnect with - can be NULL
  221. // Calls ReconnectEx on the filter graph
  222. function ReconnectPin(Pin: IPin; pmt: PAMMediaType): HRESULT;
  223. // find out the current pin version (used by enumerators)
  224. function GetPinVersion: LongInt; virtual;
  225. procedure IncrementPinVersion;
  226. // you need to supply these to access the pins from the enumerator
  227. // and for default Stop and Pause/Run activation.
  228. function GetPinCount: integer; virtual; abstract;
  229. function GetPin(n: Integer): TBCBasePin; virtual; abstract;
  230. // --- IAMovieSetup methods ---
  231. {nev: start 04/16/04 added "virtual"}
  232. function Register: HRESULT; virtual; stdcall;
  233. function Unregister: HRESULT; virtual; stdcall;
  234. {nev: end}
  235. property State: TFilterState read FState;
  236. property GRaph : IFilterGraph read FGRaph;
  237. end;
  238. { NOTE The implementation of this class calls the CUnknown constructor with
  239. a NULL outer unknown pointer. This has the effect of making us a self
  240. contained class, ie any QueryInterface, AddRef or Release calls will be
  241. routed to the class's NonDelegatingUnknown methods. You will typically
  242. find that the classes that do this then override one or more of these
  243. virtual functions to provide more specialised behaviour. A good example
  244. of this is where a class wants to keep the QueryInterface internal but
  245. still wants its lifetime controlled by the external object }
  246. TBCBasePin = class(TBCUnknown, IPin, IQualityControl)
  247. protected
  248. FPinName: WideString;
  249. FConnected : IPin; // Pin we have connected to
  250. Fdir : TPinDirection; // Direction of this pin
  251. FLock : TBCCritSec; // Object we use for locking
  252. FRunTimeError : boolean; // Run time error generated
  253. FCanReconnectWhenActive: boolean; // OK to reconnect when active
  254. FTryMyTypesFirst : boolean; // When connecting enumerate
  255. // this pin's types first
  256. FFilter : TBCBaseFilter; // Filter we were created by
  257. FQSink : IQualityControl; // Target for Quality messages
  258. FTypeVersion : LongInt; // Holds current type version
  259. Fmt : TAMMediaType; // Media type of connection
  260. FStart : TReferenceTime; // time from NewSegment call
  261. FStop : TReferenceTime; // time from NewSegment
  262. FRate : double; // rate from NewSegment
  263. FRef : LongInt;
  264. function GetCurrentMediaType: TBCMediaType;
  265. function GetAMMediaType: PAMMediaType;
  266. protected
  267. procedure DisplayPinInfo(ReceivePin: IPin);
  268. procedure DisplayTypeInfo(Pin: IPin; pmt: PAMMediaType);
  269. // used to agree a media type for a pin connection
  270. // given a specific media type, attempt a connection (includes
  271. // checking that the type is acceptable to this pin)
  272. function AttemptConnection(
  273. ReceivePin: IPin; // connect to this pin
  274. pmt : PAMMediaType // using this type
  275. ): HRESULT;
  276. // try all the media types in this enumerator - for each that
  277. // we accept, try to connect using ReceiveConnection.
  278. function TryMediaTypes(
  279. ReceivePin: IPin; // connect to this pin
  280. pmt : PAMMediaType; // proposed type from Connect
  281. Enum : IEnumMediaTypes // try this enumerator
  282. ): HRESULT;
  283. // establish a connection with a suitable mediatype. Needs to
  284. // propose a media type if the pmt pointer is null or partially
  285. // specified - use TryMediaTypes on both our and then the other pin's
  286. // enumerator until we find one that works.
  287. function AgreeMediaType(
  288. ReceivePin: IPin; // connect to this pin
  289. pmt : PAMMediaType // proposed type from Connect
  290. ): HRESULT;
  291. function DisconnectInternal: HRESULT; stdcall;
  292. public
  293. function NonDelegatingAddRef: Integer; override; stdcall;
  294. function NonDelegatingRelease: Integer; override; stdcall;
  295. constructor Create(
  296. ObjectName: string; // Object description
  297. Filter : TBCBaseFilter; // Owning filter who knows about pins
  298. Lock : TBCCritSec; // Object who implements the lock
  299. out hr : HRESULT; // General OLE return code
  300. Name : WideString; // Pin name for us
  301. dir : TPinDirection); // Either PINDIR_INPUT or PINDIR_OUTPUT
  302. destructor destroy; override;
  303. // --- IPin methods ---
  304. // take lead role in establishing a connection. Media type pointer
  305. // may be null, or may point to partially-specified mediatype
  306. // (subtype or format type may be GUID_NULL).
  307. function Connect(pReceivePin: IPin; const pmt: PAMMediaType): HRESULT; virtual; stdcall;
  308. // (passive) accept a connection from another pin
  309. function ReceiveConnection(pConnector: IPin; const pmt: TAMMediaType): HRESULT; virtual; stdcall;
  310. function Disconnect: HRESULT; virtual; stdcall;
  311. function ConnectedTo(out pPin: IPin): HRESULT; virtual; stdcall;
  312. function ConnectionMediaType(out pmt: TAMMediaType): HRESULT; virtual; stdcall;
  313. function QueryPinInfo(out pInfo: TPinInfo): HRESULT; virtual; stdcall;
  314. function QueryDirection(out pPinDir: TPinDirection): HRESULT; stdcall;
  315. function QueryId(out Id: PWideChar): HRESULT; virtual; stdcall;
  316. // does the pin support this media type
  317. function QueryAccept(const pmt: TAMMediaType): HRESULT; virtual; stdcall;
  318. // return an enumerator for this pins preferred media types
  319. function EnumMediaTypes(out ppEnum: IEnumMediaTypes): HRESULT; virtual; stdcall;
  320. // return an array of IPin* - the pins that this pin internally connects to
  321. // All pins put in the array must be AddReffed (but no others)
  322. // Errors: "Can't say" - FAIL, not enough slots - return S_FALSE
  323. // Default: return E_NOTIMPL
  324. // The filter graph will interpret NOT_IMPL as any input pin connects to
  325. // all visible output pins and vice versa.
  326. // apPin can be NULL if nPin==0 (not otherwise).
  327. function QueryInternalConnections(out apPin: IPin; var nPin: ULONG): HRESULT; virtual; stdcall;
  328. // Called when no more data will be sent
  329. function EndOfStream: HRESULT; virtual; stdcall;
  330. function BeginFlush: HRESULT; virtual; stdcall; abstract;
  331. function EndFlush: HRESULT; virtual; stdcall; abstract;
  332. // Begin/EndFlush still PURE
  333. // NewSegment notifies of the start/stop/rate applying to the data
  334. // about to be received. Default implementation records data and
  335. // returns S_OK.
  336. // Override this to pass downstream.
  337. function NewSegment(tStart, tStop: TReferenceTime; dRate: double): HRESULT; virtual; stdcall;
  338. // --- IQualityControl methods ---
  339. function Notify(pSelf: IBaseFilter; q: TQuality): HRESULT; virtual; stdcall;
  340. function SetSink(piqc: IQualityControl): HRESULT; virtual; stdcall;
  341. // --- helper methods ---
  342. // Returns True if the pin is connected. false otherwise.
  343. function IsConnected: boolean;
  344. // Return the pin this is connected to (if any)
  345. property GetConnected: IPin read FConnected;
  346. // Check if our filter is currently stopped
  347. function IsStopped: boolean;
  348. // find out the current type version (used by enumerators)
  349. function GetMediaTypeVersion: longint; virtual;
  350. procedure IncrementTypeVersion;
  351. // switch the pin to active (paused or running) mode
  352. // not an error to call this if already active
  353. function Active: HRESULT; virtual;
  354. // switch the pin to inactive state - may already be inactive
  355. function Inactive: HRESULT; virtual;
  356. // Notify of Run() from filter
  357. function Run(Start: TReferenceTime): HRESULT; virtual;
  358. // check if the pin can support this specific proposed type and format
  359. function CheckMediaType(mt: PAMMediaType): HRESULT; virtual; abstract;
  360. // set the connection to use this format (previously agreed)
  361. function SetMediaType(mt: PAMMediaType): HRESULT; virtual;
  362. // check that the connection is ok before verifying it
  363. // can be overridden eg to check what interfaces will be supported.
  364. function CheckConnect(Pin: IPin): HRESULT; virtual;
  365. // Set and release resources required for a connection
  366. function BreakConnect: HRESULT; virtual;
  367. function CompleteConnect(ReceivePin: IPin): HRESULT; virtual;
  368. // returns the preferred formats for a pin
  369. function GetMediaType(Position: integer; out MediaType: PAMMediaType): HRESULT; virtual;
  370. // access to NewSegment values
  371. property CurrentStopTime: TReferenceTime read FStop;
  372. property CurrentStartTime: TReferenceTime read FStart;
  373. property CurrentRate: double read FRate;
  374. // Access name
  375. property Name: WideString read FPinName;
  376. property CanReconnectWhenActive: boolean read FCanReconnectWhenActive write FCanReconnectWhenActive;
  377. // Media type
  378. property CurrentMediaType: TBCMediaType read GetCurrentMediaType;
  379. property AMMediaType: PAMMediaType read GetAMMediaType;
  380. end;
  381. TBCEnumPins = class(TInterfacedObject, IEnumPins)
  382. private
  383. FPosition: integer; // Current ordinal position
  384. FPinCount: integer; // Number of pins available
  385. FFilter: TBCBaseFilter; // The filter who owns us
  386. FVersion: LongInt; // Pin version information
  387. // These pointers have not been AddRef'ed and
  388. // so they should not be dereferenced. They are
  389. // merely kept to ID which pins have been enumerated.
  390. FPinCache: TList;
  391. { If while we are retrieving a pin for example from the filter an error
  392. occurs we assume that our internal state is stale with respect to the
  393. filter (someone may have deleted all the pins). We can check before
  394. starting whether or not the operation is likely to fail by asking the
  395. filter what it's current version number is. If the filter has not
  396. overriden the GetPinVersion method then this will always match }
  397. function AreWeOutOfSync: boolean;
  398. (* This method performs the same operations as Reset, except is does not clear
  399. the cache of pins already enumerated. *)
  400. function Refresh: HRESULT; stdcall;
  401. public
  402. constructor Create(Filter: TBCBaseFilter; EnumPins: TBCEnumPins);
  403. destructor Destroy; override;
  404. function Next(cPins: ULONG; // place this many pins...
  405. out ppPins: IPin; // ...in this array of IPin*
  406. pcFetched: PULONG // actual count passed returned here
  407. ): HRESULT; stdcall;
  408. function Skip(cPins: ULONG): HRESULT; stdcall;
  409. function Reset: HRESULT; stdcall;
  410. function Clone(out ppEnum: IEnumPins): HRESULT; stdcall;
  411. end;
  412. TBCEnumMediaTypes = class(TInterfacedObject, IEnumMediaTypes)
  413. private
  414. FPosition: Cardinal; // Current ordinal position
  415. FPin : TBCBasePin; // The pin who owns us
  416. FVersion : LongInt; // Media type version value
  417. function AreWeOutOfSync: boolean;
  418. public
  419. constructor Create(Pin: TBCBasePin; EnumMediaTypes: TBCEnumMediaTypes);
  420. destructor Destroy; override;
  421. function Next(cMediaTypes: ULONG; out ppMediaTypes: PAMMediaType;
  422. pcFetched: PULONG): HRESULT; stdcall;
  423. function Skip(cMediaTypes: ULONG): HRESULT; stdcall;
  424. function Reset: HRESULT; stdcall;
  425. function Clone(out ppEnum: IEnumMediaTypes): HRESULT; stdcall;
  426. end;
  427. TBCBaseOutputPin = class(TBCBasePin)
  428. protected
  429. FAllocator: IMemAllocator;
  430. // interface on the downstreaminput pin, set up in CheckConnect when we connect.
  431. FInputPin : IMemInputPin;
  432. public
  433. constructor Create(ObjectName: string; Filter: TBCBaseFilter; Lock: TBCCritSec;
  434. out hr: HRESULT; const Name: WideString);
  435. // override CompleteConnect() so we can negotiate an allocator
  436. function CompleteConnect(ReceivePin: IPin): HRESULT; override;
  437. // negotiate the allocator and its buffer size/count and other properties
  438. // Calls DecideBufferSize to set properties
  439. function DecideAllocator(Pin: IMemInputPin; out Alloc: IMemAllocator): HRESULT; virtual;
  440. // override this to set the buffer size and count. Return an error
  441. // if the size/count is not to your liking.
  442. // The allocator properties passed in are those requested by the
  443. // input pin - use eg the alignment and prefix members if you have
  444. // no preference on these.
  445. function DecideBufferSize(Alloc: IMemAllocator; propInputRequest: PAllocatorProperties): HRESULT; virtual;
  446. // returns an empty sample buffer from the allocator
  447. function GetDeliveryBuffer(out Sample: IMediaSample; StartTime: PReferenceTime;
  448. EndTime: PReferenceTime; Flags: Longword): HRESULT; virtual;
  449. // deliver a filled-in sample to the connected input pin
  450. // note - you need to release it after calling this. The receiving
  451. // pin will addref the sample if it needs to hold it beyond the
  452. // call.
  453. function Deliver(Sample: IMediaSample): HRESULT; virtual;
  454. // override this to control the connection
  455. function InitAllocator(out Alloc: IMemAllocator): HRESULT; virtual;
  456. function CheckConnect(Pin: IPin): HRESULT; override;
  457. function BreakConnect: HRESULT; override;
  458. // override to call Commit and Decommit
  459. function Active: HRESULT; override;
  460. function Inactive: HRESULT; override;
  461. // we have a default handling of EndOfStream which is to return
  462. // an error, since this should be called on input pins only
  463. function EndOfStream: HRESULT; override; stdcall;
  464. // called from elsewhere in our filter to pass EOS downstream to
  465. // our connected input pin
  466. function DeliverEndOfStream: HRESULT; virtual;
  467. // same for Begin/EndFlush - we handle Begin/EndFlush since it
  468. // is an error on an output pin, and we have Deliver methods to
  469. // call the methods on the connected pin
  470. function BeginFlush: HRESULT; override; stdcall;
  471. function EndFlush: HRESULT; override; stdcall;
  472. function DeliverBeginFlush: HRESULT; virtual;
  473. function DeliverEndFlush: HRESULT; virtual;
  474. // deliver NewSegment to connected pin - you will need to
  475. // override this if you queue any data in your output pin.
  476. function DeliverNewSegment(Start, Stop: TReferenceTime; Rate: double): HRESULT; virtual;
  477. end;
  478. TBCBaseInputPin = class(TBCBasePin, IMemInputPin)
  479. protected
  480. FAllocator: IMemAllocator; // Default memory allocator
  481. // allocator is read-only, so received samples
  482. // cannot be modified (probably only relevant to in-place
  483. // transforms
  484. FReadOnly: boolean;
  485. //private: this should really be private... only the MPEG code
  486. // currently looks at it directly and it should use IsFlushing().
  487. // in flushing state (between BeginFlush and EndFlush)
  488. // if True, all Receives are returned with S_FALSE
  489. FFlushing: boolean;
  490. // Sample properties - initalized in Receive
  491. FSampleProps: TAMSample2Properties;
  492. public
  493. constructor Create(ObjectName: string; Filter: TBCBaseFilter;
  494. Lock: TBCCritSec; out hr: HRESULT; Name: WideString);
  495. destructor Destroy; override;
  496. // ----------IMemInputPin--------------
  497. // return the allocator interface that this input pin
  498. // would like the output pin to use
  499. function GetAllocator(out ppAllocator: IMemAllocator): HRESULT; stdcall;
  500. // tell the input pin which allocator the output pin is actually
  501. // going to use.
  502. function NotifyAllocator(pAllocator: IMemAllocator; bReadOnly: BOOL): HRESULT; stdcall;
  503. // this method is optional (can return E_NOTIMPL).
  504. // default implementation returns E_NOTIMPL. Override if you have
  505. // specific alignment or prefix needs, but could use an upstream
  506. // allocator
  507. function GetAllocatorRequirements(out pProps: TAllocatorProperties): HRESULT; stdcall;
  508. // do something with this media sample
  509. function Receive(pSample: IMediaSample): HRESULT; virtual; stdcall;
  510. // do something with these media samples
  511. function ReceiveMultiple(var pSamples: IMediaSample; nSamples: Longint;
  512. out nSamplesProcessed: Longint): HRESULT; stdcall;
  513. // See if Receive() blocks
  514. function ReceiveCanBlock: HRESULT; stdcall;
  515. //-----------Helper-------------
  516. // Default handling for BeginFlush - call at the beginning
  517. // of your implementation (makes sure that all Receive calls
  518. // fail). After calling this, you need to free any queued data
  519. // and then call downstream.
  520. function BeginFlush: HRESULT; override; stdcall;
  521. // default handling for EndFlush - call at end of your implementation
  522. // - before calling this, ensure that there is no queued data and no thread
  523. // pushing any more without a further receive, then call downstream,
  524. // then call this method to clear the m_bFlushing flag and re-enable
  525. // receives
  526. function EndFlush: HRESULT; override; stdcall;
  527. // Release the pin's allocator.
  528. function BreakConnect: HRESULT; override;
  529. // helper method to check the read-only flag
  530. property IsReadOnly: boolean read FReadOnly;
  531. // helper method to see if we are flushing
  532. property IsFlushing: boolean read FFlushing;
  533. // Override this for checking whether it's OK to process samples
  534. // Also call this from EndOfStream.
  535. function CheckStreaming: HRESULT; virtual;
  536. // Pass a Quality notification on to the appropriate sink
  537. function PassNotify(const q: TQuality): HRESULT;
  538. //================================================================================
  539. // IQualityControl methods (from CBasePin)
  540. //================================================================================
  541. function Notify(pSelf: IBaseFilter; q: TQuality): HRESULT; override; stdcall;
  542. // no need to override:
  543. // STDMETHODIMP SetSink(IQualityControl * piqc);
  544. // switch the pin to inactive state - may already be inactive
  545. function Inactive: HRESULT; override;
  546. // Return sample properties pointer
  547. function SampleProps: PAMSample2Properties;
  548. end;
  549. // milenko start (added TBCDynamicOutputPin conversion)
  550. TBLOCK_STATE = (NOT_BLOCKED, PENDING, BLOCKED);
  551. TBCDynamicOutputPin = class(TBCBaseOutputPin, IPinFlowControl)
  552. public
  553. constructor Create(ObjectName: WideString; Filter: TBCBaseFilter;
  554. Lock: TBCCritSec; out hr: HRESULT; Name: WideString);
  555. destructor Destroy; override;
  556. // IUnknown Methods
  557. function NonDelegatingQueryInterface(const IID: TGUID; out Obj): HResult; override;
  558. // IPin Methods
  559. function Disconnect: HRESULT; override; stdcall;
  560. // IPinFlowControl Methods
  561. function Block(dwBlockFlags: DWORD; hEvent: THandle): HResult; stdcall;
  562. // Set graph config info
  563. procedure SetConfigInfo(GraphConfig: IGraphConfig; StopEvent: THandle);
  564. {$IFDEF DEBUG}
  565. function Deliver(Sample: IMediaSample): HRESULT; override;
  566. function DeliverEndOfStream: HRESULT; override;
  567. function DeliverNewSegment(Start, Stop: TReferenceTime; Rate: double): HRESULT; override;
  568. {$ENDIF} // DEBUG
  569. function DeliverBeginFlush: HRESULT; override;
  570. function DeliverEndFlush: HRESULT; override;
  571. function Active: HRESULT; override;
  572. function Inactive: HRESULT; override;
  573. function CompleteConnect(ReceivePin: IPin): HRESULT; override;
  574. function StartUsingOutputPin: HRESULT; virtual;
  575. procedure StopUsingOutputPin; virtual;
  576. function StreamingThreadUsingOutputPin: Boolean; virtual;
  577. function ChangeOutputFormat(const pmt: PAMMediaType; tSegmentStart, tSegmentStop:
  578. TreferenceTime; dSegmentRate: Double): HRESULT;
  579. function ChangeMediaType(const pmt: PAMMEdiaType): HRESULT;
  580. function DynamicReconnect(const pmt: PAMMediaType): HRESULT;
  581. protected
  582. // This lock should be held when the following class members are
  583. // being used: m_hNotifyCallerPinBlockedEvent, m_BlockState,
  584. // m_dwBlockCallerThreadID and m_dwNumOutstandingOutputPinUsers.
  585. FBlockStateLock: TBCCritSec;
  586. // This event should be signaled when the output pin is
  587. // not blocked. This is a manual reset event. For more
  588. // information on events, see the documentation for
  589. // CreateEvent() in the Windows SDK.
  590. FUnblockOutputPinEvent: THandle;
  591. // This event will be signaled when block operation succeedes or
  592. // when the user cancels the block operation. The block operation
  593. // can be canceled by calling IPinFlowControl2::Block( 0, NULL )
  594. // while the block operation is pending.
  595. FNotifyCallerPinBlockedEvent: THandle;
  596. // The state of the current block operation.
  597. FBlockState: TBLOCK_STATE;
  598. // The ID of the thread which last called IPinFlowControl::Block().
  599. // For more information on thread IDs, see the documentation for
  600. // GetCurrentThreadID() in the Windows SDK.
  601. FBlockCallerThreadID: DWORD;
  602. // The number of times StartUsingOutputPin() has been sucessfully
  603. // called and a corresponding call to StopUsingOutputPin() has not
  604. // been made. When this variable is greater than 0, the streaming
  605. // thread is calling IPin::NewSegment(), IPin::EndOfStream(),
  606. // IMemInputPin::Receive() or IMemInputPin::ReceiveMultiple(). The
  607. // streaming thread could also be calling: DynamicReconnect(),
  608. // ChangeMediaType() or ChangeOutputFormat(). The output pin cannot
  609. // be blocked while the output pin is being used.
  610. FNumOutstandingOutputPinUsers: DWORD;
  611. // This event should be set when the IMediaFilter::Stop() is called.
  612. // This is a manual reset event. It is also set when the output pin
  613. // delivers a flush to the connected input pin.
  614. FStopEvent: THandle;
  615. FGraphConfig: IGraphConfig;
  616. // TRUE if the output pin's allocator's samples are read only.
  617. // Otherwise FALSE. For more information, see the documentation
  618. // for IMemInputPin::NotifyAllocator().
  619. FPinUsesReadOnlyAllocator: Boolean;
  620. function SynchronousBlockOutputPin: HRESULT;
  621. function AsynchronousBlockOutputPin(NotifyCallerPinBlockedEvent: THandle): HRESULT;
  622. function UnblockOutputPin: HRESULT;
  623. procedure BlockOutputPin;
  624. procedure ResetBlockState;
  625. class function WaitEvent(Event: THandle): HRESULT;
  626. private
  627. function Initialize: HRESULT;
  628. function ChangeMediaTypeHelper(const pmt: PAMMediaType): HRESULT;
  629. {$IFDEF DEBUG}
  630. procedure AssertValid;
  631. {$ENDIF} // DEBUG
  632. end;
  633. // milenko end
  634. TBCTransformOutputPin = class;
  635. TBCTransformInputPin = class;
  636. TBCTransformFilter = class(TBCBaseFilter)
  637. protected
  638. FEOSDelivered : boolean; // have we sent EndOfStream
  639. FSampleSkipped : boolean; // Did we just skip a frame
  640. FQualityChanged: boolean; // Have we degraded?
  641. // critical section protecting filter state.
  642. FcsFilter: TBCCritSec;
  643. // critical section stopping state changes (ie Stop) while we're
  644. // processing a sample.
  645. //
  646. // This critical section is held when processing
  647. // events that occur on the receive thread - Receive() and EndOfStream().
  648. //
  649. // If you want to hold both m_csReceive and m_csFilter then grab
  650. // m_csFilter FIRST - like CTransformFilter::Stop() does.
  651. FcsReceive: TBCCritSec;
  652. // these hold our input and output pins
  653. FInput : TBCTransformInputPin;
  654. FOutput: TBCTransformOutputPin;
  655. public
  656. // map getpin/getpincount for base enum of pins to owner
  657. // override this to return more specialised pin objects
  658. function GetPinCount: integer; override;
  659. function GetPin(n: integer): TBCBasePin; override;
  660. function FindPin(Id: PWideChar; out ppPin: IPin): HRESULT; override; stdcall;
  661. // override state changes to allow derived transform filter
  662. // to control streaming start/stop
  663. function Stop: HRESULT; override; stdcall;
  664. function Pause: HRESULT; override; stdcall;
  665. constructor Create(ObjectName: string; unk: IUnKnown; const clsid: TGUID);
  666. constructor CreateFromFactory(Factory: TBCClassFactory; const Controller: IUnknown); override;
  667. destructor destroy; override;
  668. // =================================================================
  669. // ----- override these bits ---------------------------------------
  670. // =================================================================
  671. // These must be supplied in a derived class
  672. function Transform(msIn, msout: IMediaSample): HRESULT; virtual;
  673. // check if you can support mtIn
  674. function CheckInputType(mtIn: PAMMediaType): HRESULT; virtual; abstract;
  675. // check if you can support the transform from this input to this output
  676. function CheckTransform(mtIn, mtOut: PAMMediaType): HRESULT; virtual; abstract;
  677. // this goes in the factory template table to create new instances
  678. // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *);
  679. // call the SetProperties function with appropriate arguments
  680. function DecideBufferSize(Allocator: IMemAllocator; prop: PAllocatorProperties): HRESULT; virtual; abstract;
  681. // override to suggest OUTPUT pin media types
  682. function GetMediaType(Position: integer; out MediaType: PAMMediaType): HRESULT; virtual; abstract;
  683. // =================================================================
  684. // ----- Optional Override Methods -----------------------
  685. // =================================================================
  686. // you can also override these if you want to know about streaming
  687. function StartStreaming: HRESULT; virtual;
  688. function StopStreaming: HRESULT; virtual;
  689. // override if you can do anything constructive with quality notifications
  690. function AlterQuality(const q: TQuality): HRESULT; virtual;
  691. // override this to know when the media type is actually set
  692. function SetMediaType(direction: TPinDirection; pmt: PAMMediaType): HRESULT; virtual;
  693. // chance to grab extra interfaces on connection
  694. function CheckConnect(dir: TPinDirection; Pin: IPin): HRESULT; virtual;
  695. function BreakConnect(dir: TPinDirection): HRESULT; virtual;
  696. function CompleteConnect(direction: TPinDirection; ReceivePin: IPin): HRESULT; virtual;
  697. // chance to customize the transform process
  698. function Receive(Sample: IMediaSample): HRESULT; virtual;
  699. // Standard setup for output sample
  700. function InitializeOutputSample(Sample: IMediaSample; out OutSample: IMediaSample): HRESULT; virtual;
  701. // if you override Receive, you may need to override these three too
  702. function EndOfStream: HRESULT; virtual;
  703. function BeginFlush: HRESULT; virtual;
  704. function EndFlush: HRESULT; virtual;
  705. function NewSegment(Start, Stop: TReferenceTime; Rate: double): HRESULT; virtual;
  706. property Input: TBCTransformInputPin read FInput write FInput;
  707. property Output: TBCTransformOutputPin read FOutPut write FOutput;
  708. end;
  709. TBCTransformInputPin = class(TBCBaseInputPin)
  710. private
  711. FTransformFilter: TBCTransformFilter;
  712. public
  713. constructor Create(ObjectName: string; TransformFilter: TBCTransformFilter;
  714. out hr: HRESULT; Name: WideString);
  715. destructor destroy; override;
  716. function QueryId(out id: PWideChar): HRESULT; override; stdcall;
  717. // Grab and release extra interfaces if required
  718. function CheckConnect(Pin: IPin): HRESULT; override;
  719. function BreakConnect: HRESULT; override;
  720. function CompleteConnect(ReceivePin: IPin): HRESULT; override;
  721. // check that we can support this output type
  722. function CheckMediaType(mtIn: PAMMediaType): HRESULT; override;
  723. // set the connection media type
  724. function SetMediaType(mt: PAMMediaType): HRESULT; override;
  725. // --- IMemInputPin -----
  726. // here's the next block of data from the stream.
  727. // AddRef it yourself if you need to hold it beyond the end
  728. // of this call.
  729. function Receive(pSample: IMediaSample): HRESULT; override; stdcall;
  730. // provide EndOfStream that passes straight downstream
  731. // (there is no queued data)
  732. function EndOfStream: HRESULT; override; stdcall;
  733. // passes it to CTransformFilter::BeginFlush
  734. function BeginFlush: HRESULT; override; stdcall;
  735. // passes it to CTransformFilter::EndFlush
  736. function EndFlush: HRESULT; override; stdcall;
  737. function NewSegment(Start, Stop: TReferenceTime; Rate: double): HRESULT; override; stdcall;
  738. // Check if it's OK to process samples
  739. function CheckStreaming: HRESULT; override;
  740. end;
  741. TBCTransformOutputPin = class(TBCBaseOutputPin)
  742. protected
  743. FTransformFilter: TBCTransformFilter;
  744. // implement IMediaPosition by passing upstream
  745. FPosition: IUnknown;
  746. public
  747. constructor Create(ObjectName: string; TransformFilter: TBCTransformFilter;
  748. out hr: HRESULT; Name: WideString);
  749. destructor destroy; override;
  750. // override to expose IMediaPosition
  751. function NonDelegatingQueryInterface(const IID: TGUID; out Obj): HResult; override;
  752. // --- TBCBaseOutputPin ------------
  753. function QueryId(out Id: PWideChar): HRESULT; override; stdcall;
  754. // Grab and release extra interfaces if required
  755. function CheckConnect(Pin: IPin): HRESULT; override;
  756. function BreakConnect: HRESULT; override;
  757. function CompleteConnect(ReceivePin: IPin): HRESULT; override;
  758. // check that we can support this output type
  759. function CheckMediaType(mtOut: PAMMediaType): HRESULT; override;
  760. // set the connection media type
  761. function SetMediaType(pmt: PAMMediaType): HRESULT; override;
  762. // called from CBaseOutputPin during connection to ask for
  763. // the count and size of buffers we need.
  764. function DecideBufferSize(Alloc: IMemAllocator; Prop: PAllocatorProperties): HRESULT; override;
  765. // returns the preferred formats for a pin
  766. function GetMediaType(Position: integer; out MediaType: PAMMediaType): HRESULT; override;
  767. // inherited from IQualityControl via CBasePin
  768. function Notify(Sendr: IBaseFilter; q: TQuality): HRESULT; override; stdcall;
  769. end;
  770. // milenko start (added TBCVideoTransformFilter conversion)
  771. TBCVideoTransformFilter = class(TBCTransformFilter)
  772. public
  773. constructor Create(Name: WideString; Unk: IUnknown; clsid: TGUID);
  774. destructor Destroy; override;
  775. function EndFlush: HRESULT; override;
  776. // =================================================================
  777. // ----- override these bits ---------------------------------------
  778. // =================================================================
  779. // The following methods are in CTransformFilter which is inherited.
  780. // They are mentioned here for completeness
  781. //
  782. // These MUST be supplied in a derived class
  783. //
  784. // NOTE:
  785. // virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut);
  786. // virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE;
  787. // virtual HRESULT CheckTransform
  788. // (const CMediaType* mtIn, const CMediaType* mtOut) PURE;
  789. // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *);
  790. // virtual HRESULT DecideBufferSize
  791. // (IMemAllocator * pAllocator, ALLOCATOR_PROPERTIES *pprop) PURE;
  792. // virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE;
  793. //
  794. // These MAY also be overridden
  795. //
  796. // virtual HRESULT StopStreaming();
  797. // virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt);
  798. // virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin);
  799. // virtual HRESULT BreakConnect(PIN_DIRECTION dir);
  800. // virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin);
  801. // virtual HRESULT EndOfStream(void);
  802. // virtual HRESULT BeginFlush(void);
  803. // virtual HRESULT EndFlush(void);
  804. // virtual HRESULT NewSegment
  805. // (REFERENCE_TIME tStart,REFERENCE_TIME tStop,double dRate);
  806. {$IFDEF PERF}
  807. // If you override this - ensure that you register all these ids
  808. // as well as any of your own,
  809. procedure RegisterPerfId; virtual;
  810. {$ENDIF}
  811. protected
  812. // =========== QUALITY MANAGEMENT IMPLEMENTATION ========================
  813. // Frames are assumed to come in three types:
  814. // Type 1: an AVI key frame or an MPEG I frame.
  815. // This frame can be decoded with no history.
  816. // Dropping this frame means that no further frame can be decoded
  817. // until the next type 1 frame.
  818. // Type 1 frames are sync points.
  819. // Type 2: an AVI non-key frame or an MPEG P frame.
  820. // This frame cannot be decoded unless the previous type 1 frame was
  821. // decoded and all type 2 frames since have been decoded.
  822. // Dropping this frame means that no further frame can be decoded
  823. // until the next type 1 frame.
  824. // Type 3: An MPEG B frame.
  825. // This frame cannot be decoded unless the previous type 1 or 2 frame
  826. // has been decoded AND the subsequent type 1 or 2 frame has also
  827. // been decoded. (This requires decoding the frames out of sequence).
  828. // Dropping this frame affects no other frames. This implementation
  829. // does not allow for these. All non-sync-point frames are treated
  830. // as being type 2.
  831. //
  832. // The spacing of frames of type 1 in a file is not guaranteed. There MUST
  833. // be a type 1 frame at (well, near) the start of the file in order to start
  834. // decoding at all. After that there could be one every half second or so,
  835. // there could be one at the start of each scene (aka "cut", "shot") or
  836. // there could be no more at all.
  837. // If there is only a single type 1 frame then NO FRAMES CAN BE DROPPED
  838. // without losing all the rest of the movie. There is no way to tell whether
  839. // this is the case, so we find that we are in the gambling business.
  840. // To try to improve the odds, we record the greatest interval between type 1s
  841. // that we have seen and we bet on things being no worse than this in the
  842. // future.
  843. // You can tell if it's a type 1 frame by calling IsSyncPoint().
  844. // there is no architected way to test for a type 3, so you should override
  845. // the quality management here if you have B-frames.
  846. FKeyFramePeriod: integer; // the largest observed interval between type 1 frames
  847. // 1 means every frame is type 1, 2 means every other.
  848. FFramesSinceKeyFrame: integer; // Used to count frames since the last type 1.
  849. // becomes the new m_nKeyFramePeriod if greater.
  850. FSkipping: Boolean; // we are skipping to the next type 1 frame
  851. {$IFDEF PERF}
  852. FidFrameType: integer; // MSR id Frame type. 1=Key, 2="non-key"
  853. FidSkip: integer; // MSR id skipping
  854. FidLate: integer; // MSR id lateness
  855. FidTimeTillKey: integer; // MSR id for guessed time till next key frame.
  856. {$ENDIF}
  857. FitrLate: integer; // lateness from last Quality message
  858. // (this overflows at 214 secs late).
  859. FtDecodeStart: integer; // timeGetTime when decode started.
  860. FitrAvgDecode: integer; // Average decode time in reference units.
  861. FNoSkip: Boolean; // debug - no skipping.
  862. // We send an EC_QUALITY_CHANGE notification to the app if we have to degrade.
  863. // We send one when we start degrading, not one for every frame, this means
  864. // we track whether we've sent one yet.
  865. FQualityChanged: Boolean;
  866. // When non-zero, don't pass anything to renderer until next keyframe
  867. // If there are few keys, give up and eventually draw something
  868. FWaitForKey: integer;
  869. function AbortPlayback(hr: HRESULT): HRESULT; // if something bad happens
  870. function ShouldSkipFrame(pIn: IMediaSample): Boolean;
  871. public
  872. function StartStreaming: HRESULT; override;
  873. function Receive(Sample: IMediaSample): HRESULT; override;
  874. function AlterQuality(const q: TQuality): HRESULT; override;
  875. end;
  876. // milenko end
  877. TBCTransInPlaceOutputPin = class;
  878. TBCTransInPlaceInputPin = class;
  879. TBCTransInPlaceFilter = class(TBCTransformFilter)
  880. public
  881. // map getpin/getpincount for base enum of pins to owner
  882. // override this to return more specialised pin objects
  883. function GetPin(n: integer): TBCBasePin; override;
  884. // Set bModifiesData == false if your derived filter does
  885. // not modify the data samples (for instance it's just copying
  886. // them somewhere else or looking at the timestamps).
  887. constructor Create(ObjectName: string; unk: IUnKnown; clsid: TGUID;
  888. out hr: HRESULT; ModifiesData: boolean = True);
  889. constructor CreateFromFactory(Factory: TBCClassFactory; const Controller: IUnknown); override;
  890. // The following are defined to avoid undefined pure virtuals.
  891. // Even if they are never called, they will give linkage warnings/errors
  892. // We override EnumMediaTypes to bypass the transform class enumerator
  893. // which would otherwise call this.
  894. function GetMediaType(Position: integer; out MediaType: PAMMediaType): HRESULT; override;
  895. // This is called when we actually have to provide out own allocator.
  896. function DecideBufferSize(Alloc: IMemAllocator; propInputRequest: PAllocatorProperties): HRESULT; override;
  897. // The functions which call this in CTransform are overridden in this
  898. // class to call CheckInputType with the assumption that the type
  899. // does not change. In Debug builds some calls will be made and
  900. // we just ensure that they do not assert.
  901. function CheckTransform(mtIn, mtOut: PAMMediaType): HRESULT; override;
  902. // =================================================================
  903. // ----- You may want to override this -----------------------------
  904. // =================================================================
  905. function CompleteConnect(dir: TPinDirection; ReceivePin: IPin): HRESULT; override;
  906. // chance to customize the transform process
  907. function Receive(Sample: IMediaSample): HRESULT; override;
  908. // =================================================================
  909. // ----- You MUST override these -----------------------------------
  910. // =================================================================
  911. function Transform(Sample: IMediaSample): HRESULT; reintroduce; virtual; abstract;
  912. // this goes in the factory template table to create new instances
  913. // static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *);
  914. protected
  915. FModifiesData: boolean; // Does this filter change the data?
  916. function Copy(Source: IMediaSample): IMediaSample;
  917. // these hold our input and output pins
  918. function InputPin: TBCTransInPlaceInputPin;
  919. function OutputPin: TBCTransInPlaceOutputPin;
  920. // Helper to see if the input and output types match
  921. function TypesMatch: boolean;
  922. // Are the input and output allocators different?
  923. function UsingDifferentAllocators: boolean;
  924. end;
  925. TBCTransInPlaceInputPin = class(TBCTransformInputPin)
  926. protected
  927. FTIPFilter: TBCTransInPlaceFilter; // our filter
  928. FReadOnly : boolean; // incoming stream is read only
  929. public
  930. constructor Create(ObjectName: string; Filter: TBCTransInPlaceFilter;
  931. out hr: HRESULT; Name: WideString);
  932. // --- IMemInputPin -----
  933. // Provide an enumerator for media types by getting one from downstream
  934. function EnumMediaTypes(out ppEnum: IEnumMediaTypes): HRESULT; override; stdcall;
  935. // Say whether media type is acceptable.
  936. function CheckMediaType(pmt: PAMMediaType): HRESULT; override;
  937. // Return our upstream allocator
  938. function GetAllocator(out Allocator: IMemAllocator): HRESULT; stdcall;
  939. // get told which allocator the upstream output pin is actually
  940. // going to use.
  941. function NotifyAllocator(Allocator: IMemAllocator; ReadOnly: BOOL): HRESULT; stdcall;
  942. // Allow the filter to see what allocator we have
  943. // N.B. This does NOT AddRef
  944. function PeekAllocator: IMemAllocator;
  945. // Pass this on downstream if it ever gets called.
  946. function GetAllocatorRequirements(props: PAllocatorProperties): HRESULT; stdcall;
  947. property ReadOnly: Boolean read FReadOnly;
  948. end;
  949. // ==================================================
  950. // Implements the output pin
  951. // ==================================================
  952. TBCTransInPlaceOutputPin = class(TBCTransformOutputPin)
  953. protected
  954. // m_pFilter points to our CBaseFilter
  955. FTIPFilter: TBCTransInPlaceFilter;
  956. public
  957. constructor Create(ObjectName: string; Filter: TBCTransInPlaceFilter;
  958. out hr: HRESULT; Name: WideString);
  959. // --- CBaseOutputPin ------------
  960. // negotiate the allocator and its buffer size/count
  961. // Insists on using our own allocator. (Actually the one upstream of us).
  962. // We don't override this - instead we just agree the default
  963. // then let the upstream filter decide for itself on reconnect
  964. // virtual HRESULT DecideAllocator(IMemInputPin * pPin, IMemAllocator ** pAlloc);
  965. // Provide a media type enumerator. Get it from upstream.
  966. function EnumMediaTypes(out ppEnum: IEnumMediaTypes): HRESULT; override; stdcall;
  967. // Say whether media type is acceptable.
  968. function CheckMediaType(pmt: PAMMediaType): HRESULT; override;
  969. // This just saves the allocator being used on the output pin
  970. // Also called by input pin's GetAllocator()
  971. procedure SetAllocator(Allocator: IMemAllocator);
  972. function ConnectedIMemInputPin: IMemInputPin;
  973. // Allow the filter to see what allocator we have
  974. // N.B. This does NOT AddRef
  975. function PeekAllocator: IMemAllocator;
  976. end;
  977. TBCBasePropertyPage = class(TBCUnknown, IPropertyPage)
  978. private
  979. FObjectSet: boolean; // SetObject has been called or not.
  980. protected
  981. FPageSite: IPropertyPageSite; // Details for our property site
  982. FDirty: boolean; // Has anything been changed
  983. FForm: TFormPropertyPage;
  984. public
  985. constructor Create(Name: String; Unk: IUnKnown; Form: TFormPropertyPage);
  986. destructor Destroy; override;
  987. procedure SetPageDirty;
  988. { IPropertyPage }
  989. function SetPageSite(const pageSite: IPropertyPageSite): HResult; stdcall;
  990. function Activate(hwndParent: HWnd; const rc: TRect; bModal: BOOL): HResult; stdcall;
  991. function Deactivate: HResult; stdcall;
  992. function GetPageInfo(out pageInfo: TPropPageInfo): HResult; stdcall;
  993. function SetObjects(cObjects: Longint; pUnkList: PUnknownList): HResult; stdcall;
  994. function Show(nCmdShow: Integer): HResult; stdcall;
  995. function Move(const rect: TRect): HResult; stdcall;
  996. function IsPageDirty: HResult; stdcall;
  997. function Apply: HResult; stdcall;
  998. function Help(pszHelpDir: POleStr): HResult; stdcall;
  999. function TranslateAccelerator(msg: PMsg): HResult; stdcall;
  1000. end;
  1001. TOnConnect = procedure(sender: Tobject; Unknown: IUnknown) of object;
  1002. TFormPropertyPage = class(TForm, IUnKnown, IPropertyPage)
  1003. private
  1004. FPropertyPage: TBCBasePropertyPage;
  1005. procedure MyWndProc(var aMsg: TMessage);
  1006. public
  1007. constructor Create(AOwner: TComponent); override;
  1008. published
  1009. function OnConnect(Unknown: IUnknown): HRESULT; virtual;
  1010. function OnDisconnect: HRESULT; virtual;
  1011. function OnApplyChanges: HRESULT; virtual;
  1012. property PropertyPage : TBCBasePropertyPage read FPropertyPage implements IUnKnown, IPropertyPage;
  1013. end;
  1014. TBCBaseDispatch = class{IDispatch}
  1015. protected
  1016. FTI: ITypeInfo;
  1017. public
  1018. // IDispatch methods
  1019. function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
  1020. function GetTypeInfo(const iid: TGUID; info: Cardinal; lcid: LCID; out tinfo): HRESULT; stdcall;
  1021. function GetIDsOfNames(const IID: TGUID; Names: Pointer;
  1022. NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
  1023. end;
  1024. TBCMediaControl = class(TBCUnknown, IDispatch)
  1025. public
  1026. FBaseDisp: TBCBaseDispatch;
  1027. constructor Create(name: string; unk: IUnknown);
  1028. destructor Destroy; override;
  1029. // IDispatch methods
  1030. function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
  1031. function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
  1032. function GetIDsOfNames(const IID: TGUID; Names: Pointer;
  1033. NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
  1034. function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
  1035. Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
  1036. end;
  1037. TBCMediaEvent = class(TBCUnknown, IDisPatch{,IMediaEventEx})
  1038. protected
  1039. FBasedisp: TBCBaseDispatch;
  1040. public
  1041. constructor Create(Name: string; Unk: IUnknown);
  1042. destructor destroy; override;
  1043. // IDispatch methods
  1044. function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
  1045. function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
  1046. function GetIDsOfNames(const IID: TGUID; Names: Pointer;
  1047. NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
  1048. function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
  1049. Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
  1050. end;
  1051. TBCMediaPosition = class(TBCUnknown, IDispatch {IMediaPosition})
  1052. protected
  1053. FBaseDisp: TBCBaseDispatch;
  1054. public
  1055. constructor Create(Name: String; Unk: IUnknown); overload;
  1056. constructor Create(Name: String; Unk: IUnknown; out hr: HRESULT); overload;
  1057. destructor Destroy; override;
  1058. // IDispatch methods
  1059. function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
  1060. function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
  1061. function GetIDsOfNames(const IID: TGUID; Names: Pointer;
  1062. NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
  1063. function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
  1064. Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
  1065. end;
  1066. // A utility class that handles IMediaPosition and IMediaSeeking on behalf
  1067. // of single-input pin renderers, or transform filters.
  1068. //
  1069. // Renderers will expose this from the filter; transform filters will
  1070. // expose it from the output pin and not the renderer.
  1071. //
  1072. // Create one of these, giving it your IPin* for your input pin, and delegate
  1073. // all IMediaPosition methods to it. It will query the input pin for
  1074. // IMediaPosition and respond appropriately.
  1075. //
  1076. // Call ForceRefresh if the pin connection changes.
  1077. //
  1078. // This class no longer caches the upstream IMediaPosition or IMediaSeeking
  1079. // it acquires it on each method call. This means ForceRefresh is not needed.
  1080. // The method is kept for source compatibility and to minimise the changes
  1081. // if we need to put it back later for performance reasons.
  1082. TBCPosPassThru = class(TBCMediaPosition, IMediaSeeking)
  1083. protected
  1084. FPin: IPin;
  1085. function GetPeer(out MP: IMediaPosition): HRESULT;
  1086. function GetPeerSeeking(out MS: IMediaSeeking): HRESULT;
  1087. public
  1088. constructor Create(name: String; Unk: IUnknown; out hr: HRESULT; Pin: IPin);
  1089. function ForceRefresh: HRESULT;{return S_OK;}
  1090. // override to return an accurate current position
  1091. function GetMediaTime(out StartTime, EndTime: int64): HRESULT; virtual;
  1092. // IMediaSeeking methods
  1093. function GetCapabilities(out pCapabilities: DWORD): HRESULT; stdcall;
  1094. function CheckCapabilities(var pCapabilities: DWORD): HRESULT; stdcall;
  1095. function IsFormatSupported(const pFormat: TGUID): HRESULT; stdcall;
  1096. function QueryPreferredFormat(out pFormat: TGUID): HRESULT; stdcall;
  1097. function GetTimeFormat(out pFormat: TGUID): HRESULT; stdcall;
  1098. function IsUsingTimeFormat(const pFormat: TGUID): HRESULT; stdcall;
  1099. function SetTimeFormat(const pFormat: TGUID): HRESULT; stdcall;
  1100. function GetDuration(out pDuration: int64): HRESULT; stdcall;
  1101. function GetStopPosition(out pStop: int64): HRESULT; stdcall;
  1102. function GetCurrentPosition(out pCurrent: int64): HRESULT; stdcall;
  1103. function ConvertTimeFormat(out pTarget: int64; pTargetFormat: PGUID;
  1104. Source: int64; pSourceFormat: PGUID): HRESULT; stdcall;
  1105. function SetPositions(var pCurrent: int64; dwCurrentFlags: DWORD;
  1106. var pStop: int64; dwStopFlags: DWORD): HRESULT; stdcall;
  1107. function GetPositions(out pCurrent, pStop: int64): HRESULT; stdcall;
  1108. function GetAvailable(out pEarliest, pLatest: int64): HRESULT; stdcall;
  1109. function SetRate(dRate: double): HRESULT; stdcall;
  1110. function GetRate(out pdRate: double): HRESULT; stdcall;
  1111. function GetPreroll(out pllPreroll: int64): HRESULT; stdcall;
  1112. // IMediaPosition properties
  1113. function get_Duration(out plength: TRefTime): HResult; stdcall;
  1114. function put_CurrentPosition(llTime: TRefTime): HResult; stdcall;
  1115. function get_CurrentPosition(out pllTime: TRefTime): HResult; stdcall;
  1116. function get_StopTime(out pllTime: TRefTime): HResult; stdcall;
  1117. function put_StopTime(llTime: TRefTime): HResult; stdcall;
  1118. function get_PrerollTime(out pllTime: TRefTime): HResult; stdcall;
  1119. function put_PrerollTime(llTime: TRefTime): HResult; stdcall;
  1120. function put_Rate(dRate: double): HResult; stdcall;
  1121. function get_Rate(out pdRate: double): HResult; stdcall;
  1122. function CanSeekForward(out pCanSeekForward: Longint): HResult; stdcall;
  1123. function CanSeekBackward(out pCanSeekBackward: Longint): HResult; stdcall;
  1124. end;
  1125. TBCRendererPosPassThru = class(TBCPosPassThru)
  1126. protected
  1127. FPositionLock: TBCCritSec; // Locks access to our position
  1128. FStartMedia : Int64; // Start media time last seen
  1129. FEndMedia : Int64; // And likewise the end media
  1130. FReset : boolean; // Have media times been set
  1131. public
  1132. // Used to help with passing media times through graph
  1133. constructor Create(name: String; Unk: IUnknown; out hr: HRESULT; Pin: IPin); reintroduce;
  1134. destructor destroy; override;
  1135. function RegisterMediaTime(MediaSample: IMediaSample): HRESULT; overload;
  1136. function RegisterMediaTime(StartTime, EndTime: int64): HRESULT; overload;
  1137. function GetMediaTime(out StartTime, EndTime: int64): HRESULT; override;
  1138. function ResetMediaTime: HRESULT;
  1139. function EOS: HRESULT;
  1140. end;
  1141. // wrapper for event objects
  1142. TBCAMEvent = class
  1143. protected
  1144. FEvent: THANDLE;
  1145. public
  1146. constructor Create(ManualReset: boolean = false);
  1147. destructor destroy; override;
  1148. property Handle: THandle read FEvent;
  1149. procedure SetEv;
  1150. function Wait(Timeout: Cardinal = INFINITE): boolean;
  1151. procedure Reset;
  1152. function Check: boolean;
  1153. end;
  1154. TBCTimeoutEvent = TBCAMEvent;
  1155. // wrapper for event objects that do message processing
  1156. // This adds ONE method to the CAMEvent object to allow sent
  1157. // messages to be processed while waiting
  1158. TBCAMMsgEvent = class(TBCAMEvent)
  1159. public
  1160. // Allow SEND messages to be processed while waiting
  1161. function WaitMsg(Timeout: DWord = INFINITE): boolean;
  1162. end;
  1163. // support for a worker thread
  1164. // simple thread class supports creation of worker thread, synchronization
  1165. // and communication. Can be derived to simplify parameter passing
  1166. TThreadProc = function: DWORD of object;
  1167. TBCAMThread = class
  1168. private
  1169. FEventSend: TBCAMEvent;
  1170. FEventComplete: TBCAMEvent;
  1171. FParam: DWord;
  1172. FReturnVal: DWord;
  1173. FThreadProc: TThreadProc;
  1174. protected
  1175. FThread: THandle;
  1176. // thread will run this function on startup
  1177. // must be supplied by derived class
  1178. function ThreadProc: DWord; virtual;
  1179. public
  1180. FAccessLock: TBCCritSec; // locks access by client threads
  1181. FWorkerLock: TBCCritSec; // locks access to shared objects
  1182. constructor Create;
  1183. destructor Destroy; override;
  1184. // thread initially runs this. param is actually 'this'. function
  1185. // just gets this and calls ThreadProc
  1186. function InitialThreadProc(p: Pointer): DWORD; virtual; stdcall; // WINAPI;
  1187. // start thread running - error if already running
  1188. function Create_: boolean;
  1189. // signal the thread, and block for a response
  1190. //
  1191. function CallWorker(Param: DWORD): DWORD;
  1192. // accessor thread calls this when done with thread (having told thread
  1193. // to exit)
  1194. procedure Close;
  1195. // ThreadExists
  1196. // Return True if the thread exists. FALSE otherwise
  1197. function ThreadExists: boolean; // const
  1198. // wait for the next request
  1199. function GetRequest: DWORD;
  1200. // is there a request?
  1201. function CheckRequest(Param: PDWORD): boolean;
  1202. // reply to the request
  1203. procedure Reply(v: DWORD);
  1204. // If you want to do WaitForMultipleObjects you'll need to include
  1205. // this handle in your wait list or you won't be responsive
  1206. function GetRequestHandle: THANDLE;
  1207. // Find out what the request was
  1208. function GetRequestParam: DWORD;
  1209. // call CoInitializeEx (COINIT_DISABLE_OLE1DDE) if
  1210. // available. S_FALSE means it's not available.
  1211. class function CoInitializeHelper: HRESULT;
  1212. end;
  1213. TBCRenderedInputPin = class(TBCBaseInputPin)
  1214. private
  1215. procedure DoCompleteHandling;
  1216. protected
  1217. // Member variables to track state
  1218. FAtEndOfStream : boolean; // Set by EndOfStream
  1219. FCompleteNotified : boolean; // Set when we notify for EC_COMPLETE
  1220. public
  1221. constructor Create(ObjectName: string; Filter: TBCBaseFilter;
  1222. Lock: TBCCritSec; out hr: HRESULT; Name: WideString);
  1223. // Override methods to track end of stream state
  1224. function EndOfStream: HRESULT; override; stdcall;
  1225. function EndFlush: HRESULT; override; stdcall;
  1226. function Active: HRESULT; override;
  1227. function Run(Start: TReferenceTime): HRESULT; override;
  1228. end;
  1229. (* A generic list of pointers to objects.
  1230. No storage management or copying is done on the objects pointed to.
  1231. Objectives: avoid using MFC libraries in ndm kernel mode and
  1232. provide a really useful list type.
  1233. The class is thread safe in that separate threads may add and
  1234. delete items in the list concurrently although the application
  1235. must ensure that constructor and destructor access is suitably
  1236. synchronised. An application can cause deadlock with operations
  1237. which use two lists by simultaneously calling
  1238. list1->Operation(list2) and list2->Operation(list1). So don't!
  1239. The names must not conflict with MFC classes as an application
  1240. may use both.
  1241. *)
  1242. (* A POSITION represents (in some fashion that's opaque) a cursor
  1243. on the list that can be set to identify any element. NULL is
  1244. a valid value and several operations regard NULL as the position
  1245. "one step off the end of the list". (In an n element list there
  1246. are n+1 places to insert and NULL is that "n+1-th" value).
  1247. The POSITION of an element in the list is only invalidated if
  1248. that element is deleted. Move operations may mean that what
  1249. was a valid POSITION in one list is now a valid POSITION in
  1250. a different list.
  1251. Some operations which at first sight are illegal are allowed as
  1252. harmless no-ops. For instance RemoveHead is legal on an empty
  1253. list and it returns NULL. This allows an atomic way to test if
  1254. there is an element there, and if so, get it. The two operations
  1255. AddTail and RemoveHead thus implement a MONITOR (See Hoare's paper).
  1256. Single element operations return POSITIONs, non-NULL means it worked.
  1257. whole list operations return a BOOL. True means it all worked.
  1258. This definition is the same as the POSITION type for MFCs, so we must
  1259. avoid defining it twice.
  1260. *)
  1261. Position = Pointer;
  1262. {$ifdef DEBUG}
  1263. TBCNode = class(TBCBaseObject)
  1264. {$else}
  1265. TBCNode = class
  1266. {$endif}
  1267. private
  1268. FPrev: TBCNode; // Previous node in the list
  1269. FNext: TBCNode; // Next node in the list
  1270. FObject: Pointer; // Pointer to the object
  1271. public
  1272. // Constructor - initialise the object's pointers
  1273. {$ifdef DEBUG}
  1274. constructor Create;
  1275. {$endif}
  1276. // Return the previous node before this one
  1277. property Prev: TBCNode read FPrev write FPrev;
  1278. // Return the next node after this one
  1279. property Next: TBCNode read FNext write FNext;
  1280. // Get the pointer to the object for this node */
  1281. property Data: Pointer read FObject write FObject;
  1282. end;
  1283. TBCNodeCache = class
  1284. private
  1285. FCacheSize: Integer;
  1286. FUsed: Integer;
  1287. FHead: TBCNode;
  1288. public
  1289. constructor Create(CacheSize: Integer);
  1290. destructor Destroy; override;
  1291. procedure AddToCache(Node: TBCNode);
  1292. function RemoveFromCache: TBCNode;
  1293. end;
  1294. (* A class representing one node in a list.
  1295. Each node knows a pointer to it's adjacent nodes and also a pointer
  1296. to the object that it looks after.
  1297. All of these pointers can be retrieved or set through member functions.
  1298. *)
  1299. TBCBaseList = class
  1300. {$ifdef DEBUG}
  1301. (TBCBaseObject)
  1302. {$endif}
  1303. (* Making these classes inherit from CBaseObject does nothing
  1304. functionally but it allows us to check there are no memory
  1305. leaks in debug builds.
  1306. *)
  1307. protected
  1308. FFirst: TBCNode; // Pointer to first node in the list
  1309. FLast: TBCNode; // Pointer to the last node in the list
  1310. FCount: LongInt; // Number of nodes currently in the list
  1311. private
  1312. FCache: TBCNodeCache; // Cache of unused node pointers
  1313. public
  1314. constructor Create(Name: string; Items: Integer = DEFAULTCACHE);
  1315. destructor Destroy; override;
  1316. // Remove all the nodes from self i.e. make the list empty
  1317. procedure RemoveAll;
  1318. // Return a cursor which identifies the first element of self
  1319. function GetHeadPositionI: Position;
  1320. /// Return a cursor which identifies the last element of self
  1321. function GetTailPositionI: Position;
  1322. // Return the number of objects in self
  1323. function GetCountI: Integer;
  1324. protected
  1325. (* Return the pointer to the object at rp,
  1326. Update rp to the next node in self
  1327. but make it nil if it was at the end of self.
  1328. This is a wart retained for backwards compatibility.
  1329. GetPrev is not implemented.
  1330. Use Next, Prev and Get separately.
  1331. *)
  1332. function GetNextI(var rp: Position): Pointer;
  1333. (* Return a pointer to the object at p
  1334. Asking for the object at nil will return nil harmlessly.
  1335. *)
  1336. function GetI(p: Position): Pointer;
  1337. public
  1338. (* return the next / prev position in self
  1339. return NULL when going past the end/start.
  1340. Next(nil) is same as GetHeadPosition()
  1341. Prev(nil) is same as GetTailPosition()
  1342. An n element list therefore behaves like a n+1 element
  1343. cycle with nil at the start/end.
  1344. !!WARNING!! - This handling of nil is DIFFERENT from GetNext.
  1345. Some reasons are:
  1346. 1. For a list of n items there are n+1 positions to insert
  1347. These are conveniently encoded as the n POSITIONs and nil.
  1348. 2. If you are keeping a list sorted (fairly common) and you
  1349. search forward for an element to insert before and don't
  1350. find it you finish up with nil as the element before which
  1351. to insert. You then want that nil to be a valid POSITION
  1352. so that you can insert before it and you want that insertion
  1353. point to mean the (n+1)-th one that doesn't have a POSITION.
  1354. (symmetrically if you are working backwards through the list).
  1355. 3. It simplifies the algebra which the methods generate.
  1356. e.g. AddBefore(p,x) is identical to AddAfter(Prev(p),x)
  1357. in ALL cases. All the other arguments probably are reflections
  1358. of the algebraic point.
  1359. *)
  1360. function Next(pos: Position): Position;
  1361. function Prev(pos: Position): Position;
  1362. (* Return the first position in self which holds the given
  1363. pointer. Return nil if the pointer was not not found.
  1364. *)
  1365. protected
  1366. function FindI(Obj: Pointer): Position;
  1367. (* Remove the first node in self (deletes the pointer to its
  1368. object from the list, does not free the object itself).
  1369. Return the pointer to its object.
  1370. If self was already empty it will harmlessly return nil.
  1371. *)
  1372. function RemoveHeadI: Pointer;
  1373. (* Remove the last node in self (deletes the pointer to its
  1374. object from the list, does not free the object itself).
  1375. Return the pointer to its object.
  1376. If self was already empty it will harmlessly return nil.
  1377. *)
  1378. function RemoveTailI: Pointer;
  1379. (* Remove the node identified by p from the list (deletes the pointer
  1380. to its object from the list, does not free the object itself).
  1381. Asking to Remove the object at nil will harmlessly return nil.
  1382. Return the pointer to the object removed.
  1383. *)
  1384. function RemoveI(pos: Position): Pointer;
  1385. (* Add single object *pObj to become a new last element of the list.
  1386. Return the new tail position, nil if it fails.
  1387. If you are adding a COM objects, you might want AddRef it first.
  1388. Other existing POSITIONs in self are still valid
  1389. *)
  1390. function AddTailI(Obj: Pointer): Position;
  1391. public
  1392. (* Add all the elements in *pList to the tail of self.
  1393. This duplicates all the nodes in *pList (i.e. duplicates
  1394. all its pointers to objects). It does not duplicate the objects.
  1395. If you are adding a list of pointers to a COM object into the list
  1396. it's a good idea to AddRef them all it when you AddTail it.
  1397. Return True if it all worked, FALSE if it didn't.
  1398. If it fails some elements may have been added.
  1399. Existing POSITIONs in self are still valid
  1400. If you actually want to MOVE the elements, use MoveToTail instead.
  1401. *)
  1402. function AddTail(List: TBCBaseList): boolean;
  1403. // Mirror images of AddHead:
  1404. (* Add single object to become a new first element of the list.
  1405. Return the new head position, nil if it fails.
  1406. Existing POSITIONs in self are still valid
  1407. *)
  1408. protected
  1409. function AddHeadI(Obj: Pointer): Position;
  1410. public
  1411. (* Add all the elements in *pList to the head of self.
  1412. Same warnings apply as for AddTail.
  1413. Return True if it all worked, FALSE if it didn't.
  1414. If it fails some of the objects may have been added.
  1415. If you actually want to MOVE the elements, use MoveToHead instead.
  1416. *)
  1417. function AddHead(List: TBCBaseList): BOOL;
  1418. (* Add the object *pObj to self after position p in self.
  1419. AddAfter(nil,x) adds x to the start - equivalent to AddHead
  1420. Return the position of the object added, nil if it failed.
  1421. Existing POSITIONs in self are undisturbed, including p.
  1422. *)
  1423. protected
  1424. function AddAfterI(pos: Position; Obj: Pointer): Position;
  1425. public
  1426. (* Add the list *pList to self after position p in self
  1427. AddAfter(nil,x) adds x to the start - equivalent to AddHead
  1428. Return True if it all worked, FALSE if it didn't.
  1429. If it fails, some of the objects may be added
  1430. Existing POSITIONs in self are undisturbed, including p.
  1431. *)
  1432. function AddAfter(p: Position; List: TBCBaseList): BOOL;
  1433. (* Mirror images:
  1434. Add the object *pObj to this-List after position p in self.
  1435. AddBefore(nil,x) adds x to the end - equivalent to AddTail
  1436. Return the position of the new object, nil if it fails
  1437. Existing POSITIONs in self are undisturbed, including p.
  1438. *)
  1439. protected
  1440. function AddBeforeI(pos: Position; Obj: Pointer): Position;
  1441. public
  1442. (* Add the list *pList to self before position p in self
  1443. AddAfter(nil,x) adds x to the start - equivalent to AddHead
  1444. Return True if it all worked, FALSE if it didn't.
  1445. If it fails, some of the objects may be added
  1446. Existing POSITIONs in self are undisturbed, including p.
  1447. *)
  1448. function AddBefore(p: Position; List: TBCBaseList): BOOL;
  1449. (* Note that AddAfter(p,x) is equivalent to AddBefore(Next(p),x)
  1450. even in cases where p is nil or Next(p) is nil.
  1451. Similarly for mirror images etc.
  1452. This may make it easier to argue about programs.
  1453. *)
  1454. (* The following operations do not copy any elements.
  1455. They move existing blocks of elements around by switching pointers.
  1456. They are fairly efficient for long lists as for short lists.
  1457. (Alas, the Count slows things down).
  1458. They split the list into two parts.
  1459. One part remains as the original list, the other part
  1460. is appended to the second list. There are eight possible
  1461. variations:
  1462. Split the list {after/before} a given element
  1463. keep the {head/tail} portion in the original list
  1464. append the rest to the {head/tail} of the new list.
  1465. Since After is strictly equivalent to Before Next
  1466. we are not in serious need of the Before/After variants.
  1467. That leaves only four.
  1468. If you are processing a list left to right and dumping
  1469. the bits that you have processed into another list as
  1470. you go, the Tail/Tail variant gives the most natural result.
  1471. If you are processing in reverse order, Head/Head is best.
  1472. By using nil positions and empty lists judiciously either
  1473. of the other two can be built up in two operations.
  1474. The definition of nil (see Next/Prev etc) means that
  1475. degenerate cases include
  1476. "move all elements to new list"
  1477. "Split a list into two lists"
  1478. "Concatenate two lists"
  1479. (and quite a few no-ops)
  1480. !!WARNING!! The type checking won't buy you much if you get list
  1481. positions muddled up - e.g. use a POSITION that's in a different
  1482. list and see what a mess you get!
  1483. *)
  1484. (* Split self after position p in self
  1485. Retain as self the tail portion of the original self
  1486. Add the head portion to the tail end of *pList
  1487. Return True if it all worked, FALSE if it didn't.
  1488. e.g.
  1489. foo->MoveToTail(foo->GetHeadPosition(), bar);
  1490. moves one element from the head of foo to the tail of bar
  1491. foo->MoveToTail(nil, bar);
  1492. is a no-op, returns nil
  1493. foo->MoveToTail(foo->GetTailPosition, bar);
  1494. concatenates foo onto the end of bar and empties foo.
  1495. A better, except excessively long name might be
  1496. MoveElementsFromHeadThroughPositionToOtherTail
  1497. *)
  1498. function MoveToTail(pos: Position; List: TBCBaseList): boolean;
  1499. (* Mirror image:
  1500. Split self before position p in self.
  1501. Retain in self the head portion of the original self
  1502. Add the tail portion to the start (i.e. head) of *pList
  1503. e.g.
  1504. foo->MoveToHead(foo->GetTailPosition(), bar);
  1505. moves one element from the tail of foo to the head of bar
  1506. foo->MoveToHead(nil, bar);
  1507. is a no-op, returns nil
  1508. foo->MoveToHead(foo->GetHeadPosition, bar);
  1509. concatenates foo onto the start of bar and empties foo.
  1510. *)
  1511. function MoveToHead(pos: Position; List: TBCBaseList): boolean;
  1512. (* Reverse the order of the [pointers to] objects in self *)
  1513. procedure Reverse;
  1514. end;
  1515. // Desc: DirectShow base classes - defines classes to simplify creation of
  1516. // ActiveX source filters that support continuous generation of data.
  1517. // No support is provided for IMediaControl or IMediaPosition.
  1518. //
  1519. // Derive your source filter from CSource.
  1520. // During construction either:
  1521. // Create some CSourceStream objects to manage your pins
  1522. // Provide the user with a means of doing so eg, an IPersistFile interface.
  1523. //
  1524. // CSource provides:
  1525. // IBaseFilter interface management
  1526. // IMediaFilter interface management, via CBaseFilter
  1527. // Pin counting for CBaseFilter
  1528. //
  1529. // Derive a class from CSourceStream to manage your output pin types
  1530. // Implement GetMediaType/1 to return the type you support. If you support multiple
  1531. // types then overide GetMediaType/3, CheckMediaType and GetMediaTypeCount.
  1532. // Implement Fillbuffer() to put data into one buffer.
  1533. //
  1534. // CSourceStream provides:
  1535. // IPin management via CBaseOutputPin
  1536. // Worker thread management
  1537. // Override construction to provide a means of creating
  1538. // CSourceStream derived objects - ie a way of creating pins.
  1539. TBCSourceStream = class;
  1540. TStreamArray = array of TBCSourceStream;
  1541. TBCSource = class(TBCBaseFilter)
  1542. protected
  1543. FPins: Integer; // The number of pins on this filter. Updated by CSourceStream
  1544. FStreams: Pointer; // the pins on this filter.
  1545. FStateLock: TBCCritSec;
  1546. public
  1547. constructor Create(const Name: string; unk: IUnknown; const clsid: TGUID; out hr: HRESULT); overload;
  1548. constructor Create(const Name: string; unk: IUnknown; const clsid: TGUID); overload;
  1549. destructor Destroy; override;
  1550. function GetPinCount: Integer; override;
  1551. function GetPin(n: Integer): TBCBasePin; override;
  1552. // -- Utilities --
  1553. property StateLock: TBCCritSec read FStateLock; // provide our critical section
  1554. function AddPin(Stream: TBCSourceStream): HRESULT;
  1555. function RemovePin(Stream: TBCSourceStream): HRESULT;
  1556. function FindPin(Id: PWideChar; out Pin: IPin): HRESULT; override;
  1557. function FindPinNumber(Pin: IPin): Integer;
  1558. end;
  1559. //
  1560. // CSourceStream
  1561. //
  1562. // Use this class to manage a stream of data that comes from a
  1563. // pin.
  1564. // Uses a worker thread to put data on the pin.
  1565. TThreadCommand = (
  1566. CMD_INIT,
  1567. CMD_PAUSE,
  1568. CMD_RUN,
  1569. CMD_STOP,
  1570. CMD_EXIT
  1571. );
  1572. TBCSourceStream = class(TBCBaseOutputPin)
  1573. public
  1574. constructor Create(const ObjectName: string; out hr: HRESULT;
  1575. Filter: TBCSource; const Name: WideString);
  1576. destructor Destroy; override;
  1577. protected
  1578. FThread: TBCAMThread;
  1579. FFilter: TBCSource; // The parent of this stream
  1580. // *
  1581. // * Data Source
  1582. // *
  1583. // * The following three functions: FillBuffer, OnThreadCreate/Destroy, are
  1584. // * called from within the ThreadProc. They are used in the creation of
  1585. // * the media samples this pin will provide
  1586. // *
  1587. // Override this to provide the worker thread a means
  1588. // of processing a buffer
  1589. function FillBuffer(Samp: IMediaSample): HRESULT; virtual; abstract;
  1590. // Called as the thread is created/destroyed - use to perform
  1591. // jobs such as start/stop streaming mode
  1592. // If OnThreadCreate returns an error the thread will exit.
  1593. function OnThreadCreate: HRESULT; virtual;
  1594. function OnThreadDestroy: HRESULT; virtual;
  1595. function OnThreadStartPlay: HRESULT; virtual;
  1596. public
  1597. // *
  1598. // * Worker Thread
  1599. // *
  1600. function Active: HRESULT; override; // Starts up the worker thread
  1601. function Inactive: HRESULT; override; // Exits the worker thread.
  1602. // thread commands
  1603. function Init: HRESULT;
  1604. function Exit_: HRESULT;
  1605. function Run: HRESULT; reintroduce;
  1606. function Pause: HRESULT;
  1607. function Stop: HRESULT;
  1608. // *
  1609. // * AM_MEDIA_TYPE support
  1610. // *
  1611. // If you support more than one media type then override these 2 functions
  1612. function CheckMediaType(MediaType: PAMMediaType): HRESULT; override;
  1613. function GetMediaType(Position: integer; out MediaType: PAMMediaType): HRESULT; overload; override; // List pos. 0-n
  1614. // If you support only one type then override this fn.
  1615. // This will only be called by the default implementations
  1616. // of CheckMediaType and GetMediaType(int, CMediaType*)
  1617. // You must override this fn. or the above 2!
  1618. function GetMediaType(MediaType: PAMMediaType): HRESULT; reintroduce; overload; virtual;
  1619. function QueryId(out id: PWideChar): HRESULT; override;
  1620. protected
  1621. function GetRequest: TThreadCommand;
  1622. function CheckRequest(var com: TThreadCommand): boolean;
  1623. // override these if you want to add thread commands
  1624. function ThreadProc: DWORD; virtual; // the thread function
  1625. function DoBufferProcessingLoop: HRESULT; virtual; // the loop executed whilst running
  1626. end;
  1627. TBCBaseRenderer = class;
  1628. TBCRendererInputPin = class;
  1629. // This is our input pin class that channels calls to the renderer
  1630. TBCRendererInputPin = class(TBCBaseInputPin)
  1631. protected
  1632. FRenderer: TBCBaseRenderer;
  1633. public
  1634. constructor Create(Renderer: TBCBaseRenderer; out hr: HResult;
  1635. Name: PWideChar);
  1636. // Overriden from the base pin classes
  1637. function BreakConnect: HResult; override;
  1638. function CompleteConnect(ReceivePin: IPin): HResult; override;
  1639. function SetMediaType(MediaType: PAMMediaType): HResult; override;
  1640. function CheckMediaType(MediaType: PAMMediaType): HResult; override;
  1641. function Active: HResult; override;
  1642. function Inactive: HResult; override;
  1643. // Add rendering behaviour to interface functions
  1644. function QueryId(out Id: PWideChar): HResult; override; stdcall;
  1645. function EndOfStream: HResult; override; stdcall;
  1646. function BeginFlush: HResult; override; stdcall;
  1647. function EndFlush: HResult; override; stdcall;
  1648. function Receive(MediaSample: IMediaSample): HResult; override; stdcall;
  1649. function InheritedReceive(MediaSample: IMediaSample): HResult;
  1650. virtual; stdcall;
  1651. end;
  1652. // Main renderer class that handles synchronisation and state changes
  1653. TBCBaseRenderer = class(TBCBaseFilter)
  1654. protected
  1655. // friend class CRendererInputPin;
  1656. //FEndOfStreamTimerCB: TFNTimeCallBack;
  1657. // Media seeking pass by object
  1658. FPosition: TBCRendererPosPassThru;
  1659. //FPosition: IUnknown;
  1660. // Used to signal timer events
  1661. FRenderEvent: TBCAMEvent;
  1662. // Signalled to release worker thread
  1663. FThreadSignal: TBCAMEvent;
  1664. // Signalled when state complete
  1665. FCompleteEvent: TBCAMEvent;
  1666. // Stop us from rendering more data
  1667. FAbort: Boolean;
  1668. // Are we currently streaming
  1669. FIsStreaming: Boolean;
  1670. // Timer advise cookie
  1671. FAdvisedCookie: DWord;
  1672. // Current image media sample
  1673. FMediaSample: IMediaSample;
  1674. // Any more samples in the stream
  1675. FIsEOS: Boolean;
  1676. // Have we delivered an EC_COMPLETE
  1677. FIsEOSDelivered: Boolean;
  1678. // Our renderer input pin object
  1679. FInputPin: TBCRendererInputPin;
  1680. // Critical section for interfaces
  1681. FInterfaceLock: TBCCritSec;
  1682. // Controls access to internals
  1683. FRendererLock: TBCCritSec;
  1684. // QualityControl sink
  1685. FQSink: IQualityControl;
  1686. // Can we signal an EC_REPAINT
  1687. FRepaintStatus: Boolean;
  1688. // Avoid some deadlocks by tracking filter during stop
  1689. // Inside Receive between PrepareReceive and actually processing the sample
  1690. FInReceive: Boolean;
  1691. // Time when we signal EC_COMPLETE
  1692. FSignalTime: TReferenceTime;
  1693. // Used to signal end of stream
  1694. FEndOfStreamTimer: DWord;
  1695. // This lock protects the creation and of FPosition and FInputPin.
  1696. // It ensures that two threads cannot create either object simultaneously.
  1697. FObjectCreationLock: TBCCritSec;
  1698. // Milenko start (must be outside of the class and with stdcall; or it will crash)
  1699. // procedure EndOfStreamTimer(
  1700. // uID: UINT; // Timer identifier
  1701. // uMsg: UINT; // Not currently used
  1702. // dwUser: DWord; // User information
  1703. // dw1: DWord; // Windows reserved
  1704. // dw2: DWord // Is also reserved
  1705. // ); stdcall;
  1706. // Milenko end
  1707. public
  1708. {$IFDEF PERF}
  1709. // Just before we started drawing
  1710. // Set in OnRenderStart, Used in OnRenderEnd
  1711. FRenderStart: TReferenceTime;
  1712. // MSR_id for frame time stamp
  1713. FBaseStamp: Integer;
  1714. // MSR_id for true wait time
  1715. FBaseRenderTime: Integer;
  1716. // MSR_id for time frame is late (int)
  1717. FBaseAccuracy: Integer;
  1718. {$ENDIF}
  1719. constructor Create(
  1720. // CLSID for this renderer
  1721. RendererClass: TGUID;
  1722. // Debug ONLY description
  1723. Name: PChar;
  1724. // Aggregated owner object
  1725. Unk: IUnknown;
  1726. // General OLE return code
  1727. hr: HResult);
  1728. destructor Destroy; override;
  1729. // milenko start (added as a workaround for the TBCRendererPosPAssThru/FPosition and Renderer destructor)
  1730. function JoinFilterGraph(pGraph: IFilterGraph; pName: PWideChar): HRESULT; override;
  1731. // milenko end
  1732. // Overriden to say what interfaces we support and where
  1733. function GetMediaPositionInterface(IID: TGUID; out Obj): HResult;
  1734. virtual;
  1735. function NonDelegatingQueryInterface(const IID: TGUID; out Obj): HResult;
  1736. override; stdcall;
  1737. function SourceThreadCanWait(CanWait: Boolean): HResult; virtual;
  1738. {$IFDEF DEBUG}
  1739. // Debug only dump of the renderer state
  1740. procedure DisplayRendererState;
  1741. {$ENDIF}
  1742. function WaitForRenderTime: HResult; virtual;
  1743. function CompleteStateChange(OldState: TFilterState): HResult; virtual;
  1744. // Return internal information about this filter
  1745. property IsEndOfStream: Boolean read FIsEOS;
  1746. property IsEndOfStreamDelivered: Boolean read FIsEOSDelivered;
  1747. property IsStreaming: Boolean read FIsStreaming;
  1748. procedure SetAbortSignal(Abort_: Boolean);
  1749. procedure OnReceiveFirstSample(MediaSample: IMediaSample); virtual;
  1750. property RenderEvent: TBCAMEvent read FRenderEvent;
  1751. // Permit access to the transition state
  1752. procedure Ready;
  1753. procedure NotReady;
  1754. function CheckReady: Boolean;
  1755. function GetPinCount: Integer; override;
  1756. function GetPin(n: integer): TBCBasePin; override;
  1757. function GetRealState: TFilterState;
  1758. procedure SendRepaint;
  1759. procedure SendNotifyWindow(Pin: IPin; Handle: HWND);
  1760. function OnDisplayChange: Boolean;
  1761. procedure SetRepaintStatus(Repaint: Boolean);
  1762. // Override the filter and pin interface functions
  1763. function Stop: HResult; override; stdcall;
  1764. function Pause: HResult; override; stdcall;
  1765. function Run(StartTime: TReferenceTime): HResult; override; stdcall;
  1766. function GetState(MSecs: DWord; out State: TFilterState): HResult;
  1767. override; stdcall;
  1768. function FindPin(id: PWideChar; out Pin: IPin): HResult;
  1769. override; stdcall;
  1770. // These are available for a quality management implementation
  1771. procedure OnRenderStart(MediaSample: IMediaSample); virtual;
  1772. procedure OnRenderEnd(MediaSample: IMediaSample); virtual;
  1773. function OnStartStreaming: HResult; virtual;
  1774. function OnStopStreaming: HResult; virtual;
  1775. procedure OnWaitStart; virtual;
  1776. procedure OnWaitEnd; virtual;
  1777. procedure PrepareRender; virtual;
  1778. // Quality management implementation for scheduling rendering
  1779. function ScheduleSample(MediaSample: IMediaSample): Boolean; virtual;
  1780. function GetSampleTimes(MediaSample: IMediaSample;
  1781. out StartTime: TReferenceTime; out EndTime: TReferenceTime): HResult;
  1782. virtual;
  1783. function ShouldDrawSampleNow(MediaSample: IMediaSample;
  1784. StartTime: TReferenceTime; out EndTime: TReferenceTime): HResult; virtual;
  1785. // Lots of end of stream complexities
  1786. procedure TimerCallback;
  1787. procedure ResetEndOfStreamTimer;
  1788. function NotifyEndOfStream: HResult;
  1789. function SendEndOfStream: HResult; virtual;
  1790. function ResetEndOfStream: HResult; virtual;
  1791. function EndOfStream: HResult; virtual;
  1792. // Rendering is based around the clock
  1793. procedure SignalTimerFired;
  1794. function CancelNotification: HResult; virtual;
  1795. function ClearPendingSample: HResult; virtual;
  1796. // Called when the filter changes state
  1797. function Active: HResult; virtual;
  1798. function Inactive: HResult; virtual;
  1799. function StartStreaming: HResult; virtual;
  1800. function StopStreaming: HResult; virtual;
  1801. function BeginFlush: HResult; virtual;
  1802. function EndFlush: HResult; virtual;
  1803. // Deal with connections and type changes
  1804. function BreakConnect: HResult; virtual;
  1805. function SetMediaType(MediaType: PAMMediaType): HResult; virtual;
  1806. function CompleteConnect(ReceivePin: IPin): HResult; virtual;
  1807. // These look after the handling of data samples
  1808. function PrepareReceive(MediaSample: IMediaSample): HResult; virtual;
  1809. function Receive(MediaSample: IMediaSample): HResult; virtual;
  1810. function HaveCurrentSample: Boolean; virtual;
  1811. function GetCurrentSample: IMediaSample; virtual;
  1812. function Render(MediaSample: IMediaSample): HResult; virtual;
  1813. // Derived classes MUST override these
  1814. function DoRenderSample(MediaSample: IMediaSample): HResult;
  1815. virtual; abstract;
  1816. function CheckMediaType(MediaType: PAMMediaType): HResult;
  1817. virtual; abstract;
  1818. // Helper
  1819. procedure WaitForReceiveToComplete;
  1820. (*
  1821. // callback
  1822. property EndOfStreamTimerCB: TFNTimeCallBack read FEndOfStreamTimerCB
  1823. write FEndOfStreamTimerCB;
  1824. *)
  1825. end;
  1826. const
  1827. AVGPERIOD = 4;
  1828. type
  1829. // CBaseVideoRenderer is a renderer class (see its ancestor class) and
  1830. // it handles scheduling of media samples so that they are drawn at the
  1831. // correct time by the reference clock. It implements a degradation
  1832. // strategy. Possible degradation modes are:
  1833. // Drop frames here (only useful if the drawing takes significant time)
  1834. // Signal supplier (upstream) to drop some frame(s) - i.e. one-off skip.
  1835. // Signal supplier to change the frame rate - i.e. ongoing skipping.
  1836. // Or any combination of the above.
  1837. // In order to determine what's useful to try we need to know what's going
  1838. // on. This is done by timing various operations (including the supplier).
  1839. // This timing is done by using timeGetTime as it is accurate enough and
  1840. // usually cheaper than calling the reference clock. It also tells the
  1841. // truth if there is an audio break and the reference clock stops.
  1842. // We provide a number of public entry points (named OnXxxStart, OnXxxEnd)
  1843. // which the rest of the renderer calls at significant moments. These do
  1844. // the timing.
  1845. // the number of frames that the sliding averages are averaged over.
  1846. // the rule is (1024*NewObservation + (AVGPERIOD-1) * PreviousAverage)/AVGPERIOD
  1847. // #define DO_MOVING_AVG(avg,obs) (avg = (1024*obs + (AVGPERIOD-1)*avg)/AVGPERIOD)
  1848. // Spot the bug in this macro - I can't. but it doesn't work!
  1849. TBCBaseVideoRenderer = class(
  1850. // Base renderer class
  1851. TBCBaseRenderer,
  1852. // Property page guff
  1853. IQualProp,
  1854. // Allow throttling
  1855. IQualityControl)
  1856. protected
  1857. //******************************************************************
  1858. // State variables to control synchronisation
  1859. //******************************************************************
  1860. // Control of sending Quality messages. We need to know whether
  1861. // we are in trouble (e.g. frames being dropped) and where the time
  1862. // is being spent.
  1863. // When we drop a frame we play the next one early.
  1864. // The frame after that is likely to wait before drawing and counting this
  1865. // wait as spare time is unfair, so we count it as a zero wait.
  1866. // We therefore need to know whether we are playing frames early or not.
  1867. // The number of consecutive frames drawn at their normal time (not early)
  1868. // -1 means we just dropped a frame.
  1869. FNormal: Integer;
  1870. {$IFDEF PERF}
  1871. // Don't drop any frames (debug and I'm not keen on people using it!)
  1872. FDrawLateFrames: Bool;
  1873. {$ENDIF}
  1874. // The response to Quality messages says our supplier is handling things.
  1875. // We will allow things to go extra late before dropping frames.
  1876. // We will play very early after he has dropped one.
  1877. FSupplierHandlingQuality: Boolean;
  1878. // Control of scheduling, frame dropping etc.
  1879. // We need to know where the time is being spent so as to tell whether
  1880. // we should be taking action here, signalling supplier or what.
  1881. // The variables are initialised to a mode of NOT dropping frames.
  1882. // They will tell the truth after a few frames.
  1883. // We typically record a start time for an event, later we get the time
  1884. // again and subtract to get the elapsed time, and we average this over
  1885. // a few frames. The average is used to tell what mode we are in.
  1886. // Although these are reference times (64 bit) they are all DIFFERENCES
  1887. // between times which are small. An int will go up to 214 secs before
  1888. // overflow. Avoiding 64 bit multiplications and divisions seems
  1889. // worth while.
  1890. // Audio-video throttling. If the user has turned up audio quality
  1891. // very high (in principle it could be any other stream, not just audio)
  1892. // then we can receive cries for help via the graph manager. In this case
  1893. // we put in a wait for some time after rendering each frame.
  1894. FThrottle: Integer;
  1895. // The time taken to render (i.e. BitBlt) frames controls which component
  1896. // needs to degrade. If the blt is expensive, the renderer degrades.
  1897. // If the blt is cheap it's done anyway and the supplier degrades.
  1898. // Time frames are taking to blt
  1899. FRenderAvg: Integer;
  1900. // Time for last frame blt
  1901. FRenderLast: Integer;
  1902. // Just before we started drawing (mSec) derived from timeGetTime.
  1903. FRenderStart: Integer;
  1904. // When frames are dropped we will play the next frame as early as we can.
  1905. // If it was a false alarm and the machine is fast we slide gently back to
  1906. // normal timing. To do this, we record the offset showing just how early
  1907. // we really are. This will normally be negative meaning early or zero.
  1908. FEarliness: Integer;
  1909. // Target provides slow long-term feedback to try to reduce the
  1910. // average sync offset to zero. Whenever a frame is actually rendered
  1911. // early we add a msec or two, whenever late we take off a few.
  1912. // We add or take off 1/32 of the error time.
  1913. // Eventually we should be hovering around zero. For a really bad case
  1914. // where we were (say) 300mSec off, it might take 100 odd frames to
  1915. // settle down. The rate of change of this is intended to be slower
  1916. // than any other mechanism in Quartz, thereby avoiding hunting.
  1917. FTarget: Integer;
  1918. // The proportion of time spent waiting for the right moment to blt
  1919. // controls whether we bother to drop a frame or whether we reckon that
  1920. // we're doing well enough that we can stand a one-frame glitch.
  1921. // Average of last few wait times (actually we just average how early we were).
  1922. // Negative here means LATE.
  1923. FWaitAvg: Integer;
  1924. // The average inter-frame time.
  1925. // This is used to calculate the proportion of the time used by the
  1926. // three operations (supplying us, waiting, rendering)
  1927. // Average inter-frame time
  1928. FFrameAvg: Integer;
  1929. // duration of last frame.
  1930. FDuration: Integer;
  1931. {$IFDEF PERF}
  1932. // Performance logging identifiers
  1933. // MSR_id for frame time stamp
  1934. FTimeStamp: Integer;
  1935. // MSR_id for true wait time
  1936. FWaitReal: Integer;
  1937. // MSR_id for wait time recorded
  1938. FWait: Integer;
  1939. // MSR_id for time frame is late (int)
  1940. FFrameAccuracy: Integer;
  1941. // MSR_id for lateness at scheduler
  1942. FSchLateTime: Integer;
  1943. // MSR_id for Quality rate requested
  1944. FQualityRate: Integer;
  1945. // MSR_id for Quality time requested
  1946. FQualityTime: Integer;
  1947. // MSR_id for decision code
  1948. FDecision: Integer;
  1949. // MSR_id for trace style debugging
  1950. FDebug: Integer;
  1951. // MSR_id for timing the notifications per se
  1952. FSendQuality: Integer;
  1953. {$ENDIF}
  1954. // original time stamp of frame with no earliness fudges etc.
  1955. FRememberStampforPerf: TReferenceTime;
  1956. {$IFDEF PERF}
  1957. // time when previous frame rendered
  1958. FRememberFrameForPerf: TReferenceTime;
  1959. {$ENDIF}
  1960. // PROPERTY PAGE
  1961. // This has edit fields that show the user what's happening
  1962. // These member variables hold these counts.
  1963. // cumulative frames dropped IN THE RENDERER
  1964. FFramesDropped: Integer;
  1965. // Frames since streaming started seen BY THE RENDERER
  1966. // (some may be dropped upstream)
  1967. FFramesDrawn: Integer;
  1968. // Next two support average sync offset and standard deviation of sync offset.
  1969. // Sum of accuracies in mSec
  1970. FTotAcc: Int64;
  1971. // Sum of squares of (accuracies in mSec)
  1972. FSumSqAcc: Int64;
  1973. // Next two allow jitter calculation. Jitter is std deviation of frame time.
  1974. // Time of prev frame (for inter-frame times)
  1975. FLastDraw: TReferenceTime;
  1976. // Sum of squares of (inter-frame time in mSec)
  1977. FSumSqFrameTime: Int64;
  1978. // Sum of inter-frame times in mSec
  1979. FSumFrameTime: Int64;
  1980. // To get performance statistics on frame rate, jitter etc, we need
  1981. // to record the lateness and inter-frame time. What we actually need are the
  1982. // data above (sum, sum of squares and number of entries for each) but the data
  1983. // is generated just ahead of time and only later do we discover whether the
  1984. // frame was actually drawn or not. So we have to hang on to the data
  1985. // hold onto frame lateness
  1986. FLate: Integer;
  1987. // hold onto inter-frame time
  1988. FFrame: Integer;
  1989. // if streaming then time streaming started
  1990. // else time of last streaming session
  1991. // used for property page statistics
  1992. FStreamingStart: Integer;
  1993. {$IFDEF PERF}
  1994. // timeGetTime*10000+m_llTimeOffset==ref time
  1995. FTimeOffset: Int64;
  1996. {$ENDIF}
  1997. public
  1998. constructor Create(
  1999. // CLSID for this renderer
  2000. RenderClass: TGUID;
  2001. // Debug ONLY description
  2002. Name: PChar;
  2003. // Aggregated owner object
  2004. Unk: IUnknown;
  2005. // General OLE return code
  2006. hr: HResult);
  2007. destructor Destroy; override;
  2008. function NonDelegatingQueryInterface(const IID: TGUID; out Obj): HResult;
  2009. override; stdcall;
  2010. // IQualityControl methods - Notify allows audio-video throttling
  2011. function SetSink(QualityControl: IQualityControl): HResult; stdcall;
  2012. function Notify(Filter: IBaseFilter; q: TQuality): HResult; stdcall;
  2013. // These provide a full video quality management implementation
  2014. procedure OnRenderStart(MediaSample: IMediaSample); override;
  2015. procedure OnRenderEnd(MediaSample: IMediaSample); override;
  2016. procedure OnWaitStart; reintroduce;
  2017. procedure OnWaitEnd; reintroduce;
  2018. function OnStartStreaming: HResult; reintroduce;
  2019. function OnStopStreaming: HResult; reintroduce;
  2020. procedure ThrottleWait;
  2021. // Handle the statistics gathering for our quality management
  2022. procedure PreparePerformanceData(Late, Frame: Integer);
  2023. procedure RecordFrameLateness(Late, Frame: Integer); virtual;
  2024. procedure OnDirectRender(MediaSample: IMediaSample); virtual;
  2025. function ResetStreamingTimes: HResult; virtual;
  2026. function ScheduleSample(MediaSample: IMediaSample): Boolean; override;
  2027. function ShouldDrawSampleNow(MediaSample: IMediaSample;
  2028. StartTime: TReferenceTime; out EndTime: TReferenceTime): HResult;
  2029. override;
  2030. function SendQuality(Late, RealStream: TReferenceTime): HResult; virtual;
  2031. // milenko start (TBCBaseFilter made virtual, so just add override here)
  2032. function JoinFilterGraph(Graph: IFilterGraph; Name: PWideChar): HResult; override;
  2033. // milenko end
  2034. //
  2035. // Do estimates for standard deviations for per-frame
  2036. // statistics
  2037. //
  2038. // *piResult = (llSumSq - iTot * iTot / m_cFramesDrawn - 1) /
  2039. // (m_cFramesDrawn - 2)
  2040. // or 0 if m_cFramesDrawn <= 3
  2041. //
  2042. function GetStdDev(Samples: Integer; out Res: Integer;
  2043. SumSq, Tot: Int64): HResult;
  2044. // IQualProp property page support
  2045. // ??? out <- var function get_FramesDroppedInRenderer(out pcFrames : Integer) : HResult; stdcall;
  2046. function get_FramesDroppedInRenderer(var FramesDropped: Integer): HResult;
  2047. stdcall;
  2048. function get_FramesDrawn(out FramesDrawn: Integer): HResult; stdcall;
  2049. function get_AvgFrameRate(out AvgFrameRate: Integer): HResult; stdcall;
  2050. function get_Jitter(out Jitter: Integer): HResult; stdcall;
  2051. function get_AvgSyncOffset(out Avg: Integer): HResult; stdcall;
  2052. function get_DevSyncOffset(out Dev: Integer): HResult; stdcall;
  2053. end;
  2054. // milenko start (added TBCPullPin)
  2055. //
  2056. // CPullPin
  2057. //
  2058. // object supporting pulling data from an IAsyncReader interface.
  2059. // Given a start/stop position, calls a pure Receive method with each
  2060. // IMediaSample received.
  2061. //
  2062. // This is essentially for use in a MemInputPin when it finds itself
  2063. // connected to an IAsyncReader pin instead of a pushing pin.
  2064. //
  2065. TThreadMsg = (
  2066. TM_Pause, // stop pulling and wait for next message
  2067. TM_Start, // start pulling
  2068. TM_Exit // stop and exit
  2069. );
  2070. TBCPullPin = class(TBCAMThread)
  2071. private
  2072. FReader: IAsyncReader;
  2073. FStart: TReferenceTime;
  2074. FStop: TReferenceTime;
  2075. FDuration: TReferenceTime;
  2076. FSync: Boolean;
  2077. FState: TThreadMsg;
  2078. // running pull method (check m_bSync)
  2079. procedure Process;
  2080. // clean up any cancelled i/o after a flush
  2081. procedure CleanupCancelled;
  2082. // suspend thread from pulling, eg during seek
  2083. function PauseThread: HRESULT;
  2084. // start thread pulling - create thread if necy
  2085. function StartThread: HRESULT;
  2086. // stop and close thread
  2087. function StopThread: HRESULT;
  2088. // called from ProcessAsync to queue and collect requests
  2089. function QueueSample(var tCurrent: TReferenceTime; tAlignStop: TReferenceTime; bDiscontinuity: Boolean): HRESULT;
  2090. function CollectAndDeliver(tStart,tStop: TReferenceTime): HRESULT;
  2091. function DeliverSample(pSample: IMediaSample; tStart,tStop: TReferenceTime): HRESULT;
  2092. protected
  2093. FAlloc: IMemAllocator;
  2094. // override pure thread proc from CAMThread
  2095. function ThreadProc: DWord; override;
  2096. public
  2097. constructor Create;
  2098. destructor Destroy; override;
  2099. // returns S_OK if successfully connected to an IAsyncReader interface
  2100. // from this object
  2101. // Optional allocator should be proposed as a preferred allocator if
  2102. // necessary
  2103. // bSync is TRUE if we are to use sync reads instead of the
  2104. // async methods.
  2105. function Connect(pUnk: IUnknown; pAlloc: IMemAllocator; bSync: Boolean): HRESULT;
  2106. // disconnect any connection made in Connect
  2107. function Disconnect: HRESULT;
  2108. // agree an allocator using RequestAllocator - optional
  2109. // props param specifies your requirements (non-zero fields).
  2110. // returns an error code if fail to match requirements.
  2111. // optional IMemAllocator interface is offered as a preferred allocator
  2112. // but no error occurs if it can't be met.
  2113. function DecideAllocator(pAlloc: IMemAllocator; pProps: PAllocatorProperties): HRESULT;
  2114. // set start and stop position. if active, will start immediately at
  2115. // the new position. Default is 0 to duration
  2116. function Seek(tStart, tStop: TReferenceTime): HRESULT;
  2117. // return the total duration
  2118. function Duration(out ptDuration: TReferenceTime): HRESULT;
  2119. // start pulling data
  2120. function Active: HRESULT;
  2121. // stop pulling data
  2122. function Inactive: HRESULT;
  2123. // helper functions
  2124. function AlignDown(ll: Int64; lAlign: LongInt): Int64;
  2125. function AlignUp(ll: Int64; lAlign: LongInt): Int64;
  2126. // GetReader returns the (addrefed) IAsyncReader interface
  2127. // for SyncRead etc
  2128. function GetReader: IAsyncReader;
  2129. // -- pure --
  2130. // override this to handle data arrival
  2131. // return value other than S_OK will stop data
  2132. function Receive(Sample: IMediaSample): HRESULT; virtual; abstract;
  2133. // override this to handle end-of-stream
  2134. function EndOfStream: HRESULT; virtual; abstract;
  2135. // called on runtime errors that will have caused pulling
  2136. // to stop
  2137. // these errors are all returned from the upstream filter, who
  2138. // will have already reported any errors to the filtergraph.
  2139. procedure OnError(hr: HRESULT); virtual; abstract;
  2140. // flush this pin and all downstream
  2141. function BeginFlush: HRESULT; virtual; abstract;
  2142. function EndFlush: HRESULT; virtual; abstract;
  2143. end;
  2144. // milenko end
  2145. // milenko start (needed to access functions outside. usefull for Filter Development)
  2146. function CreateMemoryAllocator(out Allocator: IMemAllocator): HRESULT;
  2147. function AMGetWideString(Source: WideString; out Dest: PWideChar): HRESULT;
  2148. function CreatePosPassThru(Agg: IUnknown; Renderer: boolean; Pin: IPin; out PassThru: IUnknown): HRESULT; stdcall;
  2149. // milenko end
  2150. // milenko start reftime implementation
  2151. //------------------------------------------------------------------------------
  2152. // File: RefTime.h
  2153. //
  2154. // Desc: DirectShow base classes - defines CRefTime, a class that manages
  2155. // reference times.
  2156. //
  2157. // Copyright (c) 1992-2002 Microsoft Corporation. All rights reserved.
  2158. //------------------------------------------------------------------------------
  2159. //
  2160. // CRefTime
  2161. //
  2162. // Manage reference times.
  2163. // Shares same data layout as REFERENCE_TIME, but adds some (nonvirtual)
  2164. // functions providing simple comparison, conversion and arithmetic.
  2165. //
  2166. // A reference time (at the moment) is a unit of seconds represented in
  2167. // 100ns units as is used in the Win32 FILETIME structure. BUT the time
  2168. // a REFERENCE_TIME represents is NOT the time elapsed since 1/1/1601 it
  2169. // will either be stream time or reference time depending upon context
  2170. //
  2171. // This class provides simple arithmetic operations on reference times
  2172. //
  2173. // keep non-virtual otherwise the data layout will not be the same as
  2174. // REFERENCE_TIME
  2175. // -----
  2176. // note that you are safe to cast a CRefTime* to a REFERENCE_TIME*, but
  2177. // you will need to do so explicitly
  2178. // -----
  2179. type
  2180. TBCRefTime = object
  2181. public
  2182. // *MUST* be the only data member so that this class is exactly
  2183. // equivalent to a REFERENCE_TIME.
  2184. // Also, must be *no virtual functions*
  2185. FTime: TReferenceTime;
  2186. // DCODER: using Create_ as contructor replacement ...
  2187. procedure Create_; overload;
  2188. procedure Create_(msecs: Longint); overload;
  2189. // delphi 5 doesn't like "const rt: TBCRefTime" ???
  2190. function SetTime(var rt: TBCRefTime): TBCRefTime; overload;
  2191. function SetTime(var ll: LONGLONG): TBCRefTime; overload;
  2192. function AddTime(var rt: TBCRefTime): TBCRefTime; overload;
  2193. function SubstractTime(var rt: TBCRefTime): TBCRefTime; overload;
  2194. function Millisecs: Longint;
  2195. function GetUnits: LONGLONG;
  2196. end;
  2197. // milenko end;
  2198. // milenko start schedule implementation
  2199. //------------------------------------------------------------------------------
  2200. // File: Schedule.cpp
  2201. //
  2202. // Desc: DirectShow base classes.
  2203. //
  2204. // Copyright (c) 1996-2002 Microsoft Corporation. All rights reserved.
  2205. //------------------------------------------------------------------------------
  2206. type
  2207. TBCAdvisePacket = class
  2208. public
  2209. FNext : TBCAdvisePacket;
  2210. FAdviseCookie: DWORD;
  2211. FEventTime : TReferenceTime; // Time at which event should be set
  2212. FPeriod : TReferenceTime; // Periodic time
  2213. FNotify : THandle; // Handle to event or semephore
  2214. FPeriodic : Boolean; // TRUE => Periodic event
  2215. constructor Create; overload;
  2216. constructor Create(Next: TBCAdvisePacket; Time: LONGLONG); overload;
  2217. procedure InsertAfter(Packet: TBCAdvisePacket);
  2218. // That is, is it the node that represents the end of the list
  2219. function IsZ: Boolean;
  2220. function RemoveNext: TBCAdvisePacket;
  2221. procedure DeleteNext;
  2222. function Next: TBCAdvisePacket;
  2223. function Cookie: DWORD;
  2224. end;
  2225. TBCAMSchedule = class(TBCBaseObject)
  2226. private
  2227. // Structure is:
  2228. // head -> elmt1 -> elmt2 -> z -> null
  2229. // So an empty list is: head -> z -> null
  2230. // Having head & z as links makes insertaion,
  2231. // deletion and shunting much easier.
  2232. FHead,
  2233. FZ : TBCAdvisePacket; // z is both a tail and a sentry
  2234. FNextCookie : DWORD; // Strictly increasing
  2235. FAdviseCount: DWORD; // Number of elements on list
  2236. FSerialize : TBCCritSec;
  2237. // Event that we should set if the packed added above will be the next to fire.
  2238. FEvent : THandle;
  2239. // Rather than delete advise packets, we cache them for future use
  2240. FAdviseCache: TBCAdvisePacket;
  2241. FCacheCount : DWORD;
  2242. // AddAdvisePacket: adds the packet, returns the cookie (0 if failed)
  2243. function AddAdvisePacket(Packet: TBCAdvisePacket): DWORD; overload;
  2244. // A Shunt is where we have changed the first element in the
  2245. // list and want it re-evaluating (i.e. repositioned) in
  2246. // the list.
  2247. procedure ShuntHead;
  2248. procedure Delete(Packet: TBCAdvisePacket);// This "Delete" will cache the Link
  2249. public
  2250. // ev is the event we should fire if the advise time needs re-evaluating
  2251. constructor Create(Event: THandle);
  2252. destructor Destroy; override;
  2253. function GetAdviseCount: DWORD;
  2254. function GetNextAdviseTime: TReferenceTime;
  2255. // We need a method for derived classes to add advise packets, we return the cookie
  2256. function AddAdvisePacket(const Time1, Time2: TReferenceTime; h: THandle;
  2257. Periodic: Boolean): DWORD; overload;
  2258. // And a way to cancel
  2259. function Unadvise(AdviseCookie: DWORD): HRESULT;
  2260. // Tell us the time please, and we'll dispatch the expired events.
  2261. // We return the time of the next event.
  2262. // NB: The time returned will be "useless" if you start adding extra Advises.
  2263. // But that's the problem of
  2264. // whoever is using this helper class (typically a clock).
  2265. function Advise(const Time_: TReferenceTime): TReferenceTime;
  2266. // Get the event handle which will be set if advise time requires re-evaluation.
  2267. function GetEvent: THandle;
  2268. procedure DumpLinkedList;
  2269. end;
  2270. // milenko end
  2271. // milenko start refclock implementation
  2272. //------------------------------------------------------------------------------
  2273. // File: RefClock.h
  2274. //
  2275. // Desc: DirectShow base classes - defines the IReferenceClock interface.
  2276. //
  2277. // Copyright (c) 1992-2002 Microsoft Corporation. All rights reserved.
  2278. //------------------------------------------------------------------------------
  2279. (* This class hierarchy will support an IReferenceClock interface so
  2280. that an audio card (or other externally driven clock) can update the
  2281. system wide clock that everyone uses.
  2282. The interface will be pretty thin with probably just one update method
  2283. This interface has not yet been defined.
  2284. *)
  2285. (* This abstract base class implements the IReferenceClock
  2286. * interface. Classes that actually provide clock signals (from
  2287. * whatever source) have to be derived from this class.
  2288. *
  2289. * The abstract class provides implementations for:
  2290. * CUnknown support
  2291. * locking support (CCritSec)
  2292. * client advise code (creates a thread)
  2293. *
  2294. * Question: what can we do about quality? Change the timer
  2295. * resolution to lower the system load? Up the priority of the
  2296. * timer thread to force more responsive signals?
  2297. *
  2298. * During class construction we create a worker thread that is destroyed during
  2299. * destuction. This thread executes a series of WaitForSingleObject calls,
  2300. * waking up when a command is given to the thread or the next wake up point
  2301. * is reached. The wakeup points are determined by clients making Advise
  2302. * calls.
  2303. *
  2304. * Each advise call defines a point in time when they wish to be notified. A
  2305. * periodic advise is a series of these such events. We maintain a list of
  2306. * advise links and calculate when the nearest event notification is due for.
  2307. * We then call WaitForSingleObject with a timeout equal to this time. The
  2308. * handle we wait on is used by the class to signal that something has changed
  2309. * and that we must reschedule the next event. This typically happens when
  2310. * someone comes in and asks for an advise link while we are waiting for an
  2311. * event to timeout.
  2312. *
  2313. * While we are modifying the list of advise requests we
  2314. * are protected from interference through a critical section. Clients are NOT
  2315. * advised through callbacks. One shot clients have an event set, while
  2316. * periodic clients have a semaphore released for each event notification. A
  2317. * semaphore allows a client to be kept up to date with the number of events
  2318. * actually triggered and be assured that they can't miss multiple events being
  2319. * set.
  2320. *
  2321. * Keeping track of advises is taken care of by the CAMSchedule class.
  2322. *)
  2323. type
  2324. TBCBaseReferenceClock = class(TBCUnknown, IReferenceClock)
  2325. private
  2326. FLock : TBCCritSec;
  2327. FAbort : Boolean; // Flag used for thread shutdown
  2328. FThread : THandle; // Thread handle
  2329. FPrivateTime : TReferenceTime; // Current best estimate of time
  2330. FPrevSystemTime : DWORD; // Last vaule we got from timeGetTime
  2331. FLastGotTime : TReferenceTime; // Last time returned by GetTime
  2332. FNextAdvise : TReferenceTime; // Time of next advise
  2333. FTimerResolution: DWORD;
  2334. {$IFDEF PERF}
  2335. FGetSystemTime : integer;
  2336. {$ENDIF}
  2337. function AdviseThread: HRESULT; // Method in which the advise thread runs
  2338. protected
  2339. FSchedule : TBCAMSchedule;
  2340. public
  2341. constructor Create(Name: String; Unk: IUnknown; out hr: HRESULT; Sched:
  2342. TBCAMSchedule = nil);
  2343. destructor Destroy; override; // Don't let me be created on the stack!
  2344. function NonDelegatingQueryInterface(const IID: TGUID; out Obj): HResult; override; stdcall;
  2345. // IReferenceClock methods
  2346. // Derived classes must implement GetPrivateTime(). All our GetTime
  2347. // does is call GetPrivateTime and then check so that time does not
  2348. // go backwards. A return code of S_FALSE implies that the internal
  2349. // clock has gone backwards and GetTime time has halted until internal
  2350. // time has caught up. (Don't know if this will be much use to folk,
  2351. // but it seems odd not to use the return code for something useful.)
  2352. function GetTime(out Time: int64): HResult; stdcall;
  2353. // When this is called, it sets m_rtLastGotTime to the time it returns.
  2354. // Provide standard mechanisms for scheduling events
  2355. // Ask for an async notification that a time has elapsed */
  2356. function AdviseTime(
  2357. BaseTime, // base reference time
  2358. StreamTime: int64; // stream offset time
  2359. Event: THandle; // advise via this event
  2360. out AdviseCookie: DWORD // where your cookie goes
  2361. ): HResult; stdcall;
  2362. // Ask for an asynchronous periodic notification that a time has elapsed
  2363. function AdvisePeriodic(
  2364. const StartTime, // starting at this time
  2365. PeriodTime: int64; // time between notifications
  2366. Semaphore: THandle; // advise via a semaphore
  2367. out AdviseCookie: DWORD // where your cookie goes
  2368. ): HResult; stdcall;
  2369. (* Cancel a request for notification(s) - if the notification was
  2370. * a one shot timer then this function doesn't need to be called
  2371. * as the advise is automatically cancelled, however it does no
  2372. * harm to explicitly cancel a one-shot advise. It is REQUIRED that
  2373. * clients call Unadvise to clear a Periodic advise setting.
  2374. *)
  2375. function Unadvise(AdviseCookie: DWORD): HResult; stdcall;
  2376. // Methods for the benefit of derived classes or outer objects
  2377. // GetPrivateTime() is the REAL clock. GetTime is just a cover for
  2378. // it. Derived classes will probably override this method but not
  2379. // GetTime() itself.
  2380. // The important point about GetPrivateTime() is it's allowed to go
  2381. // backwards. Our GetTime() will keep returning the LastGotTime
  2382. // until GetPrivateTime() catches up.
  2383. function GetPrivateTime: TReferenceTime; virtual;
  2384. // Provide a method for correcting drift
  2385. function SetTimeDelta(const TimeDelta: TReferenceTime): HRESULT; stdcall;
  2386. function GetSchedule: TBCAMSchedule;
  2387. // Thread stuff
  2388. // Wakes thread up. Need to do this if time to next advise needs reevaluating.
  2389. procedure TriggerThread;
  2390. end;
  2391. // milenko end
  2392. // milenko start sysclock implementation
  2393. //------------------------------------------------------------------------------
  2394. // File: SysClock.h
  2395. //
  2396. // Desc: DirectShow base classes - defines a system clock implementation of
  2397. // IReferenceClock.
  2398. //
  2399. // Copyright (c) 1992-2002 Microsoft Corporation. All rights reserved.
  2400. //------------------------------------------------------------------------------
  2401. const
  2402. IID_IPersist : TGUID = '{0000010C-0000-0000-C000-000000000046}';
  2403. type
  2404. TBCSystemClock = class(TBCBaseReferenceClock, IAMClockAdjust, IPersist)
  2405. public
  2406. constructor Create(Name: WideString; Unk : IUnknown; out hr : HRESULT);
  2407. function NonDelegatingQueryInterface(const IID: TGUID; out Obj): HResult; override; stdcall;
  2408. // Yield up our class id so that we can be persisted
  2409. // Implement required Ipersist method
  2410. function GetClassID(out classID: TCLSID): HResult; stdcall;
  2411. // IAMClockAdjust methods
  2412. function SetClockDelta(rtDelta: TReferenceTime): HResult; stdcall;
  2413. end;
  2414. {$IFDEF DEBUG}
  2415. procedure DbgLog(obj: TBCBaseObJect; const msg: string); overload;
  2416. procedure DbgLog(const msg: string); overload;
  2417. procedure DbgAssert(const Message, Filename: string; LineNumber: Integer;
  2418. ErrorAddr: Pointer);
  2419. {$ENDIF}
  2420. function DllGetClassObject(const CLSID, IID: TGUID; var Obj): HResult; stdcall;
  2421. function DllCanUnloadNow: HResult; stdcall;
  2422. function DllRegisterServer: HResult; stdcall;
  2423. function DllUnregisterServer: HResult; stdcall;
  2424. (* milenko start (needed for TBCBaseReferenceClock and TBCVideoTransformFilter ) *)
  2425. {$IFDEF PERF}
  2426. procedure MSR_START(Id_: Integer);
  2427. procedure MSR_STOP(Id_: Integer);
  2428. procedure MSR_INTEGER(Id_, i: Integer);
  2429. function MSR_REGISTER(s: String): Integer;
  2430. {$ENDIF}
  2431. (* milenko end *)
  2432. implementation
  2433. var
  2434. ObjectCount : Integer;
  2435. FactoryCount : Integer;
  2436. TemplatesVar : TBCFilterTemplate;
  2437. // milenko start (added global variables instead of local constants)
  2438. IsCheckedVersion: Bool = False;
  2439. IsTimeKillSynchronousFlagAvailable: Bool = False;
  2440. MsgId: Cardinal = 0;
  2441. // milenko end
  2442. {$IFDEF DEBUG}
  2443. {$IFNDEF MESSAGE}
  2444. DebugFile : TextFile;
  2445. {$ENDIF}
  2446. procedure DbgLog(obj: TBCBaseObJect; const msg: string);
  2447. begin
  2448. {$IFNDEF MESSAGE}
  2449. if (obj = nil) then
  2450. Writeln(DebugFile, TimeToStr(time) +' > '+ msg) else
  2451. Writeln(DebugFile, TimeToStr(time) +' > '+ format('Object: %s, msg: %s.',[obj.FName, msg]));
  2452. Flush(DebugFile);
  2453. {$ELSE}
  2454. if (obj = nil) then OutputDebugString(PChar(TimeToStr(time) +' > '+ msg)) else
  2455. OutputDebugString(PChar(TimeToStr(time) +' > '+ format('Object: %s, msg: %s.',[obj.FName, msg])));
  2456. {$ENDIF}
  2457. end;
  2458. procedure DbgLog(const msg: string); overload;
  2459. begin
  2460. {$IFNDEF MESSAGE}
  2461. Writeln(DebugFile, TimeToStr(time) +' > '+ msg);
  2462. Flush(DebugFile);
  2463. {$ELSE}
  2464. OutputDebugString(PChar(TimeToStr(time) +' > '+ msg));
  2465. {$ENDIF}
  2466. end;
  2467. procedure DbgAssert(const Message, Filename: string; LineNumber: Integer;
  2468. ErrorAddr: Pointer);
  2469. begin
  2470. DbgLog(format('[ASSERT] %s (%s) line: %d, adr: $%x',
  2471. [Message, Filename, LineNumber, Integer(ErrorAddr)]));
  2472. end;
  2473. {$ENDIF}
  2474. // -----------------------------------------------------------------------------
  2475. // TBCMediaType
  2476. // -----------------------------------------------------------------------------
  2477. function TBCMediaType.Equal(mt: TBCMediaType): boolean;
  2478. begin
  2479. result := ((IsEqualGUID(Mediatype.majortype,mt.MediaType.majortype) = True) and
  2480. (IsEqualGUID(Mediatype.subtype,mt.MediaType.subtype) = True) and
  2481. (IsEqualGUID(Mediatype.formattype,mt.MediaType.formattype) = True) and
  2482. (Mediatype.cbFormat = mt.MediaType.cbFormat) and
  2483. ( (Mediatype.cbFormat = 0) or
  2484. (CompareMem(Mediatype.pbFormat, mt.MediaType.pbFormat, Mediatype.cbFormat))));
  2485. end;
  2486. function TBCMediaType.Equal(mt: PAMMediaType): boolean;
  2487. begin
  2488. result := ((IsEqualGUID(Mediatype.majortype,mt.majortype) = True) and
  2489. (IsEqualGUID(Mediatype.subtype,mt.subtype) = True) and
  2490. (IsEqualGUID(Mediatype.formattype,mt.formattype) = True) and
  2491. (Mediatype.cbFormat = mt.cbFormat) and
  2492. ( (Mediatype.cbFormat = 0) or
  2493. (CompareMem(Mediatype.pbFormat, mt.pbFormat, Mediatype.cbFormat))));
  2494. end;
  2495. function TBCMediaType.MatchesPartial(Partial: PAMMediaType): boolean;
  2496. begin
  2497. result := false;
  2498. if (not IsEqualGUID(partial.majortype, GUID_NULL) and
  2499. not IsEqualGUID(MediaType.majortype, partial.majortype)) then exit;
  2500. if (not IsEqualGUID(partial.subtype, GUID_NULL) and
  2501. not IsEqualGUID(MediaType.subtype, partial.subtype)) then exit;
  2502. if not IsEqualGUID(partial.formattype, GUID_NULL) then
  2503. begin
  2504. if not IsEqualGUID(MediaType.formattype, partial.formattype) then exit;
  2505. if (MediaType.cbFormat <> partial.cbFormat) then exit;
  2506. if ((MediaType.cbFormat <> 0) and
  2507. (CompareMem(MediaType.pbFormat, partial.pbFormat, MediaType.cbFormat) <> false)) then exit;
  2508. end;
  2509. result := True;
  2510. end;
  2511. function TBCMediaType.IsPartiallySpecified: boolean;
  2512. begin
  2513. if (IsEqualGUID(Mediatype.majortype, GUID_NULL) or
  2514. IsEqualGUID(Mediatype.formattype, GUID_NULL)) then result := True
  2515. else result := false;
  2516. end;
  2517. function TBCMediaType.IsValid: boolean;
  2518. begin
  2519. result := not IsEqualGUID(MediaType.majortype,GUID_NULL);
  2520. end;
  2521. procedure TBCMediaType.InitMediaType;
  2522. begin
  2523. ZeroMemory(MediaType, sizeof(TAMMediaType));
  2524. MediaType.lSampleSize := 1;
  2525. MediaType.bFixedSizeSamples := True;
  2526. end;
  2527. function TBCMediaType.FormatLength: Cardinal;
  2528. begin
  2529. result := MediaType.cbFormat
  2530. end;
  2531. // -----------------------------------------------------------------------------
  2532. // milenko start
  2533. function AMGetWideString(Source: WideString; out Dest: PWideChar): HRESULT;
  2534. var NameLen: Cardinal;
  2535. begin
  2536. if not assigned(@Dest) then
  2537. begin
  2538. Result := E_POINTER;
  2539. Exit;
  2540. end;
  2541. nameLen := sizeof(WCHAR) * (length(source)+1);
  2542. Dest := CoTaskMemAlloc(nameLen);
  2543. if (Dest = nil) then
  2544. begin
  2545. Result := E_OUTOFMEMORY;
  2546. Exit;
  2547. end;
  2548. CopyMemory(Dest, PWideChar(Source), nameLen);
  2549. Result := NOERROR;
  2550. end;
  2551. {
  2552. function AMGetWideString(Source: WideString; out Dest: PWideChar): HRESULT;
  2553. type TWideCharArray = array of WideChar;
  2554. var NameLen: Cardinal;
  2555. begin
  2556. if Source = '' then
  2557. begin
  2558. dest := nil;
  2559. result := S_OK;
  2560. exit;
  2561. end;
  2562. assert(@dest <> nil);
  2563. nameLen := (length(Source)+1)*2;
  2564. Dest := CoTaskMemAlloc(nameLen);
  2565. if(Dest = nil) then
  2566. begin
  2567. result := E_OUTOFMEMORY;
  2568. exit;
  2569. end;
  2570. CopyMemory(dest, pointer(Source), nameLen-1);
  2571. TWideCharArray(dest)[(nameLen div 2)-1] := #0;
  2572. result := NOERROR;
  2573. end;
  2574. }
  2575. // milenko end
  2576. // -----------------------------------------------------------------------------
  2577. function CreateMemoryAllocator(out Allocator: IMemAllocator): HRESULT;
  2578. begin
  2579. result := CoCreateInstance(CLSID_MemoryAllocator, nil, CLSCTX_INPROC_SERVER,
  2580. IID_IMemAllocator, Allocator);
  2581. end;
  2582. // Put this one here rather than in ctlutil.cpp to avoid linking
  2583. // anything brought in by ctlutil.cpp
  2584. function CreatePosPassThru(Agg: IUnknown; Renderer: boolean; Pin: IPin; out PassThru: IUnknown): HRESULT; stdcall;
  2585. var
  2586. UnkSeek: IUnknown;
  2587. APassThru: ISeekingPassThru;
  2588. begin
  2589. PassThru := nil;
  2590. result := CoCreateInstance(CLSID_SeekingPassThru, Agg, CLSCTX_INPROC_SERVER,
  2591. IUnknown, UnkSeek);
  2592. if FAILED(result) then exit;
  2593. result := UnkSeek.QueryInterface(IID_ISeekingPassThru, APassThru);
  2594. if FAILED(result) then
  2595. begin
  2596. UnkSeek := nil;
  2597. exit;
  2598. end;
  2599. result := APassThru.Init(Renderer, Pin);
  2600. APassThru := nil;
  2601. if FAILED(result) then
  2602. begin
  2603. UnkSeek := nil;
  2604. exit;
  2605. end;
  2606. PassThru := UnkSeek;
  2607. result := S_OK;
  2608. end;
  2609. // -----------------------------------------------------------------------------
  2610. function Templates: TBCFilterTemplate;
  2611. begin
  2612. if TemplatesVar = nil then TemplatesVar := TBCFilterTemplate.Create;
  2613. result := TemplatesVar;
  2614. end;
  2615. function DllGetClassObject(const CLSID, IID: TGUID; var Obj): HResult; stdcall;
  2616. var
  2617. Factory: TBCClassFactory;
  2618. begin
  2619. Factory := Templates.GetFactoryFromClassID(CLSID);
  2620. if Factory <> nil then
  2621. if Factory.GetInterface(IID, Obj) then
  2622. Result := S_OK
  2623. else
  2624. Result := E_NOINTERFACE
  2625. else
  2626. begin
  2627. Pointer(Obj) := nil;
  2628. Result := CLASS_E_CLASSNOTAVAILABLE;
  2629. end;
  2630. end;
  2631. function DllCanUnloadNow: HResult; stdcall;
  2632. begin
  2633. if (ObjectCount = 0) and (FactoryCount = 0) then
  2634. result := S_OK else result := S_FALSE;;
  2635. end;
  2636. function DllRegisterServer: HResult; stdcall;
  2637. begin
  2638. if Templates.RegisterServer(True) then result := S_OK else result := E_FAIL;
  2639. end;
  2640. function DllUnregisterServer: HResult; stdcall;
  2641. begin
  2642. if Templates.RegisterServer(false) then result := S_OK else result := E_FAIL;
  2643. end;
  2644. { TBCClassFactory }
  2645. constructor TBCClassFactory.CreateFilter(ComClass: TBCUnknownClass; Name: string;
  2646. const ClassID: TGUID; const Category: TGUID; Merit: LongWord;
  2647. PinCount: Cardinal; Pins: PRegFilterPins);
  2648. begin
  2649. Templates.AddObjectFactory(Self);
  2650. FComClass := ComClass;
  2651. FName := Name;
  2652. FClassID := ClassID;
  2653. FCategory := Category;
  2654. FMerit := Merit;
  2655. FPinCount := PinCount;
  2656. FPins := Pins;
  2657. end;
  2658. constructor TBCClassFactory.CreatePropertyPage(ComClass: TFormPropertyPageClass; const ClassID: TGUID);
  2659. begin
  2660. Templates.AddObjectFactory(Self);
  2661. FPropClass := ComClass;
  2662. FClassID := ClassID;
  2663. FCategory := ClassID;
  2664. end;
  2665. function TBCClassFactory.CreateInstance(const unkOuter: IUnKnown;
  2666. const iid: TIID; out obj): HResult;
  2667. var
  2668. ComObject: TBCUnknown;
  2669. PropObject: TFormPropertyPage;
  2670. begin
  2671. if @obj = nil then
  2672. begin
  2673. Result := E_POINTER;
  2674. Exit;
  2675. end;
  2676. Pointer(obj) := nil;
  2677. if FPropClass <> nil then
  2678. begin
  2679. PropObject := TFormPropertyPageClass(FPropClass).Create(nil);
  2680. PropObject.FPropertyPage := TBCBasePropertyPage.Create('',nil, PropObject);
  2681. Result := PropObject.QueryInterface(IID, obj);
  2682. end
  2683. else
  2684. begin
  2685. ComObject := TBCUnknownClass(FComClass).CreateFromFactory(self, unkOuter);
  2686. Result := ComObject.QueryInterface(IID, obj);
  2687. if ComObject.FRefCount = 0 then ComObject.Free;
  2688. end;
  2689. end;
  2690. procedure TBCClassFactory.UpdateRegistry(Register: Boolean);
  2691. var
  2692. FileName: array[0..MAX_PATH-1] of Char;
  2693. ClassID, ServerKeyName: String;
  2694. begin
  2695. ClassID := GUIDToString(FClassID);
  2696. ServerKeyName := 'CLSID\' + ClassID + '\' + 'InprocServer32';
  2697. if Register then
  2698. begin
  2699. CreateRegKey('CLSID\' + ClassID, '', FName);
  2700. GetModuleFileName(hinstance, FileName, MAX_PATH);
  2701. CreateRegKey(ServerKeyName, '', FileName);
  2702. CreateRegKey(ServerKeyName, 'ThreadingModel', 'Both');
  2703. end else
  2704. begin
  2705. DeleteRegKey(ServerKeyName);
  2706. DeleteRegKey('CLSID\' + ClassID);
  2707. end;
  2708. end;
  2709. function TBCClassFactory.RegisterFilter(FilterMapper: IFilterMapper; Register: Boolean): boolean;
  2710. type
  2711. TDynArrayPins = array of TRegFilterPins;
  2712. TDynArrayPinType = array of TRegPinTypes;
  2713. var
  2714. i, j: integer;
  2715. FilterGUID: TGUID;
  2716. begin
  2717. result := Succeeded(FilterMapper.UnregisterFilter(FClassID));
  2718. if Register then
  2719. begin
  2720. result := Succeeded(FilterMapper.RegisterFilter(FClassID, StringToOleStr(FName), FMerit));
  2721. if result then
  2722. begin
  2723. for i := 0 to FPinCount - 1 do
  2724. begin
  2725. if TDynArrayPins(FPins)[i].oFilter = nil then
  2726. FilterGUID := GUID_NULL else
  2727. FilterGUID := TDynArrayPins(FPins)[i].oFilter^;
  2728. result := Succeeded(FilterMapper.RegisterPin(FClassID,
  2729. TDynArrayPins(FPins)[i].strName,
  2730. TDynArrayPins(FPins)[i].bRendered,
  2731. TDynArrayPins(FPins)[i].bOutput,
  2732. TDynArrayPins(FPins)[i].bZero,
  2733. TDynArrayPins(FPins)[i].bMany,
  2734. FilterGUID,
  2735. TDynArrayPins(FPins)[i].strConnectsToPin));
  2736. if result then
  2737. begin
  2738. for j := 0 to TDynArrayPins(FPins)[i].nMediaTypes - 1 do
  2739. begin
  2740. result := Succeeded(FilterMapper.RegisterPinType(FClassID,
  2741. TDynArrayPins(FPins)[i].strName,
  2742. TDynArrayPinType(TDynArrayPins(FPins)[i].lpMediaType)[j].clsMajorType^,
  2743. TDynArrayPinType(TDynArrayPins(FPins)[i].lpMediaType)[j].clsMinorType^));
  2744. if not result then break;
  2745. end;
  2746. if not result then break;
  2747. end;
  2748. if not result then break;
  2749. end;
  2750. end;
  2751. end;
  2752. end;
  2753. function TBCClassFactory.RegisterFilter(FilterMapper: IFilterMapper2; Register: Boolean): boolean;
  2754. var
  2755. RegFilter: TRegFilter2;
  2756. begin
  2757. result := Succeeded(FilterMapper.UnregisterFilter(FCategory, nil, FClassID));
  2758. // milenko start (bugfix for Windows 98)
  2759. // Windows 98 fails when unregistering a Property Page, so the whole
  2760. // DLLUnregisterServer function fails without unregistering the Filter.
  2761. if not result and not Register and (FName = '') then Result := True;
  2762. // milenko end
  2763. if Register then
  2764. begin
  2765. RegFilter.dwVersion := 1;
  2766. RegFilter.dwMerit := FMerit;
  2767. RegFilter.cPins := FPinCount;
  2768. RegFilter.rgPins := FPins;
  2769. result := Succeeded(FilterMapper.RegisterFilter(FClassID, PWideChar(WideString(FName)),
  2770. nil, @FCategory, nil, RegFilter));
  2771. end;
  2772. end;
  2773. function TBCClassFactory._AddRef: Integer;
  2774. begin
  2775. result := InterlockedIncrement(FactoryCount);
  2776. end;
  2777. function TBCClassFactory._Release: Integer;
  2778. begin
  2779. result := InterlockedDecrement(FactoryCount);
  2780. end;
  2781. function TBCClassFactory.LockServer(fLock: BOOL): HResult;
  2782. begin
  2783. Result := CoLockObjectExternal(Self, fLock, True);
  2784. if flock then InterlockedIncrement(ObjectCount)
  2785. else InterlockedDecrement(ObjectCount);
  2786. end;
  2787. function TBCClassFactory.QueryInterface(const IID: TGUID; out Obj): HResult;
  2788. begin
  2789. if GetInterface(IID, Obj) then Result := S_OK else Result := E_NOINTERFACE;
  2790. end;
  2791. { TBCFilterTemplate }
  2792. procedure TBCFilterTemplate.AddObjectFactory(Factory: TBCClassFactory);
  2793. begin
  2794. Factory.FNext := FFactoryList;
  2795. FFactoryList := Factory;
  2796. end;
  2797. constructor TBCFilterTemplate.Create;
  2798. begin
  2799. FFactoryList := nil;
  2800. end;
  2801. destructor TBCFilterTemplate.Destroy;
  2802. var AFactory: TBCClassFactory;
  2803. begin
  2804. while FFactoryList <> nil do
  2805. begin
  2806. AFactory := FFactoryList;
  2807. FFactoryList := AFactory.FNext;
  2808. AFactory.Free;
  2809. end;
  2810. inherited Destroy;
  2811. end;
  2812. function TBCFilterTemplate.GetFactoryFromClassID(const CLSID: TGUID): TBCClassFactory;
  2813. var AFactory: TBCClassFactory;
  2814. begin
  2815. result := nil;
  2816. AFactory := FFactoryList;
  2817. while AFactory <> nil do
  2818. begin
  2819. if IsEqualGUID(CLSID, AFactory.FClassID) then
  2820. begin
  2821. result := AFactory;
  2822. break;
  2823. end;
  2824. AFactory := AFactory.FNext;
  2825. end;
  2826. end;
  2827. function TBCFilterTemplate.RegisterServer(Register: Boolean): boolean;
  2828. var
  2829. {$IFDEF DEBUG}
  2830. Filename: array[0..MAX_PATH-1] of Char;
  2831. {$ENDIF}
  2832. FilterMapper : IFilterMapper;
  2833. FilterMapper2: IFilterMapper2;
  2834. Factory: TBCClassFactory;
  2835. begin
  2836. result := false;
  2837. {$IFDEF DEBUG}
  2838. GetModuleFileName(hinstance, Filename, sizeof(Filename));
  2839. DbgLog('TBCFilterTemplate.RegisterServer in ' + Filename);
  2840. {$ENDIF}
  2841. if Failed(CoCreateInstance(CLSID_FilterMapper2, nil, CLSCTX_INPROC_SERVER, IFilterMapper2, FilterMapper2)) then
  2842. if Failed(CoCreateInstance(CLSID_FilterMapper, nil, CLSCTX_INPROC_SERVER, IFilterMapper, FilterMapper)) then exit;
  2843. Factory := FFactoryList;
  2844. while Factory <> nil do
  2845. begin
  2846. Factory.UpdateRegistry(false);
  2847. if FilterMapper2 <> nil then
  2848. result := Factory.RegisterFilter(FilterMapper2, Register)
  2849. else result := Factory.RegisterFilter(FilterMapper, Register);
  2850. if not result then break else Factory.UpdateRegistry(register);
  2851. Factory := Factory.FNext;
  2852. end;
  2853. FilterMapper := nil;
  2854. FilterMapper2 := nil;
  2855. end;
  2856. { TBCBaseObject }
  2857. constructor TBCBaseObject.Create(Name: string);
  2858. begin
  2859. {$IFDEF DEBUG}
  2860. DbgLog('[' + ClassName + ': ' + Name + '] CREATE');
  2861. {$ENDIF}
  2862. FName := name;
  2863. end;
  2864. destructor TBCBaseObject.Destroy;
  2865. begin
  2866. {$IFDEF DEBUG}
  2867. DbgLog('[' + ClassName + ': ' + FName + '] FREE');
  2868. {$ENDIF}
  2869. inherited;
  2870. end;
  2871. procedure TBCBaseObject.FreeInstance;
  2872. begin
  2873. inherited;
  2874. InterlockedDecrement(ObjectCount);
  2875. end;
  2876. class function TBCBaseObject.NewInstance: TObject;
  2877. begin
  2878. result := inherited NewInstance;
  2879. InterlockedIncrement(ObjectCount);
  2880. end;
  2881. class function TBCBaseObject.ObjectsActive: integer;
  2882. begin
  2883. result := ObjectCount;
  2884. end;
  2885. { TBCUnknown }
  2886. function TBCUnknown.QueryInterface(const IID: TGUID; out Obj): HResult;
  2887. begin
  2888. if FOwner <> nil then
  2889. Result := IUnknown(FOwner).QueryInterface(IID, Obj)
  2890. else
  2891. Result := NonDelegatingQueryInterface(IID, Obj);
  2892. end;
  2893. function TBCUnknown._AddRef: Integer;
  2894. begin
  2895. if FOwner <> nil then
  2896. Result := IUnknown(FOwner)._AddRef else
  2897. Result := NonDelegatingAddRef;
  2898. end;
  2899. function TBCUnknown._Release: Integer;
  2900. begin
  2901. if FOwner <> nil then
  2902. Result := IUnknown(FOwner)._Release else
  2903. Result := NonDelegatingRelease;
  2904. end;
  2905. function TBCUnknown.NonDelegatingQueryInterface(const IID: TGUID;
  2906. out Obj): HResult;
  2907. begin
  2908. if GetInterface(IID, Obj) then Result := S_OK else Result := E_NOINTERFACE;
  2909. end;
  2910. function TBCUnknown.NonDelegatingAddRef: Integer;
  2911. begin
  2912. Result := InterlockedIncrement(FRefCount);
  2913. end;
  2914. function TBCUnknown.NonDelegatingRelease: Integer;
  2915. begin
  2916. Result := InterlockedDecrement(FRefCount);
  2917. if Result = 0 then Destroy;
  2918. end;
  2919. function TBCUnknown.GetOwner: IUnKnown;
  2920. begin
  2921. result := IUnKnown(FOwner);
  2922. end;
  2923. constructor TBCUnknown.Create(name: string; Unk: IUnKnown);
  2924. begin
  2925. inherited Create(name);
  2926. FOwner := Pointer(Unk);
  2927. end;
  2928. constructor TBCUnknown.CreateFromFactory(Factory: TBCClassFactory;
  2929. const Controller: IUnKnown);
  2930. begin
  2931. Create(Factory.FName, Controller);
  2932. end;
  2933. { TBCBaseFilter }
  2934. constructor TBCBaseFilter.Create(Name: string; Unk: IUnKnown;
  2935. Lock: TBCCritSec; const clsid: TGUID);
  2936. begin
  2937. inherited Create(Name, Unk);
  2938. FLock := Lock;
  2939. Fclsid := clsid;
  2940. FState := State_Stopped;
  2941. FClock := nil;
  2942. FGraph := nil;
  2943. FSink := nil;
  2944. FFilterName := '';
  2945. FPinVersion := 1;
  2946. Assert(FLock <> nil, 'Lock = nil !');
  2947. end;
  2948. constructor TBCBaseFilter.Create(Name: string; Unk: IUnKnown;
  2949. Lock: TBCCritSec; const clsid: TGUID; out hr: HRESULT);
  2950. begin
  2951. Create(Name, Unk, Lock, clsid);
  2952. assert(@hr <> nil, 'Unreferenced parameter: hr');
  2953. end;
  2954. constructor TBCBaseFilter.CreateFromFactory(Factory: TBCClassFactory; const Controller: IUnknown);
  2955. begin
  2956. Create(Factory.FName,Controller, TBCCritSec.Create, Factory.FClassID);
  2957. end;
  2958. destructor TBCBaseFilter.destroy;
  2959. begin
  2960. FFilterName := '';
  2961. FClock := nil;
  2962. FLock.Free;
  2963. inherited;
  2964. end;
  2965. function TBCBaseFilter.EnumPins(out ppEnum: IEnumPins): HRESULT;
  2966. begin
  2967. // Create a new ref counted enumerator
  2968. ppEnum := TBCEnumPins.Create(self, nil);
  2969. if ppEnum = nil then result := E_OUTOFMEMORY else result := NOERROR;
  2970. end;
  2971. function TBCBaseFilter.FindPin(Id: PWideChar; out Pin: IPin): HRESULT;
  2972. var
  2973. i: integer;
  2974. APin: TBCBasePin;
  2975. begin
  2976. // We're going to search the pin list so maintain integrity
  2977. FLock.Lock;
  2978. try
  2979. for i := 0 to GetPinCount - 1 do
  2980. begin
  2981. APin := GetPin(i);
  2982. ASSERT(APin <> nil);
  2983. if (APin.FPinName = WideString(Id)) then
  2984. begin
  2985. // Found one that matches
  2986. // AddRef() and return it
  2987. Pin := APin;
  2988. result := S_OK;
  2989. exit;
  2990. end;
  2991. end;
  2992. Pin := nil;
  2993. result := VFW_E_NOT_FOUND;
  2994. finally
  2995. FLock.UnLock;
  2996. end;
  2997. end;
  2998. function TBCBaseFilter.GetClassID(out classID: TCLSID): HResult;
  2999. begin
  3000. classID := FCLSID;
  3001. result := NOERROR;
  3002. end;
  3003. function TBCBaseFilter.GetFilterGraph: IFilterGraph;
  3004. begin
  3005. result := FGRaph;
  3006. end;
  3007. function TBCBaseFilter.GetPinVersion: LongInt;
  3008. begin
  3009. result := FPinVersion;
  3010. end;
  3011. function TBCBaseFilter.GetState(dwMilliSecsTimeout: DWORD;
  3012. out State: TFilterState): HRESULT;
  3013. begin
  3014. State := FState;
  3015. result := S_OK;
  3016. end;
  3017. function TBCBaseFilter.GetSyncSource(out pClock: IReferenceClock): HRESULT;
  3018. begin
  3019. FLock.Lock;
  3020. try
  3021. pClock := FClock;
  3022. finally
  3023. result := NOERROR;
  3024. FLock.UnLock;
  3025. end;
  3026. end;
  3027. procedure TBCBaseFilter.IncrementPinVersion;
  3028. begin
  3029. InterlockedIncrement(FPinVersion)
  3030. end;
  3031. function TBCBaseFilter.IsActive: boolean;
  3032. begin
  3033. FLock.Lock;
  3034. try
  3035. result := ((FState = State_Paused) or (FState = State_Running));
  3036. finally
  3037. FLock.UnLock;
  3038. end;
  3039. end;
  3040. function TBCBaseFilter.IsStopped: boolean;
  3041. begin
  3042. result := (FState = State_Stopped);
  3043. end;
  3044. function TBCBaseFilter.JoinFilterGraph(pGraph: IFilterGraph;
  3045. pName: PWideChar): HRESULT;
  3046. begin
  3047. FLock.Lock;
  3048. try
  3049. //Henri: This implementation seem to be stupid but it's the exact conversion ?????
  3050. // NOTE: we no longer hold references on the graph (m_pGraph, m_pSink)
  3051. Pointer(FGraph) := Pointer(pGraph);
  3052. if (FGraph <> nil) then
  3053. begin
  3054. if FAILED(FGraph.QueryInterface(IID_IMediaEventSink, FSink)) then
  3055. ASSERT(FSink = nil)
  3056. else FSink._Release; // we do NOT keep a reference on it.
  3057. end
  3058. else
  3059. begin
  3060. // if graph pointer is null, then we should
  3061. // also release the IMediaEventSink on the same object - we don't
  3062. // refcount it, so just set it to null
  3063. Pointer(FSink) := nil;
  3064. end;
  3065. FFilterName := '';
  3066. if assigned(pName) then FFilterName := WideString(pName);
  3067. result := NOERROR;
  3068. finally
  3069. FLock.UnLock;
  3070. end;
  3071. end;
  3072. function TBCBaseFilter.NotifyEvent(EventCode, EventParam1,
  3073. EventParam2: Integer): HRESULT;
  3074. var
  3075. Filter : IBaseFilter;
  3076. begin
  3077. // Snapshot so we don't have to lock up
  3078. if assigned(FSink) then
  3079. begin
  3080. QueryInterface(IID_IBaseFilter,Filter);
  3081. if (EC_COMPLETE = EventCode) then EventParam2 := LongInt(Filter);
  3082. result := FSink.Notify(EventCode, EventParam1, EventParam2);
  3083. Filter := nil;
  3084. end
  3085. else
  3086. result := E_NOTIMPL;
  3087. end;
  3088. function TBCBaseFilter.Pause: HRESULT;
  3089. var
  3090. c: integer;
  3091. pin: TBCBasePin;
  3092. begin
  3093. FLock.Lock;
  3094. try
  3095. if FState = State_Stopped then
  3096. begin
  3097. for c := 0 to GetPinCount - 1 do
  3098. begin
  3099. Pin := GetPin(c);
  3100. // Disconnected pins are not activated - this saves pins
  3101. // worrying about this state themselves
  3102. if Pin.IsConnected then
  3103. begin
  3104. result := Pin.Active;
  3105. if FAILED(result) then exit;
  3106. end;
  3107. end;
  3108. end;
  3109. // notify all pins of the change to active state
  3110. FState := State_Paused;
  3111. result := S_OK;
  3112. finally
  3113. FLock.UnLock;
  3114. end;
  3115. end;
  3116. function TBCBaseFilter.QueryFilterInfo(out pInfo: TFilterInfo): HRESULT;
  3117. var
  3118. len: Integer;
  3119. begin
  3120. len := Length(pInfo.achName)-1;
  3121. if (Length(FFilterName) > 0) then
  3122. if (Length(FFilterName) > len) then
  3123. begin
  3124. CopyMemory(@pInfo.achName, PWideChar(FFilterName), len * SizeOf(WCHAR));
  3125. pInfo.achName[len] := #0;
  3126. end
  3127. else
  3128. CopyMemory(@pInfo.achName, PWideChar(FFilterName), (Length(FFilterName)+1) * SizeOf(WCHAR))
  3129. else
  3130. pInfo.achName[0] := #0;
  3131. pInfo.pGraph := FGraph;
  3132. result := NOERROR;
  3133. end;
  3134. function TBCBaseFilter.QueryVendorInfo(out pVendorInfo: PWideChar): HRESULT;
  3135. begin
  3136. result := E_NOTIMPL;
  3137. end;
  3138. function TBCBaseFilter.ReconnectPin(Pin: IPin; pmt: PAMMediaType): HRESULT;
  3139. var Graph2: IFilterGraph2;
  3140. begin
  3141. if (FGraph <> nil) then
  3142. begin
  3143. result := FGraph.QueryInterface(IID_IFilterGraph2, Graph2);
  3144. if Succeeded(result) then
  3145. begin
  3146. result := Graph2.ReconnectEx(Pin, pmt);
  3147. Graph2 := nil;
  3148. end
  3149. else
  3150. result := FGraph.Reconnect(Pin);
  3151. end
  3152. else
  3153. result := E_NOINTERFACE;
  3154. end;
  3155. function TBCBaseFilter.Register: HRESULT;
  3156. var
  3157. {$IFDEF DEBUG}
  3158. Filename: array[0..MAX_PATH-1] of Char;
  3159. {$ENDIF}
  3160. FilterMapper : IFilterMapper;
  3161. FilterMapper2: IFilterMapper2;
  3162. Factory: TBCClassFactory;
  3163. AResult : boolean;
  3164. begin
  3165. Aresult := false;
  3166. Result := S_FALSE;
  3167. Factory := Templates.GetFactoryFromClassID(FCLSID);
  3168. if Factory <> nil then
  3169. begin
  3170. {$IFDEF DEBUG}
  3171. GetModuleFileName(hinstance, Filename, sizeof(Filename));
  3172. DbgLog(Self,'Register in ' + Filename);
  3173. {$ENDIF}
  3174. if Failed(CoCreateInstance(CLSID_FilterMapper2, nil, CLSCTX_INPROC_SERVER, IFilterMapper2, FilterMapper2)) then
  3175. if Failed(CoCreateInstance(CLSID_FilterMapper, nil, CLSCTX_INPROC_SERVER, IFilterMapper, FilterMapper)) then exit;
  3176. Factory.UpdateRegistry(false);
  3177. if FilterMapper2 <> nil then
  3178. AResult := Factory.RegisterFilter(FilterMapper2, True)
  3179. else AResult := Factory.RegisterFilter(FilterMapper, True);
  3180. if Aresult then Factory.UpdateRegistry(True);
  3181. FilterMapper := nil;
  3182. FilterMapper2 := nil;
  3183. end;
  3184. if AResult then result := S_OK else result := S_False;
  3185. end;
  3186. function TBCBaseFilter.Run(tStart: TReferenceTime): HRESULT;
  3187. var
  3188. c: integer;
  3189. Pin: TBCBasePin;
  3190. begin
  3191. FLock.Lock;
  3192. try
  3193. // remember the stream time offset
  3194. FStart := tStart;
  3195. if FState = State_Stopped then
  3196. begin
  3197. result := Pause;
  3198. if FAILED(result) then exit;
  3199. end;
  3200. // notify all pins of the change to active state
  3201. if (FState <> State_Running) then
  3202. begin
  3203. for c := 0 to GetPinCount - 1 do
  3204. begin
  3205. Pin := GetPin(c);
  3206. // Disconnected pins are not activated - this saves pins
  3207. // worrying about this state themselves
  3208. if Pin.IsConnected then
  3209. begin
  3210. result := Pin.Run(tStart);
  3211. if FAILED(result) then exit;
  3212. end;
  3213. end;
  3214. end;
  3215. FState := State_Running;
  3216. result := S_OK;
  3217. finally
  3218. FLock.UnLock;
  3219. end;
  3220. end;
  3221. function TBCBaseFilter.SetSyncSource(pClock: IReferenceClock): HRESULT;
  3222. begin
  3223. FLock.Lock;
  3224. try
  3225. FClock := pClock;
  3226. finally
  3227. result := NOERROR;
  3228. FLock.UnLock;
  3229. end;
  3230. end;
  3231. function TBCBaseFilter.Stop: HRESULT;
  3232. var
  3233. c: integer;
  3234. Pin: TBCBasePin;
  3235. hr: HResult;
  3236. begin
  3237. FLock.Lock;
  3238. try
  3239. result := NOERROR;
  3240. // notify all pins of the state change
  3241. if (FState <> State_Stopped) then
  3242. begin
  3243. for c := 0 to GetPinCount - 1 do
  3244. begin
  3245. Pin := GetPin(c);
  3246. // Disconnected pins are not activated - this saves pins worrying
  3247. // about this state themselves. We ignore the return code to make
  3248. // sure everyone is inactivated regardless. The base input pin
  3249. // class can return an error if it has no allocator but Stop can
  3250. // be used to resync the graph state after something has gone bad
  3251. if Pin.IsConnected then
  3252. begin
  3253. hr := Pin.Inactive;
  3254. if (Failed(hr) and SUCCEEDED(result)) then result := hr;
  3255. end;
  3256. end;
  3257. end;
  3258. FState := State_Stopped;
  3259. finally
  3260. FLock.UnLock;
  3261. end;
  3262. end;
  3263. function TBCBaseFilter.StreamTime(out rtStream: TReferenceTime): HRESULT;
  3264. begin
  3265. // Caller must lock for synchronization
  3266. // We can't grab the filter lock because we want to be able to call
  3267. // this from worker threads without deadlocking
  3268. if FClock = nil then
  3269. begin
  3270. result := VFW_E_NO_CLOCK;
  3271. exit;
  3272. end;
  3273. // get the current reference time
  3274. result := FClock.GetTime(PInt64(@rtStream)^);
  3275. if FAILED(result) then exit;
  3276. // subtract the stream offset to get stream time
  3277. rtStream := rtStream - FStart;
  3278. result := S_OK;
  3279. end;
  3280. function TBCBaseFilter.Unregister: HRESULT;
  3281. var
  3282. {$IFDEF DEBUG}
  3283. Filename: array[0..MAX_PATH-1] of Char;
  3284. {$ENDIF}
  3285. FilterMapper : IFilterMapper;
  3286. FilterMapper2: IFilterMapper2;
  3287. Factory: TBCClassFactory;
  3288. AResult : boolean;
  3289. begin
  3290. Aresult := false;
  3291. Result := S_FALSE;
  3292. Factory := Templates.GetFactoryFromClassID(FCLSID);
  3293. if Factory <> nil then
  3294. begin
  3295. {$IFDEF DEBUG}
  3296. GetModuleFileName(hinstance, Filename, sizeof(Filename));
  3297. DbgLog(Self,'Unregister in ' + Filename);
  3298. {$ENDIF}
  3299. if Failed(CoCreateInstance(CLSID_FilterMapper2, nil, CLSCTX_INPROC_SERVER, IFilterMapper2, FilterMapper2)) then
  3300. if Failed(CoCreateInstance(CLSID_FilterMapper, nil, CLSCTX_INPROC_SERVER, IFilterMapper, FilterMapper)) then exit;
  3301. Factory.UpdateRegistry(false);
  3302. if FilterMapper2 <> nil then
  3303. AResult := Factory.RegisterFilter(FilterMapper2, false)
  3304. else AResult := Factory.RegisterFilter(FilterMapper, false);
  3305. if Aresult then Factory.UpdateRegistry(false);
  3306. FilterMapper := nil;
  3307. FilterMapper2 := nil;
  3308. end;
  3309. if AResult then result := S_OK else result := S_False;
  3310. end;
  3311. { TBCEnumPins }
  3312. constructor TBCEnumPins.Create(Filter: TBCBaseFilter; EnumPins: TBCEnumPins);
  3313. var i: integer;
  3314. begin
  3315. FPosition := 0;
  3316. FPinCount := 0;
  3317. FFilter := Filter;
  3318. FPinCache := TList.Create;
  3319. // We must be owned by a filter derived from CBaseFilter
  3320. ASSERT(FFilter <> nil);
  3321. // Hold a reference count on our filter
  3322. FFilter._AddRef;
  3323. // Are we creating a new enumerator
  3324. if (EnumPins = nil) then
  3325. begin
  3326. FVersion := FFilter.GetPinVersion;
  3327. FPinCount := FFilter.GetPinCount;
  3328. end
  3329. else
  3330. begin
  3331. ASSERT(FPosition <= FPinCount);
  3332. FPosition := EnumPins.FPosition;
  3333. FPinCount := EnumPins.FPinCount;
  3334. FVersion := EnumPins.FVersion;
  3335. FPinCache.Clear;
  3336. if EnumPins.FPinCache.Count > 0 then
  3337. for i := 0 to EnumPins.FPinCache.Count - 1 do
  3338. FPinCache.Add(EnumPins.FPinCache.Items[i]);
  3339. end;
  3340. end;
  3341. destructor TBCEnumPins.Destroy;
  3342. begin
  3343. FPinCache.Free;
  3344. FFilter._Release;
  3345. inherited Destroy;
  3346. end;
  3347. function TBCEnumPins.Clone(out ppEnum: IEnumPins): HRESULT;
  3348. begin
  3349. result := NOERROR;
  3350. // Check we are still in sync with the filter
  3351. if AreWeOutOfSync then
  3352. begin
  3353. ppEnum := nil;
  3354. result := VFW_E_ENUM_OUT_OF_SYNC;
  3355. end
  3356. else
  3357. begin
  3358. ppEnum := TBCEnumPins.Create(FFilter, self);
  3359. if ppEnum = nil then result := E_OUTOFMEMORY;
  3360. end;
  3361. end;
  3362. function TBCEnumPins.Next(cPins: ULONG; out ppPins: IPin;
  3363. pcFetched: PULONG): HRESULT;
  3364. type
  3365. TPointerDynArray = array of Pointer;
  3366. TIPinDynArray = array of IPin;
  3367. var
  3368. Fetched: cardinal;
  3369. RealPins: integer;
  3370. Pin: TBCBasePin;
  3371. begin
  3372. if pcFetched <> nil then
  3373. pcFetched^ := 0
  3374. else
  3375. if (cPins>1) then
  3376. begin
  3377. result := E_INVALIDARG;
  3378. exit;
  3379. end;
  3380. Fetched := 0; // increment as we get each one.
  3381. // Check we are still in sync with the filter
  3382. // If we are out of sync, we should refresh the enumerator.
  3383. // This will reset the position and update the other members, but
  3384. // will not clear cache of pins we have already returned.
  3385. if AreWeOutOfSync then
  3386. Refresh;
  3387. // Calculate the number of available pins
  3388. RealPins := min(FPinCount - FPosition, cPins);
  3389. if RealPins = 0 then
  3390. begin
  3391. result := S_FALSE;
  3392. exit;
  3393. end;
  3394. { Return each pin interface NOTE GetPin returns CBasePin * not addrefed
  3395. so we must QI for the IPin (which increments its reference count)
  3396. If while we are retrieving a pin from the filter an error occurs we
  3397. assume that our internal state is stale with respect to the filter
  3398. (for example someone has deleted a pin) so we
  3399. return VFW_E_ENUM_OUT_OF_SYNC }
  3400. while RealPins > 0 do
  3401. begin
  3402. // Get the next pin object from the filter */
  3403. inc(FPosition);
  3404. Pin := FFilter.GetPin(FPosition-1);
  3405. if Pin = nil then
  3406. begin
  3407. // If this happend, and it's not the first time through, then we've got a problem,
  3408. // since we should really go back and release the iPins, which we have previously
  3409. // AddRef'ed.
  3410. ASSERT(Fetched = 0);
  3411. result := VFW_E_ENUM_OUT_OF_SYNC;
  3412. exit;
  3413. end;
  3414. // We only want to return this pin, if it is not in our cache
  3415. if FPinCache.IndexOf(Pin) = -1 then
  3416. begin
  3417. // From the object get an IPin interface
  3418. TPointerDynArray(@ppPins)[Fetched] := nil;
  3419. TIPinDynArray(@ppPins)[Fetched] := Pin;
  3420. inc(Fetched);
  3421. FPinCache.Add(Pin);
  3422. dec(RealPins);
  3423. end;
  3424. end;
  3425. if (pcFetched <> nil) then pcFetched^ := Fetched;
  3426. if (cPins = Fetched) then result := NOERROR else result := S_FALSE;
  3427. end;
  3428. function TBCEnumPins.Skip(cPins: ULONG): HRESULT;
  3429. var PinsLeft: Cardinal;
  3430. begin
  3431. // Check we are still in sync with the filter
  3432. if AreWeOutOfSync then
  3433. begin
  3434. result := VFW_E_ENUM_OUT_OF_SYNC;
  3435. exit;
  3436. end;
  3437. // Work out how many pins are left to skip over
  3438. // We could position at the end if we are asked to skip too many...
  3439. // ..which would match the base implementation for CEnumMediaTypes::Skip
  3440. PinsLeft := FPinCount - FPosition;
  3441. if (cPins > PinsLeft) then
  3442. begin
  3443. result := S_FALSE;
  3444. exit;
  3445. end;
  3446. inc(FPosition, cPins);
  3447. result := NOERROR;
  3448. end;
  3449. function TBCEnumPins.Reset: HRESULT;
  3450. begin
  3451. FVersion := FFilter.GetPinVersion;
  3452. FPinCount := FFilter.GetPinCount;
  3453. FPosition := 0;
  3454. FPinCache.Clear;
  3455. result := S_OK;
  3456. end;
  3457. function TBCEnumPins.Refresh: HRESULT;
  3458. begin
  3459. FVersion := FFilter.GetPinVersion;
  3460. FPinCount := FFilter.GetPinCount;
  3461. Fposition := 0;
  3462. result := S_OK;
  3463. end;
  3464. function TBCEnumPins.AreWeOutOfSync: boolean;
  3465. begin
  3466. if FFilter.GetPinVersion = FVersion then result:= FALSE else result := True;
  3467. end;
  3468. { TBCBasePin }
  3469. { Called by IMediaFilter implementation when the state changes from Stopped
  3470. to either paused or running and in derived classes could do things like
  3471. commit memory and grab hardware resource (the default is to do nothing) }
  3472. function TBCBasePin.Active: HRESULT;
  3473. begin
  3474. result := NOERROR;
  3475. end;
  3476. { This is called to make the connection, including the task of finding
  3477. a media type for the pin connection. pmt is the proposed media type
  3478. from the Connect call: if this is fully specified, we will try that.
  3479. Otherwise we enumerate and try all the input pin's types first and
  3480. if that fails we then enumerate and try all our preferred media types.
  3481. For each media type we check it against pmt (if non-null and partially
  3482. specified) as well as checking that both pins will accept it. }
  3483. function TBCBasePin.AgreeMediaType(ReceivePin: IPin; pmt: PAMMediaType): HRESULT;
  3484. var
  3485. EnumMT: IEnumMediaTypes;
  3486. hrFailure: HResult;
  3487. i: integer;
  3488. begin
  3489. ASSERT(ReceivePin <> nil);
  3490. // if the media type is fully specified then use that
  3491. if ((pmt <> nil) and (not TBCMediaType(pmt).IsPartiallySpecified)) then
  3492. begin
  3493. // if this media type fails, then we must fail the connection
  3494. // since if pmt is nonnull we are only allowed to connect
  3495. // using a type that matches it.
  3496. result := AttemptConnection(ReceivePin, pmt);
  3497. exit;
  3498. end;
  3499. // Try the other pin's enumerator
  3500. hrFailure := VFW_E_NO_ACCEPTABLE_TYPES;
  3501. for i := 0 to 1 do
  3502. begin
  3503. if (i = byte(FTryMyTypesFirst)) then
  3504. result := ReceivePin.EnumMediaTypes(EnumMT)
  3505. else result := EnumMediaTypes(EnumMT);
  3506. if Succeeded(Result) then
  3507. begin
  3508. Assert(EnumMT <> nil);
  3509. result := TryMediaTypes(ReceivePin,pmt,EnumMT);
  3510. EnumMT := nil;
  3511. if Succeeded(result) then
  3512. begin
  3513. result := NOERROR;
  3514. exit;
  3515. end
  3516. else
  3517. begin
  3518. // try to remember specific error codes if there are any
  3519. if ((result <> E_FAIL) and
  3520. (result <> E_INVALIDARG) and
  3521. (result <> VFW_E_TYPE_NOT_ACCEPTED)) then hrFailure := result;
  3522. end;
  3523. end;
  3524. end;
  3525. result := hrFailure;
  3526. end;
  3527. function TBCBasePin.AttemptConnection(ReceivePin: IPin; pmt: PAMMediaType): HRESULT;
  3528. begin
  3529. // The caller should hold the filter lock becasue this function
  3530. // uses m_Connected. The caller should also hold the filter lock
  3531. // because this function calls SetMediaType(), IsStopped() and
  3532. // CompleteConnect().
  3533. ASSERT(FLock.CritCheckIn);
  3534. // Check that the connection is valid -- need to do this for every
  3535. // connect attempt since BreakConnect will undo it.
  3536. result := CheckConnect(ReceivePin);
  3537. if FAILED(result) then
  3538. begin
  3539. {$IFDEF DEBUG}
  3540. DbgLog(self, 'CheckConnect failed');
  3541. {$ENDIF}
  3542. // Since the procedure is already returning an error code, there
  3543. // is nothing else this function can do to report the error.
  3544. Assert(SUCCEEDED(BreakConnect));
  3545. exit;
  3546. end;
  3547. DisplayTypeInfo(ReceivePin, pmt);
  3548. // Check we will accept this media type
  3549. result := CheckMediaType(pmt);
  3550. if (result = NOERROR) then
  3551. begin
  3552. // Make ourselves look connected otherwise ReceiveConnection
  3553. // may not be able to complete the connection
  3554. FConnected := ReceivePin;
  3555. result := SetMediaType(pmt);
  3556. if Succeeded(result) then
  3557. begin
  3558. // See if the other pin will accept this type */
  3559. result := ReceivePin.ReceiveConnection(self, pmt^);
  3560. if Succeeded(result) then
  3561. begin
  3562. // Complete the connection
  3563. result := CompleteConnect(ReceivePin);
  3564. if Succeeded(result) then exit
  3565. else
  3566. begin
  3567. {$IFDEF DEBUG}
  3568. DbgLog(self, 'Failed to complete connection');
  3569. {$ENDIF}
  3570. ReceivePin.Disconnect;
  3571. end;
  3572. end;
  3573. end;
  3574. end
  3575. else
  3576. begin
  3577. // we cannot use this media type
  3578. // return a specific media type error if there is one
  3579. // or map a general failure code to something more helpful
  3580. // (in particular S_FALSE gets changed to an error code)
  3581. if (SUCCEEDED(result) or (result = E_FAIL) or (result = E_INVALIDARG)) then
  3582. result := VFW_E_TYPE_NOT_ACCEPTED;
  3583. end;
  3584. // BreakConnect and release any connection here in case CheckMediaType
  3585. // failed, or if we set anything up during a call back during
  3586. // ReceiveConnection.
  3587. // Since the procedure is already returning an error code, there
  3588. // is nothing else this function can do to report the error.
  3589. Assert(Succeeded(BreakConnect));
  3590. // If failed then undo our state
  3591. FConnected := nil;
  3592. end;
  3593. { This is called when we realise we can't make a connection to the pin and
  3594. must undo anything we did in CheckConnect - override to release QIs done }
  3595. function TBCBasePin.BreakConnect: HRESULT;
  3596. begin
  3597. result := NOERROR;
  3598. end;
  3599. { This is called during Connect() to provide a virtual method that can do
  3600. any specific check needed for connection such as QueryInterface. This
  3601. base class method just checks that the pin directions don't match }
  3602. function TBCBasePin.CheckConnect(Pin: IPin): HRESULT;
  3603. var pd: TPinDirection;
  3604. begin
  3605. // Check that pin directions DONT match
  3606. Pin.QueryDirection(pd);
  3607. ASSERT((pd = PINDIR_OUTPUT) or (pd = PINDIR_INPUT));
  3608. ASSERT((Fdir = PINDIR_OUTPUT) or (Fdir = PINDIR_INPUT));
  3609. // we should allow for non-input and non-output connections?
  3610. if (pd = Fdir) then result := VFW_E_INVALID_DIRECTION
  3611. else result := NOERROR;
  3612. end;
  3613. { Called when we want to complete a connection to another filter. Failing
  3614. this will also fail the connection and disconnect the other pin as well }
  3615. function TBCBasePin.CompleteConnect(ReceivePin: IPin): HRESULT;
  3616. begin
  3617. result := NOERROR;
  3618. end;
  3619. { Asked to connect to a pin. A pin is always attached to an owning filter
  3620. object so we always delegate our locking to that object. We first of all
  3621. retrieve a media type enumerator for the input pin and see if we accept
  3622. any of the formats that it would ideally like, failing that we retrieve
  3623. our enumerator and see if it will accept any of our preferred types }
  3624. function TBCBasePin.Connect(pReceivePin: IPin; const pmt: PAMMediaType): HRESULT;
  3625. var HR: HResult;
  3626. begin
  3627. FLock.Lock;
  3628. try
  3629. DisplayPinInfo(pReceivePin);
  3630. // See if we are already connected
  3631. if FConnected <> nil then
  3632. begin
  3633. {$IFDEF DEBUG}
  3634. DbgLog(self, 'Already connected');
  3635. {$ENDIF}
  3636. result := VFW_E_ALREADY_CONNECTED;
  3637. // milenko start
  3638. Exit;
  3639. // milenko end
  3640. end;
  3641. // See if the filter is active
  3642. if (not IsStopped) and (not FCanReconnectWhenActive) then
  3643. begin
  3644. result := VFW_E_NOT_STOPPED;
  3645. exit;
  3646. end;
  3647. // Find a mutually agreeable media type -
  3648. // Pass in the template media type. If this is partially specified,
  3649. // each of the enumerated media types will need to be checked against
  3650. // it. If it is non-null and fully specified, we will just try to connect
  3651. // with this.
  3652. Hr := AgreeMediaType(pReceivePin, pmt);
  3653. if Failed(hr) then
  3654. begin
  3655. {$IFDEF DEBUG}
  3656. DbgLog(self, 'Failed to agree type');
  3657. {$ENDIF}
  3658. // Since the procedure is already returning an error code, there
  3659. // is nothing else this function can do to report the error.
  3660. ASSERT(SUCCEEDED(BreakConnect));
  3661. result := HR;
  3662. exit;
  3663. end;
  3664. {$IFDEF DEBUG}
  3665. DbgLog(self, 'Connection succeeded');
  3666. {$ENDIF}
  3667. result := NOERROR;
  3668. finally
  3669. FLock.UnLock;
  3670. end;
  3671. end;
  3672. // Return an AddRef()'d pointer to the connected pin if there is one
  3673. function TBCBasePin.ConnectedTo(out pPin: IPin): HRESULT;
  3674. begin
  3675. // It's pointless to lock here.
  3676. // The caller should ensure integrity.
  3677. pPin := FConnected;
  3678. if (pPin <> nil) then
  3679. result := S_OK
  3680. else result := VFW_E_NOT_CONNECTED;
  3681. end;
  3682. function TBCBasePin.ConnectionMediaType(out pmt: TAMMediaType): HRESULT;
  3683. begin
  3684. FLock.Lock;
  3685. try
  3686. // Copy constructor of m_mt allocates the memory
  3687. if IsConnected then
  3688. begin
  3689. CopyMediaType(@pmt,@Fmt);
  3690. result := S_OK;
  3691. end
  3692. else
  3693. begin
  3694. zeromemory(@pmt, SizeOf(TAMMediaType));
  3695. pmt.lSampleSize := 1;
  3696. pmt.bFixedSizeSamples := True;
  3697. result := VFW_E_NOT_CONNECTED;
  3698. end;
  3699. finally
  3700. FLock.UnLock;
  3701. end;
  3702. end;
  3703. constructor TBCBasePin.Create(ObjectName: string; Filter: TBCBaseFilter;
  3704. Lock: TBCCritSec; out hr: HRESULT; Name: WideString;
  3705. dir: TPinDirection);
  3706. begin
  3707. inherited Create(ObjectName, nil);
  3708. FFilter := Filter;
  3709. FLock := Lock;
  3710. FPinName := Name;
  3711. FConnected := nil;
  3712. Fdir := dir;
  3713. FRunTimeError := FALSE;
  3714. FQSink := nil;
  3715. FTypeVersion := 1;
  3716. FStart := 0;
  3717. FStop := MAX_TIME;
  3718. FCanReconnectWhenActive := false;
  3719. FTryMyTypesFirst := false;
  3720. FRate := 1.0;
  3721. { WARNING - Filter is often not a properly constituted object at
  3722. this state (in particular QueryInterface may not work) - this
  3723. is because its owner is often its containing object and we
  3724. have been called from the containing object's constructor so
  3725. the filter's owner has not yet had its CUnknown constructor
  3726. called.}
  3727. FRef := 0; // debug
  3728. ZeroMemory(@fmt, SizeOf(TAMMediaType));
  3729. ASSERT(Filter <> nil);
  3730. ASSERT(Lock <> nil);
  3731. end;
  3732. destructor TBCBasePin.destroy;
  3733. begin
  3734. // We don't call disconnect because if the filter is going away
  3735. // all the pins must have a reference count of zero so they must
  3736. // have been disconnected anyway - (but check the assumption)
  3737. ASSERT(FConnected = nil);
  3738. FPinName := '';
  3739. Assert(FRef = 0);
  3740. FreeMediaType(@fmt);
  3741. inherited Destroy;
  3742. end;
  3743. // Called when we want to terminate a pin connection
  3744. function TBCBasePin.Disconnect: HRESULT;
  3745. begin
  3746. FLock.Lock;
  3747. try
  3748. // See if the filter is active
  3749. if not IsStopped then
  3750. result := VFW_E_NOT_STOPPED
  3751. else result := DisconnectInternal;
  3752. finally
  3753. FLock.UnLock;
  3754. end;
  3755. end;
  3756. function TBCBasePin.DisconnectInternal: HRESULT;
  3757. begin
  3758. ASSERT(FLock.CritCheckIn);
  3759. if (FConnected <> nil) then
  3760. begin
  3761. result := BreakConnect;
  3762. if FAILED(result) then
  3763. begin
  3764. // There is usually a bug in the program if BreakConnect() fails.
  3765. {$IFDEF DEBUG}
  3766. DbgLog(self, 'WARNING: BreakConnect() failed in CBasePin::Disconnect().');
  3767. {$ENDIF}
  3768. exit;
  3769. end;
  3770. FConnected := nil;
  3771. result := S_OK;
  3772. exit;
  3773. end
  3774. else
  3775. // no connection - not an error
  3776. result := S_FALSE;
  3777. end;
  3778. procedure TBCBasePin.DisplayPinInfo(ReceivePin: IPin);
  3779. {$IFDEF DEBUG}
  3780. const
  3781. BadPin : WideString = 'Bad Pin';
  3782. var
  3783. ConnectPinInfo, ReceivePinInfo: TPinInfo;
  3784. begin
  3785. if FAILED(QueryPinInfo(ConnectPinInfo)) then
  3786. move(Pointer(BadPin)^, ConnectPinInfo.achName, length(BadPin) * 2 +2)
  3787. else ConnectPinInfo.pFilter := nil;
  3788. if FAILED(ReceivePin.QueryPinInfo(ReceivePinInfo)) then
  3789. move(Pointer(BadPin)^, ReceivePinInfo.achName, length(BadPin) * 2 +2)
  3790. else ReceivePinInfo.pFilter := nil;
  3791. DbgLog(self, 'Trying to connect Pins :');
  3792. DbgLog(self, format(' <%s>', [ConnectPinInfo.achName]));
  3793. DbgLog(self, format(' <%s>', [ReceivePinInfo.achName]));
  3794. {$ELSE}
  3795. begin
  3796. {$ENDIF}
  3797. end;
  3798. procedure TBCBasePin.DisplayTypeInfo(Pin: IPin; pmt: PAMMediaType);
  3799. begin
  3800. {$IFDEF DEBUG}
  3801. DbgLog(self, 'Trying media type:');
  3802. DbgLog(self, ' major type: '+ GuidToString(pmt.majortype));
  3803. DbgLog(self, ' sub type : '+ GuidToString(pmt.subtype));
  3804. DbgLog(self, GetMediaTypeDescription(pmt));
  3805. {$ENDIF}
  3806. end;
  3807. // Called when no more data will arrive
  3808. function TBCBasePin.EndOfStream: HRESULT;
  3809. begin
  3810. result := S_OK;
  3811. end;
  3812. { This can be called to return an enumerator for the pin's list of preferred
  3813. media types. An input pin is not obliged to have any preferred formats
  3814. although it can do. For example, the window renderer has a preferred type
  3815. which describes a video image that matches the current window size. All
  3816. output pins should expose at least one preferred format otherwise it is
  3817. possible that neither pin has any types and so no connection is possible }
  3818. function TBCBasePin.EnumMediaTypes(out ppEnum: IEnumMediaTypes): HRESULT;
  3819. begin
  3820. // Create a new ref counted enumerator
  3821. ppEnum := TBCEnumMediaTypes.Create(self, nil);
  3822. if (ppEnum = nil) then result := E_OUTOFMEMORY
  3823. else result := NOERROR;
  3824. end;
  3825. { This is a virtual function that returns a media type corresponding with
  3826. place iPosition in the list. This base class simply returns an error as
  3827. we support no media types by default but derived classes should override }
  3828. function TBCBasePin.GetMediaType(Position: integer;
  3829. out MediaType: PAMMediaType): HRESULT;
  3830. begin
  3831. result := E_UNEXPECTED;;
  3832. end;
  3833. { This is a virtual function that returns the current media type version.
  3834. The base class initialises the media type enumerators with the value 1
  3835. By default we always returns that same value. A Derived class may change
  3836. the list of media types available and after doing so it should increment
  3837. the version either in a method derived from this, or more simply by just
  3838. incrementing the m_TypeVersion base pin variable. The type enumerators
  3839. call this when they want to see if their enumerations are out of date }
  3840. function TBCBasePin.GetMediaTypeVersion: longint;
  3841. begin
  3842. result := FTypeVersion;
  3843. end;
  3844. { Also called by the IMediaFilter implementation when the state changes to
  3845. Stopped at which point you should decommit allocators and free hardware
  3846. resources you grabbed in the Active call (default is also to do nothing) }
  3847. function TBCBasePin.Inactive: HRESULT;
  3848. begin
  3849. FRunTimeError := FALSE;
  3850. result := NOERROR;
  3851. end;
  3852. // Increment the cookie representing the current media type version
  3853. procedure TBCBasePin.IncrementTypeVersion;
  3854. begin
  3855. InterlockedIncrement(FTypeVersion);
  3856. end;
  3857. function TBCBasePin.IsConnected: boolean;
  3858. begin
  3859. result := FConnected <> nil;
  3860. end;
  3861. function TBCBasePin.IsStopped: boolean;
  3862. begin
  3863. result := FFilter.FState = State_Stopped;
  3864. end;
  3865. // NewSegment notifies of the start/stop/rate applying to the data
  3866. // about to be received. Default implementation records data and
  3867. // returns S_OK.
  3868. // Override this to pass downstream.
  3869. function TBCBasePin.NewSegment(tStart, tStop: TReferenceTime;
  3870. dRate: double): HRESULT;
  3871. begin
  3872. FStart := tStart;
  3873. FStop := tStop;
  3874. FRate := dRate;
  3875. result := S_OK;
  3876. end;
  3877. function TBCBasePin.NonDelegatingAddRef: Integer;
  3878. begin
  3879. ASSERT(InterlockedIncrement(FRef) > 0);
  3880. result := FFilter._AddRef;
  3881. end;
  3882. function TBCBasePin.NonDelegatingRelease: Integer;
  3883. begin
  3884. ASSERT(InterlockedDecrement(FRef) >= 0);
  3885. result := FFilter._Release
  3886. end;
  3887. function TBCBasePin.Notify(pSelf: IBaseFilter; q: TQuality): HRESULT;
  3888. begin
  3889. {$IFDEF DEBUG}
  3890. DbgLog(self, 'IQualityControl::Notify not over-ridden from CBasePin. (IGNORE is OK)');
  3891. {$ENDIF}
  3892. result := E_NOTIMPL;
  3893. end;
  3894. { Does this pin support this media type WARNING this interface function does
  3895. not lock the main object as it is meant to be asynchronous by nature - if
  3896. the media types you support depend on some internal state that is updated
  3897. dynamically then you will need to implement locking in a derived class }
  3898. function TBCBasePin.QueryAccept(const pmt: TAMMediaType): HRESULT;
  3899. begin
  3900. { The CheckMediaType method is valid to return error codes if the media
  3901. type is horrible, an example might be E_INVALIDARG. What we do here
  3902. is map all the error codes into either S_OK or S_FALSE regardless }
  3903. result := CheckMediaType(@pmt);
  3904. if FAILED(result) then result := S_FALSE;
  3905. end;
  3906. function TBCBasePin.QueryDirection(out pPinDir: TPinDirection): HRESULT;
  3907. begin
  3908. pPinDir := Fdir;
  3909. result := NOERROR;
  3910. end;
  3911. function TBCBasePin.QueryId(out Id: PWideChar): HRESULT;
  3912. begin
  3913. result := AMGetWideString(FPinName, id);
  3914. end;
  3915. function TBCBasePin.QueryInternalConnections(out apPin: IPin;
  3916. var nPin: ULONG): HRESULT;
  3917. begin
  3918. result := E_NOTIMPL;
  3919. end;
  3920. // Return information about the filter we are connect to
  3921. function TBCBasePin.QueryPinInfo(out pInfo: TPinInfo): HRESULT;
  3922. begin
  3923. pInfo.pFilter := FFilter;
  3924. if (FPinName <> '') then
  3925. begin
  3926. move(Pointer(FPinName)^, pInfo.achName, length(FPinName)*2);
  3927. pInfo.achName[length(FPinName)] := #0;
  3928. end
  3929. else pInfo.achName[0] := #0;
  3930. pInfo.dir := Fdir;
  3931. result := NOERROR;
  3932. end;
  3933. { Called normally by an output pin on an input pin to try and establish a
  3934. connection. }
  3935. function TBCBasePin.ReceiveConnection(pConnector: IPin;
  3936. const pmt: TAMMediaType): HRESULT;
  3937. begin
  3938. FLock.Lock;
  3939. try
  3940. // Are we already connected
  3941. if (FConnected <> nil) then
  3942. begin
  3943. result := VFW_E_ALREADY_CONNECTED;
  3944. exit;
  3945. end;
  3946. // See if the filter is active
  3947. if (not IsStopped) and (not FCanReconnectWhenActive) then
  3948. begin
  3949. result := VFW_E_NOT_STOPPED;
  3950. exit;
  3951. end;
  3952. result := CheckConnect(pConnector);
  3953. if FAILED(result) then
  3954. begin
  3955. // Since the procedure is already returning an error code, there
  3956. // is nothing else this function can do to report the error.
  3957. ASSERT(SUCCEEDED(BreakConnect));
  3958. exit;
  3959. end;
  3960. // Ask derived class if this media type is ok
  3961. //CMediaType * pcmt = (CMediaType*) pmt;
  3962. result := CheckMediaType(@pmt);
  3963. if (result <> NOERROR) then
  3964. begin
  3965. // no -we don't support this media type
  3966. // Since the procedure is already returning an error code, there
  3967. // is nothing else this function can do to report the error.
  3968. ASSERT(SUCCEEDED(BreakConnect));
  3969. // return a specific media type error if there is one
  3970. // or map a general failure code to something more helpful
  3971. // (in particular S_FALSE gets changed to an error code)
  3972. if (SUCCEEDED(result) or
  3973. (result = E_FAIL) or
  3974. (result = E_INVALIDARG)) then
  3975. result := VFW_E_TYPE_NOT_ACCEPTED;
  3976. exit;
  3977. end;
  3978. // Complete the connection
  3979. FConnected := pConnector;
  3980. result := SetMediaType(@pmt);
  3981. if SUCCEEDED(result) then
  3982. begin
  3983. result := CompleteConnect(pConnector);
  3984. if SUCCEEDED(result) then
  3985. begin
  3986. result := S_OK;
  3987. exit;
  3988. end;
  3989. end;
  3990. {$IFDEF DEBUG}
  3991. DbgLog(self, 'Failed to set the media type or failed to complete the connection.');
  3992. {$ENDIF}
  3993. FConnected := nil;
  3994. // Since the procedure is already returning an error code, there
  3995. // is nothing else this function can do to report the error.
  3996. ASSERT(SUCCEEDED(BreakConnect));
  3997. finally
  3998. FLock.UnLock;
  3999. end;
  4000. end;
  4001. { Called by IMediaFilter implementation when the state changes from
  4002. to either paused to running and in derived classes could do things like
  4003. commit memory and grab hardware resource (the default is to do nothing) }
  4004. function TBCBasePin.Run(Start: TReferenceTime): HRESULT;
  4005. begin
  4006. result := NOERROR;
  4007. end;
  4008. function TBCBasePin.GetCurrentMediaType: TBCMediaType;
  4009. begin
  4010. result := TBCMediaType(@FMT);
  4011. end;
  4012. function TBCBasePin.GetAMMediaType: PAMMediaType;
  4013. begin
  4014. result := @FMT;
  4015. end;
  4016. { This is called to set the format for a pin connection - CheckMediaType
  4017. will have been called to check the connection format and if it didn't
  4018. return an error code then this (virtual) function will be invoked }
  4019. function TBCBasePin.SetMediaType(mt: PAMMediaType): HRESULT;
  4020. begin
  4021. FreeMediaType(@Fmt);
  4022. CopyMediaType(@Fmt, mt);
  4023. result := NOERROR;
  4024. end;
  4025. function TBCBasePin.SetSink(piqc: IQualityControl): HRESULT;
  4026. begin
  4027. FLock.Lock;
  4028. try
  4029. FQSink := piqc;
  4030. result := NOERROR;
  4031. finally
  4032. FLock.UnLock;
  4033. end;
  4034. end;
  4035. { Given an enumerator we cycle through all the media types it proposes and
  4036. firstly suggest them to our derived pin class and if that succeeds try
  4037. them with the pin in a ReceiveConnection call. This means that if our pin
  4038. proposes a media type we still check in here that we can support it. This
  4039. is deliberate so that in simple cases the enumerator can hold all of the
  4040. media types even if some of them are not really currently available }
  4041. function TBCBasePin.TryMediaTypes(ReceivePin: IPin; pmt: PAMMediaType;
  4042. Enum: IEnumMediaTypes): HRESULT;
  4043. var
  4044. MediaCount: Cardinal;
  4045. hrFailure : HResult;
  4046. MediaType : PAMMediaType;
  4047. begin
  4048. // Reset the current enumerator position
  4049. result := Enum.Reset;
  4050. if Failed(result) then exit;
  4051. MediaCount := 0;
  4052. // attempt to remember a specific error code if there is one
  4053. hrFailure := S_OK;
  4054. while True do
  4055. begin
  4056. { Retrieve the next media type NOTE each time round the loop the
  4057. enumerator interface will allocate another AM_MEDIA_TYPE structure
  4058. If we are successful then we copy it into our output object, if
  4059. not then we must delete the memory allocated before returning }
  4060. result := Enum.Next(1, MediaType, @MediaCount);
  4061. if (result <> S_OK) then
  4062. begin
  4063. if (S_OK = hrFailure) then
  4064. hrFailure := VFW_E_NO_ACCEPTABLE_TYPES;
  4065. result := hrFailure;
  4066. exit;
  4067. end;
  4068. ASSERT(MediaCount = 1);
  4069. ASSERT(MediaType <> nil);
  4070. // check that this matches the partial type (if any)
  4071. if (pmt = nil) or TBCMediaType(MediaType).MatchesPartial(pmt) then
  4072. begin
  4073. result := AttemptConnection(ReceivePin, MediaType);
  4074. // attempt to remember a specific error code
  4075. if FAILED(result) and
  4076. SUCCEEDED(hrFailure) and
  4077. (result <> E_FAIL) and
  4078. (result <> E_INVALIDARG) and
  4079. (result <> VFW_E_TYPE_NOT_ACCEPTED) then hrFailure := result;
  4080. end
  4081. else result := VFW_E_NO_ACCEPTABLE_TYPES;
  4082. DeleteMediaType(MediaType);
  4083. if result = S_OK then exit;
  4084. end;
  4085. end;
  4086. { TBCEnumMediaTypes }
  4087. { The media types a filter supports can be quite dynamic so we add to
  4088. the general IEnumXXXX interface the ability to be signaled when they
  4089. change via an event handle the connected filter supplies. Until the
  4090. Reset method is called after the state changes all further calls to
  4091. the enumerator (except Reset) will return E_UNEXPECTED error code. }
  4092. function TBCEnumMediaTypes.AreWeOutOfSync: boolean;
  4093. begin
  4094. if FPin.GetMediaTypeVersion = FVersion then result := FALSE else result := True;
  4095. end;
  4096. { One of an enumerator's basic member functions allows us to create a cloned
  4097. interface that initially has the same state. Since we are taking a snapshot
  4098. of an object (current position and all) we must lock access at the start }
  4099. function TBCEnumMediaTypes.Clone(out ppEnum: IEnumMediaTypes): HRESULT;
  4100. begin
  4101. result := NOERROR;
  4102. // Check we are still in sync with the pin
  4103. if AreWeOutOfSync then
  4104. begin
  4105. ppEnum := nil;
  4106. result := VFW_E_ENUM_OUT_OF_SYNC;
  4107. exit;
  4108. end
  4109. else
  4110. begin
  4111. ppEnum := TBCEnumMediaTypes.Create(FPin, self);
  4112. if (ppEnum = nil) then result := E_OUTOFMEMORY;
  4113. end;
  4114. end;
  4115. constructor TBCEnumMediaTypes.Create(Pin: TBCBasePin;
  4116. EnumMediaTypes: TBCEnumMediaTypes);
  4117. begin
  4118. FPosition := 0;
  4119. FPin := Pin;
  4120. {$IFDEF DEBUG}
  4121. DbgLog('TBCEnumMediaTypes.Create');
  4122. {$ENDIF}
  4123. // We must be owned by a pin derived from CBasePin */
  4124. ASSERT(Pin <> nil);
  4125. // Hold a reference count on our pin
  4126. FPin._AddRef;
  4127. // Are we creating a new enumerator
  4128. if (EnumMediaTypes = nil) then
  4129. begin
  4130. FVersion := FPin.GetMediaTypeVersion;
  4131. exit;
  4132. end;
  4133. FPosition := EnumMediaTypes.FPosition;
  4134. FVersion := EnumMediaTypes.FVersion;
  4135. end;
  4136. { Destructor releases the reference count on our base pin. NOTE since we hold
  4137. a reference count on the pin who created us we know it is safe to release
  4138. it, no access can be made to it afterwards though as we might have just
  4139. caused the last reference count to go and the object to be deleted }
  4140. destructor TBCEnumMediaTypes.Destroy;
  4141. begin
  4142. {$IFDEF DEBUG}
  4143. DbgLog('TBCEnumMediaTypes.Destroy');
  4144. {$ENDIF}
  4145. FPin._Release;
  4146. inherited;
  4147. end;
  4148. { Enumerate the next pin(s) after the current position. The client using this
  4149. interface passes in a pointer to an array of pointers each of which will
  4150. be filled in with a pointer to a fully initialised media type format
  4151. Return NOERROR if it all works,
  4152. S_FALSE if fewer than cMediaTypes were enumerated.
  4153. VFW_E_ENUM_OUT_OF_SYNC if the enumerator has been broken by
  4154. state changes in the filter
  4155. The actual count always correctly reflects the number of types in the array.}
  4156. function TBCEnumMediaTypes.Next(cMediaTypes: ULONG;
  4157. out ppMediaTypes: PAMMediaType; pcFetched: PULONG): HRESULT;
  4158. type TMTDynArray = array of PAMMediaType;
  4159. var
  4160. Fetched: Cardinal;
  4161. cmt: PAMMediaType;
  4162. begin
  4163. // Check we are still in sync with the pin
  4164. if AreWeOutOfSync then
  4165. begin
  4166. result := VFW_E_ENUM_OUT_OF_SYNC;
  4167. exit;
  4168. end;
  4169. if (pcFetched <> nil) then
  4170. pcFetched^ := 0 // default unless we succeed
  4171. // now check that the parameter is valid
  4172. else
  4173. if (cMediaTypes > 1) then
  4174. begin // pcFetched == NULL
  4175. result := E_INVALIDARG;
  4176. exit;
  4177. end;
  4178. Fetched := 0; // increment as we get each one.
  4179. { Return each media type by asking the filter for them in turn - If we
  4180. have an error code retured to us while we are retrieving a media type
  4181. we assume that our internal state is stale with respect to the filter
  4182. (for example the window size changing) so we return
  4183. VFW_E_ENUM_OUT_OF_SYNC }
  4184. new(cmt);
  4185. while (cMediaTypes > 0) do
  4186. begin
  4187. TBCMediaType(cmt).InitMediaType;
  4188. inc(FPosition);
  4189. result := FPin.GetMediaType(FPosition-1, cmt);
  4190. if (S_OK <> result) then Break;
  4191. { We now have a CMediaType object that contains the next media type
  4192. but when we assign it to the array position we CANNOT just assign
  4193. the AM_MEDIA_TYPE structure because as soon as the object goes out of
  4194. scope it will delete the memory we have just copied. The function
  4195. we use is CreateMediaType which allocates a task memory block }
  4196. { Transfer across the format block manually to save an allocate
  4197. and free on the format block and generally go faster }
  4198. TMTDynArray(@ppMediaTypes)[Fetched] := CoTaskMemAlloc(sizeof(TAMMediaType));
  4199. if TMTDynArray(@ppMediaTypes)[Fetched] = nil then Break;
  4200. { Do a regular copy }
  4201. //CopyMediaType(TMTDynArray(@ppMediaTypes)[Fetched], cmt);
  4202. Move(cmt^,TMTDynArray(@ppMediaTypes)[Fetched]^,SizeOf(TAMMediaType));
  4203. // Make sure the destructor doesn't free these
  4204. cmt.pbFormat := nil;
  4205. cmt.cbFormat := 0;
  4206. Pointer(cmt.pUnk) := nil;
  4207. inc(Fetched);
  4208. dec(cMediaTypes);
  4209. end;
  4210. dispose(cmt);
  4211. if (pcFetched <> nil) then pcFetched^ := Fetched;
  4212. if cMediaTypes = 0 then result := NOERROR else result := S_FALSE;
  4213. end;
  4214. { Set the current position back to the start
  4215. Reset has 3 simple steps:
  4216. set position to head of list
  4217. sync enumerator with object being enumerated
  4218. return S_OK }
  4219. function TBCEnumMediaTypes.Reset: HRESULT;
  4220. begin
  4221. FPosition := 0;
  4222. // Bring the enumerator back into step with the current state. This
  4223. // may be a noop but ensures that the enumerator will be valid on the
  4224. // next call.
  4225. FVersion := FPin.GetMediaTypeVersion;
  4226. result := NOERROR;
  4227. end;
  4228. // Skip over one or more entries in the enumerator
  4229. function TBCEnumMediaTypes.Skip(cMediaTypes: ULONG): HRESULT;
  4230. var cmt: PAMMediaType;
  4231. begin
  4232. cmt := nil;
  4233. // If we're skipping 0 elements we're guaranteed to skip the
  4234. // correct number of elements
  4235. if (cMediaTypes = 0) then
  4236. begin
  4237. result := S_OK;
  4238. exit;
  4239. end;
  4240. // Check we are still in sync with the pin
  4241. if AreWeOutOfSync then
  4242. begin
  4243. result := VFW_E_ENUM_OUT_OF_SYNC;
  4244. exit;
  4245. end;
  4246. FPosition := FPosition + cMediaTypes;
  4247. // See if we're over the end
  4248. if (S_OK = FPin.GetMediaType(FPosition - 1, cmt)) then result := S_OK else result := S_FALSE;
  4249. end;
  4250. { TBCBaseOutputPin }
  4251. // Commit the allocator's memory, this is called through IMediaFilter
  4252. // which is responsible for locking the object before calling us
  4253. function TBCBaseOutputPin.Active: HRESULT;
  4254. begin
  4255. if (FAllocator = nil) then
  4256. result := VFW_E_NO_ALLOCATOR
  4257. else result := FAllocator.Commit;
  4258. end;
  4259. function TBCBaseOutputPin.BeginFlush: HRESULT;
  4260. begin
  4261. result := E_UNEXPECTED;
  4262. end;
  4263. // Overriden from CBasePin
  4264. function TBCBaseOutputPin.BreakConnect: HRESULT;
  4265. begin
  4266. // Release any allocator we hold
  4267. if (FAllocator <> nil) then
  4268. begin
  4269. // Always decommit the allocator because a downstream filter may or
  4270. // may not decommit the connection's allocator. A memory leak could
  4271. // occur if the allocator is not decommited when a connection is broken.
  4272. result := FAllocator.Decommit;
  4273. if FAILED(result) then exit;
  4274. FAllocator := nil;
  4275. end;
  4276. // Release any input pin interface we hold
  4277. if (FInputPin <> nil) then FInputPin := nil;
  4278. result := NOERROR;
  4279. end;
  4280. { This method is called when the output pin is about to try and connect to
  4281. an input pin. It is at this point that you should try and grab any extra
  4282. interfaces that you need, in this case IMemInputPin. Because this is
  4283. only called if we are not currently connected we do NOT need to call
  4284. BreakConnect. This also makes it easier to derive classes from us as
  4285. BreakConnect is only called when we actually have to break a connection
  4286. (or a partly made connection) and not when we are checking a connection }
  4287. function TBCBaseOutputPin.CheckConnect(Pin: IPin): HRESULT;
  4288. begin
  4289. result := inherited CheckConnect(Pin);
  4290. if FAILED(result) then exit;
  4291. // get an input pin and an allocator interface
  4292. result := Pin.QueryInterface(IID_IMemInputPin, FInputPin);
  4293. if FAILED(result) then exit;
  4294. result := NOERROR;
  4295. end;
  4296. // This is called after a media type has been proposed
  4297. // Try to complete the connection by agreeing the allocator
  4298. function TBCBaseOutputPin.CompleteConnect(ReceivePin: IPin): HRESULT;
  4299. begin
  4300. result := DecideAllocator(FInputPin, FAllocator);
  4301. end;
  4302. constructor TBCBaseOutputPin.Create(ObjectName: string;
  4303. Filter: TBCBaseFilter; Lock: TBCCritSec; out hr: HRESULT;
  4304. const Name: WideString);
  4305. begin
  4306. inherited Create(ObjectName, Filter, Lock, hr, Name, PINDIR_OUTPUT);
  4307. FAllocator := nil;
  4308. FInputPin := nil;
  4309. ASSERT(FFilter <> nil);
  4310. end;
  4311. { Decide on an allocator, override this if you want to use your own allocator
  4312. Override DecideBufferSize to call SetProperties. If the input pin fails
  4313. the GetAllocator call then this will construct a CMemAllocator and call
  4314. DecideBufferSize on that, and if that fails then we are completely hosed.
  4315. If the you succeed the DecideBufferSize call, we will notify the input
  4316. pin of the selected allocator. NOTE this is called during Connect() which
  4317. therefore looks after grabbing and locking the object's critical section }
  4318. // We query the input pin for its requested properties and pass this to
  4319. // DecideBufferSize to allow it to fulfill requests that it is happy
  4320. // with (eg most people don't care about alignment and are thus happy to
  4321. // use the downstream pin's alignment request).
  4322. function TBCBaseOutputPin.DecideAllocator(Pin: IMemInputPin;
  4323. out Alloc: IMemAllocator): HRESULT;
  4324. var
  4325. prop: TAllocatorProperties;
  4326. begin
  4327. Alloc := nil;
  4328. // get downstream prop request
  4329. // the derived class may modify this in DecideBufferSize, but
  4330. // we assume that he will consistently modify it the same way,
  4331. // so we only get it once
  4332. ZeroMemory(@prop, sizeof(TAllocatorProperties));
  4333. // whatever he returns, we assume prop is either all zeros
  4334. // or he has filled it out.
  4335. Pin.GetAllocatorRequirements(prop);
  4336. // if he doesn't care about alignment, then set it to 1
  4337. if (prop.cbAlign = 0) then prop.cbAlign := 1;
  4338. // Try the allocator provided by the input pin
  4339. result := Pin.GetAllocator(Alloc);
  4340. if SUCCEEDED(result) then
  4341. begin
  4342. result := DecideBufferSize(Alloc, @prop);
  4343. if SUCCEEDED(result) then
  4344. begin
  4345. result := Pin.NotifyAllocator(Alloc, FALSE);
  4346. if SUCCEEDED(result) then
  4347. begin
  4348. result := NOERROR;
  4349. exit;
  4350. end;
  4351. end;
  4352. end;
  4353. // If the GetAllocator failed we may not have an interface
  4354. if (Alloc <> nil) then Alloc := nil;
  4355. // Try the output pin's allocator by the same method
  4356. result := InitAllocator(Alloc);
  4357. if SUCCEEDED(result) then
  4358. begin
  4359. // note - the properties passed here are in the same
  4360. // structure as above and may have been modified by
  4361. // the previous call to DecideBufferSize
  4362. result := DecideBufferSize(Alloc, @prop);
  4363. if SUCCEEDED(result) then
  4364. begin
  4365. result := Pin.NotifyAllocator(Alloc, FALSE);
  4366. if SUCCEEDED(result) then
  4367. begin
  4368. result := NOERROR;
  4369. exit;
  4370. end;
  4371. end;
  4372. end;
  4373. // Likewise we may not have an interface to release
  4374. if (Alloc <> nil) then Alloc := nil;
  4375. end;
  4376. function TBCBaseOutputPin.DecideBufferSize(Alloc: IMemAllocator;
  4377. propInputRequest: PAllocatorProperties): HRESULT;
  4378. begin
  4379. result := S_OK; // ???
  4380. end;
  4381. { Deliver a filled-in sample to the connected input pin. NOTE the object must
  4382. have locked itself before calling us otherwise we may get halfway through
  4383. executing this method only to find the filter graph has got in and
  4384. disconnected us from the input pin. If the filter has no worker threads
  4385. then the lock is best applied on Receive(), otherwise it should be done
  4386. when the worker thread is ready to deliver. There is a wee snag to worker
  4387. threads that this shows up. The worker thread must lock the object when
  4388. it is ready to deliver a sample, but it may have to wait until a state
  4389. change has completed, but that may never complete because the state change
  4390. is waiting for the worker thread to complete. The way to handle this is for
  4391. the state change code to grab the critical section, then set an abort event
  4392. for the worker thread, then release the critical section and wait for the
  4393. worker thread to see the event we set and then signal that it has finished
  4394. (with another event). At which point the state change code can complete }
  4395. // note (if you've still got any breath left after reading that) that you
  4396. // need to release the sample yourself after this call. if the connected
  4397. // input pin needs to hold onto the sample beyond the call, it will addref
  4398. // the sample itself.
  4399. // of course you must release this one and call GetDeliveryBuffer for the
  4400. // next. You cannot reuse it directly.
  4401. function TBCBaseOutputPin.Deliver(Sample: IMediaSample): HRESULT;
  4402. begin
  4403. if (FInputPin = nil) then result := VFW_E_NOT_CONNECTED
  4404. else result := FInputPin.Receive(Sample);
  4405. end;
  4406. // call BeginFlush on the connected input pin
  4407. function TBCBaseOutputPin.DeliverBeginFlush: HRESULT;
  4408. begin
  4409. // remember this is on IPin not IMemInputPin
  4410. if (FConnected = nil) then
  4411. result := VFW_E_NOT_CONNECTED
  4412. else result := FConnected.BeginFlush;
  4413. end;
  4414. // call EndFlush on the connected input pin
  4415. function TBCBaseOutputPin.DeliverEndFlush: HRESULT;
  4416. begin
  4417. // remember this is on IPin not IMemInputPin
  4418. if (FConnected = nil) then
  4419. result := VFW_E_NOT_CONNECTED
  4420. else result := FConnected.EndFlush;
  4421. end;
  4422. // called from elsewhere in our filter to pass EOS downstream to
  4423. // our connected input pin
  4424. function TBCBaseOutputPin.DeliverEndOfStream: HRESULT;
  4425. begin
  4426. // remember this is on IPin not IMemInputPin
  4427. if (FConnected = nil) then
  4428. result := VFW_E_NOT_CONNECTED
  4429. else result := FConnected.EndOfStream;
  4430. end;
  4431. // deliver NewSegment to connected pin
  4432. function TBCBaseOutputPin.DeliverNewSegment(Start, Stop: TReferenceTime;
  4433. Rate: double): HRESULT;
  4434. begin
  4435. if (FConnected = nil) then
  4436. result := VFW_E_NOT_CONNECTED
  4437. else result := FConnected.NewSegment(Start, Stop, Rate);
  4438. end;
  4439. function TBCBaseOutputPin.EndFlush: HRESULT;
  4440. begin
  4441. result := E_UNEXPECTED;
  4442. end;
  4443. // we have a default handling of EndOfStream which is to return
  4444. // an error, since this should be called on input pins only
  4445. function TBCBaseOutputPin.EndOfStream: HRESULT;
  4446. begin
  4447. result := E_UNEXPECTED;
  4448. end;
  4449. // This returns an empty sample buffer from the allocator WARNING the same
  4450. // dangers and restrictions apply here as described below for Deliver()
  4451. function TBCBaseOutputPin.GetDeliveryBuffer(out Sample: IMediaSample;
  4452. StartTime, EndTime: PReferenceTime; Flags: Longword): HRESULT;
  4453. begin
  4454. if (FAllocator <> nil) then
  4455. result := FAllocator.GetBuffer(Sample, StartTime, EndTime, Flags)
  4456. else result := E_NOINTERFACE;
  4457. end;
  4458. { Free up or unprepare allocator's memory, this is called through
  4459. IMediaFilter which is responsible for locking the object first }
  4460. function TBCBaseOutputPin.Inactive: HRESULT;
  4461. begin
  4462. FRunTimeError := FALSE;
  4463. if (FAllocator = nil) then
  4464. result := VFW_E_NO_ALLOCATOR
  4465. else result := FAllocator.Decommit;
  4466. end;
  4467. // This is called when the input pin didn't give us a valid allocator
  4468. function TBCBaseOutputPin.InitAllocator(out Alloc: IMemAllocator): HRESULT;
  4469. begin
  4470. result := CoCreateInstance(CLSID_MemoryAllocator, nil, CLSCTX_INPROC_SERVER,
  4471. IID_IMemAllocator, Alloc);
  4472. end;
  4473. { TBCBaseInputPin }
  4474. // Default handling for BeginFlush - call at the beginning
  4475. // of your implementation (makes sure that all Receive calls
  4476. // fail). After calling this, you need to free any queued data
  4477. // and then call downstream.
  4478. function TBCBaseInputPin.BeginFlush: HRESULT;
  4479. begin
  4480. // BeginFlush is NOT synchronized with streaming but is part of
  4481. // a control action - hence we synchronize with the filter
  4482. FLock.Lock;
  4483. try
  4484. // if we are already in mid-flush, this is probably a mistake
  4485. // though not harmful - try to pick it up for now so I can think about it
  4486. ASSERT(not FFlushing);
  4487. // first thing to do is ensure that no further Receive calls succeed
  4488. FFlushing := True;
  4489. // now discard any data and call downstream - must do that
  4490. // in derived classes
  4491. result := S_OK;
  4492. finally
  4493. FLock.UnLock;
  4494. end;
  4495. end;
  4496. function TBCBaseInputPin.BreakConnect: HRESULT;
  4497. begin
  4498. // We don't need our allocator any more
  4499. if (FAllocator <> nil) then
  4500. begin
  4501. // Always decommit the allocator because a downstream filter may or
  4502. // may not decommit the connection's allocator. A memory leak could
  4503. // occur if the allocator is not decommited when a pin is disconnected.
  4504. result := FAllocator.Decommit;
  4505. if FAILED(result) then exit;
  4506. FAllocator := nil;
  4507. end;
  4508. result := S_OK;
  4509. end;
  4510. // Check if it's OK to process data
  4511. function TBCBaseInputPin.CheckStreaming: HRESULT;
  4512. begin
  4513. // Shouldn't be able to get any data if we're not connected!
  4514. ASSERT(IsConnected);
  4515. // Don't process stuff in Stopped state
  4516. if IsStopped then begin result := VFW_E_WRONG_STATE; exit end;
  4517. if FFlushing then begin result := S_FALSE; exit end;
  4518. if FRunTimeError then begin result := VFW_E_RUNTIME_ERROR; exit end;
  4519. result := S_OK;
  4520. end;
  4521. // Constructor creates a default allocator object
  4522. constructor TBCBaseInputPin.Create(ObjectName: string;
  4523. Filter: TBCBaseFilter; Lock: TBCCritSec; out hr: HRESULT;
  4524. Name: WideString);
  4525. begin
  4526. inherited create(ObjectName, Filter, Lock, hr, Name, PINDIR_INPUT);
  4527. FAllocator := nil;
  4528. FReadOnly := false;
  4529. FFlushing := false;
  4530. ZeroMemory(@FSampleProps, sizeof(FSampleProps));
  4531. end;
  4532. destructor TBCBaseInputPin.Destroy;
  4533. begin
  4534. if FAllocator <> nil then FAllocator := nil;
  4535. inherited;
  4536. end;
  4537. // default handling for EndFlush - call at end of your implementation
  4538. // - before calling this, ensure that there is no queued data and no thread
  4539. // pushing any more without a further receive, then call downstream,
  4540. // then call this method to clear the m_bFlushing flag and re-enable
  4541. // receives
  4542. function TBCBaseInputPin.EndFlush: HRESULT;
  4543. begin
  4544. // Endlush is NOT synchronized with streaming but is part of
  4545. // a control action - hence we synchronize with the filter
  4546. FLock.Lock;
  4547. try
  4548. // almost certainly a mistake if we are not in mid-flush
  4549. ASSERT(FFlushing);
  4550. // before calling, sync with pushing thread and ensure
  4551. // no more data is going downstream, then call EndFlush on
  4552. // downstream pins.
  4553. // now re-enable Receives
  4554. FFlushing := FALSE;
  4555. // No more errors
  4556. FRunTimeError := FALSE;
  4557. result := S_OK;
  4558. finally
  4559. FLock.UnLock;
  4560. end;
  4561. end;
  4562. { Return the allocator interface that this input pin would like the output
  4563. pin to use. NOTE subsequent calls to GetAllocator should all return an
  4564. interface onto the SAME object so we create one object at the start
  4565. Note:
  4566. The allocator is Release()'d on disconnect and replaced on
  4567. NotifyAllocator().
  4568. Override this to provide your own allocator.}
  4569. function TBCBaseInputPin.GetAllocator(
  4570. out ppAllocator: IMemAllocator): HRESULT;
  4571. begin
  4572. FLock.Lock;
  4573. try
  4574. if (FAllocator = nil) then
  4575. begin
  4576. result := CoCreateInstance(CLSID_MemoryAllocator, nil, CLSCTX_INPROC_SERVER,
  4577. IID_IMemAllocator, FAllocator);
  4578. if FAILED(result) then exit;
  4579. end;
  4580. ASSERT(FAllocator <> nil);
  4581. ppAllocator := FAllocator;
  4582. result := NOERROR;
  4583. finally
  4584. FLock.UnLock;
  4585. end;
  4586. end;
  4587. // what requirements do we have of the allocator - override if you want
  4588. // to support other people's allocators but need a specific alignment
  4589. // or prefix.
  4590. function TBCBaseInputPin.GetAllocatorRequirements(
  4591. out pProps: TAllocatorProperties): HRESULT;
  4592. begin
  4593. result := E_NOTIMPL;
  4594. end;
  4595. { Free up or unprepare allocator's memory, this is called through
  4596. IMediaFilter which is responsible for locking the object first. }
  4597. function TBCBaseInputPin.Inactive: HRESULT;
  4598. begin
  4599. FRunTimeError := FALSE;
  4600. if (FAllocator = nil) then
  4601. begin
  4602. result := VFW_E_NO_ALLOCATOR;
  4603. exit;
  4604. end;
  4605. FFlushing := FALSE;
  4606. result := FAllocator.Decommit;
  4607. end;
  4608. function TBCBaseInputPin.Notify(pSelf: IBaseFilter; q: TQuality): HRESULT;
  4609. begin
  4610. {$IFDEF DEBUG}
  4611. DbgLog(self, 'IQuality.Notify called on an input pin');
  4612. {$ENDIF}
  4613. result := NOERROR;
  4614. end;
  4615. { Tell the input pin which allocator the output pin is actually going to use
  4616. Override this if you care - NOTE the locking we do both here and also in
  4617. GetAllocator is unnecessary but derived classes that do something useful
  4618. will undoubtedly have to lock the object so this might help remind people }
  4619. function TBCBaseInputPin.NotifyAllocator(pAllocator: IMemAllocator;
  4620. bReadOnly: BOOL): HRESULT;
  4621. begin
  4622. FLock.Lock;
  4623. try
  4624. FAllocator := pAllocator;
  4625. // the readonly flag indicates whether samples from this allocator should
  4626. // be regarded as readonly - if True, then inplace transforms will not be
  4627. // allowed.
  4628. FReadOnly := bReadOnly;
  4629. result := NOERROR;
  4630. finally
  4631. FLock.UnLock;
  4632. end;
  4633. end;
  4634. // Pass on the Quality notification q to
  4635. // a. Our QualityControl sink (if we have one) or else
  4636. // b. to our upstream filter
  4637. // and if that doesn't work, throw it away with a bad return code
  4638. function TBCBaseInputPin.PassNotify(const q: TQuality): HRESULT;
  4639. var IQC: IQualityControl;
  4640. begin
  4641. // We pass the message on, which means that we find the quality sink
  4642. // for our input pin and send it there
  4643. {$IFDEF DEBUG}
  4644. DbgLog(self, 'Passing Quality notification through transform');
  4645. {$ENDIF}
  4646. if (FQSink <> nil) then
  4647. begin
  4648. result := FQSink.Notify(FFilter, q);
  4649. exit;
  4650. end
  4651. else
  4652. begin
  4653. // no sink set, so pass it upstream
  4654. result := VFW_E_NOT_FOUND; // default
  4655. if (FConnected <> nil) then
  4656. begin
  4657. FConnected.QueryInterface(IID_IQualityControl, IQC);
  4658. if (IQC <> nil) then
  4659. begin
  4660. result := IQC.Notify(FFilter, q);
  4661. IQC := nil;
  4662. end;
  4663. end;
  4664. end;
  4665. end;
  4666. { Do something with this media sample - this base class checks to see if the
  4667. format has changed with this media sample and if so checks that the filter
  4668. will accept it, generating a run time error if not. Once we have raised a
  4669. run time error we set a flag so that no more samples will be accepted
  4670. It is important that any filter should override this method and implement
  4671. synchronization so that samples are not processed when the pin is
  4672. disconnected etc. }
  4673. function TBCBaseInputPin.Receive(pSample: IMediaSample): HRESULT;
  4674. var Sample2: IMediaSample2;
  4675. begin
  4676. ASSERT(pSample <> nil);
  4677. result := CheckStreaming;
  4678. if (S_OK <> result) then exit;
  4679. // Check for IMediaSample2
  4680. if SUCCEEDED(pSample.QueryInterface(IID_IMediaSample2, Sample2)) then
  4681. begin
  4682. result := Sample2.GetProperties(sizeof(FSampleProps), FSampleProps);
  4683. Sample2 := nil;
  4684. if FAILED(result) then exit;
  4685. end
  4686. else
  4687. begin
  4688. // Get the properties the hard way
  4689. FSampleProps.cbData := sizeof(FSampleProps);
  4690. FSampleProps.dwTypeSpecificFlags := 0;
  4691. FSampleProps.dwStreamId := AM_STREAM_MEDIA;
  4692. FSampleProps.dwSampleFlags := 0;
  4693. if (S_OK = pSample.IsDiscontinuity) then
  4694. FSampleProps.dwSampleFlags := FSampleProps.dwSampleFlags or AM_SAMPLE_DATADISCONTINUITY;
  4695. if (S_OK = pSample.IsPreroll) then
  4696. FSampleProps.dwSampleFlags := FSampleProps.dwSampleFlags or AM_SAMPLE_PREROLL;
  4697. if (S_OK = pSample.IsSyncPoint) then
  4698. FSampleProps.dwSampleFlags := FSampleProps.dwSampleFlags or AM_SAMPLE_SPLICEPOINT;
  4699. if SUCCEEDED(pSample.GetTime(FSampleProps.tStart, FSampleProps.tStop)) then
  4700. FSampleProps.dwSampleFlags := FSampleProps.dwSampleFlags or AM_SAMPLE_TIMEVALID or AM_SAMPLE_STOPVALID;
  4701. if (S_OK = pSample.GetMediaType(FSampleProps.pMediaType)) then
  4702. FSampleProps.dwSampleFlags := FSampleProps.dwSampleFlags or AM_SAMPLE_TYPECHANGED;
  4703. pSample.GetPointer(PByte(FSampleProps.pbBuffer));
  4704. FSampleProps.lActual := pSample.GetActualDataLength;
  4705. FSampleProps.cbBuffer := pSample.GetSize;
  4706. end;
  4707. // Has the format changed in this sample
  4708. if (not BOOL(FSampleProps.dwSampleFlags and AM_SAMPLE_TYPECHANGED)) then
  4709. begin
  4710. result := NOERROR;
  4711. exit;
  4712. end;
  4713. // Check the derived class accepts this format */
  4714. // This shouldn't fail as the source must call QueryAccept first */
  4715. result := CheckMediaType(FSampleProps.pMediaType);
  4716. if (result = NOERROR) then exit;
  4717. // Raise a runtime error if we fail the media type
  4718. FRunTimeError := True;
  4719. EndOfStream;
  4720. FFilter.NotifyEvent(EC_ERRORABORT,VFW_E_TYPE_NOT_ACCEPTED,0);
  4721. result := VFW_E_INVALIDMEDIATYPE;
  4722. end;
  4723. // See if Receive() might block
  4724. function TBCBaseInputPin.ReceiveCanBlock: HRESULT;
  4725. var
  4726. c, Pins, OutputPins: Integer;
  4727. Pin: TBCBasePin;
  4728. pd: TPinDirection;
  4729. Connected: IPin;
  4730. InputPin: IMemInputPin;
  4731. begin
  4732. { Ask all the output pins if they block
  4733. If there are no output pin assume we do block. }
  4734. Pins := FFilter.GetPinCount;
  4735. OutputPins := 0;
  4736. for c := 0 to Pins - 1 do
  4737. begin
  4738. Pin := FFilter.GetPin(c);
  4739. result := Pin.QueryDirection(pd);
  4740. if FAILED(result) then exit;
  4741. if (pd = PINDIR_OUTPUT) then
  4742. begin
  4743. result := Pin.ConnectedTo(Connected);
  4744. if SUCCEEDED(result) then
  4745. begin
  4746. assert(Connected <> nil);
  4747. inc(OutputPins);
  4748. result := Connected.QueryInterface(IID_IMemInputPin, InputPin);
  4749. Connected := nil;
  4750. if SUCCEEDED(result) then
  4751. begin
  4752. result := InputPin.ReceiveCanBlock;
  4753. InputPin := nil;
  4754. if (result <> S_FALSE) then
  4755. begin
  4756. result := S_OK;
  4757. exit;
  4758. end;
  4759. end
  4760. else
  4761. begin
  4762. // There's a transport we don't understand here
  4763. result := S_OK;
  4764. exit;
  4765. end;
  4766. end;
  4767. end;
  4768. end;
  4769. if OutputPins = 0 then result := S_OK else result := S_FALSE;
  4770. end;
  4771. // Receive multiple samples
  4772. function TBCBaseInputPin.ReceiveMultiple(var pSamples: IMediaSample;
  4773. nSamples: Integer; out nSamplesProcessed: Integer): HRESULT;
  4774. type
  4775. TMediaSampleDynArray = array of IMediaSample;
  4776. begin
  4777. result := S_OK;
  4778. nSamplesProcessed := 0;
  4779. dec(nSamples);
  4780. while (nSamples >= 0) do
  4781. begin
  4782. result := Receive(TMediaSampleDynArray(@pSamples)[nSamplesProcessed]);
  4783. // S_FALSE means don't send any more
  4784. if (result <> S_OK) then break;
  4785. inc(nSamplesProcessed);
  4786. dec(nSamples)
  4787. end;
  4788. end;
  4789. function TBCBaseInputPin.SampleProps: PAMSample2Properties;
  4790. begin
  4791. ASSERT(FSampleProps.cbData <> 0);
  4792. result := @FSampleProps;
  4793. end;
  4794. // milenko start (added TBCDynamicOutputPin conversion)
  4795. { TBCDynamicOutputPin }
  4796. //
  4797. // The streaming thread calls IPin::NewSegment(), IPin::EndOfStream(),
  4798. // IMemInputPin::Receive() and IMemInputPin::ReceiveMultiple() on the
  4799. // connected input pin. The application thread calls Block(). The
  4800. // following class members can only be called by the streaming thread.
  4801. //
  4802. // Deliver()
  4803. // DeliverNewSegment()
  4804. // StartUsingOutputPin()
  4805. // StopUsingOutputPin()
  4806. // ChangeOutputFormat()
  4807. // ChangeMediaType()
  4808. // DynamicReconnect()
  4809. //
  4810. // The following class members can only be called by the application thread.
  4811. //
  4812. // Block()
  4813. // SynchronousBlockOutputPin()
  4814. // AsynchronousBlockOutputPin()
  4815. //
  4816. constructor TBCDynamicOutputPin.Create(ObjectName: WideString; Filter: TBCBaseFilter;
  4817. Lock: TBCCritSec; out hr: HRESULT; Name: WideString);
  4818. begin
  4819. inherited Create(ObjectName,Filter,Lock,hr,Name);
  4820. FStopEvent := 0;
  4821. FGraphConfig := nil;
  4822. FPinUsesReadOnlyAllocator := False;
  4823. FBlockState := NOT_BLOCKED;
  4824. FUnblockOutputPinEvent := 0;
  4825. FNotifyCallerPinBlockedEvent := 0;
  4826. FBlockCallerThreadID := 0;
  4827. FNumOutstandingOutputPinUsers := 0;
  4828. FBlockStateLock := TBCCritSec.Create;
  4829. hr := Initialize;
  4830. end;
  4831. destructor TBCDynamicOutputPin.Destroy;
  4832. begin
  4833. if(FUnblockOutputPinEvent <> 0) then
  4834. begin
  4835. // This call should not fail because we have access to m_hUnblockOutputPinEvent
  4836. // and m_hUnblockOutputPinEvent is a valid event.
  4837. ASSERT(CloseHandle(FUnblockOutputPinEvent));
  4838. end;
  4839. if(FNotifyCallerPinBlockedEvent <> 0) then
  4840. begin
  4841. // This call should not fail because we have access to m_hNotifyCallerPinBlockedEvent
  4842. // and m_hNotifyCallerPinBlockedEvent is a valid event.
  4843. ASSERT(CloseHandle(FNotifyCallerPinBlockedEvent));
  4844. end;
  4845. if Assigned(FBlockStateLock) then FreeAndNil(FBlockStateLock);
  4846. inherited Destroy;
  4847. end;
  4848. function TBCDynamicOutputPin.NonDelegatingQueryInterface(const IID: TGUID; out Obj): HResult;
  4849. begin
  4850. if IsEqualGUID(IID,IID_IPinFlowControl) then
  4851. begin
  4852. if GetInterface(IID_IPinFlowControl, Obj) then Result := S_OK
  4853. else Result := E_NOINTERFACE;
  4854. end else
  4855. begin
  4856. Result := inherited NonDelegatingQueryInterface(IID,Obj);
  4857. end;
  4858. end;
  4859. function TBCDynamicOutputPin.Disconnect: HRESULT;
  4860. begin
  4861. FLock.Lock;
  4862. try
  4863. Result := DisconnectInternal;
  4864. finally
  4865. FLock.Unlock;
  4866. end;
  4867. end;
  4868. function TBCDynamicOutputPin.Block(dwBlockFlags: DWORD; hEvent: THandle): HResult;
  4869. begin
  4870. // Check for illegal flags.
  4871. if BOOL(dwBlockFlags and not AM_PIN_FLOW_CONTROL_BLOCK) then
  4872. begin
  4873. Result := E_INVALIDARG;
  4874. Exit;
  4875. end;
  4876. // Make sure the event is unsignaled.
  4877. if(BOOL(dwBlockFlags and AM_PIN_FLOW_CONTROL_BLOCK) and (hEvent <> 0)) then
  4878. begin
  4879. if not ResetEvent(hEvent) then
  4880. begin
  4881. Result := AmGetLastErrorToHResult;
  4882. Exit
  4883. end;
  4884. end;
  4885. // No flags are set if we are unblocking the output pin.
  4886. if(dwBlockFlags = 0) then
  4887. begin
  4888. // This parameter should be NULL because unblock operations are always synchronous.
  4889. // There is no need to notify the caller when the event is done.
  4890. if(hEvent <> 0) then
  4891. begin
  4892. Result := E_INVALIDARG;
  4893. Exit;
  4894. end;
  4895. end;
  4896. {$IFDEF DEBUG}
  4897. AssertValid;
  4898. {$ENDIF} // DEBUG
  4899. if BOOL(dwBlockFlags and AM_PIN_FLOW_CONTROL_BLOCK) then
  4900. begin
  4901. // IPinFlowControl::Block()'s hEvent parameter is NULL if the block is synchronous.
  4902. // If hEvent is not NULL, the block is asynchronous.
  4903. if(hEvent = 0) then Result := SynchronousBlockOutputPin
  4904. else Result := AsynchronousBlockOutputPin(hEvent);
  4905. end else
  4906. begin
  4907. Result := UnblockOutputPin;
  4908. end;
  4909. {$IFDEF DEBUG}
  4910. AssertValid;
  4911. {$ENDIF} // DEBUG
  4912. if(FAILED(Result)) then Exit;
  4913. Result := S_OK;
  4914. end;
  4915. procedure TBCDynamicOutputPin.SetConfigInfo(GraphConfig: IGraphConfig; StopEvent: THandle);
  4916. begin
  4917. // This pointer is not addrefed because filters are not allowed to
  4918. // hold references to the filter graph manager. See the documentation for
  4919. // IBaseFilter::JoinFilterGraph() in the Direct Show SDK for more information.
  4920. Pointer(FGraphConfig) := Pointer(GraphConfig);
  4921. FStopEvent := StopEvent;
  4922. end;
  4923. {$IFDEF DEBUG}
  4924. function TBCDynamicOutputPin.Deliver(Sample: IMediaSample): HRESULT;
  4925. begin
  4926. // The caller should call StartUsingOutputPin() before calling this
  4927. // method.
  4928. ASSERT(StreamingThreadUsingOutputPin);
  4929. Result := inherited Deliver(Sample);
  4930. end;
  4931. function TBCDynamicOutputPin.DeliverEndOfStream: HRESULT;
  4932. begin
  4933. // The caller should call StartUsingOutputPin() before calling this
  4934. // method.
  4935. ASSERT(StreamingThreadUsingOutputPin);
  4936. Result := inherited DeliverEndOfStream;
  4937. end;
  4938. function TBCDynamicOutputPin.DeliverNewSegment(Start, Stop: TReferenceTime; Rate: Double): HRESULT;
  4939. begin
  4940. // The caller should call StartUsingOutputPin() before calling this
  4941. // method.
  4942. ASSERT(StreamingThreadUsingOutputPin);
  4943. Result := inherited DeliverNewSegment(Start, Stop, Rate);
  4944. end;
  4945. {$ENDIF}
  4946. function TBCDynamicOutputPin.DeliverBeginFlush: HRESULT;
  4947. begin
  4948. // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo().
  4949. // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called.
  4950. // An event handle is invalid if 1) the event does not exist or the user does not have the security
  4951. // permissions to use the event.
  4952. ASSERT(SetEvent(FStopEvent));
  4953. Result := inherited DeliverBeginFlush;
  4954. end;
  4955. function TBCDynamicOutputPin.DeliverEndFlush: HRESULT;
  4956. begin
  4957. // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo().
  4958. // The ASSERT can also fire if the event if destroyed and then DeliverBeginFlush() is called.
  4959. // An event handle is invalid if 1) the event does not exist or the user does not have the security
  4960. // permissions to use the event.
  4961. ASSERT(ResetEvent(FStopEvent));
  4962. Result := inherited DeliverEndFlush;
  4963. end;
  4964. function TBCDynamicOutputPin.Active: HRESULT;
  4965. begin
  4966. // Make sure the user initialized the object by calling SetConfigInfo().
  4967. if(FStopEvent = 0) or (FGraphConfig = nil) then
  4968. begin
  4969. {$IFDEF DEBUG}
  4970. DbgLog('ERROR: TBCDynamicOutputPin.Active() failed because m_pGraphConfig' +
  4971. ' and m_hStopEvent were not initialized. Call SetConfigInfo() to initialize them.');
  4972. {$ENDIF} // DEBUG
  4973. Result := E_FAIL;
  4974. Exit;
  4975. end;
  4976. // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo().
  4977. // The ASSERT can also fire if the event if destroyed and then Active() is called. An event
  4978. // handle is invalid if 1) the event does not exist or the user does not have the security
  4979. // permissions to use the event.
  4980. ASSERT(ResetEvent(FStopEvent));
  4981. Result := inherited Active;
  4982. end;
  4983. function TBCDynamicOutputPin.Inactive: HRESULT;
  4984. begin
  4985. // If this ASSERT fires, the user may have passed an invalid event handle to SetConfigInfo().
  4986. // The ASSERT can also fire if the event if destroyed and then Active() is called. An event
  4987. // handle is invalid if 1) the event does not exist or the user does not have the security
  4988. // permissions to use the event.
  4989. ASSERT(SetEvent(FStopEvent));
  4990. Result := inherited Inactive;
  4991. end;
  4992. function TBCDynamicOutputPin.CompleteConnect(ReceivePin: IPin): HRESULT;
  4993. begin
  4994. Result := inherited CompleteConnect(ReceivePin);
  4995. if(SUCCEEDED(Result)) then
  4996. begin
  4997. if (not IsStopped) and (FAllocator <> nil) then
  4998. begin
  4999. Result := FAllocator.Commit;
  5000. ASSERT(Result <> VFW_E_ALREADY_COMMITTED);
  5001. end;
  5002. end;
  5003. end;
  5004. function TBCDynamicOutputPin.StartUsingOutputPin: HRESULT;
  5005. var
  5006. WaitEvents: array[0..1] of THandle;
  5007. NumWaitEvents: DWORD;
  5008. ReturnValue: DWORD;
  5009. begin
  5010. // The caller should not hold m_BlockStateLock. If the caller does,
  5011. // a deadlock could occur.
  5012. ASSERT(FBlockStateLock.CritCheckIn);
  5013. FBlockStateLock.Lock;
  5014. try
  5015. {$IFDEF DEBUG}
  5016. AssertValid;
  5017. {$ENDIF} // DEBUG
  5018. // Are we in the middle of a block operation?
  5019. while(BLOCKED = FBlockState) do
  5020. begin
  5021. FBlockStateLock.Unlock;
  5022. // If this ASSERT fires, a deadlock could occur. The caller should make sure
  5023. // that this thread never acquires the Block State lock more than once.
  5024. ASSERT(FBlockStateLock.CritCheckIn);
  5025. // WaitForMultipleObjects() returns WAIT_OBJECT_0 if the unblock event
  5026. // is fired. It returns WAIT_OBJECT_0 + 1 if the stop event if fired.
  5027. // See the Windows SDK documentation for more information on
  5028. // WaitForMultipleObjects().
  5029. WaitEvents[0] := FUnblockOutputPinEvent;
  5030. WaitEvents[0] := FStopEvent;
  5031. NumWaitEvents := sizeof(WaitEvents) div sizeof(THANDLE);
  5032. ReturnValue := WaitForMultipleObjects(NumWaitEvents, @WaitEvents, False, INFINITE);
  5033. FBlockStateLock.Lock;
  5034. {$IFDEF DEBUG}
  5035. AssertValid;
  5036. {$ENDIF} // DEBUG
  5037. case ReturnValue of
  5038. WAIT_OBJECT_0: break;
  5039. WAIT_OBJECT_0 + 1:
  5040. begin
  5041. Result := VFW_E_STATE_CHANGED;
  5042. Exit;
  5043. end;
  5044. WAIT_FAILED:
  5045. begin
  5046. Result := AmGetLastErrorToHResult;
  5047. Exit;
  5048. end;
  5049. else
  5050. begin
  5051. {$IFDEF DEBUG}
  5052. DbgLog('An Unexpected case occured in TBCDynamicOutputPin.StartUsingOutputPin().');
  5053. {$ENDIF} // DEBUG
  5054. Result := E_UNEXPECTED;
  5055. Exit;
  5056. end;
  5057. end;
  5058. end;
  5059. inc(FNumOutstandingOutputPinUsers);
  5060. {$IFDEF DEBUG}
  5061. AssertValid;
  5062. {$ENDIF} // DEBUG
  5063. Result := S_OK;
  5064. finally
  5065. FBlockStateLock.Unlock;
  5066. end;
  5067. end;
  5068. procedure TBCDynamicOutputPin.StopUsingOutputPin;
  5069. begin
  5070. FBlockStateLock.Lock;
  5071. try
  5072. {$IFDEF DEBUG}
  5073. AssertValid;
  5074. {$ENDIF} // DEBUG
  5075. dec(FNumOutstandingOutputPinUsers);
  5076. if(FNumOutstandingOutputPinUsers = 0) and (NOT_BLOCKED <> FBlockState)
  5077. then BlockOutputPin;
  5078. {$IFDEF DEBUG}
  5079. AssertValid;
  5080. {$ENDIF} // DEBUG
  5081. finally
  5082. FBlockStateLock.Unlock;
  5083. end;
  5084. end;
  5085. function TBCDynamicOutputPin.StreamingThreadUsingOutputPin: Boolean;
  5086. begin
  5087. FBlockStateLock.Lock;
  5088. try
  5089. Result := (FNumOutstandingOutputPinUsers > 0);
  5090. finally
  5091. FBlockStateLock.UnLock;
  5092. end;
  5093. end;
  5094. function TBCDynamicOutputPin.ChangeOutputFormat(const pmt: PAMMEdiaType; tSegmentStart, tSegmentStop:
  5095. TreferenceTime; dSegmentRate: Double): HRESULT;
  5096. begin
  5097. // The caller should call StartUsingOutputPin() before calling this
  5098. // method.
  5099. ASSERT(StreamingThreadUsingOutputPin);
  5100. // Callers should always pass a valid media type to ChangeOutputFormat() .
  5101. ASSERT(pmt <> nil);
  5102. Result := ChangeMediaType(pmt);
  5103. if (FAILED(Result)) then Exit;
  5104. Result :=DeliverNewSegment(tSegmentStart, tSegmentStop, dSegmentRate);
  5105. if(FAILED(Result)) then Exit;
  5106. Result := S_OK;
  5107. end;
  5108. function TBCDynamicOutputPin.ChangeMediaType(const pmt: PAMMediaType): HRESULT;
  5109. var
  5110. pConnection: IPinConnection;
  5111. begin
  5112. // The caller should call StartUsingOutputPin() before calling this
  5113. // method.
  5114. ASSERT(StreamingThreadUsingOutputPin);
  5115. // This function assumes the filter graph is running.
  5116. ASSERT(not IsStopped);
  5117. if (not IsConnected) then
  5118. begin
  5119. Result := VFW_E_NOT_CONNECTED;
  5120. Exit;
  5121. end;
  5122. // First check if the downstream pin will accept a dynamic
  5123. // format change
  5124. FConnected.QueryInterface(IID_IPinConnection, pConnection);
  5125. if(pConnection <> nil) then
  5126. begin
  5127. if(S_OK = pConnection.DynamicQueryAccept(pmt^)) then
  5128. begin
  5129. Result := ChangeMediaTypeHelper(pmt);
  5130. if(FAILED(Result)) then Exit;
  5131. Result := S_OK;
  5132. Exit;
  5133. end;
  5134. end;
  5135. // Can't do the dynamic connection
  5136. Result := DynamicReconnect(pmt);
  5137. end;
  5138. // this method has to be called from the thread that is pushing data,
  5139. // and it's the caller's responsibility to make sure that the thread
  5140. // has no outstand samples because they cannot be delivered after a
  5141. // reconnect
  5142. //
  5143. function TBCDynamicOutputPin.DynamicReconnect(const pmt: PAMMediaType): HRESULT;
  5144. begin
  5145. // The caller should call StartUsingOutputPin() before calling this
  5146. // method.
  5147. ASSERT(StreamingThreadUsingOutputPin);
  5148. if(FGraphConfig = nil) or (FStopEvent = 0) then
  5149. begin
  5150. Result := E_FAIL;
  5151. Exit;
  5152. end;
  5153. Result := FGraphConfig.Reconnect(Self,nil,pmt,nil,FStopEvent,
  5154. AM_GRAPH_CONFIG_RECONNECT_CACHE_REMOVED_FILTERS);
  5155. end;
  5156. function TBCDynamicOutputPin.SynchronousBlockOutputPin: HRESULT;
  5157. var
  5158. NotifyCallerPinBlockedEvent: THandle;
  5159. begin
  5160. NotifyCallerPinBlockedEvent := CreateEvent(nil, // The event will have the default security attributes.
  5161. False, // This is an automatic reset event.
  5162. False, // The event is initially unsignaled.
  5163. nil); // The event is not named.
  5164. // CreateEvent() returns NULL if an error occurs.
  5165. if(NotifyCallerPinBlockedEvent = 0) then
  5166. begin
  5167. Result := AmGetLastErrorToHResult;
  5168. Exit;
  5169. end;
  5170. Result := AsynchronousBlockOutputPin(NotifyCallerPinBlockedEvent);
  5171. if(FAILED(Result)) then
  5172. begin
  5173. // This call should not fail because we have access to hNotifyCallerPinBlockedEvent
  5174. // and hNotifyCallerPinBlockedEvent is a valid event.
  5175. ASSERT(CloseHandle(NotifyCallerPinBlockedEvent));
  5176. Exit;
  5177. end;
  5178. Result := WaitEvent(NotifyCallerPinBlockedEvent);
  5179. // This call should not fail because we have access to hNotifyCallerPinBlockedEvent
  5180. // and hNotifyCallerPinBlockedEvent is a valid event.
  5181. ASSERT(CloseHandle(NotifyCallerPinBlockedEvent));
  5182. if(FAILED(Result)) then Exit;
  5183. Result := S_OK;
  5184. end;
  5185. function TBCDynamicOutputPin.AsynchronousBlockOutputPin(NotifyCallerPinBlockedEvent: THandle): HRESULT;
  5186. var
  5187. Success : Boolean;
  5188. begin
  5189. // This function holds the m_BlockStateLock because it uses
  5190. // m_dwBlockCallerThreadID, m_BlockState and
  5191. // m_hNotifyCallerPinBlockedEvent.
  5192. FBlockStateLock.Lock;
  5193. try
  5194. if (NOT_BLOCKED <> FBlockState) then
  5195. begin
  5196. if(FBlockCallerThreadID = GetCurrentThreadId)
  5197. then Result := VFW_E_PIN_ALREADY_BLOCKED_ON_THIS_THREAD
  5198. else Result := VFW_E_PIN_ALREADY_BLOCKED;
  5199. Exit;
  5200. end;
  5201. Success := DuplicateHandle(GetCurrentProcess,
  5202. NotifyCallerPinBlockedEvent,
  5203. GetCurrentProcess,
  5204. @FNotifyCallerPinBlockedEvent,
  5205. EVENT_MODIFY_STATE,
  5206. False,
  5207. 0);
  5208. if not Success then
  5209. begin
  5210. Result := AmGetLastErrorToHResult;
  5211. Exit;
  5212. end;
  5213. FBlockState := PENDING;
  5214. FBlockCallerThreadID := GetCurrentThreadId;
  5215. // The output pin cannot be blocked if the streaming thread is
  5216. // calling IPin::NewSegment(), IPin::EndOfStream(), IMemInputPin::Receive()
  5217. // or IMemInputPin::ReceiveMultiple() on the connected input pin. Also, it
  5218. // cannot be blocked if the streaming thread is calling DynamicReconnect(),
  5219. // ChangeMediaType() or ChangeOutputFormat().
  5220. // The output pin can be immediately blocked.
  5221. if not StreamingThreadUsingOutputPin then BlockOutputPin();
  5222. Result := S_OK;
  5223. finally
  5224. FBlockStateLock.Unlock;
  5225. end;
  5226. end;
  5227. function TBCDynamicOutputPin.UnblockOutputPin: HRESULT;
  5228. begin
  5229. // UnblockOutputPin() holds the m_BlockStateLock because it
  5230. // uses m_BlockState, m_dwBlockCallerThreadID and
  5231. // m_hNotifyCallerPinBlockedEvent.
  5232. FBlockStateLock.Lock;
  5233. try
  5234. if (NOT_BLOCKED = FBlockState) then
  5235. begin
  5236. Result := S_FALSE;
  5237. Exit;
  5238. end;
  5239. // This should not fail because we successfully created the event
  5240. // and we have the security permissions to change it's state.
  5241. ASSERT(SetEvent(FUnblockOutputPinEvent));
  5242. // Cancel the block operation if it's still pending.
  5243. if (FNotifyCallerPinBlockedEvent <> 0) then
  5244. begin
  5245. // This event should not fail because AsynchronousBlockOutputPin() successfully
  5246. // duplicated this handle and we have the appropriate security permissions.
  5247. ASSERT(SetEvent(FNotifyCallerPinBlockedEvent));
  5248. ASSERT(CloseHandle(FNotifyCallerPinBlockedEvent));
  5249. end;
  5250. FBlockState := NOT_BLOCKED;
  5251. FBlockCallerThreadID := 0;
  5252. FNotifyCallerPinBlockedEvent := 0;
  5253. Result := S_OK;
  5254. finally
  5255. FBlockStateLock.Unlock;
  5256. end;
  5257. end;
  5258. procedure TBCDynamicOutputPin.BlockOutputPin;
  5259. begin
  5260. // The caller should always hold the m_BlockStateLock because this function
  5261. // uses m_BlockState and m_hNotifyCallerPinBlockedEvent.
  5262. ASSERT(FBlockStateLock.CritCheckIn);
  5263. // This function should not be called if the streaming thread is modifying
  5264. // the connection state or it's passing data downstream.
  5265. ASSERT(not StreamingThreadUsingOutputPin);
  5266. // This should not fail because we successfully created the event
  5267. // and we have the security permissions to change it's state.
  5268. ASSERT(ResetEvent(FUnblockOutputPinEvent));
  5269. // This event should not fail because AsynchronousBlockOutputPin() successfully
  5270. // duplicated this handle and we have the appropriate security permissions.
  5271. ASSERT(SetEvent(FNotifyCallerPinBlockedEvent));
  5272. ASSERT(CloseHandle(FNotifyCallerPinBlockedEvent));
  5273. FBlockState := BLOCKED;
  5274. FNotifyCallerPinBlockedEvent := 0;
  5275. end;
  5276. procedure TBCDynamicOutputPin.ResetBlockState;
  5277. begin
  5278. end;
  5279. class function TBCDynamicOutputPin.WaitEvent(Event: THandle): HRESULT;
  5280. var
  5281. ReturnValue: DWORD;
  5282. begin
  5283. ReturnValue := WaitForSingleObject(Event, INFINITE);
  5284. case ReturnValue of
  5285. WAIT_OBJECT_0: Result := S_OK;
  5286. WAIT_FAILED : Result := AmGetLastErrorToHResult;
  5287. else
  5288. begin
  5289. {$IFDEF DEBUG}
  5290. DbgLog('An Unexpected case occured in TBCDynamicOutputPin::WaitEvent.');
  5291. {$ENDIF}
  5292. Result := E_UNEXPECTED;
  5293. end;
  5294. end;
  5295. end;
  5296. function TBCDynamicOutputPin.Initialize: HRESULT;
  5297. begin
  5298. FUnblockOutputPinEvent := CreateEvent(nil, // The event will have the default security descriptor.
  5299. True, // This is a manual reset event.
  5300. True, // The event is initially signaled.
  5301. nil); // The event is not named.
  5302. // CreateEvent() returns NULL if an error occurs.
  5303. if (FUnblockOutputPinEvent = 0) then
  5304. begin
  5305. Result := AmGetLastErrorToHResult;
  5306. Exit;
  5307. end;
  5308. // Set flag to say we can reconnect while streaming.
  5309. CanReconnectWhenActive := True;
  5310. Result := S_OK;
  5311. end;
  5312. function TBCDynamicOutputPin.ChangeMediaTypeHelper(const pmt: PAMMediaType): HRESULT;
  5313. var
  5314. InputPinRequirements: ALLOCATOR_PROPERTIES;
  5315. begin
  5316. // The caller should call StartUsingOutputPin() before calling this
  5317. // method.
  5318. ASSERT(StreamingThreadUsingOutputPin);
  5319. Result := FConnected.ReceiveConnection(Self,pmt^);
  5320. if(FAILED(Result)) then Exit;
  5321. Result := SetMediaType(pmt);
  5322. if(FAILED(Result)) then Exit;
  5323. // Does this pin use the local memory transport?
  5324. if(FInputPin <> nil) then
  5325. begin
  5326. // This function assumes that m_pInputPin and m_Connected are
  5327. // two different interfaces to the same object.
  5328. ASSERT(IsEqualObject(FConnected, FInputPin));
  5329. InputPinRequirements.cbAlign := 0;
  5330. InputPinRequirements.cbBuffer := 0;
  5331. InputPinRequirements.cbPrefix := 0;
  5332. InputPinRequirements.cBuffers := 0;
  5333. FInputPin.GetAllocatorRequirements(InputPinRequirements);
  5334. // A zero allignment does not make any sense.
  5335. if(0 = InputPinRequirements.cbAlign)
  5336. then InputPinRequirements.cbAlign := 1;
  5337. Result := FAllocator.Decommit;
  5338. if(FAILED(Result)) then Exit;
  5339. Result := DecideBufferSize(FAllocator, @InputPinRequirements);
  5340. if(FAILED(Result)) then Exit;
  5341. Result := FAllocator.Commit;
  5342. if(FAILED(Result)) then Exit;
  5343. Result := FInputPin.NotifyAllocator(FAllocator, FPinUsesReadOnlyAllocator);
  5344. if(FAILED(Result)) then Exit;
  5345. end;
  5346. Result := S_OK;
  5347. end;
  5348. {$IFDEF DEBUG}
  5349. procedure TBCDynamicOutputPin.AssertValid;
  5350. begin
  5351. // Make sure the object was correctly initialized.
  5352. // This ASSERT only fires if the object failed to initialize
  5353. // and the user ignored the constructor's return code (phr).
  5354. ASSERT(FUnblockOutputPinEvent <> 0);
  5355. // If either of these ASSERTs fire, the user did not correctly call
  5356. // SetConfigInfo().
  5357. ASSERT(FStopEvent <> 0);
  5358. ASSERT(FGraphConfig <> nil);
  5359. // Make sure the block state is consistent.
  5360. FBlockStateLock.Lock;
  5361. try
  5362. // BLOCK_STATE variables only have three legal values: PENDING, BLOCKED and NOT_BLOCKED.
  5363. ASSERT((NOT_BLOCKED = FBlockState) or (PENDING = FBlockState) or (BLOCKED = FBlockState));
  5364. // m_hNotifyCallerPinBlockedEvent is only needed when a block operation cannot complete
  5365. // immediately.
  5366. ASSERT(((FNotifyCallerPinBlockedEvent = 0) and (PENDING <> FBlockState)) or
  5367. ((FNotifyCallerPinBlockedEvent <> 0) and (PENDING = FBlockState)) );
  5368. // m_dwBlockCallerThreadID should always be 0 if the pin is not blocked and
  5369. // the user is not trying to block the pin.
  5370. ASSERT((0 = FBlockCallerThreadID) or (NOT_BLOCKED <> FBlockState));
  5371. // If this ASSERT fires, the streaming thread is using the output pin and the
  5372. // output pin is blocked.
  5373. ASSERT(((0 <> FNumOutstandingOutputPinUsers) and (BLOCKED <> FBlockState)) or
  5374. ((0 = FNumOutstandingOutputPinUsers) and (NOT_BLOCKED <> FBlockState)) or
  5375. ((0 = FNumOutstandingOutputPinUsers) and (NOT_BLOCKED = FBlockState)) );
  5376. finally
  5377. FBlockStateLock.UnLock;
  5378. end;
  5379. end;
  5380. {$ENDIF}
  5381. // milenko end
  5382. { TBCTransformInputPin }
  5383. // enter flushing state. Call default handler to block Receives, then
  5384. // pass to overridable method in filter
  5385. function TBCTransformInputPin.BeginFlush: HRESULT;
  5386. begin
  5387. FTransformFilter.FcsFilter.Lock;
  5388. try
  5389. // Are we actually doing anything?
  5390. ASSERT(FTransformFilter.FOutput <> nil);
  5391. if ((not IsConnected) or (not FTransformFilter.FOutput.IsConnected)) then
  5392. begin
  5393. result := VFW_E_NOT_CONNECTED;
  5394. exit;
  5395. end;
  5396. result := inherited BeginFlush;
  5397. if FAILED(result) then exit;
  5398. result := FTransformFilter.BeginFlush;
  5399. finally
  5400. FTransformFilter.FcsFilter.UnLock;
  5401. end;
  5402. end;
  5403. // provides derived filter a chance to release it's extra interfaces
  5404. function TBCTransformInputPin.BreakConnect: HRESULT;
  5405. begin
  5406. ASSERT(IsStopped);
  5407. FTransformFilter.BreakConnect(PINDIR_INPUT);
  5408. result := inherited BreakConnect;
  5409. end;
  5410. function TBCTransformInputPin.CheckConnect(Pin: IPin): HRESULT;
  5411. begin
  5412. result := FTransformFilter.CheckConnect(PINDIR_INPUT, Pin);
  5413. if FAILED(result) then exit;
  5414. result := inherited CheckConnect(Pin);
  5415. end;
  5416. // check that we can support a given media type
  5417. function TBCTransformInputPin.CheckMediaType(
  5418. mtIn: PAMMediaType): HRESULT;
  5419. begin
  5420. // Check the input type
  5421. result := FTransformFilter.CheckInputType(mtIn);
  5422. if (S_OK <> result) then exit;
  5423. // if the output pin is still connected, then we have
  5424. // to check the transform not just the input format
  5425. if ((FTransformFilter.FOutput <> nil) and
  5426. (FTransformFilter.FOutput.IsConnected)) then
  5427. begin
  5428. result := FTransformFilter.CheckTransform(mtIn,
  5429. FTransformFilter.FOutput.AMMediaType);
  5430. end;
  5431. end;
  5432. function TBCTransformInputPin.CheckStreaming: HRESULT;
  5433. begin
  5434. ASSERT(FTransformFilter.FOutput <> nil);
  5435. if(not FTransformFilter.FOutput.IsConnected) then
  5436. begin
  5437. result := VFW_E_NOT_CONNECTED;
  5438. exit;
  5439. end
  5440. else
  5441. begin
  5442. // Shouldn't be able to get any data if we're not connected!
  5443. ASSERT(IsConnected);
  5444. // we're flushing
  5445. if FFlushing then
  5446. begin
  5447. result := S_FALSE;
  5448. exit;
  5449. end;
  5450. // Don't process stuff in Stopped state
  5451. if IsStopped then
  5452. begin
  5453. result := VFW_E_WRONG_STATE;
  5454. exit;
  5455. end;
  5456. if FRunTimeError then
  5457. begin
  5458. result := VFW_E_RUNTIME_ERROR;
  5459. exit;
  5460. end;
  5461. result := S_OK;
  5462. end;
  5463. end;
  5464. function TBCTransformInputPin.CompleteConnect(ReceivePin: IPin): HRESULT;
  5465. begin
  5466. result := FTransformFilter.CompleteConnect(PINDIR_INPUT, ReceivePin);
  5467. if FAILED(result) then exit;
  5468. result := inherited CompleteConnect(ReceivePin);
  5469. end;
  5470. constructor TBCTransformInputPin.Create(ObjectName: string;
  5471. TransformFilter: TBCTransformFilter; out hr: HRESULT; Name: WideString);
  5472. begin
  5473. inherited Create(ObjectName, TransformFilter, TransformFilter.FcsFilter, hr, Name);
  5474. {$IFDEF DEBUG}
  5475. DbgLog(self, 'TBCTransformInputPin.Create');
  5476. {$ENDIF}
  5477. FTransformFilter := TransformFilter;
  5478. end;
  5479. // leave flushing state.
  5480. // Pass to overridable method in filter, then call base class
  5481. // to unblock receives (finally)
  5482. destructor TBCTransformInputPin.destroy;
  5483. begin
  5484. {$IFDEF DEBUG}
  5485. DbgLog(self, 'TBCTransformInputPin.destroy');
  5486. {$ENDIF}
  5487. inherited;
  5488. end;
  5489. function TBCTransformInputPin.EndFlush: HRESULT;
  5490. begin
  5491. FTransformFilter.FcsFilter.Lock;
  5492. try
  5493. // Are we actually doing anything?
  5494. ASSERT(FTransformFilter.FOutput <> nil);
  5495. if((not IsConnected) or (not FTransformFilter.FOutput.IsConnected)) then
  5496. begin
  5497. result := VFW_E_NOT_CONNECTED;
  5498. exit;
  5499. end;
  5500. result := FTransformFilter.EndFlush;
  5501. if FAILED(result) then exit;
  5502. result := inherited EndFlush;
  5503. finally
  5504. FTransformFilter.FcsFilter.UnLock;
  5505. end;
  5506. end;
  5507. // provide EndOfStream that passes straight downstream
  5508. // (there is no queued data)
  5509. function TBCTransformInputPin.EndOfStream: HRESULT;
  5510. begin
  5511. FTransformFilter.FcsReceive.Lock;
  5512. try
  5513. result := CheckStreaming;
  5514. if (S_OK = result) then
  5515. result := FTransformFilter.EndOfStream;
  5516. finally
  5517. FTransformFilter.FcsReceive.UnLock;
  5518. end;
  5519. end;
  5520. function TBCTransformInputPin.NewSegment(Start, Stop: TReferenceTime;
  5521. Rate: double): HRESULT;
  5522. begin
  5523. // Save the values in the pin
  5524. inherited NewSegment(Start, Stop, Rate);
  5525. result := FTransformFilter.NewSegment(Start, Stop, Rate);
  5526. end;
  5527. function TBCTransformInputPin.QueryId(out id: PWideChar): HRESULT;
  5528. begin
  5529. // milenko start (AMGetWideString was bugged, now the second line is not needed)
  5530. Result := AMGetWideString('In', Id);
  5531. // if id <> nil then result := S_OK else result := S_FALSE;
  5532. // milenko end
  5533. end;
  5534. // here's the next block of data from the stream.
  5535. // AddRef it yourself if you need to hold it beyond the end
  5536. // of this call.
  5537. function TBCTransformInputPin.Receive(pSample: IMediaSample): HRESULT;
  5538. begin
  5539. FTransformFilter.FcsReceive.Lock;
  5540. try
  5541. ASSERT(pSample <> nil);
  5542. // check all is well with the base class
  5543. result := inherited Receive(pSample);
  5544. if (result = S_OK) then
  5545. result := FTransformFilter.Receive(pSample);
  5546. finally
  5547. FTransformFilter.FcsReceive.Unlock;
  5548. end;
  5549. end;
  5550. // set the media type for this connection
  5551. function TBCTransformInputPin.SetMediaType(mt: PAMMediaType): HRESULT;
  5552. begin
  5553. // Set the base class media type (should always succeed)
  5554. result := inherited SetMediaType(mt);
  5555. if FAILED(result) then exit;
  5556. // check the transform can be done (should always succeed)
  5557. ASSERT(SUCCEEDED(FTransformFilter.CheckInputType(mt)));
  5558. result := FTransformFilter.SetMediaType(PINDIR_INPUT,mt);
  5559. end;
  5560. { TBCCritSec }
  5561. constructor TBCCritSec.Create;
  5562. begin
  5563. InitializeCriticalSection(FCritSec);
  5564. {$IFDEF DEBUG}
  5565. FcurrentOwner := 0;
  5566. FlockCount := 0;
  5567. // {$IFDEF TRACE}
  5568. // FTrace := True;
  5569. // {$ELSE}
  5570. // FTrace := FALSE;
  5571. // {$ENDIF}
  5572. {$ENDIF}
  5573. end;
  5574. function TBCCritSec.CritCheckIn: boolean;
  5575. begin
  5576. {$IFDEF DEBUG}
  5577. result := (GetCurrentThreadId = Self.FcurrentOwner);
  5578. {$ELSE}
  5579. result := True;
  5580. {$ENDIF}
  5581. end;
  5582. function TBCCritSec.CritCheckOut: boolean;
  5583. begin
  5584. {$IFDEF DEBUG}
  5585. result := (GetCurrentThreadId <> Self.FcurrentOwner);
  5586. {$ELSE}
  5587. result := false;
  5588. {$ENDIF}
  5589. end;
  5590. destructor TBCCritSec.Destroy;
  5591. begin
  5592. DeleteCriticalSection(FCritSec)
  5593. end;
  5594. procedure TBCCritSec.Lock;
  5595. begin
  5596. {$IFDEF DEBUG}
  5597. if ((FCurrentOwner <> 0) and (FCurrentOwner <> GetCurrentThreadId)) then
  5598. begin
  5599. // already owned, but not by us
  5600. {$IFDEF TRACE}
  5601. DbgLog(format('Thread %d about to wait for lock %x owned by %d',
  5602. [GetCurrentThreadId, longint(self), FCurrentOwner]));
  5603. {$ENDIF}
  5604. end;
  5605. {$ENDIF}
  5606. EnterCriticalSection(FCritSec);
  5607. {$IFDEF DEBUG}
  5608. inc(FLockCount);
  5609. if (FLockCount > 0) then
  5610. begin
  5611. // we now own it for the first time. Set owner information
  5612. FcurrentOwner := GetCurrentThreadId;
  5613. {$IFDEF TRACE}
  5614. DbgLog(format('Thread %d now owns lock %x', [FcurrentOwner, LongInt(self)]));
  5615. {$ENDIF}
  5616. end;
  5617. {$ENDIF}
  5618. end;
  5619. procedure TBCCritSec.UnLock;
  5620. begin
  5621. {$IFDEF DEBUG}
  5622. dec(FlockCount);
  5623. if(FlockCount = 0) then
  5624. begin
  5625. // about to be unowned
  5626. {$IFDEF TRACE}
  5627. DbgLog(format('Thread %d releasing lock %x', [FcurrentOwner, LongInt(Self)]));
  5628. {$ENDIF}
  5629. FcurrentOwner := 0;
  5630. end;
  5631. {$ENDIF}
  5632. LeaveCriticalSection(FCritSec)
  5633. end;
  5634. { TBCTransformFilter }
  5635. // Return S_FALSE to mean "pass the note on upstream"
  5636. // Return NOERROR (Same as S_OK)
  5637. // to mean "I've done something about it, don't pass it on"
  5638. function TBCTransformFilter.AlterQuality(const q: TQuality): HRESULT;
  5639. begin
  5640. result := S_FALSE;
  5641. end;
  5642. // enter flush state. Receives already blocked
  5643. // must override this if you have queued data or a worker thread
  5644. function TBCTransformFilter.BeginFlush: HRESULT;
  5645. begin
  5646. result := NOERROR;
  5647. if (FOutput <> nil) then
  5648. // block receives -- done by caller (CBaseInputPin::BeginFlush)
  5649. // discard queued data -- we have no queued data
  5650. // free anyone blocked on receive - not possible in this filter
  5651. // call downstream
  5652. result := FOutput.DeliverBeginFlush;
  5653. end;
  5654. function TBCTransformFilter.BreakConnect(dir: TPinDirection): HRESULT;
  5655. begin
  5656. result := NOERROR;
  5657. end;
  5658. function TBCTransformFilter.CheckConnect(dir: TPinDirection;
  5659. Pin: IPin): HRESULT;
  5660. begin
  5661. result := NOERROR;
  5662. end;
  5663. function TBCTransformFilter.CompleteConnect(direction: TPinDirection;
  5664. ReceivePin: IPin): HRESULT;
  5665. begin
  5666. result := NOERROR;
  5667. end;
  5668. constructor TBCTransformFilter.Create(ObjectName: string; unk: IUnKnown;
  5669. const clsid: TGUID);
  5670. begin
  5671. FcsFilter := TBCCritSec.Create;
  5672. FcsReceive := TBCCritSec.Create;
  5673. inherited Create(ObjectName,Unk,FcsFilter, clsid);
  5674. FInput := nil;
  5675. FOutput := nil;
  5676. FEOSDelivered := FALSE;
  5677. FQualityChanged:= FALSE;
  5678. FSampleSkipped := FALSE;
  5679. {$ifdef PERF}
  5680. // RegisterPerfId;
  5681. {$endif}
  5682. end;
  5683. constructor TBCTransformFilter.CreateFromFactory(Factory: TBCClassFactory; const Controller: IUnknown);
  5684. begin
  5685. Create(Factory.FName, Controller, Factory.FClassID);
  5686. end;
  5687. destructor TBCTransformFilter.destroy;
  5688. begin
  5689. if FInput <> nil then FInput.Free;
  5690. if FOutput <> nil then FOutput.Free;
  5691. {$IFDEF DEBUG}
  5692. DbgLog(self, 'TBCTransformFilter.destroy');
  5693. {$ENDIF}
  5694. FcsReceive.Free;
  5695. inherited;
  5696. end;
  5697. // leave flush state. must override this if you have queued data
  5698. // or a worker thread
  5699. function TBCTransformFilter.EndFlush: HRESULT;
  5700. begin
  5701. // sync with pushing thread -- we have no worker thread
  5702. // ensure no more data to go downstream -- we have no queued data
  5703. // call EndFlush on downstream pins
  5704. ASSERT(FOutput <> nil);
  5705. result := FOutput.DeliverEndFlush;
  5706. // caller (the input pin's method) will unblock Receives
  5707. end;
  5708. // EndOfStream received. Default behaviour is to deliver straight
  5709. // downstream, since we have no queued data. If you overrode Receive
  5710. // and have queue data, then you need to handle this and deliver EOS after
  5711. // all queued data is sent
  5712. function TBCTransformFilter.EndOfStream: HRESULT;
  5713. begin
  5714. result := NOERROR;
  5715. if (FOutput <> nil) then
  5716. result := FOutput.DeliverEndOfStream;
  5717. end;
  5718. // If Id is In or Out then return the IPin* for that pin
  5719. // creating the pin if need be. Otherwise return NULL with an error.
  5720. function TBCTransformFilter.FindPin(Id: PWideChar; out ppPin: IPin): HRESULT;
  5721. begin
  5722. if(WideString(Id) = 'In') then ppPin := GetPin(0) else
  5723. if(WideString(Id) = 'Out') then ppPin := GetPin(1) else
  5724. begin
  5725. ppPin := nil;
  5726. result := VFW_E_NOT_FOUND;
  5727. exit;
  5728. end;
  5729. result := NOERROR;
  5730. if(ppPin = nil) then result := E_OUTOFMEMORY;
  5731. end;
  5732. // return a non-addrefed CBasePin * for the user to addref if he holds onto it
  5733. // for longer than his pointer to us. We create the pins dynamically when they
  5734. // are asked for rather than in the constructor. This is because we want to
  5735. // give the derived class an oppportunity to return different pin objects
  5736. // We return the objects as and when they are needed. If either of these fails
  5737. // then we return NULL, the assumption being that the caller will realise the
  5738. // whole deal is off and destroy us - which in turn will delete everything.
  5739. function TBCTransformFilter.GetPin(n: integer): TBCBasePin;
  5740. var hr: HRESULT;
  5741. begin
  5742. hr := S_OK;
  5743. // Create an input pin if necessary
  5744. if(FInput = nil) then
  5745. begin
  5746. FInput := TBCTransformInputPin.Create('Transform input pin',
  5747. self, // Owner filter
  5748. hr, // Result code
  5749. 'XForm In'); // Pin name
  5750. // Can't fail
  5751. ASSERT(SUCCEEDED(hr));
  5752. if(FInput = nil) then
  5753. begin
  5754. result := nil;
  5755. exit;
  5756. end;
  5757. FOutput := TBCTransformOutputPin.Create('Transform output pin',
  5758. self, // Owner filter
  5759. hr, // Result code
  5760. 'XForm Out'); // Pin name
  5761. // Can't fail
  5762. ASSERT(SUCCEEDED(hr));
  5763. if(FOutput = nil) then FreeAndNil(FInput);
  5764. end;
  5765. // Return the appropriate pin
  5766. case n of
  5767. 0 : result := FInput;
  5768. 1 : result := FOutput;
  5769. else
  5770. result := nil;
  5771. end;
  5772. end;
  5773. function TBCTransformFilter.GetPinCount: integer;
  5774. begin
  5775. result := 2;
  5776. end;
  5777. // Set up our output sample
  5778. function TBCTransformFilter.InitializeOutputSample(Sample: IMediaSample;
  5779. out OutSample: IMediaSample): HRESULT;
  5780. var
  5781. Props: PAMSample2Properties;
  5782. Flags: DWORD;
  5783. Start, Stop: PReferenceTime;
  5784. OutSample2: IMediaSample2;
  5785. OutProps: TAMSample2Properties;
  5786. MediaStart, MediaEnd: Int64;
  5787. begin
  5788. // default - times are the same
  5789. Props := FInput.SampleProps;
  5790. if FSampleSkipped then Flags := AM_GBF_PREVFRAMESKIPPED else Flags := 0;
  5791. // This will prevent the image renderer from switching us to DirectDraw
  5792. // when we can't do it without skipping frames because we're not on a
  5793. // keyframe. If it really has to switch us, it still will, but then we
  5794. // will have to wait for the next keyframe
  5795. if(not BOOL(Props.dwSampleFlags and AM_SAMPLE_SPLICEPOINT)) then Flags := Flags or AM_GBF_NOTASYNCPOINT;
  5796. ASSERT(FOutput.FAllocator <> nil);
  5797. if BOOL(Props.dwSampleFlags and AM_SAMPLE_TIMEVALID) then Start := @Props.tStart else Start := nil;
  5798. if BOOL(Props.dwSampleFlags and AM_SAMPLE_STOPVALID) then Stop := @Props.tStop else Stop := nil;
  5799. result := FOutput.FAllocator.GetBuffer(OutSample, Start, Stop, Flags);
  5800. if FAILED(result) then exit;
  5801. ASSERT(OutSample <> nil);
  5802. if SUCCEEDED(OutSample.QueryInterface(IID_IMediaSample2, OutSample2)) then
  5803. begin
  5804. ASSERT(SUCCEEDED(OutSample2.GetProperties(4*4, OutProps)));
  5805. OutProps.dwTypeSpecificFlags := Props.dwTypeSpecificFlags;
  5806. OutProps.dwSampleFlags := (OutProps.dwSampleFlags and AM_SAMPLE_TYPECHANGED) or
  5807. (Props.dwSampleFlags and (not AM_SAMPLE_TYPECHANGED));
  5808. OutProps.tStart := Props.tStart;
  5809. OutProps.tStop := Props.tStop;
  5810. OutProps.cbData := (4*4) + (2*8);
  5811. OutSample2.SetProperties((4*4)+(2*8), OutProps);
  5812. if BOOL(Props.dwSampleFlags and AM_SAMPLE_DATADISCONTINUITY) then FSampleSkipped := FALSE;
  5813. OutSample2 := nil;
  5814. end
  5815. else
  5816. begin
  5817. if BOOL(Props.dwSampleFlags and AM_SAMPLE_TIMEVALID) then
  5818. OutSample.SetTime(@Props.tStart, @Props.tStop);
  5819. if BOOL(Props.dwSampleFlags and AM_SAMPLE_SPLICEPOINT) then
  5820. OutSample.SetSyncPoint(True);
  5821. if BOOL(Props.dwSampleFlags and AM_SAMPLE_DATADISCONTINUITY) then
  5822. begin
  5823. OutSample.SetDiscontinuity(True);
  5824. FSampleSkipped := FALSE;
  5825. end;
  5826. // Copy the media times
  5827. if (Sample.GetMediaTime(MediaStart,MediaEnd) = NOERROR) then
  5828. OutSample.SetMediaTime(@MediaStart, @MediaEnd);
  5829. end;
  5830. result := S_OK;
  5831. end;
  5832. function TBCTransformFilter.NewSegment(Start, Stop: TReferenceTime;
  5833. Rate: double): HRESULT;
  5834. begin
  5835. result := S_OK;
  5836. if (FOutput <> nil) then
  5837. result := FOutput.DeliverNewSegment(Start, Stop, Rate);
  5838. end;
  5839. function TBCTransformFilter.Pause: HRESULT;
  5840. begin
  5841. FcsFilter.Lock;
  5842. try
  5843. result := NOERROR;
  5844. if (FState = State_Paused) then
  5845. begin
  5846. // (This space left deliberately blank)
  5847. end
  5848. // If we have no input pin or it isn't yet connected then when we are
  5849. // asked to pause we deliver an end of stream to the downstream filter.
  5850. // This makes sure that it doesn't sit there forever waiting for
  5851. // samples which we cannot ever deliver without an input connection.
  5852. else
  5853. if ((FInput = nil) or (FInput.IsConnected = FALSE)) then
  5854. begin
  5855. if ((FOutput <> nil) and (FEOSDelivered = FALSE)) then
  5856. begin
  5857. FOutput.DeliverEndOfStream;
  5858. FEOSDelivered := True;
  5859. end;
  5860. FState := State_Paused;
  5861. end
  5862. // We may have an input connection but no output connection
  5863. // However, if we have an input pin we do have an output pin
  5864. else
  5865. if (FOutput.IsConnected = FALSE) then
  5866. FState := State_Paused
  5867. else
  5868. begin
  5869. if(FState = State_Stopped) then
  5870. begin
  5871. // allow a class derived from CTransformFilter
  5872. // to know about starting and stopping streaming
  5873. FcsReceive.Lock;
  5874. try
  5875. result := StartStreaming;
  5876. finally
  5877. FcsReceive.UnLock;
  5878. end;
  5879. end;
  5880. if SUCCEEDED(result) then result := inherited Pause;
  5881. end;
  5882. FSampleSkipped := FALSE;
  5883. FQualityChanged := FALSE;
  5884. finally
  5885. FcsFilter.UnLock;
  5886. end;
  5887. end;
  5888. // override this to customize the transform process
  5889. function TBCTransformFilter.Receive(Sample: IMediaSample): HRESULT;
  5890. var
  5891. Props: PAMSample2Properties;
  5892. OutSample: IMediaSample;
  5893. begin
  5894. // Check for other streams and pass them on
  5895. Props := FInput.SampleProps;
  5896. if(Props.dwStreamId <> AM_STREAM_MEDIA) then
  5897. begin
  5898. result := FOutput.FInputPin.Receive(Sample);
  5899. exit;
  5900. end;
  5901. // If no output to deliver to then no point sending us data
  5902. ASSERT(FOutput <> nil) ;
  5903. // Set up the output sample
  5904. result := InitializeOutputSample(Sample, OutSample);
  5905. if FAILED(result) then exit;
  5906. result := Transform(Sample, OutSample);
  5907. if FAILED(result) then
  5908. begin
  5909. {$IFDEF DEBUG}
  5910. DbgLog(self, 'Error from transform');
  5911. {$ENDIF}
  5912. exit;
  5913. end
  5914. else
  5915. begin
  5916. // the Transform() function can return S_FALSE to indicate that the
  5917. // sample should not be delivered; we only deliver the sample if it's
  5918. // really S_OK (same as NOERROR, of course.)
  5919. if (result = NOERROR) then
  5920. begin
  5921. result := FOutput.FInputPin.Receive(OutSample);
  5922. FSampleSkipped := FALSE; // last thing no longer dropped
  5923. end
  5924. else
  5925. begin
  5926. // S_FALSE returned from Transform is a PRIVATE agreement
  5927. // We should return NOERROR from Receive() in this cause because returning S_FALSE
  5928. // from Receive() means that this is the end of the stream and no more data should
  5929. // be sent.
  5930. if (result = S_FALSE) then
  5931. begin
  5932. // Release the sample before calling notify to avoid
  5933. // deadlocks if the sample holds a lock on the system
  5934. // such as DirectDraw buffers do
  5935. OutSample := nil;
  5936. FSampleSkipped := True;
  5937. if not FQualityChanged then
  5938. begin
  5939. NotifyEvent(EC_QUALITY_CHANGE,0,0);
  5940. FQualityChanged := True;
  5941. end;
  5942. result := NOERROR;
  5943. exit;
  5944. end;
  5945. end;
  5946. end;
  5947. // release the output buffer. If the connected pin still needs it,
  5948. // it will have addrefed it itself.
  5949. OutSample := nil;
  5950. end;
  5951. function TBCTransformFilter.SetMediaType(direction: TPinDirection;
  5952. pmt: PAMMediaType): HRESULT;
  5953. begin
  5954. result := NOERROR;
  5955. end;
  5956. // override these two functions if you want to inform something
  5957. // about entry to or exit from streaming state.
  5958. function TBCTransformFilter.StartStreaming: HRESULT;
  5959. begin
  5960. result := NOERROR;
  5961. end;
  5962. // override these so that the derived filter can catch them
  5963. function TBCTransformFilter.Stop: HRESULT;
  5964. begin
  5965. FcsFilter.Lock;
  5966. try
  5967. if(FState = State_Stopped) then
  5968. begin
  5969. result := NOERROR;
  5970. exit;
  5971. end;
  5972. // Succeed the Stop if we are not completely connected
  5973. ASSERT((FInput = nil) or (FOutput <> nil));
  5974. if((FInput = nil) or (FInput.IsConnected = FALSE) or (FOutput.IsConnected = FALSE)) then
  5975. begin
  5976. FState := State_Stopped;
  5977. FEOSDelivered := FALSE;
  5978. result := NOERROR;
  5979. exit;
  5980. end;
  5981. ASSERT(FInput <> nil);
  5982. ASSERT(FOutput <> nil);
  5983. // decommit the input pin before locking or we can deadlock
  5984. FInput.Inactive;
  5985. // synchronize with Receive calls
  5986. FcsReceive.Lock;
  5987. try
  5988. FOutput.Inactive;
  5989. // allow a class derived from CTransformFilter
  5990. // to know about starting and stopping streaming
  5991. result := StopStreaming;
  5992. if SUCCEEDED(result) then
  5993. begin
  5994. // complete the state transition
  5995. FState := State_Stopped;
  5996. FEOSDelivered := FALSE;
  5997. end;
  5998. finally
  5999. FcsReceive.UnLock;
  6000. end;
  6001. finally
  6002. FcsFilter.UnLock;
  6003. end;
  6004. end;
  6005. function TBCTransformFilter.StopStreaming: HRESULT;
  6006. begin
  6007. result := NOERROR;
  6008. end;
  6009. function TBCTransformFilter.Transform(msIn, msout: IMediaSample): HRESULT;
  6010. begin
  6011. {$IFDEF DEBUG}
  6012. DbgLog(self, 'TBCTransformFilter.Transform should never be called');
  6013. {$ENDIF}
  6014. result := E_UNEXPECTED;
  6015. end;
  6016. { TBCTransformOutputPin }
  6017. // provides derived filter a chance to release it's extra interfaces
  6018. function TBCTransformOutputPin.BreakConnect: HRESULT;
  6019. begin
  6020. // Can't disconnect unless stopped
  6021. ASSERT(IsStopped);
  6022. FTransformFilter.BreakConnect(PINDIR_OUTPUT);
  6023. result := inherited BreakConnect;
  6024. end;
  6025. // provides derived filter a chance to grab extra interfaces
  6026. function TBCTransformOutputPin.CheckConnect(Pin: IPin): HRESULT;
  6027. begin
  6028. // we should have an input connection first
  6029. ASSERT(FTransformFilter.FInput <> nil);
  6030. if(FTransformFilter.FInput.IsConnected = FALSE) then
  6031. begin
  6032. result := E_UNEXPECTED;
  6033. exit;
  6034. end;
  6035. result := FTransformFilter.CheckConnect(PINDIR_OUTPUT, Pin);
  6036. if FAILED(result) then exit;
  6037. result := inherited CheckConnect(Pin);
  6038. end;
  6039. // check a given transform - must have selected input type first
  6040. function TBCTransformOutputPin.CheckMediaType(
  6041. mtOut: PAMMediaType): HRESULT;
  6042. begin
  6043. // must have selected input first
  6044. ASSERT(FTransformFilter.FInput <> nil);
  6045. if(FTransformFilter.FInput.IsConnected = FALSE) then
  6046. begin
  6047. result := E_INVALIDARG;
  6048. exit;
  6049. end;
  6050. result := FTransformFilter.CheckTransform(FTransformFilter.FInput.AMMediaType, mtOut);
  6051. end;
  6052. // Let derived class know when the output pin is connected
  6053. function TBCTransformOutputPin.CompleteConnect(ReceivePin: IPin): HRESULT;
  6054. begin
  6055. result := FTransformFilter.CompleteConnect(PINDIR_OUTPUT, ReceivePin);
  6056. if FAILED(result) then exit;
  6057. result := inherited CompleteConnect(ReceivePin);
  6058. end;
  6059. constructor TBCTransformOutputPin.Create(ObjectName: string;
  6060. TransformFilter: TBCTransformFilter; out hr: HRESULT; Name: WideString);
  6061. begin
  6062. inherited create(ObjectName, TransformFilter, TransformFilter.FcsFilter, hr, Name);
  6063. FPosition := nil;
  6064. {$IFDEF DEBUG}
  6065. DbgLog(self, 'TBCTransformOutputPin.Create');
  6066. {$ENDIF}
  6067. FTransformFilter := TransformFilter;
  6068. end;
  6069. function TBCTransformOutputPin.DecideBufferSize(Alloc: IMemAllocator;
  6070. Prop: PAllocatorProperties): HRESULT;
  6071. begin
  6072. result := FTransformFilter.DecideBufferSize(Alloc, Prop);
  6073. end;
  6074. destructor TBCTransformOutputPin.destroy;
  6075. begin
  6076. {$IFDEF DEBUG}
  6077. DbgLog(self, 'TBCTransformOutputPin.Destroy');
  6078. {$ENDIF}
  6079. FPosition := nil;
  6080. inherited;
  6081. end;
  6082. function TBCTransformOutputPin.GetMediaType(Position: integer;
  6083. out MediaType: PAMMediaType): HRESULT;
  6084. begin
  6085. ASSERT(FTransformFilter.FInput <> nil);
  6086. // We don't have any media types if our input is not connected
  6087. if(FTransformFilter.FInput.IsConnected) then
  6088. begin
  6089. result := FTransformFilter.GetMediaType(Position, MediaType);
  6090. exit;
  6091. end
  6092. else
  6093. result := VFW_S_NO_MORE_ITEMS;
  6094. end;
  6095. function TBCTransformOutputPin.NonDelegatingQueryInterface(
  6096. const IID: TGUID; out Obj): HResult;
  6097. begin
  6098. if IsEqualGUID(iid, IID_IMediaPosition) or IsEqualGUID(iid, IID_IMediaSeeking) then
  6099. begin
  6100. // we should have an input pin by now
  6101. ASSERT(FTransformFilter.FInput <> nil);
  6102. if (FPosition = nil) then
  6103. begin
  6104. result := CreatePosPassThru(GetOwner, FALSE, FTransformFilter.FInput, FPosition);
  6105. if FAILED(result) then exit;
  6106. end;
  6107. result := FPosition.QueryInterface(iid, obj);
  6108. end
  6109. else
  6110. result := inherited NonDelegatingQueryInterface(iid, obj);
  6111. end;
  6112. // Override this if you can do something constructive to act on the
  6113. // quality message. Consider passing it upstream as well
  6114. // Pass the quality mesage on upstream.
  6115. function TBCTransformOutputPin.Notify(Sendr: IBaseFilter; q: TQuality): HRESULT;
  6116. begin
  6117. // First see if we want to handle this ourselves
  6118. result := FTransformFilter.AlterQuality(q);
  6119. if (result <> S_FALSE) then exit;
  6120. // S_FALSE means we pass the message on.
  6121. // Find the quality sink for our input pin and send it there
  6122. ASSERT(FTransformFilter.FInput <> nil);
  6123. result := FTransformFilter.FInput.PassNotify(q);
  6124. end;
  6125. function TBCTransformOutputPin.QueryId(out Id: PWideChar): HRESULT;
  6126. begin
  6127. result := AMGetWideString('Out', Id);
  6128. end;
  6129. // called after we have agreed a media type to actually set it in which case
  6130. // we run the CheckTransform function to get the output format type again
  6131. function TBCTransformOutputPin.SetMediaType(pmt: PAMMediaType): HRESULT;
  6132. begin
  6133. ASSERT(FTransformFilter.FInput <> nil);
  6134. ASSERT(not IsEqualGUID(FTransformFilter.FInput.AMMediaType.majortype,GUID_NULL));
  6135. // Set the base class media type (should always succeed)
  6136. result := inherited SetMediaType(pmt);
  6137. if FAILED(result) then exit;
  6138. {$ifdef DEBUG}
  6139. if(FAILED(FTransformFilter.CheckTransform(FTransformFilter.FInput.AMMediaType, pmt))) then
  6140. begin
  6141. DbgLog(self, '*** This filter is accepting an output media type');
  6142. DbgLog(self, ' that it can''t currently transform to. I hope');
  6143. DbgLog(self, ' it''s smart enough to reconnect its input.');
  6144. end;
  6145. {$endif}
  6146. result := FTransformFilter.SetMediaType(PINDIR_OUTPUT,pmt);
  6147. end;
  6148. // milenko start (added TBCVideoTransformFilter conversion)
  6149. { TBCVideoTransformFilter }
  6150. // This class is derived from CTransformFilter, but is specialised to handle
  6151. // the requirements of video quality control by frame dropping.
  6152. // This is a non-in-place transform, (i.e. it copies the data) such as a decoder.
  6153. constructor TBCVideoTransformFilter.Create(Name: WideString; Unk: IUnknown; clsid: TGUID);
  6154. begin
  6155. inherited Create(name, Unk, clsid);
  6156. FitrLate := 0;
  6157. FKeyFramePeriod := 0; // No QM until we see at least 2 key frames
  6158. FFramesSinceKeyFrame := 0;
  6159. FSkipping := False;
  6160. FtDecodeStart := 0;
  6161. FitrAvgDecode := 300000; // 30mSec - probably allows skipping
  6162. FQualityChanged := False;
  6163. {$IFDEF PERF}
  6164. RegisterPerfId();
  6165. {$ENDIF} // PERF
  6166. end;
  6167. destructor TBCVideoTransformFilter.Destroy;
  6168. begin
  6169. inherited Destroy;
  6170. end;
  6171. // Overriden to reset quality management information
  6172. function TBCVideoTransformFilter.EndFlush: HRESULT;
  6173. begin
  6174. FcsReceive.Lock;
  6175. try
  6176. // Reset our stats
  6177. //
  6178. // Note - we don't want to call derived classes here,
  6179. // we only want to reset our internal variables and this
  6180. // is a convenient way to do it
  6181. StartStreaming;
  6182. Result := inherited EndFlush;
  6183. finally
  6184. FcsReceive.UnLock;
  6185. end;
  6186. end;
  6187. {$IFDEF PERF}
  6188. procedure TBCVideoTransformFilter.RegisterPerfId;
  6189. begin
  6190. FidSkip := MSR_REGISTER('Video Transform Skip frame');
  6191. FidFrameType := MSR_REGISTER('Video transform frame type');
  6192. FidLate := MSR_REGISTER('Video Transform Lateness');
  6193. FidTimeTillKey := MSR_REGISTER('Video Transform Estd. time to next key');
  6194. // inherited RegisterPerfId;
  6195. end;
  6196. {$ENDIF}
  6197. function TBCVideoTransformFilter.StartStreaming: HRESULT;
  6198. begin
  6199. FitrLate := 0;
  6200. FKeyFramePeriod := 0; // No QM until we see at least 2 key frames
  6201. FFramesSinceKeyFrame := 0;
  6202. FSkipping := False;
  6203. FtDecodeStart := 0;
  6204. FitrAvgDecode := 300000; // 30mSec - probably allows skipping
  6205. FQualityChanged := False;
  6206. FSampleSkipped := False;
  6207. Result := NOERROR;
  6208. end;
  6209. // Reset our quality management state
  6210. function TBCVideoTransformFilter.AbortPlayback(hr: HRESULT): HRESULT;
  6211. begin
  6212. NotifyEvent(EC_ERRORABORT, hr, 0);
  6213. FOutput.DeliverEndOfStream;
  6214. Result := hr;
  6215. end;
  6216. // Receive()
  6217. //
  6218. // Accept a sample from upstream, decide whether to process it
  6219. // or drop it. If we process it then get a buffer from the
  6220. // allocator of the downstream connection, transform it into the
  6221. // new buffer and deliver it to the downstream filter.
  6222. // If we decide not to process it then we do not get a buffer.
  6223. // Remember that although this code will notice format changes coming into
  6224. // the input pin, it will NOT change its output format if that results
  6225. // in the filter needing to make a corresponding output format change. Your
  6226. // derived filter will have to take care of that. (eg. a palette change if
  6227. // the input and output is an 8 bit format). If the input sample is discarded
  6228. // and nothing is sent out for this Receive, please remember to put the format
  6229. // change on the first output sample that you actually do send.
  6230. // If your filter will produce the same output type even when the input type
  6231. // changes, then this base class code will do everything you need.
  6232. function TBCVideoTransformFilter.Receive(Sample: IMediaSample): HRESULT;
  6233. var
  6234. pmtOut, pmt: PAMMediaType;
  6235. pOutSample: IMediaSample;
  6236. {$IFDEF DEBUG}
  6237. fccOut: TGUID;
  6238. lCompression: LongInt;
  6239. lBitCount: LongInt;
  6240. lStride: LongInt;
  6241. rcS: TRect;
  6242. rcT: TRect;
  6243. rcS1: TRect;
  6244. rcT1: TRect;
  6245. {$ENDIF}
  6246. begin
  6247. // If the next filter downstream is the video renderer, then it may
  6248. // be able to operate in DirectDraw mode which saves copying the data
  6249. // and gives higher performance. In that case the buffer which we
  6250. // get from GetDeliveryBuffer will be a DirectDraw buffer, and
  6251. // drawing into this buffer draws directly onto the display surface.
  6252. // This means that any waiting for the correct time to draw occurs
  6253. // during GetDeliveryBuffer, and that once the buffer is given to us
  6254. // the video renderer will count it in its statistics as a frame drawn.
  6255. // This means that any decision to drop the frame must be taken before
  6256. // calling GetDeliveryBuffer.
  6257. ASSERT(FcsReceive.CritCheckIn);
  6258. ASSERT(Sample <> nil);
  6259. // If no output pin to deliver to then no point sending us data
  6260. ASSERT (FOutput <> nil) ;
  6261. // The source filter may dynamically ask us to start transforming from a
  6262. // different media type than the one we're using now. If we don't, we'll
  6263. // draw garbage. (typically, this is a palette change in the movie,
  6264. // but could be something more sinister like the compression type changing,
  6265. // or even the video size changing)
  6266. Sample.GetMediaType(pmt);
  6267. if (pmt <> nil) and (pmt.pbFormat <> nil) then
  6268. begin
  6269. // spew some debug output
  6270. ASSERT(not IsEqualGUID(pmt.majortype, GUID_NULL));
  6271. {$IFDEF DEBUG}
  6272. fccOut := pmt.subtype;
  6273. lCompression := PVideoInfoHeader(pmt.pbFormat).bmiHeader.biCompression;
  6274. lBitCount := PVideoInfoHeader(pmt.pbFormat).bmiHeader.biBitCount;
  6275. lStride := (PVideoInfoHeader(pmt.pbFormat).bmiHeader.biWidth * lBitCount + 7) div 8;
  6276. lStride := (lStride + 3) and not 3;
  6277. rcS1 := PVideoInfoHeader(pmt.pbFormat).rcSource;
  6278. rcT1 := PVideoInfoHeader(pmt.pbFormat).rcTarget;
  6279. DbgLog(Self,'Changing input type on the fly to');
  6280. DbgLog(Self,'FourCC: ' + inttohex(fccOut.D1,8) + ' Compression: ' + inttostr(lCompression) +
  6281. ' BitCount: ' + inttostr(lBitCount));
  6282. DbgLog(Self,'biHeight: ' + inttostr(PVideoInfoHeader(pmt.pbFormat).bmiHeader.biHeight) +
  6283. ' rcDst: (' + inttostr(rcT1.left) + ', ' + inttostr(rcT1.top) + ', ' +
  6284. inttostr(rcT1.right) + ', ' + inttostr(rcT1.bottom) + ')');
  6285. DbgLog(Self,'rcSrc: (' + inttostr(rcS1.left) + ', ' + inttostr(rcS1.top) + ', ' +
  6286. inttostr(rcS1.right) + ', ' + inttostr(rcS1.bottom) + ') Stride' + inttostr(lStride));
  6287. {$ENDIF}
  6288. // now switch to using the new format. I am assuming that the
  6289. // derived filter will do the right thing when its media type is
  6290. // switched and streaming is restarted.
  6291. StopStreaming();
  6292. CopyMediaType(FInput.AMMediaType,pmt);
  6293. DeleteMediaType(pmt);
  6294. // if this fails, playback will stop, so signal an error
  6295. Result := StartStreaming;
  6296. if (FAILED(Result)) then
  6297. begin
  6298. Result := AbortPlayback(Result);
  6299. Exit;
  6300. end;
  6301. end;
  6302. // Now that we have noticed any format changes on the input sample, it's
  6303. // OK to discard it.
  6304. if ShouldSkipFrame(Sample) then
  6305. begin
  6306. {$IFDEF PERF}
  6307. // MSR_NOTE(m_idSkip);
  6308. {$ENDIF}
  6309. FSampleSkipped := True;
  6310. Result := NOERROR;
  6311. Exit;
  6312. end;
  6313. // Set up the output sample
  6314. Result := InitializeOutputSample(Sample, pOutSample);
  6315. if (FAILED(Result)) then Exit;
  6316. FSampleSkipped := False;
  6317. // The renderer may ask us to on-the-fly to start transforming to a
  6318. // different format. If we don't obey it, we'll draw garbage
  6319. pOutSample.GetMediaType(pmtOut);
  6320. if (pmtOut <> nil) and (pmtOut.pbFormat <> nil) then
  6321. begin
  6322. // spew some debug output
  6323. ASSERT(not IsEqualGUID(pmtOut.majortype, GUID_NULL));
  6324. {$IFDEF DEBUG}
  6325. fccOut := pmtOut.subtype;
  6326. lCompression := PVideoInfoHeader(pmtOut.pbFormat).bmiHeader.biCompression;
  6327. lBitCount := PVideoInfoHeader(pmtOut.pbFormat).bmiHeader.biBitCount;
  6328. lStride := (PVideoInfoHeader(pmtOut.pbFormat).bmiHeader.biWidth * lBitCount + 7) div 8;
  6329. lStride := (lStride + 3) and not 3;
  6330. rcS := PVideoInfoHeader(pmtOut.pbFormat).rcSource;
  6331. rcT := PVideoInfoHeader(pmtOut.pbFormat).rcTarget;
  6332. DbgLog(Self,'Changing input type on the fly to');
  6333. DbgLog(Self,'FourCC: ' + inttohex(fccOut.D1,8) + ' Compression: ' + inttostr(lCompression) +
  6334. ' BitCount: ' + inttostr(lBitCount));
  6335. DbgLog(Self,'biHeight: ' + inttostr(PVideoInfoHeader(pmtOut.pbFormat).bmiHeader.biHeight) +
  6336. ' rcDst: (' + inttostr(rcT1.left) + ', ' + inttostr(rcT1.top) + ', ' +
  6337. inttostr(rcT1.right) + ', ' + inttostr(rcT1.bottom) + ')');
  6338. DbgLog(Self,'rcSrc: (' + inttostr(rcS1.left) + ', ' + inttostr(rcS1.top) + ', ' +
  6339. inttostr(rcS1.right) + ', ' + inttostr(rcS1.bottom) + ') Stride' + inttostr(lStride));
  6340. {$ENDIF}
  6341. // now switch to using the new format. I am assuming that the
  6342. // derived filter will do the right thing when its media type is
  6343. // switched and streaming is restarted.
  6344. StopStreaming();
  6345. CopyMediaType(FOutput.AMMediaType,pmtOut);
  6346. DeleteMediaType(pmtOut);
  6347. Result := StartStreaming;
  6348. if (SUCCEEDED(Result)) then
  6349. begin
  6350. // a new format, means a new empty buffer, so wait for a keyframe
  6351. // before passing anything on to the renderer.
  6352. // !!! a keyframe may never come, so give up after 30 frames
  6353. {$IFDEF DEBUG}
  6354. DbgLog(Self,'Output format change means we must wait for a keyframe');
  6355. {$ENDIF}
  6356. FWaitForKey := 30;
  6357. // if this fails, playback will stop, so signal an error
  6358. end else
  6359. begin
  6360. // Must release the sample before calling AbortPlayback
  6361. // because we might be holding the win16 lock or
  6362. // ddraw lock
  6363. pOutSample := nil;
  6364. AbortPlayback(Result);
  6365. Exit;
  6366. end;
  6367. end;
  6368. // After a discontinuity, we need to wait for the next key frame
  6369. if (Sample.IsDiscontinuity = S_OK) then
  6370. begin
  6371. {$IFDEF DEBUG}
  6372. DbgLog(Self,'Non-key discontinuity - wait for keyframe');
  6373. {$ENDIF}
  6374. FWaitForKey := 30;
  6375. end;
  6376. // Start timing the transform (and log it if PERF is defined)
  6377. if (SUCCEEDED(Result)) then
  6378. begin
  6379. FtDecodeStart := timeGetTime;
  6380. {$IFDEF PERF}
  6381. // MSR_START(FidTransform); // not added in conversion
  6382. {$ENDIF}
  6383. // have the derived class transform the data
  6384. Result := Transform(Sample, pOutSample);
  6385. // Stop the clock (and log it if PERF is defined)
  6386. {$IFDEF PERF}
  6387. // MSR_STOP(m_idTransform); // not added in conversion
  6388. {$ENDIF}
  6389. FtDecodeStart := timeGetTime - int64(FtDecodeStart);
  6390. FitrAvgDecode := Round(FtDecodeStart * (10000 / 16) + 15 * (FitrAvgDecode / 16));
  6391. // Maybe we're waiting for a keyframe still?
  6392. if (FWaitForKey > 0) then dec(FWaitForKey);
  6393. if (FWaitForKey > 0) and (Sample.IsSyncPoint = S_OK) then BOOL(FWaitForKey) := False;
  6394. // if so, then we don't want to pass this on to the renderer
  6395. if (FWaitForKey > 0) and (Result = NOERROR) then
  6396. begin
  6397. {$IFDEF DEBUG}
  6398. DbgLog(Self,'still waiting for a keyframe');
  6399. Result := S_FALSE;
  6400. {$ENDIF}
  6401. end;
  6402. end;
  6403. if (FAILED(Result)) then
  6404. begin
  6405. {$IFDEF DEBUG}
  6406. DbgLog(Self,'Error from video transform');
  6407. {$ENDIF}
  6408. end else
  6409. begin
  6410. // the Transform() function can return S_FALSE to indicate that the
  6411. // sample should not be delivered; we only deliver the sample if it's
  6412. // really S_OK (same as NOERROR, of course.)
  6413. // Try not to return S_FALSE to a direct draw buffer (it's wasteful)
  6414. // Try to take the decision earlier - before you get it.
  6415. if (Result = NOERROR) then
  6416. begin
  6417. Result := FOutput.Deliver(pOutSample);
  6418. end else
  6419. begin
  6420. // S_FALSE returned from Transform is a PRIVATE agreement
  6421. // We should return NOERROR from Receive() in this case because returning S_FALSE
  6422. // from Receive() means that this is the end of the stream and no more data should
  6423. // be sent.
  6424. if (S_FALSE = Result) then
  6425. begin
  6426. // We must Release() the sample before doing anything
  6427. // like calling the filter graph because having the
  6428. // sample means we may have the DirectDraw lock
  6429. // (== win16 lock on some versions)
  6430. pOutSample := nil;
  6431. FSampleSkipped := True;
  6432. if not FQualityChanged then
  6433. begin
  6434. FQualityChanged := True;
  6435. NotifyEvent(EC_QUALITY_CHANGE,0,0);
  6436. end;
  6437. Result := NOERROR;
  6438. Exit;
  6439. end;
  6440. end;
  6441. end;
  6442. // release the output buffer. If the connected pin still needs it,
  6443. // it will have addrefed it itself.
  6444. pOutSample := nil;
  6445. ASSERT(FcsReceive.CritCheckIn);
  6446. end;
  6447. function TBCVideoTransformFilter.AlterQuality(const q: TQuality): HRESULT;
  6448. begin
  6449. // to reduce the amount of 64 bit arithmetic, m_itrLate is an int.
  6450. // +, -, >, == etc are not too bad, but * and / are painful.
  6451. if (FitrLate > 300000000) then
  6452. begin
  6453. // Avoid overflow and silliness - more than 30 secs late is already silly
  6454. FitrLate := 300000000;
  6455. end else
  6456. begin
  6457. FitrLate := integer(q.Late);
  6458. end;
  6459. // We ignore the other fields
  6460. // We're actually not very good at handling this. In non-direct draw mode
  6461. // most of the time can be spent in the renderer which can skip any frame.
  6462. // In that case we'd rather the renderer handled things.
  6463. // Nevertheless we will keep an eye on it and if we really start getting
  6464. // a very long way behind then we will actually skip - but we'll still tell
  6465. // the renderer (or whoever is downstream) that they should handle quality.
  6466. Result := E_FAIL; // Tell the renderer to do his thing.
  6467. end;
  6468. function TBCVideoTransformFilter.ShouldSkipFrame(pIn: IMediaSample): Boolean;
  6469. var
  6470. Start, StopAt: TReferenceTime;
  6471. itrFrame: integer;
  6472. it: integer;
  6473. begin
  6474. Result := pIn.GetTime(Start, StopAt) = S_OK;
  6475. // Don't skip frames with no timestamps
  6476. if not Result then Exit;
  6477. itrFrame := integer(StopAt - Start); // frame duration
  6478. if(S_OK = pIn.IsSyncPoint) then
  6479. begin
  6480. {$IFDEF PERF}
  6481. MSR_INTEGER(FidFrameType, 1);
  6482. {$ENDIF}
  6483. if (FKeyFramePeriod < FFramesSinceKeyFrame) then
  6484. begin
  6485. // record the max
  6486. FKeyFramePeriod := FFramesSinceKeyFrame;
  6487. end;
  6488. FFramesSinceKeyFrame := 0;
  6489. FSkipping := False;
  6490. end else
  6491. begin
  6492. {$IFDEF PERF}
  6493. MSR_INTEGER(FidFrameType, 2);
  6494. {$ENDIF}
  6495. if (FFramesSinceKeyFrame > FKeyFramePeriod) and (FKeyFramePeriod > 0) then
  6496. begin
  6497. // We haven't seen the key frame yet, but we were clearly being
  6498. // overoptimistic about how frequent they are.
  6499. FKeyFramePeriod := FFramesSinceKeyFrame;
  6500. end;
  6501. end;
  6502. // Whatever we might otherwise decide,
  6503. // if we are taking only a small fraction of the required frame time to decode
  6504. // then any quality problems are actually coming from somewhere else.
  6505. // Could be a net problem at the source for instance. In this case there's
  6506. // no point in us skipping frames here.
  6507. if (FitrAvgDecode * 4 > itrFrame) then
  6508. begin
  6509. // Don't skip unless we are at least a whole frame late.
  6510. // (We would skip B frames if more than 1/2 frame late, but they're safe).
  6511. if (FitrLate > itrFrame) then
  6512. begin
  6513. // Don't skip unless the anticipated key frame would be no more than
  6514. // 1 frame early. If the renderer has not been waiting (we *guess*
  6515. // it hasn't because we're late) then it will allow frames to be
  6516. // played early by up to a frame.
  6517. // Let T = Stream time from now to anticipated next key frame
  6518. // = (frame duration) * (KeyFramePeriod - FramesSinceKeyFrame)
  6519. // So we skip if T - Late < one frame i.e.
  6520. // (duration) * (freq - FramesSince) - Late < duration
  6521. // or (duration) * (freq - FramesSince - 1) < Late
  6522. // We don't dare skip until we have seen some key frames and have
  6523. // some idea how often they occur and they are reasonably frequent.
  6524. if (FKeyFramePeriod > 0) then
  6525. begin
  6526. // It would be crazy - but we could have a stream with key frames
  6527. // a very long way apart - and if they are further than about
  6528. // 3.5 minutes apart then we could get arithmetic overflow in
  6529. // reference time units. Therefore we switch to mSec at this point
  6530. it := (itrFrame div 10000) * (FKeyFramePeriod - FFramesSinceKeyFrame - 1);
  6531. {$IFDEF PERF}
  6532. MSR_INTEGER(FidTimeTillKey, it);
  6533. {$ENDIF}
  6534. // For debug - might want to see the details - dump them as scratch pad
  6535. {$IFDEF VTRANSPERF}
  6536. MSR_INTEGER(0, itrFrame);
  6537. MSR_INTEGER(0, FFramesSinceKeyFrame);
  6538. MSR_INTEGER(0, FKeyFramePeriod);
  6539. {$ENDIF}
  6540. if (FitrLate div 10000 > it) then
  6541. begin
  6542. FSkipping := True;
  6543. // Now we are committed. Once we start skipping, we
  6544. // cannot stop until we hit a key frame.
  6545. end else
  6546. begin
  6547. {$IFDEF VTRANSPERF}
  6548. MSR_INTEGER(0, 777770); // not near enough to next key
  6549. {$ENDIF}
  6550. end;
  6551. end else
  6552. begin
  6553. {$IFDEF VTRANSPERF}
  6554. MSR_INTEGER(0, 777771); // Next key not predictable
  6555. {$ENDIF}
  6556. end;
  6557. end else
  6558. begin
  6559. {$IFDEF VTRANSPERF}
  6560. MSR_INTEGER(0, 777772); // Less than one frame late
  6561. MSR_INTEGER(0, FitrLate);
  6562. MSR_INTEGER(0, itrFrame);
  6563. {$ENDIF}
  6564. end;
  6565. end else
  6566. begin
  6567. {$IFDEF VTRANSPERF}
  6568. MSR_INTEGER(0, 777773); // Decode time short - not not worth skipping
  6569. MSR_INTEGER(0, FitrAvgDecode);
  6570. MSR_INTEGER(0, itrFrame);
  6571. {$ENDIF}
  6572. end;
  6573. inc(FFramesSinceKeyFrame);
  6574. if FSkipping then
  6575. begin
  6576. // We will count down the lateness as we skip each frame.
  6577. // We re-assess each frame. The key frame might not arrive when expected.
  6578. // We reset m_itrLate if we get a new Quality message, but actually that's
  6579. // not likely because we're not sending frames on to the Renderer. In
  6580. // fact if we DID get another one it would mean that there's a long
  6581. // pipe between us and the renderer and we might need an altogether
  6582. // better strategy to avoid hunting!
  6583. FitrLate := FitrLate - itrFrame;
  6584. end;
  6585. {$IFDEF PERF}
  6586. MSR_INTEGER(FidLate, integer(FitrLate div 10000)); // Note how late we think we are
  6587. {$ENDIF}
  6588. if FSkipping then
  6589. begin
  6590. if not FQualityChanged then
  6591. begin
  6592. FQualityChanged := True;
  6593. NotifyEvent(EC_QUALITY_CHANGE,0,0);
  6594. end;
  6595. end;
  6596. Result := FSkipping;
  6597. end;
  6598. // milenko end
  6599. { TCTransInPlaceInputPin }
  6600. function TBCTransInPlaceInputPin.CheckMediaType(
  6601. pmt: PAMMediaType): HRESULT;
  6602. begin
  6603. result := FTIPFilter.CheckInputType(pmt);
  6604. if (result <> S_OK) then exit;
  6605. if FTIPFilter.FOutput.IsConnected then
  6606. result := FTIPFilter.FOutput.GetConnected.QueryAccept(pmt^)
  6607. else
  6608. result := S_OK;
  6609. end;
  6610. function TBCTransInPlaceInputPin.EnumMediaTypes(
  6611. out ppEnum: IEnumMediaTypes): HRESULT;
  6612. begin
  6613. // Can only pass through if connected
  6614. if (not FTIPFilter.FOutput.IsConnected) then
  6615. begin
  6616. result := VFW_E_NOT_CONNECTED;
  6617. exit;
  6618. end;
  6619. result := FTIPFilter.FOutput.GetConnected.EnumMediaTypes(ppEnum);
  6620. end;
  6621. function TBCTransInPlaceInputPin.GetAllocator(
  6622. out Allocator: IMemAllocator): HRESULT;
  6623. begin
  6624. FLock.Lock;
  6625. try
  6626. if FTIPFilter.FOutput.IsConnected then
  6627. begin
  6628. // Store the allocator we got
  6629. result := FTIPFilter.OutputPin.ConnectedIMemInputPin.GetAllocator(Allocator);
  6630. if SUCCEEDED(result) then
  6631. FTIPFilter.OutputPin.SetAllocator(Allocator);
  6632. end
  6633. else
  6634. begin
  6635. // Help upstream filter (eg TIP filter which is having to do a copy)
  6636. // by providing a temp allocator here - we'll never use
  6637. // this allocator because when our output is connected we'll
  6638. // reconnect this pin
  6639. result := inherited GetAllocator(Allocator);
  6640. end;
  6641. finally
  6642. FLock.UnLock;
  6643. end;
  6644. end;
  6645. function TBCTransInPlaceInputPin.GetAllocatorRequirements(
  6646. props: PAllocatorProperties): HRESULT;
  6647. begin
  6648. if FTIPFilter.FOutput.IsConnected then
  6649. result := FTIPFilter.OutputPin.ConnectedIMemInputPin.GetAllocatorRequirements(Props^)
  6650. else
  6651. result := E_NOTIMPL;
  6652. end;
  6653. function TBCTransInPlaceInputPin.NotifyAllocator(Allocator: IMemAllocator;
  6654. ReadOnly: BOOL): HRESULT;
  6655. var
  6656. OutputAllocator: IMemAllocator;
  6657. Props, Actual: TAllocatorProperties;
  6658. begin
  6659. result := S_OK;
  6660. FLock.Lock;
  6661. try
  6662. FReadOnly := ReadOnly;
  6663. // If we modify data then don't accept the allocator if it's
  6664. // the same as the output pin's allocator
  6665. // If our output is not connected just accept the allocator
  6666. // We're never going to use this allocator because when our
  6667. // output pin is connected we'll reconnect this pin
  6668. if not FTIPFilter.OutputPin.IsConnected then
  6669. begin
  6670. result := inherited NotifyAllocator(Allocator, ReadOnly);
  6671. exit;
  6672. end;
  6673. // If the allocator is read-only and we're modifying data
  6674. // and the allocator is the same as the output pin's
  6675. // then reject
  6676. if (FReadOnly and FTIPFilter.FModifiesData) then
  6677. begin
  6678. OutputAllocator := FTIPFilter.OutputPin.PeekAllocator;
  6679. // Make sure we have an output allocator
  6680. if (OutputAllocator = nil) then
  6681. begin
  6682. result := FTIPFilter.OutputPin.ConnectedIMemInputPin.GetAllocator(OutputAllocator);
  6683. if FAILED(result) then result := CreateMemoryAllocator(OutputAllocator);
  6684. if SUCCEEDED(result) then
  6685. begin
  6686. FTIPFilter.OutputPin.SetAllocator(OutputAllocator);
  6687. OutputAllocator := nil;
  6688. end;
  6689. end;
  6690. if (Allocator = OutputAllocator) then
  6691. begin
  6692. result := E_FAIL;
  6693. exit;
  6694. end
  6695. else
  6696. if SUCCEEDED(result) then
  6697. begin
  6698. // Must copy so set the allocator properties on the output
  6699. result := Allocator.GetProperties(Props);
  6700. if SUCCEEDED(result) then
  6701. result := OutputAllocator.SetProperties(Props, Actual);
  6702. if SUCCEEDED(result) then
  6703. begin
  6704. if ((Props.cBuffers > Actual.cBuffers)
  6705. or (Props.cbBuffer > Actual.cbBuffer)
  6706. or (Props.cbAlign > Actual.cbAlign)) then
  6707. result := E_FAIL;
  6708. end;
  6709. // Set the allocator on the output pin
  6710. if SUCCEEDED(result) then
  6711. result := FTIPFilter.OutputPin.ConnectedIMemInputPin.NotifyAllocator(OutputAllocator, FALSE);
  6712. end;
  6713. end
  6714. else
  6715. begin
  6716. result := FTIPFilter.OutputPin.ConnectedIMemInputPin.NotifyAllocator(Allocator, ReadOnly);
  6717. if SUCCEEDED(result) then FTIPFilter.OutputPin.SetAllocator(Allocator);
  6718. end;
  6719. if SUCCEEDED(result) then
  6720. begin
  6721. // It's possible that the old and the new are the same thing.
  6722. // AddRef before release ensures that we don't unload it.
  6723. Allocator._AddRef;
  6724. if (FAllocator <> nil) then FAllocator := nil;
  6725. Pointer(FAllocator) := Pointer(Allocator); // We have an allocator for the input pin
  6726. end;
  6727. finally
  6728. FLock.UnLock;
  6729. end;
  6730. end;
  6731. function TBCTransInPlaceInputPin.PeekAllocator: IMemAllocator;
  6732. begin
  6733. result := FAllocator;
  6734. end;
  6735. constructor TBCTransInPlaceInputPin.Create(ObjectName: string;
  6736. Filter: TBCTransInPlaceFilter; out hr: HRESULT; Name: WideString);
  6737. begin
  6738. inherited Create(ObjectName, Filter, hr, Name);
  6739. FReadOnly := FALSE;
  6740. FTIPFilter := Filter;
  6741. {$IFDEF DEBUG}
  6742. DbgLog(self, 'TBCTransInPlaceInputPin.Create');
  6743. {$ENDIF}
  6744. end;
  6745. { TBCTransInPlaceOutputPin }
  6746. function TBCTransInPlaceOutputPin.CheckMediaType(
  6747. pmt: PAMMediaType): HRESULT;
  6748. begin
  6749. // Don't accept any output pin type changes if we're copying
  6750. // between allocators - it's too late to change the input
  6751. // allocator size.
  6752. if (FTIPFilter.UsingDifferentAllocators and (not FFilter.IsStopped)) then
  6753. begin
  6754. if TBCMediaType(pmt).Equal(@Fmt) then result := S_OK else result := VFW_E_TYPE_NOT_ACCEPTED;
  6755. exit;
  6756. end;
  6757. // Assumes the type does not change. That's why we're calling
  6758. // CheckINPUTType here on the OUTPUT pin.
  6759. result := FTIPFilter.CheckInputType(pmt);
  6760. if (result <> S_OK) then exit;
  6761. if (FTIPFilter.FInput.IsConnected) then
  6762. result := FTIPFilter.FInput.GetConnected.QueryAccept(pmt^)
  6763. else
  6764. result := S_OK;
  6765. end;
  6766. function TBCTransInPlaceOutputPin.ConnectedIMemInputPin: IMemInputPin;
  6767. begin
  6768. pointer(result) := pointer(FInputPin);
  6769. end;
  6770. constructor TBCTransInPlaceOutputPin.Create(ObjectName: string;
  6771. Filter: TBCTransInPlaceFilter; out hr: HRESULT; Name: WideString);
  6772. begin
  6773. inherited Create(ObjectName, Filter, hr, Name);
  6774. FTIPFilter := Filter;
  6775. {$IFDEF DEBUG}
  6776. DbgLog(self, 'TBCTransInPlaceOutputPin.Create');
  6777. {$ENDIF}
  6778. end;
  6779. function TBCTransInPlaceOutputPin.EnumMediaTypes(
  6780. out ppEnum: IEnumMediaTypes): HRESULT;
  6781. begin
  6782. // Can only pass through if connected.
  6783. if not FTIPFilter.FInput.IsConnected then
  6784. result := VFW_E_NOT_CONNECTED
  6785. else
  6786. result := FTIPFilter.FInput.GetConnected.EnumMediaTypes(ppEnum);
  6787. end;
  6788. function TBCTransInPlaceOutputPin.PeekAllocator: IMemAllocator;
  6789. begin
  6790. result := FAllocator;
  6791. end;
  6792. procedure TBCTransInPlaceOutputPin.SetAllocator(Allocator: IMemAllocator);
  6793. begin
  6794. Allocator._AddRef;
  6795. if(FAllocator <> nil) then FAllocator._Release;
  6796. Pointer(FAllocator) := Pointer(Allocator);
  6797. end;
  6798. { TBCTransInPlaceFilter }
  6799. function TBCTransInPlaceFilter.CheckTransform(mtIn,
  6800. mtOut: PAMMediaType): HRESULT;
  6801. begin
  6802. result := S_OK;
  6803. end;
  6804. // dir is the direction of our pin.
  6805. // pReceivePin is the pin we are connecting to.
  6806. function TBCTransInPlaceFilter.CompleteConnect(dir: TPinDirection;
  6807. ReceivePin: IPin): HRESULT;
  6808. var
  6809. pmt: PAMMediaType;
  6810. begin
  6811. ASSERT(FInput <> nil);
  6812. ASSERT(FOutput <> nil);
  6813. // if we are not part of a graph, then don't indirect the pointer
  6814. // this probably prevents use of the filter without a filtergraph
  6815. if(FGraph = nil) then
  6816. begin
  6817. result := VFW_E_NOT_IN_GRAPH;
  6818. exit;
  6819. end;
  6820. // Always reconnect the input to account for buffering changes
  6821. //
  6822. // Because we don't get to suggest a type on ReceiveConnection
  6823. // we need another way of making sure the right type gets used.
  6824. //
  6825. // One way would be to have our EnumMediaTypes return our output
  6826. // connection type first but more deterministic and simple is to
  6827. // call ReconnectEx passing the type we want to reconnect with
  6828. // via the base class ReconeectPin method.
  6829. if(dir = PINDIR_OUTPUT) then
  6830. begin
  6831. if FInput.IsConnected then
  6832. begin
  6833. result := ReconnectPin(FInput, FOutput.AMMediaType);
  6834. exit;
  6835. end;
  6836. result := NOERROR;
  6837. exit;
  6838. end;
  6839. ASSERT(dir = PINDIR_INPUT);
  6840. // Reconnect output if necessary
  6841. if FOutput.IsConnected then
  6842. begin
  6843. pmt := FInput.CurrentMediaType.MediaType;
  6844. if (not TBCMediaType(pmt).Equal(FOutput.CurrentMediaType.MediaType)) then
  6845. begin
  6846. result := ReconnectPin(FOutput, FInput.CurrentMediaType.MediaType);
  6847. exit;
  6848. end;
  6849. end;
  6850. result := NOERROR;
  6851. end;
  6852. function TBCTransInPlaceFilter.Copy(Source: IMediaSample): IMediaSample;
  6853. var
  6854. Start, Stop: TReferenceTime;
  6855. Time: boolean;
  6856. pStartTime, pEndTime: PReferenceTime;
  6857. TimeStart, TimeEnd: Int64;
  6858. Flags: DWORD;
  6859. Sample2: IMediaSample2;
  6860. props: PAMSample2Properties;
  6861. MediaType: PAMMediaType;
  6862. DataLength: LongInt;
  6863. SourceBuffer, DestBuffer: PByte;
  6864. SourceSize, DestSize: LongInt;
  6865. hr: hresult;
  6866. begin
  6867. Time := (Source.GetTime(Start, Stop) = S_OK);
  6868. // this may block for an indeterminate amount of time
  6869. if Time then
  6870. begin
  6871. pStartTime := @Start;
  6872. pEndTime := @Stop;
  6873. end
  6874. else
  6875. begin
  6876. pStartTime := nil;
  6877. pEndTime := nil;
  6878. end;
  6879. if FSampleSkipped then Flags := AM_GBF_PREVFRAMESKIPPED else Flags := 0;
  6880. hr := OutputPin.PeekAllocator.GetBuffer(result, pStartTime, pEndTime, Flags);
  6881. if FAILED(hr) then exit;
  6882. ASSERT(result <> nil);
  6883. if(SUCCEEDED(result.QueryInterface(IID_IMediaSample2, Sample2))) then
  6884. begin
  6885. props := FInput.SampleProps;
  6886. hr := Sample2.SetProperties(SizeOf(TAMSample2Properties) - (4*2), props^);
  6887. Sample2 := nil;
  6888. if FAILED(hr) then
  6889. begin
  6890. result := nil;
  6891. exit;
  6892. end;
  6893. end
  6894. else
  6895. begin
  6896. if Time then result.SetTime(@Start, @Stop);
  6897. if (Source.IsSyncPoint = S_OK) then result.SetSyncPoint(True);
  6898. if ((Source.IsDiscontinuity = S_OK) or FSampleSkipped) then result.SetDiscontinuity(True);
  6899. if (Source.IsPreroll = S_OK) then result.SetPreroll(True);
  6900. // Copy the media type
  6901. if (Source.GetMediaType(MediaType) = S_OK) then
  6902. begin
  6903. result.SetMediaType(MediaType^);
  6904. DeleteMediaType(MediaType);
  6905. end;
  6906. end;
  6907. FSampleSkipped := FALSE;
  6908. // Copy the sample media times
  6909. if (Source.GetMediaTime(TimeStart, TimeEnd) = NOERROR) then
  6910. result.SetMediaTime(@TimeStart,@TimeEnd);
  6911. // Copy the actual data length and the actual data.
  6912. DataLength := Source.GetActualDataLength;
  6913. result.SetActualDataLength(DataLength);
  6914. // Copy the sample data
  6915. SourceSize := Source.GetSize;
  6916. DestSize := result.GetSize;
  6917. // milenko start get rid of compiler warnings
  6918. if (DestSize < SourceSize) then
  6919. begin
  6920. end;
  6921. // milenko end
  6922. ASSERT(DestSize >= SourceSize, format('DestSize (%d) < SourceSize (%d)',[DestSize, SourceSize]));
  6923. ASSERT(DestSize >= DataLength);
  6924. Source.GetPointer(SourceBuffer);
  6925. result.GetPointer(DestBuffer);
  6926. ASSERT((DestSize = 0) or (SourceBuffer <> nil) and (DestBuffer <> nil));
  6927. CopyMemory(DestBuffer, SourceBuffer, DataLength);
  6928. end;
  6929. constructor TBCTransInPlaceFilter.Create(ObjectName: string;
  6930. unk: IUnKnown; clsid: TGUID; out hr: HRESULT; ModifiesData: boolean);
  6931. begin
  6932. inherited create(ObjectName, Unk, clsid);
  6933. FModifiesData := ModifiesData;
  6934. end;
  6935. constructor TBCTransInPlaceFilter.CreateFromFactory(Factory: TBCClassFactory;
  6936. const Controller: IUnknown);
  6937. begin
  6938. inherited create(FacTory.FName, Controller, FacTory.FClassID);
  6939. FModifiesData := True;
  6940. end;
  6941. // Tell the output pin's allocator what size buffers we require.
  6942. // *pAlloc will be the allocator our output pin is using.
  6943. function TBCTransInPlaceFilter.DecideBufferSize(Alloc: IMemAllocator;
  6944. propInputRequest: PAllocatorProperties): HRESULT;
  6945. var Request, Actual: TAllocatorProperties;
  6946. begin
  6947. // If we are connected upstream, get his views
  6948. if FInput.IsConnected then
  6949. begin
  6950. // Get the input pin allocator, and get its size and count.
  6951. // we don't care about his alignment and prefix.
  6952. result := InputPin.FAllocator.GetProperties(Request);
  6953. //Request.cbBuffer := 230400;
  6954. if FAILED(result) then exit; // Input connected but with a secretive allocator - enough!
  6955. end
  6956. else
  6957. begin
  6958. // We're reduced to blind guessing. Let's guess one byte and if
  6959. // this isn't enough then when the other pin does get connected
  6960. // we can revise it.
  6961. ZeroMemory(@Request, sizeof(Request));
  6962. Request.cBuffers := 1;
  6963. Request.cbBuffer := 1;
  6964. end;
  6965. {$IFDEF DEBUG}
  6966. DbgLog(self, 'Setting Allocator Requirements');
  6967. DbgLog(self, format('Count %d, Size %d',[Request.cBuffers, Request.cbBuffer]));
  6968. {$ENDIF}
  6969. // Pass the allocator requirements to our output side
  6970. // but do a little sanity checking first or we'll just hit
  6971. // asserts in the allocator.
  6972. propInputRequest.cBuffers := Request.cBuffers;
  6973. propInputRequest.cbBuffer := Request.cbBuffer;
  6974. if (propInputRequest.cBuffers <= 0) then propInputRequest.cBuffers := 1;
  6975. if (propInputRequest.cbBuffer <= 0) then propInputRequest.cbBuffer := 1;
  6976. result := Alloc.SetProperties(propInputRequest^, Actual);
  6977. if FAILED(result) then exit;
  6978. {$IFDEF DEBUG}
  6979. DbgLog(self, 'Obtained Allocator Requirements');
  6980. DbgLog(self, format('Count %d, Size %d, Alignment %d', [Actual.cBuffers, Actual.cbBuffer, Actual.cbAlign]));
  6981. {$ENDIF}
  6982. // Make sure we got the right alignment and at least the minimum required
  6983. if ((Request.cBuffers > Actual.cBuffers)
  6984. or (Request.cbBuffer > Actual.cbBuffer)
  6985. or (Request.cbAlign > Actual.cbAlign)) then
  6986. result := E_FAIL
  6987. else
  6988. result := NOERROR;
  6989. end;
  6990. function TBCTransInPlaceFilter.GetMediaType(Position: integer;
  6991. out MediaType: PAMMediaType): HRESULT;
  6992. begin
  6993. {$IFDEF DEBUG}
  6994. DbgLog(self, 'TBCTransInPlaceFilter.GetMediaType should never be called');
  6995. {$ENDIF}
  6996. result := E_UNEXPECTED;
  6997. end;
  6998. // return a non-addrefed CBasePin * for the user to addref if he holds onto it
  6999. // for longer than his pointer to us. We create the pins dynamically when they
  7000. // are asked for rather than in the constructor. This is because we want to
  7001. // give the derived class an oppportunity to return different pin objects
  7002. // As soon as any pin is needed we create both (this is different from the
  7003. // usual transform filter) because enumerators, allocators etc are passed
  7004. // through from one pin to another and it becomes very painful if the other
  7005. // pin isn't there. If we fail to create either pin we ensure we fail both.
  7006. function TBCTransInPlaceFilter.GetPin(n: integer): TBCBasePin;
  7007. var hr: HRESULT;
  7008. begin
  7009. hr := S_OK;
  7010. // Create an input pin if not already done
  7011. if(FInput = nil) then
  7012. begin
  7013. FInput := TBCTransInPlaceInputPin.Create('TransInPlace input pin',
  7014. self, // Owner filter
  7015. hr, // Result code
  7016. 'Input'); // Pin name
  7017. // Constructor for CTransInPlaceInputPin can't fail
  7018. ASSERT(SUCCEEDED(hr));
  7019. end;
  7020. // Create an output pin if not already done
  7021. if((FInput <> nil) and (FOutput = nil)) then
  7022. begin
  7023. FOutput := TBCTransInPlaceOutputPin.Create('TransInPlace output pin',
  7024. self, // Owner filter
  7025. hr, // Result code
  7026. 'Output'); // Pin name
  7027. // a failed return code should delete the object
  7028. ASSERT(SUCCEEDED(hr));
  7029. if(FOutput = nil) then
  7030. begin
  7031. FInput.Free;
  7032. FInput := nil;
  7033. end;
  7034. end;
  7035. // Return the appropriate pin
  7036. ASSERT(n in [0,1]);
  7037. case n of
  7038. 0: result := FInput;
  7039. 1: result := FOutput;
  7040. else
  7041. result := nil;
  7042. end;
  7043. end;
  7044. function TBCTransInPlaceFilter.InputPin: TBCTransInPlaceInputPin;
  7045. begin
  7046. result := TBCTransInPlaceInputPin(FInput);
  7047. end;
  7048. function TBCTransInPlaceFilter.OutputPin: TBCTransInPlaceOutputPin;
  7049. begin
  7050. result := TBCTransInPlaceOutputPin(FOutput);
  7051. end;
  7052. function TBCTransInPlaceFilter.Receive(Sample: IMediaSample): HRESULT;
  7053. var Props: PAMSample2Properties;
  7054. begin
  7055. // Check for other streams and pass them on */
  7056. Props := FInput.SampleProps;
  7057. if (Props.dwStreamId <> AM_STREAM_MEDIA) then
  7058. begin
  7059. result := FOutput.Deliver(Sample);
  7060. exit;
  7061. end;
  7062. if UsingDifferentAllocators then
  7063. begin
  7064. // We have to copy the data.
  7065. Sample := Copy(Sample);
  7066. if (Sample = nil) then
  7067. begin
  7068. result := E_UNEXPECTED;
  7069. exit;
  7070. end;
  7071. end;
  7072. // have the derived class transform the data
  7073. result := Transform(Sample);
  7074. if FAILED(result) then
  7075. begin
  7076. {$IFDEF DEBUG}
  7077. DbgLog(self, 'Error from TransInPlace');
  7078. {$ENDIF}
  7079. if UsingDifferentAllocators then Sample := nil;
  7080. exit;
  7081. end;
  7082. // the Transform() function can return S_FALSE to indicate that the
  7083. // sample should not be delivered; we only deliver the sample if it's
  7084. // really S_OK (same as NOERROR, of course.)
  7085. if (result = NOERROR) then
  7086. result := FOutput.Deliver(Sample)
  7087. else
  7088. begin
  7089. // But it would be an error to return this private workaround
  7090. // to the caller ...
  7091. if (result = S_FALSE) then
  7092. begin
  7093. // S_FALSE returned from Transform is a PRIVATE agreement
  7094. // We should return NOERROR from Receive() in this cause because
  7095. // returning S_FALSE from Receive() means that this is the end
  7096. // of the stream and no more data should be sent.
  7097. FSampleSkipped := True;
  7098. if (not FQualityChanged) then
  7099. begin
  7100. NotifyEvent(EC_QUALITY_CHANGE,0,0);
  7101. FQualityChanged := True;
  7102. end;
  7103. result := NOERROR;
  7104. end;
  7105. end;
  7106. // release the output buffer. If the connected pin still needs it,
  7107. // it will have addrefed it itself.
  7108. if UsingDifferentAllocators then Sample := nil;
  7109. end;
  7110. function TBCTransInPlaceFilter.TypesMatch: boolean;
  7111. var
  7112. pmt: PAMMediaType;
  7113. begin
  7114. pmt := InputPin.CurrentMediaType.MediaType;
  7115. result := TBCMediaType(pmt).Equal(OutputPin.CurrentMediaType.MediaType);
  7116. end;
  7117. function TBCTransInPlaceFilter.UsingDifferentAllocators: boolean;
  7118. begin
  7119. result := Pointer(InputPin.FAllocator) <> Pointer(OutputPin.FAllocator);
  7120. end;
  7121. { TBCBasePropertyPage }
  7122. function TBCBasePropertyPage.Activate(hwndParent: HWnd; const rc: TRect;
  7123. bModal: BOOL): HResult;
  7124. begin
  7125. // Return failure if SetObject has not been called.
  7126. if (FObjectSet = FALSE) or (hwndParent = 0) then
  7127. begin
  7128. result := E_UNEXPECTED;
  7129. exit;
  7130. end;
  7131. // FForm := TCustomFormClass(FFormClass).Create(nil);
  7132. if (FForm = nil) then
  7133. begin
  7134. result := E_OUTOFMEMORY;
  7135. exit;
  7136. end;
  7137. FForm.ParentWindow := hwndParent;
  7138. if assigned(FForm.OnActivate) then FForm.OnActivate(FForm);
  7139. Move(rc);
  7140. result := Show(SW_SHOWNORMAL);
  7141. end;
  7142. function TBCBasePropertyPage.Apply: HResult;
  7143. begin
  7144. // In ActiveMovie 1.0 we used to check whether we had been activated or
  7145. // not. This is too constrictive. Apply should be allowed as long as
  7146. // SetObject was called to set an object. So we will no longer check to
  7147. // see if we have been activated (ie., m_hWnd != NULL), but instead
  7148. // make sure that m_bObjectSet is True (ie., SetObject has been called).
  7149. if (FObjectSet = FALSE) or (FPageSite = nil) then
  7150. begin
  7151. result := E_UNEXPECTED;
  7152. exit;
  7153. end;
  7154. if (FDirty = FALSE) then
  7155. begin
  7156. result := NOERROR;
  7157. exit;
  7158. end;
  7159. // Commit derived class changes
  7160. result := FForm.OnApplyChanges;
  7161. if SUCCEEDED(result) then FDirty := FALSE;
  7162. end;
  7163. function TBCBasePropertyPage.Deactivate: HResult;
  7164. var Style: DWORD;
  7165. begin
  7166. if (FForm = nil) then
  7167. begin
  7168. result := E_UNEXPECTED;
  7169. exit;
  7170. end;
  7171. // Remove WS_EX_CONTROLPARENT before DestroyWindow call
  7172. Style := GetWindowLong(FForm.Handle, GWL_EXSTYLE);
  7173. Style := Style and (not WS_EX_CONTROLPARENT);
  7174. // Set m_hwnd to be NULL temporarily so the message handler
  7175. // for WM_STYLECHANGING doesn't add the WS_EX_CONTROLPARENT
  7176. // style back in
  7177. SetWindowLong(FForm.Handle, GWL_EXSTYLE, Style);
  7178. if assigned(FForm.OnDeactivate) then FForm.OnDeactivate(FForm);
  7179. // Destroy the dialog window
  7180. //FForm.Free;
  7181. //FForm := nil;
  7182. result := NOERROR;
  7183. end;
  7184. function TBCBasePropertyPage.GetPageInfo(out pageInfo: TPropPageInfo): HResult;
  7185. begin
  7186. pageInfo.cb := sizeof(TPropPageInfo);
  7187. AMGetWideString(FForm.Caption, pageInfo.pszTitle);
  7188. PageInfo.pszDocString := nil;
  7189. PageInfo.pszHelpFile := nil;
  7190. PageInfo.dwHelpContext:= 0;
  7191. PageInfo.size.cx := FForm.width;
  7192. PageInfo.size.cy := FForm.Height;
  7193. Result := NoError;
  7194. end;
  7195. function TBCBasePropertyPage.Help(pszHelpDir: POleStr): HResult;
  7196. begin
  7197. result := E_NOTIMPL;
  7198. end;
  7199. function TBCBasePropertyPage.IsPageDirty: HResult;
  7200. begin
  7201. if FDirty then result := S_OK else result := S_FALSE;
  7202. end;
  7203. function TBCBasePropertyPage.Move(const rect: TRect): HResult;
  7204. begin
  7205. if (FForm = nil) then
  7206. begin
  7207. result := E_UNEXPECTED;
  7208. exit;
  7209. end;
  7210. MoveWindow(FForm.Handle, // Property page handle
  7211. Rect.left, // x coordinate
  7212. Rect.top, // y coordinate
  7213. Rect.Right - Rect.Left, // Overall window width
  7214. Rect.Bottom - Rect.Top, // And likewise height
  7215. True); // Should we repaint it
  7216. result := NOERROR;
  7217. end;
  7218. function TBCBasePropertyPage.SetObjects(cObjects: Integer;
  7219. pUnkList: PUnknownList): HResult;
  7220. begin
  7221. if (cObjects = 1) then
  7222. begin
  7223. if (pUnkList = nil) then
  7224. begin
  7225. result := E_POINTER;
  7226. exit;
  7227. end;
  7228. // Set a flag to say that we have set the Object
  7229. FObjectSet := True ;
  7230. result := FForm.OnConnect(pUnkList^[0]);
  7231. exit;
  7232. end
  7233. else
  7234. if (cObjects = 0) then
  7235. begin
  7236. // Set a flag to say that we have not set the Object for the page
  7237. FObjectSet := FALSE;
  7238. result := FForm.OnDisconnect;
  7239. exit;
  7240. end;
  7241. {$IFDEF DEBUG}
  7242. DbgLog(self, 'No support for more than one object');
  7243. {$ENDIF}
  7244. result := E_UNEXPECTED;
  7245. end;
  7246. function TBCBasePropertyPage.SetPageSite(
  7247. const pageSite: IPropertyPageSite): HResult;
  7248. begin
  7249. if (pageSite <> nil) then
  7250. begin
  7251. if (FPageSite <> nil) then
  7252. begin
  7253. result := E_UNEXPECTED;
  7254. exit;
  7255. end;
  7256. FPageSite := pageSite;
  7257. end
  7258. else
  7259. begin
  7260. if (FPageSite = nil) then
  7261. begin
  7262. result := E_UNEXPECTED;
  7263. exit;
  7264. end;
  7265. FPageSite := nil;
  7266. end;
  7267. result := NOERROR;
  7268. end;
  7269. function TBCBasePropertyPage.Show(nCmdShow: Integer): HResult;
  7270. begin
  7271. if (FForm = nil) then
  7272. begin
  7273. result := E_UNEXPECTED;
  7274. exit;
  7275. end;
  7276. if ((nCmdShow <> SW_SHOW) and (nCmdShow <> SW_SHOWNORMAL) and (nCmdShow <> SW_HIDE)) then
  7277. begin
  7278. result := E_INVALIDARG;
  7279. exit;
  7280. end;
  7281. if nCmdShow in [SW_SHOW,SW_SHOWNORMAL] then FForm.Show else FForm.Hide;
  7282. InvalidateRect(FForm.Handle, nil, True);
  7283. result := NOERROR;
  7284. end;
  7285. function TBCBasePropertyPage.TranslateAccelerator(msg: PMsg): HResult;
  7286. begin
  7287. result := E_NOTIMPL;
  7288. end;
  7289. constructor TBCBasePropertyPage.Create(Name: String; Unk: IUnKnown; Form: TFormPropertyPage);
  7290. begin
  7291. inherited Create(Name, Unk);
  7292. FForm := Form;
  7293. FForm.BorderStyle := bsNone;
  7294. FPageSite := nil;
  7295. FObjectSet := false;
  7296. FDirty := false;
  7297. end;
  7298. destructor TBCBasePropertyPage.Destroy;
  7299. begin
  7300. if FForm <> nil then
  7301. begin
  7302. FForm.Free;
  7303. FForm := nil;
  7304. end;
  7305. inherited;
  7306. end;
  7307. constructor TFormPropertyPage.Create(AOwner: TComponent);
  7308. begin
  7309. inherited Create(AOwner);
  7310. WindowProc := MyWndProc;
  7311. end;
  7312. procedure TFormPropertyPage.MyWndProc(var aMsg: TMessage);
  7313. var
  7314. lpss : PStyleStruct;
  7315. begin
  7316. // we would like the TAB key to move around the tab stops in our property
  7317. // page, but for some reason OleCreatePropertyFrame clears the CONTROLPARENT
  7318. // style behind our back, so we need to switch it back on now behind its
  7319. // back. Otherwise the tab key will be useless in every page.
  7320. // DCoder: removing CONTROLPARENT is also the reason for non responding
  7321. // PropertyPages when using ShowMessage and TComboBox.
  7322. if (aMsg.Msg = WM_STYLECHANGING) and (aMsg.WParam = GWL_EXSTYLE) then
  7323. begin
  7324. lpss := PStyleStruct(aMsg.LParam);
  7325. lpss.styleNew := lpss.styleNew or WS_EX_CONTROLPARENT;
  7326. aMsg.Result := 0;
  7327. Exit;
  7328. end;
  7329. WndProc(aMsg);
  7330. end;
  7331. function TFormPropertyPage.OnApplyChanges: HRESULT;
  7332. begin
  7333. result := NOERROR;
  7334. end;
  7335. function TFormPropertyPage.OnConnect(Unknown: IUnKnown): HRESULT;
  7336. begin
  7337. result := NOERROR;
  7338. end;
  7339. function TFormPropertyPage.OnDisconnect: HRESULT;
  7340. begin
  7341. result := NOERROR;
  7342. end;
  7343. procedure TBCBasePropertyPage.SetPageDirty;
  7344. begin
  7345. FDirty := True;
  7346. if Assigned(FPageSite) then FPageSite.OnStatusChange(PROPPAGESTATUS_DIRTY);
  7347. end;
  7348. { TBCBaseDispatch }
  7349. function TBCBaseDispatch.GetIDsOfNames(const IID: TGUID; Names: Pointer;
  7350. NameCount, LocaleID: Integer; DispIDs: Pointer): HResult;
  7351. var ti: ITypeInfo;
  7352. begin
  7353. // although the IDispatch riid is dead, we use this to pass from
  7354. // the interface implementation class to us the iid we are talking about.
  7355. result := GetTypeInfo(iid, 0, LocaleID, ti);
  7356. if SUCCEEDED(result) then
  7357. result := ti.GetIDsOfNames(Names, NameCount, DispIDs);
  7358. end;
  7359. function TBCBaseDispatch.GetTypeInfo(const iid: TGUID; info: Cardinal; lcid: LCID;
  7360. out tinfo): HRESULT; stdcall;
  7361. var
  7362. tlib : ITypeLib;
  7363. begin
  7364. // we only support one type element
  7365. if (info <> 0) then
  7366. begin
  7367. result := TYPE_E_ELEMENTNOTFOUND;
  7368. exit;
  7369. end;
  7370. // always look for neutral
  7371. if (FTI = nil) then
  7372. begin
  7373. result := LoadRegTypeLib(LIBID_QuartzTypeLib, 1, 0, lcid, tlib);
  7374. if FAILED(result) then
  7375. begin
  7376. result := LoadTypeLib('control.tlb', tlib);
  7377. if FAILED(result) then exit;
  7378. end;
  7379. result := tlib.GetTypeInfoOfGuid(iid, Fti);
  7380. tlib := nil;
  7381. if FAILED(result) then exit;
  7382. end;
  7383. ITypeInfo(tinfo) := Fti;
  7384. result := S_OK;
  7385. end;
  7386. function TBCBaseDispatch.GetTypeInfoCount(out Count: Integer): HResult;
  7387. begin
  7388. count := 1;
  7389. result := S_OK;
  7390. end;
  7391. { TBCMediaControl }
  7392. constructor TBCMediaControl.Create(name: string; unk: IUnknown);
  7393. begin
  7394. FBaseDisp := TBCBaseDispatch.Create;
  7395. end;
  7396. destructor TBCMediaControl.Destroy;
  7397. begin
  7398. FBaseDisp.Free;
  7399. inherited;
  7400. end;
  7401. function TBCMediaControl.GetIDsOfNames(const IID: TGUID; Names: Pointer;
  7402. NameCount, LocaleID: Integer; DispIDs: Pointer): HResult;
  7403. begin
  7404. result := FBasedisp.GetIDsOfNames(IID_IMediaControl, Names, NameCount, LocaleID, DispIDs);
  7405. end;
  7406. function TBCMediaControl.GetTypeInfo(Index, LocaleID: Integer;
  7407. out TypeInfo): HResult;
  7408. begin
  7409. result := Fbasedisp.GetTypeInfo(IID_IMediaControl, index, LocaleID, TypeInfo);
  7410. end;
  7411. function TBCMediaControl.GetTypeInfoCount(out Count: Integer): HResult;
  7412. begin
  7413. result := FBaseDisp.GetTypeInfoCount(Count);
  7414. end;
  7415. function TBCMediaControl.Invoke(DispID: Integer; const IID: TGUID;
  7416. LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo,
  7417. ArgErr: Pointer): HResult;
  7418. var ti: ITypeInfo;
  7419. begin
  7420. // this parameter is a dead leftover from an earlier interface
  7421. if not IsEqualGUID(GUID_NULL, IID) then
  7422. begin
  7423. result := DISP_E_UNKNOWNINTERFACE;
  7424. exit;
  7425. end;
  7426. result := GetTypeInfo(0, LocaleID, ti);
  7427. if FAILED(result) then exit;
  7428. result := ti.Invoke(Pointer(Integer(Self)), DISPID, Flags, TDispParams(Params),
  7429. VarResult, ExcepInfo, ArgErr);
  7430. end;
  7431. { TBCMediaEvent }
  7432. constructor TBCMediaEvent.Create(Name: string; Unk: IUnknown);
  7433. begin
  7434. inherited Create(name, Unk);
  7435. FBasedisp := TBCBaseDispatch.Create;
  7436. end;
  7437. destructor TBCMediaEvent.destroy;
  7438. begin
  7439. FBasedisp.Free;
  7440. inherited;
  7441. end;
  7442. function TBCMediaEvent.GetIDsOfNames(const IID: TGUID; Names: Pointer;
  7443. NameCount, LocaleID: Integer; DispIDs: Pointer): HResult;
  7444. begin
  7445. result := FBasedisp.GetIDsOfNames(IID_IMediaEvent, Names, NameCount, LocaleID, DispIDs);
  7446. end;
  7447. function TBCMediaEvent.GetTypeInfo(Index, LocaleID: Integer;
  7448. out TypeInfo): HResult;
  7449. begin
  7450. result := Fbasedisp.GetTypeInfo(IID_IMediaEvent, index, LocaleID, TypeInfo);
  7451. end;
  7452. function TBCMediaEvent.GetTypeInfoCount(out Count: Integer): HResult;
  7453. begin
  7454. result := FBaseDisp.GetTypeInfoCount(Count);
  7455. end;
  7456. function TBCMediaEvent.Invoke(DispID: Integer; const IID: TGUID;
  7457. LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo,
  7458. ArgErr: Pointer): HResult;
  7459. var ti: ITypeInfo;
  7460. begin
  7461. // this parameter is a dead leftover from an earlier interface
  7462. if not IsEqualGUID(GUID_NULL, IID) then
  7463. begin
  7464. result := DISP_E_UNKNOWNINTERFACE;
  7465. exit;
  7466. end;
  7467. result := GetTypeInfo(0, LocaleID, ti);
  7468. if FAILED(result) then exit;
  7469. result := ti.Invoke(Pointer(Integer(Self)), DISPID, Flags, TDispParams(Params), VarResult, ExcepInfo, ArgErr);
  7470. end;
  7471. { TBCMediaPosition }
  7472. constructor TBCMediaPosition.Create(Name: String; Unk: IUnknown);
  7473. begin
  7474. inherited Create(Name, Unk);
  7475. FBaseDisp := TBCBaseDispatch.Create;
  7476. end;
  7477. constructor TBCMediaPosition.Create(Name: String; Unk: IUnknown;
  7478. out hr: HRESULT);
  7479. begin
  7480. inherited Create(Name, Unk);
  7481. FBaseDisp := TBCBaseDispatch.Create;
  7482. end;
  7483. destructor TBCMediaPosition.Destroy;
  7484. begin
  7485. FBaseDisp.Free;
  7486. inherited;
  7487. end;
  7488. function TBCMediaPosition.GetIDsOfNames(const IID: TGUID; Names: Pointer;
  7489. NameCount, LocaleID: Integer; DispIDs: Pointer): HResult;
  7490. begin
  7491. result := FBasedisp.GetIDsOfNames(IID_IMediaPosition, Names, NameCount, LocaleID, DispIDs);
  7492. end;
  7493. function TBCMediaPosition.GetTypeInfo(Index, LocaleID: Integer;
  7494. out TypeInfo): HResult;
  7495. begin
  7496. result := Fbasedisp.GetTypeInfo(IID_IMediaPosition, index, LocaleID, TypeInfo);
  7497. end;
  7498. function TBCMediaPosition.GetTypeInfoCount(out Count: Integer): HResult;
  7499. begin
  7500. result := Fbasedisp.GetTypeInfoCount(Count);
  7501. end;
  7502. function TBCMediaPosition.Invoke(DispID: Integer; const IID: TGUID;
  7503. LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo,
  7504. ArgErr: Pointer): HResult;
  7505. var ti: ITypeInfo;
  7506. begin
  7507. // this parameter is a dead leftover from an earlier interface
  7508. if not IsEqualGUID(GUID_NULL, IID) then
  7509. begin
  7510. result := DISP_E_UNKNOWNINTERFACE;
  7511. exit;
  7512. end;
  7513. result := GetTypeInfo(0, LocaleID, ti);
  7514. if FAILED(result) then exit;
  7515. result := ti.Invoke(Pointer(Integer(Self)), DISPID, Flags, TDispParams(Params), VarResult, ExcepInfo, ArgErr);
  7516. end;
  7517. { TBCPosPassThru }
  7518. function TBCPosPassThru.CanSeekBackward(
  7519. out pCanSeekBackward: Integer): HResult;
  7520. var MP: IMediaPosition;
  7521. begin
  7522. result := GetPeer(MP);
  7523. if FAILED(result) then exit;
  7524. result := MP.CanSeekBackward(pCanSeekBackward);
  7525. end;
  7526. function TBCPosPassThru.CanSeekForward(
  7527. out pCanSeekForward: Integer): HResult;
  7528. var MP: IMediaPosition;
  7529. begin
  7530. result := GetPeer(MP);
  7531. if FAILED(result) then exit;
  7532. result := MP.CanSeekForward(pCanSeekForward);
  7533. end;
  7534. function TBCPosPassThru.CheckCapabilities(
  7535. var pCapabilities: DWORD): HRESULT;
  7536. var
  7537. MS: IMediaSeeking;
  7538. begin
  7539. result := GetPeerSeeking(MS);
  7540. if FAILED(result) then exit;
  7541. result := MS.CheckCapabilities(pCapabilities);
  7542. end;
  7543. function TBCPosPassThru.ConvertTimeFormat(out pTarget: int64;
  7544. pTargetFormat: PGUID; Source: int64; pSourceFormat: PGUID): HRESULT;
  7545. var MS: IMediaSeeking;
  7546. begin
  7547. result := GetPeerSeeking(MS);
  7548. if FAILED(result) then exit;
  7549. result := MS.ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat);
  7550. end;
  7551. constructor TBCPosPassThru.Create(name: String; Unk: IUnknown;
  7552. out hr: HRESULT; Pin: IPin);
  7553. begin
  7554. assert(Pin <> nil);
  7555. inherited Create(Name,Unk);
  7556. FPin := Pin;
  7557. end;
  7558. function TBCPosPassThru.ForceRefresh: HRESULT;
  7559. begin
  7560. result := S_OK;
  7561. end;
  7562. function TBCPosPassThru.get_CurrentPosition(
  7563. out pllTime: TRefTime): HResult;
  7564. var MP: IMediaPosition;
  7565. begin
  7566. result := GetPeer(MP);
  7567. if FAILED(result) then exit;
  7568. result := MP.get_CurrentPosition(pllTime);
  7569. end;
  7570. function TBCPosPassThru.get_Duration(out plength: TRefTime): HResult;
  7571. var MP: IMediaPosition;
  7572. begin
  7573. result := GetPeer(MP);
  7574. if FAILED(result) then exit;
  7575. result := MP.get_Duration(plength);
  7576. end;
  7577. function TBCPosPassThru.get_PrerollTime(out pllTime: TRefTime): HResult;
  7578. var MP: IMediaPosition;
  7579. begin
  7580. result := GetPeer(MP);
  7581. if FAILED(result) then exit;
  7582. result := MP.get_PrerollTime(pllTime);
  7583. end;
  7584. function TBCPosPassThru.get_Rate(out pdRate: double): HResult;
  7585. var MP: IMediaPosition;
  7586. begin
  7587. result := GetPeer(MP);
  7588. if FAILED(result) then exit;
  7589. result := MP.get_Rate(pdRate);
  7590. end;
  7591. function TBCPosPassThru.get_StopTime(out pllTime: TRefTime): HResult;
  7592. var MP: IMediaPosition;
  7593. begin
  7594. result := GetPeer(MP);
  7595. if FAILED(result) then exit;
  7596. result := MP.get_StopTime(pllTime);
  7597. end;
  7598. function TBCPosPassThru.GetAvailable(out pEarliest,
  7599. pLatest: int64): HRESULT;
  7600. var MS: IMediaSeeking;
  7601. begin
  7602. result := GetPeerSeeking(MS);
  7603. if FAILED(result) then exit;
  7604. result := MS.GetAvailable(pEarliest, pLatest);
  7605. end;
  7606. function TBCPosPassThru.GetCapabilities(out pCapabilities: DWORD): HRESULT;
  7607. var MS: IMediaSeeking;
  7608. begin
  7609. result := GetPeerSeeking(MS);
  7610. if FAILED(result) then exit;
  7611. result := MS.GetCapabilities(pCapabilities);
  7612. end;
  7613. function TBCPosPassThru.GetCurrentPosition(out pCurrent: int64): HRESULT;
  7614. var
  7615. MS: IMediaSeeking;
  7616. Stop: int64;
  7617. begin
  7618. result := GetMediaTime(pCurrent, Stop);
  7619. if SUCCEEDED(result) then
  7620. result := NOERROR
  7621. else
  7622. begin
  7623. result := GetPeerSeeking(MS);
  7624. if FAILED(result) then exit;
  7625. result := MS.GetCurrentPosition(pCurrent)
  7626. end;
  7627. end;
  7628. function TBCPosPassThru.GetDuration(out pDuration: int64): HRESULT;
  7629. var MS: IMediaSeeking;
  7630. begin
  7631. result := GetPeerSeeking(MS);
  7632. if FAILED(result) then exit;
  7633. result := MS.GetDuration(pDuration);
  7634. end;
  7635. function TBCPosPassThru.GetMediaTime(out StartTime,
  7636. EndTime: Int64): HRESULT;
  7637. begin
  7638. result := E_FAIL;
  7639. end;
  7640. // Return the IMediaPosition interface from our peer
  7641. function TBCPosPassThru.GetPeer(out MP: IMediaPosition): HRESULT;
  7642. var
  7643. Connected: IPin;
  7644. begin
  7645. result := FPin.ConnectedTo(Connected);
  7646. if FAILED(result) then
  7647. begin
  7648. result := E_NOTIMPL;
  7649. exit;
  7650. end;
  7651. result := Connected.QueryInterface(IID_IMediaPosition, MP);
  7652. Connected := nil;
  7653. if FAILED(result) then
  7654. begin
  7655. result := E_NOTIMPL;
  7656. exit;
  7657. end;
  7658. result := S_OK;
  7659. end;
  7660. function TBCPosPassThru.GetPeerSeeking(out MS: IMediaSeeking): HRESULT;
  7661. var
  7662. Connected: IPin;
  7663. begin
  7664. MS := nil;
  7665. result := FPin.ConnectedTo(Connected);
  7666. if FAILED(result) then
  7667. begin
  7668. result := E_NOTIMPL;
  7669. exit;
  7670. end;
  7671. result := Connected.QueryInterface(IID_IMediaSeeking, MS);
  7672. Connected := nil;
  7673. if FAILED(result) then
  7674. begin
  7675. result := E_NOTIMPL;
  7676. exit;
  7677. end;
  7678. result := S_OK;
  7679. end;
  7680. function TBCPosPassThru.GetPositions(out pCurrent, pStop: int64): HRESULT;
  7681. var MS: IMediaSeeking;
  7682. begin
  7683. result := GetPeerSeeking(MS);
  7684. if FAILED(result) then exit;
  7685. result := MS.GetPositions(pCurrent, pStop);
  7686. end;
  7687. function TBCPosPassThru.GetPreroll(out pllPreroll: int64): HRESULT;
  7688. var MS: IMediaSeeking;
  7689. begin
  7690. result := GetPeerSeeking(MS);
  7691. if FAILED(result) then exit;
  7692. result := MS.GetPreroll(pllPreroll);
  7693. end;
  7694. function TBCPosPassThru.GetRate(out pdRate: double): HRESULT;
  7695. var MS: IMediaSeeking;
  7696. begin
  7697. result := GetPeerSeeking(MS);
  7698. if FAILED(result) then exit;
  7699. result := MS.GetRate(pdRate);
  7700. end;
  7701. function TBCPosPassThru.GetStopPosition(out pStop: int64): HRESULT;
  7702. var MS: IMediaSeeking;
  7703. begin
  7704. result := GetPeerSeeking(MS);
  7705. if FAILED(result) then exit;
  7706. result := MS.GetStopPosition(pStop);
  7707. end;
  7708. function TBCPosPassThru.GetTimeFormat(out pFormat: TGUID): HRESULT;
  7709. var MS: IMediaSeeking;
  7710. begin
  7711. result := GetPeerSeeking(MS);
  7712. if FAILED(result) then exit;
  7713. result := MS.GetTimeFormat(pFormat);
  7714. end;
  7715. function TBCPosPassThru.IsFormatSupported(const pFormat: TGUID): HRESULT;
  7716. var MS: IMediaSeeking;
  7717. begin
  7718. result := GetPeerSeeking(MS);
  7719. if FAILED(result) then exit;
  7720. result := MS.IsFormatSupported(pFormat);
  7721. end;
  7722. function TBCPosPassThru.IsUsingTimeFormat(const pFormat: TGUID): HRESULT;
  7723. var MS: IMediaSeeking;
  7724. begin
  7725. result := GetPeerSeeking(MS);
  7726. if FAILED(result) then exit;
  7727. result := MS.IsUsingTimeFormat(pFormat);
  7728. end;
  7729. function TBCPosPassThru.put_CurrentPosition(llTime: TRefTime): HResult;
  7730. var MP: IMediaPosition;
  7731. begin
  7732. result := GetPeer(MP);
  7733. if FAILED(result) then exit;
  7734. result := MP.put_CurrentPosition(llTime);
  7735. end;
  7736. function TBCPosPassThru.put_PrerollTime(llTime: TRefTime): HResult;
  7737. var MP: IMediaPosition;
  7738. begin
  7739. result := GetPeer(MP);
  7740. if FAILED(result) then exit;
  7741. result := MP.put_PrerollTime(llTime);
  7742. end;
  7743. function TBCPosPassThru.put_Rate(dRate: double): HResult;
  7744. var MP: IMediaPosition;
  7745. begin
  7746. if (dRate = 0.0) then
  7747. begin
  7748. result := E_INVALIDARG;
  7749. exit;
  7750. end;
  7751. result := GetPeer(MP);
  7752. if FAILED(result) then exit;
  7753. result := MP.put_Rate(dRate);
  7754. end;
  7755. function TBCPosPassThru.put_StopTime(llTime: TRefTime): HResult;
  7756. var MP: IMediaPosition;
  7757. begin
  7758. result := GetPeer(MP);
  7759. if FAILED(result) then exit;
  7760. result := MP.put_StopTime(llTime);
  7761. end;
  7762. function TBCPosPassThru.QueryPreferredFormat(out pFormat: TGUID): HRESULT;
  7763. var MS: IMediaSeeking;
  7764. begin
  7765. result := GetPeerSeeking(MS);
  7766. if FAILED(result) then exit;
  7767. result := MS.QueryPreferredFormat(pFormat);
  7768. end;
  7769. function TBCPosPassThru.SetPositions(var pCurrent: int64;
  7770. dwCurrentFlags: DWORD; var pStop: int64; dwStopFlags: DWORD): HRESULT;
  7771. var MS: IMediaSeeking;
  7772. begin
  7773. result := GetPeerSeeking(MS);
  7774. if FAILED(result) then exit;
  7775. result := MS.SetPositions(pCurrent, dwCurrentFlags, pStop, dwStopFlags);
  7776. end;
  7777. function TBCPosPassThru.SetRate(dRate: double): HRESULT;
  7778. var MS: IMediaSeeking;
  7779. begin
  7780. if (dRate = 0.0) then
  7781. begin
  7782. result := E_INVALIDARG;
  7783. exit;
  7784. end;
  7785. result := GetPeerSeeking(MS);
  7786. if FAILED(result) then exit;
  7787. result := MS.SetRate(dRate);
  7788. end;
  7789. function TBCPosPassThru.SetTimeFormat(const pFormat: TGUID): HRESULT;
  7790. var MS: IMediaSeeking;
  7791. begin
  7792. result := GetPeerSeeking(MS);
  7793. if FAILED(result) then exit;
  7794. result := MS.SetTimeFormat(pFormat);
  7795. end;
  7796. { TBCRendererPosPassThru }
  7797. // Media times (eg current frame, field, sample etc) are passed through the
  7798. // filtergraph in media samples. When a renderer gets a sample with media
  7799. // times in it, it will call one of the RegisterMediaTime methods we expose
  7800. // (one takes an IMediaSample, the other takes the media times direct). We
  7801. // store the media times internally and return them in GetCurrentPosition.
  7802. constructor TBCRendererPosPassThru.Create(name: String; Unk: IUnknown;
  7803. out hr: HRESULT; Pin: IPin);
  7804. begin
  7805. inherited Create(Name,Unk,hr,Pin);
  7806. FStartMedia:= 0;
  7807. FEndMedia := 0;
  7808. FReset := True;
  7809. FPositionLock := TBCCritSec.Create;
  7810. end;
  7811. destructor TBCRendererPosPassThru.destroy;
  7812. begin
  7813. FPositionLock.Free;
  7814. inherited;
  7815. end;
  7816. // Intended to be called by the owing filter during EOS processing so
  7817. // that the media times can be adjusted to the stop time. This ensures
  7818. // that the GetCurrentPosition will actully get to the stop position.
  7819. function TBCRendererPosPassThru.EOS: HRESULT;
  7820. var Stop: int64;
  7821. begin
  7822. if FReset then result := E_FAIL
  7823. else
  7824. begin
  7825. result := GetStopPosition(Stop);
  7826. if SUCCEEDED(result) then
  7827. begin
  7828. FPositionLock.Lock;
  7829. try
  7830. FStartMedia := Stop;
  7831. FEndMedia := Stop;
  7832. finally
  7833. FPositionLock.UnLock;
  7834. end;
  7835. end;
  7836. end;
  7837. end;
  7838. function TBCRendererPosPassThru.GetMediaTime(out StartTime,
  7839. EndTime: int64): HRESULT;
  7840. begin
  7841. FPositionLock.Lock;
  7842. try
  7843. if FReset then
  7844. begin
  7845. result := E_FAIL;
  7846. exit;
  7847. end;
  7848. // We don't have to return the end time
  7849. result := ConvertTimeFormat(StartTime, nil, FStartMedia, @TIME_FORMAT_MEDIA_TIME);
  7850. if SUCCEEDED(result) then
  7851. result := ConvertTimeFormat(EndTime, nil, FEndMedia, @TIME_FORMAT_MEDIA_TIME);
  7852. finally
  7853. FPositionLock.UnLock;
  7854. end;
  7855. end;
  7856. // Sets the media times the object should report
  7857. function TBCRendererPosPassThru.RegisterMediaTime(
  7858. MediaSample: IMediaSample): HRESULT;
  7859. var StartMedia, EndMedia: TReferenceTime;
  7860. begin
  7861. ASSERT(assigned(MediaSample));
  7862. FPositionLock.Lock;
  7863. try
  7864. // Get the media times from the sample
  7865. result := MediaSample.GetTime(StartMedia, EndMedia);
  7866. if FAILED(result) then
  7867. begin
  7868. ASSERT(result = VFW_E_SAMPLE_TIME_NOT_SET);
  7869. exit;
  7870. end;
  7871. FStartMedia := StartMedia;
  7872. FEndMedia := EndMedia;
  7873. FReset := FALSE;
  7874. result := NOERROR;
  7875. finally
  7876. FPositionLock.Unlock;
  7877. end;
  7878. end;
  7879. // Sets the media times the object should report
  7880. function TBCRendererPosPassThru.RegisterMediaTime(StartTime,
  7881. EndTime: int64): HRESULT;
  7882. begin
  7883. FPositionLock.Lock;
  7884. try
  7885. FStartMedia := StartTime;
  7886. FEndMedia := EndTime;
  7887. FReset := FALSE;
  7888. result := NOERROR;
  7889. finally
  7890. FPositionLock.UnLock;
  7891. end;
  7892. end;
  7893. // Resets the media times we hold
  7894. function TBCRendererPosPassThru.ResetMediaTime: HRESULT;
  7895. begin
  7896. FPositionLock.Lock;
  7897. try
  7898. FStartMedia := 0;
  7899. FEndMedia := 0;
  7900. FReset := True;
  7901. result := NOERROR;
  7902. finally
  7903. FPositionLock.UnLock;
  7904. end;
  7905. end;
  7906. { TBCAMEvent }
  7907. function TBCAMEvent.Check: boolean;
  7908. begin
  7909. result := Wait(0);
  7910. end;
  7911. constructor TBCAMEvent.Create(ManualReset: boolean);
  7912. begin
  7913. FEvent := CreateEvent(nil, ManualReset, FALSE, nil);
  7914. end;
  7915. destructor TBCAMEvent.destroy;
  7916. begin
  7917. if FEvent <> 0 then
  7918. Assert(CloseHandle(FEvent));
  7919. inherited;
  7920. end;
  7921. procedure TBCAMEvent.Reset;
  7922. begin
  7923. ResetEvent(FEvent);
  7924. end;
  7925. procedure TBCAMEvent.SetEv;
  7926. begin
  7927. SetEvent(FEvent);
  7928. end;
  7929. function TBCAMEvent.Wait(Timeout: Cardinal): boolean;
  7930. begin
  7931. result := (WaitForSingleObject(FEvent, Timeout) = WAIT_OBJECT_0);
  7932. end;
  7933. { TBCRenderedInputPin }
  7934. function TBCRenderedInputPin.Active: HRESULT;
  7935. begin
  7936. FAtEndOfStream := FALSE;
  7937. FCompleteNotified := FALSE;
  7938. result := inherited Active;
  7939. end;
  7940. constructor TBCRenderedInputPin.Create(ObjectName: string;
  7941. Filter: TBCBaseFilter; Lock: TBCCritSec; out hr: HRESULT;
  7942. Name: WideString);
  7943. begin
  7944. inherited Create(ObjectName, Filter, Lock, hr, Name);
  7945. FAtEndOfStream := FALSE;
  7946. FCompleteNotified := FALSE;
  7947. end;
  7948. procedure TBCRenderedInputPin.DoCompleteHandling;
  7949. begin
  7950. ASSERT(FAtEndOfStream);
  7951. if (not FCompleteNotified) then
  7952. begin
  7953. FCompleteNotified := True;
  7954. FFilter.NotifyEvent(EC_COMPLETE, S_OK, Integer(FFilter));
  7955. end;
  7956. end;
  7957. function TBCRenderedInputPin.EndFlush: HRESULT;
  7958. begin
  7959. FLock.Lock;
  7960. try
  7961. // Clean up renderer state
  7962. FAtEndOfStream := FALSE;
  7963. FCompleteNotified := FALSE;
  7964. result := inherited EndFlush;
  7965. finally
  7966. FLock.UnLock;
  7967. end;
  7968. end;
  7969. function TBCRenderedInputPin.EndOfStream: HRESULT;
  7970. var
  7971. fs: TFilterState;
  7972. begin
  7973. result := CheckStreaming;
  7974. // Do EC_COMPLETE handling for rendered pins
  7975. if ((result = S_OK) and (not FAtEndOfStream)) then
  7976. begin
  7977. FAtEndOfStream := True;
  7978. ASSERT(SUCCEEDED(FFilter.GetState(0, fs)));
  7979. if (fs = State_Running) then
  7980. DoCompleteHandling;
  7981. end;
  7982. end;
  7983. function TBCRenderedInputPin.Run(Start: TReferenceTime): HRESULT;
  7984. begin
  7985. FCompleteNotified := FALSE;
  7986. if FAtEndOfStream then DoCompleteHandling;
  7987. result := S_OK;
  7988. end;
  7989. { TBCAMMsgEvent }
  7990. function TBCAMMsgEvent.WaitMsg(Timeout: DWord): boolean;
  7991. var
  7992. // wait for the event to be signalled, or for the
  7993. // timeout (in MS) to expire. allow SENT messages
  7994. // to be processed while we wait
  7995. Wait, StartTime: DWord;
  7996. // set the waiting period.
  7997. WaitTime: Dword;
  7998. Msg: TMsg;
  7999. Elapsed: DWord;
  8000. begin
  8001. WaitTime := Timeout;
  8002. // the timeout will eventually run down as we iterate
  8003. // processing messages. grab the start time so that
  8004. // we can calculate elapsed times.
  8005. if (WaitTime <> INFINITE) then
  8006. StartTime := timeGetTime else
  8007. StartTime := 0; // don't generate compiler hint
  8008. repeat
  8009. Wait := MsgWaitForMultipleObjects(1, FEvent, FALSE, WaitTime, QS_SENDMESSAGE);
  8010. if (Wait = WAIT_OBJECT_0 + 1) then
  8011. begin
  8012. PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE);
  8013. // If we have an explicit length of time to wait calculate
  8014. // the next wake up point - which might be now.
  8015. // If dwTimeout is INFINITE, it stays INFINITE
  8016. if (WaitTime <> INFINITE) then
  8017. begin
  8018. Elapsed := timeGetTime - StartTime;
  8019. if (Elapsed >= Timeout) then
  8020. WaitTime := 0 else // wake up with WAIT_TIMEOUT
  8021. WaitTime := Timeout - Elapsed;
  8022. end;
  8023. end
  8024. until (Wait <> WAIT_OBJECT_0 + 1);
  8025. // return True if we woke on the event handle,
  8026. // FALSE if we timed out.
  8027. result := (Wait = WAIT_OBJECT_0);
  8028. end;
  8029. { TBCAMThread }
  8030. function TBCAMThread.CallWorker(Param: DWORD): DWORD;
  8031. begin
  8032. // lock access to the worker thread for scope of this object
  8033. FAccessLock.Lock;
  8034. try
  8035. if not ThreadExists then
  8036. begin
  8037. Result := DWORD(E_FAIL);
  8038. Exit;
  8039. end;
  8040. // set the parameter
  8041. FParam := Param;
  8042. // signal the worker thread
  8043. FEventSend.SetEv;
  8044. // wait for the completion to be signalled
  8045. FEventComplete.Wait;
  8046. // done - this is the thread's return value
  8047. Result := FReturnVal;
  8048. finally
  8049. FAccessLock.unlock;
  8050. end;
  8051. end;
  8052. function TBCAMThread.CheckRequest(Param: PDWORD): boolean;
  8053. begin
  8054. if not FEventSend.Check then
  8055. begin
  8056. Result := FALSE;
  8057. Exit;
  8058. end else
  8059. begin
  8060. if (Param <> nil) then
  8061. Param^ := FParam;
  8062. Result := True;
  8063. end;
  8064. end;
  8065. procedure TBCAMThread.Close;
  8066. var
  8067. Thread: THandle;
  8068. begin
  8069. Thread := InterlockedExchange(Integer(FThread), 0);
  8070. if BOOL(Thread) then
  8071. begin
  8072. WaitForSingleObject(Thread, INFINITE);
  8073. CloseHandle(Thread);
  8074. end;
  8075. end;
  8076. class function TBCAMThread.CoInitializeHelper: HRESULT;
  8077. var
  8078. hr: HRESULT;
  8079. hOle: LongWord;
  8080. CoInitializeEx: function(pvReserved: Pointer; coInit: Longint): HResult; stdcall;
  8081. begin
  8082. // call CoInitializeEx and tell OLE not to create a window (this
  8083. // thread probably won't dispatch messages and will hang on
  8084. // broadcast msgs o/w).
  8085. //
  8086. // If CoInitEx is not available, threads that don't call CoCreate
  8087. // aren't affected. Threads that do will have to handle the
  8088. // failure. Perhaps we should fall back to CoInitialize and risk
  8089. // hanging?
  8090. //
  8091. // older versions of ole32.dll don't have CoInitializeEx
  8092. hr := E_FAIL;
  8093. hOle := GetModuleHandle(PChar('ole32.dll'));
  8094. if (hOle <> 0) then
  8095. begin
  8096. CoInitializeEx := GetProcAddress(hOle, 'CoInitializeEx');
  8097. if (@CoInitializeEx <> nil) then
  8098. hr := CoInitializeEx(nil, COINIT_DISABLE_OLE1DDE);
  8099. end else
  8100. begin
  8101. {$IFDEF DEBUG}
  8102. // caller must load ole32.dll
  8103. DbgLog('couldn''t locate ole32.dll');
  8104. {$ENDIF}
  8105. end;
  8106. result := hr;
  8107. end;
  8108. constructor TBCAMThread.Create;
  8109. begin
  8110. // must be manual-reset for CheckRequest()
  8111. FAccessLock := TBCCritSec.Create;
  8112. FWorkerLock := TBCCritSec.Create;
  8113. FEventSend := TBCAMEvent.Create(True);
  8114. FEventComplete := TBCAMEvent.Create;
  8115. FThread := 0;
  8116. FThreadProc := nil;
  8117. end;
  8118. function TBCAMThread.Create_: boolean;
  8119. var
  8120. threadid: DWORD;
  8121. begin
  8122. FAccessLock.Lock;
  8123. try
  8124. if ThreadExists then
  8125. begin
  8126. Result := False;
  8127. Exit;
  8128. end;
  8129. FThread := CreateThread(nil, 0, @TBCAMThread.InitialThreadProc,
  8130. Self, 0, threadid);
  8131. if not BOOL(FThread) then
  8132. Result := FALSE else
  8133. Result := True;
  8134. finally
  8135. FAccessLock.Unlock;
  8136. end;
  8137. end;
  8138. destructor TBCAMThread.Destroy;
  8139. begin
  8140. Close;
  8141. FAccessLock.Free;
  8142. FWorkerLock.Free;
  8143. FEventSend.Free;
  8144. FEventComplete.Free;
  8145. inherited;
  8146. end;
  8147. function TBCAMThread.GetRequest: DWORD;
  8148. begin
  8149. FEventSend.Wait;
  8150. Result := FParam;
  8151. end;
  8152. function TBCAMThread.GetRequestHandle: THANDLE;
  8153. begin
  8154. Result := FEventSend.FEvent
  8155. end;
  8156. function TBCAMThread.GetRequestParam: DWORD;
  8157. begin
  8158. Result := FParam;
  8159. end;
  8160. function TBCAMThread.InitialThreadProc(p: Pointer): DWORD;
  8161. var
  8162. hrCoInit: HRESULT;
  8163. begin
  8164. hrCoInit := TBCAMThread.CoInitializeHelper;
  8165. {$IFDEF DEBUG}
  8166. if(FAILED(hrCoInit)) then
  8167. DbgLog('CoInitializeEx failed.');
  8168. {$ENDIF}
  8169. Result := ThreadProc;
  8170. if(SUCCEEDED(hrCoInit)) then
  8171. CoUninitialize;
  8172. end;
  8173. procedure TBCAMThread.Reply(v: DWORD);
  8174. begin
  8175. FReturnVal := v;
  8176. // The request is now complete so CheckRequest should fail from
  8177. // now on
  8178. //
  8179. // This event should be reset BEFORE we signal the client or
  8180. // the client may Set it before we reset it and we'll then
  8181. // reset it (!)
  8182. FEventSend.Reset;
  8183. // Tell the client we're finished
  8184. FEventComplete.SetEv;
  8185. end;
  8186. function TBCAMThread.ThreadExists: boolean;
  8187. begin
  8188. Result := FThread <> 0;
  8189. end;
  8190. function TBCAMThread.ThreadProc: DWord;
  8191. begin
  8192. if @FThreadProc <> nil then
  8193. Result := FThreadProc else
  8194. Result := 0
  8195. end;
  8196. { TBCNode }
  8197. {$ifdef DEBUG}
  8198. constructor TBCNode.Create;
  8199. begin
  8200. inherited Create('List node');
  8201. end;
  8202. {$ENDIF}
  8203. { TBCNodeCache }
  8204. procedure TBCNodeCache.AddToCache(Node: TBCNode);
  8205. begin
  8206. if (FUsed < FCacheSize) then
  8207. begin
  8208. Node.Next := FHead;
  8209. FHead := Node;
  8210. inc(FUsed);
  8211. end else
  8212. Node.Free;
  8213. end;
  8214. constructor TBCNodeCache.Create(CacheSize: Integer);
  8215. begin
  8216. FCacheSize := CacheSize;
  8217. FHead := nil;
  8218. FUsed := 0;
  8219. end;
  8220. destructor TBCNodeCache.Destroy;
  8221. var Node, Current: TBCNode;
  8222. begin
  8223. Node := FHead;
  8224. while (Node <> nil) do
  8225. begin
  8226. Current := Node;
  8227. Node := Node.Next;
  8228. Current.Free;
  8229. end;
  8230. inherited;
  8231. end;
  8232. function TBCNodeCache.RemoveFromCache: TBCNode;
  8233. var Node: TBCNode;
  8234. begin
  8235. Node := FHead;
  8236. if (Node <> nil) then
  8237. begin
  8238. FHead := Node.Next;
  8239. Dec(FUsed);
  8240. ASSERT(FUsed >= 0);
  8241. end else
  8242. ASSERT(FUsed = 0);
  8243. Result := Node;
  8244. end;
  8245. { TBCBaseList }
  8246. function TBCBaseList.AddAfter(p: Position; List: TBCBaseList): BOOL;
  8247. var pos: Position;
  8248. begin
  8249. pos := list.GetHeadPositionI;
  8250. while(pos <> nil) do
  8251. begin
  8252. // p follows along the elements being added
  8253. p := AddAfterI(p, List.GetI(pos));
  8254. if (p = nil) then
  8255. begin
  8256. Result := FALSE;
  8257. Exit;
  8258. end;
  8259. pos := list.Next(pos);
  8260. end;
  8261. Result := True;
  8262. end;
  8263. (* Add the object after position p
  8264. p is still valid after the operation.
  8265. AddAfter(NULL,x) adds x to the start - same as AddHead
  8266. Return the position of the new object, NULL if it failed
  8267. *)
  8268. function TBCBaseList.AddAfterI(pos: Position; Obj: Pointer): Position;
  8269. var After, Node, Before: TBCNode;
  8270. begin
  8271. if (pos = nil) then
  8272. Result := AddHeadI(Obj) else
  8273. begin
  8274. (* As someone else might be furkling with the list -
  8275. Lock the critical section before continuing
  8276. *)
  8277. After := pos;
  8278. ASSERT(After <> nil);
  8279. if (After = FLast) then
  8280. Result := AddTailI(Obj) else
  8281. begin
  8282. // set pnode to point to a new node, preferably from the cache
  8283. Node := FCache.RemoveFromCache;
  8284. if (Node = nil) then
  8285. Node := TBCNode.Create;
  8286. // Check we have a valid object
  8287. if (Node = nil) then
  8288. Result := nil else
  8289. begin
  8290. (* Initialise all the CNode object
  8291. just in case it came from the cache
  8292. *)
  8293. Node.Data := Obj;
  8294. (* It is to be added to the middle of the list - there is a before
  8295. and after node. Chain it after pAfter, before pBefore.
  8296. *)
  8297. Before := After.Next;
  8298. ASSERT(Before <> nil);
  8299. // chain it in (set four pointers)
  8300. Node.Prev := After;
  8301. Node.Next := Before;
  8302. Before.Prev := Node;
  8303. After.Next := Node;
  8304. inc(FCount);
  8305. Result := Node;
  8306. end;
  8307. end;
  8308. end;
  8309. end;
  8310. function TBCBaseList.AddBefore(p: Position; List: TBCBaseList): BOOL;
  8311. var pos: Position;
  8312. begin
  8313. pos := List.GetTailPositionI;
  8314. while (pos <> nil) do
  8315. begin
  8316. // p follows along the elements being added
  8317. p := AddBeforeI(p, List.GetI(pos));
  8318. if (p = nil) then
  8319. begin
  8320. Result := FALSE;
  8321. Exit;
  8322. end;
  8323. pos := list.Prev(pos);
  8324. end;
  8325. Result := True;
  8326. end;
  8327. (* Mirror images:
  8328. Add the element or list after position p.
  8329. p is still valid after the operation.
  8330. AddBefore(NULL,x) adds x to the end - same as AddTail
  8331. *)
  8332. function TBCBaseList.AddBeforeI(pos: Position; Obj: Pointer): Position;
  8333. var
  8334. Before, Node, After: TBCNode;
  8335. begin
  8336. if (pos = nil) then
  8337. Result := AddTailI(Obj) else
  8338. begin
  8339. // set pnode to point to a new node, preferably from the cache
  8340. Before := pos;
  8341. ASSERT(Before <> nil);
  8342. if (Before = FFirst) then
  8343. Result := AddHeadI(Obj) else
  8344. begin
  8345. Node := FCache.RemoveFromCache;
  8346. if (Node = nil) then
  8347. Node := TBCNode.Create;
  8348. // Check we have a valid object */
  8349. if (Node = nil) then
  8350. Result := nil else
  8351. begin
  8352. (* Initialise all the CNode object
  8353. just in case it came from the cache
  8354. *)
  8355. Node.Data := Obj;
  8356. (* It is to be added to the middle of the list - there is a before
  8357. and after node. Chain it after pAfter, before pBefore.
  8358. *)
  8359. After := Before.Prev;
  8360. ASSERT(After <> nil);
  8361. // chain it in (set four pointers)
  8362. Node.Prev := After;
  8363. Node.Next := Before;
  8364. Before.Prev := Node;
  8365. After.Next := Node;
  8366. inc(FCount);
  8367. Result := Node;
  8368. end;
  8369. end;
  8370. end;
  8371. end;
  8372. (* Add all the elements in *pList to the head of this list.
  8373. Return True if it all worked, FALSE if it didn't.
  8374. If it fails some elements may have been added.
  8375. *)
  8376. function TBCBaseList.AddHead(List: TBCBaseList): BOOL;
  8377. var
  8378. pos: Position;
  8379. begin
  8380. (* lock the object before starting then enumerate
  8381. each entry in the source list and add them one by one to
  8382. our list (while still holding the object lock)
  8383. Lock the other list too.
  8384. To avoid reversing the list, traverse it backwards.
  8385. *)
  8386. pos := list.GetTailPositionI;
  8387. while (pos <> nil) do
  8388. begin
  8389. if (nil = AddHeadI(List.GetI(pos))) then
  8390. begin
  8391. Result := FALSE;
  8392. Exit;
  8393. end;
  8394. pos := list.Prev(pos)
  8395. end;
  8396. Result := True;
  8397. end;
  8398. (* Add this object to the head end of our list
  8399. Return the new head position.
  8400. *)
  8401. function TBCBaseList.AddHeadI(Obj: Pointer): Position;
  8402. var Node: TBCNode;
  8403. begin
  8404. (* If there is a node objects in the cache then use
  8405. that otherwise we will have to create a new one *)
  8406. Node := FCache.RemoveFromCache;
  8407. if (Node = nil) then
  8408. Node := TBCNode.Create;
  8409. // Check we have a valid object
  8410. if (Node = nil) then
  8411. begin
  8412. Result := nil;
  8413. Exit;
  8414. end;
  8415. (* Initialise all the CNode object
  8416. just in case it came from the cache
  8417. *)
  8418. Node.Data := Obj;
  8419. // chain it in (set four pointers)
  8420. Node.Prev := nil;
  8421. Node.Next := FFirst;
  8422. if (FFirst = nil) then
  8423. FLast := Node;
  8424. FFirst.Prev := Node;
  8425. FFirst := Node;
  8426. inc(FCount);
  8427. Result := Node;
  8428. end;
  8429. (* Add all the elements in *pList to the tail of this list.
  8430. Return True if it all worked, FALSE if it didn't.
  8431. If it fails some elements may have been added.
  8432. *)
  8433. function TBCBaseList.AddTail(List: TBCBaseList): boolean;
  8434. var pos: Position;
  8435. begin
  8436. (* lock the object before starting then enumerate
  8437. each entry in the source list and add them one by one to
  8438. our list (while still holding the object lock)
  8439. Lock the other list too.
  8440. *)
  8441. Result := false;
  8442. pos := List.GetHeadPositionI;
  8443. while (pos <> nil) do
  8444. if (nil = AddTailI(List.GetNextI(pos))) then
  8445. Exit;
  8446. Result := True;
  8447. end;
  8448. (* Add this object to the tail end of our list
  8449. Return the new tail position.
  8450. *)
  8451. function TBCBaseList.AddTailI(Obj: Pointer): Position;
  8452. var
  8453. Node: TBCNode;
  8454. begin
  8455. // Lock the critical section before continuing
  8456. // ASSERT(pObject); // NULL pointers in the list are allowed.
  8457. (* If there is a node objects in the cache then use
  8458. that otherwise we will have to create a new one *)
  8459. Node := FCache.RemoveFromCache;
  8460. if (Node = nil) then
  8461. Node := TBCNode.Create;
  8462. // Check we have a valid object
  8463. if Node = nil then // HG: out of memory ???
  8464. begin
  8465. Result := nil;
  8466. Exit;
  8467. end;
  8468. (* Initialise all the CNode object
  8469. just in case it came from the cache
  8470. *)
  8471. Node.Data := Obj;
  8472. Node.Next := nil;
  8473. Node.Prev := FLast;
  8474. if (FLast = nil) then
  8475. FFirst := Node;
  8476. FLast.Next := Node;
  8477. (* Set the new last node pointer and also increment the number
  8478. of list entries, the critical section is unlocked when we
  8479. exit the function
  8480. *)
  8481. FLast := Node;
  8482. inc(FCount);
  8483. Result := Node;
  8484. end;
  8485. (* Constructor calls a separate initialisation function that
  8486. creates a node cache, optionally creates a lock object
  8487. and optionally creates a signaling object.
  8488. By default we create a locking object, a DEFAULTCACHE sized
  8489. cache but no event object so the list cannot be used in calls
  8490. to WaitForSingleObject
  8491. *)
  8492. constructor TBCBaseList.Create(Name: string; Items: Integer = DEFAULTCACHE);
  8493. begin
  8494. {$ifdef DEBUG}
  8495. inherited Create(Name);
  8496. {$endif}
  8497. FFirst := nil;
  8498. FLast := nil;
  8499. FCount := 0;
  8500. FCache := TBCNodeCache.Create(Items);
  8501. end;
  8502. (* The destructor enumerates all the node objects in the list and
  8503. in the cache deleting each in turn. We do not do any processing
  8504. on the objects that the list holds (i.e. points to) so if they
  8505. represent interfaces for example the creator of the list should
  8506. ensure that each of them is released before deleting us
  8507. *)
  8508. destructor TBCBaseList.Destroy;
  8509. begin
  8510. RemoveAll;
  8511. FCache.Free;
  8512. inherited;
  8513. end;
  8514. (* Return the first position in the list which holds the given pointer.
  8515. Return NULL if it's not found.
  8516. *)
  8517. function TBCBaseList.FindI(Obj: Pointer): Position;
  8518. begin
  8519. Result := GetHeadPositionI;
  8520. while (Result <> nil) do
  8521. begin
  8522. if (GetI(Result) = Obj) then Exit;
  8523. Result := Next(Result);
  8524. end;
  8525. end;
  8526. (* Get the number of objects in the list,
  8527. Get the lock before accessing the count.
  8528. Locking may not be entirely necessary but it has the side effect
  8529. of making sure that all operations are complete before we get it.
  8530. So for example if a list is being added to this list then that
  8531. will have completed in full before we continue rather than seeing
  8532. an intermediate albeit valid state
  8533. *)
  8534. function TBCBaseList.GetCountI: Integer;
  8535. begin
  8536. Result := FCount;
  8537. end;
  8538. (* Return a position enumerator for the entire list.
  8539. A position enumerator is a pointer to a node object cast to a
  8540. transparent type so all we do is return the head/tail node
  8541. pointer in the list.
  8542. WARNING because the position is a pointer to a node there is
  8543. an implicit assumption for users a the list class that after
  8544. deleting an object from the list that any other position
  8545. enumerators that you have may be invalid (since the node
  8546. may be gone).
  8547. *)
  8548. function TBCBaseList.GetHeadPositionI: Position;
  8549. begin
  8550. result := Position(FFirst);
  8551. end;
  8552. (* Return the object at p.
  8553. Asking for the object at NULL ASSERTs then returns NULL
  8554. The object is NOT locked. The list is not being changed
  8555. in any way. If another thread is busy deleting the object
  8556. then locking would only result in a change from one bad
  8557. behaviour to another.
  8558. *)
  8559. function TBCBaseList.GetI(p: Position): Pointer;
  8560. begin
  8561. if (p = nil) then
  8562. Result := nil else
  8563. Result := TBCNode(p).Data;
  8564. end;
  8565. (* Return the object at rp, update rp to the next object from
  8566. the list or NULL if you have moved over the last object.
  8567. You may still call this function once we return NULL but
  8568. we will continue to return a NULL position value
  8569. *)
  8570. function TBCBaseList.GetNextI(var rp: Position): Pointer;
  8571. var
  8572. pn: TBCNode;
  8573. begin
  8574. // have we reached the end of the list
  8575. if (rp = nil) then
  8576. Result := nil else
  8577. begin
  8578. // Lock the object before continuing
  8579. // Copy the original position then step on
  8580. pn := rp;
  8581. ASSERT(pn <> nil);
  8582. rp := Position(pn.Next);
  8583. // Get the object at the original position from the list
  8584. Result := pn.Data;
  8585. end;
  8586. end;
  8587. function TBCBaseList.GetTailPositionI: Position;
  8588. begin
  8589. Result := Position(FLast);
  8590. end;
  8591. (* Mirror image of MoveToTail:
  8592. Split self before position p in self.
  8593. Retain in self the head portion of the original self
  8594. Add the tail portion to the start (i.e. head) of *pList
  8595. Return True if it all worked, FALSE if it didn't.
  8596. e.g.
  8597. foo->MoveToHead(foo->GetTailPosition(), bar);
  8598. moves one element from the tail of foo to the head of bar
  8599. foo->MoveToHead(NULL, bar);
  8600. is a no-op
  8601. foo->MoveToHead(foo->GetHeadPosition, bar);
  8602. concatenates foo onto the start of bar and empties foo.
  8603. *)
  8604. function TBCBaseList.MoveToHead(pos: Position; List: TBCBaseList): boolean;
  8605. var
  8606. p: TBCNode;
  8607. m: Integer;
  8608. begin
  8609. // See the comments on the algorithm in MoveToTail
  8610. if (pos = nil) then
  8611. Result := True else // no-op. Eliminates special cases later.
  8612. begin
  8613. // Make cMove the number of nodes to move
  8614. p := pos;
  8615. m := 0; // number of nodes to move
  8616. while(p <> nil) do
  8617. begin
  8618. p := p.Next;
  8619. inc(m);
  8620. end;
  8621. // Join the two chains together
  8622. if (List.FFirst <> nil) then
  8623. List.FFirst.Prev := FLast;
  8624. if (FLast <> nil) then
  8625. FLast.Next := List.FFirst;
  8626. // set first and last pointers
  8627. p := pos;
  8628. if (List.FLast = nil) then
  8629. List.FLast := FLast;
  8630. FLast := p.Prev;
  8631. if (FLast = nil) then
  8632. FFirst := nil;
  8633. List.FFirst := p;
  8634. // Break the chain after p to create the new pieces
  8635. if (FLast <> nil) then
  8636. FLast.Next := nil;
  8637. p.Prev := nil;
  8638. // Adjust the counts
  8639. dec(FCount, m);
  8640. inc(List.FCount, m);
  8641. Result := True;
  8642. end;
  8643. end;
  8644. (* Split self after position p in self
  8645. Retain as self the tail portion of the original self
  8646. Add the head portion to the tail end of *pList
  8647. Return True if it all worked, FALSE if it didn't.
  8648. e.g.
  8649. foo->MoveToTail(foo->GetHeadPosition(), bar);
  8650. moves one element from the head of foo to the tail of bar
  8651. foo->MoveToTail(NULL, bar);
  8652. is a no-op
  8653. foo->MoveToTail(foo->GetTailPosition, bar);
  8654. concatenates foo onto the end of bar and empties foo.
  8655. A better, except excessively long name might be
  8656. MoveElementsFromHeadThroughPositionToOtherTail
  8657. *)
  8658. function TBCBaseList.MoveToTail(pos: Position; List: TBCBaseList): boolean;
  8659. var
  8660. p: TBCNode;
  8661. m: Integer;
  8662. begin
  8663. (* Algorithm:
  8664. Note that the elements (including their order) in the concatenation
  8665. of *pList to the head of self is invariant.
  8666. 1. Count elements to be moved
  8667. 2. Join *pList onto the head of this to make one long chain
  8668. 3. Set first/Last pointers in self and *pList
  8669. 4. Break the chain at the new place
  8670. 5. Adjust counts
  8671. 6. Set/Reset any events
  8672. *)
  8673. if (pos = nil) then
  8674. Result := True else // no-op. Eliminates special cases later.
  8675. begin
  8676. // Make m the number of nodes to move
  8677. p := pos;
  8678. m := 0; // number of nodes to move
  8679. while(p <> nil) do
  8680. begin
  8681. p := p.Prev;
  8682. inc(m);
  8683. end;
  8684. // Join the two chains together
  8685. if (List.FLast <> nil) then
  8686. List.FLast.Next := FFirst;
  8687. if (FFirst <> nil) then
  8688. FFirst.Prev := List.FLast;
  8689. // set first and last pointers
  8690. p := pos;
  8691. if (List.FFirst = nil) then
  8692. List.FFirst := FFirst;
  8693. FFirst := p.Next;
  8694. if (FFirst = nil) then
  8695. FLast := nil;
  8696. List.FLast := p;
  8697. // Break the chain after p to create the new pieces
  8698. if (FFirst <> nil) then
  8699. FFirst.Prev := nil;
  8700. p.Next := nil;
  8701. // Adjust the counts
  8702. dec(FCount, m);
  8703. inc(List.FCount, m);
  8704. Result := True;
  8705. end;
  8706. end;
  8707. function TBCBaseList.Next(pos: Position): Position;
  8708. begin
  8709. if (pos = nil) then
  8710. Result := Position(FFirst) else
  8711. Result := Position(TBCNode(pos).Next);
  8712. end;
  8713. function TBCBaseList.Prev(pos: Position): Position;
  8714. begin
  8715. if (pos = nil) then
  8716. Result := Position(FLast) else
  8717. Result := Position(TBCNode(pos).Prev);
  8718. end;
  8719. (* Remove all the nodes from the list but don't do anything
  8720. with the objects that each node looks after (this is the
  8721. responsibility of the creator).
  8722. Aa a last act we reset the signalling event
  8723. (if available) to indicate to clients that the list
  8724. does not have any entries in it.
  8725. *)
  8726. procedure TBCBaseList.RemoveAll;
  8727. var pn, op: TBCNode;
  8728. begin
  8729. (* Free up all the CNode objects NOTE we don't bother putting the
  8730. deleted nodes into the cache as this method is only really called
  8731. in serious times of change such as when we are being deleted at
  8732. which point the cache will be deleted anyway *)
  8733. pn := FFirst;
  8734. while (pn <> nil) do
  8735. begin
  8736. op := pn;
  8737. pn := pn.Next;
  8738. op.Free;
  8739. end;
  8740. (* Reset the object count and the list pointers *)
  8741. FCount := 0;
  8742. FFirst := nil;
  8743. FLast := nil;
  8744. end;
  8745. (* Remove the first node in the list (deletes the pointer to its object
  8746. from the list, does not free the object itself).
  8747. Return the pointer to its object or NULL if empty
  8748. *)
  8749. function TBCBaseList.RemoveHeadI: Pointer;
  8750. begin
  8751. (* All we do is get the head position and ask for that to be deleted.
  8752. We could special case this since some of the code path checking
  8753. in Remove() is redundant as we know there is no previous
  8754. node for example but it seems to gain little over the
  8755. added complexity
  8756. *)
  8757. Result := RemoveI(FFirst);
  8758. end;
  8759. (* Remove the pointer to the object in this position from the list.
  8760. Deal with all the chain pointers
  8761. Return a pointer to the object removed from the list.
  8762. The node object that is freed as a result
  8763. of this operation is added to the node cache where
  8764. it can be used again.
  8765. Remove(NULL) is a harmless no-op - but probably is a wart.
  8766. *)
  8767. function TBCBaseList.RemoveI(pos: Position): Pointer;
  8768. var
  8769. Current, Node: TBCNode;
  8770. begin
  8771. (* Lock the critical section before continuing *)
  8772. if (pos = nil) then
  8773. Result := nil else
  8774. begin
  8775. Current := pos;
  8776. ASSERT(Current <> nil);
  8777. // Update the previous node
  8778. Node := Current.Prev;
  8779. if (Node = nil) then
  8780. FFirst := Current.Next else
  8781. Node.Next := Current.Next;
  8782. // Update the following node
  8783. Node := Current.Next;
  8784. if (Node = nil) then
  8785. FLast := Current.Prev else
  8786. Node.Prev := Current.Prev;
  8787. // Get the object this node was looking after */
  8788. Result := Current.Data;
  8789. // ASSERT(pObject != NULL); // NULL pointers in the list are allowed.
  8790. (* Try and add the node object to the cache -
  8791. a NULL return code from the cache means we ran out of room.
  8792. The cache size is fixed by a constructor argument when the
  8793. list is created and defaults to DEFAULTCACHE.
  8794. This means that the cache will have room for this many
  8795. node objects. So if you have a list of media samples
  8796. and you know there will never be more than five active at
  8797. any given time of them for example then override the default
  8798. constructor
  8799. *)
  8800. FCache.AddToCache(Current);
  8801. // If the list is empty then reset the list event
  8802. Dec(FCount);
  8803. ASSERT(FCount >= 0);
  8804. end;
  8805. end;
  8806. (* Remove the last node in the list (deletes the pointer to its object
  8807. from the list, does not free the object itself).
  8808. Return the pointer to its object or NULL if empty
  8809. *)
  8810. function TBCBaseList.RemoveTailI: Pointer;
  8811. begin
  8812. (* All we do is get the tail position and ask for that to be deleted.
  8813. We could special case this since some of the code path checking
  8814. in Remove() is redundant as we know there is no previous
  8815. node for example but it seems to gain little over the
  8816. added complexity
  8817. *)
  8818. Result := RemoveI(FLast);
  8819. end;
  8820. (* Reverse the order of the [pointers to] objects in slef *)
  8821. procedure TBCBaseList.Reverse;
  8822. var p, q: TBCNode;
  8823. begin
  8824. (* algorithm:
  8825. The obvious booby trap is that you flip pointers around and lose
  8826. addressability to the node that you are going to process next.
  8827. The easy way to avoid this is do do one chain at a time.
  8828. Run along the forward chain,
  8829. For each node, set the reverse pointer to the one ahead of us.
  8830. The reverse chain is now a copy of the old forward chain, including
  8831. the NULL termination.
  8832. Run along the reverse chain (i.e. old forward chain again)
  8833. For each node set the forward pointer of the node ahead to point back
  8834. to the one we're standing on.
  8835. The first node needs special treatment,
  8836. it's new forward pointer is NULL.
  8837. Finally set the First/Last pointers
  8838. *)
  8839. // Yes we COULD use a traverse, but it would look funny!
  8840. p := FFirst;
  8841. while (p <> nil) do
  8842. begin
  8843. q := p.Next;
  8844. p.Next := p.Prev;
  8845. p.Prev := q;
  8846. p := q;
  8847. end;
  8848. p := FFirst;
  8849. FFirst := FLast;
  8850. FLast := p;
  8851. end;
  8852. { TBCSource }
  8853. function TBCSource.AddPin(Stream: TBCSourceStream): HRESULT;
  8854. begin
  8855. FStateLock.Lock;
  8856. try
  8857. inc(FPins);
  8858. ReallocMem(FStreams, FPins * SizeOf(TBCSourceStream));
  8859. TStreamArray(FStreams)[FPins-1] := Stream;
  8860. Result := S_OK;
  8861. finally
  8862. FStateLock.UnLock;
  8863. end;
  8864. end;
  8865. // milenko start (delphi 5 doesn't IInterface - changed IInterface to IUnknown)
  8866. constructor TBCSource.Create(const Name: string; unk: IUnknown;
  8867. // milenko end
  8868. const clsid: TGUID; out hr: HRESULT);
  8869. begin
  8870. FStateLock := TBCCritSec.Create;
  8871. // nev: changed 02/17/04
  8872. inherited Create(Name, unk, FStateLock, clsid, hr);
  8873. FPins := 0;
  8874. FStreams := nil;
  8875. end;
  8876. // milenko start (delphi 5 doesn't IInterface - changed IInterface to IUnknown)
  8877. constructor TBCSource.Create(const Name: string; unk: IUnknown;
  8878. // milenko end
  8879. const clsid: TGUID);
  8880. begin
  8881. FStateLock := TBCCritSec.Create;
  8882. inherited Create(Name, unk, FStateLock, clsid);
  8883. FPins := 0;
  8884. FStreams := nil;
  8885. end;
  8886. destructor TBCSource.Destroy;
  8887. begin
  8888. // Free our pins and pin array
  8889. while (FPins <> 0) do
  8890. // deleting the pins causes them to be removed from the array...
  8891. TStreamArray(FStreams)[FPins - 1].Free;
  8892. if Assigned(FStreams) then FreeMem(FStreams);
  8893. ASSERT(FPins = 0);
  8894. inherited;
  8895. end;
  8896. // Set Pin to the IPin that has the id Id.
  8897. // or to nil if the Id cannot be matched.
  8898. function TBCSource.FindPin(Id: PWideChar; out Pin: IPin): HRESULT;
  8899. var
  8900. i : integer;
  8901. Code : integer;
  8902. begin
  8903. // The -1 undoes the +1 in QueryId and ensures that totally invalid
  8904. // strings (for which WstrToInt delivers 0) give a deliver a NULL pin.
  8905. // DCoder (1. Nov 2003)
  8906. // StrToInt throws EConvertError Exceptions if
  8907. // a Filter calls FindPin with a String instead of a Number in ID.
  8908. // To be sure, capture the Error Handling by using Val and call
  8909. // the inherited function if Val fails.
  8910. Val(Id,i,Code);
  8911. if Code = 0 then
  8912. begin
  8913. i := i - 1;
  8914. Pin := GetPin(i);
  8915. if (Pin <> nil) then
  8916. Result := NOERROR else
  8917. Result := VFW_E_NOT_FOUND;
  8918. end else Result := inherited FindPin(Id,Pin);
  8919. end;
  8920. // return the number of the pin with this IPin or -1 if none
  8921. function TBCSource.FindPinNumber(Pin: IPin): Integer;
  8922. begin
  8923. for Result := 0 to FPins - 1 do
  8924. if (IPin(TStreamArray(FStreams)[Result]) = Pin) then
  8925. Exit;
  8926. Result := -1;
  8927. end;
  8928. // Return a non-addref'd pointer to pin n
  8929. // needed by CBaseFilter
  8930. function TBCSource.GetPin(n: Integer): TBCBasePin;
  8931. begin
  8932. FStateLock.Lock;
  8933. try
  8934. // n must be in the range 0..m_iPins-1
  8935. // if m_iPins>n && n>=0 it follows that m_iPins>0
  8936. // which is what used to be checked (i.e. checking that we have a pin)
  8937. if ((n >= 0) and (n < FPins)) then
  8938. begin
  8939. ASSERT(TStreamArray(FStreams)[n] <> nil);
  8940. Result := TStreamArray(FStreams)[n];
  8941. end else
  8942. Result := nil;
  8943. finally
  8944. FStateLock.UnLock;
  8945. end;
  8946. end;
  8947. // Returns the number of pins this filter has
  8948. function TBCSource.GetPinCount: Integer;
  8949. begin
  8950. FStateLock.Lock;
  8951. try
  8952. Result := FPins;
  8953. finally
  8954. FStateLock.UnLock;
  8955. end;
  8956. end;
  8957. function TBCSource.RemovePin(Stream: TBCSourceStream): HRESULT;
  8958. var i, j: Integer;
  8959. begin
  8960. for i := 0 to FPins - 1 do
  8961. begin
  8962. if (TStreamArray(FStreams)[i] = Stream) then
  8963. begin
  8964. if (FPins = 1) then
  8965. begin
  8966. FreeMem(FStreams);
  8967. FStreams := nil;
  8968. end else
  8969. begin
  8970. // no need to reallocate
  8971. j := i + 1;
  8972. while (j < FPins) do
  8973. begin
  8974. TStreamArray(FStreams)[j-1] := TStreamArray(FStreams)[j];
  8975. inc(j);
  8976. end;
  8977. end;
  8978. dec(FPins);
  8979. Result := S_OK;
  8980. Exit;
  8981. end;
  8982. end;
  8983. Result := S_FALSE;
  8984. end;
  8985. { TBCSourceStream }
  8986. // The pin is active - start up the worker thread
  8987. function TBCSourceStream.Active: HRESULT;
  8988. begin
  8989. FFilter.FStateLock.Lock;
  8990. try
  8991. if (FFilter.IsActive) then
  8992. begin
  8993. Result := S_FALSE; // succeeded, but did not allocate resources (they already exist...)
  8994. Exit;
  8995. end;
  8996. // do nothing if not connected - its ok not to connect to
  8997. // all pins of a source filter
  8998. if not IsConnected then
  8999. begin
  9000. Result := NOERROR;
  9001. Exit;
  9002. end;
  9003. Result := inherited Active;
  9004. if FAILED(Result) then
  9005. Exit;
  9006. ASSERT(not FThread.ThreadExists);
  9007. // start the thread
  9008. if not FThread.Create_ then
  9009. begin
  9010. Result := E_FAIL;
  9011. Exit;
  9012. end;
  9013. // Tell thread to initialize. If OnThreadCreate Fails, so does this.
  9014. Result := Init;
  9015. if FAILED(Result) then
  9016. Exit;
  9017. Result := Pause;
  9018. finally
  9019. FFilter.FStateLock.UnLock;
  9020. end;
  9021. end;
  9022. // Do we support this type? Provides the default support for 1 type.
  9023. function TBCSourceStream.CheckMediaType(MediaType: PAMMediaType): HRESULT;
  9024. var mt: TAMMediaType;
  9025. pmt: PAMMediaType;
  9026. begin
  9027. FFilter.FStateLock.Lock;
  9028. try
  9029. pmt := @mt;
  9030. GetMediaType(pmt);
  9031. if TBCMediaType(pmt).Equal(MediaType) then
  9032. Result := NOERROR else
  9033. Result := E_FAIL;
  9034. finally
  9035. FFilter.FStateLock.UnLock;
  9036. end;
  9037. end;
  9038. function TBCSourceStream.CheckRequest(var com: TThreadCommand): boolean;
  9039. begin
  9040. Result := FThread.CheckRequest(@Com);
  9041. end;
  9042. // increments the number of pins present on the filter
  9043. constructor TBCSourceStream.Create(const ObjectName: string;
  9044. out hr: HRESULT; Filter: TBCSource; const Name: WideString);
  9045. begin
  9046. FThread := TBCAMThread.Create;
  9047. FThread.FThreadProc := ThreadProc;
  9048. inherited Create(ObjectName, Filter, Filter.FStateLock, hr, Name);
  9049. FFilter := Filter;
  9050. hr := FFilter.AddPin(Self);
  9051. end;
  9052. // Decrements the number of pins on this filter
  9053. destructor TBCSourceStream.Destroy;
  9054. begin
  9055. FFilter.RemovePin(Self);
  9056. inherited;
  9057. FThread.Free;
  9058. end;
  9059. // Grabs a buffer and calls the users processing function.
  9060. // Overridable, so that different delivery styles can be catered for.
  9061. function TBCSourceStream.DoBufferProcessingLoop: HRESULT;
  9062. var
  9063. com: TThreadCommand;
  9064. Sample: IMediaSample;
  9065. begin
  9066. OnThreadStartPlay;
  9067. repeat
  9068. begin
  9069. while not CheckRequest(com) do
  9070. begin
  9071. Result := GetDeliveryBuffer(Sample, nil, nil, 0);
  9072. if FAILED(result) then
  9073. begin
  9074. Sleep(1);
  9075. continue; // go round again. Perhaps the error will go away
  9076. // or the allocator is decommited & we will be asked to
  9077. // exit soon.
  9078. end;
  9079. // Virtual function user will override.
  9080. Result := FillBuffer(Sample);
  9081. if (Result = S_OK) then
  9082. begin
  9083. Result := Deliver(Sample);
  9084. Sample := nil;
  9085. // downstream filter returns S_FALSE if it wants us to
  9086. // stop or an error if it's reporting an error.
  9087. if (Result <> S_OK) then
  9088. begin
  9089. {$IFDEF DEBUG}
  9090. DbgLog(format('Deliver() returned %08x; stopping', [Result]));
  9091. {$ENDIF}
  9092. Result := S_OK;
  9093. Exit;
  9094. end;
  9095. end else
  9096. if (Result = S_FALSE) then
  9097. begin
  9098. // derived class wants us to stop pushing data
  9099. Sample := nil;
  9100. DeliverEndOfStream;
  9101. Result := S_OK;
  9102. Exit;
  9103. end else
  9104. begin
  9105. // derived class encountered an error
  9106. Sample := nil;
  9107. {$IFDEF DEBUG}
  9108. DbgLog(format('Error %08lX from FillBuffer!!!', [Result]));
  9109. {$ENDIF}
  9110. DeliverEndOfStream;
  9111. FFilter.NotifyEvent(EC_ERRORABORT, Result, 0);
  9112. Exit;
  9113. end;
  9114. // all paths release the sample
  9115. end;
  9116. // For all commands sent to us there must be a Reply call!
  9117. if ((com = CMD_RUN) or (com = CMD_PAUSE)) then
  9118. FThread.Reply(NOERROR) else
  9119. if (com <> CMD_STOP) then
  9120. begin
  9121. Fthread.Reply(DWORD(E_UNEXPECTED));
  9122. {$IFDEF DEBUG}
  9123. DbgLog('Unexpected command!!!');
  9124. {$ENDIF}
  9125. end
  9126. end until (com = CMD_STOP);
  9127. Result := S_FALSE;
  9128. end;
  9129. function TBCSourceStream.Exit_: HRESULT;
  9130. begin
  9131. Result := FThread.CallWorker(Ord(CMD_EXIT));
  9132. end;
  9133. function TBCSourceStream.GetMediaType(MediaType: PAMMediaType): HRESULT;
  9134. begin
  9135. Result := E_UNEXPECTED;
  9136. end;
  9137. function TBCSourceStream.GetMediaType(Position: integer;
  9138. out MediaType: PAMMediaType): HRESULT;
  9139. begin
  9140. // By default we support only one type
  9141. // Position indexes are 0-n
  9142. FFilter.FStateLock.Lock;
  9143. try
  9144. if (Position = 0) then
  9145. Result := GetMediaType(MediaType)
  9146. else
  9147. if (Position > 0) then
  9148. Result := VFW_S_NO_MORE_ITEMS else
  9149. Result := E_INVALIDARG;
  9150. finally
  9151. FFilter.FStateLock.UnLock;
  9152. end;
  9153. end;
  9154. function TBCSourceStream.GetRequest: TThreadCommand;
  9155. begin
  9156. Result := TThreadCommand(FThread.GetRequest);
  9157. end;
  9158. // Pin is inactive - shut down the worker thread
  9159. // Waits for the worker to exit before returning.
  9160. function TBCSourceStream.Inactive: HRESULT;
  9161. begin
  9162. FFilter.FStateLock.Lock;
  9163. try
  9164. // do nothing if not connected - its ok not to connect to
  9165. // all pins of a source filter
  9166. if not IsConnected then
  9167. begin
  9168. Result := NOERROR;
  9169. Exit;
  9170. end;
  9171. // !!! need to do this before trying to stop the thread, because
  9172. // we may be stuck waiting for our own allocator!!!
  9173. Result := inherited Inactive; // call this first to Decommit the allocator
  9174. if FAILED(Result) then
  9175. Exit;
  9176. if FThread.ThreadExists then
  9177. begin
  9178. Result := Stop;
  9179. if FAILED(Result) then
  9180. Exit;
  9181. Result := Exit_;
  9182. if FAILED(Result) then
  9183. Exit;
  9184. FThread.Close; // Wait for the thread to exit, then tidy up.
  9185. end;
  9186. Result := NOERROR;
  9187. finally
  9188. FFilter.FStateLock.UnLock;
  9189. end;
  9190. end;
  9191. function TBCSourceStream.Init: HRESULT;
  9192. begin
  9193. Result := FThread.CallWorker(Ord(CMD_INIT));
  9194. end;
  9195. function TBCSourceStream.OnThreadCreate: HRESULT;
  9196. begin
  9197. Result := NOERROR;
  9198. end;
  9199. function TBCSourceStream.OnThreadDestroy: HRESULT;
  9200. begin
  9201. Result := NOERROR;
  9202. end;
  9203. function TBCSourceStream.OnThreadStartPlay: HRESULT;
  9204. begin
  9205. Result := NOERROR;
  9206. end;
  9207. function TBCSourceStream.Pause: HRESULT;
  9208. begin
  9209. Result := FThread.CallWorker(Ord(CMD_PAUSE));
  9210. end;
  9211. // Set Id to point to a CoTaskMemAlloc'd
  9212. function TBCSourceStream.QueryId(out id: PWideChar): HRESULT;
  9213. var
  9214. i: Integer;
  9215. begin
  9216. // We give the pins id's which are 1,2,...
  9217. // FindPinNumber returns -1 for an invalid pin
  9218. i := 1 + FFilter.FindPinNumber(Self);
  9219. if (i < 1) then
  9220. Result := VFW_E_NOT_FOUND else
  9221. Result := AMGetWideString(IntToStr(i), id);
  9222. end;
  9223. function TBCSourceStream.Run: HRESULT;
  9224. begin
  9225. Result := FThread.CallWorker(Ord(CMD_RUN));
  9226. end;
  9227. function TBCSourceStream.Stop: HRESULT;
  9228. begin
  9229. Result := FThread.CallWorker(Ord(CMD_STOP));
  9230. end;
  9231. // When this returns the thread exits
  9232. // Return codes > 0 indicate an error occured
  9233. function TBCSourceStream.ThreadProc: DWORD;
  9234. var
  9235. com, cmd: TThreadCommand;
  9236. begin
  9237. repeat
  9238. com := GetRequest;
  9239. if (com <> CMD_INIT) then
  9240. begin
  9241. {$IFDEF DEBUG}
  9242. DbgLog(self, 'Thread expected init command');
  9243. {$ENDIF}
  9244. FThread.Reply(DWORD(E_UNEXPECTED));
  9245. end;
  9246. until (com = CMD_INIT);
  9247. {$IFDEF DEBUG}
  9248. DbgLog(self, 'Worker thread initializing');
  9249. {$ENDIF}
  9250. Result := OnThreadCreate; // perform set up tasks
  9251. if FAILED(Result) then
  9252. begin
  9253. {$IFDEF DEBUG}
  9254. DbgLog(Self, 'OnThreadCreate failed. Aborting thread.');
  9255. {$ENDIF}
  9256. OnThreadDestroy();
  9257. FThread.Reply(Result); // send failed return code from OnThreadCreate
  9258. Result := 1;
  9259. Exit;
  9260. end;
  9261. // Initialisation suceeded
  9262. FThread.Reply(NOERROR);
  9263. repeat
  9264. cmd := GetRequest;
  9265. // nev: changed 02/17/04
  9266. // "repeat..until false" ensures, that if cmd = CMD_RUN
  9267. // the next executing block will be CMD_PAUSE handler block.
  9268. // This corresponds to the original C "switch" functionality
  9269. repeat
  9270. case cmd of
  9271. CMD_EXIT, CMD_STOP:
  9272. begin
  9273. FThread.Reply(NOERROR);
  9274. Break;
  9275. end;
  9276. CMD_RUN:
  9277. begin
  9278. {$IFDEF DEBUG}
  9279. DbgLog(Self, 'CMD_RUN received before a CMD_PAUSE???');
  9280. {$ENDIF}
  9281. // !!! fall through???
  9282. cmd := CMD_PAUSE;
  9283. end;
  9284. CMD_PAUSE:
  9285. begin
  9286. FThread.Reply(NOERROR);
  9287. DoBufferProcessingLoop;
  9288. Break;
  9289. end;
  9290. else
  9291. {$IFDEF DEBUG}
  9292. DbgLog(self, format('Unknown command %d received!', [Integer(cmd)]));
  9293. {$ENDIF}
  9294. FThread.Reply(DWORD(E_NOTIMPL));
  9295. Break;
  9296. end;
  9297. until False;
  9298. until (cmd = CMD_EXIT);
  9299. Result := OnThreadDestroy; // tidy up.
  9300. if FAILED(Result) then
  9301. begin
  9302. {$IFDEF DEBUG}
  9303. DbgLog(self, 'OnThreadDestroy failed. Exiting thread.');
  9304. {$ENDIF}
  9305. Result := 1;
  9306. Exit;
  9307. end;
  9308. {$IFDEF DEBUG}
  9309. DbgLog(Self, 'worker thread exiting');
  9310. {$ENDIF}
  9311. Result := 0;
  9312. end;
  9313. function TimeKillSynchronousFlagAvailable: Boolean;
  9314. var
  9315. osverinfo: TOSVERSIONINFO;
  9316. begin
  9317. osverinfo.dwOSVersionInfoSize := sizeof(osverinfo);
  9318. if GetVersionEx(osverinfo) then
  9319. // Windows XP's major version is 5 and its' minor version is 1.
  9320. // timeSetEvent() started supporting the TIME_KILL_SYNCHRONOUS flag
  9321. // in Windows XP.
  9322. Result := (osverinfo.dwMajorVersion > 5) or
  9323. ((osverinfo.dwMajorVersion = 5) and (osverinfo.dwMinorVersion >= 1))
  9324. else
  9325. Result := False;
  9326. end;
  9327. function CompatibleTimeSetEvent(Delay, Resolution: UINT;
  9328. TimeProc: TFNTimeCallBack; User: DWORD; Event: UINT): MMResult;
  9329. // milenko start (replaced with global variables)
  9330. //const
  9331. //{$IFOPT J-}
  9332. //{$DEFINE ResetJ}
  9333. //{$J+}
  9334. //{$ENDIF}
  9335. // IsCheckedVersion: Bool = False;
  9336. // IsTimeKillSynchronousFlagAvailable: Bool = False;
  9337. //{$IFDEF ResetJ}
  9338. //{$J-}
  9339. //{$UNDEF ResetJ}
  9340. //{$ENDIF}
  9341. const
  9342. TIME_KILL_SYNCHRONOUS = $100;
  9343. // Milenko end
  9344. var
  9345. Event_: UINT;
  9346. begin
  9347. Event_ := Event;
  9348. // ??? TIME_KILL_SYNCHRONOUS flag is defined in MMSystem for XP:
  9349. // need to check that D7 unit for proper compilation flag
  9350. // Milenko start (no need for "ifdef xp" in delphi)
  9351. // {$IFDEF XP}
  9352. if not IsCheckedVersion then
  9353. begin
  9354. IsTimeKillSynchronousFlagAvailable := TimeKillSynchronousFlagAvailable;
  9355. IsCheckedVersion := true;
  9356. end;
  9357. if IsTimeKillSynchronousFlagAvailable then
  9358. Event_ := Event_ or TIME_KILL_SYNCHRONOUS;
  9359. // {$ENDIF}
  9360. // Milenko end
  9361. Result := timeSetEvent(Delay, Resolution, TimeProc, User, Event_);
  9362. end;
  9363. // ??? See Measure.h for Msr_??? definition
  9364. // milenko start (only needed with PERF)
  9365. {$IFDEF PERF}
  9366. type
  9367. TIncidentRec = packed record
  9368. Name: String[255];
  9369. end;
  9370. TIncidentLog = packed record
  9371. Id: Integer;
  9372. Time: TReferenceTime;
  9373. Data: Integer;
  9374. Note: String[10];
  9375. end;
  9376. var
  9377. Incidents: array of TIncidentRec;
  9378. IncidentsLog: array of TIncidentLog;
  9379. {$ENDIF}
  9380. // milenko end
  9381. function MSR_REGISTER(s: String): Integer;
  9382. // milenko start (only needed with PERF)
  9383. {$IFDEF PERF}
  9384. var
  9385. k: Integer;
  9386. {$ENDIF}
  9387. // milenko end
  9388. begin
  9389. // milenko start (only needed with PERF)
  9390. {$IFDEF PERF}
  9391. k := Length(Incidents) + 1;
  9392. SetLength(Incidents, k);
  9393. Incidents[k-1].Name := Copy(s, 0, 255);
  9394. Result := k-1;
  9395. {$ELSE}
  9396. Result := 0;
  9397. {$ENDIF}
  9398. // milenko end
  9399. end;
  9400. procedure MSR_START(Id_: Integer);
  9401. {$IFDEF PERF}
  9402. var
  9403. k: Integer;
  9404. {$ENDIF}
  9405. begin
  9406. {$IFDEF PERF}
  9407. Assert((Id_>=0) and (Id_<Length(Incidents)));
  9408. k := Length(IncidentsLog) + 1;
  9409. SetLength(IncidentsLog, k);
  9410. with IncidentsLog[k-1] do
  9411. begin
  9412. Id := Id_;
  9413. Time := timeGetTime;
  9414. Data := 0;
  9415. Note := Copy('START', 0, 10);
  9416. end;
  9417. {$ENDIF}
  9418. end;
  9419. procedure MSR_STOP(Id_: Integer);
  9420. {$IFDEF PERF}
  9421. var
  9422. k: Integer;
  9423. {$ENDIF}
  9424. begin
  9425. {$IFDEF PERF}
  9426. Assert((Id_>=0) and (Id_<Length(Incidents)));
  9427. k := Length(IncidentsLog) + 1;
  9428. SetLength(IncidentsLog, k);
  9429. with IncidentsLog[k-1] do
  9430. begin
  9431. Id := Id_;
  9432. Time := timeGetTime;
  9433. Data := 0;
  9434. Note := Copy('STOP', 0, 10);
  9435. end;
  9436. {$ENDIF}
  9437. end;
  9438. procedure MSR_INTEGER(Id_, i: Integer);
  9439. {$IFDEF PERF}
  9440. var
  9441. k: Integer;
  9442. {$ENDIF}
  9443. begin
  9444. {$IFDEF PERF}
  9445. Assert((Id_>=0) and (Id_<Length(Incidents)));
  9446. k := Length(IncidentsLog) + 1;
  9447. SetLength(IncidentsLog, k);
  9448. with IncidentsLog[k-1] do
  9449. begin
  9450. Id := Id_;
  9451. Time := timeGetTime;
  9452. Data := i;
  9453. Note := Copy('START', 0, 10);
  9454. end;
  9455. {$ENDIF}
  9456. end;
  9457. // #define DO_MOVING_AVG(avg,obs) (avg = (1024*obs + (AVGPERIOD-1)*avg)/AVGPERIOD)
  9458. procedure DO_MOVING_AVG(var avg, obs: Integer);
  9459. begin
  9460. avg := (1024 * obs + (AVGPERIOD - 1) * avg) div AVGPERIOD;
  9461. end;
  9462. // Helper function for clamping time differences
  9463. function TimeDiff(rt: TReferenceTime): Integer;
  9464. begin
  9465. if (rt < -(50 * UNITS)) then
  9466. Result := -(50 * UNITS)
  9467. else
  9468. if (rt > 50 * UNITS) then
  9469. Result := 50 * UNITS
  9470. else
  9471. Result := Integer(rt);
  9472. end;
  9473. // Implements the CBaseRenderer class
  9474. constructor TBCBaseRenderer.Create(RendererClass: TGUID; Name: PChar;
  9475. Unk: IUnknown; hr: HResult);
  9476. begin
  9477. FInterfaceLock := TBCCritSec.Create;
  9478. FRendererLock := TBCCritSec.Create;
  9479. FObjectCreationLock := TBCCritSec.Create;
  9480. inherited Create(Name, Unk, FInterfaceLock, RendererClass);
  9481. FCompleteEvent := TBCAMEvent.Create(True);
  9482. FRenderEvent := TBCAMEvent.Create(True);
  9483. FAbort := False;
  9484. FPosition := nil;
  9485. FThreadSignal := TBCAMEvent.Create(True);
  9486. FIsStreaming := False;
  9487. FIsEOS := False;
  9488. FIsEOSDelivered := False;
  9489. FMediaSample := nil;
  9490. FAdvisedCookie := 0;
  9491. FQSink := nil;
  9492. FInputPin := nil;
  9493. FRepaintStatus := True;
  9494. FSignalTime := 0;
  9495. FInReceive := False;
  9496. FEndOfStreamTimer := 0;
  9497. Ready;
  9498. {$IFDEF PERF}
  9499. FBaseStamp := MSR_REGISTER('BaseRenderer: sample time stamp');
  9500. FBaseRenderTime := MSR_REGISTER('BaseRenderer: draw time(msec)');
  9501. FBaseAccuracy := MSR_REGISTER('BaseRenderer: Accuracy(msec)');
  9502. {$ENDIF}
  9503. end;
  9504. // Delete the dynamically allocated IMediaPosition and IMediaSeeking helper
  9505. // object. The object is created when somebody queries us. These are standard
  9506. // control interfaces for seeking and setting start/stop positions and rates.
  9507. // We will probably also have made an input pin based on CRendererInputPin
  9508. // that has to be deleted, it's created when an enumerator calls our GetPin
  9509. destructor TBCBaseRenderer.Destroy;
  9510. begin
  9511. Assert(not FIsStreaming);
  9512. Assert(FEndOfStreamTimer = 0);
  9513. StopStreaming;
  9514. ClearPendingSample;
  9515. // Delete any IMediaPosition implementation
  9516. if Assigned(FPosition) then
  9517. FreeAndNil(FPosition);
  9518. // Delete any input pin created
  9519. if Assigned(FInputPin) then
  9520. FreeAndNil(FInputPin);
  9521. // Release any Quality sink
  9522. Assert(FQSink = nil);
  9523. // Release critical sections objects
  9524. // ??? will be deleted by the parent class destroy FreeAndNil(FInterfaceLock);
  9525. FreeAndNil(FRendererLock);
  9526. FreeAndNil(FObjectCreationLock);
  9527. FreeAndNil(FCompleteEvent);
  9528. FreeAndNil(FRenderEvent);
  9529. FreeAndNil(FThreadSignal);
  9530. inherited Destroy;
  9531. end;
  9532. // This returns the IMediaPosition and IMediaSeeking interfaces
  9533. function TBCBaseRenderer.GetMediaPositionInterface(IID: TGUID;
  9534. out Obj): HResult;
  9535. var
  9536. hr: HResult;
  9537. begin
  9538. FObjectCreationLock.Lock;
  9539. try
  9540. if Assigned(FPosition) then
  9541. begin
  9542. // Milenko start
  9543. // Result := FPosition.QueryInterface(IID, Obj);
  9544. Result := FPosition.NonDelegatingQueryInterface(IID, Obj);
  9545. // Milenko end
  9546. Exit;
  9547. end;
  9548. hr := NOERROR;
  9549. // Create implementation of this dynamically since sometimes we may
  9550. // never try and do a seek. The helper object implements a position
  9551. // control interface (IMediaPosition) which in fact simply takes the
  9552. // calls normally from the filter graph and passes them upstream
  9553. //hr := CreatePosPassThru(GetOwner, False, GetPin(0), FPosition);
  9554. FPosition := TBCRendererPosPassThru.Create('Renderer TBCPosPassThru',
  9555. Inherited GetOwner, hr, GetPin(0));
  9556. if (FPosition = nil) then
  9557. begin
  9558. Result := E_OUTOFMEMORY;
  9559. Exit;
  9560. end;
  9561. if (Failed(hr)) then
  9562. begin
  9563. FreeAndNil(FPosition);
  9564. Result := E_NOINTERFACE;
  9565. Exit;
  9566. end;
  9567. // milenko start (needed or the class will destroy itself. Disadvantage=Destructor is not called)
  9568. // Solution is to keep FPosition alive without adding a Reference Count to it. But how???
  9569. FPosition._AddRef;
  9570. // milenko end
  9571. Result := GetMediaPositionInterface(IID, Obj);
  9572. finally
  9573. FObjectCreationLock.UnLock;
  9574. end;
  9575. end;
  9576. // milenko start (workaround for destructor issue with FPosition)
  9577. function TBCBaseRenderer.JoinFilterGraph(pGraph: IFilterGraph;
  9578. pName: PWideChar): HRESULT;
  9579. begin
  9580. if (pGraph = nil) and (FPosition <> nil) then
  9581. begin
  9582. FPosition._Release;
  9583. Pointer(FPosition) := nil;
  9584. end;
  9585. Result := inherited JoinFilterGraph(pGraph,pName);
  9586. end;
  9587. // milenko end
  9588. // Overriden to say what interfaces we support and where
  9589. function TBCBaseRenderer.NonDelegatingQueryInterface(const IID: TGUID;
  9590. out Obj): HResult;
  9591. begin
  9592. // Milenko start (removed unnessacery code)
  9593. // Do we have this interface
  9594. if IsEqualGUID(IID, IID_IMediaPosition) or IsEqualGUID(IID, IID_IMediaSeeking)
  9595. then Result := GetMediaPositionInterface(IID,Obj)
  9596. else Result := inherited NonDelegatingQueryInterface(IID, Obj);
  9597. // Milenko end
  9598. end;
  9599. // This is called whenever we change states, we have a manual reset event that
  9600. // is signalled whenever we don't won't the source filter thread to wait in us
  9601. // (such as in a stopped state) and likewise is not signalled whenever it can
  9602. // wait (during paused and running) this function sets or resets the thread
  9603. // event. The event is used to stop source filter threads waiting in Receive
  9604. function TBCBaseRenderer.SourceThreadCanWait(CanWait: Boolean): HResult;
  9605. begin
  9606. if CanWait then
  9607. FThreadSignal.Reset
  9608. else
  9609. FThreadSignal.SetEv;
  9610. Result := NOERROR;
  9611. end;
  9612. {$IFDEF DEBUG}
  9613. // Dump the current renderer state to the debug terminal. The hardest part of
  9614. // the renderer is the window where we unlock everything to wait for a clock
  9615. // to signal it is time to draw or for the application to cancel everything
  9616. // by stopping the filter. If we get things wrong we can leave the thread in
  9617. // WaitForRenderTime with no way for it to ever get out and we will deadlock
  9618. procedure TBCBaseRenderer.DisplayRendererState;
  9619. var
  9620. bSignalled, bFlushing: Boolean;
  9621. CurrentTime, StartTime, EndTime, Offset, Wait: TReferenceTime;
  9622. function RT_in_Millisecs(rt: TReferenceTime): Int64;
  9623. begin
  9624. Result := rt div 10000;
  9625. end;
  9626. begin
  9627. DbgLog(Self, 'Timed out in WaitForRenderTime');
  9628. // No way should this be signalled at this point
  9629. bSignalled := FThreadSignal.Check;
  9630. DbgLog(Self, Format('Signal sanity check %d', [Byte(bSignalled)]));
  9631. // Now output the current renderer state variables
  9632. DbgLog(Self, Format('Filter state %d', [Ord(FState)]));
  9633. DbgLog(Self, Format('Abort flag %d', [Byte(FAbort)]));
  9634. DbgLog(Self, Format('Streaming flag %d', [Byte(FIsStreaming)]));
  9635. DbgLog(Self, Format('Clock advise link %d', [FAdvisedCookie]));
  9636. // DbgLog(Self, Format('Current media sample %x', [FMediaSample]));
  9637. DbgLog(Self, Format('EOS signalled %d', [Byte(FIsEOS)]));
  9638. DbgLog(Self, Format('EOS delivered %d', [Byte(FIsEOSDelivered)]));
  9639. DbgLog(Self, Format('Repaint status %d', [Byte(FRepaintStatus)]));
  9640. // Output the delayed end of stream timer information
  9641. DbgLog(Self, Format('End of stream timer %x', [FEndOfStreamTimer]));
  9642. // ??? convert reftime to str
  9643. // DbgLog((LOG_TIMING, 1, TEXT("Deliver time %s"),CDisp((LONGLONG)FSignalTime)));
  9644. DbgLog(Self, Format('Deliver time %d', [FSignalTime]));
  9645. // Should never timeout during a flushing state
  9646. bFlushing := FInputPin.IsFlushing;
  9647. DbgLog(Self, Format('Flushing sanity check %d', [Byte(bFlushing)]));
  9648. // Display the time we were told to start at
  9649. // ??? DbgLog((LOG_TIMING, 1, TEXT("Last run time %s"),CDisp((LONGLONG)m_tStart.m_time)));
  9650. DbgLog(Self, Format('Last run time %d', [FStart]));
  9651. // Have we got a reference clock
  9652. if (FClock = nil) then
  9653. Exit;
  9654. // Get the current time from the wall clock
  9655. FClock.GetTime(int64(CurrentTime));
  9656. Offset := CurrentTime - FStart;
  9657. // Display the current time from the clock
  9658. DbgLog(Self, Format('Clock time %d', [CurrentTime]));
  9659. DbgLog(Self, Format('Time difference %d ms', [RT_in_Millisecs(Offset)]));
  9660. // Do we have a sample ready to render
  9661. if (FMediaSample = nil) then
  9662. Exit;
  9663. FMediaSample.GetTime(StartTime, EndTime);
  9664. DbgLog(Self, Format('Next sample stream times (Start %d End %d ms)',
  9665. [RT_in_Millisecs(StartTime), RT_in_Millisecs(EndTime)]));
  9666. // Calculate how long it is until it is due for rendering
  9667. Wait := (FStart + StartTime) - CurrentTime;
  9668. DbgLog(Self, Format('Wait required %d ms', [RT_in_Millisecs(Wait)]));
  9669. end;
  9670. {$ENDIF}
  9671. // Wait until the clock sets the timer event or we're otherwise signalled. We
  9672. // set an arbitrary timeout for this wait and if it fires then we display the
  9673. // current renderer state on the debugger. It will often fire if the filter's
  9674. // left paused in an application however it may also fire during stress tests
  9675. // if the synchronisation with application seeks and state changes is faulty
  9676. const
  9677. RENDER_TIMEOUT = 10000;
  9678. function TBCBaseRenderer.WaitForRenderTime: HResult;
  9679. var
  9680. WaitObjects: array[0..1] of THandle;
  9681. begin
  9682. WaitObjects[0] := FThreadSignal.Handle;
  9683. WaitObjects[1] := FRenderEvent.Handle;
  9684. DWord(Result) := WAIT_TIMEOUT;
  9685. // Wait for either the time to arrive or for us to be stopped
  9686. OnWaitStart;
  9687. while (Result = WAIT_TIMEOUT) do
  9688. begin
  9689. Result := WaitForMultipleObjects(2, @WaitObjects, False, RENDER_TIMEOUT);
  9690. {$IFDEF DEBUG}
  9691. if (Result = WAIT_TIMEOUT) then
  9692. DisplayRendererState;
  9693. {$ENDIF}
  9694. end;
  9695. OnWaitEnd;
  9696. // We may have been awoken without the timer firing
  9697. if (Result = WAIT_OBJECT_0) then
  9698. begin
  9699. Result := VFW_E_STATE_CHANGED;
  9700. Exit;
  9701. end;
  9702. SignalTimerFired;
  9703. Result := NOERROR;
  9704. end;
  9705. // Poll waiting for Receive to complete. This really matters when
  9706. // Receive may set the palette and cause window messages
  9707. // The problem is that if we don't really wait for a renderer to
  9708. // stop processing we can deadlock waiting for a transform which
  9709. // is calling the renderer's Receive() method because the transform's
  9710. // Stop method doesn't know to process window messages to unblock
  9711. // the renderer's Receive processing
  9712. procedure TBCBaseRenderer.WaitForReceiveToComplete;
  9713. var
  9714. msg: TMsg;
  9715. begin
  9716. repeat
  9717. if Not FInReceive then
  9718. Break;
  9719. // Receive all interthread sendmessages
  9720. PeekMessage(msg, 0, WM_NULL, WM_NULL, PM_NOREMOVE);
  9721. Sleep(1);
  9722. until False;
  9723. // If the wakebit for QS_POSTMESSAGE is set, the PeekMessage call
  9724. // above just cleared the changebit which will cause some messaging
  9725. // calls to block (waitMessage, MsgWaitFor...) now.
  9726. // Post a dummy message to set the QS_POSTMESSAGE bit again
  9727. if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) and QS_POSTMESSAGE) <> 0 then
  9728. // Send dummy message
  9729. PostThreadMessage(GetCurrentThreadId, WM_NULL, 0, 0);
  9730. end;
  9731. // A filter can have four discrete states, namely Stopped, Running, Paused,
  9732. // Intermediate. We are in an intermediate state if we are currently trying
  9733. // to pause but haven't yet got the first sample (or if we have been flushed
  9734. // in paused state and therefore still have to wait for a sample to arrive)
  9735. // This class contains an event called FCompleteEvent which is signalled when
  9736. // the current state is completed and is not signalled when we are waiting to
  9737. // complete the last state transition. As mentioned above the only time we
  9738. // use this at the moment is when we wait for a media sample in paused state
  9739. // If while we are waiting we receive an end of stream notification from the
  9740. // source filter then we know no data is imminent so we can reset the event
  9741. // This means that when we transition to paused the source filter must call
  9742. // end of stream on us or send us an image otherwise we'll hang indefinately
  9743. // Simple internal way of getting the real state
  9744. // !!! make property here
  9745. function TBCBaseRenderer.GetRealState: TFilterState;
  9746. begin
  9747. Result := FState;
  9748. end;
  9749. // Waits for the HANDLE hObject. While waiting messages sent
  9750. // to windows on our thread by SendMessage will be processed.
  9751. // Using this function to do waits and mutual exclusion
  9752. // avoids some deadlocks in objects with windows.
  9753. // Return codes are the same as for WaitForSingleObject
  9754. function WaitDispatchingMessages(Object_: THandle; Wait: DWord;
  9755. Wnd: HWnd = 0; Msg: Cardinal = 0; Event: THandle = 0): DWord;
  9756. // milenko start (replaced with global variables)
  9757. //const
  9758. //{$IFOPT J-}
  9759. //{$DEFINE ResetJ}
  9760. //{$J+}
  9761. //{$ENDIF}
  9762. // MsgId: Cardinal = 0;
  9763. //{$IFDEF ResetJ}
  9764. //{$J-}
  9765. //{$UNDEF ResetJ}
  9766. //{$ENDIF}
  9767. // milenko end
  9768. var
  9769. Peeked: Boolean;
  9770. Res, Start, ThreadPriority: DWord;
  9771. Objects: array[0..1] of THandle;
  9772. Count, TimeOut, WakeMask, Now_, Diff: DWord;
  9773. Msg_: TMsg;
  9774. begin
  9775. Peeked := False;
  9776. MsgId := 0;
  9777. Start := 0;
  9778. ThreadPriority := THREAD_PRIORITY_NORMAL;
  9779. Objects[0] := Object_;
  9780. Objects[1] := Event;
  9781. if (Wait <> INFINITE) and (Wait <> 0) then
  9782. Start := GetTickCount;
  9783. repeat
  9784. if (Event <> 0) then
  9785. Count := 2
  9786. else
  9787. Count := 1;
  9788. // Minimize the chance of actually dispatching any messages
  9789. // by seeing if we can lock immediately.
  9790. Res := WaitForMultipleObjects(Count, @Objects, False, 0);
  9791. if (Res < WAIT_OBJECT_0 + Count) then
  9792. Break;
  9793. TimeOut := Wait;
  9794. if (TimeOut > 10) then
  9795. TimeOut := 10;
  9796. if (Wnd = 0) then
  9797. WakeMask := QS_SENDMESSAGE
  9798. else
  9799. WakeMask := QS_SENDMESSAGE + QS_POSTMESSAGE;
  9800. Res := MsgWaitForMultipleObjects(Count, Objects, False,
  9801. TimeOut, WakeMask);
  9802. if (Res = WAIT_OBJECT_0 + Count) or
  9803. ((Res = WAIT_TIMEOUT) and (TimeOut <> Wait)) then
  9804. begin
  9805. if (Wnd <> 0) then
  9806. while PeekMessage(Msg_, Wnd, Msg, Msg, PM_REMOVE) do
  9807. DispatchMessage(Msg_);
  9808. // Do this anyway - the previous peek doesn't flush out the
  9809. // messages
  9810. PeekMessage(Msg_, 0, 0, 0, PM_NOREMOVE);
  9811. if (Wait <> INFINITE) and (Wait <> 0) then
  9812. begin
  9813. Now_ := GetTickCount();
  9814. // Working with differences handles wrap-around
  9815. Diff := Now_ - Start;
  9816. if (Diff > Wait) then
  9817. Wait := 0
  9818. else
  9819. Dec(Wait, Diff);
  9820. Start := Now_;
  9821. end;
  9822. if not (Peeked) then
  9823. begin
  9824. // Raise our priority to prevent our message queue
  9825. // building up
  9826. ThreadPriority := GetThreadPriority(GetCurrentThread);
  9827. if (ThreadPriority < THREAD_PRIORITY_HIGHEST) then
  9828. begin
  9829. // ??? raising priority requires one more routine....
  9830. SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_HIGHEST);
  9831. end;
  9832. Peeked := True;
  9833. end;
  9834. end
  9835. else
  9836. Break;
  9837. until False;
  9838. if (Peeked) then
  9839. begin
  9840. // ??? setting priority requires one more routine....
  9841. SetThreadPriority(GetCurrentThread, ThreadPriority);
  9842. // milenko start (important!)
  9843. // if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) and QS_POSTMESSAGE) = 0 then
  9844. if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) and QS_POSTMESSAGE) > 0 then
  9845. // milenko end
  9846. begin
  9847. if (MsgId = 0) then
  9848. MsgId := RegisterWindowMessage('AMUnblock')
  9849. else
  9850. // Remove old ones
  9851. while (PeekMessage(Msg_, (Wnd) - 1, MsgId, MsgId, PM_REMOVE)) do
  9852. // milenko start (this is a loop without any further function.
  9853. // it does not call PostThreadMEssage while looping!)
  9854. begin
  9855. end;
  9856. // milenko end
  9857. PostThreadMessage(GetCurrentThreadId, MsgId, 0, 0);
  9858. end;
  9859. end;
  9860. Result := Res;
  9861. end;
  9862. // The renderer doesn't complete the full transition to paused states until
  9863. // it has got one media sample to render. If you ask it for its state while
  9864. // it's waiting it will return the state along with VFW_S_STATE_INTERMEDIATE
  9865. function TBCBaseRenderer.GetState(MSecs: DWord; out State: TFilterState):
  9866. HResult;
  9867. begin
  9868. if (WaitDispatchingMessages(FCompleteEvent.Handle, MSecs) = WAIT_TIMEOUT) then
  9869. Result := VFW_S_STATE_INTERMEDIATE
  9870. else
  9871. Result := NOERROR;
  9872. State := FState;
  9873. end;
  9874. // If we're pausing and we have no samples we don't complete the transition
  9875. // to State_Paused and we return S_FALSE. However if the FAborting flag has
  9876. // been set then all samples are rejected so there is no point waiting for
  9877. // one. If we do have a sample then return NOERROR. We will only ever return
  9878. // VFW_S_STATE_INTERMEDIATE from GetState after being paused with no sample
  9879. // (calling GetState after either being stopped or Run will NOT return this)
  9880. function TBCBaseRenderer.CompleteStateChange(OldState: TFilterState): HResult;
  9881. begin
  9882. // Allow us to be paused when disconnected
  9883. if not (FInputPin.IsConnected) or
  9884. // Have we run off the end of stream
  9885. IsEndOfStream or
  9886. // Make sure we get fresh data after being stopped
  9887. (HaveCurrentSample and (OldState <> State_Stopped)) then
  9888. begin
  9889. Ready;
  9890. Result := S_OK;
  9891. Exit;
  9892. end;
  9893. NotReady;
  9894. Result := S_False;
  9895. end;
  9896. procedure TBCBaseRenderer.SetAbortSignal(Abort_: Boolean);
  9897. begin
  9898. FAbort := Abort_;
  9899. end;
  9900. procedure TBCBaseRenderer.OnReceiveFirstSample(MediaSample: IMediaSample);
  9901. begin
  9902. end;
  9903. procedure TBCBaseRenderer.Ready;
  9904. begin
  9905. FCompleteEvent.SetEv
  9906. end;
  9907. procedure TBCBaseRenderer.NotReady;
  9908. begin
  9909. FCompleteEvent.Reset
  9910. end;
  9911. function TBCBaseRenderer.CheckReady: Boolean;
  9912. begin
  9913. Result := FCompleteEvent.Check
  9914. end;
  9915. // When we stop the filter the things we do are:-
  9916. // Decommit the allocator being used in the connection
  9917. // Release the source filter if it's waiting in Receive
  9918. // Cancel any advise link we set up with the clock
  9919. // Any end of stream signalled is now obsolete so reset
  9920. // Allow us to be stopped when we are not connected
  9921. function TBCBaseRenderer.Stop: HResult;
  9922. begin
  9923. FInterfaceLock.Lock;
  9924. try
  9925. // Make sure there really is a state change
  9926. if (FState = State_Stopped) then
  9927. begin
  9928. Result := NOERROR;
  9929. Exit;
  9930. end;
  9931. // Is our input pin connected
  9932. if not (FInputPin.IsConnected) then
  9933. begin
  9934. {$IFDEF DEBUG}
  9935. DbgLog(Self, 'Input pin is not connected');
  9936. {$ENDIF}
  9937. FState := State_Stopped;
  9938. Result := NOERROR;
  9939. Exit;
  9940. end;
  9941. inherited Stop;
  9942. // If we are going into a stopped state then we must decommit whatever
  9943. // allocator we are using it so that any source filter waiting in the
  9944. // GetBuffer can be released and unlock themselves for a state change
  9945. if Assigned(FInputPin.FAllocator) then
  9946. FInputPin.FAllocator.Decommit;
  9947. // Cancel any scheduled rendering
  9948. SetRepaintStatus(True);
  9949. StopStreaming;
  9950. SourceThreadCanWait(False);
  9951. ResetEndOfStream;
  9952. CancelNotification;
  9953. // There should be no outstanding clock advise
  9954. Assert(CancelNotification = S_FALSE);
  9955. Assert(WAIT_TIMEOUT = WaitForSingleObject(FRenderEvent.Handle, 0));
  9956. Assert(FEndOfStreamTimer = 0);
  9957. Ready;
  9958. WaitForReceiveToComplete;
  9959. FAbort := False;
  9960. Result := NOERROR;
  9961. finally
  9962. FInterfaceLock.UnLock;
  9963. end;
  9964. end;
  9965. // When we pause the filter the things we do are:-
  9966. // Commit the allocator being used in the connection
  9967. // Allow a source filter thread to wait in Receive
  9968. // Cancel any clock advise link (we may be running)
  9969. // Possibly complete the state change if we have data
  9970. // Allow us to be paused when we are not connected
  9971. function TBCBaseRenderer.Pause: HResult;
  9972. var
  9973. OldState: TFilterState;
  9974. hr: HResult;
  9975. begin
  9976. FInterfaceLock.Lock;
  9977. try
  9978. OldState := FState;
  9979. Assert(not FInputPin.IsFlushing);
  9980. // Make sure there really is a state change
  9981. if (FState = State_Paused) then
  9982. begin
  9983. Result := CompleteStateChange(State_Paused);
  9984. Exit;
  9985. end;
  9986. // Has our input pin been connected
  9987. if Not FInputPin.IsConnected then
  9988. begin
  9989. {$IFDEF DEBUG}
  9990. DbgLog(Self, 'Input pin is not connected');
  9991. {$ENDIF}
  9992. FState := State_Paused;
  9993. Result := CompleteStateChange(State_Paused);
  9994. Exit;
  9995. end;
  9996. // Pause the base filter class
  9997. hr := inherited Pause;
  9998. if Failed(hr) then
  9999. begin
  10000. {$IFDEF DEBUG}
  10001. DbgLog(Self, 'Pause failed');
  10002. {$ENDIF}
  10003. Result := hr;
  10004. Exit;
  10005. end;
  10006. // Enable EC_REPAINT events again
  10007. SetRepaintStatus(True);
  10008. StopStreaming;
  10009. SourceThreadCanWait(True);
  10010. CancelNotification;
  10011. ResetEndOfStreamTimer;
  10012. // If we are going into a paused state then we must commit whatever
  10013. // allocator we are using it so that any source filter can call the
  10014. // GetBuffer and expect to get a buffer without returning an error
  10015. if Assigned(FInputPin.FAllocator) then
  10016. FInputPin.FAllocator.Commit;
  10017. // There should be no outstanding advise
  10018. Assert(CancelNotification = S_FALSE);
  10019. Assert(WAIT_TIMEOUT = WaitForSingleObject(FRenderEvent.Handle, 0));
  10020. Assert(FEndOfStreamTimer = 0);
  10021. Assert(not FInputPin.IsFlushing);
  10022. // When we come out of a stopped state we must clear any image we were
  10023. // holding onto for frame refreshing. Since renderers see state changes
  10024. // first we can reset ourselves ready to accept the source thread data
  10025. // Paused or running after being stopped causes the current position to
  10026. // be reset so we're not interested in passing end of stream signals
  10027. if (OldState = State_Stopped) then
  10028. begin
  10029. FAbort := False;
  10030. ClearPendingSample;
  10031. end;
  10032. Result := CompleteStateChange(OldState);
  10033. finally
  10034. FInterfaceLock.Unlock;
  10035. end;
  10036. end;
  10037. // When we run the filter the things we do are:-
  10038. // Commit the allocator being used in the connection
  10039. // Allow a source filter thread to wait in Receive
  10040. // Signal the render event just to get us going
  10041. // Start the base class by calling StartStreaming
  10042. // Allow us to be run when we are not connected
  10043. // Signal EC_COMPLETE if we are not connected
  10044. function TBCBaseRenderer.Run(StartTime: TReferenceTime): HResult;
  10045. var
  10046. OldState: TFilterState;
  10047. hr: HResult;
  10048. // milenko start
  10049. Filter: IBaseFilter;
  10050. // milenko end
  10051. begin
  10052. FInterfaceLock.Lock;
  10053. try
  10054. OldState := FState;
  10055. // Make sure there really is a state change
  10056. if (FState = State_Running) then
  10057. begin
  10058. Result := NOERROR;
  10059. Exit;
  10060. end;
  10061. // Send EC_COMPLETE if we're not connected
  10062. if not FInputPin.IsConnected then
  10063. begin
  10064. // milenko start (Delphi 5 compatibility)
  10065. QueryInterface(IID_IBaseFilter,Filter);
  10066. NotifyEvent(EC_COMPLETE, S_OK, Integer(Filter));
  10067. Filter := nil;
  10068. // milenko end
  10069. FState := State_Running;
  10070. Result := NOERROR;
  10071. Exit;
  10072. end;
  10073. Ready;
  10074. // Pause the base filter class
  10075. hr := inherited Run(StartTime);
  10076. if Failed(hr) then
  10077. begin
  10078. {$IFDEF DEBUG}
  10079. DbgLog(Self, 'Run failed');
  10080. {$ENDIF}
  10081. Result := hr;
  10082. Exit;
  10083. end;
  10084. // Allow the source thread to wait
  10085. Assert(not FInputPin.IsFlushing);
  10086. SourceThreadCanWait(True);
  10087. SetRepaintStatus(False);
  10088. // There should be no outstanding advise
  10089. Assert(CancelNotification = S_FALSE);
  10090. Assert(WAIT_TIMEOUT = WaitForSingleObject(FRenderEvent.Handle, 0));
  10091. Assert(FEndOfStreamTimer = 0);
  10092. Assert(not FInputPin.IsFlushing);
  10093. // If we are going into a running state then we must commit whatever
  10094. // allocator we are using it so that any source filter can call the
  10095. // GetBuffer and expect to get a buffer without returning an error
  10096. if Assigned(FInputPin.FAllocator) then
  10097. FInputPin.FAllocator.Commit;
  10098. // When we come out of a stopped state we must clear any image we were
  10099. // holding onto for frame refreshing. Since renderers see state changes
  10100. // first we can reset ourselves ready to accept the source thread data
  10101. // Paused or running after being stopped causes the current position to
  10102. // be reset so we're not interested in passing end of stream signals
  10103. if (OldState = State_Stopped) then
  10104. begin
  10105. FAbort := False;
  10106. ClearPendingSample;
  10107. end;
  10108. Result := StartStreaming;
  10109. finally
  10110. FInterfaceLock.Unlock;
  10111. end;
  10112. end;
  10113. // Return the number of input pins we support
  10114. function TBCBaseRenderer.GetPinCount: Integer;
  10115. begin
  10116. Result := 1;
  10117. end;
  10118. // We only support one input pin and it is numbered zero
  10119. function TBCBaseRenderer.GetPin(n: integer): TBCBasePin;
  10120. var
  10121. hr: HResult;
  10122. begin
  10123. FObjectCreationLock.Lock;
  10124. try
  10125. // Should only ever be called with zero
  10126. Assert(n = 0);
  10127. if (n <> 0) then
  10128. begin
  10129. Result := nil;
  10130. Exit;
  10131. end;
  10132. // Create the input pin if not already done so
  10133. if (FInputPin = nil) then
  10134. begin
  10135. // hr must be initialized to NOERROR because
  10136. // CRendererInputPin's constructor only changes
  10137. // hr's value if an error occurs.
  10138. hr := NOERROR;
  10139. FInputPin := TBCRendererInputPin.Create(Self, hr, 'In');
  10140. if (FInputPin = nil) then
  10141. begin
  10142. Result := nil;
  10143. Exit;
  10144. end;
  10145. if Failed(hr) then
  10146. begin
  10147. FreeAndNil(FInputPin);
  10148. Result := nil;
  10149. Exit;
  10150. end;
  10151. end;
  10152. Result := FInputPin;
  10153. finally
  10154. FObjectCreationLock.UnLock;
  10155. end;
  10156. end;
  10157. function DumbItDownFor95(const S1, S2: WideString; CmpFlags: Integer): Integer;
  10158. var
  10159. a1, a2: AnsiString;
  10160. begin
  10161. a1 := s1;
  10162. a2 := s2;
  10163. Result := CompareStringA(LOCALE_USER_DEFAULT, CmpFlags, PChar(a1), Length(a1),
  10164. PChar(a2), Length(a2)) - 2;
  10165. end;
  10166. function WideCompareText(const S1, S2: WideString): Integer;
  10167. begin
  10168. SetLastError(0);
  10169. Result := CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, PWideChar(S1),
  10170. Length(S1), PWideChar(S2), Length(S2)) - 2;
  10171. case GetLastError of
  10172. 0: ;
  10173. ERROR_CALL_NOT_IMPLEMENTED: Result := DumbItDownFor95(S1, S2, NORM_IGNORECASE);
  10174. end;
  10175. end;
  10176. // If "In" then return the IPin for our input pin, otherwise NULL and error
  10177. function TBCBaseRenderer.FindPin(id: PWideChar; out Pin: IPin): HResult;
  10178. begin
  10179. // Milenko start
  10180. if (@Pin = nil) then
  10181. begin
  10182. Result := E_POINTER;
  10183. Exit;
  10184. end;
  10185. // Milenko end
  10186. // milenko start (delphi 5 doesn't know WideCompareText)
  10187. if WideCompareText(id, 'In') = 0 then
  10188. // milenko end
  10189. begin
  10190. Pin := GetPin(0);
  10191. Assert(Pin <> nil);
  10192. // ??? Pin.AddRef;
  10193. Result := NOERROR;
  10194. end
  10195. else
  10196. begin
  10197. Pin := nil;
  10198. Result := VFW_E_NOT_FOUND;
  10199. end;
  10200. end;
  10201. // Called when the input pin receives an EndOfStream notification. If we have
  10202. // not got a sample, then notify EC_COMPLETE now. If we have samples, then set
  10203. // m_bEOS and check for this on completing samples. If we're waiting to pause
  10204. // then complete the transition to paused state by setting the state event
  10205. function TBCBaseRenderer.EndOfStream: HResult;
  10206. begin
  10207. // Ignore these calls if we are stopped
  10208. if (FState = State_Stopped) then
  10209. begin
  10210. Result := NOERROR;
  10211. Exit;
  10212. end;
  10213. // If we have a sample then wait for it to be rendered
  10214. FIsEOS := True;
  10215. if Assigned(FMediaSample) then
  10216. begin
  10217. Result := NOERROR;
  10218. Exit;
  10219. end;
  10220. // If we are waiting for pause then we are now ready since we cannot now
  10221. // carry on waiting for a sample to arrive since we are being told there
  10222. // won't be any. This sets an event that the GetState function picks up
  10223. Ready;
  10224. // Only signal completion now if we are running otherwise queue it until
  10225. // we do run in StartStreaming. This is used when we seek because a seek
  10226. // causes a pause where early notification of completion is misleading
  10227. if FIsStreaming then
  10228. SendEndOfStream;
  10229. Result := NOERROR;
  10230. end;
  10231. // When we are told to flush we should release the source thread
  10232. function TBCBaseRenderer.BeginFlush: HResult;
  10233. begin
  10234. // If paused then report state intermediate until we get some data
  10235. if (FState = State_Paused) then
  10236. NotReady;
  10237. SourceThreadCanWait(False);
  10238. CancelNotification;
  10239. ClearPendingSample;
  10240. // Wait for Receive to complete
  10241. WaitForReceiveToComplete;
  10242. Result := NOERROR;
  10243. end;
  10244. // After flushing the source thread can wait in Receive again
  10245. function TBCBaseRenderer.EndFlush: HResult;
  10246. begin
  10247. // Reset the current sample media time
  10248. if Assigned(FPosition) then
  10249. FPosition.ResetMediaTime;
  10250. // There should be no outstanding advise
  10251. Assert(CancelNotification = S_FALSE);
  10252. SourceThreadCanWait(True);
  10253. Result := NOERROR;
  10254. end;
  10255. // We can now send EC_REPAINTs if so required
  10256. function TBCBaseRenderer.CompleteConnect(ReceivePin: IPin): HResult;
  10257. begin
  10258. // The caller should always hold the interface lock because
  10259. // the function uses CBaseFilter::m_State.
  10260. {$IFDEF DEBUG}
  10261. Assert(FInterfaceLock.CritCheckIn);
  10262. {$ENDIF}
  10263. FAbort := False;
  10264. if (State_Running = GetRealState) then
  10265. begin
  10266. Result := StartStreaming;
  10267. if Failed(Result) then
  10268. Exit;
  10269. SetRepaintStatus(False);
  10270. end
  10271. else
  10272. SetRepaintStatus(True);
  10273. Result := NOERROR;
  10274. end;
  10275. // Called when we go paused or running
  10276. function TBCBaseRenderer.Active: HResult;
  10277. begin
  10278. Result := NOERROR;
  10279. end;
  10280. // Called when we go into a stopped state
  10281. function TBCBaseRenderer.Inactive: HResult;
  10282. begin
  10283. if Assigned(FPosition) then
  10284. FPosition.ResetMediaTime;
  10285. // People who derive from this may want to override this behaviour
  10286. // to keep hold of the sample in some circumstances
  10287. ClearPendingSample;
  10288. Result := NOERROR;
  10289. end;
  10290. // Tell derived classes about the media type agreed
  10291. function TBCBaseRenderer.SetMediaType(MediaType: PAMMediaType): HResult;
  10292. begin
  10293. Result := NOERROR;
  10294. end;
  10295. // When we break the input pin connection we should reset the EOS flags. When
  10296. // we are asked for either IMediaPosition or IMediaSeeking we will create a
  10297. // CPosPassThru object to handles media time pass through. When we're handed
  10298. // samples we store (by calling CPosPassThru::RegisterMediaTime) their media
  10299. // times so we can then return a real current position of data being rendered
  10300. function TBCBaseRenderer.BreakConnect: HResult;
  10301. begin
  10302. // Do we have a quality management sink
  10303. if Assigned(FQSink) then
  10304. FQSink := nil;
  10305. // Check we have a valid connection
  10306. if not FInputPin.IsConnected then
  10307. begin
  10308. Result := S_FALSE;
  10309. Exit;
  10310. end;
  10311. // Check we are stopped before disconnecting
  10312. if (FState <> State_Stopped) and (not FInputPin.CanReconnectWhenActive) then
  10313. begin
  10314. Result := VFW_E_NOT_STOPPED;
  10315. Exit;
  10316. end;
  10317. SetRepaintStatus(False);
  10318. ResetEndOfStream;
  10319. ClearPendingSample;
  10320. FAbort := False;
  10321. if (State_Running = FState) then
  10322. StopStreaming;
  10323. Result := NOERROR;
  10324. end;
  10325. // Retrieves the sample times for this samples (note the sample times are
  10326. // passed in by reference not value). We return S_FALSE to say schedule this
  10327. // sample according to the times on the sample. We also return S_OK in
  10328. // which case the object should simply render the sample data immediately
  10329. function TBCBaseRenderer.GetSampleTimes(MediaSample: IMediaSample;
  10330. out StartTime: TReferenceTime; out EndTime: TReferenceTime): HResult;
  10331. begin
  10332. Assert(FAdvisedCookie = 0);
  10333. Assert(Assigned(MediaSample));
  10334. // If the stop time for this sample is before or the same as start time,
  10335. // then just ignore it (release it) and schedule the next one in line
  10336. // Source filters should always fill in the start and end times properly!
  10337. if Succeeded(MediaSample.GetTime(StartTime, EndTime)) then
  10338. begin
  10339. if (EndTime < StartTime) then
  10340. begin
  10341. Result := VFW_E_START_TIME_AFTER_END;
  10342. Exit;
  10343. end;
  10344. end
  10345. else
  10346. begin
  10347. // no time set in the sample... draw it now?
  10348. Result := S_OK;
  10349. Exit;
  10350. end;
  10351. // Can't synchronise without a clock so we return S_OK which tells the
  10352. // caller that the sample should be rendered immediately without going
  10353. // through the overhead of setting a timer advise link with the clock
  10354. if (FClock = nil) then
  10355. Result := S_OK
  10356. else
  10357. Result := ShouldDrawSampleNow(MediaSample, StartTime, EndTime);
  10358. end;
  10359. // By default all samples are drawn according to their time stamps so we
  10360. // return S_FALSE. Returning S_OK means draw immediately, this is used
  10361. // by the derived video renderer class in its quality management.
  10362. function TBCBaseRenderer.ShouldDrawSampleNow(MediaSample: IMediaSample;
  10363. StartTime: TReferenceTime; out EndTime: TReferenceTime): HResult;
  10364. begin
  10365. Result := S_FALSE;
  10366. end;
  10367. // We must always reset the current advise time to zero after a timer fires
  10368. // because there are several possible ways which lead us not to do any more
  10369. // scheduling such as the pending image being cleared after state changes
  10370. procedure TBCBaseRenderer.SignalTimerFired;
  10371. begin
  10372. FAdvisedCookie := 0;
  10373. end;
  10374. // Cancel any notification currently scheduled. This is called by the owning
  10375. // window object when it is told to stop streaming. If there is no timer link
  10376. // outstanding then calling this is benign otherwise we go ahead and cancel
  10377. // We must always reset the render event as the quality management code can
  10378. // signal immediate rendering by setting the event without setting an advise
  10379. // link. If we're subsequently stopped and run the first attempt to setup an
  10380. // advise link with the reference clock will find the event still signalled
  10381. function TBCBaseRenderer.CancelNotification: HResult;
  10382. var
  10383. dwAdvisedCookie: DWord;
  10384. begin
  10385. Assert((FAdvisedCookie = 0) or Assigned(FClock));
  10386. dwAdvisedCookie := FAdvisedCookie;
  10387. // Have we a live advise link
  10388. if (FAdvisedCookie <> 0) then
  10389. begin
  10390. FClock.Unadvise(FAdvisedCookie);
  10391. SignalTimerFired;
  10392. Assert(FAdvisedCookie = 0);
  10393. end;
  10394. // Clear the event and return our status
  10395. FRenderEvent.Reset;
  10396. if (dwAdvisedCookie <> 0) then
  10397. Result := S_OK
  10398. else
  10399. Result := S_FALSE;
  10400. end;
  10401. // Responsible for setting up one shot advise links with the clock
  10402. // Return FALSE if the sample is to be dropped (not drawn at all)
  10403. // Return TRUE if the sample is to be drawn and in this case also
  10404. // arrange for m_RenderEvent to be set at the appropriate time
  10405. function TBCBaseRenderer.ScheduleSample(MediaSample: IMediaSample): Boolean;
  10406. var
  10407. StartSample, EndSample: TReferenceTime;
  10408. hr: HResult;
  10409. begin
  10410. // Is someone pulling our leg
  10411. if (MediaSample = nil) then
  10412. begin
  10413. Result := False;
  10414. Exit;
  10415. end;
  10416. // Get the next sample due up for rendering. If there aren't any ready
  10417. // then GetNextSampleTimes returns an error. If there is one to be done
  10418. // then it succeeds and yields the sample times. If it is due now then
  10419. // it returns S_OK other if it's to be done when due it returns S_FALSE
  10420. hr := GetSampleTimes(MediaSample, StartSample, EndSample);
  10421. if Failed(hr) then
  10422. begin
  10423. Result := False;
  10424. Exit;
  10425. end;
  10426. // If we don't have a reference clock then we cannot set up the advise
  10427. // time so we simply set the event indicating an image to render. This
  10428. // will cause us to run flat out without any timing or synchronisation
  10429. if (hr = S_OK) then
  10430. begin
  10431. // ???Assert(SetEvent(FRenderEvent.Handle));
  10432. FRenderEvent.SetEv;
  10433. Result := True;
  10434. Exit;
  10435. end;
  10436. Assert(FAdvisedCookie = 0);
  10437. Assert(Assigned(FClock));
  10438. Assert(Wait_Timeout = WaitForSingleObject(FRenderEvent.Handle, 0));
  10439. // We do have a valid reference clock interface so we can ask it to
  10440. // set an event when the image comes due for rendering. We pass in
  10441. // the reference time we were told to start at and also the current
  10442. // stream time which is the offset from the start reference time
  10443. hr := FClock.AdviseTime(
  10444. FStart, // Start run time
  10445. StartSample, // Stream time
  10446. FRenderEvent.Handle, // Render notification
  10447. FAdvisedCookie); // Advise cookie
  10448. if Succeeded(hr) then
  10449. begin
  10450. Result := True;
  10451. Exit;
  10452. end;
  10453. // We could not schedule the next sample for rendering despite the fact
  10454. // we have a valid sample here. This is a fair indication that either
  10455. // the system clock is wrong or the time stamp for the sample is duff
  10456. Assert(FAdvisedCookie = 0);
  10457. Result := False;
  10458. end;
  10459. // This is called when a sample comes due for rendering. We pass the sample
  10460. // on to the derived class. After rendering we will initialise the timer for
  10461. // the next sample, NOTE signal that the last one fired first, if we don't
  10462. // do this it thinks there is still one outstanding that hasn't completed
  10463. function TBCBaseRenderer.Render(MediaSample: IMediaSample): HResult;
  10464. begin
  10465. // If the media sample is NULL then we will have been notified by the
  10466. // clock that another sample is ready but in the mean time someone has
  10467. // stopped us streaming which causes the next sample to be released
  10468. if (MediaSample = nil) then
  10469. begin
  10470. Result := S_FALSE;
  10471. Exit;
  10472. end;
  10473. // If we have stopped streaming then don't render any more samples, the
  10474. // thread that got in and locked us and then reset this flag does not
  10475. // clear the pending sample as we can use it to refresh any output device
  10476. if Not FIsStreaming then
  10477. begin
  10478. Result := S_FALSE;
  10479. Exit;
  10480. end;
  10481. // Time how long the rendering takes
  10482. OnRenderStart(MediaSample);
  10483. DoRenderSample(MediaSample);
  10484. OnRenderEnd(MediaSample);
  10485. Result := NOERROR;
  10486. end;
  10487. // Checks if there is a sample waiting at the renderer
  10488. function TBCBaseRenderer.HaveCurrentSample: Boolean;
  10489. begin
  10490. FRendererLock.Lock;
  10491. try
  10492. Result := (FMediaSample <> nil);
  10493. finally
  10494. FRendererLock.UnLock;
  10495. end;
  10496. end;
  10497. // Returns the current sample waiting at the video renderer. We AddRef the
  10498. // sample before returning so that should it come due for rendering the
  10499. // person who called this method will hold the remaining reference count
  10500. // that will stop the sample being added back onto the allocator free list
  10501. function TBCBaseRenderer.GetCurrentSample: IMediaSample;
  10502. begin
  10503. FRendererLock.Lock;
  10504. try
  10505. (* ???
  10506. if (m_pMediaSample) {
  10507. m_pMediaSample->AddRef();
  10508. *)
  10509. Result := FMediaSample;
  10510. finally
  10511. FRendererLock.Unlock;
  10512. end;
  10513. end;
  10514. // Called when the source delivers us a sample. We go through a few checks to
  10515. // make sure the sample can be rendered. If we are running (streaming) then we
  10516. // have the sample scheduled with the reference clock, if we are not streaming
  10517. // then we have received an sample in paused mode so we can complete any state
  10518. // transition. On leaving this function everything will be unlocked so an app
  10519. // thread may get in and change our state to stopped (for example) in which
  10520. // case it will also signal the thread event so that our wait call is stopped
  10521. function TBCBaseRenderer.PrepareReceive(MediaSample: IMediaSample): HResult;
  10522. var
  10523. hr: HResult;
  10524. begin
  10525. FInterfaceLock.Lock;
  10526. try
  10527. FInReceive := True;
  10528. // Check our flushing and filter state
  10529. // This function must hold the interface lock because it calls
  10530. // CBaseInputPin::Receive() and CBaseInputPin::Receive() uses
  10531. // CBasePin::m_bRunTimeError.
  10532. // ??? HRESULT hr = m_pInputPin->CBaseInputPin::Receive(MediaSample);
  10533. hr := FInputPin.InheritedReceive(MediaSample);
  10534. if (hr <> NOERROR) then
  10535. begin
  10536. FInReceive := False;
  10537. Result := E_FAIL;
  10538. Exit;
  10539. end;
  10540. // Has the type changed on a media sample. We do all rendering
  10541. // synchronously on the source thread, which has a side effect
  10542. // that only one buffer is ever outstanding. Therefore when we
  10543. // have Receive called we can go ahead and change the format
  10544. // Since the format change can cause a SendMessage we just don't
  10545. // lock
  10546. if Assigned(FInputPin.SampleProps.pMediaType) then
  10547. begin
  10548. hr := FInputPin.SetMediaType(FInputPin.FSampleProps.pMediaType);
  10549. if Failed(hr) then
  10550. begin
  10551. Result := hr;
  10552. FInReceive := False;
  10553. Exit;
  10554. end;
  10555. end;
  10556. FRendererLock.Lock;
  10557. try
  10558. Assert(IsActive);
  10559. Assert(not FInputPin.IsFlushing);
  10560. Assert(FInputPin.IsConnected);
  10561. Assert(FMediaSample = nil);
  10562. // Return an error if we already have a sample waiting for rendering
  10563. // source pins must serialise the Receive calls - we also check that
  10564. // no data is being sent after the source signalled an end of stream
  10565. if (Assigned(FMediaSample) or FIsEOS or FAbort) then
  10566. begin
  10567. Ready;
  10568. FInReceive := False;
  10569. Result := E_UNEXPECTED;
  10570. Exit;
  10571. end;
  10572. // Store the media times from this sample
  10573. if Assigned(FPosition) then
  10574. FPosition.RegisterMediaTime(MediaSample);
  10575. // Schedule the next sample if we are streaming
  10576. if (FIsStreaming and (not ScheduleSample(MediaSample))) then
  10577. begin
  10578. Assert(WAIT_TIMEOUT = WaitForSingleObject(FRenderEvent.Handle, 0));
  10579. Assert(CancelNotification = S_FALSE);
  10580. FInReceive := False;
  10581. Result := VFW_E_SAMPLE_REJECTED;
  10582. Exit;
  10583. end;
  10584. // Store the sample end time for EC_COMPLETE handling
  10585. FSignalTime := FInputPin.FSampleProps.tStop;
  10586. // BEWARE we sometimes keep the sample even after returning the thread to
  10587. // the source filter such as when we go into a stopped state (we keep it
  10588. // to refresh the device with) so we must AddRef it to keep it safely. If
  10589. // we start flushing the source thread is released and any sample waiting
  10590. // will be released otherwise GetBuffer may never return (see BeginFlush)
  10591. FMediaSample := MediaSample;
  10592. //??? m_pMediaSample->AddRef();
  10593. if not FIsStreaming then
  10594. SetRepaintStatus(True);
  10595. Result := NOERROR;
  10596. finally
  10597. FRendererLock.Unlock;
  10598. end;
  10599. finally
  10600. FInterfaceLock.UnLock;
  10601. end;
  10602. end;
  10603. // Called by the source filter when we have a sample to render. Under normal
  10604. // circumstances we set an advise link with the clock, wait for the time to
  10605. // arrive and then render the data using the PURE virtual DoRenderSample that
  10606. // the derived class will have overriden. After rendering the sample we may
  10607. // also signal EOS if it was the last one sent before EndOfStream was called
  10608. function TBCBaseRenderer.Receive(MediaSample: IMediaSample): HResult;
  10609. begin
  10610. Assert(Assigned(MediaSample));
  10611. // It may return VFW_E_SAMPLE_REJECTED code to say don't bother
  10612. Result := PrepareReceive(MediaSample);
  10613. Assert(FInReceive = Succeeded(Result));
  10614. if Failed(Result) then
  10615. begin
  10616. if (Result = VFW_E_SAMPLE_REJECTED) then
  10617. Result := NOERROR;
  10618. Exit;
  10619. end;
  10620. // We realize the palette in "PrepareRender()" so we have to give away the
  10621. // filter lock here.
  10622. if (FState = State_Paused) then
  10623. begin
  10624. PrepareRender;
  10625. // no need to use InterlockedExchange
  10626. FInReceive := False;
  10627. // We must hold both these locks
  10628. FInterfaceLock.Lock;
  10629. try
  10630. if (FState = State_Stopped) then
  10631. begin
  10632. Result := NOERROR;
  10633. Exit;
  10634. end;
  10635. FInReceive := True;
  10636. FRendererLock.Lock;
  10637. try
  10638. OnReceiveFirstSample(MediaSample);
  10639. finally
  10640. FRendererLock.UnLock;
  10641. end;
  10642. finally
  10643. FInterfaceLock.UnLock;
  10644. end;
  10645. Ready;
  10646. end;
  10647. // Having set an advise link with the clock we sit and wait. We may be
  10648. // awoken by the clock firing or by a state change. The rendering call
  10649. // will lock the critical section and check we can still render the data
  10650. Result := WaitForRenderTime;
  10651. if Failed(Result) then
  10652. begin
  10653. FInReceive := False;
  10654. Result := NOERROR;
  10655. Exit;
  10656. end;
  10657. PrepareRender;
  10658. // Set this here and poll it until we work out the locking correctly
  10659. // It can't be right that the streaming stuff grabs the interface
  10660. // lock - after all we want to be able to wait for this stuff
  10661. // to complete
  10662. FInReceive := False;
  10663. // We must hold both these locks
  10664. FInterfaceLock.Lock;
  10665. try
  10666. // since we gave away the filter wide lock, the sate of the filter could
  10667. // have chnaged to Stopped
  10668. if (FState = State_Stopped) then
  10669. begin
  10670. Result := NOERROR;
  10671. Exit;
  10672. end;
  10673. FRendererLock.Lock;
  10674. try
  10675. // Deal with this sample
  10676. Render(FMediaSample);
  10677. ClearPendingSample;
  10678. // milenko start (why commented before?)
  10679. SendEndOfStream;
  10680. // milenko end
  10681. CancelNotification;
  10682. Result := NOERROR;
  10683. finally
  10684. FRendererLock.UnLock;
  10685. end;
  10686. finally
  10687. FInterfaceLock.UnLock;
  10688. end;
  10689. end;
  10690. // This is called when we stop or are inactivated to clear the pending sample
  10691. // We release the media sample interface so that they can be allocated to the
  10692. // source filter again, unless of course we are changing state to inactive in
  10693. // which case GetBuffer will return an error. We must also reset the current
  10694. // media sample to NULL so that we know we do not currently have an image
  10695. function TBCBaseRenderer.ClearPendingSample: HResult;
  10696. begin
  10697. FRendererLock.Lock;
  10698. try
  10699. if Assigned(FMediaSample) then
  10700. FMediaSample := nil;
  10701. Result := NOERROR;
  10702. finally
  10703. FRendererLock.Unlock;
  10704. end;
  10705. end;
  10706. // Used to signal end of stream according to the sample end time
  10707. // Milenko start (use this callback outside of the class and with stdcall;)
  10708. procedure EndOfStreamTimer(uID, uMsg: UINT;
  10709. dwUser, dw1, dw2: DWord); stdcall;
  10710. var
  10711. Renderer: TBCBaseRenderer;
  10712. begin
  10713. Renderer := TBCBaseRenderer(dwUser);
  10714. {$IFDEF DEBUG}
  10715. //NOTE1("EndOfStreamTimer called (%d)",uID);
  10716. DbgLog(Format('EndOfStreamTimer called (%d)', [uID]));
  10717. {$ENDIF}
  10718. Renderer.TimerCallback;
  10719. {
  10720. ???
  10721. CBaseRenderer *pRenderer = (CBaseRenderer * ) dwUser;
  10722. pRenderer->TimerCallback();
  10723. }
  10724. end;
  10725. // Milenko end
  10726. // Do the timer callback work
  10727. procedure TBCBaseRenderer.TimerCallback;
  10728. begin
  10729. // Lock for synchronization (but don't hold this lock when calling
  10730. // timeKillEvent)
  10731. FRendererLock.Lock;
  10732. try
  10733. // See if we should signal end of stream now
  10734. if (FEndOfStreamTimer <> 0) then
  10735. begin
  10736. FEndOfStreamTimer := 0;
  10737. // milenko start (why commented before?)
  10738. SendEndOfStream;
  10739. // milenko end
  10740. end;
  10741. finally
  10742. FRendererLock.Unlock;
  10743. end;
  10744. end;
  10745. // If we are at the end of the stream signal the filter graph but do not set
  10746. // the state flag back to FALSE. Once we drop off the end of the stream we
  10747. // leave the flag set (until a subsequent ResetEndOfStream). Each sample we
  10748. // get delivered will update m_SignalTime to be the last sample's end time.
  10749. // We must wait this long before signalling end of stream to the filtergraph
  10750. const
  10751. TIMEOUT_DELIVERYWAIT = 50;
  10752. TIMEOUT_RESOLUTION = 10;
  10753. function TBCBaseRenderer.SendEndOfStream: HResult;
  10754. var
  10755. Signal, CurrentTime: TReferenceTime;
  10756. Delay: Longint;
  10757. begin
  10758. {$IFDEF DEBUG}
  10759. Assert(FRendererLock.CritCheckIn);
  10760. {$ENDIF}
  10761. if ((not FIsEOS) or FIsEOSDelivered or (FEndOfStreamTimer <> 0)) then
  10762. begin
  10763. Result := NOERROR;
  10764. Exit;
  10765. end;
  10766. // If there is no clock then signal immediately
  10767. if (FClock = nil) then
  10768. begin
  10769. Result := NotifyEndOfStream;
  10770. Exit;
  10771. end;
  10772. // How long into the future is the delivery time
  10773. Signal := FStart + FSignalTime;
  10774. FClock.GetTime(int64(CurrentTime));
  10775. // Milenko Start (important!)
  10776. // Delay := (Longint(Signal) - CurrentTime) div 10000;
  10777. Delay := LongInt((Signal - CurrentTime) div 10000);
  10778. // Milenko end
  10779. // Dump the timing information to the debugger
  10780. {$IFDEF DEBUG}
  10781. DbgLog(Self, Format('Delay until end of stream delivery %d', [Delay]));
  10782. // ??? NOTE1("Current %s",(LPCTSTR)CDisp((LONGLONG)CurrentTime));
  10783. // ??? NOTE1("Signal %s",(LPCTSTR)CDisp((LONGLONG)Signal));
  10784. DbgLog(Self, Format('Current %d', [CurrentTime]));
  10785. DbgLog(Self, Format('Signal %d', [Signal]));
  10786. {$ENDIF}
  10787. // Wait for the delivery time to arrive
  10788. if (Delay < TIMEOUT_DELIVERYWAIT) then
  10789. begin
  10790. Result := NotifyEndOfStream;
  10791. Exit;
  10792. end;
  10793. // Signal a timer callback on another worker thread
  10794. FEndOfStreamTimer := CompatibleTimeSetEvent(
  10795. Delay, // Period of timer
  10796. TIMEOUT_RESOLUTION, // Timer resolution
  10797. // ???
  10798. // Milenko start (callback is now outside of the class)
  10799. @EndOfStreamTimer,// Callback function
  10800. // Milenko end
  10801. Cardinal(Self), // Used information
  10802. TIME_ONESHOT); // Type of callback
  10803. if (FEndOfStreamTimer = 0) then
  10804. begin
  10805. Result := NotifyEndOfStream;
  10806. Exit;
  10807. end;
  10808. Result := NOERROR;
  10809. end;
  10810. // Signals EC_COMPLETE to the filtergraph manager
  10811. function TBCBaseRenderer.NotifyEndOfStream: HResult;
  10812. var
  10813. Filter: IBaseFilter;
  10814. begin
  10815. FRendererLock.Lock;
  10816. try
  10817. Assert(not FIsEOSDelivered);
  10818. Assert(FEndOfStreamTimer = 0);
  10819. // Has the filter changed state
  10820. if not FIsStreaming then
  10821. begin
  10822. Assert(FEndOfStreamTimer = 0);
  10823. Result := NOERROR;
  10824. Exit;
  10825. end;
  10826. // Reset the end of stream timer
  10827. FEndOfStreamTimer := 0;
  10828. // If we've been using the IMediaPosition interface, set it's start
  10829. // and end media "times" to the stop position by hand. This ensures
  10830. // that we actually get to the end, even if the MPEG guestimate has
  10831. // been bad or if the quality management dropped the last few frames
  10832. if Assigned(FPosition) then
  10833. FPosition.EOS;
  10834. FIsEOSDelivered := True;
  10835. {$IFDEF DEBUG}
  10836. DbgLog('Sending EC_COMPLETE...');
  10837. {$ENDIF}
  10838. // ??? return NotifyEvent(EC_COMPLETE,S_OK,(LONG_PTR)(IBaseFilter *)this);
  10839. // milenko start (Delphi 5 compatibility)
  10840. QueryInterface(IID_IBaseFilter,Filter);
  10841. Result := NotifyEvent(EC_COMPLETE, S_OK, Integer(Filter));
  10842. Filter := nil;
  10843. // milenko end
  10844. finally
  10845. FRendererLock.UnLock;
  10846. end;
  10847. end;
  10848. // Reset the end of stream flag, this is typically called when we transfer to
  10849. // stopped states since that resets the current position back to the start so
  10850. // we will receive more samples or another EndOfStream if there aren't any. We
  10851. // keep two separate flags one to say we have run off the end of the stream
  10852. // (this is the m_bEOS flag) and another to say we have delivered EC_COMPLETE
  10853. // to the filter graph. We need the latter otherwise we can end up sending an
  10854. // EC_COMPLETE every time the source changes state and calls our EndOfStream
  10855. function TBCBaseRenderer.ResetEndOfStream: HResult;
  10856. begin
  10857. ResetEndOfStreamTimer;
  10858. FRendererLock.Lock;
  10859. try
  10860. FIsEOS := False;
  10861. FIsEOSDelivered := False;
  10862. FSignalTime := 0;
  10863. Result := NOERROR;
  10864. finally
  10865. FRendererLock.UnLock;
  10866. end;
  10867. end;
  10868. // Kills any outstanding end of stream timer
  10869. procedure TBCBaseRenderer.ResetEndOfStreamTimer;
  10870. begin
  10871. {$IFDEF DEBUG}
  10872. Assert(FRendererLock.CritCheckOut);
  10873. {$ENDIF}
  10874. if (FEndOfStreamTimer <> 0) then
  10875. begin
  10876. timeKillEvent(FEndOfStreamTimer);
  10877. FEndOfStreamTimer := 0;
  10878. end;
  10879. end;
  10880. // This is called when we start running so that we can schedule any pending
  10881. // image we have with the clock and display any timing information. If we
  10882. // don't have any sample but we have queued an EOS flag then we send it. If
  10883. // we do have a sample then we wait until that has been rendered before we
  10884. // signal the filter graph otherwise we may change state before it's done
  10885. function TBCBaseRenderer.StartStreaming: HResult;
  10886. begin
  10887. FRendererLock.Lock;
  10888. try
  10889. if FIsStreaming then
  10890. begin
  10891. Result := NOERROR;
  10892. Exit;
  10893. end;
  10894. // Reset the streaming times ready for running
  10895. FIsStreaming := True;
  10896. timeBeginPeriod(1);
  10897. OnStartStreaming;
  10898. // There should be no outstanding advise
  10899. Assert(WAIT_TIMEOUT = WaitForSingleObject(FRenderEvent.Handle, 0));
  10900. Assert(CancelNotification = S_FALSE);
  10901. // If we have an EOS and no data then deliver it now
  10902. if (FMediaSample = nil) then
  10903. begin
  10904. Result := SendEndOfStream;
  10905. Exit;
  10906. end;
  10907. // Have the data rendered
  10908. Assert(Assigned(FMediaSample));
  10909. if not ScheduleSample(FMediaSample) then
  10910. FRenderEvent.SetEv;
  10911. Result := NOERROR;
  10912. finally
  10913. FRendererLock.UnLock;
  10914. end;
  10915. end;
  10916. // This is called when we stop streaming so that we can set our internal flag
  10917. // indicating we are not now to schedule any more samples arriving. The state
  10918. // change methods in the filter implementation take care of cancelling any
  10919. // clock advise link we have set up and clearing any pending sample we have
  10920. function TBCBaseRenderer.StopStreaming: HResult;
  10921. begin
  10922. FRendererLock.Lock;
  10923. try
  10924. FIsEOSDelivered := False;
  10925. if FIsStreaming then
  10926. begin
  10927. FIsStreaming := False;
  10928. OnStopStreaming;
  10929. timeEndPeriod(1);
  10930. end;
  10931. Result := NOERROR;
  10932. finally
  10933. FRendererLock.Unlock;
  10934. end;
  10935. end;
  10936. // We have a boolean flag that is reset when we have signalled EC_REPAINT to
  10937. // the filter graph. We set this when we receive an image so that should any
  10938. // conditions arise again we can send another one. By having a flag we ensure
  10939. // we don't flood the filter graph with redundant calls. We do not set the
  10940. // event when we receive an EndOfStream call since there is no point in us
  10941. // sending further EC_REPAINTs. In particular the AutoShowWindow method and
  10942. // the DirectDraw object use this method to control the window repainting
  10943. procedure TBCBaseRenderer.SetRepaintStatus(Repaint: Boolean);
  10944. begin
  10945. FRendererLock.Lock;
  10946. try
  10947. FRepaintStatus := Repaint;
  10948. finally
  10949. FRendererLock.Unlock;
  10950. end;
  10951. end;
  10952. // Pass the window handle to the upstream filter
  10953. procedure TBCBaseRenderer.SendNotifyWindow(Pin: IPin; Handle: HWND);
  10954. var
  10955. Sink: IMediaEventSink;
  10956. hr: HResult;
  10957. begin
  10958. // Does the pin support IMediaEventSink
  10959. hr := Pin.QueryInterface(IID_IMediaEventSink, Sink);
  10960. if Succeeded(hr) then
  10961. begin
  10962. Sink.Notify(EC_NOTIFY_WINDOW, Handle, 0);
  10963. Sink := nil;
  10964. end;
  10965. NotifyEvent(EC_NOTIFY_WINDOW, Handle, 0);
  10966. end;
  10967. // Signal an EC_REPAINT to the filter graph. This can be used to have data
  10968. // sent to us. For example when a video window is first displayed it may
  10969. // not have an image to display, at which point it signals EC_REPAINT. The
  10970. // filtergraph will either pause the graph if stopped or if already paused
  10971. // it will call put_CurrentPosition of the current position. Setting the
  10972. // current position to itself has the stream flushed and the image resent
  10973. // ??? #define RLOG(_x_) DbgLog((LOG_TRACE,1,TEXT(_x_)));
  10974. procedure TBCBaseRenderer.SendRepaint;
  10975. var
  10976. Pin: IPin;
  10977. begin
  10978. FRendererLock.Lock;
  10979. try
  10980. Assert(Assigned(FInputPin));
  10981. // We should not send repaint notifications when...
  10982. // - An end of stream has been notified
  10983. // - Our input pin is being flushed
  10984. // - The input pin is not connected
  10985. // - We have aborted a video playback
  10986. // - There is a repaint already sent
  10987. if (not FAbort) and
  10988. (FInputPin.IsConnected) and
  10989. (not FInputPin.IsFlushing) and
  10990. (not IsEndOfStream) and
  10991. FRepaintStatus then
  10992. begin
  10993. // milenko start (delphi 5 compatibility)
  10994. // Pin := FInputPin as IPin;
  10995. FInputPin.QueryInterface(IID_IPin,Pin);
  10996. NotifyEvent(EC_REPAINT, Integer(Pin), 0);
  10997. Pin := nil;
  10998. // milenko end
  10999. SetRepaintStatus(False);
  11000. {$IFDEF DEBUG}
  11001. DbgLog('Sending repaint');
  11002. {$ENDIF}
  11003. end;
  11004. finally
  11005. FRendererLock.Unlock;
  11006. end;
  11007. end;
  11008. // When a video window detects a display change (WM_DISPLAYCHANGE message) it
  11009. // can send an EC_DISPLAY_CHANGED event code along with the renderer pin. The
  11010. // filtergraph will stop everyone and reconnect our input pin. As we're then
  11011. // reconnected we can accept the media type that matches the new display mode
  11012. // since we may no longer be able to draw the current image type efficiently
  11013. function TBCBaseRenderer.OnDisplayChange: Boolean;
  11014. var
  11015. Pin: IPin;
  11016. begin
  11017. // Ignore if we are not connected yet
  11018. FRendererLock.Lock;
  11019. try
  11020. if not FInputPin.IsConnected then
  11021. begin
  11022. Result := False;
  11023. Exit;
  11024. end;
  11025. {$IFDEF DEBUG}
  11026. DbgLog('Notification of EC_DISPLAY_CHANGE');
  11027. {$ENDIF}
  11028. // Pass our input pin as parameter on the event
  11029. // milenko start (Delphi 5 compatibility)
  11030. // Pin := FInputPin as IPin;
  11031. FInputPin.QueryInterface(IID_IPin,Pin);
  11032. // ??? m_pInputPin->AddRef();
  11033. NotifyEvent(EC_DISPLAY_CHANGED, Integer(Pin), 0);
  11034. SetAbortSignal(True);
  11035. ClearPendingSample;
  11036. // FreeAndNil(FInputPin);
  11037. Pin := nil;
  11038. // milenko end
  11039. Result := True;
  11040. finally
  11041. FRendererLock.Unlock;
  11042. end;
  11043. end;
  11044. // Called just before we start drawing.
  11045. // Store the current time in m_trRenderStart to allow the rendering time to be
  11046. // logged. Log the time stamp of the sample and how late it is (neg is early)
  11047. procedure TBCBaseRenderer.OnRenderStart(MediaSample: IMediaSample);
  11048. {$IFDEF PERF}
  11049. var
  11050. StartTime, EndTime, StreamTime: TReferenceTime;
  11051. {$ENDIF}
  11052. begin
  11053. {$IFDEF PERF}
  11054. MediaSample.GetTime(StartTime, EndTime);
  11055. MSR_INTEGER(FBaseStamp, Integer(StartTime)); // dump low order 32 bits
  11056. FClock.GetTime(pint64(@FRenderStart)^);
  11057. MSR_INTEGER(0, Integer(FRenderStart));
  11058. StreamTime := FRenderStart - FStart; // convert reftime to stream time
  11059. MSR_INTEGER(0, Integer(StreamTime));
  11060. MSR_INTEGER(FBaseAccuracy, RefTimeToMiliSec(StreamTime - StartTime)); // dump in mSec
  11061. {$ENDIF}
  11062. end;
  11063. // Called directly after drawing an image.
  11064. // calculate the time spent drawing and log it.
  11065. procedure TBCBaseRenderer.OnRenderEnd(MediaSample: IMediaSample);
  11066. {$IFDEF PERF}
  11067. var
  11068. NowTime: TReferenceTime;
  11069. t: Integer;
  11070. {$ENDIF}
  11071. begin
  11072. {$IFDEF PERF}
  11073. FClock.GetTime(int64(NowTime));
  11074. MSR_INTEGER(0, Integer(NowTime));
  11075. t := RefTimeToMiliSec(NowTime - FRenderStart); // convert UNITS->msec
  11076. MSR_INTEGER(FBaseRenderTime, t);
  11077. {$ENDIF}
  11078. end;
  11079. function TBCBaseRenderer.OnStartStreaming: HResult;
  11080. begin
  11081. Result := NOERROR;
  11082. end;
  11083. function TBCBaseRenderer.OnStopStreaming: HResult;
  11084. begin
  11085. Result := NOERROR;
  11086. end;
  11087. procedure TBCBaseRenderer.OnWaitStart;
  11088. begin
  11089. end;
  11090. procedure TBCBaseRenderer.OnWaitEnd;
  11091. begin
  11092. end;
  11093. procedure TBCBaseRenderer.PrepareRender;
  11094. begin
  11095. end;
  11096. // Constructor must be passed the base renderer object
  11097. constructor TBCRendererInputPin.Create(Renderer: TBCBaseRenderer;
  11098. out hr: HResult; Name: PWideChar);
  11099. begin
  11100. inherited Create('Renderer pin', Renderer, Renderer.FInterfaceLock,
  11101. hr, Name);
  11102. FRenderer := Renderer;
  11103. Assert(Assigned(FRenderer));
  11104. end;
  11105. // Signals end of data stream on the input pin
  11106. function TBCRendererInputPin.EndOfStream: HResult;
  11107. begin
  11108. FRenderer.FInterfaceLock.Lock;
  11109. FRenderer.FRendererLock.Lock;
  11110. try
  11111. // Make sure we're streaming ok
  11112. Result := CheckStreaming;
  11113. if (Result <> NOERROR) then
  11114. Exit;
  11115. // Pass it onto the renderer
  11116. Result := FRenderer.EndOfStream;
  11117. if Succeeded(Result) then
  11118. Result := inherited EndOfStream;
  11119. finally
  11120. FRenderer.FRendererLock.UnLock;
  11121. FRenderer.FInterfaceLock.UnLock;
  11122. end;
  11123. end;
  11124. // Signals start of flushing on the input pin - we do the final reset end of
  11125. // stream with the renderer lock unlocked but with the interface lock locked
  11126. // We must do this because we call timeKillEvent, our timer callback method
  11127. // has to take the renderer lock to serialise our state. Therefore holding a
  11128. // renderer lock when calling timeKillEvent could cause a deadlock condition
  11129. function TBCRendererInputPin.BeginFlush: HResult;
  11130. begin
  11131. FRenderer.FInterfaceLock.Lock;
  11132. try
  11133. FRenderer.FRendererLock.Lock;
  11134. try
  11135. inherited BeginFlush;
  11136. FRenderer.BeginFlush;
  11137. finally
  11138. FRenderer.FRendererLock.UnLock;
  11139. end;
  11140. Result := FRenderer.ResetEndOfStream;
  11141. finally
  11142. FRenderer.FInterfaceLock.UnLock;
  11143. end;
  11144. end;
  11145. // Signals end of flushing on the input pin
  11146. function TBCRendererInputPin.EndFlush: HResult;
  11147. begin
  11148. FRenderer.FInterfaceLock.Lock;
  11149. FRenderer.FRendererLock.Lock;
  11150. try
  11151. Result := FRenderer.EndFlush;
  11152. if Succeeded(Result) then
  11153. Result := inherited EndFlush;
  11154. finally
  11155. FRenderer.FRendererLock.UnLock;
  11156. FRenderer.FInterfaceLock.UnLock;
  11157. end;
  11158. end;
  11159. // Pass the sample straight through to the renderer object
  11160. function TBCRendererInputPin.Receive(MediaSample: IMediaSample): HResult;
  11161. var
  11162. hr: HResult;
  11163. begin
  11164. hr := FRenderer.Receive(MediaSample);
  11165. if Failed(hr) then
  11166. begin
  11167. // A deadlock could occur if the caller holds the renderer lock and
  11168. // attempts to acquire the interface lock.
  11169. {$IFDEF DEBUG}
  11170. Assert(FRenderer.FRendererLock.CritCheckOut);
  11171. {$ENDIF}
  11172. // The interface lock must be held when the filter is calling
  11173. // IsStopped or IsFlushing. The interface lock must also
  11174. // be held because the function uses m_bRunTimeError.
  11175. FRenderer.FInterfaceLock.Lock;
  11176. try
  11177. // We do not report errors which occur while the filter is stopping,
  11178. // flushing or if the FAborting flag is set . Errors are expected to
  11179. // occur during these operations and the streaming thread correctly
  11180. // handles the errors.
  11181. if (not IsStopped) and (not IsFlushing) and
  11182. (not FRenderer.FAbort) and
  11183. (not FRunTimeError) then
  11184. begin
  11185. // EC_ERRORABORT's first parameter is the error which caused
  11186. // the event and its' last parameter is 0. See the Direct
  11187. // Show SDK documentation for more information.
  11188. FRenderer.NotifyEvent(EC_ERRORABORT, hr, 0);
  11189. FRenderer.FRendererLock.Lock;
  11190. try
  11191. if (FRenderer.IsStreaming and
  11192. (not FRenderer.IsEndOfStreamDelivered)) then
  11193. FRenderer.NotifyEndOfStream;
  11194. finally
  11195. FRenderer.FRendererLock.UnLock;
  11196. end;
  11197. FRunTimeError := True;
  11198. end;
  11199. finally
  11200. FRenderer.FInterfaceLock.UnLock;
  11201. end;
  11202. end;
  11203. Result := hr;
  11204. end;
  11205. function TBCRendererInputPin.InheritedReceive(MediaSample: IMediaSample): HResult;
  11206. begin
  11207. Result := Inherited Receive(MediaSample);
  11208. end;
  11209. // Called when the input pin is disconnected
  11210. function TBCRendererInputPin.BreakConnect: HResult;
  11211. begin
  11212. Result := FRenderer.BreakConnect;
  11213. if Succeeded(Result) then
  11214. Result := inherited BreakConnect;
  11215. end;
  11216. // Called when the input pin is connected
  11217. function TBCRendererInputPin.CompleteConnect(ReceivePin: IPin): HResult;
  11218. begin
  11219. Result := FRenderer.CompleteConnect(ReceivePin);
  11220. if Succeeded(Result) then
  11221. Result := inherited CompleteConnect(ReceivePin);
  11222. end;
  11223. // Give the pin id of our one and only pin
  11224. function TBCRendererInputPin.QueryId(out Id: PWideChar): HRESULT;
  11225. begin
  11226. // milenko start (AMGetWideString bugged before, so this call only will do fine now)
  11227. Result := AMGetWideString('In', Id);
  11228. // milenko end
  11229. end;
  11230. // Will the filter accept this media type
  11231. function TBCRendererInputPin.CheckMediaType(MediaType: PAMMediaType): HResult;
  11232. begin
  11233. Result := FRenderer.CheckMediaType(MediaType);
  11234. end;
  11235. // Called when we go paused or running
  11236. function TBCRendererInputPin.Active: HResult;
  11237. begin
  11238. Result := FRenderer.Active;
  11239. end;
  11240. // Called when we go into a stopped state
  11241. function TBCRendererInputPin.Inactive: HResult;
  11242. begin
  11243. // The caller must hold the interface lock because
  11244. // this function uses FRunTimeError.
  11245. {$IFDEF DEBUG}
  11246. Assert(FRenderer.FInterfaceLock.CritCheckIn);
  11247. {$ENDIF}
  11248. FRunTimeError := False;
  11249. Result := FRenderer.Inactive;
  11250. end;
  11251. // Tell derived classes about the media type agreed
  11252. function TBCRendererInputPin.SetMediaType(MediaType: PAMMediaType): HResult;
  11253. begin
  11254. Result := inherited SetMediaType(MediaType);
  11255. if Succeeded(Result) then
  11256. Result := FRenderer.SetMediaType(MediaType);
  11257. end;
  11258. // We do not keep an event object to use when setting up a timer link with
  11259. // the clock but are given a pointer to one by the owning object through the
  11260. // SetNotificationObject method - this must be initialised before starting
  11261. // We can override the default quality management process to have it always
  11262. // draw late frames, this is currently done by having the following registry
  11263. // key (actually an INI key) called DrawLateFrames set to 1 (default is 0)
  11264. (* ???
  11265. const TCHAR AMQUALITY[] = TEXT("ActiveMovie");
  11266. const TCHAR DRAWLATEFRAMES[] = TEXT("DrawLateFrames");
  11267. *)
  11268. resourcestring
  11269. AMQUALITY = 'ActiveMovie';
  11270. DRAWLATEFRAMES = 'DrawLateFrames';
  11271. constructor TBCBaseVideoRenderer.Create(RenderClass: TGUID; Name: PChar;
  11272. Unk: IUnknown; hr: HResult);
  11273. begin
  11274. // milenko start (not sure if this is really needed, but looks better)
  11275. // inherited;
  11276. inherited Create(RenderClass,Name,Unk,hr);
  11277. // milenko end
  11278. FFramesDropped := 0;
  11279. FFramesDrawn := 0;
  11280. FSupplierHandlingQuality:= False;
  11281. ResetStreamingTimes;
  11282. {$IFDEF PERF}
  11283. FTimeStamp := MSR_REGISTER('Frame time stamp');
  11284. FEarliness := MSR_REGISTER('Earliness fudge');
  11285. FTarget := MSR_REGISTER('Target(mSec)');
  11286. FSchLateTime := MSR_REGISTER('mSec late when scheduled');
  11287. FDecision := MSR_REGISTER('Scheduler decision code');
  11288. FQualityRate := MSR_REGISTER('Quality rate sent');
  11289. FQualityTime := MSR_REGISTER('Quality time sent');
  11290. FWaitReal := MSR_REGISTER('Render wait');
  11291. FWait := MSR_REGISTER('wait time recorded (msec)');
  11292. FFrameAccuracy := MSR_REGISTER('Frame accuracy(msecs)');
  11293. FDrawLateFrames := Boolean(GetProfileInt(PChar(AMQUALITY),
  11294. PChar(DRAWLATEFRAMES), Integer(False)));
  11295. FSendQuality := MSR_REGISTER('Processing Quality message');
  11296. FRenderAvg := MSR_REGISTER('Render draw time Avg');
  11297. FFrameAvg := MSR_REGISTER('FrameAvg');
  11298. FWaitAvg := MSR_REGISTER('WaitAvg');
  11299. FDuration := MSR_REGISTER('Duration');
  11300. FThrottle := MSR_REGISTER('Audio - video throttle wait');
  11301. FDebug := MSR_REGISTER('Debug stuff');
  11302. {$ENDIF}
  11303. end;
  11304. // Destructor is just a placeholder
  11305. destructor TBCBaseVideoRenderer.Destroy;
  11306. begin
  11307. Assert(FAdvisedCookie = 0);
  11308. // ??? seems should leave it, but...
  11309. // milenko start (not really needed...)
  11310. // inherited;
  11311. inherited Destroy;
  11312. // milenko end
  11313. end;
  11314. // The timing functions in this class are called by the window object and by
  11315. // the renderer's allocator.
  11316. // The windows object calls timing functions as it receives media sample
  11317. // images for drawing using GDI.
  11318. // The allocator calls timing functions when it starts passing DCI/DirectDraw
  11319. // surfaces which are not rendered in the same way; The decompressor writes
  11320. // directly to the surface with no separate rendering, so those code paths
  11321. // call direct into us. Since we only ever hand out DCI/DirectDraw surfaces
  11322. // when we have allocated one and only one image we know there cannot be any
  11323. // conflict between the two.
  11324. //
  11325. // We use timeGetTime to return the timing counts we use (since it's relative
  11326. // performance we are interested in rather than absolute compared to a clock)
  11327. // The window object sets the accuracy of the system clock (normally 1ms) by
  11328. // calling timeBeginPeriod/timeEndPeriod when it changes streaming states
  11329. // Reset all times controlling streaming.
  11330. // Set them so that
  11331. // 1. Frames will not initially be dropped
  11332. // 2. The first frame will definitely be drawn (achieved by saying that there
  11333. // has not ben a frame drawn for a long time).
  11334. function TBCBaseVideoRenderer.ResetStreamingTimes: HResult;
  11335. begin
  11336. FLastDraw := -1000; // set up as first frame since ages (1 sec) ago
  11337. FStreamingStart := timeGetTime;
  11338. FRenderAvg := 0;
  11339. FFrameAvg := -1; // -1000 fps :=:= "unset"
  11340. FDuration := 0; // 0 - strange value
  11341. FRenderLast := 0;
  11342. FWaitAvg := 0;
  11343. FRenderStart := 0;
  11344. FFramesDrawn := 0;
  11345. FFramesDropped := 0;
  11346. FTotAcc := 0;
  11347. FSumSqAcc := 0;
  11348. FSumSqFrameTime := 0;
  11349. FFrame := 0; // hygiene - not really needed
  11350. FLate := 0; // hygiene - not really needed
  11351. FSumFrameTime := 0;
  11352. FNormal := 0;
  11353. FEarliness := 0;
  11354. FTarget := -300000; // 30mSec early
  11355. FThrottle := 0;
  11356. FRememberStampForPerf := 0;
  11357. {$IFDEF PERF}
  11358. FRememberFrameForPerf := 0;
  11359. {$ENDIF}
  11360. Result := NOERROR;
  11361. end;
  11362. // Reset all times controlling streaming. Note that we're now streaming. We
  11363. // don't need to set the rendering event to have the source filter released
  11364. // as it is done during the Run processing. When we are run we immediately
  11365. // release the source filter thread and draw any image waiting (that image
  11366. // may already have been drawn once as a poster frame while we were paused)
  11367. function TBCBaseVideoRenderer.OnStartStreaming: HResult;
  11368. begin
  11369. ResetStreamingTimes;
  11370. Result := NOERROR;
  11371. end;
  11372. // Called at end of streaming. Fixes times for property page report
  11373. function TBCBaseVideoRenderer.OnStopStreaming: HResult;
  11374. begin
  11375. // milenko start (better to use int64 instead of integer)
  11376. // FStreamingStart := Integer(timeGetTime) - FStreamingStart;
  11377. FStreamingStart := Int64(timeGetTime) - FStreamingStart;
  11378. // milenko end
  11379. Result := NOERROR;
  11380. end;
  11381. // Called when we start waiting for a rendering event.
  11382. // Used to update times spent waiting and not waiting.
  11383. procedure TBCBaseVideoRenderer.OnWaitStart;
  11384. begin
  11385. {$IFDEF PERF}
  11386. MSR_START(FWaitReal);
  11387. {$ENDIF}
  11388. end;
  11389. // Called when we are awoken from the wait in the window OR by our allocator
  11390. // when it is hanging around until the next sample is due for rendering on a
  11391. // DCI/DirectDraw surface. We add the wait time into our rolling average.
  11392. // We grab the interface lock so that we're serialised with the application
  11393. // thread going through the run code - which in due course ends up calling
  11394. // ResetStreaming times - possibly as we run through this section of code
  11395. procedure TBCBaseVideoRenderer.OnWaitEnd;
  11396. {$IFDEF PERF}
  11397. var
  11398. RealStream, RefTime: TReferenceTime;
  11399. // the real time now expressed as stream time.
  11400. Late, Frame: Integer;
  11401. {$ENDIF}
  11402. begin
  11403. {$IFDEF PERF}
  11404. MSR_STOP(FWaitReal);
  11405. // for a perf build we want to know just exactly how late we REALLY are.
  11406. // even if this means that we have to look at the clock again.
  11407. {$IFDEF 0}
  11408. FClock.GetTime(RealStream); // Calling clock here causes W95 deadlock!
  11409. {$ELSE}
  11410. // We will be discarding overflows like mad here!
  11411. // This is wrong really because timeGetTime() can wrap but it's
  11412. // only for PERF
  11413. RefTime := timeGetTime * 10000;
  11414. RealStream := RefTime + FTimeOffset;
  11415. {$ENDIF}
  11416. Dec(RealStream, FStart); // convert to stream time (this is a reftime)
  11417. if (FRememberStampForPerf = 0) then
  11418. // This is probably the poster frame at the start, and it is not scheduled
  11419. // in the usual way at all. Just count it. The rememberstamp gets set
  11420. // in ShouldDrawSampleNow, so this does invalid frame recording until we
  11421. // actually start playing.
  11422. PreparePerformanceData(0, 0)
  11423. else
  11424. begin
  11425. Late := RealStream - FRememberStampForPerf;
  11426. Frame := RefTime - FRememberFrameForPerf;
  11427. PreparePerformanceData(Late, Frame);
  11428. end;
  11429. FRememberFrameForPerf := RefTime;
  11430. {$ENDIF}
  11431. end;
  11432. // Put data on one side that describes the lateness of the current frame.
  11433. // We don't yet know whether it will actually be drawn. In direct draw mode,
  11434. // this decision is up to the filter upstream, and it could change its mind.
  11435. // The rules say that if it did draw it must call Receive(). One way or
  11436. // another we eventually get into either OnRenderStart or OnDirectRender and
  11437. // these both call RecordFrameLateness to update the statistics.
  11438. procedure TBCBaseVideoRenderer.PreparePerformanceData(Late, Frame: Integer);
  11439. begin
  11440. FLate := Late;
  11441. FFrame := Frame;
  11442. end;
  11443. // update the statistics:
  11444. // m_iTotAcc, m_iSumSqAcc, m_iSumSqFrameTime, m_iSumFrameTime, m_cFramesDrawn
  11445. // Note that because the properties page reports using these variables,
  11446. // 1. We need to be inside a critical section
  11447. // 2. They must all be updated together. Updating the sums here and the count
  11448. // elsewhere can result in imaginary jitter (i.e. attempts to find square roots
  11449. // of negative numbers) in the property page code.
  11450. procedure TBCBaseVideoRenderer.RecordFrameLateness(Late, Frame: Integer);
  11451. var
  11452. _Late, _Frame: Integer;
  11453. begin
  11454. // Record how timely we are.
  11455. _Late := Late div 10000;
  11456. // Best estimate of moment of appearing on the screen is average of
  11457. // start and end draw times. Here we have only the end time. This may
  11458. // tend to show us as spuriously late by up to 1/2 frame rate achieved.
  11459. // Decoder probably monitors draw time. We don't bother.
  11460. {$IFDEF PERF}
  11461. MSR_INTEGER(FFrameAccuracy, _Late);
  11462. {$ENDIF}
  11463. // This is a kludge - we can get frames that are very late
  11464. // especially (at start-up) and they invalidate the statistics.
  11465. // So ignore things that are more than 1 sec off.
  11466. if (_Late > 1000) or (_Late < -1000) then
  11467. if (FFramesDrawn <= 1) then
  11468. _Late := 0
  11469. else if (_Late > 0) then
  11470. _Late := 1000
  11471. else
  11472. _Late := -1000;
  11473. // The very first frame often has a invalid time, so don't
  11474. // count it into the statistics. (???)
  11475. if (FFramesDrawn > 1) then
  11476. begin
  11477. Inc(FTotAcc, _Late);
  11478. Inc(FSumSqAcc, _Late * _Late);
  11479. end;
  11480. // calculate inter-frame time. Doesn't make sense for first frame
  11481. // second frame suffers from invalid first frame stamp.
  11482. if (FFramesDrawn > 2) then
  11483. begin
  11484. _Frame := Frame div 10000; // convert to mSec else it overflows
  11485. // This is a kludge. It can overflow anyway (a pause can cause
  11486. // a very long inter-frame time) and it overflows at 2**31/10**7
  11487. // or about 215 seconds i.e. 3min 35sec
  11488. if (_Frame > 1000) or (_Frame < 0) then
  11489. _Frame := 1000;
  11490. Inc(FSumSqFrameTime, _Frame * _Frame);
  11491. Assert(FSumSqFrameTime >= 0);
  11492. Inc(FSumFrameTime, _Frame);
  11493. end;
  11494. Inc(FFramesDrawn);
  11495. end;
  11496. procedure TBCBaseVideoRenderer.ThrottleWait;
  11497. var
  11498. Throttle: Integer;
  11499. begin
  11500. if (FThrottle > 0) then
  11501. begin
  11502. Throttle := FThrottle div 10000; // convert to mSec
  11503. MSR_INTEGER(FThrottle, Throttle);
  11504. {$IFDEF DEBUG}
  11505. DbgLog(Self, Format('Throttle %d ms', [Throttle]));
  11506. {$ENDIF}
  11507. Sleep(Throttle);
  11508. end
  11509. else
  11510. Sleep(0);
  11511. end;
  11512. // Whenever a frame is rendered it goes though either OnRenderStart
  11513. // or OnDirectRender. Data that are generated during ShouldDrawSample
  11514. // are added to the statistics by calling RecordFrameLateness from both
  11515. // these two places.
  11516. // Called in place of OnRenderStart..OnRenderEnd
  11517. // When a DirectDraw image is drawn
  11518. procedure TBCBaseVideoRenderer.OnDirectRender(MediaSample: IMediaSample);
  11519. begin
  11520. FRenderAvg := 0;
  11521. FRenderLast := 5000000; // If we mode switch, we do NOT want this
  11522. // to inhibit the new average getting going!
  11523. // so we set it to half a second
  11524. // MSR_INTEGER(m_idRenderAvg, m_trRenderAvg div 10000);
  11525. RecordFrameLateness(FLate, FFrame);
  11526. ThrottleWait;
  11527. end;
  11528. // Called just before we start drawing. All we do is to get the current clock
  11529. // time (from the system) and return. We have to store the start render time
  11530. // in a member variable because it isn't used until we complete the drawing
  11531. // The rest is just performance logging.
  11532. procedure TBCBaseVideoRenderer.OnRenderStart(MediaSample: IMediaSample);
  11533. begin
  11534. RecordFrameLateness(FLate, FFrame);
  11535. FRenderStart := timeGetTime;
  11536. end;
  11537. // Called directly after drawing an image. We calculate the time spent in the
  11538. // drawing code and if this doesn't appear to have any odd looking spikes in
  11539. // it then we add it to the current average draw time. Measurement spikes may
  11540. // occur if the drawing thread is interrupted and switched to somewhere else.
  11541. procedure TBCBaseVideoRenderer.OnRenderEnd(MediaSample: IMediaSample);
  11542. var
  11543. RefTime: Integer;
  11544. begin
  11545. // The renderer time can vary erratically if we are interrupted so we do
  11546. // some smoothing to help get more sensible figures out but even that is
  11547. // not enough as figures can go 9,10,9,9,83,9 and we must disregard 83
  11548. // milenko start
  11549. // RefTime := (Integer(timeGetTime) - FRenderStart) * 10000;
  11550. RefTime := (Int64(timeGetTime) - FRenderStart) * 10000;
  11551. // milenko end
  11552. // convert mSec->UNITS
  11553. if (RefTime < FRenderAvg * 2) or (RefTime < 2 * FRenderLast) then
  11554. // DO_MOVING_AVG(m_trRenderAvg, tr);
  11555. FRenderAvg := (RefTime + (AVGPERIOD - 1) * FRenderAvg) div AVGPERIOD;
  11556. FRenderLast := RefTime;
  11557. ThrottleWait;
  11558. end;
  11559. function TBCBaseVideoRenderer.SetSink(QualityControl: IQualityControl): HResult;
  11560. begin
  11561. FQSink := QualityControl;
  11562. Result := NOERROR;
  11563. end;
  11564. function TBCBaseVideoRenderer.Notify(Filter: IBaseFilter;
  11565. Q: TQuality): HResult;
  11566. begin
  11567. // NOTE: We are NOT getting any locks here. We could be called
  11568. // asynchronously and possibly even on a time critical thread of
  11569. // someone else's - so we do the minumum. We only set one state
  11570. // variable (an integer) and if that happens to be in the middle
  11571. // of another thread reading it they will just get either the new
  11572. // or the old value. Locking would achieve no more than this.
  11573. // It might be nice to check that we are being called from m_pGraph, but
  11574. // it turns out to be a millisecond or so per throw!
  11575. // This is heuristics, these numbers are aimed at being "what works"
  11576. // rather than anything based on some theory.
  11577. // We use a hyperbola because it's easy to calculate and it includes
  11578. // a panic button asymptote (which we push off just to the left)
  11579. // The throttling fits the following table (roughly)
  11580. // Proportion Throttle (msec)
  11581. // >=1000 0
  11582. // 900 3
  11583. // 800 7
  11584. // 700 11
  11585. // 600 17
  11586. // 500 25
  11587. // 400 35
  11588. // 300 50
  11589. // 200 72
  11590. // 125 100
  11591. // 100 112
  11592. // 50 146
  11593. // 0 200
  11594. // (some evidence that we could go for a sharper kink - e.g. no throttling
  11595. // until below the 750 mark - might give fractionally more frames on a
  11596. // P60-ish machine). The easy way to get these coefficients is to use
  11597. // Renbase.xls follow the instructions therein using excel solver.
  11598. if (q.Proportion >= 1000) then
  11599. FThrottle := 0
  11600. else
  11601. // The DWORD is to make quite sure I get unsigned arithmetic
  11602. // as the constant is between 2**31 and 2**32
  11603. FThrottle := -330000 + (388880000 div (q.Proportion + 167));
  11604. Result := NOERROR;
  11605. end;
  11606. // Send a message to indicate what our supplier should do about quality.
  11607. // Theory:
  11608. // What a supplier wants to know is "is the frame I'm working on NOW
  11609. // going to be late?".
  11610. // F1 is the frame at the supplier (as above)
  11611. // Tf1 is the due time for F1
  11612. // T1 is the time at that point (NOW!)
  11613. // Tr1 is the time that f1 WILL actually be rendered
  11614. // L1 is the latency of the graph for frame F1 = Tr1-T1
  11615. // D1 (for delay) is how late F1 will be beyond its due time i.e.
  11616. // D1 = (Tr1-Tf1) which is what the supplier really wants to know.
  11617. // Unfortunately Tr1 is in the future and is unknown, so is L1
  11618. //
  11619. // We could estimate L1 by its value for a previous frame,
  11620. // L0 = Tr0-T0 and work off
  11621. // D1' = ((T1+L0)-Tf1) = (T1 + (Tr0-T0) -Tf1)
  11622. // Rearranging terms:
  11623. // D1' = (T1-T0) + (Tr0-Tf1)
  11624. // adding (Tf0-Tf0) and rearranging again:
  11625. // = (T1-T0) + (Tr0-Tf0) + (Tf0-Tf1)
  11626. // = (T1-T0) - (Tf1-Tf0) + (Tr0-Tf0)
  11627. // But (Tr0-Tf0) is just D0 - how late frame zero was, and this is the
  11628. // Late field in the quality message that we send.
  11629. // The other two terms just state what correction should be applied before
  11630. // using the lateness of F0 to predict the lateness of F1.
  11631. // (T1-T0) says how much time has actually passed (we have lost this much)
  11632. // (Tf1-Tf0) says how much time should have passed if we were keeping pace
  11633. // (we have gained this much).
  11634. //
  11635. // Suppliers should therefore work off:
  11636. // Quality.Late + (T1-T0) - (Tf1-Tf0)
  11637. // and see if this is "acceptably late" or even early (i.e. negative).
  11638. // They get T1 and T0 by polling the clock, they get Tf1 and Tf0 from
  11639. // the time stamps in the frames. They get Quality.Late from us.
  11640. //
  11641. function TBCBaseVideoRenderer.SendQuality(Late,
  11642. RealStream: TReferenceTime): HResult;
  11643. var
  11644. q: TQuality;
  11645. hr: HResult;
  11646. QC: IQualityControl;
  11647. OutputPin: IPin;
  11648. begin
  11649. // If we are the main user of time, then report this as Flood/Dry.
  11650. // If our suppliers are, then report it as Famine/Glut.
  11651. //
  11652. // We need to take action, but avoid hunting. Hunting is caused by
  11653. // 1. Taking too much action too soon and overshooting
  11654. // 2. Taking too long to react (so averaging can CAUSE hunting).
  11655. //
  11656. // The reason why we use trLate as well as Wait is to reduce hunting;
  11657. // if the wait time is coming down and about to go into the red, we do
  11658. // NOT want to rely on some average which is only telling is that it used
  11659. // to be OK once.
  11660. q.TimeStamp := RealStream;
  11661. if (FFrameAvg < 0) then
  11662. q.Typ := Famine // guess
  11663. // Is the greater part of the time taken bltting or something else
  11664. else if (FFrameAvg > 2 * FRenderAvg) then
  11665. q.Typ := Famine // mainly other
  11666. else
  11667. q.Typ := Flood; // mainly bltting
  11668. q.Proportion := 1000; // default
  11669. if (FFrameAvg < 0) then
  11670. // leave it alone - we don't know enough
  11671. else if (Late > 0) then
  11672. begin
  11673. // try to catch up over the next second
  11674. // We could be Really, REALLY late, but rendering all the frames
  11675. // anyway, just because it's so cheap.
  11676. q.Proportion := 1000 - (Late div (UNITS div 1000));
  11677. if (q.Proportion < 500) then
  11678. q.Proportion := 500; // don't go daft. (could've been negative!)
  11679. end
  11680. // milenko start
  11681. else if (FWaitAvg > 20000) and (Late < -20000) then
  11682. begin
  11683. // if (FWaitAvg > 20000) and (Late < -20000) then
  11684. // Go cautiously faster - aim at 2mSec wait.
  11685. if (FWaitAvg >= FFrameAvg) then
  11686. begin
  11687. // This can happen because of some fudges.
  11688. // The waitAvg is how long we originally planned to wait
  11689. // The frameAvg is more honest.
  11690. // It means that we are spending a LOT of time waiting
  11691. q.Proportion := 2000 // double.
  11692. end else
  11693. begin
  11694. if (FFrameAvg + 20000 > FWaitAvg) then
  11695. q.Proportion := 1000 * (FFrameAvg div (FFrameAvg + 20000 - FWaitAvg))
  11696. else
  11697. // We're apparently spending more than the whole frame time waiting.
  11698. // Assume that the averages are slightly out of kilter, but that we
  11699. // are indeed doing a lot of waiting. (This leg probably never
  11700. // happens, but the code avoids any potential divide by zero).
  11701. q.Proportion := 2000;
  11702. end;
  11703. if (q.Proportion > 2000) then
  11704. q.Proportion := 2000; // don't go crazy.
  11705. end;
  11706. // milenko end
  11707. // Tell the supplier how late frames are when they get rendered
  11708. // That's how late we are now.
  11709. // If we are in directdraw mode then the guy upstream can see the drawing
  11710. // times and we'll just report on the start time. He can figure out any
  11711. // offset to apply. If we are in DIB Section mode then we will apply an
  11712. // extra offset which is half of our drawing time. This is usually small
  11713. // but can sometimes be the dominant effect. For this we will use the
  11714. // average drawing time rather than the last frame. If the last frame took
  11715. // a long time to draw and made us late, that's already in the lateness
  11716. // figure. We should not add it in again unless we expect the next frame
  11717. // to be the same. We don't, we expect the average to be a better shot.
  11718. // In direct draw mode the RenderAvg will be zero.
  11719. q.Late := Late + FRenderAvg div 2;
  11720. {$IFDEF PERF}
  11721. // log what we're doing
  11722. MSR_INTEGER(FQualityRate, q.Proportion);
  11723. MSR_INTEGER(FQualityTime, refTimeToMiliSec(q.Late));
  11724. {$ENDIF}
  11725. // A specific sink interface may be set through IPin
  11726. if (FQSink = nil) then
  11727. begin
  11728. // Get our input pin's peer. We send quality management messages
  11729. // to any nominated receiver of these things (set in the IPin
  11730. // interface), or else to our source filter.
  11731. QC := nil;
  11732. OutputPin := FInputPin.GetConnected;
  11733. Assert(Assigned(OutputPin));
  11734. // And get an AddRef'd quality control interface
  11735. hr := OutputPin.QueryInterface(IID_IQualityControl, QC);
  11736. if Succeeded(hr) then
  11737. FQSink := QC;
  11738. end;
  11739. if Assigned(FQSink) then
  11740. Result := FQSink.Notify(Self, q)
  11741. else
  11742. Result := S_FALSE;
  11743. end;
  11744. // We are called with a valid IMediaSample image to decide whether this is to
  11745. // be drawn or not. There must be a reference clock in operation.
  11746. // Return S_OK if it is to be drawn Now (as soon as possible)
  11747. // Return S_FALSE if it is to be drawn when it's due
  11748. // Return an error if we want to drop it
  11749. // m_nNormal=-1 indicates that we dropped the previous frame and so this
  11750. // one should be drawn early. Respect it and update it.
  11751. // Use current stream time plus a number of heuristics (detailed below)
  11752. // to make the decision
  11753. (* ??? StartTime is changing inside routine:
  11754. Inc(StartTime, E); // N.B. earliness is negative
  11755. So, maybe it should be declared as var or out?
  11756. *)
  11757. function TBCBaseVideoRenderer.ShouldDrawSampleNow(MediaSample: IMediaSample;
  11758. StartTime: TReferenceTime; out EndTime: TReferenceTime): HResult;
  11759. var
  11760. RealStream: TReferenceTime; // the real time now expressed as stream time.
  11761. RefTime: TReferenceTime;
  11762. TrueLate, Late, Duration, t, WaitAvg, L, Frame, E, Delay
  11763. {$IFNDEF PERF} , Accuracy{$ENDIF}: Integer;
  11764. hr: HResult;
  11765. JustDroppedFrame, Res, PlayASAP: Boolean;
  11766. begin
  11767. // Don't call us unless there's a clock interface to synchronise with
  11768. Assert(Assigned(FClock));
  11769. {$IFDEF PERF}
  11770. MSR_INTEGER(FTimeStamp, Integer(StartTime shr 32)); // high order 32 bits
  11771. MSR_INTEGER(FTimeStamp, Integer(StartTime)); // low order 32 bits
  11772. {$ENDIF}
  11773. // We lose a bit of time depending on the monitor type waiting for the next
  11774. // screen refresh. On average this might be about 8mSec - so it will be
  11775. // later than we think when the picture appears. To compensate a bit
  11776. // we bias the media samples by -8mSec i.e. 80000 UNITs.
  11777. // We don't ever make a stream time negative (call it paranoia)
  11778. if (StartTime >= 80000) then
  11779. begin
  11780. Dec(StartTime, 80000);
  11781. Dec(EndTime, 80000); // bias stop to to retain valid frame duration
  11782. end;
  11783. // Cache the time stamp now. We will want to compare what we did with what
  11784. // we started with (after making the monitor allowance).
  11785. FRememberStampForPerf := StartTime;
  11786. // Get reference times (current and late)
  11787. FClock.GetTime(int64(RealStream));
  11788. {$IFDEF PERF}
  11789. // While the reference clock is expensive:
  11790. // Remember the offset from timeGetTime and use that.
  11791. // This overflows all over the place, but when we subtract to get
  11792. // differences the overflows all cancel out.
  11793. FTimeOffset := RealStream - timeGetTime * 10000;
  11794. {$ENDIF}
  11795. Dec(RealStream, FStart); // convert to stream time (this is a reftime)
  11796. // We have to wory about two versions of "lateness". The truth, which we
  11797. // try to work out here and the one measured against m_trTarget which
  11798. // includes long term feedback. We report statistics against the truth
  11799. // but for operational decisions we work to the target.
  11800. // We use TimeDiff to make sure we get an integer because we
  11801. // may actually be late (or more likely early if there is a big time
  11802. // gap) by a very long time.
  11803. TrueLate := TimeDiff(RealStream - StartTime);
  11804. Late := TrueLate;
  11805. {$IFDEF PERF}
  11806. MSR_INTEGER(FSchLateTime, refTimeToMiliSec(TrueLate));
  11807. {$ENDIF}
  11808. // Send quality control messages upstream, measured against target
  11809. hr := SendQuality(Late, RealStream);
  11810. // Note: the filter upstream is allowed to this FAIL meaning "you do it".
  11811. FSupplierHandlingQuality := (hr = S_OK);
  11812. // Decision time! Do we drop, draw when ready or draw immediately?
  11813. Duration := EndTime - StartTime;
  11814. // We need to see if the frame rate of the file has just changed.
  11815. // This would make comparing our previous frame rate with the current
  11816. // frame rate inefficent. Hang on a moment though. I've seen files
  11817. // where the frames vary between 33 and 34 mSec so as to average
  11818. // 30fps. A minor variation like that won't hurt us.
  11819. t := FDuration div 32;
  11820. if (Duration > FDuration + t) or (Duration < FDuration - t) then
  11821. begin
  11822. // There's a major variation. Reset the average frame rate to
  11823. // exactly the current rate to disable decision 9002 for this frame,
  11824. // and remember the new rate.
  11825. FFrameAvg := Duration;
  11826. FDuration := Duration;
  11827. end;
  11828. {$IFDEF PERF}
  11829. MSR_INTEGER(FEarliness, refTimeToMiliSec(FEarliness));
  11830. MSR_INTEGER(FRenderAvg, refTimeToMiliSec(FRenderAvg));
  11831. MSR_INTEGER(FFrameAvg, refTimeToMiliSec(FFrameAvg));
  11832. MSR_INTEGER(FWaitAvg, refTimeToMiliSec(FWaitAvg));
  11833. MSR_INTEGER(FDuration, refTimeToMiliSec(FDuration));
  11834. if (S_OK = MediaSample.IsDiscontinuity) then
  11835. MSR_INTEGER(FDecision, 9000);
  11836. {$ENDIF}
  11837. // Control the graceful slide back from slow to fast machine mode.
  11838. // After a frame drop accept an early frame and set the earliness to here
  11839. // If this frame is already later than the earliness then slide it to here
  11840. // otherwise do the standard slide (reduce by about 12% per frame).
  11841. // Note: earliness is normally NEGATIVE
  11842. JustDroppedFrame :=
  11843. (FSupplierHandlingQuality and
  11844. // Can't use the pin sample properties because we might
  11845. // not be in Receive when we call this
  11846. (S_OK = MediaSample.IsDiscontinuity) // he just dropped one
  11847. ) or
  11848. (FNormal = -1); // we just dropped one
  11849. // Set m_trEarliness (slide back from slow to fast machine mode)
  11850. if (Late > 0) then
  11851. FEarliness := 0 // we are no longer in fast machine mode at all!
  11852. else if ((Late >= FEarliness) or JustDroppedFrame) then
  11853. FEarliness := Late // Things have slipped of their own accord
  11854. else
  11855. FEarliness := FEarliness - FEarliness div 8; // graceful slide
  11856. // prepare the new wait average - but don't pollute the old one until
  11857. // we have finished with it.
  11858. // We never mix in a negative wait. This causes us to believe in fast machines
  11859. // slightly more.
  11860. if (Late < 0) then
  11861. L := -Late
  11862. else
  11863. L := 0;
  11864. WaitAvg := (L + FWaitAvg * (AVGPERIOD - 1)) div AVGPERIOD;
  11865. RefTime := RealStream - FLastDraw; // Cd be large - 4 min pause!
  11866. if (RefTime > 10000000) then
  11867. RefTime := 10000000; // 1 second - arbitrarily.
  11868. Frame := RefTime;
  11869. if FSupplierHandlingQuality then
  11870. Res := (Late <= Duration * 4)
  11871. else
  11872. Res := (Late + Late < Duration);
  11873. // We will DRAW this frame IF...
  11874. if (
  11875. // ...the time we are spending drawing is a small fraction of the total
  11876. // observed inter-frame time so that dropping it won't help much.
  11877. (3 * FRenderAvg <= FFrameAvg)
  11878. // ...or our supplier is NOT handling things and the next frame would
  11879. // be less timely than this one or our supplier CLAIMS to be handling
  11880. // things, and is now less than a full FOUR frames late.
  11881. or Res
  11882. // ...or we are on average waiting for over eight milliseconds then
  11883. // this may be just a glitch. Draw it and we'll hope to catch up.
  11884. or (FWaitAvg > 80000)
  11885. // ...or we haven't drawn an image for over a second. We will update
  11886. // the display, which stops the video looking hung.
  11887. // Do this regardless of how late this media sample is.
  11888. or ((RealStream - FLastDraw) > UNITS)
  11889. ) then
  11890. begin
  11891. // We are going to play this frame. We may want to play it early.
  11892. // We will play it early if we think we are in slow machine mode.
  11893. // If we think we are NOT in slow machine mode, we will still play
  11894. // it early by m_trEarliness as this controls the graceful slide back.
  11895. // and in addition we aim at being m_trTarget late rather than "on time".
  11896. PlayASAP := False;
  11897. // we will play it AT ONCE (slow machine mode) if...
  11898. // ...we are playing catch-up
  11899. if (JustDroppedFrame) then
  11900. begin
  11901. PlayASAP := True;
  11902. {$IFDEF PERF}
  11903. MSR_INTEGER(FDecision, 9001);
  11904. {$ENDIF}
  11905. end
  11906. // ...or if we are running below the true frame rate
  11907. // exact comparisons are glitchy, for these measurements,
  11908. // so add an extra 5% or so
  11909. else if (FFrameAvg > Duration + Duration div 16)
  11910. // It's possible to get into a state where we are losing ground, but
  11911. // are a very long way ahead. To avoid this or recover from it
  11912. // we refuse to play early by more than 10 frames.
  11913. and (Late > -Duration * 10) then
  11914. begin
  11915. PlayASAP := True;
  11916. {$IFDEF PERF}
  11917. MSR_INTEGER(FDecision, 9002);
  11918. {$ENDIF}
  11919. end
  11920. {$IFDEF 0}
  11921. // ...or if we have been late and are less than one frame early
  11922. else if ((Late + Duration > 0) and
  11923. (FWaitAvg <= 20000) then
  11924. begin
  11925. PlayASAP := True;
  11926. {$IFDEF PERF}
  11927. MSR_INTEGER(m_idDecision, 9003);
  11928. {$ENDIF}
  11929. end
  11930. {$ENDIF}
  11931. ;
  11932. // We will NOT play it at once if we are grossly early. On very slow frame
  11933. // rate movies - e.g. clock.avi - it is not a good idea to leap ahead just
  11934. // because we got starved (for instance by the net) and dropped one frame
  11935. // some time or other. If we are more than 900mSec early, then wait.
  11936. if (Late < -9000000) then
  11937. PlayASAP := False;
  11938. if PlayASAP then
  11939. begin
  11940. FNormal := 0;
  11941. {$IFDEF PERF}
  11942. MSR_INTEGER(FDecision, 0);
  11943. {$ENDIF}
  11944. // When we are here, we are in slow-machine mode. trLate may well
  11945. // oscillate between negative and positive when the supplier is
  11946. // dropping frames to keep sync. We should not let that mislead
  11947. // us into thinking that we have as much as zero spare time!
  11948. // We just update with a zero wait.
  11949. FWaitAvg := (FWaitAvg * (AVGPERIOD - 1)) div AVGPERIOD;
  11950. // Assume that we draw it immediately. Update inter-frame stats
  11951. FFrameAvg := (Frame + FFrameAvg * (AVGPERIOD - 1)) div AVGPERIOD;
  11952. {$IFNDEF PERF}
  11953. // If this is NOT a perf build, then report what we know so far
  11954. // without looking at the clock any more. This assumes that we
  11955. // actually wait for exactly the time we hope to. It also reports
  11956. // how close we get to the manipulated time stamps that we now have
  11957. // rather than the ones we originally started with. It will
  11958. // therefore be a little optimistic. However it's fast.
  11959. PreparePerformanceData(TrueLate, Frame);
  11960. {$ENDIF}
  11961. FLastDraw := RealStream;
  11962. if (FEarliness > Late) then
  11963. FEarliness := Late; // if we are actually early, this is neg
  11964. Result := S_OK; // Draw it now
  11965. end
  11966. else
  11967. begin
  11968. Inc(FNormal);
  11969. // Set the average frame rate to EXACTLY the ideal rate.
  11970. // If we are exiting slow-machine mode then we will have caught up
  11971. // and be running ahead, so as we slide back to exact timing we will
  11972. // have a longer than usual gap at this point. If we record this
  11973. // real gap then we'll think that we're running slow and go back
  11974. // into slow-machine mode and vever get it straight.
  11975. FFrameAvg := Duration;
  11976. {$IFDEF PERF}
  11977. MSR_INTEGER(FDecision, 1);
  11978. {$ENDIF}
  11979. // Play it early by m_trEarliness and by m_trTarget
  11980. E := FEarliness;
  11981. if (E < -FFrameAvg) then
  11982. E := -FFrameAvg;
  11983. Inc(StartTime, E); // N.B. earliness is negative
  11984. Delay := -TrueLate;
  11985. if (Delay <= 0) then
  11986. Result := S_OK
  11987. else
  11988. Result := S_FALSE; // OK = draw now, FALSE = wait
  11989. FWaitAvg := WaitAvg;
  11990. // Predict when it will actually be drawn and update frame stats
  11991. if (Result = S_FALSE) then // We are going to wait
  11992. begin
  11993. {$IFNDEF PERF}
  11994. Frame := TimeDiff(StartTime - FLastDraw);
  11995. {$ENDIF}
  11996. FLastDraw := StartTime;
  11997. end
  11998. else
  11999. // trFrame is already = trRealStream-m_trLastDraw;
  12000. FLastDraw := RealStream;
  12001. {$IFNDEF PERF}
  12002. if (Delay > 0) then
  12003. // Report lateness based on when we intend to play it
  12004. Accuracy := TimeDiff(StartTime - FRememberStampForPerf)
  12005. else
  12006. // Report lateness based on playing it *now*.
  12007. Accuracy := TrueLate; // trRealStream-RememberStampForPerf;
  12008. PreparePerformanceData(Accuracy, Frame);
  12009. {$ENDIF}
  12010. end;
  12011. Exit;
  12012. end;
  12013. // We are going to drop this frame!
  12014. // Of course in DirectDraw mode the guy upstream may draw it anyway.
  12015. // This will probably give a large negative wack to the wait avg.
  12016. FWaitAvg := WaitAvg;
  12017. {$IFDEF PERF}
  12018. // Respect registry setting - debug only!
  12019. if (FDrawLateFrames) then
  12020. begin
  12021. Result := S_OK; // draw it when it's ready
  12022. // even though it's late.
  12023. Exit;
  12024. end;
  12025. {$ENDIF}
  12026. // We are going to drop this frame so draw the next one early
  12027. // n.b. if the supplier is doing direct draw then he may draw it anyway
  12028. // but he's doing something funny to arrive here in that case.
  12029. {$IFDEF PERF}
  12030. MSR_INTEGER(FDecision, 2);
  12031. {$ENDIF}
  12032. FNormal := -1;
  12033. Result := E_FAIL; // drop it
  12034. end;
  12035. // NOTE we're called by both the window thread and the source filter thread
  12036. // so we have to be protected by a critical section (locked before called)
  12037. // Also, when the window thread gets signalled to render an image, it always
  12038. // does so regardless of how late it is. All the degradation is done when we
  12039. // are scheduling the next sample to be drawn. Hence when we start an advise
  12040. // link to draw a sample, that sample's time will always become the last one
  12041. // drawn - unless of course we stop streaming in which case we cancel links
  12042. function TBCBaseVideoRenderer.ScheduleSample(MediaSample: IMediaSample):
  12043. Boolean;
  12044. begin
  12045. // We override ShouldDrawSampleNow to add quality management
  12046. Result := inherited ScheduleSample(MediaSample);
  12047. if not Result then
  12048. Inc(FFramesDropped);
  12049. // m_cFramesDrawn must NOT be updated here. It has to be updated
  12050. // in RecordFrameLateness at the same time as the other statistics.
  12051. end;
  12052. // Implementation of IQualProp interface needed to support the property page
  12053. // This is how the property page gets the data out of the scheduler. We are
  12054. // passed into the constructor the owning object in the COM sense, this will
  12055. // either be the video renderer or an external IUnknown if we're aggregated.
  12056. // We initialise our CUnknown base class with this interface pointer. Then
  12057. // all we have to do is to override NonDelegatingQueryInterface to expose
  12058. // our IQualProp interface. The AddRef and Release are handled automatically
  12059. // by the base class and will be passed on to the appropriate outer object
  12060. function TBCBaseVideoRenderer.get_FramesDroppedInRenderer(var FramesDropped:
  12061. Integer): HResult;
  12062. begin
  12063. // milenko start
  12064. if not Assigned(@FramesDropped) then
  12065. begin
  12066. Result := E_POINTER;
  12067. Exit;
  12068. end;
  12069. // milenko end
  12070. FInterfaceLock.Lock;
  12071. try
  12072. FramesDropped := FFramesDropped;
  12073. Result := NOERROR;
  12074. finally
  12075. FInterfaceLock.UnLock;
  12076. end;
  12077. end;
  12078. // Set *pcFramesDrawn to the number of frames drawn since
  12079. // streaming started.
  12080. function TBCBaseVideoRenderer.get_FramesDrawn(out FramesDrawn: Integer):
  12081. HResult;
  12082. begin
  12083. // milenko start
  12084. if not Assigned(@FramesDrawn) then
  12085. begin
  12086. Result := E_POINTER;
  12087. Exit;
  12088. end;
  12089. // milenko end
  12090. FInterfaceLock.Lock;
  12091. try
  12092. FramesDrawn := FFramesDrawn;
  12093. Result := NOERROR;
  12094. finally
  12095. FInterfaceLock.UnLock;
  12096. end;
  12097. end;
  12098. // Set iAvgFrameRate to the frames per hundred secs since
  12099. // streaming started. 0 otherwise.
  12100. function TBCBaseVideoRenderer.get_AvgFrameRate(out AvgFrameRate: Integer):
  12101. HResult;
  12102. var
  12103. t: Integer;
  12104. begin
  12105. // milenko start
  12106. if not Assigned(@AvgFrameRate) then
  12107. begin
  12108. Result := E_POINTER;
  12109. Exit;
  12110. end;
  12111. // milenko end
  12112. FInterfaceLock.Lock;
  12113. try
  12114. if (FIsStreaming) then
  12115. // milenko start
  12116. // t := Integer(timeGetTime) - FStreamingStart
  12117. t := Int64(timeGetTime) - FStreamingStart
  12118. // milenko end
  12119. else
  12120. t := FStreamingStart;
  12121. if (t <= 0) then
  12122. begin
  12123. AvgFrameRate := 0;
  12124. Assert(FFramesDrawn = 0);
  12125. end
  12126. else
  12127. // i is frames per hundred seconds
  12128. AvgFrameRate := MulDiv(100000, FFramesDrawn, t);
  12129. Result := NOERROR;
  12130. finally
  12131. FInterfaceLock.UnLock;
  12132. end;
  12133. end;
  12134. // Set *piAvg to the average sync offset since streaming started
  12135. // in mSec. The sync offset is the time in mSec between when the frame
  12136. // should have been drawn and when the frame was actually drawn.
  12137. function TBCBaseVideoRenderer.get_AvgSyncOffset(out Avg: Integer): HResult;
  12138. begin
  12139. // milenko start
  12140. if not Assigned(@Avg) then
  12141. begin
  12142. Result := E_POINTER;
  12143. Exit;
  12144. end;
  12145. // milenko end
  12146. FInterfaceLock.Lock;
  12147. try
  12148. if (nil = FClock) then
  12149. begin
  12150. Avg := 0;
  12151. Result := NOERROR;
  12152. Exit;
  12153. end;
  12154. // Note that we didn't gather the stats on the first frame
  12155. // so we use m_cFramesDrawn-1 here
  12156. if (FFramesDrawn <= 1) then
  12157. Avg := 0
  12158. else
  12159. Avg := (FTotAcc div (FFramesDrawn - 1));
  12160. Result := NOERROR;
  12161. finally
  12162. FInterfaceLock.UnLock;
  12163. end;
  12164. end;
  12165. // To avoid dragging in the maths library - a cheap
  12166. // approximate integer square root.
  12167. // We do this by getting a starting guess which is between 1
  12168. // and 2 times too large, followed by THREE iterations of
  12169. // Newton Raphson. (That will give accuracy to the nearest mSec
  12170. // for the range in question - roughly 0..1000)
  12171. //
  12172. // It would be faster to use a linear interpolation and ONE NR, but
  12173. // who cares. If anyone does - the best linear interpolation is
  12174. // to approximates sqrt(x) by
  12175. // y = x * (sqrt(2)-1) + 1 - 1/sqrt(2) + 1/(8*(sqrt(2)-1))
  12176. // 0r y = x*0.41421 + 0.59467
  12177. // This minimises the maximal error in the range in question.
  12178. // (error is about +0.008883 and then one NR will give error .0000something
  12179. // (Of course these are integers, so you can't just multiply by 0.41421
  12180. // you'd have to do some sort of MulDiv).
  12181. // Anyone wanna check my maths? (This is only for a property display!)
  12182. function isqrt(x: Integer): Integer;
  12183. var
  12184. s: Integer;
  12185. begin
  12186. s := 1;
  12187. // Make s an initial guess for sqrt(x)
  12188. if (x > $40000000) then
  12189. s := $8000 // prevent any conceivable closed loop
  12190. else
  12191. begin
  12192. while (s * s < x) do // loop cannot possible go more than 31 times
  12193. s := 2 * s; // normally it goes about 6 times
  12194. // Three NR iterations.
  12195. if (x = 0) then
  12196. s := 0 // Wouldn't it be tragic to divide by zero whenever our
  12197. // accuracy was perfect!
  12198. else
  12199. begin
  12200. s := (s * s + x) div (2 * s);
  12201. if (s >= 0) then
  12202. s := (s * s + x) div (2 * s);
  12203. if (s >= 0) then
  12204. s := (s * s + x) div (2 * s);
  12205. end;
  12206. end;
  12207. Result := s;
  12208. end;
  12209. //
  12210. // Do estimates for standard deviations for per-frame
  12211. // statistics
  12212. //
  12213. function TBCBaseVideoRenderer.GetStdDev(Samples: Integer; out Res: Integer;
  12214. SumSq, Tot: Int64): HResult;
  12215. var
  12216. x: Int64;
  12217. begin
  12218. // milenko start
  12219. if not Assigned(@Res) then
  12220. begin
  12221. Result := E_POINTER;
  12222. Exit;
  12223. end;
  12224. // milenko end
  12225. FInterfaceLock.Lock;
  12226. try
  12227. if (nil = FClock) then
  12228. begin
  12229. Res := 0;
  12230. Result := NOERROR;
  12231. Exit;
  12232. end;
  12233. // If S is the Sum of the Squares of observations and
  12234. // T the Total (i.e. sum) of the observations and there were
  12235. // N observations, then an estimate of the standard deviation is
  12236. // sqrt( (S - T**2/N) / (N-1) )
  12237. if (Samples <= 1) then
  12238. Res := 0
  12239. else
  12240. begin
  12241. // First frames have invalid stamps, so we get no stats for them
  12242. // So we need 2 frames to get 1 datum, so N is cFramesDrawn-1
  12243. // so we use m_cFramesDrawn-1 here
  12244. // ??? llMilDiv ???
  12245. // milenko start (removed the 2 outputdebugstring messages...i added them and
  12246. // they are not needed anymore)
  12247. x := SumSq - llMulDiv(Tot, Tot, Samples, 0);
  12248. x := x div (Samples - 1);
  12249. // milenko end
  12250. Assert(x >= 0);
  12251. Res := isqrt(Longint(x));
  12252. end;
  12253. Result := NOERROR;
  12254. finally
  12255. FInterfaceLock.UnLock;
  12256. end;
  12257. end;
  12258. // Set *piDev to the standard deviation in mSec of the sync offset
  12259. // of each frame since streaming started.
  12260. function TBCBaseVideoRenderer.get_DevSyncOffset(out Dev: Integer): HResult;
  12261. begin
  12262. // First frames have invalid stamps, so we get no stats for them
  12263. // So we need 2 frames to get 1 datum, so N is cFramesDrawn-1
  12264. Result := GetStdDev(FFramesDrawn - 1, Dev, FSumSqAcc, FTotAcc);
  12265. end;
  12266. // Set *piJitter to the standard deviation in mSec of the inter-frame time
  12267. // of frames since streaming started.
  12268. function TBCBaseVideoRenderer.get_Jitter(out Jitter: Integer): HResult;
  12269. begin
  12270. // First frames have invalid stamps, so we get no stats for them
  12271. // So second frame gives invalid inter-frame time
  12272. // So we need 3 frames to get 1 datum, so N is cFramesDrawn-2
  12273. Result := GetStdDev(FFramesDrawn - 2, Jitter, FSumSqFrameTime, FSumFrameTime);
  12274. end;
  12275. // Overidden to return our IQualProp interface
  12276. function TBCBaseVideoRenderer.NonDelegatingQueryInterface(const IID: TGUID;
  12277. out Obj): HResult;
  12278. begin
  12279. // We return IQualProp and delegate everything else
  12280. if IsEqualGUID(IID, IID_IQualProp) then
  12281. if GetInterface(IID_IQualProp, Obj) then
  12282. Result := S_OK
  12283. else
  12284. Result := E_FAIL
  12285. else if IsEqualGUID(IID, IID_IQualityControl) then
  12286. if GetInterface(IID_IQualityControl, Obj) then
  12287. Result := S_OK
  12288. else
  12289. Result := E_FAIL
  12290. else
  12291. Result := inherited NonDelegatingQueryInterface(IID, Obj);
  12292. end;
  12293. // Override JoinFilterGraph so that, just before leaving
  12294. // the graph we can send an EC_WINDOW_DESTROYED event
  12295. function TBCBaseVideoRenderer.JoinFilterGraph(Graph: IFilterGraph;
  12296. Name: PWideChar): HResult;
  12297. var
  12298. Filter: IBaseFilter;
  12299. begin
  12300. // Since we send EC_ACTIVATE, we also need to ensure
  12301. // we send EC_WINDOW_DESTROYED or the resource manager may be
  12302. // holding us as a focus object
  12303. if (Graph = nil) and Assigned(FGraph) then
  12304. begin
  12305. // We were in a graph and now we're not
  12306. // Do this properly in case we are aggregated
  12307. QueryInterface(IID_IBaseFilter, Filter);
  12308. NotifyEvent(EC_WINDOW_DESTROYED, Integer(Filter), 0);
  12309. Filter := nil;
  12310. end;
  12311. Result := inherited JoinFilterGraph(Graph, Name);
  12312. end;
  12313. // milenko start (added TBCPullPin)
  12314. constructor TBCPullPin.Create;
  12315. begin
  12316. inherited Create;
  12317. FReader := nil;
  12318. FAlloc := nil;
  12319. FState := TM_Exit;
  12320. end;
  12321. destructor TBCPullPin.Destroy;
  12322. begin
  12323. Disconnect;
  12324. end;
  12325. procedure TBCPullPin.Process;
  12326. var
  12327. Discontinuity: Boolean;
  12328. Actual: TAllocatorProperties;
  12329. hr: HRESULT;
  12330. Start, Stop, Current, AlignStop: TReferenceTime;
  12331. Request: DWORD;
  12332. Sample: IMediaSample;
  12333. StopThis: Int64;
  12334. begin
  12335. // is there anything to do?
  12336. if (FStop <= FStart) then
  12337. begin
  12338. EndOfStream;
  12339. Exit;
  12340. end;
  12341. Discontinuity := True;
  12342. // if there is more than one sample at the allocator,
  12343. // then try to queue 2 at once in order to overlap.
  12344. // -- get buffer count and required alignment
  12345. FAlloc.GetProperties(Actual);
  12346. // align the start position downwards
  12347. Start := AlignDown(FStart div UNITS, Actual.cbAlign) * UNITS;
  12348. Current := Start;
  12349. Stop := FStop;
  12350. if (Stop > FDuration) then Stop := FDuration;
  12351. // align the stop position - may be past stop, but that
  12352. // doesn't matter
  12353. AlignStop := AlignUp(Stop div UNITS, Actual.cbAlign) * UNITS;
  12354. if not FSync then
  12355. begin
  12356. // Break out of the loop either if we get to the end or we're asked
  12357. // to do something else
  12358. while (Current < AlignStop) do
  12359. begin
  12360. // Break out without calling EndOfStream if we're asked to
  12361. // do something different
  12362. if CheckRequest(@Request) then Exit;
  12363. // queue a first sample
  12364. if (Actual.cBuffers > 1) then
  12365. begin
  12366. hr := QueueSample(Current, AlignStop, True);
  12367. Discontinuity := False;
  12368. if FAILED(hr) then Exit;
  12369. end;
  12370. // loop queueing second and waiting for first..
  12371. while (Current < AlignStop) do
  12372. begin
  12373. hr := QueueSample(Current, AlignStop, Discontinuity);
  12374. Discontinuity := False;
  12375. if FAILED(hr) then Exit;
  12376. hr := CollectAndDeliver(Start, Stop);
  12377. if (S_OK <> hr) then
  12378. begin
  12379. // stop if error, or if downstream filter said
  12380. // to stop.
  12381. Exit;
  12382. end;
  12383. end;
  12384. if (Actual.cBuffers > 1) then
  12385. begin
  12386. hr := CollectAndDeliver(Start, Stop);
  12387. if FAILED(hr) then Exit;
  12388. end;
  12389. end;
  12390. end else
  12391. begin
  12392. // sync version of above loop
  12393. while (Current < AlignStop) do
  12394. begin
  12395. // Break out without calling EndOfStream if we're asked to
  12396. // do something different
  12397. if CheckRequest(@Request) then Exit;
  12398. hr := FAlloc.GetBuffer(Sample, nil, nil, 0);
  12399. if FAILED(hr) then
  12400. begin
  12401. OnError(hr);
  12402. Exit;
  12403. end;
  12404. StopThis := Current + (Sample.GetSize * UNITS);
  12405. if (StopThis > AlignStop) then StopThis := AlignStop;
  12406. Sample.SetTime(@Current, @StopThis);
  12407. Current := StopThis;
  12408. if Discontinuity then
  12409. begin
  12410. Sample.SetDiscontinuity(True);
  12411. Discontinuity := False;
  12412. end;
  12413. hr := FReader.SyncReadAligned(Sample);
  12414. if FAILED(hr) then
  12415. begin
  12416. Sample := nil;
  12417. OnError(hr);
  12418. Exit;
  12419. end;
  12420. hr := DeliverSample(Sample, Start, Stop);
  12421. if (hr <> S_OK) then
  12422. begin
  12423. if FAILED(hr) then OnError(hr);
  12424. Exit;
  12425. end;
  12426. end;
  12427. end;
  12428. EndOfStream;
  12429. end;
  12430. procedure TBCPullPin.CleanupCancelled;
  12431. var
  12432. Sample: IMediaSample;
  12433. Unused: DWORD;
  12434. begin
  12435. while True do
  12436. begin
  12437. FReader.WaitForNext(
  12438. 0, // no wait
  12439. Sample,
  12440. Unused);
  12441. if Assigned(Sample) then Sample := nil
  12442. else Exit;
  12443. end;
  12444. end;
  12445. function TBCPullPin.PauseThread: HRESULT;
  12446. begin
  12447. FAccessLock.Lock;
  12448. try
  12449. if not ThreadExists then
  12450. begin
  12451. Result := E_UNEXPECTED;
  12452. Exit;
  12453. end;
  12454. // need to flush to ensure the thread is not blocked
  12455. // in WaitForNext
  12456. Result := FReader.BeginFlush;
  12457. if FAILED(Result) then Exit;
  12458. FState := TM_Pause;
  12459. Result := CallWorker(Cardinal(TM_Pause));
  12460. FReader.EndFlush;
  12461. finally
  12462. FAccessLock.UnLock;
  12463. end;
  12464. end;
  12465. function TBCPullPin.StartThread: HRESULT;
  12466. begin
  12467. FAccessLock.Lock;
  12468. try
  12469. if not Assigned(FAlloc) or not Assigned(FReader) then
  12470. begin
  12471. Result := E_UNEXPECTED;
  12472. Exit;
  12473. end;
  12474. if not ThreadExists then
  12475. begin
  12476. // commit allocator
  12477. Result := FAlloc.Commit;
  12478. if FAILED(Result) then Exit;
  12479. // start thread
  12480. if not Create_ then
  12481. begin
  12482. Result := E_FAIL;
  12483. Exit;
  12484. end;
  12485. end;
  12486. FState := TM_Start;
  12487. Result := HRESULT(CallWorker(DWORD(FState)));
  12488. finally
  12489. FAccessLock.UnLock;
  12490. end;
  12491. end;
  12492. function TBCPullPin.StopThread: HRESULT;
  12493. begin
  12494. FAccessLock.Lock;
  12495. try
  12496. if not ThreadExists then
  12497. begin
  12498. Result := S_FALSE;
  12499. Exit;
  12500. end;
  12501. // need to flush to ensure the thread is not blocked
  12502. // in WaitForNext
  12503. Result := FReader.BeginFlush;
  12504. if FAILED(Result) then Exit;
  12505. FState := TM_Exit;
  12506. Result := CallWorker(Cardinal(TM_Exit));
  12507. FReader.EndFlush;
  12508. // wait for thread to completely exit
  12509. Close;
  12510. // decommit allocator
  12511. if Assigned(FAlloc) then FAlloc.Decommit;
  12512. Result := S_OK;
  12513. finally
  12514. FAccessLock.UnLock;
  12515. end;
  12516. end;
  12517. function TBCPullPin.QueueSample(var tCurrent: TReferenceTime; tAlignStop: TReferenceTime; bDiscontinuity: Boolean): HRESULT;
  12518. var
  12519. Sample: IMediaSample;
  12520. StopThis: Int64;
  12521. begin
  12522. Result := FAlloc.GetBuffer(Sample, nil, nil, 0);
  12523. if FAILED(Result) then Exit;
  12524. StopThis := tCurrent + (Sample.GetSize * UNITS);
  12525. if (StopThis > tAlignStop) then StopThis := tAlignStop;
  12526. Sample.SetTime(@tCurrent, @StopThis);
  12527. tCurrent := StopThis;
  12528. Sample.SetDiscontinuity(bDiscontinuity);
  12529. Result := FReader.Request(Sample,0);
  12530. if FAILED(Result) then
  12531. begin
  12532. Sample := nil;
  12533. CleanupCancelled;
  12534. OnError(Result);
  12535. end;
  12536. end;
  12537. function TBCPullPin.CollectAndDeliver(tStart,tStop: TReferenceTime): HRESULT;
  12538. var
  12539. Sample: IMediaSample;
  12540. Unused: DWORD;
  12541. begin
  12542. Result := FReader.WaitForNext(INFINITE,Sample,Unused);
  12543. if FAILED(Result) then
  12544. begin
  12545. if Assigned(Sample) then Sample := nil;
  12546. end else
  12547. begin
  12548. Result := DeliverSample(Sample, tStart, tStop);
  12549. end;
  12550. if FAILED(Result) then
  12551. begin
  12552. CleanupCancelled;
  12553. OnError(Result);
  12554. end;
  12555. end;
  12556. function TBCPullPin.DeliverSample(pSample: IMediaSample; tStart,tStop: TReferenceTime): HRESULT;
  12557. var
  12558. t1, t2: TReferenceTime;
  12559. begin
  12560. // fix up sample if past actual stop (for sector alignment)
  12561. pSample.GetTime(t1, t2);
  12562. if (t2 > tStop) then t2 := tStop;
  12563. // adjust times to be relative to (aligned) start time
  12564. dec(t1,tStart);
  12565. dec(t2,tStart);
  12566. pSample.SetTime(@t1, @t2);
  12567. Result := Receive(pSample);
  12568. pSample := nil;
  12569. end;
  12570. function TBCPullPin.ThreadProc: DWord;
  12571. var
  12572. cmd: DWORD;
  12573. begin
  12574. Result := 1; // ???
  12575. while True do
  12576. begin
  12577. cmd := GetRequest;
  12578. case TThreadMsg(cmd) of
  12579. TM_Exit:
  12580. begin
  12581. Reply(S_OK);
  12582. Result := 0;
  12583. Exit;
  12584. end;
  12585. TM_Pause:
  12586. begin
  12587. // we are paused already
  12588. Reply(S_OK);
  12589. break;
  12590. end;
  12591. TM_Start:
  12592. begin
  12593. Reply(S_OK);
  12594. Process;
  12595. break;
  12596. end;
  12597. end;
  12598. // at this point, there should be no outstanding requests on the
  12599. // upstream filter.
  12600. // We should force begin/endflush to ensure that this is true.
  12601. // !!!Note that we may currently be inside a BeginFlush/EndFlush pair
  12602. // on another thread, but the premature EndFlush will do no harm now
  12603. // that we are idle.
  12604. FReader.BeginFlush;
  12605. CleanupCancelled;
  12606. FReader.EndFlush;
  12607. end;
  12608. end;
  12609. // returns S_OK if successfully connected to an IAsyncReader interface
  12610. // from this object
  12611. // Optional allocator should be proposed as a preferred allocator if
  12612. // necessary
  12613. function TBCPullPin.Connect(pUnk: IUnknown; pAlloc: IMemAllocator; bSync: Boolean): HRESULT;
  12614. var
  12615. Total, Avail: Int64;
  12616. begin
  12617. FAccessLock.Lock;
  12618. try
  12619. if Assigned(FReader) then
  12620. begin
  12621. Result := VFW_E_ALREADY_CONNECTED;
  12622. Exit;
  12623. end;
  12624. Result := pUnk.QueryInterface(IID_IAsyncReader, FReader);
  12625. if FAILED(Result) then Exit;
  12626. Result := DecideAllocator(pAlloc, nil);
  12627. if FAILED(Result) then
  12628. begin
  12629. Disconnect;
  12630. Exit;
  12631. end;
  12632. Result := FReader.Length(Total, Avail);
  12633. if FAILED(Result) then
  12634. begin
  12635. Disconnect;
  12636. Exit;
  12637. end;
  12638. // convert from file position to reference time
  12639. FDuration := Total * UNITS;
  12640. FStop := FDuration;
  12641. FStart := 0;
  12642. FSync := bSync;
  12643. Result := S_OK;
  12644. finally
  12645. FAccessLock.UnLock;
  12646. end;
  12647. end;
  12648. // disconnect any connection made in Connect
  12649. function TBCPullPin.Disconnect: HRESULT;
  12650. begin
  12651. FAccessLock.Lock;
  12652. try
  12653. StopThread;
  12654. if Assigned(FReader) then FReader := nil;
  12655. if Assigned(FAlloc) then FAlloc := nil;
  12656. Result := S_OK;
  12657. finally
  12658. FAccessLock.UnLock;
  12659. end;
  12660. end;
  12661. // agree an allocator using RequestAllocator - optional
  12662. // props param specifies your requirements (non-zero fields).
  12663. // returns an error code if fail to match requirements.
  12664. // optional IMemAllocator interface is offered as a preferred allocator
  12665. // but no error occurs if it can't be met.
  12666. function TBCPullPin.DecideAllocator(pAlloc: IMemAllocator; pProps: PAllocatorProperties): HRESULT;
  12667. var
  12668. pRequest: PAllocatorProperties;
  12669. Request: TAllocatorProperties;
  12670. begin
  12671. if (pProps = nil) then
  12672. begin
  12673. Request.cBuffers := 3;
  12674. Request.cbBuffer := 64*1024;
  12675. Request.cbAlign := 0;
  12676. Request.cbPrefix := 0;
  12677. pRequest := @Request;
  12678. end else
  12679. begin
  12680. pRequest := pProps;
  12681. end;
  12682. Result := FReader.RequestAllocator(pAlloc,pRequest,FAlloc);
  12683. end;
  12684. function TBCPullPin.Seek(tStart, tStop: TReferenceTime): HRESULT;
  12685. var
  12686. AtStart: TThreadMsg;
  12687. begin
  12688. FAccessLock.Lock;
  12689. try
  12690. AtStart := FState;
  12691. if (AtStart = TM_Start) then
  12692. begin
  12693. BeginFlush;
  12694. PauseThread;
  12695. EndFlush;
  12696. end;
  12697. FStart := tStart;
  12698. FStop := tStop;
  12699. Result := S_OK;
  12700. if (AtStart = TM_Start) then Result := StartThread;
  12701. finally
  12702. FAccessLock.UnLock;
  12703. end;
  12704. end;
  12705. function TBCPullPin.Duration(out ptDuration: TReferenceTime): HRESULT;
  12706. begin
  12707. ptDuration := FDuration;
  12708. Result := S_OK;
  12709. end;
  12710. // start pulling data
  12711. function TBCPullPin.Active: HRESULT;
  12712. begin
  12713. ASSERT(not ThreadExists);
  12714. Result := StartThread;
  12715. end;
  12716. // stop pulling data
  12717. function TBCPullPin.Inactive: HRESULT;
  12718. begin
  12719. StopThread;
  12720. Result := S_OK;
  12721. end;
  12722. function TBCPullPin.AlignDown(ll: Int64; lAlign: LongInt): Int64;
  12723. begin
  12724. Result := ll and not (lAlign-1);
  12725. end;
  12726. function TBCPullPin.AlignUp(ll: Int64; lAlign: LongInt): Int64;
  12727. begin
  12728. Result := (ll + (lAlign -1)) and not (lAlign -1);
  12729. end;
  12730. function TBCPullPin.GetReader: IAsyncReader;
  12731. begin
  12732. Result := FReader;
  12733. end;
  12734. // milenko end
  12735. // milenko start reftime implementation
  12736. procedure TBCRefTime.Create_;
  12737. begin
  12738. FTime := 0;
  12739. end;
  12740. procedure TBCRefTime.Create_(msecs: Longint);
  12741. begin
  12742. FTime := MILLISECONDS_TO_100NS_UNITS(msecs);
  12743. end;
  12744. function TBCRefTime.SetTime(var rt: TBCRefTime): TBCRefTime;
  12745. begin
  12746. FTime := rt.FTime;
  12747. Result := Self;
  12748. end;
  12749. function TBCRefTime.SetTime(var ll: LONGLONG): TBCRefTime;
  12750. begin
  12751. FTime := ll;
  12752. end;
  12753. function TBCRefTime.AddTime(var rt: TBCRefTime): TBCRefTime;
  12754. begin
  12755. TReferenceTime(Self) := TReferenceTime(Self) + TReferenceTime(rt);
  12756. Result := Self;
  12757. end;
  12758. function TBCRefTime.SubstractTime(var rt: TBCRefTime): TBCRefTime;
  12759. begin
  12760. TReferenceTime(Self) := TReferenceTime(Self) - TReferenceTime(rt);
  12761. Result := Self;
  12762. end;
  12763. function TBCRefTime.Millisecs: Longint;
  12764. begin
  12765. Result := fTime div (UNITS div MILLISECONDS);
  12766. end;
  12767. function TBCRefTime.GetUnits: LONGLONG;
  12768. begin
  12769. Result := fTime;
  12770. end;
  12771. // milenko end
  12772. // milenko start schedule implementation
  12773. constructor TBCAdvisePacket.Create;
  12774. begin
  12775. inherited Create;
  12776. end;
  12777. constructor TBCAdvisePacket.Create(Next: TBCAdvisePacket; Time: LONGLONG);
  12778. begin
  12779. inherited Create;
  12780. FNext := Next;
  12781. FEventTime := Time;
  12782. end;
  12783. procedure TBCAdvisePacket.InsertAfter(Packet: TBCAdvisePacket);
  12784. begin
  12785. Packet.FNext := FNext;
  12786. FNext := Packet;
  12787. end;
  12788. function TBCAdvisePacket.IsZ: Boolean;
  12789. begin
  12790. Result := FNext = nil;
  12791. end;
  12792. function TBCAdvisePacket.RemoveNext: TBCAdvisePacket;
  12793. var
  12794. Next,
  12795. NewNext : TBCAdvisePacket;
  12796. begin
  12797. Next := FNext;
  12798. NewNext := Next.FNext;
  12799. FNext := NewNext;
  12800. Result := Next;
  12801. end;
  12802. procedure TBCAdvisePacket.DeleteNext;
  12803. begin
  12804. RemoveNext.Free;
  12805. end;
  12806. function TBCAdvisePacket.Next: TBCAdvisePacket;
  12807. begin
  12808. Result := FNext;
  12809. if Result.IsZ then Result := nil;
  12810. end;
  12811. function TBCAdvisePacket.Cookie: DWORD;
  12812. begin
  12813. Result := FAdviseCookie;
  12814. end;
  12815. constructor TBCAMSchedule.Create(Event: THandle);
  12816. begin
  12817. inherited Create('TBCAMSchedule');
  12818. FZ := TBCAdvisePacket.Create(nil,MAX_TIME);
  12819. FHead := TBCAdvisePacket.Create(FZ,0);
  12820. FNextCookie := 0;
  12821. FAdviseCount := 0;
  12822. FAdviseCache := nil;
  12823. FCacheCount := 0;
  12824. FEvent := Event;
  12825. FSerialize := TBCCritSec.Create;
  12826. FZ.FAdviseCookie := 0;
  12827. FHead.FAdviseCookie := FZ.FAdviseCookie;
  12828. end;
  12829. destructor TBCAMSchedule.Destroy;
  12830. var
  12831. p, p_next : TBCAdvisePacket;
  12832. begin
  12833. FSerialize.Lock;
  12834. try
  12835. // Delete cache
  12836. p := FAdviseCache;
  12837. while (p <> nil) do
  12838. begin
  12839. p_next := p.FNext;
  12840. FreeAndNil(p);
  12841. p := p_next;
  12842. end;
  12843. ASSERT(FAdviseCount = 0);
  12844. // Better to be safe than sorry
  12845. if (FAdviseCount > 0) then
  12846. begin
  12847. DumpLinkedList;
  12848. while not FHead.FNext.IsZ do
  12849. begin
  12850. FHead.DeleteNext;
  12851. dec(FAdviseCount);
  12852. end;
  12853. end;
  12854. // If, in the debug version, we assert twice, it means, not only
  12855. // did we have left over advises, but we have also let m_dwAdviseCount
  12856. // get out of sync. with the number of advises actually on the list.
  12857. ASSERT(FAdviseCount = 0);
  12858. finally
  12859. FSerialize.Unlock;
  12860. end;
  12861. FreeAndNil(FSerialize);
  12862. inherited Destroy;
  12863. end;
  12864. function TBCAMSchedule.GetAdviseCount: DWORD;
  12865. begin
  12866. // No need to lock, m_dwAdviseCount is 32bits & declared volatile
  12867. // DCODER: No volatile in Delphi -> needs a lock ?
  12868. FSerialize.Lock;
  12869. try
  12870. Result := FAdviseCount;
  12871. finally
  12872. FSerialize.UnLock;
  12873. end;
  12874. end;
  12875. function TBCAMSchedule.GetNextAdviseTime: TReferenceTime;
  12876. begin
  12877. FSerialize.Lock; // Need to stop the linked list from changing
  12878. try
  12879. Result := FHead.FNext.FEventTime;
  12880. finally
  12881. FSerialize.UnLock;
  12882. end;
  12883. end;
  12884. function TBCAMSchedule.AddAdvisePacket(const time1, time2: TReferenceTime;
  12885. h: THandle; periodic: Boolean): DWORD;
  12886. var
  12887. p : TBCAdvisePacket;
  12888. begin
  12889. // Since we use MAX_TIME as a sentry, we can't afford to
  12890. // schedule a notification at MAX_TIME
  12891. ASSERT(time1 < MAX_TIME);
  12892. FSerialize.Lock;
  12893. try
  12894. if Assigned(FAdviseCache) then
  12895. begin
  12896. p := FAdviseCache;
  12897. FAdviseCache := p.FNext;
  12898. dec(FCacheCount);
  12899. end else
  12900. begin
  12901. p := TBCAdvisePacket.Create;
  12902. end;
  12903. if Assigned(p) then
  12904. begin
  12905. p.FEventTime := time1;
  12906. p.FPeriod := time2;
  12907. p.FNotify := h;
  12908. p.FPeriodic := periodic;
  12909. Result := AddAdvisePacket(p);
  12910. end else
  12911. begin
  12912. Result := 0;
  12913. end;
  12914. finally
  12915. FSerialize.UnLock;
  12916. end;
  12917. end;
  12918. function TBCAMSchedule.Unadvise(AdviseCookie: DWORD): HRESULT;
  12919. var
  12920. p_prev, p_n : TBCAdvisePacket;
  12921. begin
  12922. Result := S_FALSE;
  12923. p_prev := FHead;
  12924. FSerialize.Lock;
  12925. try
  12926. p_n := p_prev.Next;
  12927. while Assigned(p_n) do // The Next() method returns NULL when it hits z
  12928. begin
  12929. if (p_n.FAdviseCookie = AdviseCookie) then
  12930. begin
  12931. Delete(p_prev.RemoveNext);
  12932. dec(FAdviseCount);
  12933. Result := S_OK;
  12934. // Having found one cookie that matches, there should be no more
  12935. {$IFDEF DEBUG}
  12936. p_n := p_prev.Next;
  12937. while Assigned(p_n) do
  12938. begin
  12939. ASSERT(p_n.FAdviseCookie <> AdviseCookie);
  12940. p_prev := p_n;
  12941. p_n := p_prev.Next;
  12942. end;
  12943. {$ENDIF}
  12944. break;
  12945. end;
  12946. p_prev := p_n;
  12947. p_n := p_prev.Next;
  12948. end;
  12949. finally
  12950. FSerialize.UnLock;
  12951. end;
  12952. end;
  12953. function TBCAMSchedule.Advise(const Time_: TReferenceTime): TReferenceTime;
  12954. var
  12955. NextTime : TReferenceTime;
  12956. Advise : TBCAdvisePacket;
  12957. begin
  12958. {$IFDEF DEBUG}
  12959. DbgLog(
  12960. Self, 'TBCAMSchedule.Advise( ' +
  12961. inttostr((Time_ div (UNITS div MILLISECONDS))) + ' ms '
  12962. );
  12963. {$ENDIF}
  12964. FSerialize.Lock;
  12965. try
  12966. {$IFDEF DEBUG}
  12967. DumpLinkedList;
  12968. {$ENDIF}
  12969. // Note - DON'T cache the difference, it might overflow
  12970. Advise := FHead.FNext;
  12971. NextTime := Advise.FEventTime;
  12972. while ((Time_ >= NextTime) and not Advise.IsZ) do
  12973. begin
  12974. // DCODER: assert raised here
  12975. ASSERT(Advise.FAdviseCookie > 0); // If this is zero, its the head or the tail!!
  12976. ASSERT(Advise.FNotify <> INVALID_HANDLE_VALUE);
  12977. if (Advise.FPeriodic = True) then
  12978. begin
  12979. ReleaseSemaphore(Advise.FNotify,1,nil);
  12980. Advise.FEventTime := Advise.FEventTime + Advise.FPeriod;
  12981. ShuntHead;
  12982. end else
  12983. begin
  12984. ASSERT(Advise.FPeriodic = False);
  12985. SetEvent(Advise.FNotify);
  12986. dec(FAdviseCount);
  12987. Delete(FHead.RemoveNext);
  12988. end;
  12989. Advise := FHead.FNext;
  12990. NextTime := Advise.FEventTime;
  12991. end;
  12992. finally
  12993. FSerialize.UnLock;
  12994. end;
  12995. {$IFDEF DEBUG}
  12996. DbgLog(
  12997. Self, 'TBCAMSchedule.Advise(Next time stamp: ' +
  12998. inttostr((NextTime div (UNITS div MILLISECONDS))) +
  12999. ' ms, for advise ' + inttostr(Advise.FAdviseCookie)
  13000. );
  13001. {$ENDIF}
  13002. Result := NextTime;
  13003. end;
  13004. function TBCAMSchedule.GetEvent: THandle;
  13005. begin
  13006. Result := FEvent;
  13007. end;
  13008. procedure TBCAMSchedule.DumpLinkedList;
  13009. {$IFDEF DEBUG}
  13010. var
  13011. i : integer;
  13012. p : TBCAdvisePacket;
  13013. {$ENDIF}
  13014. begin
  13015. {$IFDEF DEBUG}
  13016. FSerialize.Lock;
  13017. try
  13018. DbgLog(Self,'TBCAMSchedule.DumpLinkedList');
  13019. i := 0;
  13020. p := FHead;
  13021. while True do
  13022. begin
  13023. if p = nil then break;
  13024. DbgLog(
  13025. Self, 'Advise List # ' + inttostr(i) + ', Cookie ' +
  13026. inttostr(p.FAdviseCookie) + ', RefTime ' +
  13027. inttostr(p.FEventTime div (UNITS div MILLISECONDS))
  13028. );
  13029. inc(i);
  13030. p := p.Next;
  13031. end;
  13032. finally
  13033. FSerialize.Unlock;
  13034. end;
  13035. {$ENDIF}
  13036. end;
  13037. function TBCAMSchedule.AddAdvisePacket(Packet: TBCAdvisePacket): DWORD;
  13038. var
  13039. p_prev, p_n : TBCAdvisePacket;
  13040. begin
  13041. ASSERT((Packet.FEventTime >= 0) and (Packet.FEventTime < MAX_TIME));
  13042. {$IFDEF DEBUG}
  13043. ASSERT(FSerialize.CritCheckIn);
  13044. {$ENDIF}
  13045. p_prev := FHead;
  13046. inc(FNextCookie);
  13047. Packet.FAdviseCookie := FNextCookie;
  13048. Result := Packet.FAdviseCookie;
  13049. // This relies on the fact that z is a sentry with a maximal m_rtEventTime
  13050. while True do
  13051. begin
  13052. p_n := p_prev.FNext;
  13053. if (p_n.FEventTime >= Packet.FEventTime) then break;
  13054. p_prev := p_n;
  13055. end;
  13056. p_prev.InsertAfter(Packet);
  13057. inc(FAdviseCount);
  13058. {$IFDEF DEBUG}
  13059. DbgLog(
  13060. Self, 'Added advise ' + inttostr(Packet.FAdviseCookie) + ', for thread ' +
  13061. inttostr(GetCurrentThreadId) + ', scheduled at ' +
  13062. inttostr(Packet.FEventTime div (UNITS div MILLISECONDS))
  13063. );
  13064. {$ENDIF}
  13065. // If packet added at the head, then clock needs to re-evaluate wait time.
  13066. if (p_prev = FHead) then SetEvent(FEvent);
  13067. end;
  13068. procedure TBCAMSchedule.ShuntHead;
  13069. var
  13070. p_prev, p_n : TBCAdvisePacket;
  13071. Packet : TBCAdvisePacket;
  13072. begin
  13073. p_prev := FHead;
  13074. p_n := nil;
  13075. FSerialize.Lock;
  13076. try
  13077. Packet := FHead.FNext;
  13078. // This will catch both an empty list,
  13079. // and if somehow a MAX_TIME time gets into the list
  13080. // (which would also break this method).
  13081. ASSERT(Packet.FEventTime < MAX_TIME);
  13082. // This relies on the fact that z is a sentry with a maximal m_rtEventTime
  13083. while True do
  13084. begin
  13085. p_n := p_prev.FNext;
  13086. if (p_n.FEventTime >= Packet.FEventTime) then break;
  13087. p_prev := p_n;
  13088. end;
  13089. // If p_prev == pPacket then we're already in the right place
  13090. if (p_prev <> Packet) then
  13091. begin
  13092. FHead.FNext := Packet.FNext;
  13093. p_prev.FNext := Packet;
  13094. p_prev.FNext.FNext := p_n;
  13095. end;
  13096. {$IFDEF DEBUG}
  13097. DbgLog(
  13098. Self, 'Periodic advise ' + inttostr(Packet.FAdviseCookie) + ', shunted to ' +
  13099. inttostr(Packet.FEventTime div (UNITS div MILLISECONDS))
  13100. );
  13101. {$ENDIF}
  13102. finally
  13103. FSerialize.Unlock;
  13104. end;
  13105. end;
  13106. procedure TBCAMSchedule.Delete(Packet: TBCAdvisePacket);
  13107. const
  13108. CacheMax = 5; // Don't bother caching more than five
  13109. begin
  13110. if (FCacheCount >= CacheMax) then FreeAndNil(Packet)
  13111. else
  13112. begin
  13113. FSerialize.Lock;
  13114. try
  13115. Packet.FNext := FAdviseCache;
  13116. FAdviseCache := Packet;
  13117. inc(FCacheCount);
  13118. finally
  13119. FSerialize.Unlock;
  13120. end;
  13121. end;
  13122. end;
  13123. // milenko end
  13124. // milenko start refclock implementation
  13125. function AdviseThreadFunction(p: Pointer): DWORD; stdcall;
  13126. begin
  13127. Result := TBCBaseReferenceClock(p).AdviseThread;
  13128. end;
  13129. constructor TBCBaseReferenceClock.Create(Name: String; Unk: IUnknown; out hr: HRESULT;
  13130. Sched: TBCAMSchedule);
  13131. var
  13132. tc : TIMECAPS;
  13133. ThreadID : DWORD;
  13134. begin
  13135. inherited Create(Name,Unk);
  13136. FLastGotTime := 0;
  13137. FTimerResolution := 0;
  13138. FAbort := False;
  13139. if not Assigned(Sched)
  13140. then FSchedule := TBCAMSchedule.Create(CreateEvent(nil,False,False,nil))
  13141. else FSchedule := Sched;
  13142. ASSERT(fSchedule <> nil);
  13143. if not Assigned(FSchedule) then
  13144. begin
  13145. hr := E_OUTOFMEMORY;
  13146. end else
  13147. begin
  13148. FLock := TBCCritSec.Create;
  13149. // Set up the highest resolution timer we can manage
  13150. if (timeGetDevCaps(@tc, sizeof(tc)) = TIMERR_NOERROR)
  13151. then FTimerResolution := tc.wPeriodMin
  13152. else FTimerResolution := 1;
  13153. timeBeginPeriod(FTimerResolution);
  13154. // Initialise our system times - the derived clock should set the right values
  13155. FPrevSystemTime := timeGetTime;
  13156. FPrivateTime := (UNITS div MILLISECONDS) * FPrevSystemTime;
  13157. {$IFDEF PERF}
  13158. FGetSystemTime := MSR_REGISTER('TBCBaseReferenceClock.GetTime');
  13159. {$ENDIF}
  13160. if not Assigned(Sched) then
  13161. begin
  13162. FThread := CreateThread(nil, // Security attributes
  13163. 0, // Initial stack size
  13164. @AdviseThreadFunction, // Thread start address
  13165. Self, // Thread parameter
  13166. 0, // Creation flags
  13167. ThreadID); // Thread identifier
  13168. if (FThread > 0) then
  13169. begin
  13170. SetThreadPriority(FThread, THREAD_PRIORITY_TIME_CRITICAL);
  13171. end else
  13172. begin
  13173. hr := E_FAIL;
  13174. CloseHandle(FSchedule.GetEvent);
  13175. FreeAndNil(FSchedule);
  13176. end;
  13177. end;
  13178. end;
  13179. end;
  13180. destructor TBCBaseReferenceClock.Destroy;
  13181. begin
  13182. if (FTimerResolution > 0) then
  13183. begin
  13184. timeEndPeriod(FTimerResolution);
  13185. FTimerResolution := 0;
  13186. end;
  13187. FSchedule.DumpLinkedList;
  13188. if (FThread > 0) then
  13189. begin
  13190. FAbort := True;
  13191. TriggerThread;
  13192. WaitForSingleObject(FThread, INFINITE);
  13193. CloseHandle(FSchedule.GetEvent);
  13194. FreeAndNil(FSchedule);
  13195. end;
  13196. if Assigned(FLock) then FreeAndNil(FLock);
  13197. inherited Destroy;
  13198. end;
  13199. function TBCBaseReferenceClock.AdviseThread: HRESULT;
  13200. var
  13201. dwWait : DWORD;
  13202. rtNow : TReferenceTime;
  13203. llWait : LONGLONG;
  13204. begin
  13205. dwWait := INFINITE;
  13206. // The first thing we do is wait until something interesting happens
  13207. // (meaning a first advise or shutdown). This prevents us calling
  13208. // GetPrivateTime immediately which is goodness as that is a virtual
  13209. // routine and the derived class may not yet be constructed. (This
  13210. // thread is created in the base class constructor.)
  13211. while not FAbort do
  13212. begin
  13213. // Wait for an interesting event to happen
  13214. {$IFDEF DEBUG}
  13215. DbgLog(Self,'AdviseThread Delay: ' + inttostr(dwWait) + ' ms');
  13216. {$ENDIF}
  13217. WaitForSingleObject(FSchedule.GetEvent, dwWait);
  13218. if FAbort then break;
  13219. // There are several reasons why we need to work from the internal
  13220. // time, mainly to do with what happens when time goes backwards.
  13221. // Mainly, it stop us looping madly if an event is just about to
  13222. // expire when the clock goes backward (i.e. GetTime stop for a
  13223. // while).
  13224. rtNow := GetPrivateTime;
  13225. {$IFDEF DEBUG}
  13226. DbgLog(
  13227. Self,'AdviseThread Woke at = ' + inttostr(RefTimeToMiliSec(rtNow)) + ' ms'
  13228. );
  13229. {$ENDIF}
  13230. // We must add in a millisecond, since this is the resolution of our
  13231. // WaitForSingleObject timer. Failure to do so will cause us to loop
  13232. // franticly for (approx) 1 a millisecond.
  13233. FNextAdvise := FSchedule.Advise(10000 + rtNow);
  13234. llWait := FNextAdvise - rtNow;
  13235. ASSERT(llWait > 0);
  13236. llWait := RefTimeToMiliSec(llWait);
  13237. // DON'T replace this with a max!! (The type's of these things is VERY important)
  13238. if (llWait > REFERENCE_TIME(HIGH(DWORD))) then dwWait := HIGH(DWORD)
  13239. else dwWait := DWORD(llWait)
  13240. end;
  13241. Result := NOERROR;
  13242. end;
  13243. function TBCBaseReferenceClock.NonDelegatingQueryInterface(const IID: TGUID;
  13244. out Obj): HResult; stdcall;
  13245. begin
  13246. if (IsEqualGUID(IID,IID_IReferenceClock)) then
  13247. begin
  13248. if GetInterface(IID,Obj) then Result := S_OK
  13249. else Result := E_NOINTERFACE;
  13250. end
  13251. else
  13252. Result := inherited NonDelegatingQueryInterface(IID, Obj);
  13253. end;
  13254. function TBCBaseReferenceClock.GetTime(out Time: int64): HResult; stdcall;
  13255. var
  13256. Now_ : TReferenceTime;
  13257. begin
  13258. if Assigned(@Time) then
  13259. begin
  13260. FLock.Lock;
  13261. try
  13262. Now_ := GetPrivateTime;
  13263. if (Now_ > FLastGotTime) then
  13264. begin
  13265. FLastGotTime := Now_;
  13266. Result := S_OK;
  13267. end else
  13268. begin
  13269. Result := S_FALSE;
  13270. end;
  13271. Time := FLastGotTime;
  13272. finally
  13273. FLock.UnLock;
  13274. end;
  13275. {$IFDEF PERF}
  13276. MSR_INTEGER(FGetSystemTime, Time div (UNITS div MILLISECONDS));
  13277. {$ENDIF}
  13278. end else Result := E_POINTER;
  13279. end;
  13280. function TBCBaseReferenceClock.AdviseTime(BaseTime, StreamTime: int64;
  13281. Event: THandle; out AdviseCookie: DWORD): HResult; stdcall;
  13282. var
  13283. RefTime : TReferenceTime;
  13284. begin
  13285. if @AdviseCookie = nil then
  13286. begin
  13287. Result := E_POINTER;
  13288. Exit;
  13289. end;
  13290. AdviseCookie := 0;
  13291. // Check that the event is not already set
  13292. ASSERT(WAIT_TIMEOUT = WaitForSingleObject(Event,0));
  13293. RefTime := BaseTime + StreamTime;
  13294. if ((RefTime <= 0) or (RefTime = MAX_TIME)) then
  13295. begin
  13296. Result := E_INVALIDARG;
  13297. end else
  13298. begin
  13299. AdviseCookie := FSchedule.AddAdvisePacket(RefTime, 0, Event, False);
  13300. if AdviseCookie > 0 then Result := NOERROR
  13301. else Result := E_OUTOFMEMORY;
  13302. end;
  13303. end;
  13304. function TBCBaseReferenceClock.AdvisePeriodic(const StartTime, PeriodTime: int64;
  13305. Semaphore: THandle; out AdviseCookie: DWORD): HResult; stdcall;
  13306. begin
  13307. if @AdviseCookie = nil then
  13308. begin
  13309. Result := E_POINTER;
  13310. Exit;
  13311. end;
  13312. AdviseCookie := 0;
  13313. if ((StartTime > 0) and (PeriodTime > 0) and (StartTime <> MAX_TIME)) then
  13314. begin
  13315. AdviseCookie := FSchedule.AddAdvisePacket(StartTime,PeriodTime,Semaphore,True);
  13316. if AdviseCookie > 0 then Result := NOERROR
  13317. else Result := E_OUTOFMEMORY;
  13318. end
  13319. else Result := E_INVALIDARG;
  13320. end;
  13321. function TBCBaseReferenceClock.Unadvise(AdviseCookie: DWORD): HResult; stdcall;
  13322. begin
  13323. Result := FSchedule.Unadvise(AdviseCookie);
  13324. end;
  13325. function TBCBaseReferenceClock.GetPrivateTime: TReferenceTime;
  13326. var
  13327. Time_ : DWORD;
  13328. begin
  13329. FLock.Lock;
  13330. try
  13331. (* If the clock has wrapped then the current time will be less than
  13332. * the last time we were notified so add on the extra milliseconds
  13333. *
  13334. * The time period is long enough so that the likelihood of
  13335. * successive calls spanning the clock cycle is not considered.
  13336. *)
  13337. Time_ := timeGetTime;
  13338. FPrivateTime := FPrivateTime + Int32x32To64(UNITS div MILLISECONDS, DWORD(Time_ - FPrevSystemTime));
  13339. FPrevSystemTime := Time_;
  13340. finally
  13341. FLock.UnLock;
  13342. end;
  13343. Result := FPrivateTime;
  13344. end;
  13345. function TBCBaseReferenceClock.SetTimeDelta(const TimeDelta: TReferenceTime): HRESULT; stdcall;
  13346. {$IFDEF DEBUG}
  13347. var
  13348. llDelta : LONGLONG;
  13349. usDelta : Longint;
  13350. delta : DWORD;
  13351. Severity : integer;
  13352. {$ENDIF}
  13353. begin
  13354. {$IFDEF DEBUG}
  13355. // Just break if passed an improper time delta value
  13356. if TimeDelta > 0 then llDelta := TimeDelta
  13357. else llDelta := -TimeDelta;
  13358. if (llDelta > UNITS * 1000) then
  13359. begin
  13360. DbgLog(Self,'Bad Time Delta');
  13361. // DebugBreak;
  13362. end;
  13363. // We're going to calculate a "severity" for the time change. Max -1
  13364. // min 8. We'll then use this as the debug logging level for a
  13365. // debug log message.
  13366. usDelta := Longint(TimeDelta div 10); // Delta in micro-secs
  13367. delta := abs(usDelta); // varying delta
  13368. // Severity == 8 - ceil(log<base 8>(abs( micro-secs delta)))
  13369. Severity := 8;
  13370. while (delta > 0) do
  13371. begin
  13372. delta := delta shr 3; // div 8
  13373. dec(Severity);
  13374. end;
  13375. // Sev == 0 => > 2 second delta!
  13376. DbgLog(
  13377. Self, 'Sev ' + inttostr(Severity) + ': CSystemClock::SetTimeDelta(' +
  13378. inttostr(usDelta) + ' us) ' + inttostr(RefTimeToMiliSec(FPrivateTime)) +
  13379. ' -> ' + inttostr(RefTimeToMiliSec(TimeDelta + FPrivateTime)) + ' ms'
  13380. );
  13381. {$ENDIF}
  13382. FLock.Lock;
  13383. try
  13384. FPrivateTime := FPrivateTime + TimeDelta;
  13385. // If time goes forwards, and we have advises, then we need to
  13386. // trigger the thread so that it can re-evaluate its wait time.
  13387. // Since we don't want the cost of the thread switches if the change
  13388. // is really small, only do it if clock goes forward by more than
  13389. // 0.5 millisecond. If the time goes backwards, the thread will
  13390. // wake up "early" (relativly speaking) and will re-evaluate at
  13391. // that time.
  13392. if ((TimeDelta > 5000) and (FSchedule.GetAdviseCount > 0)) then TriggerThread;
  13393. finally
  13394. FLock.UnLock;
  13395. end;
  13396. Result := NOERROR;
  13397. end;
  13398. function TBCBaseReferenceClock.GetSchedule : TBCAMSchedule;
  13399. begin
  13400. Result := FSchedule;
  13401. end;
  13402. procedure TBCBaseReferenceClock.TriggerThread;
  13403. begin
  13404. {$IFDEF DEBUG}
  13405. DbgLog(Self,'TriggerThread : ' + inttostr(FSchedule.GetEvent));
  13406. {$ENDIF}
  13407. SetEvent(FSchedule.GetEvent);
  13408. end;
  13409. // milenko end
  13410. // milenko start sysclock implementation
  13411. constructor TBCSystemClock.Create(Name: WideString; Unk : IUnknown; out hr : HRESULT);
  13412. begin
  13413. inherited Create(Name,Unk,hr);
  13414. end;
  13415. function TBCSystemClock.NonDelegatingQueryInterface(const IID: TGUID; out Obj): HResult;
  13416. begin
  13417. if IsEqualGUID(IID,IID_IPersist) then
  13418. begin
  13419. if GetInterface(IID,Obj) then Result := S_OK
  13420. else Result := E_NOINTERFACE;
  13421. end else
  13422. if IsEqualGUID(IID,IID_IAMClockAdjust) then
  13423. begin
  13424. if GetInterface(IID,Obj) then Result := S_OK
  13425. else Result := E_NOINTERFACE;
  13426. end
  13427. else Result := inherited NonDelegatingQueryInterface(IID,Obj);
  13428. end;
  13429. function TBCSystemClock.GetClassID(out classID: TCLSID): HResult; stdcall;
  13430. begin
  13431. if not Assigned(@ClassID) then
  13432. begin
  13433. Result := E_POINTER;
  13434. Exit;
  13435. end;
  13436. classID := CLSID_SystemClock;
  13437. Result := NOERROR;
  13438. end;
  13439. function TBCSystemClock.SetClockDelta(rtDelta: TReferenceTime): HResult; stdcall;
  13440. begin
  13441. Result := SetTimeDelta(rtDelta);
  13442. end;
  13443. // milenko end
  13444. initialization
  13445. {$IFDEF DEBUG}
  13446. {$IFDEF VER130}
  13447. AssertErrorProc := @DbgAssert;
  13448. {$ELSE}
  13449. AssertErrorProc := DbgAssert;
  13450. {$ENDIF}
  13451. {$IFNDEF MESSAGE}
  13452. AssignFile(DebugFile, ParamStr(0) + '.log');
  13453. if FileExists(ParamStr(0) + '.log') then
  13454. Append(DebugFile) else
  13455. Rewrite(DebugFile);
  13456. {$ENDIF}
  13457. {$ENDIF}
  13458. finalization
  13459. begin
  13460. if TemplatesVar <> nil then TemplatesVar.Free;
  13461. TemplatesVar := nil;
  13462. {$IFDEF DEBUG}
  13463. {$IFNDEF MESSAGE}
  13464. Writeln(DebugFile, format('FactoryCount: %d, ObjectCount: %d.',[FactoryCount, ObjectCount]));
  13465. CloseFile(DebugFile);
  13466. {$ELSE}
  13467. OutputDebugString(PChar(format('FactoryCount: %d, ObjectCount: %d.',[FactoryCount, ObjectCount])));
  13468. {$ENDIF}
  13469. {$ENDIF}
  13470. // milenko start (only needed with PERF)
  13471. {$IFDEF PERF}
  13472. SetLength(Incidents, 0);
  13473. SetLength(IncidentsLog, 0);
  13474. {$ENDIF}
  13475. // milenko end
  13476. end;
  13477. end.