12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665 |
- From 1353d8feca19f2f84019797942d70864054db1b0 Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Mon, 5 Aug 2013 13:12:46 +0100
- Subject: [PATCH 01/94] h264_parser: Initialize the h264dsp context in the
- parser as well
- MIME-Version: 1.0
- Content-Type: text/plain; charset=UTF-8
- Content-Transfer-Encoding: 8bit
- Each AVStream struct for an H.264 elementary stream actually has two
- copies of the H264DSPContext struct (and in fact all the other members
- of H264Context as well):
- ((H264Context *) ((AVStream *)st)->codec->priv_data)->h264dsp
- ((H264Context *) ((AVStream *)st)->parser->priv_data)->h264dsp
- but only the first of these was actually being initialised. This
- prevented the addition of platform-specific implementations of
- parser-related functions.
- Signed-off-by: Martin Storsjö <martin@martin.st>
- ---
- lib/ffmpeg/libavcodec/h264_parser.c | 1 +
- 1 file changed, 1 insertion(+)
- diff --git a/lib/ffmpeg/libavcodec/h264_parser.c b/lib/ffmpeg/libavcodec/h264_parser.c
- index aff9ba1..a732f79 100644
- --- a/lib/ffmpeg/libavcodec/h264_parser.c
- +++ b/lib/ffmpeg/libavcodec/h264_parser.c
- @@ -386,6 +386,7 @@ static int init(AVCodecParserContext *s)
- H264Context *h = s->priv_data;
- h->thread_context[0] = h;
- h->slice_context_count = 1;
- + ff_h264dsp_init(&h->h264dsp, 8, 1);
- return 0;
- }
-
- --
- 1.9.3
- From 7ea2cb68f6fb1149fce70854e36ed6357a267238 Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Mon, 5 Aug 2013 13:12:47 +0100
- Subject: [PATCH 02/94] h264dsp: Factorize code into a new function,
- h264_find_start_code_candidate
- MIME-Version: 1.0
- Content-Type: text/plain; charset=UTF-8
- Content-Transfer-Encoding: 8bit
- This performs the start code search which was previously part of
- h264_find_frame_end() - the most CPU intensive part of the function.
- By itself, this results in a performance regression:
- Before After
- Mean StdDev Mean StdDev Change
- Overall time 2925.6 26.2 3068.5 31.7 -4.7%
- but this can more than be made up for by platform-optimised
- implementations of the function.
- Signed-off-by: Martin Storsjö <martin@martin.st>
- ---
- lib/ffmpeg/libavcodec/h264_parser.c | 20 +++-----------------
- lib/ffmpeg/libavcodec/h264dsp.c | 29 +++++++++++++++++++++++++++++
- lib/ffmpeg/libavcodec/h264dsp.h | 9 +++++++++
- 3 files changed, 41 insertions(+), 17 deletions(-)
- diff --git a/lib/ffmpeg/libavcodec/h264_parser.c b/lib/ffmpeg/libavcodec/h264_parser.c
- index a732f79..972aace 100644
- --- a/lib/ffmpeg/libavcodec/h264_parser.c
- +++ b/lib/ffmpeg/libavcodec/h264_parser.c
- @@ -62,23 +62,9 @@ static int ff_h264_find_frame_end(H264Context *h, const uint8_t *buf, int buf_si
- }
-
- if(state==7){
- -#if HAVE_FAST_UNALIGNED
- - /* we check i<buf_size instead of i+3/7 because its simpler
- - * and there should be FF_INPUT_BUFFER_PADDING_SIZE bytes at the end
- - */
- -# if HAVE_FAST_64BIT
- - while(i<next_avc && !((~*(const uint64_t*)(buf+i) & (*(const uint64_t*)(buf+i) - 0x0101010101010101ULL)) & 0x8080808080808080ULL))
- - i+=8;
- -# else
- - while(i<next_avc && !((~*(const uint32_t*)(buf+i) & (*(const uint32_t*)(buf+i) - 0x01010101U)) & 0x80808080U))
- - i+=4;
- -# endif
- -#endif
- - for(; i<next_avc; i++){
- - if(!buf[i]){
- - state=2;
- - break;
- - }
- + i += h->h264dsp.h264_find_start_code_candidate(buf + i, buf_size - i);
- + if (i < buf_size)
- + state = 2;
- }
- }else if(state<=2){
- if(buf[i]==1) state^= 5; //2->7, 1->4, 0->5
- diff --git a/lib/ffmpeg/libavcodec/h264dsp.c b/lib/ffmpeg/libavcodec/h264dsp.c
- index da9e417..b7d61cd 100644
- --- a/lib/ffmpeg/libavcodec/h264dsp.c
- +++ b/lib/ffmpeg/libavcodec/h264dsp.c
- @@ -60,6 +60,34 @@
- #include "h264addpx_template.c"
- #undef BIT_DEPTH
-
- +static int h264_find_start_code_candidate_c(const uint8_t *buf, int size)
- +{
- + int i = 0;
- +#if HAVE_FAST_UNALIGNED
- + /* we check i < size instead of i + 3 / 7 because it is
- + * simpler and there must be FF_INPUT_BUFFER_PADDING_SIZE
- + * bytes at the end.
- + */
- +#if HAVE_FAST_64BIT
- + while (i < size &&
- + !((~*(const uint64_t *)(buf + i) &
- + (*(const uint64_t *)(buf + i) - 0x0101010101010101ULL)) &
- + 0x8080808080808080ULL))
- + i += 8;
- +#else
- + while (i < size &&
- + !((~*(const uint32_t *)(buf + i) &
- + (*(const uint32_t *)(buf + i) - 0x01010101U)) &
- + 0x80808080U))
- + i += 4;
- +#endif
- +#endif
- + for (; i < size; i++)
- + if (!buf[i])
- + break;
- + return i;
- +}
- +
- void ff_h264dsp_init(H264DSPContext *c, const int bit_depth, const int chroma_format_idc)
- {
- #undef FUNC
- @@ -146,6 +174,7 @@ void ff_h264dsp_init(H264DSPContext *c, const int bit_depth, const int chroma_fo
- H264_DSP(8);
- break;
- }
- + c->h264_find_start_code_candidate = h264_find_start_code_candidate_c;
-
- if (ARCH_ARM) ff_h264dsp_init_arm(c, bit_depth, chroma_format_idc);
- if (HAVE_ALTIVEC) ff_h264dsp_init_ppc(c, bit_depth, chroma_format_idc);
- diff --git a/lib/ffmpeg/libavcodec/h264dsp.h b/lib/ffmpeg/libavcodec/h264dsp.h
- index 98ea15c..1be4804 100644
- --- a/lib/ffmpeg/libavcodec/h264dsp.h
- +++ b/lib/ffmpeg/libavcodec/h264dsp.h
- @@ -105,6 +105,15 @@ typedef struct H264DSPContext {
- /* bypass-transform */
- void (*h264_add_pixels8_clear)(uint8_t *dst, int16_t *block, int stride);
- void (*h264_add_pixels4_clear)(uint8_t *dst, int16_t *block, int stride);
- +
- + /**
- + * Search buf from the start for up to size bytes. Return the index
- + * of a zero byte, or >= size if not found. Ideally, use lookahead
- + * to filter out any zero bytes that are known to not be followed by
- + * one or more further zero bytes and a one byte. Better still, filter
- + * out any bytes that form the trailing_zero_8bits syntax element too.
- + */
- + int (*h264_find_start_code_candidate)(const uint8_t *buf, int size);
- } H264DSPContext;
-
- void ff_h264dsp_init(H264DSPContext *c, const int bit_depth,
- --
- 1.9.3
- From 458ff4b6c1855c529f563dbbd15e35aaab50adae Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Mon, 5 Aug 2013 13:12:48 +0100
- Subject: [PATCH 03/94] arm: Add assembly version of
- h264_find_start_code_candidate
- MIME-Version: 1.0
- Content-Type: text/plain; charset=UTF-8
- Content-Transfer-Encoding: 8bit
- Before After
- Mean StdDev Mean StdDev Change
- This function 508.8 23.4 185.4 9.0 +174.4%
- Overall 3068.5 31.7 2752.1 29.4 +11.5%
- In combination with the preceding patch:
- Before After
- Mean StdDev Mean StdDev Change
- Overall 2925.6 26.2 2752.1 29.4 +6.3%
- Signed-off-by: Martin Storsjö <martin@martin.st>
- ---
- lib/ffmpeg/libavcodec/arm/Makefile | 1 +
- lib/ffmpeg/libavcodec/arm/h264dsp_armv6.S | 253 +++++++++++++++++++++++++++
- lib/ffmpeg/libavcodec/arm/h264dsp_init_arm.c | 4 +
- lib/ffmpeg/libavcodec/h264_parser.c | 1 -
- 4 files changed, 258 insertions(+), 1 deletion(-)
- create mode 100644 lib/ffmpeg/libavcodec/arm/h264dsp_armv6.S
- diff --git a/lib/ffmpeg/libavcodec/arm/Makefile b/lib/ffmpeg/libavcodec/arm/Makefile
- index 7390a8b..480000b71 100644
- --- a/lib/ffmpeg/libavcodec/arm/Makefile
- +++ b/lib/ffmpeg/libavcodec/arm/Makefile
- @@ -9,6 +9,7 @@ OBJS-$(CONFIG_AAC_DECODER) += arm/sbrdsp_init_arm.o \
- OBJS-$(CONFIG_DCA_DECODER) += arm/dcadsp_init_arm.o \
-
- ARMV6-OBJS-$(CONFIG_AC3DSP) += arm/ac3dsp_armv6.o
- +ARMV6-OBJS-$(CONFIG_H264DSP) += arm/h264dsp_armv6.o
-
- OBJS-$(CONFIG_FLAC_DECODER) += arm/flacdsp_init_arm.o \
- arm/flacdsp_arm.o \
- diff --git a/lib/ffmpeg/libavcodec/arm/h264dsp_armv6.S b/lib/ffmpeg/libavcodec/arm/h264dsp_armv6.S
- new file mode 100644
- index 0000000..c4f12a6
- --- /dev/null
- +++ b/lib/ffmpeg/libavcodec/arm/h264dsp_armv6.S
- @@ -0,0 +1,253 @@
- +/*
- + * Copyright (c) 2013 RISC OS Open Ltd
- + * Author: Ben Avison <bavison@riscosopen.org>
- + *
- + * This file is part of Libav.
- + *
- + * Libav is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU Lesser General Public
- + * License as published by the Free Software Foundation; either
- + * version 2.1 of the License, or (at your option) any later version.
- + *
- + * Libav is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- + * Lesser General Public License for more details.
- + *
- + * You should have received a copy of the GNU Lesser General Public
- + * License along with Libav; if not, write to the Free Software
- + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- + */
- +
- +#include "libavutil/arm/asm.S"
- +
- +RESULT .req a1
- +BUF .req a1
- +SIZE .req a2
- +PATTERN .req a3
- +PTR .req a4
- +DAT0 .req v1
- +DAT1 .req v2
- +DAT2 .req v3
- +DAT3 .req v4
- +TMP0 .req v5
- +TMP1 .req v6
- +TMP2 .req ip
- +TMP3 .req lr
- +
- +#define PRELOAD_DISTANCE 4
- +
- +.macro innerloop4
- + ldr DAT0, [PTR], #4
- + subs SIZE, SIZE, #4 @ C flag survives rest of macro
- + sub TMP0, DAT0, PATTERN, lsr #14
- + bic TMP0, TMP0, DAT0
- + ands TMP0, TMP0, PATTERN
- +.endm
- +
- +.macro innerloop16 decrement, do_preload
- + ldmia PTR!, {DAT0,DAT1,DAT2,DAT3}
- + .ifnc "\do_preload",""
- + pld [PTR, #PRELOAD_DISTANCE*32]
- + .endif
- + .ifnc "\decrement",""
- + subs SIZE, SIZE, #\decrement @ C flag survives rest of macro
- + .endif
- + sub TMP0, DAT0, PATTERN, lsr #14
- + sub TMP1, DAT1, PATTERN, lsr #14
- + bic TMP0, TMP0, DAT0
- + bic TMP1, TMP1, DAT1
- + sub TMP2, DAT2, PATTERN, lsr #14
- + sub TMP3, DAT3, PATTERN, lsr #14
- + ands TMP0, TMP0, PATTERN
- + bic TMP2, TMP2, DAT2
- + it eq
- + andseq TMP1, TMP1, PATTERN
- + bic TMP3, TMP3, DAT3
- + itt eq
- + andseq TMP2, TMP2, PATTERN
- + andseq TMP3, TMP3, PATTERN
- +.endm
- +
- +/* int ff_h264_find_start_code_candidate_armv6(const uint8_t *buf, int size) */
- +function ff_h264_find_start_code_candidate_armv6, export=1
- + push {v1-v6,lr}
- + mov PTR, BUF
- + @ Ensure there are at least (PRELOAD_DISTANCE+2) complete cachelines to go
- + @ before using code that does preloads
- + cmp SIZE, #(PRELOAD_DISTANCE+3)*32 - 1
- + blo 60f
- +
- + @ Get to word-alignment, 1 byte at a time
- + tst PTR, #3
- + beq 2f
- +1: ldrb DAT0, [PTR], #1
- + sub SIZE, SIZE, #1
- + teq DAT0, #0
- + beq 90f
- + tst PTR, #3
- + bne 1b
- +2: @ Get to 4-word alignment, 1 word at a time
- + ldr PATTERN, =0x80008000
- + setend be
- + tst PTR, #12
- + beq 4f
- +3: innerloop4
- + bne 91f
- + tst PTR, #12
- + bne 3b
- +4: @ Get to cacheline (8-word) alignment
- + tst PTR, #16
- + beq 5f
- + innerloop16 16
- + bne 93f
- +5: @ Check complete cachelines, with preloading
- + @ We need to stop when there are still (PRELOAD_DISTANCE+1)
- + @ complete cachelines to go
- + sub SIZE, SIZE, #(PRELOAD_DISTANCE+2)*32
- +6: innerloop16 , do_preload
- + bne 93f
- + innerloop16 32
- + bne 93f
- + bcs 6b
- + @ Preload trailing part-cacheline, if any
- + tst SIZE, #31
- + beq 7f
- + pld [PTR, #(PRELOAD_DISTANCE+1)*32]
- + @ Check remaining data without doing any more preloads. First
- + @ do in chunks of 4 words:
- +7: adds SIZE, SIZE, #(PRELOAD_DISTANCE+2)*32 - 16
- + bmi 9f
- +8: innerloop16 16
- + bne 93f
- + bcs 8b
- + @ Then in words:
- +9: adds SIZE, SIZE, #16 - 4
- + bmi 11f
- +10: innerloop4
- + bne 91f
- + bcs 10b
- +11: setend le
- + @ Check second byte of final halfword
- + ldrb DAT0, [PTR, #-1]
- + teq DAT0, #0
- + beq 90f
- + @ Check any remaining bytes
- + tst SIZE, #3
- + beq 13f
- +12: ldrb DAT0, [PTR], #1
- + sub SIZE, SIZE, #1
- + teq DAT0, #0
- + beq 90f
- + tst SIZE, #3
- + bne 12b
- + @ No candidate found
- +13: sub RESULT, PTR, BUF
- + b 99f
- +
- +60: @ Small buffer - simply check by looping over bytes
- + subs SIZE, SIZE, #1
- + bcc 99f
- +61: ldrb DAT0, [PTR], #1
- + subs SIZE, SIZE, #1
- + teq DAT0, #0
- + beq 90f
- + bcs 61b
- + @ No candidate found
- + sub RESULT, PTR, BUF
- + b 99f
- +
- +90: @ Found a candidate at the preceding byte
- + sub RESULT, PTR, BUF
- + sub RESULT, RESULT, #1
- + b 99f
- +
- +91: @ Found a candidate somewhere in the preceding 4 bytes
- + sub RESULT, PTR, BUF
- + sub RESULT, RESULT, #4
- + sub TMP0, DAT0, #0x20000
- + bics TMP0, TMP0, DAT0
- + itt pl
- + ldrbpl DAT0, [PTR, #-3]
- + addpl RESULT, RESULT, #2
- + bpl 92f
- + teq RESULT, #0
- + beq 98f @ don't look back a byte if found at first byte in buffer
- + ldrb DAT0, [PTR, #-5]
- +92: teq DAT0, #0
- + it eq
- + subeq RESULT, RESULT, #1
- + b 98f
- +
- +93: @ Found a candidate somewhere in the preceding 16 bytes
- + sub RESULT, PTR, BUF
- + sub RESULT, RESULT, #16
- + teq TMP0, #0
- + beq 95f @ not in first 4 bytes
- + sub TMP0, DAT0, #0x20000
- + bics TMP0, TMP0, DAT0
- + itt pl
- + ldrbpl DAT0, [PTR, #-15]
- + addpl RESULT, RESULT, #2
- + bpl 94f
- + teq RESULT, #0
- + beq 98f @ don't look back a byte if found at first byte in buffer
- + ldrb DAT0, [PTR, #-17]
- +94: teq DAT0, #0
- + it eq
- + subeq RESULT, RESULT, #1
- + b 98f
- +95: add RESULT, RESULT, #4
- + teq TMP1, #0
- + beq 96f @ not in next 4 bytes
- + sub TMP1, DAT1, #0x20000
- + bics TMP1, TMP1, DAT1
- + itee mi
- + ldrbmi DAT0, [PTR, #-13]
- + ldrbpl DAT0, [PTR, #-11]
- + addpl RESULT, RESULT, #2
- + teq DAT0, #0
- + it eq
- + subeq RESULT, RESULT, #1
- + b 98f
- +96: add RESULT, RESULT, #4
- + teq TMP2, #0
- + beq 97f @ not in next 4 bytes
- + sub TMP2, DAT2, #0x20000
- + bics TMP2, TMP2, DAT2
- + itee mi
- + ldrbmi DAT0, [PTR, #-9]
- + ldrbpl DAT0, [PTR, #-7]
- + addpl RESULT, RESULT, #2
- + teq DAT0, #0
- + it eq
- + subeq RESULT, RESULT, #1
- + b 98f
- +97: add RESULT, RESULT, #4
- + sub TMP3, DAT3, #0x20000
- + bics TMP3, TMP3, DAT3
- + itee mi
- + ldrbmi DAT0, [PTR, #-5]
- + ldrbpl DAT0, [PTR, #-3]
- + addpl RESULT, RESULT, #2
- + teq DAT0, #0
- + it eq
- + subeq RESULT, RESULT, #1
- + @ drop through to 98f
- +98: setend le
- +99: pop {v1-v6,pc}
- +.endfunc
- +
- + .unreq RESULT
- + .unreq BUF
- + .unreq SIZE
- + .unreq PATTERN
- + .unreq PTR
- + .unreq DAT0
- + .unreq DAT1
- + .unreq DAT2
- + .unreq DAT3
- + .unreq TMP0
- + .unreq TMP1
- + .unreq TMP2
- + .unreq TMP3
- diff --git a/lib/ffmpeg/libavcodec/arm/h264dsp_init_arm.c b/lib/ffmpeg/libavcodec/arm/h264dsp_init_arm.c
- index 785b604..2804e56 100644
- --- a/lib/ffmpeg/libavcodec/arm/h264dsp_init_arm.c
- +++ b/lib/ffmpeg/libavcodec/arm/h264dsp_init_arm.c
- @@ -24,6 +24,8 @@
- #include "libavutil/arm/cpu.h"
- #include "libavcodec/h264dsp.h"
-
- +int ff_h264_find_start_code_candidate_armv6(const uint8_t *buf, int size);
- +
- void ff_h264_v_loop_filter_luma_neon(uint8_t *pix, int stride, int alpha,
- int beta, int8_t *tc0);
- void ff_h264_h_loop_filter_luma_neon(uint8_t *pix, int stride, int alpha,
- @@ -106,6 +108,8 @@ av_cold void ff_h264dsp_init_arm(H264DSPContext *c, const int bit_depth,
- {
- int cpu_flags = av_get_cpu_flags();
-
- + if (have_armv6(cpu_flags))
- + c->h264_find_start_code_candidate = ff_h264_find_start_code_candidate_armv6;
- if (have_neon(cpu_flags))
- ff_h264dsp_init_neon(c, bit_depth, chroma_format_idc);
- }
- diff --git a/lib/ffmpeg/libavcodec/h264_parser.c b/lib/ffmpeg/libavcodec/h264_parser.c
- index 972aace..363843c 100644
- --- a/lib/ffmpeg/libavcodec/h264_parser.c
- +++ b/lib/ffmpeg/libavcodec/h264_parser.c
- @@ -65,7 +65,6 @@ static int ff_h264_find_frame_end(H264Context *h, const uint8_t *buf, int buf_si
- i += h->h264dsp.h264_find_start_code_candidate(buf + i, buf_size - i);
- if (i < buf_size)
- state = 2;
- - }
- }else if(state<=2){
- if(buf[i]==1) state^= 5; //2->7, 1->4, 0->5
- else if(buf[i]) state = 7;
- --
- 1.9.3
- From 5841d5b69f0df2f286c0a8e419deb16d927e864e Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Mon, 19 Aug 2013 22:48:05 +0100
- Subject: [PATCH 04/94] [ffmpeg] Backport of h264_find_start_code_candidate
- optimisation
- ---
- ...-Initialize-the-h264dsp-context-in-the-pa.patch | 39 +++
- ...torize-code-into-a-new-function-h264_find.patch | 134 +++++++++
- ...embly-version-of-h264_find_start_code_can.patch | 322 +++++++++++++++++++++
- 3 files changed, 495 insertions(+)
- create mode 100644 lib/ffmpeg/patches/0056-h264_parser-Initialize-the-h264dsp-context-in-the-pa.patch
- create mode 100644 lib/ffmpeg/patches/0057-h264dsp-Factorize-code-into-a-new-function-h264_find.patch
- create mode 100644 lib/ffmpeg/patches/0058-arm-Add-assembly-version-of-h264_find_start_code_can.patch
- diff --git a/lib/ffmpeg/patches/0056-h264_parser-Initialize-the-h264dsp-context-in-the-pa.patch b/lib/ffmpeg/patches/0056-h264_parser-Initialize-the-h264dsp-context-in-the-pa.patch
- new file mode 100644
- index 0000000..263578d
- --- /dev/null
- +++ b/lib/ffmpeg/patches/0056-h264_parser-Initialize-the-h264dsp-context-in-the-pa.patch
- @@ -0,0 +1,39 @@
- +From 7a82022ee2f9b1fad991ace0936901e7419444be Mon Sep 17 00:00:00 2001
- +From: Ben Avison <bavison@riscosopen.org>
- +Date: Mon, 5 Aug 2013 13:12:46 +0100
- +Subject: [PATCH 1/3] h264_parser: Initialize the h264dsp context in the
- + parser as well
- +MIME-Version: 1.0
- +Content-Type: text/plain; charset=UTF-8
- +Content-Transfer-Encoding: 8bit
- +
- +Each AVStream struct for an H.264 elementary stream actually has two
- +copies of the H264DSPContext struct (and in fact all the other members
- +of H264Context as well):
- +
- +((H264Context *) ((AVStream *)st)->codec->priv_data)->h264dsp
- +((H264Context *) ((AVStream *)st)->parser->priv_data)->h264dsp
- +
- +but only the first of these was actually being initialised. This
- +prevented the addition of platform-specific implementations of
- +parser-related functions.
- +
- +Signed-off-by: Martin Storsjö <martin@martin.st>
- +---
- + libavcodec/h264_parser.c | 1 +
- + 1 file changed, 1 insertion(+)
- +
- +diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c
- +index 2ed155c..da2a5f9 100644
- +--- a/libavcodec/h264_parser.c
- ++++ b/libavcodec/h264_parser.c
- +@@ -417,6 +417,7 @@ static av_cold int init(AVCodecParserContext *s)
- + H264Context *h = s->priv_data;
- + h->thread_context[0] = h;
- + h->slice_context_count = 1;
- ++ ff_h264dsp_init(&h->h264dsp, 8, 1);
- + return 0;
- + }
- +
- +--
- +1.7.9.5
- diff --git a/lib/ffmpeg/patches/0057-h264dsp-Factorize-code-into-a-new-function-h264_find.patch b/lib/ffmpeg/patches/0057-h264dsp-Factorize-code-into-a-new-function-h264_find.patch
- new file mode 100644
- index 0000000..0151d85
- --- /dev/null
- +++ b/lib/ffmpeg/patches/0057-h264dsp-Factorize-code-into-a-new-function-h264_find.patch
- @@ -0,0 +1,134 @@
- +From 218d6844b37d339ffbf2044ad07d8be7767e2734 Mon Sep 17 00:00:00 2001
- +From: Ben Avison <bavison@riscosopen.org>
- +Date: Mon, 5 Aug 2013 13:12:47 +0100
- +Subject: [PATCH 2/3] h264dsp: Factorize code into a new function,
- + h264_find_start_code_candidate
- +MIME-Version: 1.0
- +Content-Type: text/plain; charset=UTF-8
- +Content-Transfer-Encoding: 8bit
- +
- +This performs the start code search which was previously part of
- +h264_find_frame_end() - the most CPU intensive part of the function.
- +
- +By itself, this results in a performance regression:
- + Before After
- + Mean StdDev Mean StdDev Change
- +Overall time 2925.6 26.2 3068.5 31.7 -4.7%
- +
- +but this can more than be made up for by platform-optimised
- +implementations of the function.
- +
- +Signed-off-by: Martin Storsjö <martin@martin.st>
- +---
- + libavcodec/h264_parser.c | 27 +++------------------------
- + libavcodec/h264dsp.c | 29 +++++++++++++++++++++++++++++
- + libavcodec/h264dsp.h | 9 +++++++++
- + 3 files changed, 41 insertions(+), 24 deletions(-)
- +
- +diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c
- +index da2a5f9..ef5da98 100644
- +--- a/libavcodec/h264_parser.c
- ++++ b/libavcodec/h264_parser.c
- +@@ -47,30 +47,9 @@ static int h264_find_frame_end(H264Context *h, const uint8_t *buf,
- +
- + for (i = 0; i < buf_size; i++) {
- + if (state == 7) {
- +-#if HAVE_FAST_UNALIGNED
- +- /* we check i < buf_size instead of i + 3 / 7 because it is
- +- * simpler and there must be FF_INPUT_BUFFER_PADDING_SIZE
- +- * bytes at the end.
- +- */
- +-#if HAVE_FAST_64BIT
- +- while (i < buf_size &&
- +- !((~*(const uint64_t *)(buf + i) &
- +- (*(const uint64_t *)(buf + i) - 0x0101010101010101ULL)) &
- +- 0x8080808080808080ULL))
- +- i += 8;
- +-#else
- +- while (i < buf_size &&
- +- !((~*(const uint32_t *)(buf + i) &
- +- (*(const uint32_t *)(buf + i) - 0x01010101U)) &
- +- 0x80808080U))
- +- i += 4;
- +-#endif
- +-#endif
- +- for (; i < buf_size; i++)
- +- if (!buf[i]) {
- +- state = 2;
- +- break;
- +- }
- ++ i += h->h264dsp.h264_find_start_code_candidate(buf + i, buf_size - i);
- ++ if (i < buf_size)
- ++ state = 2;
- + } else if (state <= 2) {
- + if (buf[i] == 1)
- + state ^= 5; // 2->7, 1->4, 0->5
- +diff --git a/libavcodec/h264dsp.c b/libavcodec/h264dsp.c
- +index 3ca6abe..a901dbb 100644
- +--- a/libavcodec/h264dsp.c
- ++++ b/libavcodec/h264dsp.c
- +@@ -53,6 +53,34 @@
- + #include "h264addpx_template.c"
- + #undef BIT_DEPTH
- +
- ++static int h264_find_start_code_candidate_c(const uint8_t *buf, int size)
- ++{
- ++ int i = 0;
- ++#if HAVE_FAST_UNALIGNED
- ++ /* we check i < size instead of i + 3 / 7 because it is
- ++ * simpler and there must be FF_INPUT_BUFFER_PADDING_SIZE
- ++ * bytes at the end.
- ++ */
- ++#if HAVE_FAST_64BIT
- ++ while (i < size &&
- ++ !((~*(const uint64_t *)(buf + i) &
- ++ (*(const uint64_t *)(buf + i) - 0x0101010101010101ULL)) &
- ++ 0x8080808080808080ULL))
- ++ i += 8;
- ++#else
- ++ while (i < size &&
- ++ !((~*(const uint32_t *)(buf + i) &
- ++ (*(const uint32_t *)(buf + i) - 0x01010101U)) &
- ++ 0x80808080U))
- ++ i += 4;
- ++#endif
- ++#endif
- ++ for (; i < size; i++)
- ++ if (!buf[i])
- ++ break;
- ++ return i;
- ++}
- ++
- + av_cold void ff_h264dsp_init(H264DSPContext *c, const int bit_depth,
- + const int chroma_format_idc)
- + {
- +@@ -133,6 +161,7 @@ av_cold void ff_h264dsp_init(H264DSPContext *c, const int bit_depth,
- + H264_DSP(8);
- + break;
- + }
- ++ c->h264_find_start_code_candidate = h264_find_start_code_candidate_c;
- +
- + if (ARCH_ARM) ff_h264dsp_init_arm(c, bit_depth, chroma_format_idc);
- + if (ARCH_PPC) ff_h264dsp_init_ppc(c, bit_depth, chroma_format_idc);
- +diff --git a/libavcodec/h264dsp.h b/libavcodec/h264dsp.h
- +index 1f9f8fe..6249ba7 100644
- +--- a/libavcodec/h264dsp.h
- ++++ b/libavcodec/h264dsp.h
- +@@ -105,6 +105,15 @@ typedef struct H264DSPContext {
- + /* bypass-transform */
- + void (*h264_add_pixels8_clear)(uint8_t *dst, int16_t *block, int stride);
- + void (*h264_add_pixels4_clear)(uint8_t *dst, int16_t *block, int stride);
- ++
- ++ /**
- ++ * Search buf from the start for up to size bytes. Return the index
- ++ * of a zero byte, or >= size if not found. Ideally, use lookahead
- ++ * to filter out any zero bytes that are known to not be followed by
- ++ * one or more further zero bytes and a one byte. Better still, filter
- ++ * out any bytes that form the trailing_zero_8bits syntax element too.
- ++ */
- ++ int (*h264_find_start_code_candidate)(const uint8_t *buf, int size);
- + } H264DSPContext;
- +
- + void ff_h264dsp_init(H264DSPContext *c, const int bit_depth,
- +--
- +1.7.9.5
- diff --git a/lib/ffmpeg/patches/0058-arm-Add-assembly-version-of-h264_find_start_code_can.patch b/lib/ffmpeg/patches/0058-arm-Add-assembly-version-of-h264_find_start_code_can.patch
- new file mode 100644
- index 0000000..cdc2d1e
- --- /dev/null
- +++ b/lib/ffmpeg/patches/0058-arm-Add-assembly-version-of-h264_find_start_code_can.patch
- @@ -0,0 +1,322 @@
- +From 45e10e5c8d3df09c80a4d80483bff2712367f3fa Mon Sep 17 00:00:00 2001
- +From: Ben Avison <bavison@riscosopen.org>
- +Date: Mon, 5 Aug 2013 13:12:48 +0100
- +Subject: [PATCH 3/3] arm: Add assembly version of
- + h264_find_start_code_candidate
- +MIME-Version: 1.0
- +Content-Type: text/plain; charset=UTF-8
- +Content-Transfer-Encoding: 8bit
- +
- + Before After
- + Mean StdDev Mean StdDev Change
- +This function 508.8 23.4 185.4 9.0 +174.4%
- +Overall 3068.5 31.7 2752.1 29.4 +11.5%
- +
- +In combination with the preceding patch:
- + Before After
- + Mean StdDev Mean StdDev Change
- +Overall 2925.6 26.2 2752.1 29.4 +6.3%
- +
- +Signed-off-by: Martin Storsjö <martin@martin.st>
- +---
- + libavcodec/arm/Makefile | 1 +
- + libavcodec/arm/h264dsp_armv6.S | 253 +++++++++++++++++++++++++++++++++++++
- + libavcodec/arm/h264dsp_init_arm.c | 4 +
- + 3 files changed, 258 insertions(+)
- + create mode 100644 libavcodec/arm/h264dsp_armv6.S
- +
- +diff --git a/libavcodec/arm/Makefile b/libavcodec/arm/Makefile
- +index e941aaa..9c64b36 100644
- +--- a/libavcodec/arm/Makefile
- ++++ b/libavcodec/arm/Makefile
- +@@ -45,6 +45,7 @@ ARMV6-OBJS-$(CONFIG_DSPUTIL) += arm/dsputil_init_armv6.o \
- + arm/simple_idct_armv6.o \
- +
- + ARMV6-OBJS-$(CONFIG_AC3DSP) += arm/ac3dsp_armv6.o
- ++ARMV6-OBJS-$(CONFIG_H264DSP) += arm/h264dsp_armv6.o
- + ARMV6-OBJS-$(CONFIG_HPELDSP) += arm/hpeldsp_init_armv6.o \
- + arm/hpeldsp_armv6.o
- + ARMV6-OBJS-$(CONFIG_MPEGAUDIODSP) += arm/mpegaudiodsp_fixed_armv6.o
- +diff --git a/libavcodec/arm/h264dsp_armv6.S b/libavcodec/arm/h264dsp_armv6.S
- +new file mode 100644
- +index 0000000..c4f12a6
- +--- /dev/null
- ++++ b/libavcodec/arm/h264dsp_armv6.S
- +@@ -0,0 +1,253 @@
- ++/*
- ++ * Copyright (c) 2013 RISC OS Open Ltd
- ++ * Author: Ben Avison <bavison@riscosopen.org>
- ++ *
- ++ * This file is part of Libav.
- ++ *
- ++ * Libav is free software; you can redistribute it and/or
- ++ * modify it under the terms of the GNU Lesser General Public
- ++ * License as published by the Free Software Foundation; either
- ++ * version 2.1 of the License, or (at your option) any later version.
- ++ *
- ++ * Libav is distributed in the hope that it will be useful,
- ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
- ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- ++ * Lesser General Public License for more details.
- ++ *
- ++ * You should have received a copy of the GNU Lesser General Public
- ++ * License along with Libav; if not, write to the Free Software
- ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- ++ */
- ++
- ++#include "libavutil/arm/asm.S"
- ++
- ++RESULT .req a1
- ++BUF .req a1
- ++SIZE .req a2
- ++PATTERN .req a3
- ++PTR .req a4
- ++DAT0 .req v1
- ++DAT1 .req v2
- ++DAT2 .req v3
- ++DAT3 .req v4
- ++TMP0 .req v5
- ++TMP1 .req v6
- ++TMP2 .req ip
- ++TMP3 .req lr
- ++
- ++#define PRELOAD_DISTANCE 4
- ++
- ++.macro innerloop4
- ++ ldr DAT0, [PTR], #4
- ++ subs SIZE, SIZE, #4 @ C flag survives rest of macro
- ++ sub TMP0, DAT0, PATTERN, lsr #14
- ++ bic TMP0, TMP0, DAT0
- ++ ands TMP0, TMP0, PATTERN
- ++.endm
- ++
- ++.macro innerloop16 decrement, do_preload
- ++ ldmia PTR!, {DAT0,DAT1,DAT2,DAT3}
- ++ .ifnc "\do_preload",""
- ++ pld [PTR, #PRELOAD_DISTANCE*32]
- ++ .endif
- ++ .ifnc "\decrement",""
- ++ subs SIZE, SIZE, #\decrement @ C flag survives rest of macro
- ++ .endif
- ++ sub TMP0, DAT0, PATTERN, lsr #14
- ++ sub TMP1, DAT1, PATTERN, lsr #14
- ++ bic TMP0, TMP0, DAT0
- ++ bic TMP1, TMP1, DAT1
- ++ sub TMP2, DAT2, PATTERN, lsr #14
- ++ sub TMP3, DAT3, PATTERN, lsr #14
- ++ ands TMP0, TMP0, PATTERN
- ++ bic TMP2, TMP2, DAT2
- ++ it eq
- ++ andseq TMP1, TMP1, PATTERN
- ++ bic TMP3, TMP3, DAT3
- ++ itt eq
- ++ andseq TMP2, TMP2, PATTERN
- ++ andseq TMP3, TMP3, PATTERN
- ++.endm
- ++
- ++/* int ff_h264_find_start_code_candidate_armv6(const uint8_t *buf, int size) */
- ++function ff_h264_find_start_code_candidate_armv6, export=1
- ++ push {v1-v6,lr}
- ++ mov PTR, BUF
- ++ @ Ensure there are at least (PRELOAD_DISTANCE+2) complete cachelines to go
- ++ @ before using code that does preloads
- ++ cmp SIZE, #(PRELOAD_DISTANCE+3)*32 - 1
- ++ blo 60f
- ++
- ++ @ Get to word-alignment, 1 byte at a time
- ++ tst PTR, #3
- ++ beq 2f
- ++1: ldrb DAT0, [PTR], #1
- ++ sub SIZE, SIZE, #1
- ++ teq DAT0, #0
- ++ beq 90f
- ++ tst PTR, #3
- ++ bne 1b
- ++2: @ Get to 4-word alignment, 1 word at a time
- ++ ldr PATTERN, =0x80008000
- ++ setend be
- ++ tst PTR, #12
- ++ beq 4f
- ++3: innerloop4
- ++ bne 91f
- ++ tst PTR, #12
- ++ bne 3b
- ++4: @ Get to cacheline (8-word) alignment
- ++ tst PTR, #16
- ++ beq 5f
- ++ innerloop16 16
- ++ bne 93f
- ++5: @ Check complete cachelines, with preloading
- ++ @ We need to stop when there are still (PRELOAD_DISTANCE+1)
- ++ @ complete cachelines to go
- ++ sub SIZE, SIZE, #(PRELOAD_DISTANCE+2)*32
- ++6: innerloop16 , do_preload
- ++ bne 93f
- ++ innerloop16 32
- ++ bne 93f
- ++ bcs 6b
- ++ @ Preload trailing part-cacheline, if any
- ++ tst SIZE, #31
- ++ beq 7f
- ++ pld [PTR, #(PRELOAD_DISTANCE+1)*32]
- ++ @ Check remaining data without doing any more preloads. First
- ++ @ do in chunks of 4 words:
- ++7: adds SIZE, SIZE, #(PRELOAD_DISTANCE+2)*32 - 16
- ++ bmi 9f
- ++8: innerloop16 16
- ++ bne 93f
- ++ bcs 8b
- ++ @ Then in words:
- ++9: adds SIZE, SIZE, #16 - 4
- ++ bmi 11f
- ++10: innerloop4
- ++ bne 91f
- ++ bcs 10b
- ++11: setend le
- ++ @ Check second byte of final halfword
- ++ ldrb DAT0, [PTR, #-1]
- ++ teq DAT0, #0
- ++ beq 90f
- ++ @ Check any remaining bytes
- ++ tst SIZE, #3
- ++ beq 13f
- ++12: ldrb DAT0, [PTR], #1
- ++ sub SIZE, SIZE, #1
- ++ teq DAT0, #0
- ++ beq 90f
- ++ tst SIZE, #3
- ++ bne 12b
- ++ @ No candidate found
- ++13: sub RESULT, PTR, BUF
- ++ b 99f
- ++
- ++60: @ Small buffer - simply check by looping over bytes
- ++ subs SIZE, SIZE, #1
- ++ bcc 99f
- ++61: ldrb DAT0, [PTR], #1
- ++ subs SIZE, SIZE, #1
- ++ teq DAT0, #0
- ++ beq 90f
- ++ bcs 61b
- ++ @ No candidate found
- ++ sub RESULT, PTR, BUF
- ++ b 99f
- ++
- ++90: @ Found a candidate at the preceding byte
- ++ sub RESULT, PTR, BUF
- ++ sub RESULT, RESULT, #1
- ++ b 99f
- ++
- ++91: @ Found a candidate somewhere in the preceding 4 bytes
- ++ sub RESULT, PTR, BUF
- ++ sub RESULT, RESULT, #4
- ++ sub TMP0, DAT0, #0x20000
- ++ bics TMP0, TMP0, DAT0
- ++ itt pl
- ++ ldrbpl DAT0, [PTR, #-3]
- ++ addpl RESULT, RESULT, #2
- ++ bpl 92f
- ++ teq RESULT, #0
- ++ beq 98f @ don't look back a byte if found at first byte in buffer
- ++ ldrb DAT0, [PTR, #-5]
- ++92: teq DAT0, #0
- ++ it eq
- ++ subeq RESULT, RESULT, #1
- ++ b 98f
- ++
- ++93: @ Found a candidate somewhere in the preceding 16 bytes
- ++ sub RESULT, PTR, BUF
- ++ sub RESULT, RESULT, #16
- ++ teq TMP0, #0
- ++ beq 95f @ not in first 4 bytes
- ++ sub TMP0, DAT0, #0x20000
- ++ bics TMP0, TMP0, DAT0
- ++ itt pl
- ++ ldrbpl DAT0, [PTR, #-15]
- ++ addpl RESULT, RESULT, #2
- ++ bpl 94f
- ++ teq RESULT, #0
- ++ beq 98f @ don't look back a byte if found at first byte in buffer
- ++ ldrb DAT0, [PTR, #-17]
- ++94: teq DAT0, #0
- ++ it eq
- ++ subeq RESULT, RESULT, #1
- ++ b 98f
- ++95: add RESULT, RESULT, #4
- ++ teq TMP1, #0
- ++ beq 96f @ not in next 4 bytes
- ++ sub TMP1, DAT1, #0x20000
- ++ bics TMP1, TMP1, DAT1
- ++ itee mi
- ++ ldrbmi DAT0, [PTR, #-13]
- ++ ldrbpl DAT0, [PTR, #-11]
- ++ addpl RESULT, RESULT, #2
- ++ teq DAT0, #0
- ++ it eq
- ++ subeq RESULT, RESULT, #1
- ++ b 98f
- ++96: add RESULT, RESULT, #4
- ++ teq TMP2, #0
- ++ beq 97f @ not in next 4 bytes
- ++ sub TMP2, DAT2, #0x20000
- ++ bics TMP2, TMP2, DAT2
- ++ itee mi
- ++ ldrbmi DAT0, [PTR, #-9]
- ++ ldrbpl DAT0, [PTR, #-7]
- ++ addpl RESULT, RESULT, #2
- ++ teq DAT0, #0
- ++ it eq
- ++ subeq RESULT, RESULT, #1
- ++ b 98f
- ++97: add RESULT, RESULT, #4
- ++ sub TMP3, DAT3, #0x20000
- ++ bics TMP3, TMP3, DAT3
- ++ itee mi
- ++ ldrbmi DAT0, [PTR, #-5]
- ++ ldrbpl DAT0, [PTR, #-3]
- ++ addpl RESULT, RESULT, #2
- ++ teq DAT0, #0
- ++ it eq
- ++ subeq RESULT, RESULT, #1
- ++ @ drop through to 98f
- ++98: setend le
- ++99: pop {v1-v6,pc}
- ++.endfunc
- ++
- ++ .unreq RESULT
- ++ .unreq BUF
- ++ .unreq SIZE
- ++ .unreq PATTERN
- ++ .unreq PTR
- ++ .unreq DAT0
- ++ .unreq DAT1
- ++ .unreq DAT2
- ++ .unreq DAT3
- ++ .unreq TMP0
- ++ .unreq TMP1
- ++ .unreq TMP2
- ++ .unreq TMP3
- +diff --git a/libavcodec/arm/h264dsp_init_arm.c b/libavcodec/arm/h264dsp_init_arm.c
- +index bb8b3b9..b206a1b 100644
- +--- a/libavcodec/arm/h264dsp_init_arm.c
- ++++ b/libavcodec/arm/h264dsp_init_arm.c
- +@@ -24,6 +24,8 @@
- + #include "libavutil/arm/cpu.h"
- + #include "libavcodec/h264dsp.h"
- +
- ++int ff_h264_find_start_code_candidate_armv6(const uint8_t *buf, int size);
- ++
- + void ff_h264_v_loop_filter_luma_neon(uint8_t *pix, int stride, int alpha,
- + int beta, int8_t *tc0);
- + void ff_h264_h_loop_filter_luma_neon(uint8_t *pix, int stride, int alpha,
- +@@ -102,6 +104,8 @@ av_cold void ff_h264dsp_init_arm(H264DSPContext *c, const int bit_depth,
- + {
- + int cpu_flags = av_get_cpu_flags();
- +
- ++ if (have_armv6(cpu_flags))
- ++ c->h264_find_start_code_candidate = ff_h264_find_start_code_candidate_armv6;
- + if (have_neon(cpu_flags))
- + h264dsp_init_neon(c, bit_depth, chroma_format_idc);
- + }
- +--
- +1.7.9.5
- --
- 1.9.3
- From db098a580259625bb7b7385a48cb0756aea5cafe Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Wed, 16 Apr 2014 01:51:31 +0100
- Subject: [PATCH 05/94] h264: Move search code search functions into separate
- source files.
- This permits re-use with parsers for codecs which use similar start codes.
- Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
- ---
- lib/ffmpeg/libavcodec/Makefile | 2 +-
- lib/ffmpeg/libavcodec/arm/Makefile | 2 +-
- lib/ffmpeg/libavcodec/arm/h264dsp_armv6.S | 253 ---------------------------
- lib/ffmpeg/libavcodec/arm/h264dsp_init_arm.c | 4 +-
- lib/ffmpeg/libavcodec/arm/startcode_armv6.S | 253 +++++++++++++++++++++++++++
- lib/ffmpeg/libavcodec/h264dsp.c | 31 +---
- lib/ffmpeg/libavcodec/startcode.c | 57 ++++++
- lib/ffmpeg/libavcodec/startcode.h | 35 ++++
- 8 files changed, 351 insertions(+), 286 deletions(-)
- delete mode 100644 lib/ffmpeg/libavcodec/arm/h264dsp_armv6.S
- create mode 100644 lib/ffmpeg/libavcodec/arm/startcode_armv6.S
- create mode 100644 lib/ffmpeg/libavcodec/startcode.c
- create mode 100644 lib/ffmpeg/libavcodec/startcode.h
- diff --git a/lib/ffmpeg/libavcodec/Makefile b/lib/ffmpeg/libavcodec/Makefile
- index dc065a5..460f42c 100644
- --- a/lib/ffmpeg/libavcodec/Makefile
- +++ b/lib/ffmpeg/libavcodec/Makefile
- @@ -49,7 +49,7 @@ OBJS-$(CONFIG_FFT) += avfft.o fft_fixed.o fft_float.o \
- $(FFT-OBJS-yes)
- OBJS-$(CONFIG_GOLOMB) += golomb.o
- OBJS-$(CONFIG_H264CHROMA) += h264chroma.o
- -OBJS-$(CONFIG_H264DSP) += h264dsp.o h264idct.o
- +OBJS-$(CONFIG_H264DSP) += h264dsp.o h264idct.o startcode.o
- OBJS-$(CONFIG_H264PRED) += h264pred.o
- OBJS-$(CONFIG_H264QPEL) += h264qpel.o
- OBJS-$(CONFIG_HUFFMAN) += huffman.o
- diff --git a/lib/ffmpeg/libavcodec/arm/Makefile b/lib/ffmpeg/libavcodec/arm/Makefile
- index 480000b71..0b432e3 100644
- --- a/lib/ffmpeg/libavcodec/arm/Makefile
- +++ b/lib/ffmpeg/libavcodec/arm/Makefile
- @@ -9,7 +9,7 @@ OBJS-$(CONFIG_AAC_DECODER) += arm/sbrdsp_init_arm.o \
- OBJS-$(CONFIG_DCA_DECODER) += arm/dcadsp_init_arm.o \
-
- ARMV6-OBJS-$(CONFIG_AC3DSP) += arm/ac3dsp_armv6.o
- -ARMV6-OBJS-$(CONFIG_H264DSP) += arm/h264dsp_armv6.o
- +ARMV6-OBJS-$(CONFIG_H264DSP) += arm/startcode_armv6.o
-
- OBJS-$(CONFIG_FLAC_DECODER) += arm/flacdsp_init_arm.o \
- arm/flacdsp_arm.o \
- diff --git a/lib/ffmpeg/libavcodec/arm/h264dsp_armv6.S b/lib/ffmpeg/libavcodec/arm/h264dsp_armv6.S
- deleted file mode 100644
- index c4f12a6..0000000
- --- a/lib/ffmpeg/libavcodec/arm/h264dsp_armv6.S
- +++ /dev/null
- @@ -1,253 +0,0 @@
- -/*
- - * Copyright (c) 2013 RISC OS Open Ltd
- - * Author: Ben Avison <bavison@riscosopen.org>
- - *
- - * This file is part of Libav.
- - *
- - * Libav is free software; you can redistribute it and/or
- - * modify it under the terms of the GNU Lesser General Public
- - * License as published by the Free Software Foundation; either
- - * version 2.1 of the License, or (at your option) any later version.
- - *
- - * Libav is distributed in the hope that it will be useful,
- - * but WITHOUT ANY WARRANTY; without even the implied warranty of
- - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- - * Lesser General Public License for more details.
- - *
- - * You should have received a copy of the GNU Lesser General Public
- - * License along with Libav; if not, write to the Free Software
- - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- - */
- -
- -#include "libavutil/arm/asm.S"
- -
- -RESULT .req a1
- -BUF .req a1
- -SIZE .req a2
- -PATTERN .req a3
- -PTR .req a4
- -DAT0 .req v1
- -DAT1 .req v2
- -DAT2 .req v3
- -DAT3 .req v4
- -TMP0 .req v5
- -TMP1 .req v6
- -TMP2 .req ip
- -TMP3 .req lr
- -
- -#define PRELOAD_DISTANCE 4
- -
- -.macro innerloop4
- - ldr DAT0, [PTR], #4
- - subs SIZE, SIZE, #4 @ C flag survives rest of macro
- - sub TMP0, DAT0, PATTERN, lsr #14
- - bic TMP0, TMP0, DAT0
- - ands TMP0, TMP0, PATTERN
- -.endm
- -
- -.macro innerloop16 decrement, do_preload
- - ldmia PTR!, {DAT0,DAT1,DAT2,DAT3}
- - .ifnc "\do_preload",""
- - pld [PTR, #PRELOAD_DISTANCE*32]
- - .endif
- - .ifnc "\decrement",""
- - subs SIZE, SIZE, #\decrement @ C flag survives rest of macro
- - .endif
- - sub TMP0, DAT0, PATTERN, lsr #14
- - sub TMP1, DAT1, PATTERN, lsr #14
- - bic TMP0, TMP0, DAT0
- - bic TMP1, TMP1, DAT1
- - sub TMP2, DAT2, PATTERN, lsr #14
- - sub TMP3, DAT3, PATTERN, lsr #14
- - ands TMP0, TMP0, PATTERN
- - bic TMP2, TMP2, DAT2
- - it eq
- - andseq TMP1, TMP1, PATTERN
- - bic TMP3, TMP3, DAT3
- - itt eq
- - andseq TMP2, TMP2, PATTERN
- - andseq TMP3, TMP3, PATTERN
- -.endm
- -
- -/* int ff_h264_find_start_code_candidate_armv6(const uint8_t *buf, int size) */
- -function ff_h264_find_start_code_candidate_armv6, export=1
- - push {v1-v6,lr}
- - mov PTR, BUF
- - @ Ensure there are at least (PRELOAD_DISTANCE+2) complete cachelines to go
- - @ before using code that does preloads
- - cmp SIZE, #(PRELOAD_DISTANCE+3)*32 - 1
- - blo 60f
- -
- - @ Get to word-alignment, 1 byte at a time
- - tst PTR, #3
- - beq 2f
- -1: ldrb DAT0, [PTR], #1
- - sub SIZE, SIZE, #1
- - teq DAT0, #0
- - beq 90f
- - tst PTR, #3
- - bne 1b
- -2: @ Get to 4-word alignment, 1 word at a time
- - ldr PATTERN, =0x80008000
- - setend be
- - tst PTR, #12
- - beq 4f
- -3: innerloop4
- - bne 91f
- - tst PTR, #12
- - bne 3b
- -4: @ Get to cacheline (8-word) alignment
- - tst PTR, #16
- - beq 5f
- - innerloop16 16
- - bne 93f
- -5: @ Check complete cachelines, with preloading
- - @ We need to stop when there are still (PRELOAD_DISTANCE+1)
- - @ complete cachelines to go
- - sub SIZE, SIZE, #(PRELOAD_DISTANCE+2)*32
- -6: innerloop16 , do_preload
- - bne 93f
- - innerloop16 32
- - bne 93f
- - bcs 6b
- - @ Preload trailing part-cacheline, if any
- - tst SIZE, #31
- - beq 7f
- - pld [PTR, #(PRELOAD_DISTANCE+1)*32]
- - @ Check remaining data without doing any more preloads. First
- - @ do in chunks of 4 words:
- -7: adds SIZE, SIZE, #(PRELOAD_DISTANCE+2)*32 - 16
- - bmi 9f
- -8: innerloop16 16
- - bne 93f
- - bcs 8b
- - @ Then in words:
- -9: adds SIZE, SIZE, #16 - 4
- - bmi 11f
- -10: innerloop4
- - bne 91f
- - bcs 10b
- -11: setend le
- - @ Check second byte of final halfword
- - ldrb DAT0, [PTR, #-1]
- - teq DAT0, #0
- - beq 90f
- - @ Check any remaining bytes
- - tst SIZE, #3
- - beq 13f
- -12: ldrb DAT0, [PTR], #1
- - sub SIZE, SIZE, #1
- - teq DAT0, #0
- - beq 90f
- - tst SIZE, #3
- - bne 12b
- - @ No candidate found
- -13: sub RESULT, PTR, BUF
- - b 99f
- -
- -60: @ Small buffer - simply check by looping over bytes
- - subs SIZE, SIZE, #1
- - bcc 99f
- -61: ldrb DAT0, [PTR], #1
- - subs SIZE, SIZE, #1
- - teq DAT0, #0
- - beq 90f
- - bcs 61b
- - @ No candidate found
- - sub RESULT, PTR, BUF
- - b 99f
- -
- -90: @ Found a candidate at the preceding byte
- - sub RESULT, PTR, BUF
- - sub RESULT, RESULT, #1
- - b 99f
- -
- -91: @ Found a candidate somewhere in the preceding 4 bytes
- - sub RESULT, PTR, BUF
- - sub RESULT, RESULT, #4
- - sub TMP0, DAT0, #0x20000
- - bics TMP0, TMP0, DAT0
- - itt pl
- - ldrbpl DAT0, [PTR, #-3]
- - addpl RESULT, RESULT, #2
- - bpl 92f
- - teq RESULT, #0
- - beq 98f @ don't look back a byte if found at first byte in buffer
- - ldrb DAT0, [PTR, #-5]
- -92: teq DAT0, #0
- - it eq
- - subeq RESULT, RESULT, #1
- - b 98f
- -
- -93: @ Found a candidate somewhere in the preceding 16 bytes
- - sub RESULT, PTR, BUF
- - sub RESULT, RESULT, #16
- - teq TMP0, #0
- - beq 95f @ not in first 4 bytes
- - sub TMP0, DAT0, #0x20000
- - bics TMP0, TMP0, DAT0
- - itt pl
- - ldrbpl DAT0, [PTR, #-15]
- - addpl RESULT, RESULT, #2
- - bpl 94f
- - teq RESULT, #0
- - beq 98f @ don't look back a byte if found at first byte in buffer
- - ldrb DAT0, [PTR, #-17]
- -94: teq DAT0, #0
- - it eq
- - subeq RESULT, RESULT, #1
- - b 98f
- -95: add RESULT, RESULT, #4
- - teq TMP1, #0
- - beq 96f @ not in next 4 bytes
- - sub TMP1, DAT1, #0x20000
- - bics TMP1, TMP1, DAT1
- - itee mi
- - ldrbmi DAT0, [PTR, #-13]
- - ldrbpl DAT0, [PTR, #-11]
- - addpl RESULT, RESULT, #2
- - teq DAT0, #0
- - it eq
- - subeq RESULT, RESULT, #1
- - b 98f
- -96: add RESULT, RESULT, #4
- - teq TMP2, #0
- - beq 97f @ not in next 4 bytes
- - sub TMP2, DAT2, #0x20000
- - bics TMP2, TMP2, DAT2
- - itee mi
- - ldrbmi DAT0, [PTR, #-9]
- - ldrbpl DAT0, [PTR, #-7]
- - addpl RESULT, RESULT, #2
- - teq DAT0, #0
- - it eq
- - subeq RESULT, RESULT, #1
- - b 98f
- -97: add RESULT, RESULT, #4
- - sub TMP3, DAT3, #0x20000
- - bics TMP3, TMP3, DAT3
- - itee mi
- - ldrbmi DAT0, [PTR, #-5]
- - ldrbpl DAT0, [PTR, #-3]
- - addpl RESULT, RESULT, #2
- - teq DAT0, #0
- - it eq
- - subeq RESULT, RESULT, #1
- - @ drop through to 98f
- -98: setend le
- -99: pop {v1-v6,pc}
- -.endfunc
- -
- - .unreq RESULT
- - .unreq BUF
- - .unreq SIZE
- - .unreq PATTERN
- - .unreq PTR
- - .unreq DAT0
- - .unreq DAT1
- - .unreq DAT2
- - .unreq DAT3
- - .unreq TMP0
- - .unreq TMP1
- - .unreq TMP2
- - .unreq TMP3
- diff --git a/lib/ffmpeg/libavcodec/arm/h264dsp_init_arm.c b/lib/ffmpeg/libavcodec/arm/h264dsp_init_arm.c
- index 2804e56..842fb9f 100644
- --- a/lib/ffmpeg/libavcodec/arm/h264dsp_init_arm.c
- +++ b/lib/ffmpeg/libavcodec/arm/h264dsp_init_arm.c
- @@ -24,7 +24,7 @@
- #include "libavutil/arm/cpu.h"
- #include "libavcodec/h264dsp.h"
-
- -int ff_h264_find_start_code_candidate_armv6(const uint8_t *buf, int size);
- +int ff_startcode_find_candidate_armv6(const uint8_t *buf, int size);
-
- void ff_h264_v_loop_filter_luma_neon(uint8_t *pix, int stride, int alpha,
- int beta, int8_t *tc0);
- @@ -109,7 +109,7 @@ av_cold void ff_h264dsp_init_arm(H264DSPContext *c, const int bit_depth,
- int cpu_flags = av_get_cpu_flags();
-
- if (have_armv6(cpu_flags))
- - c->h264_find_start_code_candidate = ff_h264_find_start_code_candidate_armv6;
- + c->h264_find_start_code_candidate = ff_startcode_find_candidate_armv6;
- if (have_neon(cpu_flags))
- ff_h264dsp_init_neon(c, bit_depth, chroma_format_idc);
- }
- diff --git a/lib/ffmpeg/libavcodec/arm/startcode_armv6.S b/lib/ffmpeg/libavcodec/arm/startcode_armv6.S
- new file mode 100644
- index 0000000..a46f009
- --- /dev/null
- +++ b/lib/ffmpeg/libavcodec/arm/startcode_armv6.S
- @@ -0,0 +1,253 @@
- +/*
- + * Copyright (c) 2013 RISC OS Open Ltd
- + * Author: Ben Avison <bavison@riscosopen.org>
- + *
- + * This file is part of FFmpeg.
- + *
- + * FFmpeg is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU Lesser General Public
- + * License as published by the Free Software Foundation; either
- + * version 2.1 of the License, or (at your option) any later version.
- + *
- + * FFmpeg is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- + * Lesser General Public License for more details.
- + *
- + * You should have received a copy of the GNU Lesser General Public
- + * License along with FFmpeg; if not, write to the Free Software
- + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- + */
- +
- +#include "libavutil/arm/asm.S"
- +
- +RESULT .req a1
- +BUF .req a1
- +SIZE .req a2
- +PATTERN .req a3
- +PTR .req a4
- +DAT0 .req v1
- +DAT1 .req v2
- +DAT2 .req v3
- +DAT3 .req v4
- +TMP0 .req v5
- +TMP1 .req v6
- +TMP2 .req ip
- +TMP3 .req lr
- +
- +#define PRELOAD_DISTANCE 4
- +
- +.macro innerloop4
- + ldr DAT0, [PTR], #4
- + subs SIZE, SIZE, #4 @ C flag survives rest of macro
- + sub TMP0, DAT0, PATTERN, lsr #14
- + bic TMP0, TMP0, DAT0
- + ands TMP0, TMP0, PATTERN
- +.endm
- +
- +.macro innerloop16 decrement, do_preload
- + ldmia PTR!, {DAT0,DAT1,DAT2,DAT3}
- + .ifnc "\do_preload",""
- + pld [PTR, #PRELOAD_DISTANCE*32]
- + .endif
- + .ifnc "\decrement",""
- + subs SIZE, SIZE, #\decrement @ C flag survives rest of macro
- + .endif
- + sub TMP0, DAT0, PATTERN, lsr #14
- + sub TMP1, DAT1, PATTERN, lsr #14
- + bic TMP0, TMP0, DAT0
- + bic TMP1, TMP1, DAT1
- + sub TMP2, DAT2, PATTERN, lsr #14
- + sub TMP3, DAT3, PATTERN, lsr #14
- + ands TMP0, TMP0, PATTERN
- + bic TMP2, TMP2, DAT2
- + it eq
- + andseq TMP1, TMP1, PATTERN
- + bic TMP3, TMP3, DAT3
- + itt eq
- + andseq TMP2, TMP2, PATTERN
- + andseq TMP3, TMP3, PATTERN
- +.endm
- +
- +/* int ff_startcode_find_candidate_armv6(const uint8_t *buf, int size) */
- +function ff_startcode_find_candidate_armv6, export=1
- + push {v1-v6,lr}
- + mov PTR, BUF
- + @ Ensure there are at least (PRELOAD_DISTANCE+2) complete cachelines to go
- + @ before using code that does preloads
- + cmp SIZE, #(PRELOAD_DISTANCE+3)*32 - 1
- + blo 60f
- +
- + @ Get to word-alignment, 1 byte at a time
- + tst PTR, #3
- + beq 2f
- +1: ldrb DAT0, [PTR], #1
- + sub SIZE, SIZE, #1
- + teq DAT0, #0
- + beq 90f
- + tst PTR, #3
- + bne 1b
- +2: @ Get to 4-word alignment, 1 word at a time
- + ldr PATTERN, =0x80008000
- + setend be
- + tst PTR, #12
- + beq 4f
- +3: innerloop4
- + bne 91f
- + tst PTR, #12
- + bne 3b
- +4: @ Get to cacheline (8-word) alignment
- + tst PTR, #16
- + beq 5f
- + innerloop16 16
- + bne 93f
- +5: @ Check complete cachelines, with preloading
- + @ We need to stop when there are still (PRELOAD_DISTANCE+1)
- + @ complete cachelines to go
- + sub SIZE, SIZE, #(PRELOAD_DISTANCE+2)*32
- +6: innerloop16 , do_preload
- + bne 93f
- + innerloop16 32
- + bne 93f
- + bcs 6b
- + @ Preload trailing part-cacheline, if any
- + tst SIZE, #31
- + beq 7f
- + pld [PTR, #(PRELOAD_DISTANCE+1)*32]
- + @ Check remaining data without doing any more preloads. First
- + @ do in chunks of 4 words:
- +7: adds SIZE, SIZE, #(PRELOAD_DISTANCE+2)*32 - 16
- + bmi 9f
- +8: innerloop16 16
- + bne 93f
- + bcs 8b
- + @ Then in words:
- +9: adds SIZE, SIZE, #16 - 4
- + bmi 11f
- +10: innerloop4
- + bne 91f
- + bcs 10b
- +11: setend le
- + @ Check second byte of final halfword
- + ldrb DAT0, [PTR, #-1]
- + teq DAT0, #0
- + beq 90f
- + @ Check any remaining bytes
- + tst SIZE, #3
- + beq 13f
- +12: ldrb DAT0, [PTR], #1
- + sub SIZE, SIZE, #1
- + teq DAT0, #0
- + beq 90f
- + tst SIZE, #3
- + bne 12b
- + @ No candidate found
- +13: sub RESULT, PTR, BUF
- + b 99f
- +
- +60: @ Small buffer - simply check by looping over bytes
- + subs SIZE, SIZE, #1
- + bcc 99f
- +61: ldrb DAT0, [PTR], #1
- + subs SIZE, SIZE, #1
- + teq DAT0, #0
- + beq 90f
- + bcs 61b
- + @ No candidate found
- + sub RESULT, PTR, BUF
- + b 99f
- +
- +90: @ Found a candidate at the preceding byte
- + sub RESULT, PTR, BUF
- + sub RESULT, RESULT, #1
- + b 99f
- +
- +91: @ Found a candidate somewhere in the preceding 4 bytes
- + sub RESULT, PTR, BUF
- + sub RESULT, RESULT, #4
- + sub TMP0, DAT0, #0x20000
- + bics TMP0, TMP0, DAT0
- + itt pl
- + ldrbpl DAT0, [PTR, #-3]
- + addpl RESULT, RESULT, #2
- + bpl 92f
- + teq RESULT, #0
- + beq 98f @ don't look back a byte if found at first byte in buffer
- + ldrb DAT0, [PTR, #-5]
- +92: teq DAT0, #0
- + it eq
- + subeq RESULT, RESULT, #1
- + b 98f
- +
- +93: @ Found a candidate somewhere in the preceding 16 bytes
- + sub RESULT, PTR, BUF
- + sub RESULT, RESULT, #16
- + teq TMP0, #0
- + beq 95f @ not in first 4 bytes
- + sub TMP0, DAT0, #0x20000
- + bics TMP0, TMP0, DAT0
- + itt pl
- + ldrbpl DAT0, [PTR, #-15]
- + addpl RESULT, RESULT, #2
- + bpl 94f
- + teq RESULT, #0
- + beq 98f @ don't look back a byte if found at first byte in buffer
- + ldrb DAT0, [PTR, #-17]
- +94: teq DAT0, #0
- + it eq
- + subeq RESULT, RESULT, #1
- + b 98f
- +95: add RESULT, RESULT, #4
- + teq TMP1, #0
- + beq 96f @ not in next 4 bytes
- + sub TMP1, DAT1, #0x20000
- + bics TMP1, TMP1, DAT1
- + itee mi
- + ldrbmi DAT0, [PTR, #-13]
- + ldrbpl DAT0, [PTR, #-11]
- + addpl RESULT, RESULT, #2
- + teq DAT0, #0
- + it eq
- + subeq RESULT, RESULT, #1
- + b 98f
- +96: add RESULT, RESULT, #4
- + teq TMP2, #0
- + beq 97f @ not in next 4 bytes
- + sub TMP2, DAT2, #0x20000
- + bics TMP2, TMP2, DAT2
- + itee mi
- + ldrbmi DAT0, [PTR, #-9]
- + ldrbpl DAT0, [PTR, #-7]
- + addpl RESULT, RESULT, #2
- + teq DAT0, #0
- + it eq
- + subeq RESULT, RESULT, #1
- + b 98f
- +97: add RESULT, RESULT, #4
- + sub TMP3, DAT3, #0x20000
- + bics TMP3, TMP3, DAT3
- + itee mi
- + ldrbmi DAT0, [PTR, #-5]
- + ldrbpl DAT0, [PTR, #-3]
- + addpl RESULT, RESULT, #2
- + teq DAT0, #0
- + it eq
- + subeq RESULT, RESULT, #1
- + @ drop through to 98f
- +98: setend le
- +99: pop {v1-v6,pc}
- +endfunc
- +
- + .unreq RESULT
- + .unreq BUF
- + .unreq SIZE
- + .unreq PATTERN
- + .unreq PTR
- + .unreq DAT0
- + .unreq DAT1
- + .unreq DAT2
- + .unreq DAT3
- + .unreq TMP0
- + .unreq TMP1
- + .unreq TMP2
- + .unreq TMP3
- diff --git a/lib/ffmpeg/libavcodec/h264dsp.c b/lib/ffmpeg/libavcodec/h264dsp.c
- index b7d61cd..a84ae59 100644
- --- a/lib/ffmpeg/libavcodec/h264dsp.c
- +++ b/lib/ffmpeg/libavcodec/h264dsp.c
- @@ -30,6 +30,7 @@
- #include "avcodec.h"
- #include "h264dsp.h"
- #include "h264idct.h"
- +#include "startcode.h"
- #include "libavutil/common.h"
-
- #define BIT_DEPTH 8
- @@ -60,34 +61,6 @@
- #include "h264addpx_template.c"
- #undef BIT_DEPTH
-
- -static int h264_find_start_code_candidate_c(const uint8_t *buf, int size)
- -{
- - int i = 0;
- -#if HAVE_FAST_UNALIGNED
- - /* we check i < size instead of i + 3 / 7 because it is
- - * simpler and there must be FF_INPUT_BUFFER_PADDING_SIZE
- - * bytes at the end.
- - */
- -#if HAVE_FAST_64BIT
- - while (i < size &&
- - !((~*(const uint64_t *)(buf + i) &
- - (*(const uint64_t *)(buf + i) - 0x0101010101010101ULL)) &
- - 0x8080808080808080ULL))
- - i += 8;
- -#else
- - while (i < size &&
- - !((~*(const uint32_t *)(buf + i) &
- - (*(const uint32_t *)(buf + i) - 0x01010101U)) &
- - 0x80808080U))
- - i += 4;
- -#endif
- -#endif
- - for (; i < size; i++)
- - if (!buf[i])
- - break;
- - return i;
- -}
- -
- void ff_h264dsp_init(H264DSPContext *c, const int bit_depth, const int chroma_format_idc)
- {
- #undef FUNC
- @@ -174,7 +147,7 @@ void ff_h264dsp_init(H264DSPContext *c, const int bit_depth, const int chroma_fo
- H264_DSP(8);
- break;
- }
- - c->h264_find_start_code_candidate = h264_find_start_code_candidate_c;
- + c->h264_find_start_code_candidate = ff_startcode_find_candidate_c;
-
- if (ARCH_ARM) ff_h264dsp_init_arm(c, bit_depth, chroma_format_idc);
- if (HAVE_ALTIVEC) ff_h264dsp_init_ppc(c, bit_depth, chroma_format_idc);
- diff --git a/lib/ffmpeg/libavcodec/startcode.c b/lib/ffmpeg/libavcodec/startcode.c
- new file mode 100644
- index 0000000..5df7695
- --- /dev/null
- +++ b/lib/ffmpeg/libavcodec/startcode.c
- @@ -0,0 +1,57 @@
- +/*
- + * Copyright (c) 2003-2010 Michael Niedermayer <michaelni@gmx.at>
- + *
- + * This file is part of FFmpeg.
- + *
- + * FFmpeg is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU Lesser General Public
- + * License as published by the Free Software Foundation; either
- + * version 2.1 of the License, or (at your option) any later version.
- + *
- + * FFmpeg is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- + * Lesser General Public License for more details.
- + *
- + * You should have received a copy of the GNU Lesser General Public
- + * License along with FFmpeg; if not, write to the Free Software
- + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- + */
- +
- +/**
- + * @file
- + * Accelerated start code search function for start codes common to
- + * MPEG-1/2/4 video, VC-1, H.264/5
- + * @author Michael Niedermayer <michaelni@gmx.at>
- + */
- +
- +#include "startcode.h"
- +#include "config.h"
- +
- +int ff_startcode_find_candidate_c(const uint8_t *buf, int size)
- +{
- + int i = 0;
- +#if HAVE_FAST_UNALIGNED
- + /* we check i < size instead of i + 3 / 7 because it is
- + * simpler and there must be FF_INPUT_BUFFER_PADDING_SIZE
- + * bytes at the end.
- + */
- +# if HAVE_FAST_64BIT
- + while (i < size &&
- + !((~*(const uint64_t *)(buf + i) &
- + (*(const uint64_t *)(buf + i) - 0x0101010101010101ULL)) &
- + 0x8080808080808080ULL))
- + i += 8;
- +# else
- + while (i < size &&
- + !((~*(const uint32_t *)(buf + i) &
- + (*(const uint32_t *)(buf + i) - 0x01010101U)) &
- + 0x80808080U))
- + i += 4;
- +# endif
- +#endif
- + for (; i < size; i++)
- + if (!buf[i])
- + break;
- + return i;
- +}
- diff --git a/lib/ffmpeg/libavcodec/startcode.h b/lib/ffmpeg/libavcodec/startcode.h
- new file mode 100644
- index 0000000..cc55d5f
- --- /dev/null
- +++ b/lib/ffmpeg/libavcodec/startcode.h
- @@ -0,0 +1,35 @@
- +/*
- + * Copyright (c) 2003-2010 Michael Niedermayer <michaelni@gmx.at>
- + *
- + * This file is part of FFmpeg.
- + *
- + * FFmpeg is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU Lesser General Public
- + * License as published by the Free Software Foundation; either
- + * version 2.1 of the License, or (at your option) any later version.
- + *
- + * FFmpeg is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- + * Lesser General Public License for more details.
- + *
- + * You should have received a copy of the GNU Lesser General Public
- + * License along with FFmpeg; if not, write to the Free Software
- + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- + */
- +
- +/**
- + * @file
- + * Accelerated start code search function for start codes common to
- + * MPEG-1/2/4 video, VC-1, H.264/5
- + * @author Michael Niedermayer <michaelni@gmx.at>
- + */
- +
- +#ifndef AVCODEC_STARTCODE_H
- +#define AVCODEC_STARTCODE_H
- +
- +#include <stdint.h>
- +
- +int ff_startcode_find_candidate_c(const uint8_t *buf, int size);
- +
- +#endif /* AVCODEC_STARTCODE_H */
- --
- 1.9.3
- From 7d95eb8e026582e5446e7e11d75ba999286a34d0 Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Wed, 16 Apr 2014 01:51:32 +0100
- Subject: [PATCH 06/94] vc-1: Add platform-specific start code search routine
- to VC1DSPContext.
- Initialise VC1DSPContext for parser as well as for decoder.
- Note, the VC-1 code doesn't actually use the function pointer yet.
- Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
- ---
- lib/ffmpeg/libavcodec/Makefile | 7 +++---
- lib/ffmpeg/libavcodec/arm/Makefile | 3 +++
- lib/ffmpeg/libavcodec/arm/vc1dsp_init_arm.c | 33 +++++++++++++++++++++++++++++
- lib/ffmpeg/libavcodec/vc1.c | 2 ++
- lib/ffmpeg/libavcodec/vc1dec.c | 1 -
- lib/ffmpeg/libavcodec/vc1dsp.c | 5 +++++
- lib/ffmpeg/libavcodec/vc1dsp.h | 9 ++++++++
- 7 files changed, 56 insertions(+), 4 deletions(-)
- create mode 100644 lib/ffmpeg/libavcodec/arm/vc1dsp_init_arm.c
- diff --git a/lib/ffmpeg/libavcodec/Makefile b/lib/ffmpeg/libavcodec/Makefile
- index 460f42c..8d8a548 100644
- --- a/lib/ffmpeg/libavcodec/Makefile
- +++ b/lib/ffmpeg/libavcodec/Makefile
- @@ -455,7 +455,7 @@ OBJS-$(CONFIG_VB_DECODER) += vb.o
- OBJS-$(CONFIG_VBLE_DECODER) += vble.o
- OBJS-$(CONFIG_VC1_DECODER) += vc1dec.o vc1.o vc1data.o vc1dsp.o \
- msmpeg4.o msmpeg4data.o \
- - intrax8.o intrax8dsp.o
- + intrax8.o intrax8dsp.o startcode.o
- OBJS-$(CONFIG_VC1_DXVA2_HWACCEL) += dxva2_vc1.o
- OBJS-$(CONFIG_VC1_VAAPI_HWACCEL) += vaapi_vc1.o
- OBJS-$(CONFIG_VC1_VDPAU_HWACCEL) += vdpau_vc1.o
- @@ -487,6 +487,7 @@ OBJS-$(CONFIG_WMAVOICE_DECODER) += wmavoice.o \
- celp_filters.o \
- acelp_vectors.o acelp_filters.o
- OBJS-$(CONFIG_WMV1_DECODER) += msmpeg4.o msmpeg4data.o
- +
- OBJS-$(CONFIG_WMV2_DECODER) += wmv2dec.o wmv2.o wmv2dsp.o \
- msmpeg4.o msmpeg4data.o \
- intrax8.o intrax8dsp.o
- @@ -746,9 +747,9 @@ OBJS-$(CONFIG_PNM_PARSER) += pnm_parser.o pnm.o
- OBJS-$(CONFIG_RV30_PARSER) += rv34_parser.o
- OBJS-$(CONFIG_RV40_PARSER) += rv34_parser.o
- OBJS-$(CONFIG_TAK_PARSER) += tak_parser.o tak.o
- -OBJS-$(CONFIG_VC1_PARSER) += vc1_parser.o vc1.o vc1data.o \
- +OBJS-$(CONFIG_VC1_PARSER) += vc1_parser.o vc1.o vc1data.o vc1dsp.o \
- msmpeg4.o msmpeg4data.o mpeg4video.o \
- - h263.o
- + h263.o startcode.o
- OBJS-$(CONFIG_VORBIS_PARSER) += vorbis_parser.o xiph.o
- OBJS-$(CONFIG_VP3_PARSER) += vp3_parser.o
- OBJS-$(CONFIG_VP8_PARSER) += vp8_parser.o
- diff --git a/lib/ffmpeg/libavcodec/arm/Makefile b/lib/ffmpeg/libavcodec/arm/Makefile
- index 0b432e3..715eed7 100644
- --- a/lib/ffmpeg/libavcodec/arm/Makefile
- +++ b/lib/ffmpeg/libavcodec/arm/Makefile
- @@ -16,6 +16,9 @@ OBJS-$(CONFIG_FLAC_DECODER) += arm/flacdsp_init_arm.o \
-
- OBJS-$(CONFIG_MPEGAUDIODSP) += arm/mpegaudiodsp_init_arm.o
- ARMV6-OBJS-$(CONFIG_MPEGAUDIODSP) += arm/mpegaudiodsp_fixed_armv6.o
- +ARMV6-OBJS-$(CONFIG_VC1_DECODER) += arm/startcode_armv6.o
- +OBJS-$(CONFIG_VC1_DECODER) += arm/vc1dsp_init_arm.o
- +ARMV6-OBJS-$(CONFIG_VC1_PARSER) += arm/startcode_armv6.o
-
- OBJS-$(CONFIG_MPEGVIDEO) += arm/mpegvideo_arm.o
- OBJS-$(CONFIG_VORBIS_DECODER) += arm/vorbisdsp_init_arm.o
- diff --git a/lib/ffmpeg/libavcodec/arm/vc1dsp_init_arm.c b/lib/ffmpeg/libavcodec/arm/vc1dsp_init_arm.c
- new file mode 100644
- index 0000000..fec5e78
- --- /dev/null
- +++ b/lib/ffmpeg/libavcodec/arm/vc1dsp_init_arm.c
- @@ -0,0 +1,33 @@
- +/*
- + * This file is part of Libav.
- + *
- + * Libav is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU Lesser General Public
- + * License as published by the Free Software Foundation; either
- + * version 2.1 of the License, or (at your option) any later version.
- + *
- + * Libav is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- + * Lesser General Public License for more details.
- + *
- + * You should have received a copy of the GNU Lesser General Public
- + * License along with Libav; if not, write to the Free Software
- + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- + */
- +
- +#include <stdint.h>
- +
- +#include "libavutil/attributes.h"
- +#include "libavutil/arm/cpu.h"
- +#include "libavcodec/vc1dsp.h"
- +
- +int ff_startcode_find_candidate_armv6(const uint8_t *buf, int size);
- +
- +av_cold void ff_vc1dsp_init_arm(VC1DSPContext *dsp)
- +{
- + int cpu_flags = av_get_cpu_flags();
- +
- + if (have_armv6(cpu_flags))
- + dsp->vc1_find_start_code_candidate = ff_startcode_find_candidate_armv6;
- +}
- diff --git a/lib/ffmpeg/libavcodec/vc1.c b/lib/ffmpeg/libavcodec/vc1.c
- index e2e90a8..9b15809 100644
- --- a/lib/ffmpeg/libavcodec/vc1.c
- +++ b/lib/ffmpeg/libavcodec/vc1.c
- @@ -1663,5 +1663,7 @@ int ff_vc1_init_common(VC1Context *v)
- v->pq = -1;
- v->mvrange = 0; /* 7.1.1.18, p80 */
-
- + ff_vc1dsp_init(&v->vc1dsp);
- +
- return 0;
- }
- diff --git a/lib/ffmpeg/libavcodec/vc1dec.c b/lib/ffmpeg/libavcodec/vc1dec.c
- index 2130c74..9fd3cae 100644
- --- a/lib/ffmpeg/libavcodec/vc1dec.c
- +++ b/lib/ffmpeg/libavcodec/vc1dec.c
- @@ -5193,7 +5193,6 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx)
- ff_vc1_decode_end(avctx);
-
- ff_h264chroma_init(&v->h264chroma, 8);
- - ff_vc1dsp_init(&v->vc1dsp);
-
- if (avctx->codec_id == AV_CODEC_ID_WMV3 || avctx->codec_id == AV_CODEC_ID_WMV3IMAGE) {
- int count = 0;
- diff --git a/lib/ffmpeg/libavcodec/vc1dsp.c b/lib/ffmpeg/libavcodec/vc1dsp.c
- index 260eda4..3e3f00e 100644
- --- a/lib/ffmpeg/libavcodec/vc1dsp.c
- +++ b/lib/ffmpeg/libavcodec/vc1dsp.c
- @@ -30,6 +30,7 @@
- #include "h264chroma.h"
- #include "rnd_avg.h"
- #include "vc1dsp.h"
- +#include "startcode.h"
-
-
- /** Apply overlap transform to horizontal edge
- @@ -861,8 +862,12 @@ av_cold void ff_vc1dsp_init(VC1DSPContext* dsp) {
- dsp->sprite_v_double_twoscale = sprite_v_double_twoscale_c;
- #endif
-
- + dsp->vc1_find_start_code_candidate = ff_startcode_find_candidate_c;
- +
- if (HAVE_ALTIVEC)
- ff_vc1dsp_init_altivec(dsp);
- + if (ARCH_ARM)
- + ff_vc1dsp_init_arm(dsp);
- if (ARCH_X86)
- ff_vc1dsp_init_x86(dsp);
- }
- diff --git a/lib/ffmpeg/libavcodec/vc1dsp.h b/lib/ffmpeg/libavcodec/vc1dsp.h
- index 6540eff..302e4a8 100644
- --- a/lib/ffmpeg/libavcodec/vc1dsp.h
- +++ b/lib/ffmpeg/libavcodec/vc1dsp.h
- @@ -73,10 +73,19 @@ typedef struct VC1DSPContext {
- void (*sprite_v_double_twoscale)(uint8_t *dst, const uint8_t *src1a, const uint8_t *src1b, int offset1,
- const uint8_t *src2a, const uint8_t *src2b, int offset2,
- int alpha, int width);
- +
- + /**
- + * Search buf from the start for up to size bytes. Return the index
- + * of a zero byte, or >= size if not found. Ideally, use lookahead
- + * to filter out any zero bytes that are known to not be followed by
- + * one or more further zero bytes and a one byte.
- + */
- + int (*vc1_find_start_code_candidate)(const uint8_t *buf, int size);
- } VC1DSPContext;
-
- void ff_vc1dsp_init(VC1DSPContext* c);
- void ff_vc1dsp_init_altivec(VC1DSPContext* c);
- +void ff_vc1dsp_init_arm(VC1DSPContext* dsp);
- void ff_vc1dsp_init_x86(VC1DSPContext* dsp);
-
- #endif /* AVCODEC_VC1DSP_H */
- --
- 1.9.3
- From 9b459c3c4130299099b2e5aca5bff3d6f8d60e72 Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Wed, 23 Apr 2014 01:41:04 +0100
- Subject: [PATCH 07/94] vc-1: Optimise parser (with special attention to ARM)
- The previous implementation of the parser made four passes over each input
- buffer (reduced to two if the container format already guaranteed the input
- buffer corresponded to frames, such as with MKV). But these buffers are
- often 200K in size, certainly enough to flush the data out of L1 cache, and
- for many CPUs, all the way out to main memory. The passes were:
- 1) locate frame boundaries (not needed for MKV etc)
- 2) copy the data into a contiguous block (not needed for MKV etc)
- 3) locate the start codes within each frame
- 4) unescape the data between start codes
- After this, the unescaped data was parsed to extract certain header fields,
- but because the unescape operation was so large, this was usually also
- effectively operating on uncached memory. Most of the unescaped data was
- simply thrown away and never processed further. Only step 2 - because it
- used memcpy - was using prefetch, making things even worse.
- This patch reorganises these steps so that, aside from the copying, the
- operations are performed in parallel, maximising cache utilisation. No more
- than the worst-case number of bytes needed for header parsing is unescaped.
- Most of the data is, in practice, only read in order to search for a start
- code, for which optimised implementations already existed in the H264 codec
- (notably the ARM version uses prefetch, so we end up doing both remaining
- passes at maximum speed). For MKV files, we know when we've found the last
- start code of interest in a given frame, so we are able to avoid doing even
- that one remaining pass for most of the buffer.
- In some use-cases (such as the Raspberry Pi) video decode is handled by the
- GPU, but the entire elementary stream is still fed through the parser to
- pick out certain elements of the header which are necessary to manage the
- decode process. As you might expect, in these cases, the performance of the
- parser is significant.
- To measure parser performance, I used the same VC-1 elementary stream in
- either an MPEG-2 transport stream or a MKV file, and fed it through ffmpeg
- with -c:v copy -c:a copy -f null. These are the gperftools counts for
- those streams, both filtered to only include vc1_parse() and its callees,
- and unfiltered (to include the whole binary). Lower numbers are better:
- Before After
- File Filtered Mean StdDev Mean StdDev Confidence Change
- M2TS No 861.7 8.2 650.5 8.1 100.0% +32.5%
- MKV No 868.9 7.4 731.7 9.0 100.0% +18.8%
- M2TS Yes 250.0 11.2 27.2 3.4 100.0% +817.9%
- MKV Yes 149.0 12.8 1.7 0.8 100.0% +8526.3%
- Yes, that last case shows vc1_parse() running 86 times faster! The M2TS
- case does show a larger absolute improvement though, since it was worse
- to begin with.
- This patch has been tested with the FATE suite (albeit on x86 for speed).
- Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
- ---
- lib/ffmpeg/libavcodec/vc1_parser.c | 269 ++++++++++++++++++++++++-------------
- 1 file changed, 175 insertions(+), 94 deletions(-)
- diff --git a/lib/ffmpeg/libavcodec/vc1_parser.c b/lib/ffmpeg/libavcodec/vc1_parser.c
- index 53af61c..af601ad 100644
- --- a/lib/ffmpeg/libavcodec/vc1_parser.c
- +++ b/lib/ffmpeg/libavcodec/vc1_parser.c
- @@ -29,112 +29,83 @@
- #include "vc1.h"
- #include "get_bits.h"
-
- +/** The maximum number of bytes of a sequence, entry point or
- + * frame header whose values we pay any attention to */
- +#define UNESCAPED_THRESHOLD 37
- +
- +/** The maximum number of bytes of a sequence, entry point or
- + * frame header which must be valid memory (because they are
- + * used to update the bitstream cache in skip_bits() calls)
- + */
- +#define UNESCAPED_LIMIT 144
- +
- +typedef enum {
- + NO_MATCH,
- + ONE_ZERO,
- + TWO_ZEROS,
- + ONE
- +} VC1ParseSearchState;
- +
- typedef struct {
- ParseContext pc;
- VC1Context v;
- + uint8_t prev_start_code;
- + size_t bytes_to_skip;
- + uint8_t unesc_buffer[UNESCAPED_LIMIT];
- + size_t unesc_index;
- + VC1ParseSearchState search_state;
- } VC1ParseContext;
-
- -static void vc1_extract_headers(AVCodecParserContext *s, AVCodecContext *avctx,
- - const uint8_t *buf, int buf_size)
- +static void vc1_extract_header(AVCodecParserContext *s, AVCodecContext *avctx,
- + const uint8_t *buf, int buf_size)
- {
- + /* Parse the header we just finished unescaping */
- VC1ParseContext *vpc = s->priv_data;
- GetBitContext gb;
- - const uint8_t *start, *end, *next;
- - uint8_t *buf2 = av_mallocz(buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
- -
- + int ret;
- vpc->v.s.avctx = avctx;
- vpc->v.parse_only = 1;
- - next = buf;
- - s->repeat_pict = 0;
- -
- - for(start = buf, end = buf + buf_size; next < end; start = next){
- - int buf2_size, size;
- -
- - next = find_next_marker(start + 4, end);
- - size = next - start - 4;
- - buf2_size = vc1_unescape_buffer(start + 4, size, buf2);
- - init_get_bits(&gb, buf2, buf2_size * 8);
- - if(size <= 0) continue;
- - switch(AV_RB32(start)){
- - case VC1_CODE_SEQHDR:
- - ff_vc1_decode_sequence_header(avctx, &vpc->v, &gb);
- - break;
- - case VC1_CODE_ENTRYPOINT:
- - ff_vc1_decode_entry_point(avctx, &vpc->v, &gb);
- - break;
- - case VC1_CODE_FRAME:
- - if(vpc->v.profile < PROFILE_ADVANCED)
- - ff_vc1_parse_frame_header (&vpc->v, &gb);
- - else
- - ff_vc1_parse_frame_header_adv(&vpc->v, &gb);
- -
- - /* keep AV_PICTURE_TYPE_BI internal to VC1 */
- - if (vpc->v.s.pict_type == AV_PICTURE_TYPE_BI)
- - s->pict_type = AV_PICTURE_TYPE_B;
- - else
- - s->pict_type = vpc->v.s.pict_type;
- -
- - if (avctx->ticks_per_frame > 1){
- - // process pulldown flags
- - s->repeat_pict = 1;
- - // Pulldown flags are only valid when 'broadcast' has been set.
- - // So ticks_per_frame will be 2
- - if (vpc->v.rff){
- - // repeat field
- - s->repeat_pict = 2;
- - }else if (vpc->v.rptfrm){
- - // repeat frames
- - s->repeat_pict = vpc->v.rptfrm * 2 + 1;
- - }
- - }
- + init_get_bits(&gb, buf, buf_size * 8);
- + switch (vpc->prev_start_code) {
- + case VC1_CODE_SEQHDR & 0xFF:
- + ff_vc1_decode_sequence_header(avctx, &vpc->v, &gb);
- + break;
- + case VC1_CODE_ENTRYPOINT & 0xFF:
- + ff_vc1_decode_entry_point(avctx, &vpc->v, &gb);
- + break;
- + case VC1_CODE_FRAME & 0xFF:
- + if(vpc->v.profile < PROFILE_ADVANCED)
- + ret = ff_vc1_parse_frame_header (&vpc->v, &gb);
- + else
- + ret = ff_vc1_parse_frame_header_adv(&vpc->v, &gb);
-
- + if (ret < 0)
- break;
- - }
- - }
-
- - av_free(buf2);
- -}
- + /* keep AV_PICTURE_TYPE_BI internal to VC1 */
- + if (vpc->v.s.pict_type == AV_PICTURE_TYPE_BI)
- + s->pict_type = AV_PICTURE_TYPE_B;
- + else
- + s->pict_type = vpc->v.s.pict_type;
-
- -/**
- - * Find the end of the current frame in the bitstream.
- - * @return the position of the first byte of the next frame, or -1
- - */
- -static int vc1_find_frame_end(ParseContext *pc, const uint8_t *buf,
- - int buf_size) {
- - int pic_found, i;
- - uint32_t state;
- -
- - pic_found= pc->frame_start_found;
- - state= pc->state;
- -
- - i=0;
- - if(!pic_found){
- - for(i=0; i<buf_size; i++){
- - state= (state<<8) | buf[i];
- - if(state == VC1_CODE_FRAME || state == VC1_CODE_FIELD){
- - i++;
- - pic_found=1;
- - break;
- + if (avctx->ticks_per_frame > 1){
- + // process pulldown flags
- + s->repeat_pict = 1;
- + // Pulldown flags are only valid when 'broadcast' has been set.
- + // So ticks_per_frame will be 2
- + if (vpc->v.rff){
- + // repeat field
- + s->repeat_pict = 2;
- + }else if (vpc->v.rptfrm){
- + // repeat frames
- + s->repeat_pict = vpc->v.rptfrm * 2 + 1;
- }
- + }else{
- + s->repeat_pict = 0;
- }
- - }
-
- - if(pic_found){
- - /* EOF considered as end of frame */
- - if (buf_size == 0)
- - return 0;
- - for(; i<buf_size; i++){
- - state= (state<<8) | buf[i];
- - if(IS_MARKER(state) && state != VC1_CODE_FIELD && state != VC1_CODE_SLICE){
- - pc->frame_start_found=0;
- - pc->state=-1;
- - return i-3;
- - }
- - }
- + break;
- }
- - pc->frame_start_found= pic_found;
- - pc->state= state;
- - return END_NOT_FOUND;
- }
-
- static int vc1_parse(AVCodecParserContext *s,
- @@ -142,22 +113,127 @@ static int vc1_parse(AVCodecParserContext *s,
- const uint8_t **poutbuf, int *poutbuf_size,
- const uint8_t *buf, int buf_size)
- {
- + /* Here we do the searching for frame boundaries and headers at
- + * the same time. Only a minimal amount at the start of each
- + * header is unescaped. */
- VC1ParseContext *vpc = s->priv_data;
- - int next;
- + int pic_found = vpc->pc.frame_start_found;
- + uint8_t *unesc_buffer = vpc->unesc_buffer;
- + size_t unesc_index = vpc->unesc_index;
- + VC1ParseSearchState search_state = vpc->search_state;
- + int next = END_NOT_FOUND;
- + int i = vpc->bytes_to_skip;
-
- - if(s->flags & PARSER_FLAG_COMPLETE_FRAMES){
- - next= buf_size;
- - }else{
- - next= vc1_find_frame_end(&vpc->pc, buf, buf_size);
- + if (pic_found && buf_size == 0) {
- + /* EOF considered as end of frame */
- + memset(unesc_buffer + unesc_index, 0, UNESCAPED_THRESHOLD - unesc_index);
- + vc1_extract_header(s, avctx, unesc_buffer, unesc_index);
- + next = 0;
- + }
- + while (i < buf_size) {
- + int start_code_found = 0;
- + uint8_t b;
- + while (i < buf_size && unesc_index < UNESCAPED_THRESHOLD) {
- + b = buf[i++];
- + unesc_buffer[unesc_index++] = b;
- + if (search_state <= ONE_ZERO)
- + search_state = b ? NO_MATCH : search_state + 1;
- + else if (search_state == TWO_ZEROS) {
- + if (b == 1)
- + search_state = ONE;
- + else if (b > 1) {
- + if (b == 3)
- + unesc_index--; // swallow emulation prevention byte
- + search_state = NO_MATCH;
- + }
- + }
- + else { // search_state == ONE
- + // Header unescaping terminates early due to detection of next start code
- + search_state = NO_MATCH;
- + start_code_found = 1;
- + break;
- + }
- + }
- + if ((s->flags & PARSER_FLAG_COMPLETE_FRAMES) &&
- + unesc_index >= UNESCAPED_THRESHOLD &&
- + vpc->prev_start_code == (VC1_CODE_FRAME & 0xFF))
- + {
- + // No need to keep scanning the rest of the buffer for
- + // start codes if we know it contains a complete frame and
- + // we've already unescaped all we need of the frame header
- + vc1_extract_header(s, avctx, unesc_buffer, unesc_index);
- + break;
- + }
- + if (unesc_index >= UNESCAPED_THRESHOLD && !start_code_found) {
- + while (i < buf_size) {
- + if (search_state == NO_MATCH) {
- + i += vpc->v.vc1dsp.vc1_find_start_code_candidate(buf + i, buf_size - i);
- + if (i < buf_size) {
- + search_state = ONE_ZERO;
- + }
- + i++;
- + } else {
- + b = buf[i++];
- + if (search_state == ONE_ZERO)
- + search_state = b ? NO_MATCH : TWO_ZEROS;
- + else if (search_state == TWO_ZEROS) {
- + if (b >= 1)
- + search_state = b == 1 ? ONE : NO_MATCH;
- + }
- + else { // search_state == ONE
- + search_state = NO_MATCH;
- + start_code_found = 1;
- + break;
- + }
- + }
- + }
- + }
- + if (start_code_found) {
- + vc1_extract_header(s, avctx, unesc_buffer, unesc_index);
- +
- + vpc->prev_start_code = b;
- + unesc_index = 0;
- +
- + if (!(s->flags & PARSER_FLAG_COMPLETE_FRAMES)) {
- + if (!pic_found && (b == (VC1_CODE_FRAME & 0xFF) || b == (VC1_CODE_FIELD & 0xFF))) {
- + pic_found = 1;
- + }
- + else if (pic_found && b != (VC1_CODE_FIELD & 0xFF) && b != (VC1_CODE_SLICE & 0xFF)) {
- + next = i - 4;
- + pic_found = b == (VC1_CODE_FRAME & 0xFF);
- + break;
- + }
- + }
- + }
- + }
-
- + vpc->pc.frame_start_found = pic_found;
- + vpc->unesc_index = unesc_index;
- + vpc->search_state = search_state;
- +
- + if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
- + next = buf_size;
- + } else {
- if (ff_combine_frame(&vpc->pc, next, &buf, &buf_size) < 0) {
- + vpc->bytes_to_skip = 0;
- *poutbuf = NULL;
- *poutbuf_size = 0;
- return buf_size;
- }
- }
-
- - vc1_extract_headers(s, avctx, buf, buf_size);
- + vpc->v.first_pic_header_flag = 1;
- +
- + /* If we return with a valid pointer to a combined frame buffer
- + * then on the next call then we'll have been unhelpfully rewound
- + * by up to 4 bytes (depending upon whether the start code
- + * overlapped the input buffer, and if so by how much). We don't
- + * want this: it will either cause spurious second detections of
- + * the start code we've already seen, or cause extra bytes to be
- + * inserted at the start of the unescaped buffer. */
- + vpc->bytes_to_skip = 4;
- + if (next < 0)
- + vpc->bytes_to_skip += next;
-
- *poutbuf = buf;
- *poutbuf_size = buf_size;
- @@ -188,6 +264,11 @@ static int vc1_parse_init(AVCodecParserContext *s)
- {
- VC1ParseContext *vpc = s->priv_data;
- vpc->v.s.slice_context_count = 1;
- + vpc->v.first_pic_header_flag = 1;
- + vpc->prev_start_code = 0;
- + vpc->bytes_to_skip = 0;
- + vpc->unesc_index = 0;
- + vpc->search_state = NO_MATCH;
- return ff_vc1_init_common(&vpc->v);
- }
-
- --
- 1.9.3
- From c2ebe54fe1d7c7a6cee7282bcf2668a826006ade Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Wed, 19 Mar 2014 17:44:59 +0000
- Subject: [PATCH 08/94] truehd: add hand-scheduled ARM asm version of
- mlp_filter_channel.
- Profiling results for overall audio decode and the mlp_filter_channel(_arm)
- function in particular are as follows:
- Before After
- Mean StdDev Mean StdDev Confidence Change
- 6:2 total 380.4 22.0 370.8 17.0 87.4% +2.6% (insignificant)
- 6:2 function 60.7 7.2 36.6 8.1 100.0% +65.8%
- 8:2 total 357.0 17.5 343.2 19.0 97.8% +4.0% (insignificant)
- 8:2 function 60.3 8.8 37.3 3.8 100.0% +61.8%
- 6:6 total 717.2 23.2 658.4 15.7 100.0% +8.9%
- 6:6 function 140.4 12.9 81.5 9.2 100.0% +72.4%
- 8:8 total 981.9 16.2 896.2 24.5 100.0% +9.6%
- 8:8 function 193.4 15.0 103.3 11.5 100.0% +87.2%
- Experiments with adding preload instructions to this function yielded no
- useful benefit, so these have not been included.
- The assembly version has also been tested with a fuzz tester to ensure that
- any combinations of inputs not exercised by my available test streams still
- generate mathematically identical results to the C version.
- ---
- lib/ffmpeg/libavcodec/arm/Makefile | 5 +-
- lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S | 430 ++++++++++++++++++++++++++++
- lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c | 36 +++
- lib/ffmpeg/libavcodec/mlpdsp.h | 1 +
- 4 files changed, 471 insertions(+), 1 deletion(-)
- create mode 100644 lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S
- create mode 100644 lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c
- diff --git a/lib/ffmpeg/libavcodec/arm/Makefile b/lib/ffmpeg/libavcodec/arm/Makefile
- index 715eed7..5b0edf0 100644
- --- a/lib/ffmpeg/libavcodec/arm/Makefile
- +++ b/lib/ffmpeg/libavcodec/arm/Makefile
- @@ -14,6 +14,8 @@ ARMV6-OBJS-$(CONFIG_H264DSP) += arm/startcode_armv6.o
- OBJS-$(CONFIG_FLAC_DECODER) += arm/flacdsp_init_arm.o \
- arm/flacdsp_arm.o \
-
- +OBJS-$(CONFIG_MLP_DECODER) += arm/mlpdsp_init_arm.o \
- + arm/mlpdsp_arm.o
- OBJS-$(CONFIG_MPEGAUDIODSP) += arm/mpegaudiodsp_init_arm.o
- ARMV6-OBJS-$(CONFIG_MPEGAUDIODSP) += arm/mpegaudiodsp_fixed_armv6.o
- ARMV6-OBJS-$(CONFIG_VC1_DECODER) += arm/startcode_armv6.o
- @@ -21,6 +23,8 @@ OBJS-$(CONFIG_VC1_DECODER) += arm/vc1dsp_init_arm.o
- ARMV6-OBJS-$(CONFIG_VC1_PARSER) += arm/startcode_armv6.o
-
- OBJS-$(CONFIG_MPEGVIDEO) += arm/mpegvideo_arm.o
- +OBJS-$(CONFIG_TRUEHD_DECODER) += arm/mlpdsp_init_arm.o \
- + arm/mlpdsp_arm.o
- OBJS-$(CONFIG_VORBIS_DECODER) += arm/vorbisdsp_init_arm.o
- OBJS-$(CONFIG_VP3DSP) += arm/vp3dsp_init_arm.o
- OBJS-$(CONFIG_VP5_DECODER) += arm/vp56dsp_init_arm.o
- @@ -34,7 +38,6 @@ OBJS-$(CONFIG_H264CHROMA) += arm/h264chroma_init_arm.o
- OBJS-$(CONFIG_H264DSP) += arm/h264dsp_init_arm.o
- OBJS-$(CONFIG_H264PRED) += arm/h264pred_init_arm.o
- OBJS-$(CONFIG_H264QPEL) += arm/h264qpel_init_arm.o
- -
- OBJS-$(CONFIG_RV30_DECODER) += arm/rv34dsp_init_arm.o
- OBJS-$(CONFIG_RV40_DECODER) += arm/rv34dsp_init_arm.o \
- arm/rv40dsp_init_arm.o \
- diff --git a/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S b/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S
- new file mode 100644
- index 0000000..114496f
- --- /dev/null
- +++ b/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S
- @@ -0,0 +1,430 @@
- +/*
- + * Copyright (c) 2014 RISC OS Open Ltd
- + * Author: Ben Avison <bavison@riscosopen.org>
- + *
- + * This file is part of Libav.
- + *
- + * Libav is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU Lesser General Public
- + * License as published by the Free Software Foundation; either
- + * version 2.1 of the License, or (at your option) any later version.
- + *
- + * Libav is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- + * Lesser General Public License for more details.
- + *
- + * You should have received a copy of the GNU Lesser General Public
- + * License along with Libav; if not, write to the Free Software
- + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- + */
- +
- +// This code uses too many ARM-only tricks to easily assemble as Thumb
- +.arm
- +#undef CONFIG_THUMB
- +#define CONFIG_THUMB 0
- +
- +#include "libavutil/arm/asm.S"
- +
- +#define MAX_CHANNELS 8
- +#define MAX_FIR_ORDER 8
- +#define MAX_IIR_ORDER 4
- +#define MAX_RATEFACTOR 4
- +#define MAX_BLOCKSIZE (40 * MAX_RATEFACTOR)
- +
- +PST .req a1
- +PCO .req a2
- +AC0 .req a3
- +AC1 .req a4
- +CO0 .req v1
- +CO1 .req v2
- +CO2 .req v3
- +CO3 .req v4
- +ST0 .req v5
- +ST1 .req v6
- +ST2 .req sl
- +ST3 .req fp
- +I .req ip
- +PSAMP .req lr
- +
- +
- +// Some macros that do loads/multiplies where the register number is determined
- +// from an assembly-time expression. Boy is GNU assembler's syntax ugly...
- +
- +.macro load group, index, base, offset
- + .altmacro
- + load_ \group, %(\index), \base, \offset
- + .noaltmacro
- +.endm
- +
- +.macro load_ group, index, base, offset
- + ldr \group\index, [\base, #\offset]
- +.endm
- +
- +.macro loadd group, index, base, offset
- + .altmacro
- + loadd_ \group, %(\index), %(\index+1), \base, \offset
- + .noaltmacro
- +.endm
- +
- +.macro loadd_ group, index0, index1, base, offset
- +A .if offset >= 256
- +A ldr \group\index0, [\base, #\offset]
- +A ldr \group\index1, [\base, #(\offset) + 4]
- +A .else
- + ldrd \group\index0, \group\index1, [\base, #\offset]
- +A .endif
- +.endm
- +
- +.macro multiply index, accumulate, long
- + .altmacro
- + multiply_ %(\index), \accumulate, \long
- + .noaltmacro
- +.endm
- +
- +.macro multiply_ index, accumulate, long
- + .if \long
- + .if \accumulate
- + smlal AC0, AC1, CO\index, ST\index
- + .else
- + smull AC0, AC1, CO\index, ST\index
- + .endif
- + .else
- + .if \accumulate
- + mla AC0, CO\index, ST\index, AC0
- + .else
- + mul AC0, CO\index, ST\index
- + .endif
- + .endif
- +.endm
- +
- +// A macro to update the load register number and load offsets
- +
- +.macro inc howmany
- + .set LOAD_REG, (LOAD_REG + \howmany) & 3
- + .set OFFSET_CO, OFFSET_CO + 4 * \howmany
- + .set OFFSET_ST, OFFSET_ST + 4 * \howmany
- + .if FIR_REMAIN > 0
- + .set FIR_REMAIN, FIR_REMAIN - \howmany
- + .if FIR_REMAIN == 0
- + .set OFFSET_CO, 4 * MAX_FIR_ORDER
- + .set OFFSET_ST, 4 * (MAX_BLOCKSIZE + MAX_FIR_ORDER)
- + .endif
- + .elseif IIR_REMAIN > 0
- + .set IIR_REMAIN, IIR_REMAIN - \howmany
- + .endif
- +.endm
- +
- +// Macro to implement the inner loop for one specific combination of parameters
- +
- +.macro implement_filter mask_minus1, shift_0, shift_8, iir_taps, fir_taps
- + .set TOTAL_TAPS, \iir_taps + \fir_taps
- +
- + // Deal with register allocation...
- + .set DEFINED_SHIFT, 0
- + .set DEFINED_MASK, 0
- + .set SHUFFLE_SHIFT, 0
- + .set SHUFFLE_MASK, 0
- + .set SPILL_SHIFT, 0
- + .set SPILL_MASK, 0
- + .if TOTAL_TAPS == 0
- + // Little register pressure in this case - just keep MASK where it was
- + .if !\mask_minus1
- + MASK .req ST1
- + .set DEFINED_MASK, 1
- + .endif
- + .else
- + .if \shift_0
- + .if !\mask_minus1
- + // AC1 is unused with shift 0
- + MASK .req AC1
- + .set DEFINED_MASK, 1
- + .set SHUFFLE_MASK, 1
- + .endif
- + .elseif \shift_8
- + .if !\mask_minus1
- + .if TOTAL_TAPS <= 4
- + // All coefficients are preloaded (so pointer not needed)
- + MASK .req PCO
- + .set DEFINED_MASK, 1
- + .set SHUFFLE_MASK, 1
- + .else
- + .set SPILL_MASK, 1
- + .endif
- + .endif
- + .else // shift not 0 or 8
- + .if TOTAL_TAPS <= 3
- + // All coefficients are preloaded, and at least one CO register is unused
- + .if \fir_taps & 1
- + SHIFT .req CO0
- + .set DEFINED_SHIFT, 1
- + .set SHUFFLE_SHIFT, 1
- + .else
- + SHIFT .req CO3
- + .set DEFINED_SHIFT, 1
- + .set SHUFFLE_SHIFT, 1
- + .endif
- + .if !\mask_minus1
- + MASK .req PCO
- + .set DEFINED_MASK, 1
- + .set SHUFFLE_MASK, 1
- + .endif
- + .elseif TOTAL_TAPS == 4
- + // All coefficients are preloaded
- + SHIFT .req PCO
- + .set DEFINED_SHIFT, 1
- + .set SHUFFLE_SHIFT, 1
- + .if !\mask_minus1
- + .set SPILL_MASK, 1
- + .endif
- + .else
- + .set SPILL_SHIFT, 1
- + .if !\mask_minus1
- + .set SPILL_MASK, 1
- + .endif
- + .endif
- + .endif
- + .endif
- + .if SPILL_SHIFT
- + SHIFT .req ST0
- + .set DEFINED_SHIFT, 1
- + .endif
- + .if SPILL_MASK
- + MASK .req ST1
- + .set DEFINED_MASK, 1
- + .endif
- +
- + // Preload coefficients if possible
- + .if TOTAL_TAPS <= 4
- + .set OFFSET_CO, 0
- + .if \fir_taps & 1
- + .set LOAD_REG, 1
- + .else
- + .set LOAD_REG, 0
- + .endif
- + .rept \fir_taps
- + load CO, LOAD_REG, PCO, OFFSET_CO
- + .set LOAD_REG, (LOAD_REG + 1) & 3
- + .set OFFSET_CO, OFFSET_CO + 4
- + .endr
- + .set OFFSET_CO, 4 * MAX_FIR_ORDER
- + .rept \iir_taps
- + load CO, LOAD_REG, PCO, OFFSET_CO
- + .set LOAD_REG, (LOAD_REG + 1) & 3
- + .set OFFSET_CO, OFFSET_CO + 4
- + .endr
- + .endif
- +
- + // Move mask/shift to final positions if necessary
- + // Need to do this after preloading, because in some cases we
- + // reuse the coefficient pointer register
- + .if SHUFFLE_SHIFT
- + mov SHIFT, ST0
- + .endif
- + .if SHUFFLE_MASK
- + mov MASK, ST1
- + .endif
- +
- + // Begin loop
- +01:
- + .if TOTAL_TAPS == 0
- + // Things simplify a lot in this case
- + // In fact this could be pipelined further if it's worth it...
- + ldr ST0, [PSAMP]
- + subs I, I, #1
- + .if !\mask_minus1
- + and ST0, ST0, MASK
- + .endif
- + str ST0, [PST, #-4]!
- + str ST0, [PST, #4 * (MAX_BLOCKSIZE + MAX_FIR_ORDER)]
- + str ST0, [PSAMP], #4 * MAX_CHANNELS
- + bne 01b
- + .else
- + .if \fir_taps & 1
- + .set LOAD_REG, 1
- + .else
- + .set LOAD_REG, 0
- + .endif
- + .set LOAD_BANK, 0
- + .set FIR_REMAIN, \fir_taps
- + .set IIR_REMAIN, \iir_taps
- + .if FIR_REMAIN == 0 // only IIR terms
- + .set OFFSET_CO, 4 * MAX_FIR_ORDER
- + .set OFFSET_ST, 4 * (MAX_BLOCKSIZE + MAX_FIR_ORDER)
- + .else
- + .set OFFSET_CO, 0
- + .set OFFSET_ST, 0
- + .endif
- + .set MUL_REG, LOAD_REG
- + .set COUNTER, 0
- + .rept TOTAL_TAPS + 2
- + // Do load(s)
- + .if FIR_REMAIN != 0 || IIR_REMAIN != 0
- + .if COUNTER == 0
- + .if TOTAL_TAPS > 4
- + load CO, LOAD_REG, PCO, OFFSET_CO
- + .endif
- + load ST, LOAD_REG, PST, OFFSET_ST
- + inc 1
- + .elseif COUNTER == 1 && (\fir_taps & 1) == 0
- + .if TOTAL_TAPS > 4
- + load CO, LOAD_REG, PCO, OFFSET_CO
- + .endif
- + load ST, LOAD_REG, PST, OFFSET_ST
- + inc 1
- + .elseif LOAD_BANK == 0
- + .if TOTAL_TAPS > 4
- + .if FIR_REMAIN == 0 && IIR_REMAIN == 1
- + load CO, LOAD_REG, PCO, OFFSET_CO
- + .else
- + loadd CO, LOAD_REG, PCO, OFFSET_CO
- + .endif
- + .endif
- + .set LOAD_BANK, 1
- + .else
- + .if FIR_REMAIN == 0 && IIR_REMAIN == 1
- + load ST, LOAD_REG, PST, OFFSET_ST
- + inc 1
- + .else
- + loadd ST, LOAD_REG, PST, OFFSET_ST
- + inc 2
- + .endif
- + .set LOAD_BANK, 0
- + .endif
- + .endif
- +
- + // Do interleaved multiplies, slightly delayed
- + .if COUNTER >= 2
- + multiply MUL_REG, COUNTER > 2, !\shift_0
- + .set MUL_REG, (MUL_REG + 1) & 3
- + .endif
- + .set COUNTER, COUNTER + 1
- + .endr
- +
- + // Post-process the result of the multiplies
- + .if SPILL_SHIFT
- + ldr SHIFT, [sp, #9*4 + 0*4]
- + .endif
- + .if SPILL_MASK
- + ldr MASK, [sp, #9*4 + 1*4]
- + .endif
- + ldr ST2, [PSAMP]
- + subs I, I, #1
- + .if \shift_8
- + mov AC0, AC0, lsr #8
- + orr AC0, AC0, AC1, lsl #24
- + .elseif !\shift_0
- + rsb ST3, SHIFT, #32
- + mov AC0, AC0, lsr SHIFT
- + orr AC0, AC0, AC1, lsl ST3
- + .endif
- + .if \mask_minus1
- + add ST3, ST2, AC0
- + .else
- + add ST2, ST2, AC0
- + and ST3, ST2, MASK
- + sub ST2, ST3, AC0
- + .endif
- + str ST3, [PST, #-4]!
- + str ST2, [PST, #4 * (MAX_BLOCKSIZE + MAX_FIR_ORDER)]
- + str ST3, [PSAMP], #4 * MAX_CHANNELS
- + bne 01b
- + .endif
- + b 99f
- +
- + .if DEFINED_SHIFT
- + .unreq SHIFT
- + .endif
- + .if DEFINED_MASK
- + .unreq MASK
- + .endif
- +.endm
- +
- +.macro switch_on_fir_taps mask_minus1, shift_0, shift_8, iir_taps
- + ldr pc, [pc, a3, LSL #2] // firorder is in range 0-(8-iir_taps)
- + .word 0
- + .word 70f
- + .word 71f
- + .word 72f
- + .word 73f
- + .word 74f
- + .word 75f
- + .if \iir_taps <= 2
- + .word 76f
- + .if \iir_taps <= 1
- + .word 77f
- + .if \iir_taps == 0
- + .word 78f
- + .endif
- + .endif
- + .endif
- +70: implement_filter \mask_minus1, \shift_0, \shift_8, \iir_taps, 0
- +71: implement_filter \mask_minus1, \shift_0, \shift_8, \iir_taps, 1
- +72: implement_filter \mask_minus1, \shift_0, \shift_8, \iir_taps, 2
- +73: implement_filter \mask_minus1, \shift_0, \shift_8, \iir_taps, 3
- +74: implement_filter \mask_minus1, \shift_0, \shift_8, \iir_taps, 4
- +75: implement_filter \mask_minus1, \shift_0, \shift_8, \iir_taps, 5
- + .if \iir_taps <= 2
- +76: implement_filter \mask_minus1, \shift_0, \shift_8, \iir_taps, 6
- + .if \iir_taps <= 1
- +77: implement_filter \mask_minus1, \shift_0, \shift_8, \iir_taps, 7
- + .if \iir_taps == 0
- +78: implement_filter \mask_minus1, \shift_0, \shift_8, \iir_taps, 8
- + .endif
- + .endif
- + .endif
- +.endm
- +
- +.macro switch_on_iir_taps mask_minus1, shift_0, shift_8
- + ldr pc, [pc, a4, LSL #2] // irorder is in range 0-3
- + .word 0
- + .word 60f
- + .word 61f
- + .word 62f
- + .word 63f
- +60: switch_on_fir_taps \mask_minus1, \shift_0, \shift_8, 0
- +61: switch_on_fir_taps \mask_minus1, \shift_0, \shift_8, 1
- +62: switch_on_fir_taps \mask_minus1, \shift_0, \shift_8, 2
- +63: switch_on_fir_taps \mask_minus1, \shift_0, \shift_8, 3
- +.endm
- +
- +/* void ff_mlp_filter_channel_arm(int32_t *state, const int32_t *coeff,
- + * int firorder, int iirorder,
- + * unsigned int filter_shift, int32_t mask,
- + * int blocksize, int32_t *sample_buffer);
- + */
- +function ff_mlp_filter_channel_arm, export=1
- + push {v1-fp,lr}
- + add v1, sp, #9*4 // point at arguments on stack
- + ldm v1, {ST0,ST1,I,PSAMP}
- + cmp ST1, #-1
- + bne 30f
- + movs ST2, ST0, lsl #29 // shift is in range 0-15; we want to special-case 0 and 8
- + bne 20f
- + bcs 10f
- + switch_on_iir_taps 1, 1, 0
- +10: switch_on_iir_taps 1, 0, 1
- +20: switch_on_iir_taps 1, 0, 0
- +30: movs ST2, ST0, lsl #29 // shift is in range 0-15; we want to special-case 0 and 8
- + bne 50f
- + bcs 40f
- + switch_on_iir_taps 0, 1, 0
- +40: switch_on_iir_taps 0, 0, 1
- +50: switch_on_iir_taps 0, 0, 0
- +99: pop {v1-fp,pc}
- +endfunc
- +
- + .unreq PST
- + .unreq PCO
- + .unreq AC0
- + .unreq AC1
- + .unreq CO0
- + .unreq CO1
- + .unreq CO2
- + .unreq CO3
- + .unreq ST0
- + .unreq ST1
- + .unreq ST2
- + .unreq ST3
- + .unreq I
- + .unreq PSAMP
- diff --git a/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c b/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c
- new file mode 100644
- index 0000000..f0ea285
- --- /dev/null
- +++ b/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c
- @@ -0,0 +1,36 @@
- +/*
- + * Copyright (c) 2014 RISC OS Open Ltd
- + * Author: Ben Avison <bavison@riscosopen.org>
- + *
- + * This file is part of Libav.
- + *
- + * Libav is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU Lesser General Public
- + * License as published by the Free Software Foundation; either
- + * version 2.1 of the License, or (at your option) any later version.
- + *
- + * Libav is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- + * Lesser General Public License for more details.
- + *
- + * You should have received a copy of the GNU Lesser General Public
- + * License along with Libav; if not, write to the Free Software
- + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- + */
- +
- +#include <stdint.h>
- +
- +#include "libavutil/arm/cpu.h"
- +#include "libavutil/attributes.h"
- +#include "libavcodec/mlpdsp.h"
- +
- +void ff_mlp_filter_channel_arm(int32_t *state, const int32_t *coeff,
- + int firorder, int iirorder,
- + unsigned int filter_shift, int32_t mask,
- + int blocksize, int32_t *sample_buffer);
- +
- +av_cold void ff_mlpdsp_init_arm(MLPDSPContext *c)
- +{
- + c->mlp_filter_channel = ff_mlp_filter_channel_arm;
- +}
- diff --git a/lib/ffmpeg/libavcodec/mlpdsp.h b/lib/ffmpeg/libavcodec/mlpdsp.h
- index 84a8aa3..129bcfe 100644
- --- a/lib/ffmpeg/libavcodec/mlpdsp.h
- +++ b/lib/ffmpeg/libavcodec/mlpdsp.h
- @@ -32,6 +32,7 @@ typedef struct MLPDSPContext {
- } MLPDSPContext;
-
- void ff_mlpdsp_init(MLPDSPContext *c);
- +void ff_mlpdsp_init_arm(MLPDSPContext *c);
- void ff_mlpdsp_init_x86(MLPDSPContext *c);
-
- #endif /* AVCODEC_MLPDSP_H */
- --
- 1.9.3
- From 904cb11e58484c5d0bca17b8c209916d106d2079 Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Wed, 19 Mar 2014 17:48:54 +0000
- Subject: [PATCH 09/94] truehd: break out part of rematrix_channels into
- platform-specific callback.
- Verified with profiling that this doesn't have a measurable effect upon
- overall performance.
- ---
- lib/ffmpeg/libavcodec/mlpdec.c | 37 ++++++++++++-------------------------
- lib/ffmpeg/libavcodec/mlpdsp.c | 35 ++++++++++++++++++++++++++++++++++-
- lib/ffmpeg/libavcodec/mlpdsp.h | 23 +++++++++++++++++++++++
- 3 files changed, 69 insertions(+), 26 deletions(-)
- diff --git a/lib/ffmpeg/libavcodec/mlpdec.c b/lib/ffmpeg/libavcodec/mlpdec.c
- index c763624..e9343a5 100644
- --- a/lib/ffmpeg/libavcodec/mlpdec.c
- +++ b/lib/ffmpeg/libavcodec/mlpdec.c
- @@ -958,7 +958,7 @@ static void fill_noise_buffer(MLPDecodeContext *m, unsigned int substr)
- static void rematrix_channels(MLPDecodeContext *m, unsigned int substr)
- {
- SubStream *s = &m->substream[substr];
- - unsigned int mat, src_ch, i;
- + unsigned int mat;
- unsigned int maxchan;
-
- maxchan = s->max_matrix_channel;
- @@ -970,31 +970,18 @@ static void rematrix_channels(MLPDecodeContext *m, unsigned int substr)
- }
-
- for (mat = 0; mat < s->num_primitive_matrices; mat++) {
- - int matrix_noise_shift = s->matrix_noise_shift[mat];
- unsigned int dest_ch = s->matrix_out_ch[mat];
- - int32_t mask = MSB_MASK(s->quant_step_size[dest_ch]);
- - int32_t *coeffs = s->matrix_coeff[mat];
- - int index = s->num_primitive_matrices - mat;
- - int index2 = 2 * index + 1;
- -
- - /* TODO: DSPContext? */
- -
- - for (i = 0; i < s->blockpos; i++) {
- - int32_t bypassed_lsb = m->bypassed_lsbs[i][mat];
- - int32_t *samples = m->sample_buffer[i];
- - int64_t accum = 0;
- -
- - for (src_ch = 0; src_ch <= maxchan; src_ch++)
- - accum += (int64_t) samples[src_ch] * coeffs[src_ch];
- -
- - if (matrix_noise_shift) {
- - index &= m->access_unit_size_pow2 - 1;
- - accum += m->noise_buffer[index] << (matrix_noise_shift + 7);
- - index += index2;
- - }
- -
- - samples[dest_ch] = ((accum >> 14) & mask) + bypassed_lsb;
- - }
- + m->dsp.mlp_rematrix_channel(&m->sample_buffer[0][0],
- + s->matrix_coeff[mat],
- + &m->bypassed_lsbs[0][mat],
- + m->noise_buffer,
- + s->num_primitive_matrices - mat,
- + dest_ch,
- + s->blockpos,
- + maxchan,
- + s->matrix_noise_shift[mat],
- + m->access_unit_size_pow2,
- + MSB_MASK(s->quant_step_size[dest_ch]));
- }
- }
-
- diff --git a/lib/ffmpeg/libavcodec/mlpdsp.c b/lib/ffmpeg/libavcodec/mlpdsp.c
- index 9a376e2..1f912fb 100644
- --- a/lib/ffmpeg/libavcodec/mlpdsp.c
- +++ b/lib/ffmpeg/libavcodec/mlpdsp.c
- @@ -56,9 +56,42 @@ static void ff_mlp_filter_channel(int32_t *state, const int32_t *coeff,
- }
- }
-
- -void ff_mlpdsp_init(MLPDSPContext *c)
- +void ff_mlp_rematrix_channel(int32_t *samples,
- + const int32_t *coeffs,
- + const uint8_t *bypassed_lsbs,
- + const int8_t *noise_buffer,
- + int index,
- + unsigned int dest_ch,
- + uint16_t blockpos,
- + unsigned int maxchan,
- + int matrix_noise_shift,
- + int access_unit_size_pow2,
- + int32_t mask)
- +{
- + unsigned int src_ch, i;
- + int index2 = 2 * index + 1;
- + for (i = 0; i < blockpos; i++) {
- + int64_t accum = 0;
- +
- + for (src_ch = 0; src_ch <= maxchan; src_ch++)
- + accum += (int64_t) samples[src_ch] * coeffs[src_ch];
- +
- + if (matrix_noise_shift) {
- + index &= access_unit_size_pow2 - 1;
- + accum += noise_buffer[index] << (matrix_noise_shift + 7);
- + index += index2;
- + }
- +
- + samples[dest_ch] = ((accum >> 14) & mask) + *bypassed_lsbs;
- + bypassed_lsbs += MAX_CHANNELS;
- + samples += MAX_CHANNELS;
- + }
- +}
- +
- +av_cold void ff_mlpdsp_init(MLPDSPContext *c)
- {
- c->mlp_filter_channel = ff_mlp_filter_channel;
- + c->mlp_rematrix_channel = ff_mlp_rematrix_channel;
- if (ARCH_X86)
- ff_mlpdsp_init_x86(c);
- }
- diff --git a/lib/ffmpeg/libavcodec/mlpdsp.h b/lib/ffmpeg/libavcodec/mlpdsp.h
- index 129bcfe..f98e9be 100644
- --- a/lib/ffmpeg/libavcodec/mlpdsp.h
- +++ b/lib/ffmpeg/libavcodec/mlpdsp.h
- @@ -24,11 +24,34 @@
-
- #include <stdint.h>
-
- +void ff_mlp_rematrix_channel(int32_t *samples,
- + const int32_t *coeffs,
- + const uint8_t *bypassed_lsbs,
- + const int8_t *noise_buffer,
- + int index,
- + unsigned int dest_ch,
- + uint16_t blockpos,
- + unsigned int maxchan,
- + int matrix_noise_shift,
- + int access_unit_size_pow2,
- + int32_t mask);
- +
- typedef struct MLPDSPContext {
- void (*mlp_filter_channel)(int32_t *state, const int32_t *coeff,
- int firorder, int iirorder,
- unsigned int filter_shift, int32_t mask,
- int blocksize, int32_t *sample_buffer);
- + void (*mlp_rematrix_channel)(int32_t *samples,
- + const int32_t *coeffs,
- + const uint8_t *bypassed_lsbs,
- + const int8_t *noise_buffer,
- + int index,
- + unsigned int dest_ch,
- + uint16_t blockpos,
- + unsigned int maxchan,
- + int matrix_noise_shift,
- + int access_unit_size_pow2,
- + int32_t mask);
- } MLPDSPContext;
-
- void ff_mlpdsp_init(MLPDSPContext *c);
- --
- 1.9.3
- From 0bb8daacca4b35d716addbc591fec43fd4fe6467 Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Wed, 19 Mar 2014 17:49:48 +0000
- Subject: [PATCH 10/94] truehd: add hand-scheduled ARM asm version of
- ff_mlp_rematrix_channel.
- Profiling results for overall audio decode and the rematrix_channels function
- in particular are as follows:
- Before After
- Mean StdDev Mean StdDev Confidence Change
- 6:2 total 370.8 17.0 348.8 20.1 99.9% +6.3%
- 6:2 function 46.4 8.4 45.8 6.6 18.0% +1.2% (insignificant)
- 8:2 total 343.2 19.0 339.1 15.4 54.7% +1.2% (insignificant)
- 8:2 function 38.9 3.9 40.2 6.9 52.4% -3.2% (insignificant)
- 6:6 total 658.4 15.7 604.6 20.8 100.0% +8.9%
- 6:6 function 109.0 8.7 59.5 5.4 100.0% +83.3%
- 8:8 total 896.2 24.5 766.4 17.6 100.0% +16.9%
- 8:8 function 223.4 12.8 93.8 5.0 100.0% +138.3%
- The assembly version has also been tested with a fuzz tester to ensure that
- any combinations of inputs not exercised by my available test streams still
- generate mathematically identical results to the C version.
- ---
- lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S | 231 ++++++++++++++++++++++++++++
- lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c | 12 ++
- 2 files changed, 243 insertions(+)
- diff --git a/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S b/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S
- index 114496f..10008fe 100644
- --- a/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S
- +++ b/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S
- @@ -428,3 +428,234 @@ endfunc
- .unreq ST3
- .unreq I
- .unreq PSAMP
- +
- +/********************************************************************/
- +
- +PSA .req a1 // samples
- +PCO .req a2 // coeffs
- +PBL .req a3 // bypassed_lsbs
- +INDEX .req a4
- +CO0 .req v1
- +CO1 .req v2
- +CO2 .req v3
- +CO3 .req v4
- +SA0 .req v5
- +SA1 .req v6
- +SA2 .req sl
- +SA3 .req fp
- +AC0 .req ip
- +AC1 .req lr
- +NOISE .req SA0
- +LSB .req SA1
- +DCH .req SA2 // dest_ch
- +MASK .req SA3
- +
- + // INDEX is used as follows:
- + // bits 0..6 index2 (values up to 17, but wider so that we can
- + // add to index field without needing to mask)
- + // bits 7..14 i (values up to 160)
- + // bit 15 underflow detect for i
- + // bits 25..31 (if access_unit_size_pow2 == 128) \ index
- + // bits 26..31 (if access_unit_size_pow2 == 64) /
- +
- +.macro implement_rematrix shift, index_mask, mask_minus1, maxchan
- + .if \maxchan == 1
- + // We can just leave the coefficients in registers in this case
- + ldrd CO0, CO1, [PCO]
- + .endif
- +1:
- + .if \maxchan == 1
- + ldrd SA0, SA1, [PSA]
- + smull AC0, AC1, CO0, SA0
- + .elseif \maxchan == 5
- + ldr CO0, [PCO, #0]
- + ldr SA0, [PSA, #0]
- + ldr CO1, [PCO, #4]
- + ldr SA1, [PSA, #4]
- + ldrd CO2, CO3, [PCO, #8]
- + smull AC0, AC1, CO0, SA0
- + ldrd SA2, SA3, [PSA, #8]
- + smlal AC0, AC1, CO1, SA1
- + ldrd CO0, CO1, [PCO, #16]
- + smlal AC0, AC1, CO2, SA2
- + ldrd SA0, SA1, [PSA, #16]
- + smlal AC0, AC1, CO3, SA3
- + smlal AC0, AC1, CO0, SA0
- + .else // \maxchan == 7
- + ldr CO2, [PCO, #0]
- + ldr SA2, [PSA, #0]
- + ldr CO3, [PCO, #4]
- + ldr SA3, [PSA, #4]
- + ldrd CO0, CO1, [PCO, #8]
- + smull AC0, AC1, CO2, SA2
- + ldrd SA0, SA1, [PSA, #8]
- + smlal AC0, AC1, CO3, SA3
- + ldrd CO2, CO3, [PCO, #16]
- + smlal AC0, AC1, CO0, SA0
- + ldrd SA2, SA3, [PSA, #16]
- + smlal AC0, AC1, CO1, SA1
- + ldrd CO0, CO1, [PCO, #24]
- + smlal AC0, AC1, CO2, SA2
- + ldrd SA0, SA1, [PSA, #24]
- + smlal AC0, AC1, CO3, SA3
- + smlal AC0, AC1, CO0, SA0
- + .endif
- + ldm sp, {NOISE, DCH, MASK}
- + smlal AC0, AC1, CO1, SA1
- + .if \shift != 0
- + .if \index_mask == 63
- + add NOISE, NOISE, INDEX, lsr #32-6
- + ldrb LSB, [PBL], #MAX_CHANNELS
- + ldrsb NOISE, [NOISE]
- + add INDEX, INDEX, INDEX, lsl #32-6
- + .else // \index_mask == 127
- + add NOISE, NOISE, INDEX, lsr #32-7
- + ldrb LSB, [PBL], #MAX_CHANNELS
- + ldrsb NOISE, [NOISE]
- + add INDEX, INDEX, INDEX, lsl #32-7
- + .endif
- + sub INDEX, INDEX, #1<<7
- + adds AC0, AC0, NOISE, lsl #\shift + 7
- + adc AC1, AC1, NOISE, asr #31
- + .else
- + ldrb LSB, [PBL], #MAX_CHANNELS
- + sub INDEX, INDEX, #1<<7
- + .endif
- + add PSA, PSA, #MAX_CHANNELS*4
- + mov AC0, AC0, lsr #14
- + orr AC0, AC0, AC1, lsl #18
- + .if !\mask_minus1
- + and AC0, AC0, MASK
- + .endif
- + add AC0, AC0, LSB
- + tst INDEX, #1<<15
- + str AC0, [PSA, DCH, lsl #2] // DCH is precompensated for the early increment of PSA
- + beq 1b
- + b 98f
- +.endm
- +
- +.macro switch_on_maxchan shift, index_mask, mask_minus1
- + cmp v4, #5
- + blo 51f
- + beq 50f
- + implement_rematrix \shift, \index_mask, \mask_minus1, 7
- +50: implement_rematrix \shift, \index_mask, \mask_minus1, 5
- +51: implement_rematrix \shift, \index_mask, \mask_minus1, 1
- +.endm
- +
- +.macro switch_on_mask shift, index_mask
- + cmp sl, #-1
- + bne 40f
- + switch_on_maxchan \shift, \index_mask, 1
- +40: switch_on_maxchan \shift, \index_mask, 0
- +.endm
- +
- +.macro switch_on_au_size shift
- + .if \shift == 0
- + switch_on_mask \shift, undefined
- + .else
- + teq v6, #64
- + bne 30f
- + orr INDEX, INDEX, v1, lsl #32-6
- + switch_on_mask \shift, 63
- +30: orr INDEX, INDEX, v1, lsl #32-7
- + switch_on_mask \shift, 127
- + .endif
- +.endm
- +
- +/* void ff_mlp_rematrix_channel_arm(int32_t *samples,
- + * const int32_t *coeffs,
- + * const uint8_t *bypassed_lsbs,
- + * const int8_t *noise_buffer,
- + * int index,
- + * unsigned int dest_ch,
- + * uint16_t blockpos,
- + * unsigned int maxchan,
- + * int matrix_noise_shift,
- + * int access_unit_size_pow2,
- + * int32_t mask);
- + */
- +function ff_mlp_rematrix_channel_arm, export=1
- + push {v1-fp,lr}
- + add v1, sp, #9*4 // point at arguments on stack
- + ldm v1, {v1-sl}
- + teq v4, #1
- + teqne v4, #5
- + teqne v4, #7
- + bne 99f
- + teq v6, #64
- + teqne v6, #128
- + bne 99f
- + sub v2, v2, #MAX_CHANNELS
- + push {a4,v2,sl} // initialise NOISE,DCH,MASK; make sp dword-aligned
- + movs INDEX, v3, lsl #7
- + beq 98f // just in case, do nothing if blockpos = 0
- + subs INDEX, INDEX, #1<<7 // offset by 1 so we borrow at the right time
- + adc lr, v1, v1 // calculate index2 (C was set by preceding subs)
- + orr INDEX, INDEX, lr
- + // Switch on matrix_noise_shift: values 0 and 1 are
- + // disproportionately common so do those in a form the branch
- + // predictor can accelerate. Values can only go up to 15.
- + cmp v5, #1
- + beq 11f
- + blo 10f
- + ldr pc, [pc, v5, lsl #2]
- + .word 0
- + .word 0
- + .word 0
- + .word 12f
- + .word 13f
- + .word 14f
- + .word 15f
- + .word 16f
- + .word 17f
- + .word 18f
- + .word 19f
- + .word 20f
- + .word 21f
- + .word 22f
- + .word 23f
- + .word 24f
- + .word 25f
- +10: switch_on_au_size 0
- +11: switch_on_au_size 1
- +12: switch_on_au_size 2
- +13: switch_on_au_size 3
- +14: switch_on_au_size 4
- +15: switch_on_au_size 5
- +16: switch_on_au_size 6
- +17: switch_on_au_size 7
- +18: switch_on_au_size 8
- +19: switch_on_au_size 9
- +20: switch_on_au_size 10
- +21: switch_on_au_size 11
- +22: switch_on_au_size 12
- +23: switch_on_au_size 13
- +24: switch_on_au_size 14
- +25: switch_on_au_size 15
- +
- +98: add sp, sp, #3*4
- + pop {v1-fp,pc}
- +99: // Can't handle these parameters, drop back to C
- + pop {v1-fp,lr}
- + b X(ff_mlp_rematrix_channel)
- +endfunc
- +
- + .unreq PSA
- + .unreq PCO
- + .unreq PBL
- + .unreq INDEX
- + .unreq CO0
- + .unreq CO1
- + .unreq CO2
- + .unreq CO3
- + .unreq SA0
- + .unreq SA1
- + .unreq SA2
- + .unreq SA3
- + .unreq AC0
- + .unreq AC1
- + .unreq NOISE
- + .unreq LSB
- + .unreq DCH
- + .unreq MASK
- diff --git a/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c b/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c
- index f0ea285..268dfdd 100644
- --- a/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c
- +++ b/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c
- @@ -29,8 +29,20 @@ void ff_mlp_filter_channel_arm(int32_t *state, const int32_t *coeff,
- int firorder, int iirorder,
- unsigned int filter_shift, int32_t mask,
- int blocksize, int32_t *sample_buffer);
- +void ff_mlp_rematrix_channel_arm(int32_t *samples,
- + const int32_t *coeffs,
- + const uint8_t *bypassed_lsbs,
- + const int8_t *noise_buffer,
- + int index,
- + unsigned int dest_ch,
- + uint16_t blockpos,
- + unsigned int maxchan,
- + int matrix_noise_shift,
- + int access_unit_size_pow2,
- + int32_t mask);
-
- av_cold void ff_mlpdsp_init_arm(MLPDSPContext *c)
- {
- c->mlp_filter_channel = ff_mlp_filter_channel_arm;
- + c->mlp_rematrix_channel = ff_mlp_rematrix_channel_arm;
- }
- --
- 1.9.3
- From 034e1a8920aec0fa36ffc7da8f63e48c68364e15 Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Wed, 19 Mar 2014 17:50:36 +0000
- Subject: [PATCH 11/94] truehd: tune VLC decoding for ARM.
- Profiling on a Raspberry Pi revealed the best performance to correspond
- with VLC_BITS = 5. Results for overall audio decode and the get_vlc2 function
- in particular are as follows:
- Before After
- Mean StdDev Mean StdDev Confidence Change
- 6:2 total 348.8 20.1 339.6 15.1 88.8% +2.7% (insignificant)
- 6:2 function 38.1 8.1 26.4 4.1 100.0% +44.5%
- 8:2 total 339.1 15.4 324.5 15.5 99.4% +4.5%
- 8:2 function 33.8 7.0 27.3 5.6 99.7% +23.6%
- 6:6 total 604.6 20.8 572.8 20.6 100.0% +5.6%
- 6:6 function 95.8 8.4 68.9 8.2 100.0% +39.1%
- 8:8 total 766.4 17.6 741.5 21.2 100.0% +3.4%
- 8:8 function 106.0 11.4 86.1 9.9 100.0% +23.1%
- ---
- lib/ffmpeg/libavcodec/mlpdec.c | 13 ++++++++++---
- 1 file changed, 10 insertions(+), 3 deletions(-)
- diff --git a/lib/ffmpeg/libavcodec/mlpdec.c b/lib/ffmpeg/libavcodec/mlpdec.c
- index e9343a5..a998dac 100644
- --- a/lib/ffmpeg/libavcodec/mlpdec.c
- +++ b/lib/ffmpeg/libavcodec/mlpdec.c
- @@ -36,9 +36,16 @@
- #include "mlp_parser.h"
- #include "mlpdsp.h"
- #include "mlp.h"
- +#include "config.h"
-
- /** number of bits used for VLC lookup - longest Huffman code is 9 */
- +#if ARCH_ARM == 1
- +#define VLC_BITS 5
- +#define VLC_STATIC_SIZE 64
- +#else
- #define VLC_BITS 9
- +#define VLC_STATIC_SIZE 512
- +#endif
-
- typedef struct SubStream {
- /// Set if a valid restart header has been read. Otherwise the substream cannot be decoded.
- @@ -190,13 +197,13 @@ static av_cold void init_static(void)
- if (!huff_vlc[0].bits) {
- INIT_VLC_STATIC(&huff_vlc[0], VLC_BITS, 18,
- &ff_mlp_huffman_tables[0][0][1], 2, 1,
- - &ff_mlp_huffman_tables[0][0][0], 2, 1, 512);
- + &ff_mlp_huffman_tables[0][0][0], 2, 1, VLC_STATIC_SIZE);
- INIT_VLC_STATIC(&huff_vlc[1], VLC_BITS, 16,
- &ff_mlp_huffman_tables[1][0][1], 2, 1,
- - &ff_mlp_huffman_tables[1][0][0], 2, 1, 512);
- + &ff_mlp_huffman_tables[1][0][0], 2, 1, VLC_STATIC_SIZE);
- INIT_VLC_STATIC(&huff_vlc[2], VLC_BITS, 15,
- &ff_mlp_huffman_tables[2][0][1], 2, 1,
- - &ff_mlp_huffman_tables[2][0][0], 2, 1, 512);
- + &ff_mlp_huffman_tables[2][0][0], 2, 1, VLC_STATIC_SIZE);
- }
-
- ff_mlp_init_crc();
- --
- 1.9.3
- From 25ab0401ebb7f035bcf7291452e6772a9c7b233a Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Wed, 19 Mar 2014 17:54:07 +0000
- Subject: [PATCH 12/94] truehd: break out part of output_data into
- platform-specific callback.
- Verified with profiling that this doesn't have a measurable effect upon
- overall performance.
- ---
- lib/ffmpeg/libavcodec/mlpdec.c | 40 +++++++++++++++++++++++-----------------
- lib/ffmpeg/libavcodec/mlpdsp.c | 36 ++++++++++++++++++++++++++++++++++++
- lib/ffmpeg/libavcodec/mlpdsp.h | 22 ++++++++++++++++++++++
- 3 files changed, 81 insertions(+), 17 deletions(-)
- diff --git a/lib/ffmpeg/libavcodec/mlpdec.c b/lib/ffmpeg/libavcodec/mlpdec.c
- index a998dac..6d7c803 100644
- --- a/lib/ffmpeg/libavcodec/mlpdec.c
- +++ b/lib/ffmpeg/libavcodec/mlpdec.c
- @@ -359,6 +359,10 @@ static int read_major_sync(MLPDecodeContext *m, GetBitContext *gb)
- m->avctx->sample_fmt = AV_SAMPLE_FMT_S32;
- else
- m->avctx->sample_fmt = AV_SAMPLE_FMT_S16;
- + m->dsp.mlp_pack_output = m->dsp.mlp_select_pack_output(m->substream[m->max_decoded_substream].max_matrix_channel,
- + m->avctx->sample_fmt == AV_SAMPLE_FMT_S32,
- + m->substream[m->max_decoded_substream].ch_assign,
- + m->substream[m->max_decoded_substream].output_shift);
-
- m->params_valid = 1;
- for (substr = 0; substr < MAX_SUBSTREAMS; substr++)
- @@ -553,6 +557,10 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp,
- if (substr == m->max_decoded_substream) {
- m->avctx->channels = s->max_matrix_channel + 1;
- m->avctx->channel_layout = s->ch_layout;
- + m->dsp.mlp_pack_output = m->dsp.mlp_select_pack_output(s->max_matrix_channel,
- + m->avctx->sample_fmt == AV_SAMPLE_FMT_S32,
- + s->ch_assign,
- + s->output_shift);
-
- if (m->avctx->codec_id == AV_CODEC_ID_MLP && m->needs_reordering) {
- if (m->avctx->channel_layout == (AV_CH_LAYOUT_QUAD|AV_CH_LOW_FREQUENCY) ||
- @@ -798,9 +806,15 @@ static int read_decoding_params(MLPDecodeContext *m, GetBitContext *gbp,
- return ret;
-
- if (s->param_presence_flags & PARAM_OUTSHIFT)
- - if (get_bits1(gbp))
- + if (get_bits1(gbp)) {
- for (ch = 0; ch <= s->max_matrix_channel; ch++)
- s->output_shift[ch] = get_sbits(gbp, 4);
- + if (substr == m->max_decoded_substream)
- + m->dsp.mlp_pack_output = m->dsp.mlp_select_pack_output(s->max_matrix_channel,
- + m->avctx->sample_fmt == AV_SAMPLE_FMT_S32,
- + s->ch_assign,
- + s->output_shift);
- + }
-
- if (s->param_presence_flags & PARAM_QUANTSTEP)
- if (get_bits1(gbp))
- @@ -999,9 +1013,6 @@ static int output_data(MLPDecodeContext *m, unsigned int substr,
- {
- AVCodecContext *avctx = m->avctx;
- SubStream *s = &m->substream[substr];
- - unsigned int i, out_ch = 0;
- - int32_t *data_32;
- - int16_t *data_16;
- int ret;
- int is32 = (m->avctx->sample_fmt == AV_SAMPLE_FMT_S32);
-
- @@ -1021,19 +1032,14 @@ static int output_data(MLPDecodeContext *m, unsigned int substr,
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return ret;
- }
- - data_32 = (int32_t *)frame->data[0];
- - data_16 = (int16_t *)frame->data[0];
- -
- - for (i = 0; i < s->blockpos; i++) {
- - for (out_ch = 0; out_ch <= s->max_matrix_channel; out_ch++) {
- - int mat_ch = s->ch_assign[out_ch];
- - int32_t sample = m->sample_buffer[i][mat_ch]
- - << s->output_shift[mat_ch];
- - s->lossless_check_data ^= (sample & 0xffffff) << mat_ch;
- - if (is32) *data_32++ = sample << 8;
- - else *data_16++ = sample >> 8;
- - }
- - }
- + s->lossless_check_data = m->dsp.mlp_pack_output(s->lossless_check_data,
- + m->sample_buffer,
- + frame->data[0],
- + s->blockpos,
- + s->max_matrix_channel,
- + is32,
- + s->ch_assign,
- + s->output_shift);
-
- *got_frame_ptr = 1;
-
- diff --git a/lib/ffmpeg/libavcodec/mlpdsp.c b/lib/ffmpeg/libavcodec/mlpdsp.c
- index 1f912fb..2bb5cec 100644
- --- a/lib/ffmpeg/libavcodec/mlpdsp.c
- +++ b/lib/ffmpeg/libavcodec/mlpdsp.c
- @@ -88,10 +88,46 @@ void ff_mlp_rematrix_channel(int32_t *samples,
- }
- }
-
- +static int32_t (*mlp_select_pack_output(uint8_t max_matrix_channel,
- + int is32,
- + uint8_t *ch_assign,
- + int8_t *output_shift))(int32_t, int32_t (*)[], void *, uint16_t, uint8_t, int, uint8_t*, int8_t *)
- +{
- + return ff_mlp_pack_output;
- +}
- +
- +int32_t ff_mlp_pack_output(int32_t lossless_check_data,
- + int32_t (*sample_buffer)[MAX_CHANNELS],
- + void *data,
- + uint16_t blockpos,
- + uint8_t max_matrix_channel,
- + int is32,
- + uint8_t *ch_assign,
- + int8_t *output_shift)
- +{
- + unsigned int i, out_ch = 0;
- + int32_t *data_32 = (int32_t *)data;
- + int16_t *data_16 = (int16_t *)data;
- +
- + for (i = 0; i < blockpos; i++) {
- + for (out_ch = 0; out_ch <= max_matrix_channel; out_ch++) {
- + int mat_ch = ch_assign[out_ch];
- + int32_t sample = sample_buffer[i][mat_ch]
- + << output_shift[mat_ch];
- + lossless_check_data ^= (sample & 0xffffff) << mat_ch;
- + if (is32) *data_32++ = sample << 8;
- + else *data_16++ = sample >> 8;
- + }
- + }
- + return lossless_check_data;
- +}
- +
- av_cold void ff_mlpdsp_init(MLPDSPContext *c)
- {
- c->mlp_filter_channel = ff_mlp_filter_channel;
- c->mlp_rematrix_channel = ff_mlp_rematrix_channel;
- + c->mlp_select_pack_output = mlp_select_pack_output;
- + c->mlp_pack_output = ff_mlp_pack_output;
- if (ARCH_X86)
- ff_mlpdsp_init_x86(c);
- }
- diff --git a/lib/ffmpeg/libavcodec/mlpdsp.h b/lib/ffmpeg/libavcodec/mlpdsp.h
- index f98e9be..5bc901f 100644
- --- a/lib/ffmpeg/libavcodec/mlpdsp.h
- +++ b/lib/ffmpeg/libavcodec/mlpdsp.h
- @@ -23,6 +23,7 @@
- #define AVCODEC_MLPDSP_H
-
- #include <stdint.h>
- +#include "mlp.h"
-
- void ff_mlp_rematrix_channel(int32_t *samples,
- const int32_t *coeffs,
- @@ -36,6 +37,15 @@ void ff_mlp_rematrix_channel(int32_t *samples,
- int access_unit_size_pow2,
- int32_t mask);
-
- +int32_t ff_mlp_pack_output(int32_t lossless_check_data,
- + int32_t (*sample_buffer)[MAX_CHANNELS],
- + void *data,
- + uint16_t blockpos,
- + uint8_t max_matrix_channel,
- + int is32,
- + uint8_t *ch_assign,
- + int8_t *output_shift);
- +
- typedef struct MLPDSPContext {
- void (*mlp_filter_channel)(int32_t *state, const int32_t *coeff,
- int firorder, int iirorder,
- @@ -52,6 +62,18 @@ typedef struct MLPDSPContext {
- int matrix_noise_shift,
- int access_unit_size_pow2,
- int32_t mask);
- + int32_t (*(*mlp_select_pack_output)(uint8_t max_matrix_channel,
- + int is32,
- + uint8_t *ch_assign,
- + int8_t *output_shift))(int32_t, int32_t (*)[], void *, uint16_t, uint8_t, int, uint8_t*, int8_t *);
- + int32_t (*mlp_pack_output)(int32_t lossless_check_data,
- + int32_t (*sample_buffer)[MAX_CHANNELS],
- + void *data,
- + uint16_t blockpos,
- + uint8_t max_matrix_channel,
- + int is32,
- + uint8_t *ch_assign,
- + int8_t *output_shift);
- } MLPDSPContext;
-
- void ff_mlpdsp_init(MLPDSPContext *c);
- --
- 1.9.3
- From bdefac00779c5601816f949353d9bbeb3b199611 Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Wed, 19 Mar 2014 17:54:59 +0000
- Subject: [PATCH 13/94] truehd: add hand-scheduled ARM asm version of
- ff_mlp_pack_output.
- Profiling results for overall decode and the output_data function in
- particular are as follows:
- Before After
- Mean StdDev Mean StdDev Confidence Change
- 6:2 total 339.6 15.1 329.3 16.0 95.8% +3.1% (insignificant)
- 6:2 function 24.6 6.0 9.9 3.1 100.0% +148.5%
- 8:2 total 324.5 15.5 323.6 14.3 15.2% +0.3% (insignificant)
- 8:2 function 20.4 3.9 9.9 3.4 100.0% +104.7%
- 6:6 total 572.8 20.6 539.9 24.2 100.0% +6.1%
- 6:6 function 54.5 5.6 16.0 3.8 100.0% +240.9%
- 8:8 total 741.5 21.2 702.5 18.5 100.0% +5.6%
- 8:8 function 63.9 7.6 18.4 4.8 100.0% +247.3%
- The assembly version has also been tested with a fuzz tester to ensure that
- any combinations of inputs not exercised by my available test streams still
- generate mathematically identical results to the C version.
- ---
- lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S | 503 ++++++++++++++++++++++++++++
- lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c | 64 ++++
- 2 files changed, 567 insertions(+)
- diff --git a/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S b/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S
- index 10008fe..338d323 100644
- --- a/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S
- +++ b/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S
- @@ -98,6 +98,26 @@ A .endif
- .endif
- .endm
-
- +.macro loadregoffsh2 group, index, base, offgroup, offindex
- + .altmacro
- + loadregoffsh2_ \group, %(\index), \base, \offgroup, %(\offindex)
- + .noaltmacro
- +.endm
- +
- +.macro loadregoffsh2_ group, index, base, offgroup, offindex
- + ldr \group\index, [\base, \offgroup\offindex, lsl #2]
- +.endm
- +
- +.macro eorlslreg check, data, group, index
- + .altmacro
- + eorlslreg_ \check, \data, \group, %(\index)
- + .noaltmacro
- +.endm
- +
- +.macro eorlslreg_ check, data, group, index
- + eor \check, \check, \data, lsl \group\index
- +.endm
- +
- // A macro to update the load register number and load offsets
-
- .macro inc howmany
- @@ -659,3 +679,486 @@ endfunc
- .unreq LSB
- .unreq DCH
- .unreq MASK
- +
- +/********************************************************************/
- +
- +.macro decr_modulo var, by, modulus
- + .set \var, \var - \by
- + .if \var == 0
- + .set \var, \modulus
- + .endif
- +.endm
- +
- + .macro load_group1 size, channels, r0, r1, r2, r3, pointer_dead=0
- + .if \size == 2
- + ldrd \r0, \r1, [IN], #(\size + 8 - \channels) * 4
- + .else // size == 4
- + .if IDX1 > 4 || \channels==8
- + ldm IN!, {\r0, \r1, \r2, \r3}
- + .else
- + ldm IN, {\r0, \r1, \r2, \r3}
- + .if !\pointer_dead
- + add IN, IN, #(4 + 8 - \channels) * 4
- + .endif
- + .endif
- + .endif
- + decr_modulo IDX1, \size, \channels
- + .endm
- +
- + .macro load_group2 size, channels, r0, r1, r2, r3, pointer_dead=0
- + .if \size == 2
- + .if IDX1 > 2
- + ldm IN!, {\r2, \r3}
- + .else
- +//A .ifc \r2, ip
- +//A .if \pointer_dead
- +//A ldm IN, {\r2, \r3}
- +//A .else
- +//A ldr \r2, [IN], #4
- +//A ldr \r3, [IN], #(\size - 1 + 8 - \channels) * 4
- +//A .endif
- +//A .else
- + ldrd \r2, \r3, [IN], #(\size + 8 - \channels) * 4
- +//A .endif
- + .endif
- + .endif
- + decr_modulo IDX1, \size, \channels
- + .endm
- +
- +.macro implement_pack inorder, channels, shift
- +.if \inorder
- +.ifc \shift, mixed
- +
- +CHECK .req a1
- +IN .req a2
- +OUT .req a3
- +COUNT .req a4
- +DAT0 .req v1
- +DAT1 .req v2
- +DAT2 .req v3
- +DAT3 .req v4
- +SHIFT0 .req v5
- +SHIFT1 .req v6
- +SHIFT2 .req sl
- +SHIFT3 .req fp
- +SHIFT4 .req ip
- +SHIFT5 .req lr
- +
- + .macro output4words
- + .set SIZE_GROUP1, IDX1
- + .if SIZE_GROUP1 > 4
- + .set SIZE_GROUP1, 4
- + .endif
- + .set SIZE_GROUP2, 4 - SIZE_GROUP1
- + load_group1 SIZE_GROUP1, \channels, DAT0, DAT1, DAT2, DAT3
- + load_group2 SIZE_GROUP2, \channels, DAT0, DAT1, DAT2, DAT3
- + .if \channels == 2
- + lsl DAT0, SHIFT0
- + lsl DAT1, SHIFT1
- + lsl DAT2, SHIFT0
- + lsl DAT3, SHIFT1
- + .elseif \channels == 6
- + .if IDX2 == 6
- + lsl DAT0, SHIFT0
- + lsl DAT1, SHIFT1
- + lsl DAT2, SHIFT2
- + lsl DAT3, SHIFT3
- + .elseif IDX2 == 2
- + lsl DAT0, SHIFT4
- + lsl DAT1, SHIFT5
- + lsl DAT2, SHIFT0
- + lsl DAT3, SHIFT1
- + .else // IDX2 == 4
- + lsl DAT0, SHIFT2
- + lsl DAT1, SHIFT3
- + lsl DAT2, SHIFT4
- + lsl DAT3, SHIFT5
- + .endif
- + .elseif \channels == 8
- + .if IDX2 == 8
- + uxtb SHIFT0, SHIFT4, ror #0
- + uxtb SHIFT1, SHIFT4, ror #8
- + uxtb SHIFT2, SHIFT4, ror #16
- + uxtb SHIFT3, SHIFT4, ror #24
- + .else
- + uxtb SHIFT0, SHIFT5, ror #0
- + uxtb SHIFT1, SHIFT5, ror #8
- + uxtb SHIFT2, SHIFT5, ror #16
- + uxtb SHIFT3, SHIFT5, ror #24
- + .endif
- + lsl DAT0, SHIFT0
- + lsl DAT1, SHIFT1
- + lsl DAT2, SHIFT2
- + lsl DAT3, SHIFT3
- + .endif
- + eor CHECK, CHECK, DAT0, lsr #8 - (\channels - IDX2)
- + eor CHECK, CHECK, DAT1, lsr #7 - (\channels - IDX2)
- + decr_modulo IDX2, 2, \channels
- + eor CHECK, CHECK, DAT2, lsr #8 - (\channels - IDX2)
- + eor CHECK, CHECK, DAT3, lsr #7 - (\channels - IDX2)
- + decr_modulo IDX2, 2, \channels
- + stm OUT!, {DAT0 - DAT3}
- + .endm
- +
- + .set WORDS_PER_LOOP, \channels // calculate LCM (channels, 4)
- + .if (WORDS_PER_LOOP % 2) == 0
- + .set WORDS_PER_LOOP, WORDS_PER_LOOP / 2
- + .endif
- + .if (WORDS_PER_LOOP % 2) == 0
- + .set WORDS_PER_LOOP, WORDS_PER_LOOP / 2
- + .endif
- + .set WORDS_PER_LOOP, WORDS_PER_LOOP * 4
- + .set SAMPLES_PER_LOOP, WORDS_PER_LOOP / \channels
- +
- +function ff_mlp_pack_output_inorder_\channels\()ch_mixedshift_arm, export=1
- + .if SAMPLES_PER_LOOP > 1
- + tst COUNT, #SAMPLES_PER_LOOP - 1 // always seems to be in practice
- + bne X(ff_mlp_pack_output) // but just in case, branch to C implementation if not
- + .endif
- + teq COUNT, #0
- + bxeq lr
- + push {v1-v6,sl,fp,lr}
- + ldr SHIFT0, [sp, #(9+3)*4] // get output_shift from stack
- + ldr SHIFT1, =0x08080808
- + ldr SHIFT4, [SHIFT0]
- + .if \channels == 2
- + uadd8 SHIFT4, SHIFT4, SHIFT1 // increase all shifts by 8
- + uxtb SHIFT0, SHIFT4, ror #0
- + uxtb SHIFT1, SHIFT4, ror #8
- + .else
- + ldr SHIFT5, [SHIFT0, #4]
- + uadd8 SHIFT4, SHIFT4, SHIFT1 // increase all shifts by 8
- + uadd8 SHIFT5, SHIFT5, SHIFT1
- + .if \channels == 6
- + uxtb SHIFT0, SHIFT4, ror #0
- + uxtb SHIFT1, SHIFT4, ror #8
- + uxtb SHIFT2, SHIFT4, ror #16
- + uxtb SHIFT3, SHIFT4, ror #24
- + uxtb SHIFT4, SHIFT5, ror #0
- + uxtb SHIFT5, SHIFT5, ror #8
- + .endif
- + .endif
- + .set IDX1, \channels
- + .set IDX2, \channels
- +0:
- + .rept WORDS_PER_LOOP / 4
- + output4words
- + .endr
- + subs COUNT, COUNT, #SAMPLES_PER_LOOP
- + bne 0b
- + pop {v1-v6,sl,fp,pc}
- + .ltorg
- +endfunc
- + .purgem output4words
- +
- + .unreq CHECK
- + .unreq IN
- + .unreq OUT
- + .unreq COUNT
- + .unreq DAT0
- + .unreq DAT1
- + .unreq DAT2
- + .unreq DAT3
- + .unreq SHIFT0
- + .unreq SHIFT1
- + .unreq SHIFT2
- + .unreq SHIFT3
- + .unreq SHIFT4
- + .unreq SHIFT5
- +
- +.else // not mixed
- +
- +CHECK .req a1
- +IN .req a2
- +OUT .req a3
- +COUNT .req a4
- +DAT0 .req v1
- +DAT1 .req v2
- +DAT2 .req v3
- +DAT3 .req v4
- +DAT4 .req v5
- +DAT5 .req v6
- +DAT6 .req sl // use these rather than the otherwise unused
- +DAT7 .req fp // ip and lr so that we can load them usinf LDRD
- +
- + .macro output4words tail, head, r0, r1, r2, r3, r4, r5, r6, r7, pointer_dead=0
- + .if \head
- + .set SIZE_GROUP1, IDX1
- + .if SIZE_GROUP1 > 4
- + .set SIZE_GROUP1, 4
- + .endif
- + .set SIZE_GROUP2, 4 - SIZE_GROUP1
- + load_group1 SIZE_GROUP1, \channels, \r0, \r1, \r2, \r3, \pointer_dead
- + .endif
- + .if \tail
- + eor CHECK, CHECK, \r4, lsr #8 - (\channels - IDX2)
- + eor CHECK, CHECK, \r5, lsr #7 - (\channels - IDX2)
- + decr_modulo IDX2, 2, \channels
- + .endif
- + .if \head
- + load_group2 SIZE_GROUP2, \channels, \r0, \r1, \r2, \r3, \pointer_dead
- + .endif
- + .if \tail
- + eor CHECK, CHECK, \r6, lsr #8 - (\channels - IDX2)
- + eor CHECK, CHECK, \r7, lsr #7 - (\channels - IDX2)
- + decr_modulo IDX2, 2, \channels
- + stm OUT!, {\r4, \r5, \r6, \r7}
- + .endif
- + .if \head
- + lsl \r0, #8 + \shift
- + lsl \r1, #8 + \shift
- + lsl \r2, #8 + \shift
- + lsl \r3, #8 + \shift
- + .endif
- + .endm
- +
- + .set WORDS_PER_LOOP, \channels // calculate LCM (channels, 8)
- + .if (WORDS_PER_LOOP % 2) == 0
- + .set WORDS_PER_LOOP, WORDS_PER_LOOP / 2
- + .endif
- + .if (WORDS_PER_LOOP % 2) == 0
- + .set WORDS_PER_LOOP, WORDS_PER_LOOP / 2
- + .endif
- + .if (WORDS_PER_LOOP % 2) == 0
- + .set WORDS_PER_LOOP, WORDS_PER_LOOP / 2
- + .endif
- + .set WORDS_PER_LOOP, WORDS_PER_LOOP * 8
- + .set SAMPLES_PER_LOOP, WORDS_PER_LOOP / \channels
- +
- +function ff_mlp_pack_output_inorder_\channels\()ch_\shift\()shift_arm, export=1
- + .if SAMPLES_PER_LOOP > 1
- + tst COUNT, #SAMPLES_PER_LOOP - 1 // always seems to be in practice
- + bne X(ff_mlp_pack_output) // but just in case, branch to C implementation if not
- + .endif
- + subs COUNT, COUNT, #SAMPLES_PER_LOOP
- + bxlo lr
- + push {v1-v6,sl,fp,lr}
- + .set IDX1, \channels
- + .set IDX2, \channels
- + output4words 0, 1, DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, DAT7
- +0: beq 1f
- + .rept WORDS_PER_LOOP / 8
- + output4words 1, 1, DAT4, DAT5, DAT6, DAT7, DAT0, DAT1, DAT2, DAT3
- + output4words 1, 1, DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, DAT7
- + .endr
- + subs COUNT, COUNT, #SAMPLES_PER_LOOP
- + bne 0b
- +1:
- + .rept WORDS_PER_LOOP / 8 - 1
- + output4words 1, 1, DAT4, DAT5, DAT6, DAT7, DAT0, DAT1, DAT2, DAT3
- + output4words 1, 1, DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, DAT7
- + .endr
- + output4words 1, 1, DAT4, DAT5, DAT6, DAT7, DAT0, DAT1, DAT2, DAT3, pointer_dead=1
- + output4words 1, 0, DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, DAT7
- + pop {v1-v6,sl,fp,pc}
- +endfunc
- + .purgem output4words
- +
- + .unreq CHECK
- + .unreq IN
- + .unreq OUT
- + .unreq COUNT
- + .unreq DAT0
- + .unreq DAT1
- + .unreq DAT2
- + .unreq DAT3
- + .unreq DAT4
- + .unreq DAT5
- + .unreq DAT6
- + .unreq DAT7
- +
- +.endif // mixed
- +.else // not inorder
- +.ifc \shift, mixed
- +
- +// This case not currently handled
- +
- +.else // not mixed
- +
- +CHECK .req a1
- +IN .req a2
- +OUT .req a3
- +COUNT .req a4
- +DAT0 .req v1
- +DAT1 .req v2
- +DAT2 .req v3
- +DAT3 .req v4
- +CHAN0 .req v5
- +CHAN1 .req v6
- +CHAN2 .req sl
- +CHAN3 .req fp
- +CHAN4 .req ip
- +CHAN5 .req lr
- +
- + .macro output4words
- + .if \channels == 8
- + .if IDX1 == 8
- + uxtb CHAN0, CHAN4, ror #0
- + uxtb CHAN1, CHAN4, ror #8
- + uxtb CHAN2, CHAN4, ror #16
- + uxtb CHAN3, CHAN4, ror #24
- + .else
- + uxtb CHAN0, CHAN5, ror #0
- + uxtb CHAN1, CHAN5, ror #8
- + uxtb CHAN2, CHAN5, ror #16
- + uxtb CHAN3, CHAN5, ror #24
- + .endif
- + ldr DAT0, [IN, CHAN0, lsl #2]
- + ldr DAT1, [IN, CHAN1, lsl #2]
- + ldr DAT2, [IN, CHAN2, lsl #2]
- + ldr DAT3, [IN, CHAN3, lsl #2]
- + .if IDX1 == 4
- + add IN, IN, #8*4
- + .endif
- + decr_modulo IDX1, 4, \channels
- + .else
- + .set SIZE_GROUP1, IDX1
- + .if SIZE_GROUP1 > 4
- + .set SIZE_GROUP1, 4
- + .endif
- + .set SIZE_GROUP2, 4 - SIZE_GROUP1
- + .if SIZE_GROUP1 == 2
- + loadregoffsh2 DAT, 0, IN, CHAN, 0 + (\channels - IDX1)
- + loadregoffsh2 DAT, 1, IN, CHAN, 1 + (\channels - IDX1)
- + add IN, IN, #8*4
- + .else // SIZE_GROUP1 == 4
- + loadregoffsh2 DAT, 0, IN, CHAN, 0 + (\channels - IDX1)
- + loadregoffsh2 DAT, 1, IN, CHAN, 1 + (\channels - IDX1)
- + loadregoffsh2 DAT, 2, IN, CHAN, 2 + (\channels - IDX1)
- + loadregoffsh2 DAT, 3, IN, CHAN, 3 + (\channels - IDX1)
- + .if IDX1 == 4
- + add IN, IN, #8*4
- + .endif
- + .endif
- + decr_modulo IDX1, SIZE_GROUP1, \channels
- + .if SIZE_GROUP2 == 2
- + loadregoffsh2 DAT, 2, IN, CHAN, 0 + (\channels - IDX1)
- + loadregoffsh2 DAT, 3, IN, CHAN, 1 + (\channels - IDX1)
- + .if IDX1 == 2
- + add IN, IN, #8*4
- + .endif
- + .endif
- + decr_modulo IDX1, SIZE_GROUP2, \channels
- + .endif
- + .if \channels == 8 // in this case we can corrupt CHAN0-3
- + rsb CHAN0, CHAN0, #8
- + rsb CHAN1, CHAN1, #8
- + rsb CHAN2, CHAN2, #8
- + rsb CHAN3, CHAN3, #8
- + lsl DAT0, #8 + \shift
- + lsl DAT1, #8 + \shift
- + lsl DAT2, #8 + \shift
- + lsl DAT3, #8 + \shift
- + eor CHECK, CHECK, DAT0, lsr CHAN0
- + eor CHECK, CHECK, DAT1, lsr CHAN1
- + eor CHECK, CHECK, DAT2, lsr CHAN2
- + eor CHECK, CHECK, DAT3, lsr CHAN3
- + .else
- + .if \shift != 0
- + lsl DAT0, #\shift
- + lsl DAT1, #\shift
- + lsl DAT2, #\shift
- + lsl DAT3, #\shift
- + .endif
- + bic DAT0, DAT0, #0xff000000
- + bic DAT1, DAT1, #0xff000000
- + bic DAT2, DAT2, #0xff000000
- + bic DAT3, DAT3, #0xff000000
- + eorlslreg CHECK, DAT0, CHAN, 0 + (\channels - IDX2)
- + eorlslreg CHECK, DAT1, CHAN, 1 + (\channels - IDX2)
- + decr_modulo IDX2, 2, \channels
- + eorlslreg CHECK, DAT2, CHAN, 0 + (\channels - IDX2)
- + eorlslreg CHECK, DAT3, CHAN, 1 + (\channels - IDX2)
- + decr_modulo IDX2, 2, \channels
- + lsl DAT0, #8
- + lsl DAT1, #8
- + lsl DAT2, #8
- + lsl DAT3, #8
- + .endif
- + stm OUT!, {DAT0 - DAT3}
- + .endm
- +
- + .set WORDS_PER_LOOP, \channels // calculate LCM (channels, 4)
- + .if (WORDS_PER_LOOP % 2) == 0
- + .set WORDS_PER_LOOP, WORDS_PER_LOOP / 2
- + .endif
- + .if (WORDS_PER_LOOP % 2) == 0
- + .set WORDS_PER_LOOP, WORDS_PER_LOOP / 2
- + .endif
- + .set WORDS_PER_LOOP, WORDS_PER_LOOP * 4
- + .set SAMPLES_PER_LOOP, WORDS_PER_LOOP / \channels
- +
- +function ff_mlp_pack_output_outoforder_\channels\()ch_\shift\()shift_arm, export=1
- + .if SAMPLES_PER_LOOP > 1
- + tst COUNT, #SAMPLES_PER_LOOP - 1 // always seems to be in practice
- + bne X(ff_mlp_pack_output) // but just in case, branch to C implementation if not
- + .endif
- + teq COUNT, #0
- + bxeq lr
- + push {v1-v6,sl,fp,lr}
- + ldr CHAN0, [sp, #(9+2)*4] // get ch_assign from stack
- + ldr CHAN4, [CHAN0]
- + .if \channels == 2
- + uxtb CHAN0, CHAN4, ror #0
- + uxtb CHAN1, CHAN4, ror #8
- + .else
- + ldr CHAN5, [CHAN0, #4]
- + .if \channels == 6
- + uxtb CHAN0, CHAN4, ror #0
- + uxtb CHAN1, CHAN4, ror #8
- + uxtb CHAN2, CHAN4, ror #16
- + uxtb CHAN3, CHAN4, ror #24
- + uxtb CHAN4, CHAN5, ror #0
- + uxtb CHAN5, CHAN5, ror #8
- + .endif
- + .endif
- + .set IDX1, \channels
- + .set IDX2, \channels
- +0:
- + .rept WORDS_PER_LOOP / 4
- + output4words
- + .endr
- + subs COUNT, COUNT, #SAMPLES_PER_LOOP
- + bne 0b
- + pop {v1-v6,sl,fp,pc}
- + .ltorg
- +endfunc
- + .purgem output4words
- +
- + .unreq CHECK
- + .unreq IN
- + .unreq OUT
- + .unreq COUNT
- + .unreq DAT0
- + .unreq DAT1
- + .unreq DAT2
- + .unreq DAT3
- + .unreq CHAN0
- + .unreq CHAN1
- + .unreq CHAN2
- + .unreq CHAN3
- + .unreq CHAN4
- + .unreq CHAN5
- +
- +.endif // mixed
- +.endif // inorder
- +.endm // implement_pack
- +
- +.macro pack_channels inorder, channels
- + implement_pack \inorder, \channels, 0
- + implement_pack \inorder, \channels, 1
- + implement_pack \inorder, \channels, 2
- + implement_pack \inorder, \channels, 3
- + implement_pack \inorder, \channels, 4
- + implement_pack \inorder, \channels, 5
- + implement_pack \inorder, \channels, mixed
- +.endm
- +
- +.macro pack_order inorder
- + pack_channels \inorder, 2
- + pack_channels \inorder, 6
- + pack_channels \inorder, 8
- +.endm
- +
- + pack_order 0
- + pack_order 1
- diff --git a/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c b/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c
- index 268dfdd..2d8b98d 100644
- --- a/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c
- +++ b/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c
- @@ -41,8 +41,72 @@ void ff_mlp_rematrix_channel_arm(int32_t *samples,
- int access_unit_size_pow2,
- int32_t mask);
-
- +#define DECLARE_PACK(order,channels,shift) \
- + int32_t ff_mlp_pack_output_##order##order_##channels##ch_##shift##shift_arm(int32_t, int32_t (*)[], void *, uint16_t, uint8_t, int, uint8_t*, int8_t *);
- +#define ENUMERATE_PACK(order,channels,shift) \
- + ff_mlp_pack_output_##order##order_##channels##ch_##shift##shift_arm,
- +#define PACK_CHANNELS(macro,order,channels) \
- + macro(order,channels,0) \
- + macro(order,channels,1) \
- + macro(order,channels,2) \
- + macro(order,channels,3) \
- + macro(order,channels,4) \
- + macro(order,channels,5) \
- + macro(order,channels,mixed)
- +#define PACK_ORDER(macro,order) \
- + PACK_CHANNELS(macro,order,2) \
- + PACK_CHANNELS(macro,order,6) \
- + PACK_CHANNELS(macro,order,8)
- +#define PACK_ALL(macro) \
- + PACK_ORDER(macro,outof) \
- + PACK_ORDER(macro,in)
- +PACK_ALL(DECLARE_PACK)
- +
- +#define ff_mlp_pack_output_outoforder_2ch_mixedshift_arm 0
- +#define ff_mlp_pack_output_outoforder_6ch_mixedshift_arm 0
- +#define ff_mlp_pack_output_outoforder_8ch_mixedshift_arm 0
- +
- +static int32_t (*mlp_select_pack_output_arm(uint8_t max_matrix_channel,
- + int is32,
- + uint8_t *ch_assign,
- + int8_t *output_shift))(int32_t, int32_t (*)[], void *, uint16_t, uint8_t, int, uint8_t*, int8_t *)
- +{
- + int ch_index;
- + int shift = output_shift[0] < 0 || output_shift[0] > 5 ? 6 : output_shift[0];
- + int inorder = 1;
- + static int32_t (*const routine[2*3*7])(int32_t, int32_t (*)[], void *, uint16_t, uint8_t, int, uint8_t*, int8_t *) = {
- + PACK_ALL(ENUMERATE_PACK)
- + };
- + int i;
- +
- + if (!is32) // don't support 16-bit output (it's not used by TrueHD)
- + return ff_mlp_pack_output;
- +
- + switch (max_matrix_channel) {
- + case 1: ch_index = 0; break;
- + case 5: ch_index = 1; break;
- + case 7: ch_index = 2; break;
- + default: return ff_mlp_pack_output;
- + }
- +
- + for (i = 0; i <= max_matrix_channel; i++) {
- + if (shift != 6 && output_shift[i] != shift)
- + shift = 6; // indicate mixed shifts
- + if (ch_assign[i] != i)
- + inorder = 0;
- + }
- + if (shift == 6 && !inorder)
- + return ff_mlp_pack_output; // can't currently handle both an order array and a shift array
- +
- + return routine[(inorder*3+ch_index)*7+shift];
- +}
- +
- av_cold void ff_mlpdsp_init_arm(MLPDSPContext *c)
- {
- + int cpu_flags = av_get_cpu_flags();
- +
- c->mlp_filter_channel = ff_mlp_filter_channel_arm;
- c->mlp_rematrix_channel = ff_mlp_rematrix_channel_arm;
- + if (cpu_flags & AV_CPU_FLAG_ARMV6)
- + c->mlp_select_pack_output = mlp_select_pack_output_arm;
- }
- --
- 1.9.3
- From 9af15bf0b7bc7940bd8bcc9ddae23178c9723bd6 Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Thu, 14 Nov 2013 19:48:41 +0000
- Subject: [PATCH 14/94] More efficient infobool expression evaluator
- Expession infobools are evaluated at runtime from one or more single infobools
- and a combination of boolean NOT, AND and OR operators. Previously, parsing
- produced a vector of operands (leaf nodes) and operators in postfix
- (reverse-Polish) form, and evaluated all leaf nodes every time the expression
- was evaluated. But this ignores the fact that in many cases, once one operand
- of an AND or OR operation has been evaluated, there is no need to evaluate the
- other operand because its value can have no effect on the ultimate result. It
- is also worth noting that AND and OR operations are associative, meaning they
- can be rearranged at runtime to better suit the selected skin.
- This patch rewrites the expression parsing and evaluation code. Now the
- internal repreentation is in the form of a tree where leaf nodes represent a
- single infobool, and branch nodes represent either an AND or an OR operation
- on two or more child nodes.
- Expressions are rewritten at parse time into a form which favours the
- formation of groups of associative nodes. These groups are then reordered at
- evaluation time such that nodes whose value renders the evaluation of the
- remainder of the group unnecessary tend to be evaluated first (these are
- true nodes for OR subexpressions, or false nodes for AND subexpressions).
- The end effect is to minimise the number of leaf nodes that need to be
- evaluated in order to determine the value of the expression. The runtime
- adaptability has the advantage of not being customised for any particular skin.
- The modifications to the expression at parse time fall into two groups:
- 1) Moving logical NOTs so that they are only applied to leaf nodes.
- For example, rewriting ![A+B]|C as !A|!B|C allows reordering such that
- any of the three leaves can be evaluated first.
- 2) Combining adjacent AND or OR operations such that each path from the root
- to a leaf encounters a strictly alternating pattern of AND and OR
- operations. So [A|B]|[C|D+[[E|F]|G] becomes A|B|C|[D+[E|F|G]].
- I measured the effect while the Videos window of the default skin was open
- (but idle) on a Raspberry Pi, and this reduced the CPU usage by 2.8% from
- 41.9% to 39.1%:
- Before After
- Mean StdDev Mean StdDev Confidence Change
- IdleCPU% 41.9 0.5 39.1 0.9 100.0% +7.0%
- ---
- xbmc/interfaces/info/InfoExpression.cpp | 313 +++++++++++++++++++++-----------
- xbmc/interfaces/info/InfoExpression.h | 63 ++++++-
- 2 files changed, 269 insertions(+), 107 deletions(-)
- diff --git a/xbmc/interfaces/info/InfoExpression.cpp b/xbmc/interfaces/info/InfoExpression.cpp
- index f4d32c1..db461dd 100644
- --- a/xbmc/interfaces/info/InfoExpression.cpp
- +++ b/xbmc/interfaces/info/InfoExpression.cpp
- @@ -22,6 +22,9 @@
- #include <stack>
- #include "utils/log.h"
- #include "GUIInfoManager.h"
- +#include <list>
- +#include <boost/shared_ptr.hpp>
- +#include <boost/make_shared.hpp>
-
- using namespace std;
- using namespace INFO;
- @@ -40,21 +43,89 @@ void InfoSingle::Update(const CGUIListItem *item)
- InfoExpression::InfoExpression(const std::string &expression, int context)
- : InfoBool(expression, context)
- {
- - Parse(expression);
- + if (!Parse(expression))
- + CLog::Log(LOGERROR, "Error parsing boolean expression %s", expression.c_str());
- }
-
- void InfoExpression::Update(const CGUIListItem *item)
- {
- - Evaluate(item, m_value);
- + m_value = m_expression_tree->Evaluate(item);
- }
-
- -#define OPERATOR_LB 5
- -#define OPERATOR_RB 4
- -#define OPERATOR_NOT 3
- -#define OPERATOR_AND 2
- -#define OPERATOR_OR 1
- +/* Expressions are rewritten at parse time into a form which favours the
- + * formation of groups of associative nodes. These groups are then reordered at
- + * evaluation time such that nodes whose value renders the evaluation of the
- + * remainder of the group unnecessary tend to be evaluated first (these are
- + * true nodes for OR subexpressions, or false nodes for AND subexpressions).
- + * The end effect is to minimise the number of leaf nodes that need to be
- + * evaluated in order to determine the value of the expression. The runtime
- + * adaptability has the advantage of not being customised for any particular skin.
- + *
- + * The modifications to the expression at parse time fall into two groups:
- + * 1) Moving logical NOTs so that they are only applied to leaf nodes.
- + * For example, rewriting ![A+B]|C as !A|!B|C allows reordering such that
- + * any of the three leaves can be evaluated first.
- + * 2) Combining adjacent AND or OR operations such that each path from the root
- + * to a leaf encounters a strictly alternating pattern of AND and OR
- + * operations. So [A|B]|[C|D+[[E|F]|G] becomes A|B|C|[D+[E|F|G]].
- + */
- +
- +bool InfoExpression::InfoLeaf::Evaluate(const CGUIListItem *item)
- +{
- + return m_invert ^ m_info->Get(item);
- +}
-
- -short InfoExpression::GetOperator(const char ch) const
- +InfoExpression::InfoAssociativeGroup::InfoAssociativeGroup(
- + bool and_not_or,
- + const InfoSubexpressionPtr &left,
- + const InfoSubexpressionPtr &right)
- + : m_and_not_or(and_not_or)
- +{
- + AddChild(right);
- + AddChild(left);
- +}
- +
- +void InfoExpression::InfoAssociativeGroup::AddChild(const InfoSubexpressionPtr &child)
- +{
- + m_children.push_front(child); // largely undoes the effect of parsing right-associative
- +}
- +
- +void InfoExpression::InfoAssociativeGroup::Merge(InfoAssociativeGroup *other)
- +{
- + m_children.splice(m_children.end(), other->m_children);
- +}
- +
- +bool InfoExpression::InfoAssociativeGroup::Evaluate(const CGUIListItem *item)
- +{
- + /* Handle either AND or OR by using the relation
- + * A AND B == !(!A OR !B)
- + * to convert ANDs into ORs
- + */
- + std::list<InfoSubexpressionPtr>::iterator last = m_children.end();
- + std::list<InfoSubexpressionPtr>::iterator it = m_children.begin();
- + bool result = m_and_not_or ^ (*it)->Evaluate(item);
- + while (!result && ++it != last)
- + {
- + result = m_and_not_or ^ (*it)->Evaluate(item);
- + if (result)
- + {
- + /* Move this child to the head of the list so we evaluate faster next time */
- + InfoSubexpressionPtr p = *it;
- + m_children.erase(it);
- + m_children.push_front(p);
- + }
- + }
- + return m_and_not_or ^ result;
- +}
- +
- +/* Expressions are parsed using the shunting-yard algorithm. Binary operators
- + * (AND/OR) are treated as right-associative so that we don't need to make a
- + * special case for the unary NOT operator. This has no effect upon the answers
- + * generated, though the initial sequence of evaluation of leaves may be
- + * different from what you might expect.
- + */
- +
- +InfoExpression::operator_t InfoExpression::GetOperator(char ch)
- {
- if (ch == '[')
- return OPERATOR_LB;
- @@ -67,122 +138,160 @@ short InfoExpression::GetOperator(const char ch) const
- else if (ch == '|')
- return OPERATOR_OR;
- else
- - return 0;
- + return OPERATOR_NONE;
- }
-
- -void InfoExpression::Parse(const std::string &expression)
- +void InfoExpression::OperatorPop(std::stack<operator_t> &operator_stack, bool &invert, std::stack<node_type_t> &node_types, std::stack<InfoSubexpressionPtr> &nodes)
- {
- - stack<char> operators;
- - std::string operand;
- - for (unsigned int i = 0; i < expression.size(); i++)
- + operator_t op2 = operator_stack.top();
- + operator_stack.pop();
- + if (op2 == OPERATOR_NOT)
- {
- - if (GetOperator(expression[i]))
- + invert = !invert;
- + }
- + else
- + {
- + // At this point, it can only be OPERATOR_AND or OPERATOR_OR
- + if (invert)
- + op2 = (operator_t) (OPERATOR_AND ^ OPERATOR_OR ^ op2);
- + node_type_t new_type = op2 == OPERATOR_AND ? NODE_AND : NODE_OR;
- +
- + InfoSubexpressionPtr right = nodes.top();
- + nodes.pop();
- + InfoSubexpressionPtr left = nodes.top();
- +
- + node_type_t right_type = node_types.top();
- + node_types.pop();
- + node_type_t left_type = node_types.top();
- +
- + // Combine associative operations into the same node where possible
- + if (left_type == new_type && right_type == new_type)
- + (static_cast<InfoAssociativeGroup *>(left.get()))->Merge(static_cast<InfoAssociativeGroup *>(right.get()));
- + else if (left_type == new_type)
- + (static_cast<InfoAssociativeGroup *>(left.get()))->AddChild(right);
- + else
- {
- - // cleanup any operand, translate and put into our expression list
- - if (!operand.empty())
- + nodes.pop();
- + node_types.pop();
- + if (right_type == new_type)
- {
- - InfoPtr info = g_infoManager.Register(operand, m_context);
- - if (info)
- - {
- - m_listItemDependent |= info->ListItemDependent();
- - m_postfix.push_back(m_operands.size());
- - m_operands.push_back(info);
- - }
- - operand.clear();
- + (static_cast<InfoAssociativeGroup *>(right.get()))->AddChild(left);
- + nodes.push(right);
- }
- - // handle closing parenthesis
- - if (expression[i] == ']')
- - {
- - while (!operators.empty())
- - {
- - char oper = operators.top();
- - operators.pop();
- + else
- + nodes.push(boost::make_shared<InfoAssociativeGroup>(new_type == NODE_AND, left, right));
- + node_types.push(new_type);
- + }
- + }
- +}
- +
- +void InfoExpression::ProcessOperator(operator_t op, std::stack<operator_t> &operator_stack, bool &invert, std::stack<node_type_t> &node_types, std::stack<InfoSubexpressionPtr> &nodes)
- +{
- + // Handle any higher-priority stacked operators, except when the new operator is left-bracket.
- + // For a right-bracket, this will stop with the matching left-bracket at the top of the operator stack.
- + if (op != OPERATOR_LB)
- + {
- + while (operator_stack.size() > 0 && operator_stack.top() > op)
- + OperatorPop(operator_stack, invert, node_types, nodes);
- + }
- + if (op == OPERATOR_RB)
- + operator_stack.pop(); // remove the matching left-bracket
- + else
- + operator_stack.push(op);
- + if (op == OPERATOR_NOT)
- + invert = !invert;
- +}
-
- - if (oper == '[')
- - break;
- +bool InfoExpression::ProcessOperand(std::string &operand, bool invert, std::stack<node_type_t> &node_types, std::stack<InfoSubexpressionPtr> &nodes)
- +{
- + InfoPtr info = g_infoManager.Register(operand, m_context);
- + if (!info)
- + return false;
- + m_listItemDependent |= info->ListItemDependent();
- + nodes.push(boost::make_shared<InfoLeaf>(info, invert));
- + node_types.push(NODE_LEAF);
- + operand.clear();
- + return true;
- +}
-
- - m_postfix.push_back(-GetOperator(oper)); // negative denotes operator
- - }
- +bool InfoExpression::Parse(const std::string &expression)
- +{
- + const char *s = expression.c_str();
- + std::string operand;
- + std::stack<operator_t> operator_stack;
- + bool invert = false;
- + std::stack<node_type_t> node_types;
- + std::stack<InfoSubexpressionPtr> nodes;
- + // The next two are for syntax-checking purposes
- + bool after_binaryoperator = true;
- + int bracket_count = 0;
- +
- + char c;
- + // Skip leading whitespace - don't want it to count as an operand if that's all there is
- + do
- + {
- + c = *s++;
- + } while (c == ' ' || c == '\t' || c == '\r' || c == '\n');
- + s--;
- + while ((c = *s++) != '\0')
- + {
- + operator_t op;
- + if ((op = GetOperator(c)) != OPERATOR_NONE)
- + {
- + // Character is an operator
- + if ((!after_binaryoperator && (c == '!' || c == '[')) ||
- + (after_binaryoperator && (c == ']' || c == '+' || c == '|')))
- + {
- + CLog::Log(LOGERROR, "Misplaced %c", c);
- + return false;
- }
- - else
- + if (c == '[')
- + bracket_count++;
- + else if (c == ']' && bracket_count-- == 0)
- + {
- + CLog::Log(LOGERROR, "Unmatched ]");
- + return false;
- + }
- + if (operand.size() > 0 && !ProcessOperand(operand, invert, node_types, nodes))
- {
- - // all other operators we pop off the stack any operator
- - // that has a higher priority than the one we have.
- - while (!operators.empty() && GetOperator(operators.top()) > GetOperator(expression[i]))
- - {
- - // only handle parenthesis once they're closed.
- - if (operators.top() == '[' && expression[i] != ']')
- - break;
- -
- - m_postfix.push_back(-GetOperator(operators.top())); // negative denotes operator
- - operators.pop();
- - }
- - operators.push(expression[i]);
- + CLog::Log(LOGERROR, "Bad operand '%s'", operand.c_str());
- + return false;
- }
- + ProcessOperator(op, operator_stack, invert, node_types, nodes);
- + if (c == '+' || c == '|')
- + after_binaryoperator = true;
- + // Skip trailing whitespace - don't want it to count as an operand if that's all there is
- + do
- + {
- + c = *s++;
- + } while (c == ' ' || c == '\t' || c == '\r' || c == '\n');
- + s--;
- }
- else
- {
- - operand += expression[i];
- + // Character is part of operand
- + operand += c;
- + after_binaryoperator = false;
- }
- }
- -
- - if (!operand.empty())
- + if (bracket_count > 0)
- {
- - InfoPtr info = g_infoManager.Register(operand, m_context);
- - if (info)
- - {
- - m_listItemDependent |= info->ListItemDependent();
- - m_postfix.push_back(m_operands.size());
- - m_operands.push_back(info);
- - }
- + CLog::Log(LOGERROR, "Unmatched [");
- + return false;
- }
- -
- - // finish up by adding any operators
- - while (!operators.empty())
- + if (after_binaryoperator)
- {
- - m_postfix.push_back(-GetOperator(operators.top())); // negative denotes operator
- - operators.pop();
- + CLog::Log(LOGERROR, "Missing operand");
- + return false;
- }
- -
- - // test evaluate
- - bool test;
- - if (!Evaluate(NULL, test))
- - CLog::Log(LOGERROR, "Error evaluating boolean expression %s", expression.c_str());
- -}
- -
- -bool InfoExpression::Evaluate(const CGUIListItem *item, bool &result)
- -{
- - stack<bool> save;
- - for (vector<short>::const_iterator it = m_postfix.begin(); it != m_postfix.end(); ++it)
- + if (operand.size() > 0 && !ProcessOperand(operand, invert, node_types, nodes))
- {
- - short expr = *it;
- - if (expr == -OPERATOR_NOT)
- - { // NOT the top item on the stack
- - if (save.empty()) return false;
- - bool expr = save.top();
- - save.pop();
- - save.push(!expr);
- - }
- - else if (expr == -OPERATOR_AND)
- - { // AND the top two items on the stack
- - if (save.size() < 2) return false;
- - bool right = save.top(); save.pop();
- - bool left = save.top(); save.pop();
- - save.push(left && right);
- - }
- - else if (expr == -OPERATOR_OR)
- - { // OR the top two items on the stack
- - if (save.size() < 2) return false;
- - bool right = save.top(); save.pop();
- - bool left = save.top(); save.pop();
- - save.push(left || right);
- - }
- - else if (expr >= 0) // operand
- - save.push(m_operands[expr]->Get(item));
- - }
- - if (save.size() != 1)
- + CLog::Log(LOGERROR, "Bad operand '%s'", operand.c_str());
- return false;
- - result = save.top();
- + }
- + while (operator_stack.size() > 0)
- + OperatorPop(operator_stack, invert, node_types, nodes);
- +
- + m_expression_tree = nodes.top();
- return true;
- }
- -
- diff --git a/xbmc/interfaces/info/InfoExpression.h b/xbmc/interfaces/info/InfoExpression.h
- index 4e0faee..0a91399 100644
- --- a/xbmc/interfaces/info/InfoExpression.h
- +++ b/xbmc/interfaces/info/InfoExpression.h
- @@ -21,6 +21,8 @@
- #pragma once
-
- #include <vector>
- +#include <list>
- +#include <stack>
- #include "InfoBool.h"
-
- class CGUIListItem;
- @@ -50,12 +52,63 @@ class InfoExpression : public InfoBool
-
- virtual void Update(const CGUIListItem *item);
- private:
- - void Parse(const std::string &expression);
- - bool Evaluate(const CGUIListItem *item, bool &result);
- - short GetOperator(const char ch) const;
- + typedef enum
- + {
- + OPERATOR_NONE = 0,
- + OPERATOR_LB, // 1
- + OPERATOR_RB, // 2
- + OPERATOR_OR, // 3
- + OPERATOR_AND, // 4
- + OPERATOR_NOT, // 5
- + } operator_t;
-
- - std::vector<short> m_postfix; ///< the postfix form of the expression (operators and operand indicies)
- - std::vector<InfoPtr> m_operands; ///< the operands in the expression
- + typedef enum
- + {
- + NODE_LEAF,
- + NODE_AND,
- + NODE_OR,
- + } node_type_t;
- +
- + // An abstract base class for nodes in the expression tree
- + class InfoSubexpression
- + {
- + public:
- + virtual ~InfoSubexpression(void) {}; // so we can destruct derived classes using a pointer to their base class
- + virtual bool Evaluate(const CGUIListItem *item) = 0;
- + };
- +
- + typedef boost::shared_ptr<InfoSubexpression> InfoSubexpressionPtr;
- +
- + // A leaf node in the expression tree
- + class InfoLeaf : public InfoSubexpression
- + {
- + public:
- + InfoLeaf(InfoPtr info, bool invert) : m_info(info), m_invert(invert) {};
- + virtual bool Evaluate(const CGUIListItem *item);
- + private:
- + InfoPtr m_info;
- + bool m_invert;
- + };
- +
- + // A branch node in the expression tree
- + class InfoAssociativeGroup : public InfoSubexpression
- + {
- + public:
- + InfoAssociativeGroup(bool and_not_or, const InfoSubexpressionPtr &left, const InfoSubexpressionPtr &right);
- + void AddChild(const InfoSubexpressionPtr &child);
- + void Merge(InfoAssociativeGroup *other);
- + virtual bool Evaluate(const CGUIListItem *item);
- + private:
- + bool m_and_not_or;
- + std::list<InfoSubexpressionPtr> m_children;
- + };
- +
- + static operator_t GetOperator(char ch);
- + static void OperatorPop(std::stack<operator_t> &operator_stack, bool &invert, std::stack<node_type_t> &node_types, std::stack<InfoSubexpressionPtr> &nodes);
- + static void ProcessOperator(operator_t op, std::stack<operator_t> &operator_stack, bool &invert, std::stack<node_type_t> &node_types, std::stack<InfoSubexpressionPtr> &nodes);
- + bool ProcessOperand(std::string &operand, bool invert, std::stack<node_type_t> &node_types, std::stack<InfoSubexpressionPtr> &nodes);
- + bool Parse(const std::string &expression);
- + InfoSubexpressionPtr m_expression_tree;
- };
-
- };
- --
- 1.9.3
- From 36067cf823d539a00eea75d561ac78a4b1431a66 Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Mon, 24 Mar 2014 22:26:21 +0000
- Subject: [PATCH 15/94] Where an infobool expression failed to parse, evaluate
- the infobool as false. Previously, this would result in a segfault due to the
- dereferencing of an uninitialised pointer to the head of the expression tree.
- ---
- xbmc/interfaces/info/InfoExpression.cpp | 3 +++
- 1 file changed, 3 insertions(+)
- diff --git a/xbmc/interfaces/info/InfoExpression.cpp b/xbmc/interfaces/info/InfoExpression.cpp
- index db461dd..7c54064 100644
- --- a/xbmc/interfaces/info/InfoExpression.cpp
- +++ b/xbmc/interfaces/info/InfoExpression.cpp
- @@ -44,7 +44,10 @@ InfoExpression::InfoExpression(const std::string &expression, int context)
- : InfoBool(expression, context)
- {
- if (!Parse(expression))
- + {
- CLog::Log(LOGERROR, "Error parsing boolean expression %s", expression.c_str());
- + m_expression_tree = boost::make_shared<InfoLeaf>(g_infoManager.Register("false", 0), false);
- + }
- }
-
- void InfoExpression::Update(const CGUIListItem *item)
- --
- 1.9.3
- From 7f2870606f1e183d70b1dc2dbc07fa8bc437d0cc Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Tue, 26 Nov 2013 20:09:48 +0000
- Subject: [PATCH 16/94] Add caching of infolabels
- The functions CGUIInfoLabel::GetLabel and CGUIInfoLabel::GetItemLabel take
- a number of strings returned from CGUIInfoManager::GetImage or
- CGUIInfoManager::GetLabel, and combine them with various constant strings
- which were determined during CGUIInfoLabel::Parse.
- Rather than perform all the string operations on every call, this patch
- changes to use a two-pass process: first it queries all the GetImage/GetLabel
- strings, and then only if at least one of them has changed does it bother
- rebuilding the resultant string - otherwise it re-uses the copy built on a
- preceding call.
- CGUIInfoLabel::GetLabel/GetItemLabel are also changed to return string
- references, rather than forcing an additional string copy.
- I have measured the effect while the Videos window of the default skin was
- open (but idle) on a Raspberry Pi, and this reduced the CPU usage by 0.8%
- from 36.2% to 35.4%:
- Before After
- Mean StdDev Mean StdDev Confidence Change
- IdleCPU% 36.2 0.5 35.4 0.5 99.9% +2.2%
- ---
- xbmc/guilib/GUIInfoTypes.cpp | 102 +++++++++++++++++++++++++++++++++----------
- xbmc/guilib/GUIInfoTypes.h | 11 ++++-
- 2 files changed, 87 insertions(+), 26 deletions(-)
- diff --git a/xbmc/guilib/GUIInfoTypes.cpp b/xbmc/guilib/GUIInfoTypes.cpp
- index 6977e0f..d78c26a 100644
- --- a/xbmc/guilib/GUIInfoTypes.cpp
- +++ b/xbmc/guilib/GUIInfoTypes.cpp
- @@ -136,37 +136,64 @@ void CGUIInfoLabel::SetLabel(const CStdString &label, const CStdString &fallback
- Parse(label, context);
- }
-
- -CStdString CGUIInfoLabel::GetLabel(int contextWindow, bool preferImage, CStdString *fallback /*= NULL*/) const
- +const std::string &CGUIInfoLabel::GetLabel(int contextWindow, bool preferImage, CStdString *fallback /*= NULL*/) const
- {
- - CStdString label;
- - for (unsigned int i = 0; i < m_info.size(); i++)
- + for (unsigned int i = 0, j = 0; i < m_info.size(); i++)
- {
- const CInfoPortion &portion = m_info[i];
- if (portion.m_info)
- {
- - CStdString infoLabel;
- + std::string infoLabel;
- if (preferImage)
- infoLabel = g_infoManager.GetImage(portion.m_info, contextWindow, fallback);
- if (infoLabel.empty())
- infoLabel = g_infoManager.GetLabel(portion.m_info, contextWindow, fallback);
- - if (!infoLabel.empty())
- - label += portion.GetLabel(infoLabel);
- + if (j == m_labelPortions.size())
- + m_labelPortions.push_back(infoLabel);
- + else if (infoLabel != m_labelPortions[j])
- + {
- + m_labelPortions[j] = infoLabel;
- + m_labelDirty = true;
- + }
- + j++;
- }
- - else
- - { // no info, so just append the prefix
- - label += portion.m_prefix;
- + }
- + if (m_labelDirty)
- + {
- + m_label.clear();
- + for (unsigned int i = 0, j= 0; i < m_info.size(); i++)
- + {
- + const CInfoPortion &portion = m_info[i];
- + if (portion.m_info)
- + {
- + if (!m_labelPortions[j].empty())
- + m_label += portion.GetLabel(m_labelPortions[j]);
- + j++;
- + }
- + else
- + { // no info, so just append the prefix
- + m_label += portion.m_prefix;
- + }
- }
- + if (m_label.empty()) // empty label, use the fallback
- + m_label = m_fallback;
- + m_labelDirty = false;
- }
- - if (label.empty()) // empty label, use the fallback
- - return m_fallback;
- - return label;
- + return m_label;
- }
-
- -CStdString CGUIInfoLabel::GetItemLabel(const CGUIListItem *item, bool preferImages, CStdString *fallback /*= NULL*/) const
- +const std::string &CGUIInfoLabel::GetItemLabel(const CGUIListItem *item, bool preferImages, CStdString *fallback /*= NULL*/) const
- {
- - if (!item->IsFileItem()) return "";
- - CStdString label;
- - for (unsigned int i = 0; i < m_info.size(); i++)
- + if (!item->IsFileItem())
- + {
- + if (m_itemLabelDirty)
- + {
- + m_itemLabel = "";
- + m_itemLabelDirty = false;
- + }
- + return m_itemLabel;
- + }
- + for (unsigned int i = 0, j = 0; i < m_info.size(); i++)
- {
- const CInfoPortion &portion = m_info[i];
- if (portion.m_info)
- @@ -176,17 +203,38 @@ CStdString CGUIInfoLabel::GetItemLabel(const CGUIListItem *item, bool preferImag
- infoLabel = g_infoManager.GetItemImage((const CFileItem *)item, portion.m_info, fallback);
- else
- infoLabel = g_infoManager.GetItemLabel((const CFileItem *)item, portion.m_info, fallback);
- - if (!infoLabel.empty())
- - label += portion.GetLabel(infoLabel);
- + if (j == m_itemLabelPortions.size())
- + m_itemLabelPortions.push_back(infoLabel);
- + else if (infoLabel != m_itemLabelPortions[j])
- + {
- + m_itemLabelPortions[j] = infoLabel;
- + m_itemLabelDirty = true;
- + }
- + j++;
- }
- - else
- - { // no info, so just append the prefix
- - label += portion.m_prefix;
- + }
- + if (m_itemLabelDirty)
- + {
- + m_itemLabel.clear();
- + for (unsigned int i = 0, j = 0; i < m_info.size(); i++)
- + {
- + const CInfoPortion &portion = m_info[i];
- + if (portion.m_info)
- + {
- + if (!m_itemLabelPortions[j].empty())
- + m_itemLabel += portion.GetLabel(m_itemLabelPortions[j]);
- + j++;
- + }
- + else
- + { // no info, so just append the prefix
- + m_itemLabel += portion.m_prefix;
- + }
- }
- + if (m_itemLabel.empty())
- + m_itemLabel = m_fallback;
- + m_itemLabelDirty = false;
- }
- - if (label.empty())
- - return m_fallback;
- - return label;
- + return m_itemLabel;
- }
-
- bool CGUIInfoLabel::IsEmpty() const
- @@ -277,6 +325,12 @@ const static infoformat infoformatmap[] = {{ "$INFO[", FORMATINFO },
- void CGUIInfoLabel::Parse(const CStdString &label, int context)
- {
- m_info.clear();
- + m_labelDirty = true;
- + m_label.clear();
- + m_labelPortions.clear();
- + m_itemLabelDirty = true;
- + m_itemLabel.clear();
- + m_itemLabelPortions.clear();
- // Step 1: Replace all $LOCALIZE[number] with the real string
- CStdString work = ReplaceLocalize(label);
- // Step 2: Replace all $ADDON[id number] with the real string
- diff --git a/xbmc/guilib/GUIInfoTypes.h b/xbmc/guilib/GUIInfoTypes.h
- index 8c1c1dc..418b2c4 100644
- --- a/xbmc/guilib/GUIInfoTypes.h
- +++ b/xbmc/guilib/GUIInfoTypes.h
- @@ -83,7 +83,7 @@ class CGUIInfoLabel
- \param fallback if non-NULL, is set to an alternate value to use should the actual value be not appropriate. Defaults to NULL.
- \return label (or image).
- */
- - CStdString GetLabel(int contextWindow, bool preferImage = false, CStdString *fallback = NULL) const;
- + const std::string &GetLabel(int contextWindow, bool preferImage = false, CStdString *fallback = NULL) const;
-
- /*!
- \brief Gets a label (or image) for a given listitem from the info manager.
- @@ -92,7 +92,7 @@ class CGUIInfoLabel
- \param fallback if non-NULL, is set to an alternate value to use should the actual value be not appropriate. Defaults to NULL.
- \return label (or image).
- */
- - CStdString GetItemLabel(const CGUIListItem *item, bool preferImage = false, CStdString *fallback = NULL) const;
- + const std::string &GetItemLabel(const CGUIListItem *item, bool preferImage = false, CStdString *fallback = NULL) const;
-
- bool IsConstant() const;
- bool IsEmpty() const;
- @@ -132,6 +132,13 @@ class CGUIInfoLabel
-
- CStdString m_fallback;
- std::vector<CInfoPortion> m_info;
- +
- + mutable bool m_labelDirty;
- + mutable std::string m_label;
- + mutable std::vector<std::string> m_labelPortions;
- + mutable bool m_itemLabelDirty;
- + mutable std::string m_itemLabel;
- + mutable std::vector<std::string> m_itemLabelPortions;
- };
-
- #endif
- --
- 1.9.3
- From 3d5a1912ffd4556ec09208fea50d2a2919775c9f Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Tue, 10 Dec 2013 01:12:31 +0000
- Subject: [PATCH 17/94] De-duplication of string cache for non-item and item
- labels
- ---
- xbmc/guilib/GUIInfoTypes.cpp | 50 +++++++++++++++++++++++++-------------------
- xbmc/guilib/GUIInfoTypes.h | 4 +---
- 2 files changed, 29 insertions(+), 25 deletions(-)
- diff --git a/xbmc/guilib/GUIInfoTypes.cpp b/xbmc/guilib/GUIInfoTypes.cpp
- index d78c26a..8bd131f 100644
- --- a/xbmc/guilib/GUIInfoTypes.cpp
- +++ b/xbmc/guilib/GUIInfoTypes.cpp
- @@ -121,7 +121,7 @@ void CGUIInfoColor::Parse(const CStdString &label, int context)
- m_color = g_colorManager.GetColor(label);
- }
-
- -CGUIInfoLabel::CGUIInfoLabel()
- +CGUIInfoLabel::CGUIInfoLabel() : m_labelDirty(true)
- {
- }
-
- @@ -178,7 +178,10 @@ const std::string &CGUIInfoLabel::GetLabel(int contextWindow, bool preferImage,
- if (m_label.empty()) // empty label, use the fallback
- m_label = m_fallback;
- m_labelDirty = false;
- + m_isLabelOfListItem = false;
- }
- + else
- + assert(m_isLabelOfListItem == false);
- return m_label;
- }
-
- @@ -186,12 +189,15 @@ const std::string &CGUIInfoLabel::GetItemLabel(const CGUIListItem *item, bool pr
- {
- if (!item->IsFileItem())
- {
- - if (m_itemLabelDirty)
- + if (m_labelDirty)
- {
- - m_itemLabel = "";
- - m_itemLabelDirty = false;
- + m_label = "";
- + m_labelDirty = false;
- + m_isLabelOfListItem = true;
- }
- - return m_itemLabel;
- + else
- + assert(m_isLabelOfListItem == true);
- + return m_label;
- }
- for (unsigned int i = 0, j = 0; i < m_info.size(); i++)
- {
- @@ -203,38 +209,41 @@ const std::string &CGUIInfoLabel::GetItemLabel(const CGUIListItem *item, bool pr
- infoLabel = g_infoManager.GetItemImage((const CFileItem *)item, portion.m_info, fallback);
- else
- infoLabel = g_infoManager.GetItemLabel((const CFileItem *)item, portion.m_info, fallback);
- - if (j == m_itemLabelPortions.size())
- - m_itemLabelPortions.push_back(infoLabel);
- - else if (infoLabel != m_itemLabelPortions[j])
- + if (j == m_labelPortions.size())
- + m_labelPortions.push_back(infoLabel);
- + else if (infoLabel != m_labelPortions[j])
- {
- - m_itemLabelPortions[j] = infoLabel;
- - m_itemLabelDirty = true;
- + m_labelPortions[j] = infoLabel;
- + m_labelDirty = true;
- }
- j++;
- }
- }
- - if (m_itemLabelDirty)
- + if (m_labelDirty)
- {
- - m_itemLabel.clear();
- + m_label.clear();
- for (unsigned int i = 0, j = 0; i < m_info.size(); i++)
- {
- const CInfoPortion &portion = m_info[i];
- if (portion.m_info)
- {
- - if (!m_itemLabelPortions[j].empty())
- - m_itemLabel += portion.GetLabel(m_itemLabelPortions[j]);
- + if (!m_labelPortions[j].empty())
- + m_label += portion.GetLabel(m_labelPortions[j]);
- j++;
- }
- else
- { // no info, so just append the prefix
- - m_itemLabel += portion.m_prefix;
- + m_label += portion.m_prefix;
- }
- }
- - if (m_itemLabel.empty())
- - m_itemLabel = m_fallback;
- - m_itemLabelDirty = false;
- + if (m_label.empty())
- + m_label = m_fallback;
- + m_labelDirty = false;
- + m_isLabelOfListItem = true;
- }
- - return m_itemLabel;
- + else
- + assert(m_isLabelOfListItem == true);
- + return m_label;
- }
-
- bool CGUIInfoLabel::IsEmpty() const
- @@ -328,9 +337,6 @@ void CGUIInfoLabel::Parse(const CStdString &label, int context)
- m_labelDirty = true;
- m_label.clear();
- m_labelPortions.clear();
- - m_itemLabelDirty = true;
- - m_itemLabel.clear();
- - m_itemLabelPortions.clear();
- // Step 1: Replace all $LOCALIZE[number] with the real string
- CStdString work = ReplaceLocalize(label);
- // Step 2: Replace all $ADDON[id number] with the real string
- diff --git a/xbmc/guilib/GUIInfoTypes.h b/xbmc/guilib/GUIInfoTypes.h
- index 418b2c4..6d9ebf7 100644
- --- a/xbmc/guilib/GUIInfoTypes.h
- +++ b/xbmc/guilib/GUIInfoTypes.h
- @@ -133,12 +133,10 @@ class CGUIInfoLabel
- CStdString m_fallback;
- std::vector<CInfoPortion> m_info;
-
- + mutable bool m_isLabelOfListItem;
- mutable bool m_labelDirty;
- mutable std::string m_label;
- mutable std::vector<std::string> m_labelPortions;
- - mutable bool m_itemLabelDirty;
- - mutable std::string m_itemLabel;
- - mutable std::vector<std::string> m_itemLabelPortions;
- };
-
- #endif
- --
- 1.9.3
- From 1427baf4395b760227afbef8e17956ba251f2fbe Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Fri, 21 Feb 2014 15:16:13 +0000
- Subject: [PATCH 18/94] Faster and simpler portable implementation of
- MathUtils::round_int().
- Much as I like a bit of inline assembler, I have also removed the ARM versions
- of MathUtils::truncate_int() and MathUtils::round_int(). The former was just
- how any sane compiler should have assembled a cast from double to signed int
- anyway. The latter was a much too complicated way to achieve the desired
- effect, and was switched out in most ARM builds anyway in favour of the old
- portable implementation that used floor().
- Verified that MathUtils::test() still passes, and that GCC is now able to
- inline MathUtils::round_int(), where it didn't previously.
- I tested on a Raspberry Pi with the default theme, displaying the front page
- with the RSS ticker enabled. This saturates the CPU, so I'm measuring the
- improvement using the debug window's FPS figure. This patch improves this from
- ~50.8 FPS to ~52.6 FPS.
- ---
- xbmc/utils/MathUtils.h | 129 +++++++++++++++++++++++--------------------------
- 1 file changed, 61 insertions(+), 68 deletions(-)
- diff --git a/xbmc/utils/MathUtils.h b/xbmc/utils/MathUtils.h
- index 96af9f4..0dae77d 100644
- --- a/xbmc/utils/MathUtils.h
- +++ b/xbmc/utils/MathUtils.h
- @@ -34,17 +34,13 @@
-
- #if defined(__ppc__) || \
- defined(__powerpc__) || \
- - (defined(TARGET_DARWIN_IOS) && defined(__llvm__)) || \
- - (defined(TARGET_ANDROID) && defined(__arm__)) || \
- - defined(TARGET_RASPBERRY_PI)
- + defined(__arm__)
- #define DISABLE_MATHUTILS_ASM_ROUND_INT
- #endif
-
- #if defined(__ppc__) || \
- defined(__powerpc__) || \
- - (defined(TARGET_DARWIN) && defined(__llvm__)) || \
- - (defined(TARGET_ANDROID) && defined(__arm__)) || \
- - defined(TARGET_RASPBERRY_PI)
- + defined(__arm__)
- #define DISABLE_MATHUTILS_ASM_TRUNCATE_INT
- #endif
-
- @@ -73,60 +69,63 @@ namespace MathUtils
- {
- assert(x > static_cast<double>(INT_MIN / 2) - 1.0);
- assert(x < static_cast<double>(INT_MAX / 2) + 1.0);
- - const float round_to_nearest = 0.5f;
- - int i;
-
- #if defined(DISABLE_MATHUTILS_ASM_ROUND_INT)
- - i = floor(x + round_to_nearest);
- -
- -#elif defined(__arm__)
- - // From 'ARM-v7-M Architecture Reference Manual' page A7-569:
- - // "The floating-point to integer operation (vcvt) [normally] uses the Round towards Zero rounding mode"
- - // Because of this...we must use some less-than-straightforward logic to perform this operation without
- - // changing the rounding mode flags
- -
- - /* The assembly below implements the following logic:
- - if (x < 0)
- - inc = -0.5f
- - else
- - inc = 0.5f
- - int_val = trunc(x+inc);
- - err = x - int_val;
- - if (err == 0.5f)
- - int_val++;
- - return int_val;
- - */
- + /* This implementation warrants some further explanation.
- + *
- + * First, a couple of notes on rounding:
- + * 1) C casts from float/double to integer round towards zero.
- + * 2) Float/double additions are rounded according to the normal rules,
- + * in other words: on some architectures, it's fixed at compile-time,
- + * and on others it can be set using fesetround()). The following
- + * analysis assumes round-to-nearest with ties rounding to even. This
- + * is a fairly sensible choice, and is the default with ARM VFP.
- + *
- + * What this function wants is round-to-nearest with ties rounding to
- + * +infinity. This isn't an IEEE rounding mode, even if we could guarantee
- + * that all architectures supported fesetround(), which they don't. Instead,
- + * this adds an offset of 2147483648.5 (= 0x80000000.8p0), then casts to
- + * an unsigned int (crucially, all possible inputs are now in a range where
- + * round to zero acts the same as round to -infinity) and then subtracts
- + * 0x80000000 in the integer domain. The 0.5 component of the offset
- + * converts what is effectively a round down into a round to nearest, with
- + * ties rounding up, as desired.
- + *
- + * There is a catch, that because there is a double rounding, there is a
- + * small region where the input falls just *below* a tie, where the addition
- + * of the offset causes a round *up* to an exact integer, due to the finite
- + * level of precision available in floating point. You need to be aware of
- + * this when calling this function, although at present it is not believed
- + * that XBMC ever attempts to round numbers in this window.
- + *
- + * It is worth proving the size of the affected window. Recall that double
- + * precision employs a mantissa of 52 bits.
- + * 1) For all inputs -0.5 <= x <= INT_MAX
- + * Once the offset is applied, the most significant binary digit in the
- + * floating-point representation is +2^31.
- + * At this magnitude, the smallest step representable in double precision
- + * is 2^31 / 2^52 = 0.000000476837158203125
- + * So the size of the range which is rounded up due to the addition is
- + * half the size of this step, or 0.0000002384185791015625
- + *
- + * 2) For all inputs INT_MIN/2 < x < -0.5
- + * Once the offset is applied, the most significant binary digit in the
- + * floating-point representation is +2^30.
- + * At this magnitude, the smallest step representable in double precision
- + * is 2^30 / 2^52 = 0.0000002384185791015625
- + * So the size of the range which is rounded up due to the addition is
- + * half the size of this step, or 0.00000011920928955078125
- + *
- + * 3) For all inputs INT_MIN <= x <= INT_MIN/2
- + * The representation once the offset is applied has equal or greater
- + * precision than the input, so the addition does not cause rounding.
- + */
- + return ((unsigned int) (x + 0x80000000.8p0)) - 0x80000000;
-
- - __asm__ __volatile__ (
- -#if defined(__ARM_PCS_VFP)
- - "fconstd d1,#%G[rnd_val] \n\t" // Copy round_to_nearest into a working register (d1 = 0.5)
- #else
- - "vmov.F64 d1,%[rnd_val] \n\t"
- -#endif
- - "fcmpezd %P[value] \n\t" // Check value against zero (value == 0?)
- - "fmstat \n\t" // Copy the floating-point status flags into the general-purpose status flags
- - "it mi \n\t"
- - "vnegmi.F64 d1, d1 \n\t" // if N-flag is set, negate round_to_nearest (if (value < 0) d1 = -1 * d1)
- - "vadd.F64 d1,%P[value],d1 \n\t" // Add round_to_nearest to value, store result in working register (d1 += value)
- - "vcvt.S32.F64 s3,d1 \n\t" // Truncate(round towards zero) (s3 = (int)d1)
- - "vmov %[result],s3 \n\t" // Store the integer result in a general-purpose register (result = s3)
- - "vcvt.F64.S32 d1,s3 \n\t" // Convert back to floating-point (d1 = (double)s3)
- - "vsub.F64 d1,%P[value],d1 \n\t" // Calculate the error (d1 = value - d1)
- -#if defined(__ARM_PCS_VFP)
- - "fconstd d2,#%G[rnd_val] \n\t" // d2 = 0.5;
- -#else
- - "vmov.F64 d2,%[rnd_val] \n\t"
- -#endif
- - "fcmped d1, d2 \n\t" // (d1 == 0.5?)
- - "fmstat \n\t" // Copy the floating-point status flags into the general-purpose status flags
- - "it eq \n\t"
- - "addeq %[result],#1 \n\t" // (if (d1 == d2) result++;)
- - : [result] "=r"(i) // Outputs
- - : [rnd_val] "Dv" (round_to_nearest), [value] "w"(x) // Inputs
- - : "d1", "d2", "s3" // Clobbers
- - );
- -
- -#elif defined(__SSE2__)
- + const float round_to_nearest = 0.5f;
- + int i;
- +#if defined(__SSE2__)
- const float round_dn_to_nearest = 0.4999999f;
- i = (x > 0) ? _mm_cvttsd_si32(_mm_set_sd(x + round_to_nearest)) : _mm_cvttsd_si32(_mm_set_sd(x - round_dn_to_nearest));
-
- @@ -150,8 +149,8 @@ namespace MathUtils
- );
-
- #endif
- -
- return i;
- +#endif
- }
-
- /*! \brief Truncate to nearest integer.
- @@ -165,20 +164,13 @@ namespace MathUtils
- {
- assert(x > static_cast<double>(INT_MIN / 2) - 1.0);
- assert(x < static_cast<double>(INT_MAX / 2) + 1.0);
- - int i;
-
- #if defined(DISABLE_MATHUTILS_ASM_TRUNCATE_INT)
- - return i = (int)x;
- -
- -#elif defined(__arm__)
- - __asm__ __volatile__ (
- - "vcvt.S32.F64 %[result],%P[value] \n\t" // Truncate(round towards zero) and store the result
- - : [result] "=w"(i) // Outputs
- - : [value] "w"(x) // Inputs
- - );
- - return i;
- + return x;
-
- -#elif defined(TARGET_WINDOWS)
- +#else
- + int i;
- +#if defined(TARGET_WINDOWS)
- const float round_towards_m_i = -0.5f;
- __asm
- {
- @@ -204,6 +196,7 @@ namespace MathUtils
- if (x < 0)
- i = -i;
- return (i);
- +#endif
- }
-
- inline int64_t abs(int64_t a)
- --
- 1.9.3
- From 0ad4df440ea225cc951a65bf9553b1f00f416d85 Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Wed, 11 Dec 2013 17:21:54 +0000
- Subject: [PATCH 19/94] Move the reference-counting of Begin and End calls from
- DX and GL source files into GUIFontTTF.cpp.
- ---
- xbmc/guilib/GUIFontTTF.cpp | 21 ++++++++
- xbmc/guilib/GUIFontTTF.h | 6 ++-
- xbmc/guilib/GUIFontTTFDX.cpp | 79 +++++++++++++----------------
- xbmc/guilib/GUIFontTTFDX.h | 4 +-
- xbmc/guilib/GUIFontTTFGL.cpp | 118 +++++++++++++++++++------------------------
- xbmc/guilib/GUIFontTTFGL.h | 4 +-
- 6 files changed, 117 insertions(+), 115 deletions(-)
- diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
- index 9c8e516..90b9c4a 100644
- --- a/xbmc/guilib/GUIFontTTF.cpp
- +++ b/xbmc/guilib/GUIFontTTF.cpp
- @@ -309,6 +309,27 @@ bool CGUIFontTTFBase::Load(const CStdString& strFilename, float height, float as
- return true;
- }
-
- +void CGUIFontTTFBase::Begin()
- +{
- + if (m_nestedBeginCount == 0 && m_texture != NULL && FirstBegin())
- + {
- + m_vertex_count = 0;
- + }
- + // Keep track of the nested begin/end calls.
- + m_nestedBeginCount++;
- +}
- +
- +void CGUIFontTTFBase::End()
- +{
- + if (m_nestedBeginCount == 0)
- + return;
- +
- + if (--m_nestedBeginCount > 0)
- + return;
- +
- + LastEnd();
- +}
- +
- void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors, const vecText &text, uint32_t alignment, float maxPixelWidth, bool scrolling)
- {
- Begin();
- diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
- index 9723a43..c1c4507 100644
- --- a/xbmc/guilib/GUIFontTTF.h
- +++ b/xbmc/guilib/GUIFontTTF.h
- @@ -77,8 +77,8 @@ class CGUIFontTTFBase
-
- bool Load(const CStdString& strFilename, float height = 20.0f, float aspect = 1.0f, float lineSpacing = 1.0f, bool border = false);
-
- - virtual void Begin() = 0;
- - virtual void End() = 0;
- + void Begin();
- + void End();
-
- const CStdString& GetFileName() const { return m_strFileName; };
-
- @@ -169,6 +169,8 @@ class CGUIFontTTFBase
- CStdString m_strFileName;
-
- private:
- + virtual bool FirstBegin() = 0;
- + virtual void LastEnd() = 0;
- CGUIFontTTFBase(const CGUIFontTTFBase&);
- CGUIFontTTFBase& operator=(const CGUIFontTTFBase&);
- int m_referenceCount;
- diff --git a/xbmc/guilib/GUIFontTTFDX.cpp b/xbmc/guilib/GUIFontTTFDX.cpp
- index e3eba24..2f90668 100644
- --- a/xbmc/guilib/GUIFontTTFDX.cpp
- +++ b/xbmc/guilib/GUIFontTTFDX.cpp
- @@ -51,65 +51,56 @@ CGUIFontTTFDX::~CGUIFontTTFDX(void)
- free(m_index);
- }
-
- -void CGUIFontTTFDX::Begin()
- +bool CGUIFontTTFDX::FirstBegin()
- {
- LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
-
- if (pD3DDevice == NULL)
- + {
- CLog::Log(LOGERROR, __FUNCTION__" - failed to get Direct3D device");
- + return false;
- + }
-
- - if (m_nestedBeginCount == 0 && pD3DDevice != NULL && m_texture != NULL)
- + int unit = 0;
- + // just have to blit from our texture.
- + m_texture->BindToUnit(unit);
- + pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP, D3DTOP_SELECTARG1 ); // only use diffuse
- + pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
- + pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
- + pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
- + pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
- + unit++;
- +
- + if(g_Windowing.UseLimitedColor())
- {
- - int unit = 0;
- - // just have to blit from our texture.
- - m_texture->BindToUnit(unit);
- - pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP, D3DTOP_SELECTARG1 ); // only use diffuse
- - pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
- - pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
- - pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
- - pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
- + pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP , D3DTOP_ADD );
- + pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG1, D3DTA_CURRENT) ;
- + pD3DDevice->SetRenderState( D3DRS_TEXTUREFACTOR, D3DCOLOR_RGBA(16,16,16,0) );
- + pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG2, D3DTA_TFACTOR );
- unit++;
- -
- - if(g_Windowing.UseLimitedColor())
- - {
- - pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP , D3DTOP_ADD );
- - pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG1, D3DTA_CURRENT) ;
- - pD3DDevice->SetRenderState( D3DRS_TEXTUREFACTOR, D3DCOLOR_RGBA(16,16,16,0) );
- - pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG2, D3DTA_TFACTOR );
- - unit++;
- - }
- -
- - // no other texture stages needed
- - pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP, D3DTOP_DISABLE);
- - pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
- -
- - pD3DDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
- - pD3DDevice->SetRenderState( D3DRS_FOGENABLE, FALSE );
- - pD3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
- - pD3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
- - pD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
- - pD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
- - pD3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
- - pD3DDevice->SetRenderState( D3DRS_LIGHTING, FALSE);
- -
- - pD3DDevice->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
- - m_vertex_count = 0;
- }
-
- - // Keep track of the nested begin/end calls.
- - m_nestedBeginCount++;
- + // no other texture stages needed
- + pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP, D3DTOP_DISABLE);
- + pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
- +
- + pD3DDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
- + pD3DDevice->SetRenderState( D3DRS_FOGENABLE, FALSE );
- + pD3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
- + pD3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
- + pD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
- + pD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
- + pD3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
- + pD3DDevice->SetRenderState( D3DRS_LIGHTING, FALSE);
- +
- + pD3DDevice->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
- + return true;
- }
-
- -void CGUIFontTTFDX::End()
- +void CGUIFontTTFDX::LastEnd()
- {
- LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
-
- - if (m_nestedBeginCount == 0)
- - return;
- -
- - if (--m_nestedBeginCount > 0)
- - return;
- -
- if (m_vertex_count == 0)
- return;
-
- diff --git a/xbmc/guilib/GUIFontTTFDX.h b/xbmc/guilib/GUIFontTTFDX.h
- index 0431085..17dfefe 100644
- --- a/xbmc/guilib/GUIFontTTFDX.h
- +++ b/xbmc/guilib/GUIFontTTFDX.h
- @@ -41,8 +41,8 @@ class CGUIFontTTFDX : public CGUIFontTTFBase
- CGUIFontTTFDX(const CStdString& strFileName);
- virtual ~CGUIFontTTFDX(void);
-
- - virtual void Begin();
- - virtual void End();
- + virtual bool FirstBegin();
- + virtual void LastEnd();
-
- protected:
- virtual CBaseTexture* ReallocTexture(unsigned int& newHeight);
- diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
- index 3358a5a..93b7ea6 100644
- --- a/xbmc/guilib/GUIFontTTFGL.cpp
- +++ b/xbmc/guilib/GUIFontTTFGL.cpp
- @@ -50,90 +50,78 @@ CGUIFontTTFGL::~CGUIFontTTFGL(void)
- {
- }
-
- -void CGUIFontTTFGL::Begin()
- +bool CGUIFontTTFGL::FirstBegin()
- {
- - if (m_nestedBeginCount == 0 && m_texture != NULL)
- + if (!m_bTextureLoaded)
- {
- - if (!m_bTextureLoaded)
- - {
- - // Have OpenGL generate a texture object handle for us
- - glGenTextures(1, (GLuint*) &m_nTexture);
- + // Have OpenGL generate a texture object handle for us
- + glGenTextures(1, (GLuint*) &m_nTexture);
-
- - // Bind the texture object
- - glBindTexture(GL_TEXTURE_2D, m_nTexture);
- + // Bind the texture object
- + glBindTexture(GL_TEXTURE_2D, m_nTexture);
- #ifdef HAS_GL
- - glEnable(GL_TEXTURE_2D);
- + glEnable(GL_TEXTURE_2D);
- #endif
- - // Set the texture's stretching properties
- - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- + // Set the texture's stretching properties
- + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
- - // Set the texture image -- THIS WORKS, so the pixels must be wrong.
- - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_texture->GetWidth(), m_texture->GetHeight(), 0,
- - GL_ALPHA, GL_UNSIGNED_BYTE, m_texture->GetPixels());
- + // Set the texture image -- THIS WORKS, so the pixels must be wrong.
- + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_texture->GetWidth(), m_texture->GetHeight(), 0,
- + GL_ALPHA, GL_UNSIGNED_BYTE, m_texture->GetPixels());
-
- - VerifyGLState();
- - m_bTextureLoaded = true;
- - }
- + VerifyGLState();
- + m_bTextureLoaded = true;
- + }
-
- - // Turn Blending On
- - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE);
- - glEnable(GL_BLEND);
- + // Turn Blending On
- + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE);
- + glEnable(GL_BLEND);
- #ifdef HAS_GL
- - glEnable(GL_TEXTURE_2D);
- + glEnable(GL_TEXTURE_2D);
- #endif
- - glBindTexture(GL_TEXTURE_2D, m_nTexture);
- + glBindTexture(GL_TEXTURE_2D, m_nTexture);
-
- #ifdef HAS_GL
- - glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);
- - glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_REPLACE);
- - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
- - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
- - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
- - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE0);
- - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
- - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
- - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
- - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- - VerifyGLState();
- + glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);
- + glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_REPLACE);
- + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
- + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
- + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
- + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE0);
- + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
- + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
- + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
- + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- + VerifyGLState();
- +
- + if(g_Windowing.UseLimitedColor())
- + {
- + glActiveTexture(GL_TEXTURE1);
- + glBindTexture(GL_TEXTURE_2D, m_nTexture); // dummy bind
- + glEnable(GL_TEXTURE_2D);
-
- - if(g_Windowing.UseLimitedColor())
- - {
- - glActiveTexture(GL_TEXTURE1);
- - glBindTexture(GL_TEXTURE_2D, m_nTexture); // dummy bind
- - glEnable(GL_TEXTURE_2D);
- -
- - const GLfloat rgba[4] = {16.0f / 255.0f, 16.0f / 255.0f, 16.0f / 255.0f, 0.0f};
- - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE , GL_COMBINE);
- - glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, rgba);
- - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB , GL_ADD);
- - glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB , GL_PREVIOUS);
- - glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB , GL_CONSTANT);
- - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB , GL_SRC_COLOR);
- - glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB , GL_SRC_COLOR);
- - glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA , GL_REPLACE);
- - glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA , GL_PREVIOUS);
- - VerifyGLState();
- - }
- + const GLfloat rgba[4] = {16.0f / 255.0f, 16.0f / 255.0f, 16.0f / 255.0f, 0.0f};
- + glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE , GL_COMBINE);
- + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, rgba);
- + glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB , GL_ADD);
- + glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB , GL_PREVIOUS);
- + glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB , GL_CONSTANT);
- + glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB , GL_SRC_COLOR);
- + glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB , GL_SRC_COLOR);
- + glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA , GL_REPLACE);
- + glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA , GL_PREVIOUS);
- + VerifyGLState();
- + }
-
- #else
- - g_Windowing.EnableGUIShader(SM_FONTS);
- + g_Windowing.EnableGUIShader(SM_FONTS);
- #endif
- -
- - m_vertex_count = 0;
- - }
- - // Keep track of the nested begin/end calls.
- - m_nestedBeginCount++;
- + return true;
- }
-
- -void CGUIFontTTFGL::End()
- +void CGUIFontTTFGL::LastEnd()
- {
- - if (m_nestedBeginCount == 0)
- - return;
- -
- - if (--m_nestedBeginCount > 0)
- - return;
- -
- #ifdef HAS_GL
- glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
-
- diff --git a/xbmc/guilib/GUIFontTTFGL.h b/xbmc/guilib/GUIFontTTFGL.h
- index a0dacba..6736cf7 100644
- --- a/xbmc/guilib/GUIFontTTFGL.h
- +++ b/xbmc/guilib/GUIFontTTFGL.h
- @@ -41,8 +41,8 @@ class CGUIFontTTFGL : public CGUIFontTTFBase
- CGUIFontTTFGL(const CStdString& strFileName);
- virtual ~CGUIFontTTFGL(void);
-
- - virtual void Begin();
- - virtual void End();
- + virtual bool FirstBegin();
- + virtual void LastEnd();
-
- protected:
- virtual CBaseTexture* ReallocTexture(unsigned int& newHeight);
- --
- 1.9.3
- From 427373ae5bb96489afb22529714c16e8f82c2195 Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Wed, 11 Dec 2013 18:47:54 +0000
- Subject: [PATCH 20/94] Convert CGUIFontTTFBase::m_vertex to be managed as a
- std::vector. Also retired CGUIFontTTFBase::m_vertex_count and
- CGUIFontTTFBase::m_vertex_size because these can be derived from vector
- member functions.
- ---
- xbmc/guilib/GUIFontTTF.cpp | 29 +++++------------------------
- xbmc/guilib/GUIFontTTF.h | 4 +---
- xbmc/guilib/GUIFontTTFDX.cpp | 12 ++++++------
- xbmc/guilib/GUIFontTTFGL.cpp | 12 ++++++------
- 4 files changed, 18 insertions(+), 39 deletions(-)
- diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
- index 90b9c4a..3f219d9 100644
- --- a/xbmc/guilib/GUIFontTTF.cpp
- +++ b/xbmc/guilib/GUIFontTTF.cpp
- @@ -139,8 +139,7 @@ CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName)
- m_nestedBeginCount = 0;
-
- m_bTextureLoaded = false;
- - m_vertex_size = 4*1024;
- - m_vertex = (SVertex*)malloc(m_vertex_size * sizeof(SVertex));
- + m_vertex.reserve(4*1024);
-
- m_face = NULL;
- m_stroker = NULL;
- @@ -155,7 +154,6 @@ CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName)
- m_textureScaleX = m_textureScaleY = 0.0;
- m_ellipsesWidth = m_height = 0.0f;
- m_color = 0;
- - m_vertex_count = 0;
- m_nTexture = 0;
- }
-
- @@ -216,9 +214,7 @@ void CGUIFontTTFBase::Clear()
- g_freeTypeLibrary.ReleaseStroker(m_stroker);
- m_stroker = NULL;
-
- - free(m_vertex);
- - m_vertex = NULL;
- - m_vertex_count = 0;
- + m_vertex.clear();
- }
-
- bool CGUIFontTTFBase::Load(const CStdString& strFilename, float height, float aspect, float lineSpacing, bool border)
- @@ -313,7 +309,7 @@ void CGUIFontTTFBase::Begin()
- {
- if (m_nestedBeginCount == 0 && m_texture != NULL && FirstBegin())
- {
- - m_vertex_count = 0;
- + m_vertex.clear();
- }
- // Keep track of the nested begin/end calls.
- m_nestedBeginCount++;
- @@ -746,22 +742,9 @@ void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *c
- float tt = texture.y1 * m_textureScaleY;
- float tb = texture.y2 * m_textureScaleY;
-
- - // grow the vertex buffer if required
- - if(m_vertex_count >= m_vertex_size)
- - {
- - m_vertex_size *= 2;
- - void* old = m_vertex;
- - m_vertex = (SVertex*)realloc(m_vertex, m_vertex_size * sizeof(SVertex));
- - if (!m_vertex)
- - {
- - free(old);
- - CLog::Log(LOGSEVERE, "%s: can't allocate %"PRIdS" bytes for texture", __FUNCTION__ , m_vertex_size * sizeof(SVertex));
- - return;
- - }
- - }
- -
- + m_vertex.resize(m_vertex.size() + 4);
- + SVertex* v = &m_vertex[m_vertex.size() - 4];
- m_color = color;
- - SVertex* v = m_vertex + m_vertex_count;
-
- unsigned char r = GET_R(color)
- , g = GET_G(color)
- @@ -828,8 +811,6 @@ void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *c
- v[3].y = y[2];
- v[3].z = z[2];
- #endif
- -
- - m_vertex_count+=4;
- }
-
- // Oblique code - original taken from freetype2 (ftsynth.c)
- diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
- index c1c4507..35e3cf9 100644
- --- a/xbmc/guilib/GUIFontTTF.h
- +++ b/xbmc/guilib/GUIFontTTF.h
- @@ -157,9 +157,7 @@ class CGUIFontTTFBase
- bool m_bTextureLoaded;
- unsigned int m_nTexture;
-
- - SVertex* m_vertex;
- - int m_vertex_count;
- - int m_vertex_size;
- + std::vector<SVertex> m_vertex;
-
- float m_textureScaleX;
- float m_textureScaleY;
- diff --git a/xbmc/guilib/GUIFontTTFDX.cpp b/xbmc/guilib/GUIFontTTFDX.cpp
- index 2f90668..6ef8984 100644
- --- a/xbmc/guilib/GUIFontTTFDX.cpp
- +++ b/xbmc/guilib/GUIFontTTFDX.cpp
- @@ -101,17 +101,17 @@ void CGUIFontTTFDX::LastEnd()
- {
- LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
-
- - if (m_vertex_count == 0)
- + if (m_vertex.size() == 0)
- return;
-
- - unsigned index_size = m_vertex_size * 6 / 4;
- + unsigned index_size = m_vertex.capacity() * 6 / 4;
- if(m_index_size < index_size)
- {
- uint16_t* id = (uint16_t*)calloc(index_size, sizeof(uint16_t));
- if(id == NULL)
- return;
-
- - for(int i = 0, b = 0; i < m_vertex_size; i += 4, b += 6)
- + for(int i = 0, b = 0; i < m_vertex.capacity(); i += 4, b += 6)
- {
- id[b+0] = i + 0;
- id[b+1] = i + 1;
- @@ -140,11 +140,11 @@ void CGUIFontTTFDX::LastEnd()
-
- pD3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST
- , 0
- - , m_vertex_count
- - , m_vertex_count / 2
- + , m_vertex.size()
- + , m_vertex.size() / 2
- , m_index
- , D3DFMT_INDEX16
- - , m_vertex
- + , &m_vertex[0]
- , sizeof(SVertex));
- pD3DDevice->SetTransform(D3DTS_WORLD, &orig);
-
- diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
- index 93b7ea6..a4e8571 100644
- --- a/xbmc/guilib/GUIFontTTFGL.cpp
- +++ b/xbmc/guilib/GUIFontTTFGL.cpp
- @@ -125,13 +125,13 @@ void CGUIFontTTFGL::LastEnd()
- #ifdef HAS_GL
- glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
-
- - glColorPointer (4, GL_UNSIGNED_BYTE, sizeof(SVertex), (char*)m_vertex + offsetof(SVertex, r));
- - glVertexPointer (3, GL_FLOAT , sizeof(SVertex), (char*)m_vertex + offsetof(SVertex, x));
- - glTexCoordPointer(2, GL_FLOAT , sizeof(SVertex), (char*)m_vertex + offsetof(SVertex, u));
- + glColorPointer (4, GL_UNSIGNED_BYTE, sizeof(SVertex), (char*)&m_vertex[0] + offsetof(SVertex, r));
- + glVertexPointer (3, GL_FLOAT , sizeof(SVertex), (char*)&m_vertex[0] + offsetof(SVertex, x));
- + glTexCoordPointer(2, GL_FLOAT , sizeof(SVertex), (char*)&m_vertex[0] + offsetof(SVertex, u));
- glEnableClientState(GL_COLOR_ARRAY);
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- - glDrawArrays(GL_QUADS, 0, m_vertex_count);
- + glDrawArrays(GL_QUADS, 0, m_vertex.size());
- glPopClientAttrib();
-
- glActiveTexture(GL_TEXTURE1);
- @@ -147,10 +147,10 @@ void CGUIFontTTFGL::LastEnd()
- GLint tex0Loc = g_Windowing.GUIShaderGetCoord0();
-
- // stack object until VBOs will be used
- - std::vector<SVertex> vecVertices( 6 * (m_vertex_count / 4) );
- + std::vector<SVertex> vecVertices( 6 * (m_vertex.size() / 4) );
- SVertex *vertices = &vecVertices[0];
-
- - for (int i=0; i<m_vertex_count; i+=4)
- + for (size_t i=0; i<m_vertex.size(); i+=4)
- {
- *vertices++ = m_vertex[i];
- *vertices++ = m_vertex[i+1];
- --
- 1.9.3
- From a3e8e7f1055726a050e04d1e4ab61a5355cdbd6a Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Mon, 16 Dec 2013 18:58:12 +0000
- Subject: [PATCH 21/94] CGUIFontTTFBase::RenderCharacter can now append to
- arbitrary vectors of vertices rather than only CGUIFontTTFBase::m_vertex
- ---
- xbmc/guilib/GUIFontTTF.cpp | 12 +++++++-----
- xbmc/guilib/GUIFontTTF.h | 2 +-
- 2 files changed, 8 insertions(+), 6 deletions(-)
- diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
- index 3f219d9..1aaf68b 100644
- --- a/xbmc/guilib/GUIFontTTF.cpp
- +++ b/xbmc/guilib/GUIFontTTF.cpp
- @@ -330,6 +330,8 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
- {
- Begin();
-
- + std::vector<SVertex> &vertices = m_vertex;
- +
- // save the origin, which is scaled separately
- m_originX = x;
- m_originY = y;
- @@ -410,7 +412,7 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
-
- for (int i = 0; i < 3; i++)
- {
- - RenderCharacter(startX + cursorX, startY, period, color, !scrolling);
- + RenderCharacter(startX + cursorX, startY, period, color, !scrolling, vertices);
- cursorX += period->advance;
- }
- break;
- @@ -419,7 +421,7 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
- else if (maxPixelWidth > 0 && cursorX > maxPixelWidth)
- break; // exceeded max allowed width - stop rendering
-
- - RenderCharacter(startX + cursorX, startY, ch, color, !scrolling);
- + RenderCharacter(startX + cursorX, startY, ch, color, !scrolling, vertices);
- if ( alignment & XBFONT_JUSTIFIED )
- {
- if ((*pos & 0xffff) == L' ')
- @@ -676,7 +678,7 @@ bool CGUIFontTTFBase::CacheCharacter(wchar_t letter, uint32_t style, Character *
- return true;
- }
-
- -void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX)
- +void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX, std::vector<SVertex> &vertices)
- {
- // actual image width isn't same as the character width as that is
- // just baseline width and height should include the descent
- @@ -742,8 +744,8 @@ void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *c
- float tt = texture.y1 * m_textureScaleY;
- float tb = texture.y2 * m_textureScaleY;
-
- - m_vertex.resize(m_vertex.size() + 4);
- - SVertex* v = &m_vertex[m_vertex.size() - 4];
- + vertices.resize(vertices.size() + 4);
- + SVertex* v = &vertices[vertices.size() - 4];
- m_color = color;
-
- unsigned char r = GET_R(color)
- diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
- index 35e3cf9..4a6a696 100644
- --- a/xbmc/guilib/GUIFontTTF.h
- +++ b/xbmc/guilib/GUIFontTTF.h
- @@ -109,7 +109,7 @@ class CGUIFontTTFBase
- // Stuff for pre-rendering for speed
- inline Character *GetCharacter(character_t letter);
- bool CacheCharacter(wchar_t letter, uint32_t style, Character *ch);
- - void RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX);
- + void RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX, std::vector<SVertex> &vertices);
- void ClearCharacterCache();
-
- virtual CBaseTexture* ReallocTexture(unsigned int& newHeight) = 0;
- --
- 1.9.3
- From 79263f02e56ef10410984c98a844aaa9bf43199e Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Wed, 15 Jan 2014 17:18:38 +0000
- Subject: [PATCH 22/94] Add a cache of font glyph bounding box vertices. This
- is implemented as a template because ultimately we will key on different
- parameters and store values of different types, depending upon whether we
- have a GLES or non-GLES backend, and for GLES, whether or not the currently
- applicable transformation matrices permit the use of hardware clipping.
- ---
- xbmc/guilib/GUIFontCache.cpp | 105 ++++++++++++++++++++
- xbmc/guilib/GUIFontCache.h | 217 ++++++++++++++++++++++++++++++++++++++++++
- xbmc/guilib/GUIFontTTF.cpp | 181 +++++++++++++++++++----------------
- xbmc/guilib/GUIFontTTF.h | 5 +
- xbmc/guilib/GUIFontTTFGL.cpp | 1 +
- xbmc/guilib/GraphicContext.h | 1 +
- xbmc/guilib/Makefile.in | 1 +
- xbmc/guilib/TransformMatrix.h | 11 +++
- 8 files changed, 438 insertions(+), 84 deletions(-)
- create mode 100644 xbmc/guilib/GUIFontCache.cpp
- create mode 100644 xbmc/guilib/GUIFontCache.h
- diff --git a/xbmc/guilib/GUIFontCache.cpp b/xbmc/guilib/GUIFontCache.cpp
- new file mode 100644
- index 0000000..c029713
- --- /dev/null
- +++ b/xbmc/guilib/GUIFontCache.cpp
- @@ -0,0 +1,105 @@
- +/*
- + * Copyright (C) 2005-2013 Team XBMC
- + * http://xbmc.org
- + *
- + * This Program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License as published by
- + * the Free Software Foundation; either version 2, or (at your option)
- + * any later version.
- + *
- + * This Program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with XBMC; see the file COPYING. If not, see
- + * <http://www.gnu.org/licenses/>.
- + *
- + */
- +
- +#include <stdint.h>
- +#include <vector>
- +#include "utils/StdString.h" // required by GUIFontTTF.h
- +#include "GUIFontTTF.h"
- +#include "GraphicContext.h"
- +
- +template<class Position, class Value>
- +void CGUIFontCacheEntry<Position, Value>::Reassign::operator()(CGUIFontCacheEntry<Position, Value> &entry)
- +{
- + entry.m_key.m_pos = m_key.m_pos;
- + entry.m_key.m_colors.assign(m_key.m_colors.begin(), m_key.m_colors.end());
- + entry.m_key.m_text.assign(m_key.m_text.begin(), m_key.m_text.end());
- + entry.m_key.m_alignment = m_key.m_alignment;
- + entry.m_key.m_maxPixelWidth = m_key.m_maxPixelWidth;
- + entry.m_key.m_scrolling = m_key.m_scrolling;
- + entry.m_matrix = m_key.m_matrix;
- + entry.m_key.m_scaleX = m_key.m_scaleX;
- + entry.m_key.m_scaleY = m_key.m_scaleY;
- +
- + entry.m_lastUsedMillis = m_nowMillis;
- + entry.m_value.clear();
- +}
- +
- +template<class Position, class Value>
- +CGUIFontCacheEntry<Position, Value>::~CGUIFontCacheEntry()
- +{
- + delete &m_key.m_colors;
- + delete &m_key.m_text;
- + m_value.clear();
- +}
- +
- +template<class Position, class Value>
- +Value &CGUIFontCache<Position, Value>::Lookup(Position &pos,
- + const vecColors &colors, const vecText &text,
- + uint32_t alignment, float maxPixelWidth,
- + bool scrolling,
- + unsigned int nowMillis, bool &dirtyCache)
- +{
- + const CGUIFontCacheKey<Position> key(pos,
- + const_cast<vecColors &>(colors), const_cast<vecText &>(text),
- + alignment, maxPixelWidth,
- + scrolling, g_graphicsContext.GetGUIMatrix(),
- + g_graphicsContext.GetGUIScaleX(), g_graphicsContext.GetGUIScaleY());
- + EntryHashIterator i = m_list.get<Hash>().find(key);
- + if (i == m_list.get<Hash>().end())
- + {
- + /* Cache miss */
- + EntryAgeIterator oldest = m_list.get<Age>().begin();
- + if (!m_list.get<Age>().empty() && nowMillis - oldest->m_lastUsedMillis > FONT_CACHE_TIME_LIMIT)
- + {
- + /* The oldest existing entry is old enough to expire and reuse */
- + m_list.get<Hash>().modify(m_list.project<Hash>(oldest), typename CGUIFontCacheEntry<Position, Value>::Reassign(key, nowMillis));
- + m_list.get<Age>().relocate(m_list.get<Age>().end(), oldest);
- + }
- + else
- + {
- + /* We need a new entry instead */
- + /* Yes, this causes the creation an destruction of a temporary entry, but
- + * this code ought to only be used infrequently, when the cache needs to grow */
- + m_list.get<Age>().push_back(CGUIFontCacheEntry<Position, Value>(*this, key, nowMillis));
- + }
- + dirtyCache = true;
- + return (--m_list.get<Age>().end())->m_value;
- + }
- + else
- + {
- + /* Cache hit */
- + /* Update time in entry and move to the back of the list */
- + i->m_lastUsedMillis = nowMillis;
- + m_list.get<Age>().relocate(m_list.get<Age>().end(), m_list.project<Age>(i));
- + dirtyCache = false;
- + return i->m_value;
- + }
- +}
- +
- +template<class Position, class Value>
- +void CGUIFontCache<Position, Value>::Flush()
- +{
- + m_list.get<Age>().clear();
- +}
- +
- +template void CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Reassign::operator()(CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue> &entry);
- +template CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::~CGUIFontCacheEntry();
- +template CGUIFontCacheStaticValue &CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Lookup(CGUIFontCacheStaticPosition &, const vecColors &, const vecText &, uint32_t, float, bool, unsigned int, bool &);
- +template void CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Flush();
- diff --git a/xbmc/guilib/GUIFontCache.h b/xbmc/guilib/GUIFontCache.h
- new file mode 100644
- index 0000000..ef65845
- --- /dev/null
- +++ b/xbmc/guilib/GUIFontCache.h
- @@ -0,0 +1,217 @@
- +/*!
- +\file GUIFontCache.h
- +\brief
- +*/
- +
- +#ifndef CGUILIB_GUIFONTCACHE_H
- +#define CGUILIB_GUIFONTCACHE_H
- +#pragma once
- +
- +/*
- + * Copyright (C) 2005-2013 Team XBMC
- + * http://xbmc.org
- + *
- + * This Program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License as published by
- + * the Free Software Foundation; either version 2, or (at your option)
- + * any later version.
- + *
- + * This Program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with XBMC; see the file COPYING. If not, see
- + * <http://www.gnu.org/licenses/>.
- + *
- + */
- +
- +#include <cstddef>
- +#include <cstring>
- +#include <stdint.h>
- +
- +#include <algorithm>
- +#include <vector>
- +
- +#include "boost/multi_index_container.hpp"
- +#include "boost/multi_index/sequenced_index.hpp"
- +#include "boost/multi_index/hashed_index.hpp"
- +#include "boost/multi_index/member.hpp"
- +
- +#include "TransformMatrix.h"
- +
- +using namespace boost::multi_index;
- +
- +#define FONT_CACHE_TIME_LIMIT (1000)
- +
- +template<class Position, class Value> class CGUIFontCache;
- +class CGUIFontTTFBase;
- +
- +template<class Position>
- +struct CGUIFontCacheKey
- +{
- + Position m_pos;
- + vecColors &m_colors;
- + vecText &m_text;
- + uint32_t m_alignment;
- + float m_maxPixelWidth;
- + bool m_scrolling;
- + const TransformMatrix &m_matrix;
- + float m_scaleX;
- + float m_scaleY;
- +
- + CGUIFontCacheKey(Position pos,
- + vecColors &colors, vecText &text,
- + uint32_t alignment, float maxPixelWidth,
- + bool scrolling, const TransformMatrix &matrix,
- + float scaleX, float scaleY) :
- + m_pos(pos),
- + m_colors(colors), m_text(text),
- + m_alignment(alignment), m_maxPixelWidth(maxPixelWidth),
- + m_scrolling(scrolling), m_matrix(matrix),
- + m_scaleX(scaleX), m_scaleY(scaleY)
- + {}
- +};
- +
- +template<class Position, class Value>
- +struct CGUIFontCacheEntry
- +{
- + const CGUIFontCache<Position, Value> &m_cache;
- + CGUIFontCacheKey<Position> m_key;
- + TransformMatrix m_matrix;
- +
- + /* These need to be declared as mutable to get round the fact that only
- + * const iterators are available. These fields do not affect comparison or
- + * hash functors, so from the container's point of view, they are mutable. */
- + mutable unsigned int m_lastUsedMillis;
- + mutable Value m_value;
- +
- + CGUIFontCacheEntry(const CGUIFontCache<Position, Value> &cache, const CGUIFontCacheKey<Position> &key, unsigned int nowMillis) :
- + m_cache(cache),
- + m_key(key.m_pos,
- + *new vecColors, *new vecText,
- + key.m_alignment, key.m_maxPixelWidth,
- + key.m_scrolling, m_matrix,
- + key.m_scaleX, key.m_scaleY),
- + m_lastUsedMillis(nowMillis)
- + {
- + m_key.m_colors.assign(key.m_colors.begin(), key.m_colors.end());
- + m_key.m_text.assign(key.m_text.begin(), key.m_text.end());
- + m_matrix = key.m_matrix;
- + }
- +
- + CGUIFontCacheEntry(const CGUIFontCacheEntry &other) :
- + m_cache(other.m_cache),
- + m_key(other.m_key.m_pos,
- + *new vecColors, *new vecText,
- + other.m_key.m_alignment, other.m_key.m_maxPixelWidth,
- + other.m_key.m_scrolling, m_matrix,
- + other.m_key.m_scaleX, other.m_key.m_scaleY),
- + m_lastUsedMillis(other.m_lastUsedMillis),
- + m_value(other.m_value)
- + {
- + m_key.m_colors.assign(other.m_key.m_colors.begin(), other.m_key.m_colors.end());
- + m_key.m_text.assign(other.m_key.m_text.begin(), other.m_key.m_text.end());
- + m_matrix = other.m_key.m_matrix;
- + }
- +
- + struct Reassign
- + {
- + Reassign(const CGUIFontCacheKey<Position> &key, unsigned int nowMillis) : m_key(key), m_nowMillis(nowMillis) {}
- + void operator()(CGUIFontCacheEntry &entry);
- + private:
- + const CGUIFontCacheKey<Position> &m_key;
- + unsigned int m_nowMillis;
- + };
- +
- + ~CGUIFontCacheEntry();
- +};
- +
- +template<class Position>
- +struct CGUIFontCacheHash
- +{
- + size_t operator()(const CGUIFontCacheKey<Position> &key) const
- + {
- + /* Not much effort has gone into choosing this hash function */
- + size_t hash = 0, i;
- + for (i = 0; i < 3 && i < key.m_text.size(); ++i)
- + hash += key.m_text[i];
- + if (key.m_colors.size())
- + hash += key.m_colors[0];
- + hash += MatrixHashContribution(key);
- + return hash;
- + }
- +};
- +
- +template<class Position>
- +struct CGUIFontCacheKeysMatch
- +{
- + bool operator()(const CGUIFontCacheKey<Position> &a, const CGUIFontCacheKey<Position> &b) const
- + {
- + return a.m_text == b.m_text &&
- + a.m_colors == b.m_colors &&
- + a.m_alignment == b.m_alignment &&
- + a.m_scrolling == b.m_scrolling &&
- + a.m_maxPixelWidth == b.m_maxPixelWidth &&
- + Match(a.m_pos, a.m_matrix, b.m_pos, b.m_matrix, a.m_scrolling) &&
- + a.m_scaleX == b.m_scaleX &&
- + a.m_scaleY == b.m_scaleY;
- + }
- +};
- +
- +template<class Position, class Value>
- +class CGUIFontCache
- +{
- + /* Empty structs used as tags to identify indexes */
- + struct Age {};
- + struct Hash {};
- +
- + typedef multi_index_container<
- + CGUIFontCacheEntry<Position, Value>,
- + indexed_by<
- + sequenced<tag<Age> >,
- + hashed_unique<tag<Hash>, member<CGUIFontCacheEntry<Position, Value>, CGUIFontCacheKey<Position>, &CGUIFontCacheEntry<Position, Value>::m_key>, CGUIFontCacheHash<Position>, CGUIFontCacheKeysMatch<Position> >
- + >
- + > EntryList;
- +
- + typedef typename EntryList::template index<Age>::type::iterator EntryAgeIterator;
- + typedef typename EntryList::template index<Hash>::type::iterator EntryHashIterator;
- +
- + EntryList m_list;
- +
- +public:
- + const CGUIFontTTFBase &m_font;
- +
- + CGUIFontCache(CGUIFontTTFBase &font) : m_font(font) {}
- + Value &Lookup(Position &pos,
- + const vecColors &colors, const vecText &text,
- + uint32_t alignment, float maxPixelWidth,
- + bool scrolling,
- + unsigned int nowMillis, bool &dirtyCache);
- + void Flush();
- +};
- +
- +struct CGUIFontCacheStaticPosition
- +{
- + float m_x;
- + float m_y;
- + CGUIFontCacheStaticPosition(float x, float y) : m_x(x), m_y(y) {}
- +};
- +
- +typedef std::vector<SVertex> CGUIFontCacheStaticValue;
- +
- +inline bool Match(const CGUIFontCacheStaticPosition &a, const TransformMatrix &a_m,
- + const CGUIFontCacheStaticPosition &b, const TransformMatrix &b_m,
- + bool scrolling)
- +{
- + return a.m_x == b.m_x && a.m_y == b.m_y && a_m == b_m;
- +}
- +
- +inline float MatrixHashContribution(const CGUIFontCacheKey<CGUIFontCacheStaticPosition> &a)
- +{
- + /* Ensure horizontally translated versions end up in different buckets */
- + return a.m_matrix.m[0][3];
- +}
- +
- +#endif
- diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
- index 1aaf68b..288e61a 100644
- --- a/xbmc/guilib/GUIFontTTF.cpp
- +++ b/xbmc/guilib/GUIFontTTF.cpp
- @@ -27,6 +27,7 @@
- #include "utils/MathUtils.h"
- #include "utils/log.h"
- #include "windowing/WindowingFactory.h"
- +#include "threads/SystemClock.h"
-
- #include <math.h>
-
- @@ -131,7 +132,7 @@ class CFreeTypeLibrary
- XBMC_GLOBAL_REF(CFreeTypeLibrary, g_freeTypeLibrary); // our freetype library
- #define g_freeTypeLibrary XBMC_GLOBAL_USE(CFreeTypeLibrary)
-
- -CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName)
- +CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) : m_staticCache(*this)
- {
- m_texture = NULL;
- m_char = NULL;
- @@ -330,108 +331,120 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
- {
- Begin();
-
- - std::vector<SVertex> &vertices = m_vertex;
- -
- - // save the origin, which is scaled separately
- - m_originX = x;
- - m_originY = y;
- -
- - // Check if we will really need to truncate or justify the text
- - if ( alignment & XBFONT_TRUNCATED )
- + bool dirtyCache;
- + CGUIFontCacheStaticPosition staticPos(x, y);
- + std::vector<SVertex> &vertices = m_staticCache.Lookup(staticPos,
- + colors, text,
- + alignment, maxPixelWidth,
- + scrolling,
- + XbmcThreads::SystemClockMillis(),
- + dirtyCache);
- + if (dirtyCache)
- {
- - if ( maxPixelWidth <= 0.0f || GetTextWidthInternal(text.begin(), text.end()) <= maxPixelWidth)
- - alignment &= ~XBFONT_TRUNCATED;
- - }
- - else if ( alignment & XBFONT_JUSTIFIED )
- - {
- - if ( maxPixelWidth <= 0.0f )
- - alignment &= ~XBFONT_JUSTIFIED;
- - }
- + // save the origin, which is scaled separately
- + m_originX = x;
- + m_originY = y;
-
- - // calculate sizing information
- - float startX = 0;
- - float startY = (alignment & XBFONT_CENTER_Y) ? -0.5f*m_cellHeight : 0; // vertical centering
- + // Check if we will really need to truncate or justify the text
- + if ( alignment & XBFONT_TRUNCATED )
- + {
- + if ( maxPixelWidth <= 0.0f || GetTextWidthInternal(text.begin(), text.end()) <= maxPixelWidth)
- + alignment &= ~XBFONT_TRUNCATED;
- + }
- + else if ( alignment & XBFONT_JUSTIFIED )
- + {
- + if ( maxPixelWidth <= 0.0f )
- + alignment &= ~XBFONT_JUSTIFIED;
- + }
-
- - if ( alignment & (XBFONT_RIGHT | XBFONT_CENTER_X) )
- - {
- - // Get the extent of this line
- - float w = GetTextWidthInternal( text.begin(), text.end() );
- + // calculate sizing information
- + float startX = 0;
- + float startY = (alignment & XBFONT_CENTER_Y) ? -0.5f*m_cellHeight : 0; // vertical centering
-
- - if ( alignment & XBFONT_TRUNCATED && w > maxPixelWidth + 0.5f ) // + 0.5f due to rounding issues
- - w = maxPixelWidth;
- + if ( alignment & (XBFONT_RIGHT | XBFONT_CENTER_X) )
- + {
- + // Get the extent of this line
- + float w = GetTextWidthInternal( text.begin(), text.end() );
-
- - if ( alignment & XBFONT_CENTER_X)
- - w *= 0.5f;
- - // Offset this line's starting position
- - startX -= w;
- - }
- + if ( alignment & XBFONT_TRUNCATED && w > maxPixelWidth + 0.5f ) // + 0.5f due to rounding issues
- + w = maxPixelWidth;
-
- - float spacePerLetter = 0; // for justification effects
- - if ( alignment & XBFONT_JUSTIFIED )
- - {
- - // first compute the size of the text to render in both characters and pixels
- - unsigned int lineChars = 0;
- - float linePixels = 0;
- - for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos)
- + if ( alignment & XBFONT_CENTER_X)
- + w *= 0.5f;
- + // Offset this line's starting position
- + startX -= w;
- + }
- +
- + float spacePerLetter = 0; // for justification effects
- + if ( alignment & XBFONT_JUSTIFIED )
- {
- - Character *ch = GetCharacter(*pos);
- - if (ch)
- - { // spaces have multiple times the justification spacing of normal letters
- - lineChars += ((*pos & 0xffff) == L' ') ? justification_word_weight : 1;
- - linePixels += ch->advance;
- + // first compute the size of the text to render in both characters and pixels
- + unsigned int lineChars = 0;
- + float linePixels = 0;
- + for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos)
- + {
- + Character *ch = GetCharacter(*pos);
- + if (ch)
- + { // spaces have multiple times the justification spacing of normal letters
- + lineChars += ((*pos & 0xffff) == L' ') ? justification_word_weight : 1;
- + linePixels += ch->advance;
- + }
- }
- + if (lineChars > 1)
- + spacePerLetter = (maxPixelWidth - linePixels) / (lineChars - 1);
- }
- - if (lineChars > 1)
- - spacePerLetter = (maxPixelWidth - linePixels) / (lineChars - 1);
- - }
- - float cursorX = 0; // current position along the line
- -
- - for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos)
- - {
- - // If starting text on a new line, determine justification effects
- - // Get the current letter in the CStdString
- - color_t color = (*pos & 0xff0000) >> 16;
- - if (color >= colors.size())
- - color = 0;
- - color = colors[color];
- + float cursorX = 0; // current position along the line
-
- - // grab the next character
- - Character *ch = GetCharacter(*pos);
- - if (!ch) continue;
- -
- - if ( alignment & XBFONT_TRUNCATED )
- + for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos)
- {
- - // Check if we will be exceeded the max allowed width
- - if ( cursorX + ch->advance + 3 * m_ellipsesWidth > maxPixelWidth )
- - {
- - // Yup. Let's draw the ellipses, then bail
- - // Perhaps we should really bail to the next line in this case??
- - Character *period = GetCharacter(L'.');
- - if (!period)
- - break;
- + // If starting text on a new line, determine justification effects
- + // Get the current letter in the CStdString
- + color_t color = (*pos & 0xff0000) >> 16;
- + if (color >= colors.size())
- + color = 0;
- + color = colors[color];
- +
- + // grab the next character
- + Character *ch = GetCharacter(*pos);
- + if (!ch) continue;
-
- - for (int i = 0; i < 3; i++)
- + if ( alignment & XBFONT_TRUNCATED )
- + {
- + // Check if we will be exceeded the max allowed width
- + if ( cursorX + ch->advance + 3 * m_ellipsesWidth > maxPixelWidth )
- {
- - RenderCharacter(startX + cursorX, startY, period, color, !scrolling, vertices);
- - cursorX += period->advance;
- + // Yup. Let's draw the ellipses, then bail
- + // Perhaps we should really bail to the next line in this case??
- + Character *period = GetCharacter(L'.');
- + if (!period)
- + break;
- +
- + for (int i = 0; i < 3; i++)
- + {
- + RenderCharacter(startX + cursorX, startY, period, color, !scrolling, vertices);
- + cursorX += period->advance;
- + }
- + break;
- }
- - break;
- }
- - }
- - else if (maxPixelWidth > 0 && cursorX > maxPixelWidth)
- - break; // exceeded max allowed width - stop rendering
- + else if (maxPixelWidth > 0 && cursorX > maxPixelWidth)
- + break; // exceeded max allowed width - stop rendering
-
- - RenderCharacter(startX + cursorX, startY, ch, color, !scrolling, vertices);
- - if ( alignment & XBFONT_JUSTIFIED )
- - {
- - if ((*pos & 0xffff) == L' ')
- - cursorX += ch->advance + spacePerLetter * justification_word_weight;
- + RenderCharacter(startX + cursorX, startY, ch, color, !scrolling, vertices);
- + if ( alignment & XBFONT_JUSTIFIED )
- + {
- + if ((*pos & 0xffff) == L' ')
- + cursorX += ch->advance + spacePerLetter * justification_word_weight;
- + else
- + cursorX += ch->advance + spacePerLetter;
- + }
- else
- - cursorX += ch->advance + spacePerLetter;
- + cursorX += ch->advance;
- }
- - else
- - cursorX += ch->advance;
- }
- + /* Append the new vertices (from the cache or otherwise) to the set collected
- + * since the first Begin() call */
- + m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end());
-
- End();
- }
- diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
- index 4a6a696..7cb4669 100644
- --- a/xbmc/guilib/GUIFontTTF.h
- +++ b/xbmc/guilib/GUIFontTTF.h
- @@ -64,6 +64,9 @@ struct SVertex
- };
-
-
- +#include "GUIFontCache.h"
- +
- +
- class CGUIFontTTFBase
- {
- friend class CGUIFont;
- @@ -166,6 +169,8 @@ class CGUIFontTTFBase
-
- CStdString m_strFileName;
-
- + CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue> m_staticCache;
- +
- private:
- virtual bool FirstBegin() = 0;
- virtual void LastEnd() = 0;
- diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
- index a4e8571..cb56987 100644
- --- a/xbmc/guilib/GUIFontTTFGL.cpp
- +++ b/xbmc/guilib/GUIFontTTFGL.cpp
- @@ -200,6 +200,7 @@ CBaseTexture* CGUIFontTTFGL::ReallocTexture(unsigned int& newHeight)
- m_textureScaleX = 1.0f / m_textureWidth;
- if (m_textureHeight < newHeight)
- CLog::Log(LOGWARNING, "%s: allocated new texture with height of %d, requested %d", __FUNCTION__, m_textureHeight, newHeight);
- + m_staticCache.Flush();
-
- memset(newTexture->GetPixels(), 0, m_textureHeight * newTexture->GetPitch());
- if (m_texture)
- diff --git a/xbmc/guilib/GraphicContext.h b/xbmc/guilib/GraphicContext.h
- index 6c2dcd4..bab2457 100644
- --- a/xbmc/guilib/GraphicContext.h
- +++ b/xbmc/guilib/GraphicContext.h
- @@ -146,6 +146,7 @@ class CGraphicContext : public CCriticalSection,
- inline void ScaleFinalCoords(float &x, float &y, float &z) const XBMC_FORCE_INLINE { m_finalTransform.matrix.TransformPosition(x, y, z); }
- bool RectIsAngled(float x1, float y1, float x2, float y2) const;
-
- + inline const TransformMatrix &GetGUIMatrix() const XBMC_FORCE_INLINE { return m_finalTransform.matrix; }
- inline float GetGUIScaleX() const XBMC_FORCE_INLINE { return m_finalTransform.scaleX; }
- inline float GetGUIScaleY() const XBMC_FORCE_INLINE { return m_finalTransform.scaleY; }
- inline color_t MergeAlpha(color_t color) const XBMC_FORCE_INLINE
- diff --git a/xbmc/guilib/Makefile.in b/xbmc/guilib/Makefile.in
- index 086fb0d..af82979 100644
- --- a/xbmc/guilib/Makefile.in
- +++ b/xbmc/guilib/Makefile.in
- @@ -23,6 +23,7 @@ SRCS += GUIEditControl.cpp
- SRCS += GUIFadeLabelControl.cpp
- SRCS += GUIFixedListContainer.cpp
- SRCS += GUIFont.cpp
- +SRCS += GUIFontCache.cpp
- SRCS += GUIFontManager.cpp
- SRCS += GUIFontTTF.cpp
- SRCS += GUIImage.cpp
- diff --git a/xbmc/guilib/TransformMatrix.h b/xbmc/guilib/TransformMatrix.h
- index f351c99..9036ba9 100644
- --- a/xbmc/guilib/TransformMatrix.h
- +++ b/xbmc/guilib/TransformMatrix.h
- @@ -245,3 +245,14 @@ class TransformMatrix
- float alpha;
- bool identity;
- };
- +
- +inline bool operator==(const TransformMatrix &a, const TransformMatrix &b)
- +{
- + return a.alpha == b.alpha && ((a.identity && b.identity) ||
- + (!a.identity && !b.identity && std::equal(&a.m[0][0], &a.m[0][0] + sizeof a.m / sizeof a.m[0][0], &b.m[0][0])));
- +}
- +
- +inline bool operator!=(const TransformMatrix &a, const TransformMatrix &b)
- +{
- + return !operator==(a, b);
- +}
- --
- 1.9.3
- From 65d2b7f112b400f75140de44579e6cdf98378b67 Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Thu, 23 Jan 2014 22:24:17 +0000
- Subject: [PATCH 23/94] Lay the groundwork for hardware clipping.
- For glScissor() to replace CGraphicContext::ClipRect, a necessary condition
- is that no shear or rotation is introduced between the coordinate systems
- they use; this depends upon the settings of the GUI matrix m_finalTransform
- as well as the OpenGL model-view and projection matrices. These all remain
- unchanged between paired calls of CGUIShader::OnEnabled and
- CGUIShader::OnDisabled, so we scan the matrices in CGUIShader::OnEnabled to
- see whether hardware clipping is possible.
- Then, in CGUIFontTTFBase::RenderCharacter, we don't apply software clipping
- in such cases. However, because vertices arising from multiple
- CGUIFontTTFBase::DrawTextInternal calls (each of which often uses a different
- clip rectangle) get lumped into the same vector, which only at the end is
- passed to OpenGL for rendering, we need to wait a few commits before we can
- actually apply hardware clipping. In the meantime, expect to see rendering
- errors.
- ---
- xbmc/guilib/GUIFontTTF.cpp | 3 +-
- xbmc/guilib/GUIShader.cpp | 80 +++++++++++++++++++++++++++++++-
- xbmc/guilib/GUIShader.h | 11 +++++
- xbmc/guilib/GraphicContext.cpp | 10 ++++
- xbmc/guilib/GraphicContext.h | 1 +
- xbmc/rendering/RenderSystem.h | 2 +
- xbmc/rendering/gles/RenderSystemGLES.cpp | 22 +++++++++
- xbmc/rendering/gles/RenderSystemGLES.h | 2 +
- 8 files changed, 128 insertions(+), 3 deletions(-)
- diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
- index 288e61a..19c7ff4 100644
- --- a/xbmc/guilib/GUIFontTTF.cpp
- +++ b/xbmc/guilib/GUIFontTTF.cpp
- @@ -710,7 +710,8 @@ void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *c
- (posY + ch->offsetY + height) * g_graphicsContext.GetGUIScaleY());
- vertex += CPoint(m_originX, m_originY);
- CRect texture(ch->left, ch->top, ch->right, ch->bottom);
- - g_graphicsContext.ClipRect(vertex, texture);
- + if (!g_Windowing.ScissorsCanEffectClipping())
- + g_graphicsContext.ClipRect(vertex, texture);
-
- // transform our positions - note, no scaling due to GUI calibration/resolution occurs
- float x[4], y[4], z[4];
- diff --git a/xbmc/guilib/GUIShader.cpp b/xbmc/guilib/GUIShader.cpp
- index 11089b8..53bce09 100644
- --- a/xbmc/guilib/GUIShader.cpp
- +++ b/xbmc/guilib/GUIShader.cpp
- @@ -26,6 +26,8 @@
- #include "GUIShader.h"
- #include "MatrixGLES.h"
- #include "utils/log.h"
- +#include "windowing/egl/WinSystemEGL.h"
- +#include "guilib/GraphicContext.h"
-
- CGUIShader::CGUIShader( const char *shader ) : CGLSLShaderProgram("guishader_vert.glsl", shader)
- {
- @@ -86,8 +88,82 @@ bool CGUIShader::OnEnabled()
- {
- // This is called after glUseProgram()
-
- - glUniformMatrix4fv(m_hProj, 1, GL_FALSE, g_matrices.GetMatrix(MM_PROJECTION));
- - glUniformMatrix4fv(m_hModel, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
- + GLfloat *projMatrix = g_matrices.GetMatrix(MM_PROJECTION);
- + GLfloat *modelMatrix = g_matrices.GetMatrix(MM_MODELVIEW);
- + glUniformMatrix4fv(m_hProj, 1, GL_FALSE, projMatrix);
- + glUniformMatrix4fv(m_hModel, 1, GL_FALSE, modelMatrix);
- +
- + const TransformMatrix &guiMatrix = g_graphicsContext.GetGUIMatrix();
- + CRect viewPort; // absolute positions of corners
- + g_Windowing.GetViewPort(viewPort);
- +
- + /* glScissor operates in window coordinates. In order that we can use it to
- + * perform clipping, we must ensure that there is an independent linear
- + * transformation from the coordinate system used by CGraphicContext::ClipRect
- + * to window coordinates, separately for X and Y (in other words, no
- + * rotation or shear is introduced at any stage). To do, this, we need to
- + * check that zeros are present in the following locations:
- + *
- + * GUI matrix:
- + * / * 0 * * \
- + * | 0 * * * |
- + * \ 0 0 * * /
- + * ^ TransformMatrix::TransformX/Y/ZCoord are only ever called with
- + * input z = 0, so this column doesn't matter
- + * Model-view matrix:
- + * / * 0 0 * \
- + * | 0 * 0 * |
- + * | 0 0 * * |
- + * \ * * * * / <- eye w has no influence on window x/y (last column below
- + * is either 0 or ignored)
- + * Projection matrix:
- + * / * 0 0 0 \
- + * | 0 * 0 0 |
- + * | * * * * | <- normalised device coordinate z has no influence on window x/y
- + * \ 0 0 * 0 /
- + *
- + * Some of these zeros are not strictly required to ensure this, but they tend
- + * to be zeroed in the common case, so by checking for zeros here, we simplify
- + * the calculation of the window x/y coordinates further down the line.
- + *
- + * (Minor detail: we don't quite deal in window coordinates as defined by
- + * OpenGL, because CRenderSystemGLES::SetScissors flips the Y axis. But all
- + * that's needed to handle that is an effective negation at the stage where
- + * Y is in normalised device coordinates.)
- + */
- + m_clipPossible = guiMatrix.m[0][1] == 0 &&
- + guiMatrix.m[1][0] == 0 &&
- + guiMatrix.m[2][0] == 0 &&
- + guiMatrix.m[2][1] == 0 &&
- + modelMatrix[0+1*4] == 0 &&
- + modelMatrix[0+2*4] == 0 &&
- + modelMatrix[1+0*4] == 0 &&
- + modelMatrix[1+2*4] == 0 &&
- + modelMatrix[2+0*4] == 0 &&
- + modelMatrix[2+1*4] == 0 &&
- + projMatrix[0+1*4] == 0 &&
- + projMatrix[0+2*4] == 0 &&
- + projMatrix[0+3*4] == 0 &&
- + projMatrix[1+0*4] == 0 &&
- + projMatrix[1+2*4] == 0 &&
- + projMatrix[1+3*4] == 0 &&
- + projMatrix[3+0*4] == 0 &&
- + projMatrix[3+1*4] == 0 &&
- + projMatrix[3+3*4] == 0;
- + if (m_clipPossible)
- + {
- + m_clipXFactor = guiMatrix.m[0][0] * modelMatrix[0+0*4] * projMatrix[0+0*4];
- + m_clipXOffset = (guiMatrix.m[0][3] * modelMatrix[0+0*4] + modelMatrix[0+3*4]) * projMatrix[0+0*4];
- + m_clipYFactor = guiMatrix.m[1][1] * modelMatrix[1+1*4] * projMatrix[1+1*4];
- + m_clipYOffset = (guiMatrix.m[1][3] * modelMatrix[1+1*4] + modelMatrix[1+3*4]) * projMatrix[1+1*4];
- + float clipW = (guiMatrix.m[2][3] * modelMatrix[2+2*4] + modelMatrix[2+3*4]) * projMatrix[3+2*4];
- + float xMult = (viewPort.x2 - viewPort.x1) / (2 * clipW);
- + float yMult = (viewPort.y1 - viewPort.y2) / (2 * clipW); // correct for inverted window coordinate scheme
- + m_clipXFactor = m_clipXFactor * xMult;
- + m_clipXOffset = m_clipXOffset * xMult + (viewPort.x2 + viewPort.x1) / 2;
- + m_clipYFactor = m_clipYFactor * yMult;
- + m_clipYOffset = m_clipYOffset * yMult + (viewPort.y2 + viewPort.y1) / 2;
- + }
-
- return true;
- }
- diff --git a/xbmc/guilib/GUIShader.h b/xbmc/guilib/GUIShader.h
- index c7e95aa..86ce4cc 100644
- --- a/xbmc/guilib/GUIShader.h
- +++ b/xbmc/guilib/GUIShader.h
- @@ -41,6 +41,11 @@ class CGUIShader : public CGLSLShaderProgram
- GLint GetCord1Loc() { return m_hCord1; }
- GLint GetUniColLoc() { return m_hUniCol; }
- GLint GetCoord0MatrixLoc() { return m_hCoord0Matrix; }
- + bool HardwareClipIsPossible() { return m_clipPossible; }
- + GLfloat GetClipXFactor() { return m_clipXFactor; }
- + GLfloat GetClipXOffset() { return m_clipXOffset; }
- + GLfloat GetClipYFactor() { return m_clipYFactor; }
- + GLfloat GetClipYOffset() { return m_clipYOffset; }
-
- protected:
- GLint m_hTex0;
- @@ -56,6 +61,12 @@ class CGUIShader : public CGLSLShaderProgram
-
- GLfloat *m_proj;
- GLfloat *m_model;
- +
- + bool m_clipPossible;
- + GLfloat m_clipXFactor;
- + GLfloat m_clipXOffset;
- + GLfloat m_clipYFactor;
- + GLfloat m_clipYOffset;
- };
-
- #endif // GUI_SHADER_H
- diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp
- index 38f17a7..5bffdf5 100644
- --- a/xbmc/guilib/GraphicContext.cpp
- +++ b/xbmc/guilib/GraphicContext.cpp
- @@ -167,6 +167,16 @@ void CGraphicContext::ClipRect(CRect &vertex, CRect &texture, CRect *texture2)
- }
- }
-
- +CRect CGraphicContext::GetClipRegion()
- +{
- + if (m_clipRegions.empty())
- + return CRect(0, 0, m_iScreenWidth, m_iScreenHeight);
- + CRect clipRegion(m_clipRegions.top());
- + if (!m_origins.empty())
- + clipRegion -= m_origins.top();
- + return clipRegion;
- +}
- +
- bool CGraphicContext::SetViewPort(float fx, float fy, float fwidth, float fheight, bool intersectPrevious /* = false */)
- {
- // transform coordinates - we may have a rotation which changes the positioning of the
- diff --git a/xbmc/guilib/GraphicContext.h b/xbmc/guilib/GraphicContext.h
- index bab2457..0a27643 100644
- --- a/xbmc/guilib/GraphicContext.h
- +++ b/xbmc/guilib/GraphicContext.h
- @@ -199,6 +199,7 @@ class CGraphicContext : public CCriticalSection,
- void ApplyHardwareTransform();
- void RestoreHardwareTransform();
- void ClipRect(CRect &vertex, CRect &texture, CRect *diffuse = NULL);
- + CRect GetClipRegion();
- inline void AddGUITransform()
- {
- m_transforms.push(m_finalTransform);
- diff --git a/xbmc/rendering/RenderSystem.h b/xbmc/rendering/RenderSystem.h
- index fa64eba..c1dfb93 100644
- --- a/xbmc/rendering/RenderSystem.h
- +++ b/xbmc/rendering/RenderSystem.h
- @@ -110,6 +110,8 @@ class CRenderSystemBase
- virtual void GetViewPort(CRect& viewPort) = 0;
- virtual void RestoreViewPort() {};
-
- + virtual bool ScissorsCanEffectClipping() { return false; }
- + virtual CRect ClipRectToScissorRect(const CRect &rect) { return CRect(); }
- virtual void SetScissors(const CRect &rect) = 0;
- virtual void ResetScissors() = 0;
-
- diff --git a/xbmc/rendering/gles/RenderSystemGLES.cpp b/xbmc/rendering/gles/RenderSystemGLES.cpp
- index 653c9ec..deb3afc 100644
- --- a/xbmc/rendering/gles/RenderSystemGLES.cpp
- +++ b/xbmc/rendering/gles/RenderSystemGLES.cpp
- @@ -533,6 +533,28 @@ void CRenderSystemGLES::SetViewPort(CRect& viewPort)
- m_viewPort[3] = viewPort.Height();
- }
-
- +bool CRenderSystemGLES::ScissorsCanEffectClipping()
- +{
- + if (m_pGUIshader[m_method])
- + return m_pGUIshader[m_method]->HardwareClipIsPossible();
- +
- + return false;
- +}
- +
- +CRect CRenderSystemGLES::ClipRectToScissorRect(const CRect &rect)
- +{
- + if (!m_pGUIshader[m_method])
- + return CRect();
- + float xFactor = m_pGUIshader[m_method]->GetClipXFactor();
- + float xOffset = m_pGUIshader[m_method]->GetClipXOffset();
- + float yFactor = m_pGUIshader[m_method]->GetClipYFactor();
- + float yOffset = m_pGUIshader[m_method]->GetClipYOffset();
- + return CRect(rect.x1 * xFactor + xOffset,
- + rect.y1 * yFactor + yOffset,
- + rect.x2 * xFactor + xOffset,
- + rect.y2 * yFactor + yOffset);
- +}
- +
- void CRenderSystemGLES::SetScissors(const CRect &rect)
- {
- if (!m_bRenderCreated)
- diff --git a/xbmc/rendering/gles/RenderSystemGLES.h b/xbmc/rendering/gles/RenderSystemGLES.h
- index 98e398a..81ee49e 100644
- --- a/xbmc/rendering/gles/RenderSystemGLES.h
- +++ b/xbmc/rendering/gles/RenderSystemGLES.h
- @@ -63,6 +63,8 @@ class CRenderSystemGLES : public CRenderSystemBase
- virtual void SetViewPort(CRect& viewPort);
- virtual void GetViewPort(CRect& viewPort);
-
- + virtual bool ScissorsCanEffectClipping();
- + virtual CRect ClipRectToScissorRect(const CRect &rect);
- virtual void SetScissors(const CRect& rect);
- virtual void ResetScissors();
-
- --
- 1.9.3
- From e372121bc53da1b0353b51f5e9897011c5f54033 Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Thu, 23 Jan 2014 16:42:22 +0000
- Subject: [PATCH 24/94] Increase font cache hit rate by keying on the
- fractional part of m_originX and m_originY *after* they have been through the
- graphics context's transformation matrix, plus the scale/rotation elements of
- the matrix, rather than the origin in the original frame of reference plus
- the complete transformation matrix. All vertices of individual glyph bounding
- boxes are a constant offset from this position, and when the fractional part
- of the translation is a match, the rounding of each vertex will be in the
- same direction; this permits us to calculate the desired vertices from the
- cached ones simply by adding the integer parts of the translations with no
- additional rounding steps.
- Note that this requires that software clipping is *not* performed.
- ---
- xbmc/guilib/GUIFontCache.cpp | 8 +++++++
- xbmc/guilib/GUIFontCache.h | 43 +++++++++++++++++++++++++++++++++++
- xbmc/guilib/GUIFontTTF.cpp | 53 +++++++++++++++++++++++++++++++++++---------
- xbmc/guilib/GUIFontTTF.h | 1 +
- 4 files changed, 95 insertions(+), 10 deletions(-)
- diff --git a/xbmc/guilib/GUIFontCache.cpp b/xbmc/guilib/GUIFontCache.cpp
- index c029713..b66c00b 100644
- --- a/xbmc/guilib/GUIFontCache.cpp
- +++ b/xbmc/guilib/GUIFontCache.cpp
- @@ -85,6 +85,9 @@ Value &CGUIFontCache<Position, Value>::Lookup(Position &pos,
- else
- {
- /* Cache hit */
- + /* Update the translation arguments so that they hold the offset to apply
- + * to the cached values (but only in the dynamic case) */
- + pos.UpdateWithOffsets(i->m_key.m_pos, scrolling);
- /* Update time in entry and move to the back of the list */
- i->m_lastUsedMillis = nowMillis;
- m_list.get<Age>().relocate(m_list.get<Age>().end(), m_list.project<Age>(i));
- @@ -103,3 +106,8 @@ template void CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStati
- template CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::~CGUIFontCacheEntry();
- template CGUIFontCacheStaticValue &CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Lookup(CGUIFontCacheStaticPosition &, const vecColors &, const vecText &, uint32_t, float, bool, unsigned int, bool &);
- template void CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Flush();
- +
- +template void CGUIFontCacheEntry<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::Reassign::operator()(CGUIFontCacheEntry<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue> &entry);
- +template CGUIFontCacheEntry<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::~CGUIFontCacheEntry();
- +template CGUIFontCacheDynamicValue &CGUIFontCache<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::Lookup(CGUIFontCacheDynamicPosition &, const vecColors &, const vecText &, uint32_t, float, bool, unsigned int, bool &);
- +template void CGUIFontCache<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::Flush();
- diff --git a/xbmc/guilib/GUIFontCache.h b/xbmc/guilib/GUIFontCache.h
- index ef65845..d913dee 100644
- --- a/xbmc/guilib/GUIFontCache.h
- +++ b/xbmc/guilib/GUIFontCache.h
- @@ -44,6 +44,7 @@
- using namespace boost::multi_index;
-
- #define FONT_CACHE_TIME_LIMIT (1000)
- +#define FONT_CACHE_DIST_LIMIT (0.01)
-
- template<class Position, class Value> class CGUIFontCache;
- class CGUIFontTTFBase;
- @@ -197,6 +198,7 @@ struct CGUIFontCacheStaticPosition
- float m_x;
- float m_y;
- CGUIFontCacheStaticPosition(float x, float y) : m_x(x), m_y(y) {}
- + void UpdateWithOffsets(const CGUIFontCacheStaticPosition &cached, bool scrolling) {}
- };
-
- typedef std::vector<SVertex> CGUIFontCacheStaticValue;
- @@ -214,4 +216,45 @@ inline float MatrixHashContribution(const CGUIFontCacheKey<CGUIFontCacheStaticPo
- return a.m_matrix.m[0][3];
- }
-
- +struct CGUIFontCacheDynamicPosition
- +{
- + float m_x;
- + float m_y;
- + float m_z;
- + CGUIFontCacheDynamicPosition() {}
- + CGUIFontCacheDynamicPosition(float x, float y, float z) : m_x(x), m_y(y), m_z(z) {}
- + void UpdateWithOffsets(const CGUIFontCacheDynamicPosition &cached, bool scrolling)
- + {
- + if (scrolling)
- + m_x = m_x - cached.m_x;
- + else
- + m_x = floorf(m_x - cached.m_x + FONT_CACHE_DIST_LIMIT);
- + m_y = floorf(m_y - cached.m_y + FONT_CACHE_DIST_LIMIT);
- + m_z = floorf(m_z - cached.m_z + FONT_CACHE_DIST_LIMIT);
- + }
- +};
- +
- +typedef std::vector<SVertex> CGUIFontCacheDynamicValue;
- +
- +inline bool Match(const CGUIFontCacheDynamicPosition &a, const TransformMatrix &a_m,
- + const CGUIFontCacheDynamicPosition &b, const TransformMatrix &b_m,
- + bool scrolling)
- +{
- + float diffX = a.m_x - b.m_x + FONT_CACHE_DIST_LIMIT;
- + float diffY = a.m_y - b.m_y + FONT_CACHE_DIST_LIMIT;
- + float diffZ = a.m_z - b.m_z + FONT_CACHE_DIST_LIMIT;
- + return (scrolling || diffX - floorf(diffX) < 2 * FONT_CACHE_DIST_LIMIT) &&
- + diffY - floorf(diffY) < 2 * FONT_CACHE_DIST_LIMIT &&
- + diffZ - floorf(diffZ) < 2 * FONT_CACHE_DIST_LIMIT &&
- + a_m.m[0][0] == b_m.m[0][0] &&
- + a_m.m[1][1] == b_m.m[1][1] &&
- + a_m.m[2][2] == b_m.m[2][2];
- + // We already know the first 3 columns of both matrices are diagonal, so no need to check the other elements
- +}
- +
- +inline float MatrixHashContribution(const CGUIFontCacheKey<CGUIFontCacheDynamicPosition> &a)
- +{
- + return 0;
- +}
- +
- #endif
- diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
- index 19c7ff4..73f0e50 100644
- --- a/xbmc/guilib/GUIFontTTF.cpp
- +++ b/xbmc/guilib/GUIFontTTF.cpp
- @@ -132,7 +132,7 @@ class CFreeTypeLibrary
- XBMC_GLOBAL_REF(CFreeTypeLibrary, g_freeTypeLibrary); // our freetype library
- #define g_freeTypeLibrary XBMC_GLOBAL_USE(CFreeTypeLibrary)
-
- -CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) : m_staticCache(*this)
- +CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) : m_staticCache(*this), m_dynamicCache(*this)
- {
- m_texture = NULL;
- m_char = NULL;
- @@ -332,13 +332,28 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
- Begin();
-
- bool dirtyCache;
- + bool hardwareClipping = g_Windowing.ScissorsCanEffectClipping();
- CGUIFontCacheStaticPosition staticPos(x, y);
- - std::vector<SVertex> &vertices = m_staticCache.Lookup(staticPos,
- - colors, text,
- - alignment, maxPixelWidth,
- - scrolling,
- - XbmcThreads::SystemClockMillis(),
- - dirtyCache);
- + CGUIFontCacheDynamicPosition dynamicPos;
- + if (hardwareClipping)
- + {
- + dynamicPos = CGUIFontCacheDynamicPosition(g_graphicsContext.ScaleFinalXCoord(x, y),
- + g_graphicsContext.ScaleFinalYCoord(x, y),
- + g_graphicsContext.ScaleFinalZCoord(x, y));
- + }
- + std::vector<SVertex> &vertices = hardwareClipping ?
- + m_dynamicCache.Lookup(dynamicPos,
- + colors, text,
- + alignment, maxPixelWidth,
- + scrolling,
- + XbmcThreads::SystemClockMillis(),
- + dirtyCache) :
- + m_staticCache.Lookup(staticPos,
- + colors, text,
- + alignment, maxPixelWidth,
- + scrolling,
- + XbmcThreads::SystemClockMillis(),
- + dirtyCache);
- if (dirtyCache)
- {
- // save the origin, which is scaled separately
- @@ -441,10 +456,28 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
- else
- cursorX += ch->advance;
- }
- + if (hardwareClipping)
- + /* Append the new vertices (which we have just constructed in the cache)
- + * to the set collected since the first Begin() call */
- + m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end());
- + }
- + else if (hardwareClipping)
- + {
- + /* Apply the translation offset to the vertices from the cache after
- + * appending them to the set collected since the first Begin() call */
- + m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end());
- + SVertex *v;
- + for (v = &*m_vertex.end() - vertices.size(); v != &*m_vertex.end(); v++)
- + {
- + v->x += dynamicPos.m_x;
- + v->y += dynamicPos.m_y;
- + v->z += dynamicPos.m_z;
- + }
- }
- - /* Append the new vertices (from the cache or otherwise) to the set collected
- - * since the first Begin() call */
- - m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end());
- + if (!hardwareClipping)
- + /* Append the new vertices (from the cache or otherwise) to the set collected
- + * since the first Begin() call */
- + m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end());
-
- End();
- }
- diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
- index 7cb4669..78445ab 100644
- --- a/xbmc/guilib/GUIFontTTF.h
- +++ b/xbmc/guilib/GUIFontTTF.h
- @@ -170,6 +170,7 @@ class CGUIFontTTFBase
- CStdString m_strFileName;
-
- CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue> m_staticCache;
- + CGUIFontCache<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue> m_dynamicCache;
-
- private:
- virtual bool FirstBegin() = 0;
- --
- 1.9.3
- From 10eeb73ca15798de26abd5f8846214c8938f8b42 Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Wed, 8 Jan 2014 12:16:33 +0000
- Subject: [PATCH 25/94] Rewrite of scrolling text code.
- No longer shuffles the string round to minimise the number of characters
- before the clipping rectangle; this doesn't save much on rendering time but
- does harm the effectiveness of the cache. Now uses a pixel offset into the
- string rather than a character + pixel offset, and plots the entire string
- every time (execpt when the wrap point is visible, in which case the entire
- string is plotted twice).
- It also makes motion smoother, because (possibly unintentionally) the
- previous code preferred to align the scroll offset with character boundaries.
- This would lead to uneven changes of position, especially when the width of
- the character currently being scrolled off the edge was only slightly more
- than an integral multiple of the scroll increment.
- ---
- xbmc/guilib/GUIFadeLabelControl.cpp | 8 +--
- xbmc/guilib/GUIFont.cpp | 123 +++++++++++++-----------------------
- xbmc/guilib/GUIFont.h | 17 ++---
- xbmc/guilib/GUIRSSControl.cpp | 6 +-
- xbmc/utils/RssReader.cpp | 2 +-
- xbmc/utils/RssReader.h | 2 +-
- 6 files changed, 58 insertions(+), 100 deletions(-)
- diff --git a/xbmc/guilib/GUIFadeLabelControl.cpp b/xbmc/guilib/GUIFadeLabelControl.cpp
- index d594c04..86ee73a 100644
- --- a/xbmc/guilib/GUIFadeLabelControl.cpp
- +++ b/xbmc/guilib/GUIFadeLabelControl.cpp
- @@ -109,18 +109,14 @@ void CGUIFadeLabelControl::Process(unsigned int currentTime, CDirtyRegionList &d
- bool moveToNextLabel = false;
- if (!m_scrollOut)
- {
- - vecText text;
- - m_textLayout.GetFirstText(text);
- - if (m_scrollInfo.characterPos && m_scrollInfo.characterPos < text.size())
- - text.erase(text.begin(), text.begin() + min((int)m_scrollInfo.characterPos - 1, (int)text.size()));
- - if (m_label.font->GetTextWidth(text) < m_width)
- + if (m_scrollInfo.pixelPos + m_width > m_scrollInfo.m_textWidth)
- {
- if (m_fadeAnim.GetProcess() != ANIM_PROCESS_NORMAL)
- m_fadeAnim.QueueAnimation(ANIM_PROCESS_NORMAL);
- moveToNextLabel = true;
- }
- }
- - else if (m_scrollInfo.characterPos > m_textLayout.GetTextLength())
- + else if (m_scrollInfo.pixelPos > m_scrollInfo.m_textWidth)
- moveToNextLabel = true;
-
- // apply the fading animation
- diff --git a/xbmc/guilib/GUIFont.cpp b/xbmc/guilib/GUIFont.cpp
- index a7ee668..eb8efdb 100644
- --- a/xbmc/guilib/GUIFont.cpp
- +++ b/xbmc/guilib/GUIFont.cpp
- @@ -36,7 +36,12 @@ CScrollInfo::CScrollInfo(unsigned int wait /* = 50 */, float pos /* = 0 */,
- initialWait = wait;
- initialPos = pos;
- SetSpeed(speed ? speed : defaultSpeed);
- - g_charsetConverter.utf8ToW(scrollSuffix, suffix);
- + CStdStringW wsuffix;
- + g_charsetConverter.utf8ToW(scrollSuffix, wsuffix);
- + suffix.clear();
- + suffix.reserve(wsuffix.size());
- + for (vecText::size_type i = 0; i < wsuffix.size(); i++)
- + suffix.push_back(wsuffix[i]);
- Reset();
- }
-
- @@ -115,11 +120,12 @@ bool CGUIFont::UpdateScrollInfo(const vecText &text, CScrollInfo &scrollInfo)
- {
- // draw at our scroll position
- // we handle the scrolling as follows:
- - // We scroll on a per-pixel basis up until we have scrolled the first character outside
- - // of our viewport, whereby we cycle the string around, and reset the scroll position.
- - //
- - // pixelPos is the amount in pixels to move the string by.
- - // characterPos is the amount in characters to rotate the string by.
- + // We scroll on a per-pixel basis (eschewing the use of character indices
- + // which were also in use previously). The complete string, including suffix,
- + // is plotted to achieve the desired effect - normally just the one time, but
- + // if there is a wrap point within the viewport then it will be plotted twice.
- + // If the string is smaller than the viewport, then it may be plotted even
- + // more times than that.
- //
- if (scrollInfo.waitTime)
- {
- @@ -135,54 +141,19 @@ bool CGUIFont::UpdateScrollInfo(const vecText &text, CScrollInfo &scrollInfo)
- // move along by the appropriate scroll amount
- float scrollAmount = fabs(scrollInfo.GetPixelsPerFrame() * g_graphicsContext.GetGUIScaleX());
-
- - if (scrollInfo.pixelSpeed > 0)
- + if (!scrollInfo.m_widthValid)
- {
- - // we want to move scrollAmount, grab the next character
- - float charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
- - if (scrollInfo.pixelPos + scrollAmount < charWidth)
- - scrollInfo.pixelPos += scrollAmount; // within the current character
- - else
- - { // past the current character, decrement scrollAmount by the charWidth and move to the next character
- - while (scrollInfo.pixelPos + scrollAmount >= charWidth)
- - {
- - scrollAmount -= (charWidth - scrollInfo.pixelPos);
- - scrollInfo.pixelPos = 0;
- - scrollInfo.characterPos++;
- - if (scrollInfo.characterPos >= text.size() + scrollInfo.suffix.size())
- - {
- - scrollInfo.Reset();
- - break;
- - }
- - charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
- - }
- - }
- - }
- - else if (scrollInfo.pixelSpeed < 0)
- - { // scrolling backwards
- - // we want to move scrollAmount, grab the next character
- - float charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
- - if (scrollInfo.pixelPos + scrollAmount < charWidth)
- - scrollInfo.pixelPos += scrollAmount; // within the current character
- - else
- - { // past the current character, decrement scrollAmount by the charWidth and move to the next character
- - while (scrollInfo.pixelPos + scrollAmount >= charWidth)
- - {
- - scrollAmount -= (charWidth - scrollInfo.pixelPos);
- - scrollInfo.pixelPos = 0;
- - if (scrollInfo.characterPos == 0)
- - {
- - scrollInfo.Reset();
- - scrollInfo.characterPos = text.size() + scrollInfo.suffix.size() - 1;
- - break;
- - }
- - scrollInfo.characterPos--;
- - charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
- - }
- - }
- + /* Calculate the pixel width of the complete string */
- + scrollInfo.m_textWidth = GetTextWidth(text);
- + scrollInfo.m_totalWidth = scrollInfo.m_textWidth + GetTextWidth(scrollInfo.suffix);
- + scrollInfo.m_widthValid = true;
- }
- + scrollInfo.pixelPos += scrollAmount;
- + assert(scrollInfo.m_totalWidth != 0);
- + while (scrollInfo.pixelPos >= scrollInfo.m_totalWidth)
- + scrollInfo.pixelPos -= scrollInfo.m_totalWidth;
-
- - if(scrollInfo.characterPos != old.characterPos
- - || scrollInfo.pixelPos != old.pixelPos)
- + if (scrollInfo.pixelPos != old.pixelPos)
- return true;
- else
- return false;
- @@ -194,39 +165,27 @@ void CGUIFont::DrawScrollingText(float x, float y, const vecColors &colors, colo
- if (!m_font) return;
- if (!shadowColor) shadowColor = m_shadowColor;
-
- - float spaceWidth = GetCharWidth(L' ');
- - // max chars on screen + extra margin chars
- - vecText::size_type maxChars =
- - std::min<vecText::size_type>(
- - (text.size() + (vecText::size_type)scrollInfo.suffix.size()),
- - (vecText::size_type)((maxWidth * 1.05f) / spaceWidth));
- -
- if (!text.size() || ClippedRegionIsEmpty(x, y, maxWidth, alignment))
- return; // nothing to render
-
- - maxWidth = ROUND((maxWidth + scrollInfo.pixelPos) / g_graphicsContext.GetGUIScaleX());
- + if (!scrollInfo.m_widthValid)
- + {
- + /* Calculate the pixel width of the complete string */
- + scrollInfo.m_textWidth = GetTextWidth(text);
- + scrollInfo.m_totalWidth = scrollInfo.m_textWidth + GetTextWidth(scrollInfo.suffix);
- + scrollInfo.m_widthValid = true;
- + }
- +
- + assert(scrollInfo.m_totalWidth != 0);
- +
- + float textPixelWidth = ROUND(scrollInfo.m_textWidth / g_graphicsContext.GetGUIScaleX());
- + float suffixPixelWidth = ROUND((scrollInfo.m_totalWidth - scrollInfo.m_textWidth) / g_graphicsContext.GetGUIScaleX());
-
- - float charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
- float offset;
- if(scrollInfo.pixelSpeed >= 0)
- offset = scrollInfo.pixelPos;
- else
- - offset = charWidth - scrollInfo.pixelPos;
- -
- - // Now rotate our string as needed, only take a slightly larger then visible part of the text.
- - unsigned int pos = scrollInfo.characterPos;
- - vecText renderText;
- - renderText.reserve(maxChars);
- - for (vecText::size_type i = 0; i < maxChars; i++)
- - {
- - if (pos >= text.size() + scrollInfo.suffix.size())
- - pos = 0;
- - if (pos < text.size())
- - renderText.push_back(text[pos]);
- - else
- - renderText.push_back(scrollInfo.suffix[pos - text.size()]);
- - pos++;
- - }
- + offset = scrollInfo.m_totalWidth - scrollInfo.pixelPos;
-
- vecColors renderColors;
- for (unsigned int i = 0; i < colors.size(); i++)
- @@ -239,9 +198,17 @@ void CGUIFont::DrawScrollingText(float x, float y, const vecColors &colors, colo
- vecColors shadowColors;
- for (unsigned int i = 0; i < renderColors.size(); i++)
- shadowColors.push_back((renderColors[i] & 0xff000000) != 0 ? shadowColor : 0);
- - m_font->DrawTextInternal(x - offset + 1, y + 1, shadowColors, renderText, alignment, maxWidth + m_font->GetLineHeight(2.0f), scroll);
- + for (float dx = -offset; dx < maxWidth; dx += scrollInfo.m_totalWidth)
- + {
- + m_font->DrawTextInternal(x + dx + 1, y + 1, shadowColors, text, alignment, textPixelWidth, scroll);
- + m_font->DrawTextInternal(x + dx + scrollInfo.m_textWidth + 1, y + 1, shadowColors, scrollInfo.suffix, alignment, suffixPixelWidth, scroll);
- + }
- + }
- + for (float dx = -offset; dx < maxWidth; dx += scrollInfo.m_totalWidth)
- + {
- + m_font->DrawTextInternal(x + dx, y, renderColors, text, alignment, textPixelWidth, scroll);
- + m_font->DrawTextInternal(x + dx + scrollInfo.m_textWidth, y, renderColors, scrollInfo.suffix, alignment, suffixPixelWidth, scroll);
- }
- - m_font->DrawTextInternal(x - offset, y, renderColors, renderText, alignment, maxWidth + m_font->GetLineHeight(2.0f), scroll);
-
- g_graphicsContext.RestoreClipRegion();
- }
- diff --git a/xbmc/guilib/GUIFont.h b/xbmc/guilib/GUIFont.h
- index c55db48..09cf9b3 100644
- --- a/xbmc/guilib/GUIFont.h
- +++ b/xbmc/guilib/GUIFont.h
- @@ -64,7 +64,6 @@ class CScrollInfo
- void Reset()
- {
- waitTime = initialWait;
- - characterPos = 0;
- // pixelPos is where we start the current letter, so is measured
- // to the left of the text rendering's left edge. Thus, a negative
- // value will mean the text starts to the right
- @@ -72,25 +71,19 @@ class CScrollInfo
- // privates:
- m_averageFrameTime = 1000.f / abs(defaultSpeed);
- m_lastFrameTime = 0;
- - }
- - uint32_t GetCurrentChar(const vecText &text) const
- - {
- - assert(text.size());
- - if (characterPos < text.size())
- - return text[characterPos];
- - else if (characterPos < text.size() + suffix.size())
- - return suffix[characterPos - text.size()];
- - return text[0];
- + m_widthValid = false;
- }
- float GetPixelsPerFrame();
-
- float pixelPos;
- float pixelSpeed;
- unsigned int waitTime;
- - unsigned int characterPos;
- unsigned int initialWait;
- float initialPos;
- - CStdStringW suffix;
- + vecText suffix;
- + mutable float m_textWidth;
- + mutable float m_totalWidth;
- + mutable bool m_widthValid;
-
- static const int defaultSpeed = 60;
- private:
- diff --git a/xbmc/guilib/GUIRSSControl.cpp b/xbmc/guilib/GUIRSSControl.cpp
- index 712e118..203c138 100644
- --- a/xbmc/guilib/GUIRSSControl.cpp
- +++ b/xbmc/guilib/GUIRSSControl.cpp
- @@ -119,7 +119,9 @@ void CGUIRSSControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyre
- dirty = true;
-
- if (CRssManager::Get().GetReader(GetID(), GetParentID(), this, m_pReader))
- - m_scrollInfo.characterPos = m_pReader->m_SavedScrollPos;
- + {
- + m_scrollInfo.pixelPos = m_pReader->m_savedScrollPixelPos;
- + }
- else
- {
- if (m_strRSSTags != "")
- @@ -177,7 +179,7 @@ void CGUIRSSControl::Render()
- if (m_pReader)
- {
- m_pReader->CheckForUpdates();
- - m_pReader->m_SavedScrollPos = m_scrollInfo.characterPos;
- + m_pReader->m_savedScrollPixelPos = m_scrollInfo.pixelPos;
- }
- }
- CGUIControl::Render();
- diff --git a/xbmc/utils/RssReader.cpp b/xbmc/utils/RssReader.cpp
- index b1e53b7..f68597a 100644
- --- a/xbmc/utils/RssReader.cpp
- +++ b/xbmc/utils/RssReader.cpp
- @@ -54,7 +54,7 @@ CRssReader::CRssReader() : CThread("RSSReader")
- m_pObserver = NULL;
- m_spacesBetweenFeeds = 0;
- m_bIsRunning = false;
- - m_SavedScrollPos = 0;
- + m_savedScrollPixelPos = 0;
- m_rtlText = false;
- m_requestRefresh = false;
- }
- diff --git a/xbmc/utils/RssReader.h b/xbmc/utils/RssReader.h
- index 2c6f366..b74faf2 100644
- --- a/xbmc/utils/RssReader.h
- +++ b/xbmc/utils/RssReader.h
- @@ -43,7 +43,7 @@ class CRssReader : public CThread
- void SetObserver(IRssObserver* observer);
- void CheckForUpdates();
- void requestRefresh();
- - unsigned int m_SavedScrollPos;
- + float m_savedScrollPixelPos;
-
- private:
- void Process();
- --
- 1.9.3
- From 7064920379f68a7f6114813db8ad40a21c4957cc Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Mon, 27 Jan 2014 23:21:10 +0000
- Subject: [PATCH 26/94] Move the application of the translation offsets into
- the GLES code. Still all pure software at this stage. Main change is in the
- data types at the interface between CGUIFontTTFBase and CGUIFontTTFGL. The
- old way (array of vertices in m_vertex) are retained in addition, for the
- sake`of cases that need to use software clipping on GLES, as well as for DX
- and GL support where the new scheme is not (yet?) used.
- ---
- xbmc/guilib/GUIFontTTF.cpp | 19 +++---------
- xbmc/guilib/GUIFontTTF.h | 17 +++++++++++
- xbmc/guilib/GUIFontTTFGL.cpp | 72 ++++++++++++++++++++++++++++++++------------
- 3 files changed, 73 insertions(+), 35 deletions(-)
- diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
- index 73f0e50..ad0a53b 100644
- --- a/xbmc/guilib/GUIFontTTF.cpp
- +++ b/xbmc/guilib/GUIFontTTF.cpp
- @@ -215,6 +215,7 @@ void CGUIFontTTFBase::Clear()
- g_freeTypeLibrary.ReleaseStroker(m_stroker);
- m_stroker = NULL;
-
- + m_vertexTrans.clear();
- m_vertex.clear();
- }
-
- @@ -310,6 +311,7 @@ void CGUIFontTTFBase::Begin()
- {
- if (m_nestedBeginCount == 0 && m_texture != NULL && FirstBegin())
- {
- + m_vertexTrans.clear();
- m_vertex.clear();
- }
- // Keep track of the nested begin/end calls.
- @@ -457,23 +459,10 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
- cursorX += ch->advance;
- }
- if (hardwareClipping)
- - /* Append the new vertices (which we have just constructed in the cache)
- - * to the set collected since the first Begin() call */
- - m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end());
- + m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertices));
- }
- else if (hardwareClipping)
- - {
- - /* Apply the translation offset to the vertices from the cache after
- - * appending them to the set collected since the first Begin() call */
- - m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end());
- - SVertex *v;
- - for (v = &*m_vertex.end() - vertices.size(); v != &*m_vertex.end(); v++)
- - {
- - v->x += dynamicPos.m_x;
- - v->y += dynamicPos.m_y;
- - v->z += dynamicPos.m_z;
- - }
- - }
- + m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertices));
- if (!hardwareClipping)
- /* Append the new vertices (from the cache or otherwise) to the set collected
- * since the first Begin() call */
- diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
- index 78445ab..c71f90d 100644
- --- a/xbmc/guilib/GUIFontTTF.h
- +++ b/xbmc/guilib/GUIFontTTF.h
- @@ -61,6 +61,14 @@ struct SVertex
- unsigned char r, g, b, a;
- #endif
- float u, v;
- + struct SVertex Offset(float translate[3]) const
- + {
- + SVertex out = *this;
- + out.x += translate[0];
- + out.y += translate[1];
- + out.z += translate[2];
- + return out;
- + }
- };
-
-
- @@ -160,6 +168,15 @@ class CGUIFontTTFBase
- bool m_bTextureLoaded;
- unsigned int m_nTexture;
-
- + struct CTranslatedVertices
- + {
- + float translateX;
- + float translateY;
- + float translateZ;
- + const std::vector<SVertex> *vertexBuffer;
- + CTranslatedVertices(float translateX, float translateY, float translateZ, const std::vector<SVertex> *vertexBuffer) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer) {}
- + };
- + std::vector<CTranslatedVertices> m_vertexTrans;
- std::vector<SVertex> m_vertex;
-
- float m_textureScaleX;
- diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
- index cb56987..f6aa081 100644
- --- a/xbmc/guilib/GUIFontTTFGL.cpp
- +++ b/xbmc/guilib/GUIFontTTFGL.cpp
- @@ -146,34 +146,65 @@ void CGUIFontTTFGL::LastEnd()
- GLint colLoc = g_Windowing.GUIShaderGetCol();
- GLint tex0Loc = g_Windowing.GUIShaderGetCoord0();
-
- - // stack object until VBOs will be used
- - std::vector<SVertex> vecVertices( 6 * (m_vertex.size() / 4) );
- - SVertex *vertices = &vecVertices[0];
- + // Enable the attributes used by this shader
- + glEnableVertexAttribArray(posLoc);
- + glEnableVertexAttribArray(colLoc);
- + glEnableVertexAttribArray(tex0Loc);
-
- - for (size_t i=0; i<m_vertex.size(); i+=4)
- + if (m_vertex.size() > 0)
- {
- - *vertices++ = m_vertex[i];
- - *vertices++ = m_vertex[i+1];
- - *vertices++ = m_vertex[i+2];
- + // Deal with vertices that had to use software clipping
- + std::vector<SVertex> vecVertices( 6 * (m_vertex.size() / 4) );
- + SVertex *vertices = &vecVertices[0];
-
- - *vertices++ = m_vertex[i+1];
- - *vertices++ = m_vertex[i+3];
- - *vertices++ = m_vertex[i+2];
- - }
- + for (size_t i=0; i<m_vertex.size(); i+=4)
- + {
- + *vertices++ = m_vertex[i];
- + *vertices++ = m_vertex[i+1];
- + *vertices++ = m_vertex[i+2];
-
- - vertices = &vecVertices[0];
- + *vertices++ = m_vertex[i+1];
- + *vertices++ = m_vertex[i+3];
- + *vertices++ = m_vertex[i+2];
- + }
-
- - glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x));
- - // Normalize color values. Does not affect Performance at all.
- - glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r));
- - glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u));
- + vertices = &vecVertices[0];
-
- - glEnableVertexAttribArray(posLoc);
- - glEnableVertexAttribArray(colLoc);
- - glEnableVertexAttribArray(tex0Loc);
- + glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x));
- + // Normalize color values. Does not affect Performance at all.
- + glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r));
- + glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u));
- +
- + glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
- + }
- + if (m_vertexTrans.size() > 0)
- + {
- + // Deal with the vertices that can be hardware clipped and therefore translated
- + std::vector<SVertex> vecVertices;
- + for (size_t i = 0; i < m_vertexTrans.size(); i++)
- + {
- + float translate[3] = { m_vertexTrans[i].translateX, m_vertexTrans[i].translateY, m_vertexTrans[i].translateZ };
- + for (size_t j = 0; j < m_vertexTrans[i].vertexBuffer->size(); j += 4)
- + {
- + vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j].Offset(translate));
- + vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1].Offset(translate));
- + vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2].Offset(translate));
- + vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1].Offset(translate));
- + vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+3].Offset(translate));
- + vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2].Offset(translate));
- + }
- + }
- + SVertex *vertices = &vecVertices[0];
-
- - glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
- + glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x));
- + // Normalize color values. Does not affect Performance at all.
- + glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r));
- + glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u));
- +
- + glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
- + }
-
- + // Disable the attributes used by this shader
- glDisableVertexAttribArray(posLoc);
- glDisableVertexAttribArray(colLoc);
- glDisableVertexAttribArray(tex0Loc);
- @@ -201,6 +232,7 @@ CBaseTexture* CGUIFontTTFGL::ReallocTexture(unsigned int& newHeight)
- if (m_textureHeight < newHeight)
- CLog::Log(LOGWARNING, "%s: allocated new texture with height of %d, requested %d", __FUNCTION__, m_textureHeight, newHeight);
- m_staticCache.Flush();
- + m_dynamicCache.Flush();
-
- memset(newTexture->GetPixels(), 0, m_textureHeight * newTexture->GetPitch());
- if (m_texture)
- --
- 1.9.3
- From 476fce7bc2897e8898f4392809d934b0d5f46518 Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Wed, 15 Jan 2014 15:28:06 +0000
- Subject: [PATCH 27/94] Rather than applying the translation offsets to the
- vertices, now applies them to the model view matrix from the top of the
- matrix stack and pushes it over to OpenGL. The vertices themselves are still
- all held client-side.
- ---
- xbmc/guilib/GUIFontTTF.h | 8 -------
- xbmc/guilib/GUIFontTTFGL.cpp | 40 +++++++++++++++++++++-----------
- xbmc/guilib/GUIShader.h | 1 +
- xbmc/rendering/gles/RenderSystemGLES.cpp | 8 +++++++
- xbmc/rendering/gles/RenderSystemGLES.h | 1 +
- 5 files changed, 36 insertions(+), 22 deletions(-)
- diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
- index c71f90d..fde2085 100644
- --- a/xbmc/guilib/GUIFontTTF.h
- +++ b/xbmc/guilib/GUIFontTTF.h
- @@ -61,14 +61,6 @@ struct SVertex
- unsigned char r, g, b, a;
- #endif
- float u, v;
- - struct SVertex Offset(float translate[3]) const
- - {
- - SVertex out = *this;
- - out.x += translate[0];
- - out.y += translate[1];
- - out.z += translate[2];
- - return out;
- - }
- };
-
-
- diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
- index f6aa081..fbffaa0 100644
- --- a/xbmc/guilib/GUIFontTTFGL.cpp
- +++ b/xbmc/guilib/GUIFontTTFGL.cpp
- @@ -29,6 +29,7 @@
- #include "utils/log.h"
- #include "utils/GLUtils.h"
- #include "windowing/WindowingFactory.h"
- +#include "guilib/MatrixGLES.h"
-
- // stuff for freetype
- #include <ft2build.h>
- @@ -145,6 +146,7 @@ void CGUIFontTTFGL::LastEnd()
- GLint posLoc = g_Windowing.GUIShaderGetPos();
- GLint colLoc = g_Windowing.GUIShaderGetCol();
- GLint tex0Loc = g_Windowing.GUIShaderGetCoord0();
- + GLint modelLoc = g_Windowing.GUIShaderGetModel();
-
- // Enable the attributes used by this shader
- glEnableVertexAttribArray(posLoc);
- @@ -183,25 +185,35 @@ void CGUIFontTTFGL::LastEnd()
- std::vector<SVertex> vecVertices;
- for (size_t i = 0; i < m_vertexTrans.size(); i++)
- {
- - float translate[3] = { m_vertexTrans[i].translateX, m_vertexTrans[i].translateY, m_vertexTrans[i].translateZ };
- + // Apply the translation to the currently active (top-of-stack) model view matrix
- + g_matrices.MatrixMode(MM_MODELVIEW);
- + g_matrices.PushMatrix();
- + g_matrices.Translatef(m_vertexTrans[i].translateX, m_vertexTrans[i].translateY, m_vertexTrans[i].translateZ);
- + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
- +
- + vecVertices.clear();
- for (size_t j = 0; j < m_vertexTrans[i].vertexBuffer->size(); j += 4)
- {
- - vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j].Offset(translate));
- - vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1].Offset(translate));
- - vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2].Offset(translate));
- - vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1].Offset(translate));
- - vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+3].Offset(translate));
- - vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2].Offset(translate));
- + vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j]);
- + vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1]);
- + vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2]);
- + vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1]);
- + vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+3]);
- + vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2]);
- }
- - }
- - SVertex *vertices = &vecVertices[0];
- + SVertex *vertices = &vecVertices[0];
-
- - glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x));
- - // Normalize color values. Does not affect Performance at all.
- - glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r));
- - glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u));
- + glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x));
- + // Normalize color values. Does not affect Performance at all.
- + glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r));
- + glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u));
-
- - glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
- + glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
- +
- + g_matrices.PopMatrix();
- + }
- + // Restore the original model view matrix
- + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
- }
-
- // Disable the attributes used by this shader
- diff --git a/xbmc/guilib/GUIShader.h b/xbmc/guilib/GUIShader.h
- index 86ce4cc..ba01956 100644
- --- a/xbmc/guilib/GUIShader.h
- +++ b/xbmc/guilib/GUIShader.h
- @@ -41,6 +41,7 @@ class CGUIShader : public CGLSLShaderProgram
- GLint GetCord1Loc() { return m_hCord1; }
- GLint GetUniColLoc() { return m_hUniCol; }
- GLint GetCoord0MatrixLoc() { return m_hCoord0Matrix; }
- + GLint GetModelLoc() { return m_hModel; }
- bool HardwareClipIsPossible() { return m_clipPossible; }
- GLfloat GetClipXFactor() { return m_clipXFactor; }
- GLfloat GetClipXOffset() { return m_clipXOffset; }
- diff --git a/xbmc/rendering/gles/RenderSystemGLES.cpp b/xbmc/rendering/gles/RenderSystemGLES.cpp
- index deb3afc..0904d1f 100644
- --- a/xbmc/rendering/gles/RenderSystemGLES.cpp
- +++ b/xbmc/rendering/gles/RenderSystemGLES.cpp
- @@ -691,4 +691,12 @@ bool CRenderSystemGLES::SupportsStereo(RENDER_STEREO_MODE mode)
- }
- }
-
- +GLint CRenderSystemGLES::GUIShaderGetModel()
- +{
- + if (m_pGUIshader[m_method])
- + return m_pGUIshader[m_method]->GetModelLoc();
- +
- + return -1;
- +}
- +
- #endif
- diff --git a/xbmc/rendering/gles/RenderSystemGLES.h b/xbmc/rendering/gles/RenderSystemGLES.h
- index 81ee49e..d2f9cd1 100644
- --- a/xbmc/rendering/gles/RenderSystemGLES.h
- +++ b/xbmc/rendering/gles/RenderSystemGLES.h
- @@ -91,6 +91,7 @@ class CRenderSystemGLES : public CRenderSystemBase
- GLint GUIShaderGetCoord1();
- GLint GUIShaderGetUniCol();
- GLint GUIShaderGetCoord0Matrix();
- + GLint GUIShaderGetModel();
-
- protected:
- virtual void SetVSyncImpl(bool enable) = 0;
- --
- 1.9.3
- From 473ccc4cbe616f672a72108d2ec98107780ac7da Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Wed, 29 Jan 2014 13:21:19 +0000
- Subject: [PATCH 28/94] Enable hardware clipping.
- ---
- xbmc/guilib/GUIFontTTF.cpp | 4 ++--
- xbmc/guilib/GUIFontTTF.h | 5 ++++-
- xbmc/guilib/GUIFontTTFGL.cpp | 6 ++++++
- 3 files changed, 12 insertions(+), 3 deletions(-)
- diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
- index ad0a53b..4dc4c8e 100644
- --- a/xbmc/guilib/GUIFontTTF.cpp
- +++ b/xbmc/guilib/GUIFontTTF.cpp
- @@ -459,10 +459,10 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
- cursorX += ch->advance;
- }
- if (hardwareClipping)
- - m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertices));
- + m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertices, g_graphicsContext.GetClipRegion()));
- }
- else if (hardwareClipping)
- - m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertices));
- + m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertices, g_graphicsContext.GetClipRegion()));
- if (!hardwareClipping)
- /* Append the new vertices (from the cache or otherwise) to the set collected
- * since the first Begin() call */
- diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
- index fde2085..5e7c31f 100644
- --- a/xbmc/guilib/GUIFontTTF.h
- +++ b/xbmc/guilib/GUIFontTTF.h
- @@ -27,6 +27,8 @@
- *
- */
-
- +#include "Geometry.h"
- +
- // forward definition
- class CBaseTexture;
-
- @@ -166,7 +168,8 @@ class CGUIFontTTFBase
- float translateY;
- float translateZ;
- const std::vector<SVertex> *vertexBuffer;
- - CTranslatedVertices(float translateX, float translateY, float translateZ, const std::vector<SVertex> *vertexBuffer) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer) {}
- + CRect clip;
- + CTranslatedVertices(float translateX, float translateY, float translateZ, const std::vector<SVertex> *vertexBuffer, const CRect &clip) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer), clip(clip) {}
- };
- std::vector<CTranslatedVertices> m_vertexTrans;
- std::vector<SVertex> m_vertex;
- diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
- index fbffaa0..b7618e1 100644
- --- a/xbmc/guilib/GUIFontTTFGL.cpp
- +++ b/xbmc/guilib/GUIFontTTFGL.cpp
- @@ -185,6 +185,10 @@ void CGUIFontTTFGL::LastEnd()
- std::vector<SVertex> vecVertices;
- for (size_t i = 0; i < m_vertexTrans.size(); i++)
- {
- + // Apply the clip rectangle
- + CRect clip = g_Windowing.ClipRectToScissorRect(m_vertexTrans[i].clip);
- + g_graphicsContext.SetScissors(clip);
- +
- // Apply the translation to the currently active (top-of-stack) model view matrix
- g_matrices.MatrixMode(MM_MODELVIEW);
- g_matrices.PushMatrix();
- @@ -212,6 +216,8 @@ void CGUIFontTTFGL::LastEnd()
-
- g_matrices.PopMatrix();
- }
- + // Restore the original scissor rectangle
- + g_graphicsContext.ResetScissors();
- // Restore the original model view matrix
- glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
- }
- --
- 1.9.3
- From f39c4523a1c05425fb94d3536a510709784f9558 Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Wed, 15 Jan 2014 15:32:51 +0000
- Subject: [PATCH 29/94] Move the vertex data across to a vertex buffer object
- just prior to drawing.
- ---
- xbmc/guilib/GUIFontTTFGL.cpp | 24 +++++++++++++++++++-----
- 1 file changed, 19 insertions(+), 5 deletions(-)
- diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
- index b7618e1..0df3749 100644
- --- a/xbmc/guilib/GUIFontTTFGL.cpp
- +++ b/xbmc/guilib/GUIFontTTFGL.cpp
- @@ -207,12 +207,24 @@ void CGUIFontTTFGL::LastEnd()
- }
- SVertex *vertices = &vecVertices[0];
-
- - glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x));
- - // Normalize color values. Does not affect Performance at all.
- - glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r));
- - glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u));
- -
- + // Generate a unique buffer object name and put it in vertexBuffer
- + GLuint vertexBuffer;
- + glGenBuffers(1, &vertexBuffer);
- + // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point
- + glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
- + // Create a data store for the buffer object bound to the GL_ARRAY_BUFFER
- + // binding point (i.e. our buffer object) and initialise it from the
- + // specified client-side pointer
- + glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof *vertices, vertices, GL_STATIC_DRAW);
- + // Set up the offsets of the various vertex attributes within the buffer
- + // object bound to GL_ARRAY_BUFFER
- + glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, x));
- + glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, r));
- + glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, u));
- + // Do the actual drawing operation, using the full set of vertices in the buffer
- glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
- + // Release the buffer name for reuse
- + glDeleteBuffers(1, &vertexBuffer);
-
- g_matrices.PopMatrix();
- }
- @@ -220,6 +232,8 @@ void CGUIFontTTFGL::LastEnd()
- g_graphicsContext.ResetScissors();
- // Restore the original model view matrix
- glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
- + // Unbind GL_ARRAY_BUFFER
- + glBindBuffer(GL_ARRAY_BUFFER, 0);
- }
-
- // Disable the attributes used by this shader
- --
- 1.9.3
- From 3c6c1c4f9c7aec0f41fd22d7d4e7f5918a70c69a Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Wed, 15 Jan 2014 16:04:04 +0000
- Subject: [PATCH 30/94] Move vertex data into an OpenGL VBO when the font cache
- entry is populated. The font cache now stores the "name" (handle) of the VBO,
- rather than a vector of vertices.
- ---
- xbmc/guilib/GUIFontCache.cpp | 6 ++++
- xbmc/guilib/GUIFontCache.h | 30 +++++++++++++++++-
- xbmc/guilib/GUIFontTTF.cpp | 15 +++++++--
- xbmc/guilib/GUIFontTTF.h | 7 +++--
- xbmc/guilib/GUIFontTTFGL.cpp | 74 ++++++++++++++++++++++++++++++--------------
- xbmc/guilib/GUIFontTTFGL.h | 5 +++
- 6 files changed, 107 insertions(+), 30 deletions(-)
- diff --git a/xbmc/guilib/GUIFontCache.cpp b/xbmc/guilib/GUIFontCache.cpp
- index b66c00b..895fa72 100644
- --- a/xbmc/guilib/GUIFontCache.cpp
- +++ b/xbmc/guilib/GUIFontCache.cpp
- @@ -111,3 +111,9 @@ template void CGUIFontCacheEntry<CGUIFontCacheDynamicPosition, CGUIFontCacheDyna
- template CGUIFontCacheEntry<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::~CGUIFontCacheEntry();
- template CGUIFontCacheDynamicValue &CGUIFontCache<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::Lookup(CGUIFontCacheDynamicPosition &, const vecColors &, const vecText &, uint32_t, float, bool, unsigned int, bool &);
- template void CGUIFontCache<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::Flush();
- +
- +void CVertexBuffer::clear()
- +{
- + if (m_font != NULL)
- + m_font->DestroyVertexBuffer(*this);
- +}
- diff --git a/xbmc/guilib/GUIFontCache.h b/xbmc/guilib/GUIFontCache.h
- index d913dee..ff766bf 100644
- --- a/xbmc/guilib/GUIFontCache.h
- +++ b/xbmc/guilib/GUIFontCache.h
- @@ -234,7 +234,35 @@ struct CGUIFontCacheDynamicPosition
- }
- };
-
- -typedef std::vector<SVertex> CGUIFontCacheDynamicValue;
- +struct CVertexBuffer
- +{
- + void *bufferHandle;
- + size_t size;
- + CVertexBuffer() : bufferHandle(NULL), size(0), m_font(NULL) {}
- + CVertexBuffer(void *bufferHandle, size_t size, const CGUIFontTTFBase *font) : bufferHandle(bufferHandle), size(size), m_font(font) {}
- + CVertexBuffer(const CVertexBuffer &other) : bufferHandle(other.bufferHandle), size(other.size), m_font(other.m_font)
- + {
- + /* In practice, the copy constructor is only called before a vertex buffer
- + * has been attached. If this should ever change, we'll need another support
- + * function in GUIFontTTFGL/DX to duplicate a buffer, given its handle. */
- + assert(other.bufferHandle == 0);
- + }
- + CVertexBuffer &operator=(CVertexBuffer &other)
- + {
- + /* This is used with move-assignment semantics for initialising the object in the font cache */
- + assert(bufferHandle == 0);
- + bufferHandle = other.bufferHandle;
- + other.bufferHandle = 0;
- + size = other.size;
- + m_font = other.m_font;
- + return *this;
- + }
- + void clear();
- +private:
- + const CGUIFontTTFBase *m_font;
- +};
- +
- +typedef CVertexBuffer CGUIFontCacheDynamicValue;
-
- inline bool Match(const CGUIFontCacheDynamicPosition &a, const TransformMatrix &a_m,
- const CGUIFontCacheDynamicPosition &b, const TransformMatrix &b_m,
- diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
- index 4dc4c8e..8b25306 100644
- --- a/xbmc/guilib/GUIFontTTF.cpp
- +++ b/xbmc/guilib/GUIFontTTF.cpp
- @@ -343,13 +343,18 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
- g_graphicsContext.ScaleFinalYCoord(x, y),
- g_graphicsContext.ScaleFinalZCoord(x, y));
- }
- - std::vector<SVertex> &vertices = hardwareClipping ?
- + CVertexBuffer unusedVertexBuffer;
- + CVertexBuffer &vertexBuffer = hardwareClipping ?
- m_dynamicCache.Lookup(dynamicPos,
- colors, text,
- alignment, maxPixelWidth,
- scrolling,
- XbmcThreads::SystemClockMillis(),
- dirtyCache) :
- + unusedVertexBuffer;
- + std::vector<SVertex> tempVertices;
- + std::vector<SVertex> &vertices = hardwareClipping ?
- + tempVertices :
- m_staticCache.Lookup(staticPos,
- colors, text,
- alignment, maxPixelWidth,
- @@ -459,10 +464,14 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
- cursorX += ch->advance;
- }
- if (hardwareClipping)
- - m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertices, g_graphicsContext.GetClipRegion()));
- + {
- + CVertexBuffer newVertexBuffer = CreateVertexBuffer(tempVertices);
- + vertexBuffer = newVertexBuffer;
- + m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertexBuffer, g_graphicsContext.GetClipRegion()));
- + }
- }
- else if (hardwareClipping)
- - m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertices, g_graphicsContext.GetClipRegion()));
- + m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertexBuffer, g_graphicsContext.GetClipRegion()));
- if (!hardwareClipping)
- /* Append the new vertices (from the cache or otherwise) to the set collected
- * since the first Begin() call */
- diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
- index 5e7c31f..b1cd525 100644
- --- a/xbmc/guilib/GUIFontTTF.h
- +++ b/xbmc/guilib/GUIFontTTF.h
- @@ -84,6 +84,9 @@ class CGUIFontTTFBase
-
- void Begin();
- void End();
- + /* The next two should only be called if we've declared we can do hardware clipping */
- + virtual CVertexBuffer CreateVertexBuffer(const std::vector<SVertex> &vertices) const { assert(false); return CVertexBuffer(); }
- + virtual void DestroyVertexBuffer(CVertexBuffer &bufferHandle) const {}
-
- const CStdString& GetFileName() const { return m_strFileName; };
-
- @@ -167,9 +170,9 @@ class CGUIFontTTFBase
- float translateX;
- float translateY;
- float translateZ;
- - const std::vector<SVertex> *vertexBuffer;
- + const CVertexBuffer *vertexBuffer;
- CRect clip;
- - CTranslatedVertices(float translateX, float translateY, float translateZ, const std::vector<SVertex> *vertexBuffer, const CRect &clip) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer), clip(clip) {}
- + CTranslatedVertices(float translateX, float translateY, float translateZ, const CVertexBuffer *vertexBuffer, const CRect &clip) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer), clip(clip) {}
- };
- std::vector<CTranslatedVertices> m_vertexTrans;
- std::vector<SVertex> m_vertex;
- diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
- index 0df3749..1cd684b7 100644
- --- a/xbmc/guilib/GUIFontTTFGL.cpp
- +++ b/xbmc/guilib/GUIFontTTFGL.cpp
- @@ -49,6 +49,10 @@ CGUIFontTTFGL::CGUIFontTTFGL(const CStdString& strFileName)
-
- CGUIFontTTFGL::~CGUIFontTTFGL(void)
- {
- + // It's important that all the CGUIFontCacheEntry objects are
- + // destructed before the CGUIFontTTFGL goes out of scope, because
- + // our virtual methods won't be accessible after this point
- + m_dynamicCache.Flush();
- }
-
- bool CGUIFontTTFGL::FirstBegin()
- @@ -182,7 +186,6 @@ void CGUIFontTTFGL::LastEnd()
- if (m_vertexTrans.size() > 0)
- {
- // Deal with the vertices that can be hardware clipped and therefore translated
- - std::vector<SVertex> vecVertices;
- for (size_t i = 0; i < m_vertexTrans.size(); i++)
- {
- // Apply the clip rectangle
- @@ -195,36 +198,17 @@ void CGUIFontTTFGL::LastEnd()
- g_matrices.Translatef(m_vertexTrans[i].translateX, m_vertexTrans[i].translateY, m_vertexTrans[i].translateZ);
- glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
-
- - vecVertices.clear();
- - for (size_t j = 0; j < m_vertexTrans[i].vertexBuffer->size(); j += 4)
- - {
- - vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j]);
- - vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1]);
- - vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2]);
- - vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1]);
- - vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+3]);
- - vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2]);
- - }
- - SVertex *vertices = &vecVertices[0];
- -
- - // Generate a unique buffer object name and put it in vertexBuffer
- - GLuint vertexBuffer;
- - glGenBuffers(1, &vertexBuffer);
- // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point
- - glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
- - // Create a data store for the buffer object bound to the GL_ARRAY_BUFFER
- - // binding point (i.e. our buffer object) and initialise it from the
- - // specified client-side pointer
- - glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof *vertices, vertices, GL_STATIC_DRAW);
- + glBindBuffer(GL_ARRAY_BUFFER, (GLuint) m_vertexTrans[i].vertexBuffer->bufferHandle);
- +
- // Set up the offsets of the various vertex attributes within the buffer
- // object bound to GL_ARRAY_BUFFER
- glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, x));
- glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, r));
- glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, u));
- +
- // Do the actual drawing operation, using the full set of vertices in the buffer
- - glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
- - // Release the buffer name for reuse
- - glDeleteBuffers(1, &vertexBuffer);
- + glDrawArrays(GL_TRIANGLES, 0, 6 * m_vertexTrans[i].vertexBuffer->size);
-
- g_matrices.PopMatrix();
- }
- @@ -245,6 +229,48 @@ void CGUIFontTTFGL::LastEnd()
- #endif
- }
-
- +#if HAS_GLES
- +CVertexBuffer CGUIFontTTFGL::CreateVertexBuffer(const std::vector<SVertex> &vertices) const
- +{
- + // Rearrange the vertices to describe triangles
- + std::vector<SVertex> triangleVertices;
- + triangleVertices.reserve(vertices.size() * 6 / 4);
- + for (size_t i = 0; i < vertices.size(); i += 4)
- + {
- + triangleVertices.push_back(vertices[i]);
- + triangleVertices.push_back(vertices[i+1]);
- + triangleVertices.push_back(vertices[i+2]);
- + triangleVertices.push_back(vertices[i+1]);
- + triangleVertices.push_back(vertices[i+3]);
- + triangleVertices.push_back(vertices[i+2]);
- + }
- +
- + // Generate a unique buffer object name and put it in bufferHandle
- + GLuint bufferHandle;
- + glGenBuffers(1, &bufferHandle);
- + // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point
- + glBindBuffer(GL_ARRAY_BUFFER, bufferHandle);
- + // Create a data store for the buffer object bound to the GL_ARRAY_BUFFER
- + // binding point (i.e. our buffer object) and initialise it from the
- + // specified client-side pointer
- + glBufferData(GL_ARRAY_BUFFER, triangleVertices.size() * sizeof (SVertex), &triangleVertices[0], GL_STATIC_DRAW);
- + // Unbind GL_ARRAY_BUFFER
- + glBindBuffer(GL_ARRAY_BUFFER, 0);
- +
- + return CVertexBuffer((void *) bufferHandle, vertices.size() / 4, this);
- +}
- +
- +void CGUIFontTTFGL::DestroyVertexBuffer(CVertexBuffer &buffer) const
- +{
- + if (buffer.bufferHandle != 0)
- + {
- + // Release the buffer name for reuse
- + glDeleteBuffers(1, (GLuint *) &buffer.bufferHandle);
- + buffer.bufferHandle = 0;
- + }
- +}
- +#endif
- +
- CBaseTexture* CGUIFontTTFGL::ReallocTexture(unsigned int& newHeight)
- {
- newHeight = CBaseTexture::PadPow2(newHeight);
- diff --git a/xbmc/guilib/GUIFontTTFGL.h b/xbmc/guilib/GUIFontTTFGL.h
- index 6736cf7..168fb21 100644
- --- a/xbmc/guilib/GUIFontTTFGL.h
- +++ b/xbmc/guilib/GUIFontTTFGL.h
- @@ -29,6 +29,7 @@
-
-
- #include "GUIFontTTF.h"
- +#include "system.h"
-
-
- /*!
- @@ -43,6 +44,10 @@ class CGUIFontTTFGL : public CGUIFontTTFBase
-
- virtual bool FirstBegin();
- virtual void LastEnd();
- +#if HAS_GLES
- + virtual CVertexBuffer CreateVertexBuffer(const std::vector<SVertex> &vertices) const;
- + virtual void DestroyVertexBuffer(CVertexBuffer &bufferHandle) const;
- +#endif
-
- protected:
- virtual CBaseTexture* ReallocTexture(unsigned int& newHeight);
- --
- 1.9.3
- From 073c09ba7de6f6b7676c83d71b6933790626874f Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Thu, 16 Jan 2014 16:29:42 +0000
- Subject: [PATCH 31/94] Switch from glDrawArrays() to glDrawElements(). This
- involves setting up a static VBO containing the indexes necessary to convert
- from quads to triangles on the fly in the GPU.
- ---
- xbmc/guilib/GUIFontTTFGL.cpp | 72 +++++++++++++++++++++++++------------
- xbmc/guilib/GUIFontTTFGL.h | 9 +++++
- xbmc/windowing/egl/WinSystemEGL.cpp | 17 +++++++++
- 3 files changed, 76 insertions(+), 22 deletions(-)
- diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
- index 1cd684b7..d476409 100644
- --- a/xbmc/guilib/GUIFontTTFGL.cpp
- +++ b/xbmc/guilib/GUIFontTTFGL.cpp
- @@ -186,6 +186,10 @@ void CGUIFontTTFGL::LastEnd()
- if (m_vertexTrans.size() > 0)
- {
- // Deal with the vertices that can be hardware clipped and therefore translated
- +
- + // Bind our pre-calculated array to GL_ELEMENT_ARRAY_BUFFER
- + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementArrayHandle);
- +
- for (size_t i = 0; i < m_vertexTrans.size(); i++)
- {
- // Apply the clip rectangle
- @@ -201,14 +205,21 @@ void CGUIFontTTFGL::LastEnd()
- // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point
- glBindBuffer(GL_ARRAY_BUFFER, (GLuint) m_vertexTrans[i].vertexBuffer->bufferHandle);
-
- - // Set up the offsets of the various vertex attributes within the buffer
- - // object bound to GL_ARRAY_BUFFER
- - glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, x));
- - glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, r));
- - glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, u));
- + // Do the actual drawing operation, split into groups of characters no
- + // larger than the pre-determined size of the element array
- + for (size_t character = 0; m_vertexTrans[i].vertexBuffer->size > character; character += ELEMENT_ARRAY_MAX_CHAR_INDEX)
- + {
- + size_t count = m_vertexTrans[i].vertexBuffer->size - character;
- + count = std::min<size_t>(count, ELEMENT_ARRAY_MAX_CHAR_INDEX);
- +
- + // Set up the offsets of the various vertex attributes within the buffer
- + // object bound to GL_ARRAY_BUFFER
- + glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) (character*sizeof(SVertex)*4 + offsetof(SVertex, x)));
- + glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (GLvoid *) (character*sizeof(SVertex)*4 + offsetof(SVertex, r)));
- + glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) (character*sizeof(SVertex)*4 + offsetof(SVertex, u)));
-
- - // Do the actual drawing operation, using the full set of vertices in the buffer
- - glDrawArrays(GL_TRIANGLES, 0, 6 * m_vertexTrans[i].vertexBuffer->size);
- + glDrawElements(GL_TRIANGLES, 6 * count, GL_UNSIGNED_SHORT, 0);
- + }
-
- g_matrices.PopMatrix();
- }
- @@ -216,8 +227,9 @@ void CGUIFontTTFGL::LastEnd()
- g_graphicsContext.ResetScissors();
- // Restore the original model view matrix
- glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
- - // Unbind GL_ARRAY_BUFFER
- + // Unbind GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- }
-
- // Disable the attributes used by this shader
- @@ -232,19 +244,6 @@ void CGUIFontTTFGL::LastEnd()
- #if HAS_GLES
- CVertexBuffer CGUIFontTTFGL::CreateVertexBuffer(const std::vector<SVertex> &vertices) const
- {
- - // Rearrange the vertices to describe triangles
- - std::vector<SVertex> triangleVertices;
- - triangleVertices.reserve(vertices.size() * 6 / 4);
- - for (size_t i = 0; i < vertices.size(); i += 4)
- - {
- - triangleVertices.push_back(vertices[i]);
- - triangleVertices.push_back(vertices[i+1]);
- - triangleVertices.push_back(vertices[i+2]);
- - triangleVertices.push_back(vertices[i+1]);
- - triangleVertices.push_back(vertices[i+3]);
- - triangleVertices.push_back(vertices[i+2]);
- - }
- -
- // Generate a unique buffer object name and put it in bufferHandle
- GLuint bufferHandle;
- glGenBuffers(1, &bufferHandle);
- @@ -253,7 +252,7 @@ CVertexBuffer CGUIFontTTFGL::CreateVertexBuffer(const std::vector<SVertex> &vert
- // Create a data store for the buffer object bound to the GL_ARRAY_BUFFER
- // binding point (i.e. our buffer object) and initialise it from the
- // specified client-side pointer
- - glBufferData(GL_ARRAY_BUFFER, triangleVertices.size() * sizeof (SVertex), &triangleVertices[0], GL_STATIC_DRAW);
- + glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof (SVertex), &vertices[0], GL_STATIC_DRAW);
- // Unbind GL_ARRAY_BUFFER
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-
- @@ -348,4 +347,33 @@ void CGUIFontTTFGL::DeleteHardwareTexture()
- }
- }
-
- +#if HAS_GLES
- +void CGUIFontTTFGL::CreateStaticVertexBuffers(void)
- +{
- + // Bind a new buffer to the OpenGL context's GL_ELEMENT_ARRAY_BUFFER binding point
- + glGenBuffers(1, &m_elementArrayHandle);
- + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementArrayHandle);
- + // Create an array holding the mesh indices to convert quads to triangles
- + GLushort index[ELEMENT_ARRAY_MAX_CHAR_INDEX][6];
- + for (size_t i = 0; i < ELEMENT_ARRAY_MAX_CHAR_INDEX; i++)
- + {
- + index[i][0] = 4*i;
- + index[i][1] = 4*i+1;
- + index[i][2] = 4*i+2;
- + index[i][3] = 4*i+1;
- + index[i][4] = 4*i+3;
- + index[i][5] = 4*i+2;
- + }
- + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof index, index, GL_STATIC_DRAW);
- + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- +}
- +
- +void CGUIFontTTFGL::DestroyStaticVertexBuffers(void)
- +{
- + glDeleteBuffers(1, &m_elementArrayHandle);
- +}
- +
- +GLuint CGUIFontTTFGL::m_elementArrayHandle;
- +#endif
- +
- #endif
- diff --git a/xbmc/guilib/GUIFontTTFGL.h b/xbmc/guilib/GUIFontTTFGL.h
- index 168fb21..a14ab7a 100644
- --- a/xbmc/guilib/GUIFontTTFGL.h
- +++ b/xbmc/guilib/GUIFontTTFGL.h
- @@ -30,6 +30,7 @@
-
- #include "GUIFontTTF.h"
- #include "system.h"
- +#include "system_gl.h"
-
-
- /*!
- @@ -47,6 +48,8 @@ class CGUIFontTTFGL : public CGUIFontTTFBase
- #if HAS_GLES
- virtual CVertexBuffer CreateVertexBuffer(const std::vector<SVertex> &vertices) const;
- virtual void DestroyVertexBuffer(CVertexBuffer &bufferHandle) const;
- + static void CreateStaticVertexBuffers(void);
- + static void DestroyStaticVertexBuffers(void);
- #endif
-
- protected:
- @@ -54,6 +57,12 @@ class CGUIFontTTFGL : public CGUIFontTTFBase
- virtual bool CopyCharToTexture(FT_BitmapGlyph bitGlyph, unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2);
- virtual void DeleteHardwareTexture();
-
- +#if HAS_GLES
- +#define ELEMENT_ARRAY_MAX_CHAR_INDEX (1000)
- +
- + static GLuint m_elementArrayHandle;
- +#endif
- +
- };
-
- #endif
- diff --git a/xbmc/windowing/egl/WinSystemEGL.cpp b/xbmc/windowing/egl/WinSystemEGL.cpp
- index dfc4672..0c32947 100644
- --- a/xbmc/windowing/egl/WinSystemEGL.cpp
- +++ b/xbmc/windowing/egl/WinSystemEGL.cpp
- @@ -29,6 +29,7 @@
- #include "settings/AdvancedSettings.h"
- #include "settings/Settings.h"
- #include "settings/DisplaySettings.h"
- +#include "guilib/GUIFontTTFGL.h"
- #include "utils/log.h"
- #include "EGLWrapper.h"
- #include "EGLQuirks.h"
- @@ -192,6 +193,9 @@ bool CWinSystemEGL::CreateWindow(RESOLUTION_INFO &res)
- return false;
- }
-
- +#if HAS_GLES
- + bool newContext = false;
- +#endif
- if (m_context == EGL_NO_CONTEXT)
- {
- if (!m_egl->CreateContext(m_display, m_config, contextAttrs, &m_context))
- @@ -199,6 +203,9 @@ bool CWinSystemEGL::CreateWindow(RESOLUTION_INFO &res)
- CLog::Log(LOGERROR, "%s: Could not create context",__FUNCTION__);
- return false;
- }
- +#if HAS_GLES
- + newContext = true;
- +#endif
- }
-
- if (!m_egl->BindContext(m_display, m_surface, m_context))
- @@ -207,6 +214,11 @@ bool CWinSystemEGL::CreateWindow(RESOLUTION_INFO &res)
- return false;
- }
-
- +#if HAS_GLES
- + if (newContext)
- + CGUIFontTTFGL::CreateStaticVertexBuffers();
- +#endif
- +
- // for the non-trivial dirty region modes, we need the EGL buffer to be preserved across updates
- if (g_advancedSettings.m_guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_COST_REDUCTION ||
- g_advancedSettings.m_guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_UNION)
- @@ -228,7 +240,12 @@ bool CWinSystemEGL::DestroyWindowSystem()
- DestroyWindow();
-
- if (m_context != EGL_NO_CONTEXT)
- + {
- +#if HAS_GLES
- + CGUIFontTTFGL::DestroyStaticVertexBuffers();
- +#endif
- m_egl->DestroyContext(m_display, m_context);
- + }
- m_context = EGL_NO_CONTEXT;
-
- if (m_display != EGL_NO_DISPLAY)
- --
- 1.9.3
- From ec39dce3628b276e3ed2fe19c95a056a1aa171b8 Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Tue, 4 Feb 2014 16:17:57 +0000
- Subject: [PATCH 32/94] Update Windows project files
- ---
- project/VS2010Express/XBMC.vcxproj | 2 ++
- project/VS2010Express/XBMC.vcxproj.filters | 6 ++++++
- 2 files changed, 8 insertions(+)
- diff --git a/project/VS2010Express/XBMC.vcxproj b/project/VS2010Express/XBMC.vcxproj
- index c6de5ca..a9731de 100644
- --- a/project/VS2010Express/XBMC.vcxproj
- +++ b/project/VS2010Express/XBMC.vcxproj
- @@ -540,6 +540,7 @@
- <ClCompile Include="..\..\xbmc\guilib\GUIFadeLabelControl.cpp" />
- <ClCompile Include="..\..\xbmc\guilib\GUIFixedListContainer.cpp" />
- <ClCompile Include="..\..\xbmc\guilib\GUIFont.cpp" />
- + <ClCompile Include="..\..\xbmc\guilib\GUIFontCache.cpp" />
- <ClCompile Include="..\..\xbmc\guilib\GUIFontManager.cpp" />
- <ClCompile Include="..\..\xbmc\guilib\GUIFontTTF.cpp" />
- <ClCompile Include="..\..\xbmc\guilib\GUIFontTTFDX.cpp" />
- @@ -2057,6 +2058,7 @@
- <ClInclude Include="..\..\xbmc\guilib\GUIFadeLabelControl.h" />
- <ClInclude Include="..\..\xbmc\guilib\GUIFixedListContainer.h" />
- <ClInclude Include="..\..\xbmc\guilib\GUIFont.h" />
- + <ClInclude Include="..\..\xbmc\guilib\GUIFontCache.h" />
- <ClInclude Include="..\..\xbmc\guilib\GUIFontManager.h" />
- <ClInclude Include="..\..\xbmc\guilib\GUIFontTTF.h" />
- <ClInclude Include="..\..\xbmc\guilib\GUIFontTTFDX.h" />
- diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters
- index b536eb3..cb34443 100644
- --- a/project/VS2010Express/XBMC.vcxproj.filters
- +++ b/project/VS2010Express/XBMC.vcxproj.filters
- @@ -1024,6 +1024,9 @@
- <ClCompile Include="..\..\xbmc\guilib\GUIFont.cpp">
- <Filter>guilib</Filter>
- </ClCompile>
- + <ClCompile Include="..\..\xbmc\guilib\GUIFontCache.cpp">
- + <Filter>guilib</Filter>
- + </ClCompile>
- <ClCompile Include="..\..\xbmc\guilib\GUIFontManager.cpp">
- <Filter>guilib</Filter>
- </ClCompile>
- @@ -3978,6 +3981,9 @@
- <ClInclude Include="..\..\xbmc\guilib\GUIFont.h">
- <Filter>guilib</Filter>
- </ClInclude>
- + <ClInclude Include="..\..\xbmc\guilib\GUIFontCache.h">
- + <Filter>guilib</Filter>
- + </ClInclude>
- <ClInclude Include="..\..\xbmc\guilib\GUIFontManager.h">
- <Filter>guilib</Filter>
- </ClInclude>
- --
- 1.9.3
- From e25eb385d09a5378be8616f10806610df90416db Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Tue, 4 Feb 2014 16:49:45 +0000
- Subject: [PATCH 33/94] Update XCode project file
- ---
- XBMC.xcodeproj/project.pbxproj | 10 ++++++++++
- 1 file changed, 10 insertions(+)
- diff --git a/XBMC.xcodeproj/project.pbxproj b/XBMC.xcodeproj/project.pbxproj
- index fdd10a1..62e7e69 100644
- --- a/XBMC.xcodeproj/project.pbxproj
- +++ b/XBMC.xcodeproj/project.pbxproj
- @@ -168,6 +168,9 @@
- 1D638128161E211E003603ED /* PeripheralImon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1D638126161E211E003603ED /* PeripheralImon.cpp */; };
- 1DAFDB7C16DFDCA7007F8C68 /* PeripheralBusCEC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1DAFDB7A16DFDCA7007F8C68 /* PeripheralBusCEC.cpp */; };
- 1DE0443515828F4B005DDB4D /* Exception.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1DE0443315828F4B005DDB4D /* Exception.cpp */; };
- + 2FD7EC5F18A14FE50047F86C /* GUIFontCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2FD7EC5D18A14FE50047F86C /* GUIFontCache.cpp */; };
- + 2FD7EC6018A14FE50047F86C /* GUIFontCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2FD7EC5D18A14FE50047F86C /* GUIFontCache.cpp */; };
- + 2FD7EC6118A14FE50047F86C /* GUIFontCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2FD7EC5D18A14FE50047F86C /* GUIFontCache.cpp */; };
- 32C631281423A90F00F18420 /* JpegIO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 32C631261423A90F00F18420 /* JpegIO.cpp */; };
- 36A9443D15821E2800727135 /* DatabaseUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9443B15821E2800727135 /* DatabaseUtils.cpp */; };
- 36A9444115821E7C00727135 /* SortUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9443F15821E7C00727135 /* SortUtils.cpp */; };
- @@ -3546,6 +3549,8 @@
- 1DAFDB7B16DFDCA7007F8C68 /* PeripheralBusCEC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PeripheralBusCEC.h; sourceTree = "<group>"; };
- 1DE0443315828F4B005DDB4D /* Exception.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Exception.cpp; path = commons/Exception.cpp; sourceTree = "<group>"; };
- 1DE0443415828F4B005DDB4D /* Exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Exception.h; path = commons/Exception.h; sourceTree = "<group>"; };
- + 2FD7EC5D18A14FE50047F86C /* GUIFontCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIFontCache.cpp; sourceTree = "<group>"; };
- + 2FD7EC5E18A14FE50047F86C /* GUIFontCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIFontCache.h; sourceTree = "<group>"; };
- 32C631261423A90F00F18420 /* JpegIO.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JpegIO.cpp; sourceTree = "<group>"; };
- 32C631271423A90F00F18420 /* JpegIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JpegIO.h; sourceTree = "<group>"; };
- 36A9443B15821E2800727135 /* DatabaseUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DatabaseUtils.cpp; sourceTree = "<group>"; };
- @@ -5923,6 +5928,8 @@
- 18B7C76A1294222E009E7A26 /* GUIFixedListContainer.cpp */,
- 18B7C7101294222D009E7A26 /* GUIFixedListContainer.h */,
- 18B7C76B1294222E009E7A26 /* GUIFont.cpp */,
- + 2FD7EC5D18A14FE50047F86C /* GUIFontCache.cpp */,
- + 2FD7EC5E18A14FE50047F86C /* GUIFontCache.h */,
- 18B7C7111294222D009E7A26 /* GUIFont.h */,
- 18B7C76C1294222E009E7A26 /* GUIFontManager.cpp */,
- 18B7C7121294222D009E7A26 /* GUIFontManager.h */,
- @@ -10930,6 +10937,7 @@
- 7C8AE850189DE3CD00C33786 /* CoreAudioHardware.cpp in Sources */,
- 7C8AE851189DE3CD00C33786 /* CoreAudioStream.cpp in Sources */,
- 7C8AE854189DE47F00C33786 /* CoreAudioHelpers.cpp in Sources */,
- + 2FD7EC5F18A14FE50047F86C /* GUIFontCache.cpp in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- @@ -11978,6 +11986,7 @@
- F5CC234818150277006B5E91 /* AESinkNULL.cpp in Sources */,
- F5CC238918150768006B5E91 /* AESinkProfiler.cpp in Sources */,
- DF374B2518AC2BA20076B514 /* CoreAudioHelpers.cpp in Sources */,
- + 2FD7EC6118A14FE50047F86C /* GUIFontCache.cpp in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- @@ -13028,6 +13037,7 @@
- F5CC234718150277006B5E91 /* AESinkNULL.cpp in Sources */,
- F5CC238818150768006B5E91 /* AESinkProfiler.cpp in Sources */,
- DF374B2418AC2BA20076B514 /* CoreAudioHelpers.cpp in Sources */,
- + 2FD7EC6018A14FE50047F86C /* GUIFontCache.cpp in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- --
- 1.9.3
- From 5f4ebd2e9fd6d503220627b916e522b671d7d9ba Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Tue, 4 Feb 2014 17:44:34 +0000
- Subject: [PATCH 34/94] Clang seems to be more picky than gcc about some C++
- template syntax
- ---
- xbmc/guilib/GUIFontCache.cpp | 20 ++++++++++----------
- 1 file changed, 10 insertions(+), 10 deletions(-)
- diff --git a/xbmc/guilib/GUIFontCache.cpp b/xbmc/guilib/GUIFontCache.cpp
- index 895fa72..bd84b9a 100644
- --- a/xbmc/guilib/GUIFontCache.cpp
- +++ b/xbmc/guilib/GUIFontCache.cpp
- @@ -61,26 +61,26 @@ Value &CGUIFontCache<Position, Value>::Lookup(Position &pos,
- alignment, maxPixelWidth,
- scrolling, g_graphicsContext.GetGUIMatrix(),
- g_graphicsContext.GetGUIScaleX(), g_graphicsContext.GetGUIScaleY());
- - EntryHashIterator i = m_list.get<Hash>().find(key);
- - if (i == m_list.get<Hash>().end())
- + EntryHashIterator i = m_list.template get<Hash>().find(key);
- + if (i == m_list.template get<Hash>().end())
- {
- /* Cache miss */
- - EntryAgeIterator oldest = m_list.get<Age>().begin();
- - if (!m_list.get<Age>().empty() && nowMillis - oldest->m_lastUsedMillis > FONT_CACHE_TIME_LIMIT)
- + EntryAgeIterator oldest = m_list.template get<Age>().begin();
- + if (!m_list.template get<Age>().empty() && nowMillis - oldest->m_lastUsedMillis > FONT_CACHE_TIME_LIMIT)
- {
- /* The oldest existing entry is old enough to expire and reuse */
- - m_list.get<Hash>().modify(m_list.project<Hash>(oldest), typename CGUIFontCacheEntry<Position, Value>::Reassign(key, nowMillis));
- - m_list.get<Age>().relocate(m_list.get<Age>().end(), oldest);
- + m_list.template get<Hash>().modify(m_list.template project<Hash>(oldest), typename CGUIFontCacheEntry<Position, Value>::Reassign(key, nowMillis));
- + m_list.template get<Age>().relocate(m_list.template get<Age>().end(), oldest);
- }
- else
- {
- /* We need a new entry instead */
- /* Yes, this causes the creation an destruction of a temporary entry, but
- * this code ought to only be used infrequently, when the cache needs to grow */
- - m_list.get<Age>().push_back(CGUIFontCacheEntry<Position, Value>(*this, key, nowMillis));
- + m_list.template get<Age>().push_back(CGUIFontCacheEntry<Position, Value>(*this, key, nowMillis));
- }
- dirtyCache = true;
- - return (--m_list.get<Age>().end())->m_value;
- + return (--m_list.template get<Age>().end())->m_value;
- }
- else
- {
- @@ -90,7 +90,7 @@ Value &CGUIFontCache<Position, Value>::Lookup(Position &pos,
- pos.UpdateWithOffsets(i->m_key.m_pos, scrolling);
- /* Update time in entry and move to the back of the list */
- i->m_lastUsedMillis = nowMillis;
- - m_list.get<Age>().relocate(m_list.get<Age>().end(), m_list.project<Age>(i));
- + m_list.template get<Age>().relocate(m_list.template get<Age>().end(), m_list.template project<Age>(i));
- dirtyCache = false;
- return i->m_value;
- }
- @@ -99,7 +99,7 @@ Value &CGUIFontCache<Position, Value>::Lookup(Position &pos,
- template<class Position, class Value>
- void CGUIFontCache<Position, Value>::Flush()
- {
- - m_list.get<Age>().clear();
- + m_list.template get<Age>().clear();
- }
-
- template void CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Reassign::operator()(CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue> &entry);
- --
- 1.9.3
- From 33693dc9ff9ba7695bc0e702a41566d54a5135b9 Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Tue, 4 Feb 2014 18:52:14 +0000
- Subject: [PATCH 35/94] Fix header to hopefully permit iOS builds to work
- again. GUIShader.cpp added #include windowing/egl/WinSystemEGL.h inside a but
- also need the header windowing/osx/WinSystemIOS.h instead. The only thing
- GUIShader.cpp needed was g_windowing.GetViewPort, which is provided by the
- common base class CRenderSystemGLES of g_windowing in both cases, so I think
- it should be sufficient to use windowing/WindowingFactory.h instead, which is
- abstracted away from the other header files.
- ---
- xbmc/guilib/GUIShader.cpp | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
- diff --git a/xbmc/guilib/GUIShader.cpp b/xbmc/guilib/GUIShader.cpp
- index 53bce09..86330cc 100644
- --- a/xbmc/guilib/GUIShader.cpp
- +++ b/xbmc/guilib/GUIShader.cpp
- @@ -26,7 +26,7 @@
- #include "GUIShader.h"
- #include "MatrixGLES.h"
- #include "utils/log.h"
- -#include "windowing/egl/WinSystemEGL.h"
- +#include "windowing/WindowingFactory.h"
- #include "guilib/GraphicContext.h"
-
- CGUIShader::CGUIShader( const char *shader ) : CGLSLShaderProgram("guishader_vert.glsl", shader)
- --
- 1.9.3
- From 9b95b3b13bd714d8320dc61c5039eee6cb3c5737 Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Tue, 8 Apr 2014 18:14:55 +0100
- Subject: [PATCH 36/94] Fix font display in stereoscopic modes
- CGUIFontTTFGL::LastEnd was previously using the relatively high-level
- CGraphicContext::SetScissors function to enforce hardware clipping. However,
- the coordinates it passed in already contained the stereoscopic offset, so
- the CGraphicContext::SetScissors effectively ended up double-applying the
- offset, with the effect that clip rectangles were always off-screen. Changed
- to call the low-level SetScissors call instead (using g_Windowing to select
- the correct implementation, e.g. CRenderSystemGLES::SetScissors). This also
- skips the intersection of the scissors with the screen limits, but that does
- not appear to matter in practice.
- ---
- xbmc/guilib/GUIFontTTFGL.cpp | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
- diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
- index d476409..8466a81 100644
- --- a/xbmc/guilib/GUIFontTTFGL.cpp
- +++ b/xbmc/guilib/GUIFontTTFGL.cpp
- @@ -194,7 +194,7 @@ void CGUIFontTTFGL::LastEnd()
- {
- // Apply the clip rectangle
- CRect clip = g_Windowing.ClipRectToScissorRect(m_vertexTrans[i].clip);
- - g_graphicsContext.SetScissors(clip);
- + g_Windowing.SetScissors(clip);
-
- // Apply the translation to the currently active (top-of-stack) model view matrix
- g_matrices.MatrixMode(MM_MODELVIEW);
- @@ -224,7 +224,7 @@ void CGUIFontTTFGL::LastEnd()
- g_matrices.PopMatrix();
- }
- // Restore the original scissor rectangle
- - g_graphicsContext.ResetScissors();
- + g_Windowing.ResetScissors();
- // Restore the original model view matrix
- glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
- // Unbind GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER
- --
- 1.9.3
- From d51ef43b61b50de46edb2832f457af8229995cab Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Fri, 10 Jan 2014 12:10:43 +0000
- Subject: [PATCH 37/94] [rbp] Don't override dvdplayer with omxplayer.
- Using dvdplayer can be useful on the Pi. We can actually play sd (up to 640x480 MPEG-4 video) video in real time.
- This is useful for codec variants like DivX3 which we don't currently play.
- This may expose bugs where dvdplayer is incorrectly used as the default player which will need to be fixed
- ---
- xbmc/cores/playercorefactory/PlayerCoreConfig.h | 7 -------
- 1 file changed, 7 deletions(-)
- diff --git a/xbmc/cores/playercorefactory/PlayerCoreConfig.h b/xbmc/cores/playercorefactory/PlayerCoreConfig.h
- index 27f0bec..fc12bb7 100644
- --- a/xbmc/cores/playercorefactory/PlayerCoreConfig.h
- +++ b/xbmc/cores/playercorefactory/PlayerCoreConfig.h
- @@ -88,14 +88,7 @@ friend class CPlayerCoreFactory;
- {
- case EPC_MPLAYER:
- // TODO: this hack needs removal until we have a better player selection
- -#if defined(HAS_OMXPLAYER)
- - case EPC_DVDPLAYER:
- - pPlayer = new COMXPlayer(callback);
- - CLog::Log(LOGINFO, "Created player %s for core %d / OMXPlayer forced as DVDPlayer", "OMXPlayer", m_eCore);
- - break;
- -#else
- case EPC_DVDPLAYER: pPlayer = new CDVDPlayer(callback); break;
- -#endif
- case EPC_PAPLAYER: pPlayer = new PAPlayer(callback); break;
- case EPC_EXTPLAYER: pPlayer = new CExternalPlayer(callback); break;
- #if defined(HAS_OMXPLAYER)
- --
- 1.9.3
- From 3cd01da5418f1693e50ed40273cb17ca9f6d622a Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Fri, 10 Jan 2014 15:37:41 +0000
- Subject: [PATCH 38/94] [players] Use default players rather than hard coded
- DVDPlayer/PAPlayer
- ---
- system/playercorefactory.xml | 23 ++++++++++++-----------
- 1 file changed, 12 insertions(+), 11 deletions(-)
- diff --git a/system/playercorefactory.xml b/system/playercorefactory.xml
- index 57dfcdd..7be9799 100644
- --- a/system/playercorefactory.xml
- +++ b/system/playercorefactory.xml
- @@ -11,31 +11,32 @@
- </players>
-
- <rules name="system rules">
- - <rule name="rtv" protocols="rtv" player="DVDPlayer" />
- - <rule name="hdhomerun/myth/mms/udp" protocols="hdhomerun|myth|cmyth|mms|mmsh|udp" player="DVDPlayer" />
- - <rule name="lastfm/shout" protocols="lastfm|shout" player="PAPlayer" />
- + <rule name="rtv" protocols="rtv" player="videodefaultplayer" />
- + <rule name="hdhomerun/myth/mms/udp" protocols="hdhomerun|myth|cmyth|mms|mmsh|udp" player="videodefaultplayer" />
- + <rule name="lastfm/shout" protocols="lastfm|shout" player="audiodefaultplayer" />
- <rule name="rtmp" protocols="rtmp" player="videodefaultplayer" />
-
- <!-- dvdplayer can play standard rtsp streams -->
- - <rule name="rtsp" protocols="rtsp" filetypes="!(rm|ra)" player="PAPlayer" />
- + <rule name="rtsp" protocols="rtsp" filetypes="!(rm|ra)" player="audiodefaultplayer" />
-
- <!-- Internet streams -->
- <rule name="streams" internetstream="true">
- - <rule name="aacp/sdp" mimetypes="audio/aacp|application/sdp" player="DVDPlayer" />
- - <rule name="mp2" mimetypes="application/octet-stream" filetypes="mp2" player="PAPlayer" />
- + <rule name="aacp/sdp" mimetypes="audio/aacp|application/sdp" player="videodefaultplayer" />
- + <rule name="mp2" mimetypes="application/octet-stream" filetypes="mp2" player="audiodefaultplayer" />
- </rule>
-
- <!-- DVDs -->
- - <rule name="dvd" dvd="true" player="DVDPlayer" />
- - <rule name="dvdimage" dvdimage="true" player="DVDPlayer" />
- + <rule name="dvd" dvd="true" player="videodefaultdvdplayer" />
- + <rule name="dvdfile" dvdfile="true" player="videodefaultdvdplayer" />
- + <rule name="dvdimage" dvdimage="true" player="videodefaultdvdplayer" />
-
- <!-- Only dvdplayer can handle these normally -->
- - <rule name="sdp/asf" filetypes="sdp|asf" player="DVDPlayer" />
- + <rule name="sdp/asf" filetypes="sdp|asf" player="videodefaultplayer" />
-
- <!-- Pass these to dvdplayer as we do not know if they are audio or video -->
- - <rule name="nsv" filetypes="nsv" player="DVDPlayer" />
- + <rule name="nsv" filetypes="nsv" player="videodefaultplayer" />
-
- <!-- pvr radio channels should be played by dvdplayer because they need buffering -->
- - <rule name="radio" filetypes="pvr" filename=".*/radio/.*" player="DVDPlayer" />
- + <rule name="radio" filetypes="pvr" filename=".*/radio/.*" player="videodefaultplayer" />
- </rules>
- </playercorefactory>
- --
- 1.9.3
- From 5c4de293325bba93c4b820aed6863ee8d732ce2c Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Sat, 11 Jan 2014 18:23:42 +0000
- Subject: [PATCH 39/94] [rbp] Don't force dvdplayer for airplay
- ---
- xbmc/network/AirPlayServer.cpp | 2 ++
- 1 file changed, 2 insertions(+)
- diff --git a/xbmc/network/AirPlayServer.cpp b/xbmc/network/AirPlayServer.cpp
- index 8040d9b..182daaa 100644
- --- a/xbmc/network/AirPlayServer.cpp
- +++ b/xbmc/network/AirPlayServer.cpp
- @@ -906,9 +906,11 @@ int CAirPlayServer::CTCPClient::ProcessRequest( CStdString& responseHeader,
- CFileItem fileToPlay(location, false);
- fileToPlay.SetProperty("StartPercent", position*100.0f);
- ServerInstance->AnnounceToClients(EVENT_LOADING);
- +#ifndef TARGET_RASPBERRY_PI
- // froce to internal dvdplayer cause it is the only
- // one who will work well with airplay
- g_application.m_eForcedNextPlayer = EPC_DVDPLAYER;
- +#endif
- CApplicationMessenger::Get().MediaPlay(fileToPlay);
- }
- }
- --
- 1.9.3
- From 454b77543018aac5d7e70769ef13231ae16eefb9 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Mon, 13 Jan 2014 13:11:06 +0000
- Subject: [PATCH 40/94] [rbp] Give plugins omxplayer when they request
- dvdplayer on pi
- ---
- xbmc/interfaces/legacy/ModuleXbmc.cpp | 4 ++++
- 1 file changed, 4 insertions(+)
- diff --git a/xbmc/interfaces/legacy/ModuleXbmc.cpp b/xbmc/interfaces/legacy/ModuleXbmc.cpp
- index 16f0174..b172d47 100644
- --- a/xbmc/interfaces/legacy/ModuleXbmc.cpp
- +++ b/xbmc/interfaces/legacy/ModuleXbmc.cpp
- @@ -536,7 +536,11 @@ namespace XBMCAddon
- int getPLAYLIST_MUSIC() { return PLAYLIST_MUSIC; }
- int getPLAYLIST_VIDEO() { return PLAYLIST_VIDEO; }
- int getPLAYER_CORE_AUTO() { return EPC_NONE; }
- +#ifdef TARGET_RASPBERRY_PI
- + int getPLAYER_CORE_DVDPLAYER() { return EPC_OMXPLAYER; }
- +#else
- int getPLAYER_CORE_DVDPLAYER() { return EPC_DVDPLAYER; }
- +#endif
- int getPLAYER_CORE_MPLAYER() { return EPC_MPLAYER; }
- int getPLAYER_CORE_PAPLAYER() { return EPC_PAPLAYER; }
- int getTRAY_OPEN() { return TRAY_OPEN; }
- --
- 1.9.3
- From 7201ee3e0ca664518eaaf3142682b294c34c69c0 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Tue, 14 Jan 2014 18:04:07 +0000
- Subject: [PATCH 41/94] [rbp] Allow ALSA to be chosen in addition to Pi sink
- Needs --enable-alsa in ./configure step and alsa support on platform
- ---
- configure.in | 1 -
- tools/depends/target/Makefile | 6 +++---
- xbmc/cores/AudioEngine/AESinkFactory.cpp | 17 +++++++++++++++--
- 3 files changed, 18 insertions(+), 6 deletions(-)
- diff --git a/configure.in b/configure.in
- index a195d00..34dd038 100644
- --- a/configure.in
- +++ b/configure.in
- @@ -742,7 +742,6 @@ case $use_platform in
- use_arch="arm"
- use_cpu=arm1176jzf-s
- use_hardcoded_tables="yes"
- - use_alsa="no"
- ARCH="arm"
- AC_DEFINE(HAS_EGLGLES, [1], [Define if supporting EGL based GLES Framebuffer])
- USE_OMXLIB=1; AC_DEFINE([HAVE_OMXLIB],[1],["Define to 1 if OMX libs is enabled"])
- diff --git a/tools/depends/target/Makefile b/tools/depends/target/Makefile
- index 4588917..0fbd3e7 100644
- --- a/tools/depends/target/Makefile
- +++ b/tools/depends/target/Makefile
- @@ -55,10 +55,10 @@ endif
- ALSA_LIB=
- LINUX_SYSTEM_LIBS=
- ifeq ($(OS),linux)
- - #not for raspberry pi
- + DEPENDS += alsa-lib
- + ALSA_LIB = alsa-lib
- ifneq ($(CPU),arm)
- - DEPENDS += alsa-lib libsdl linux-system-libs
- - ALSA_LIB = alsa-lib
- + DEPENDS += libsdl linux-system-libs
- LINUX_SYSTEM_LIBS = linux-system-libs
- endif
- endif
- diff --git a/xbmc/cores/AudioEngine/AESinkFactory.cpp b/xbmc/cores/AudioEngine/AESinkFactory.cpp
- index e493123..7df6807 100644
- --- a/xbmc/cores/AudioEngine/AESinkFactory.cpp
- +++ b/xbmc/cores/AudioEngine/AESinkFactory.cpp
- @@ -27,6 +27,7 @@
- #include "Sinks/AESinkAUDIOTRACK.h"
- #elif defined(TARGET_RASPBERRY_PI)
- #include "Sinks/AESinkPi.h"
- + #include "Sinks/AESinkALSA.h"
- #elif defined(TARGET_DARWIN_IOS)
- #include "Sinks/AESinkDARWINIOS.h"
- #elif defined(TARGET_DARWIN_OSX)
- @@ -66,6 +67,7 @@ void CAESinkFactory::ParseDevice(std::string &device, std::string &driver)
- driver == "AUDIOTRACK" ||
- #elif defined(TARGET_RASPBERRY_PI)
- driver == "PI" ||
- + driver == "ALSA" ||
- #elif defined(TARGET_DARWIN_IOS)
- driver == "DARWINIOS" ||
- #elif defined(TARGET_DARWIN_OSX)
- @@ -104,7 +106,12 @@ IAESink *CAESinkFactory::TrySink(std::string &driver, std::string &device, AEAud
- #elif defined(TARGET_ANDROID)
- sink = new CAESinkAUDIOTRACK();
- #elif defined(TARGET_RASPBERRY_PI)
- - sink = new CAESinkPi();
- + else if (driver == "PI")
- + sink = new CAESinkPi();
- + #if defined(HAS_ALSA)
- + else if (driver == "ALSA")
- + sink = new CAESinkALSA();
- + #endif
- #elif defined(TARGET_DARWIN_IOS)
- sink = new CAESinkDARWINIOS();
- #elif defined(TARGET_DARWIN_OSX)
- @@ -194,7 +201,13 @@ void CAESinkFactory::EnumerateEx(AESinkInfoList &list, bool force)
- CAESinkPi::EnumerateDevicesEx(info.m_deviceInfoList, force);
- if(!info.m_deviceInfoList.empty())
- list.push_back(info);
- -
- + #if defined(HAS_ALSA)
- + info.m_deviceInfoList.clear();
- + info.m_sinkName = "ALSA";
- + CAESinkALSA::EnumerateDevicesEx(info.m_deviceInfoList, force);
- + if(!info.m_deviceInfoList.empty())
- + list.push_back(info);
- + #endif
- #elif defined(TARGET_DARWIN_IOS)
-
- info.m_deviceInfoList.clear();
- --
- 1.9.3
- From 8ffa85ccdc4760751849d75d37924fbf6cb1b1c8 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Thu, 16 Jan 2014 01:39:29 +0000
- Subject: [PATCH 42/94] [omxcodec] Add hardware decode to dvdplayer for Pi
- Hijack the abandoned OpenMaxVideo codec
- ---
- configure.in | 21 +-
- xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 12 +-
- xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 6 +-
- xbmc/cores/VideoRenderers/RenderManager.cpp | 2 +-
- xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp | 7 +-
- .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 7 +-
- .../DVDCodecs/Video/DVDVideoCodecOpenMax.cpp | 295 +---
- .../DVDCodecs/Video/DVDVideoCodecOpenMax.h | 34 +-
- xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in | 1 -
- xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMax.cpp | 269 ----
- xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMax.h | 116 --
- .../dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 1418 ++++++++++----------
- .../cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h | 120 +-
- xbmc/cores/dvdplayer/DVDPlayer.cpp | 2 +
- xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 21 +-
- xbmc/linux/OMXCore.cpp | 45 +-
- xbmc/linux/OMXCore.h | 2 +-
- 17 files changed, 894 insertions(+), 1484 deletions(-)
- delete mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMax.cpp
- delete mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMax.h
- diff --git a/configure.in b/configure.in
- index 34dd038..e7550c0 100644
- --- a/configure.in
- +++ b/configure.in
- @@ -1956,9 +1956,24 @@ if test "$host_vendor" = "apple" ; then
- USE_OPENMAX=0
- AC_MSG_NOTICE($openmax_disabled)
- elif test "$target_platform" = "target_raspberry_pi"; then
- - use_openmax="no"
- - USE_OPENMAX=0
- - AC_MSG_NOTICE($openmax_disabled)
- + if test "$use_gles" = "yes" && test "$use_openmax" = "auto"; then
- + use_openmax="yes"
- + USE_OPENMAX=1
- + HAVE_LIBOPENMAX=1
- + AC_DEFINE([HAVE_LIBOPENMAX], [1], [Define to 1 if you have the 'LIBOPENMAX' library.])
- + AC_DEFINE([OMX_SKIP64BIT], [1], [Define to 1 if you have the 'LIBOPENMAX' library.])
- + AC_MSG_NOTICE($openmax_enabled)
- + elif test "$use_gles" = "yes" && test "$use_openmax" = "yes"; then
- + use_openmax="yes"
- + USE_OPENMAX=1
- + HAVE_LIBOPENMAX=1
- + AC_DEFINE([HAVE_LIBOPENMAX], [1], [Define to 1 if you have the 'LIBOPENMAX' library.])
- + AC_MSG_NOTICE($openmax_enabled)
- + else
- + AC_MSG_NOTICE($openmax_disabled)
- + use_openmax=no
- + USE_OPENMAX=0
- + fi
- else
- if test "$use_gles" = "yes" && test "$use_openmax" = "auto"; then
- PKG_CHECK_MODULES([OPENMAX], [libomxil-bellagio],
- diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
- index 30c0601..6d879e3 100644
- --- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
- +++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
- @@ -44,7 +44,7 @@
- #include "windowing/WindowingFactory.h"
- #include "guilib/Texture.h"
- #include "lib/DllSwScale.h"
- -#include "../dvdplayer/DVDCodecs/Video/OpenMaxVideo.h"
- +#include "DVDCodecs/Video/OpenMaxVideo.h"
- #include "threads/SingleLock.h"
- #include "RenderCapture.h"
- #include "RenderFormats.h"
- @@ -1330,6 +1330,10 @@ void CLinuxRendererGLES::RenderOpenMax(int index, int field)
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(m_textureTarget, textureId);
-
- + GLint filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR;
- + glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter);
- + glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter);
- +
- g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA);
-
- GLubyte idx[4] = {0, 1, 3, 2}; //determines order of triangle strip
- @@ -2676,10 +2680,12 @@ unsigned int CLinuxRendererGLES::GetProcessorSize()
- }
-
- #ifdef HAVE_LIBOPENMAX
- -void CLinuxRendererGLES::AddProcessor(COpenMax* openMax, DVDVideoPicture *picture, int index)
- +void CLinuxRendererGLES::AddProcessor(COpenMaxVideoBuffer *openMaxBuffer, int index)
- {
- YUVBUFFER &buf = m_buffers[index];
- - buf.openMaxBuffer = picture->openMaxBuffer;
- + COpenMaxVideoBuffer *pic = openMaxBuffer->Acquire();
- + SAFE_RELEASE(buf.openMaxBuffer);
- + buf.openMaxBuffer = pic;
- }
- #endif
- #ifdef HAVE_VIDEOTOOLBOXDECODER
- diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
- index 45e9c20..0ca56a2 100644
- --- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
- +++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
- @@ -39,7 +39,7 @@ class CRenderCapture;
- class CBaseTexture;
- namespace Shaders { class BaseYUV2RGBShader; }
- namespace Shaders { class BaseVideoFilterShader; }
- -class COpenMaxVideo;
- +class COpenMaxVideoBuffer;
- class CDVDVideoCodecStageFright;
- class CDVDMediaCodecInfo;
- typedef std::vector<int> Features;
- @@ -161,7 +161,7 @@ class CLinuxRendererGLES : public CBaseRenderer
- virtual std::vector<ERenderFormat> SupportedFormats() { return m_formats; }
-
- #ifdef HAVE_LIBOPENMAX
- - virtual void AddProcessor(COpenMax* openMax, DVDVideoPicture *picture, int index);
- + virtual void AddProcessor(COpenMaxVideoBuffer *openMaxVideoBuffer, int index);
- #endif
- #ifdef HAVE_VIDEOTOOLBOXDECODER
- virtual void AddProcessor(struct __CVBuffer *cvBufferRef, int index);
- @@ -275,7 +275,7 @@ class CLinuxRendererGLES : public CBaseRenderer
- unsigned flipindex; /* used to decide if this has been uploaded */
-
- #ifdef HAVE_LIBOPENMAX
- - OpenMaxVideoBuffer *openMaxBuffer;
- + COpenMaxVideoBuffer *openMaxBuffer;
- #endif
- #ifdef HAVE_VIDEOTOOLBOXDECODER
- struct __CVBuffer *cvBufferRef;
- diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
- index 6832721..3503988 100644
- --- a/xbmc/cores/VideoRenderers/RenderManager.cpp
- +++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
- @@ -912,7 +912,7 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic)
- #endif
- #ifdef HAVE_LIBOPENMAX
- else if(pic.format == RENDER_FMT_OMXEGL)
- - m_pRenderer->AddProcessor(pic.openMax, &pic, index);
- + m_pRenderer->AddProcessor(pic.openMaxBuffer, index);
- #endif
- #ifdef TARGET_DARWIN
- else if(pic.format == RENDER_FMT_CVBREF)
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
- index 14ad038..18b8e3a 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
- @@ -270,9 +270,12 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne
- #endif
-
- #if defined(HAVE_LIBOPENMAX)
- - if (CSettings::Get().GetBool("videoplayer.useomx") && !hint.software )
- + if (!hint.software && CSettings::Get().GetBool("videoplayer.useomx"))
- {
- - if (hint.codec == AV_CODEC_ID_H264 || hint.codec == AV_CODEC_ID_MPEG2VIDEO || hint.codec == AV_CODEC_ID_VC1)
- + if (hint.codec == AV_CODEC_ID_H264 || hint.codec == AV_CODEC_ID_H263 || hint.codec == AV_CODEC_ID_MPEG4 ||
- + hint.codec == AV_CODEC_ID_MPEG1VIDEO || hint.codec == AV_CODEC_ID_MPEG2VIDEO ||
- + hint.codec == AV_CODEC_ID_VP6 || hint.codec == AV_CODEC_ID_VP6F || hint.codec == AV_CODEC_ID_VP6A || hint.codec == AV_CODEC_ID_VP8 ||
- + hint.codec == AV_CODEC_ID_THEORA || hint.codec == AV_CODEC_ID_MJPEG || hint.codec == AV_CODEC_ID_MJPEGB || hint.codec == AV_CODEC_ID_VC1 || hint.codec == AV_CODEC_ID_WMV3)
- {
- if ( (pCodec = OpenCodec(new CDVDVideoCodecOpenMax(), hint, options)) ) return pCodec;
- }
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
- index f6751f4..dc047d7 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
- @@ -44,9 +44,7 @@ struct DVDCodecAvailableType
- namespace DXVA { class CSurfaceContext; }
- namespace VAAPI { struct CHolder; }
- namespace VDPAU { class CVdpauRenderPicture; }
- -class COpenMax;
- -class COpenMaxVideo;
- -struct OpenMaxVideoBuffer;
- +class COpenMaxVideoBuffer;
- class CDVDVideoCodecStageFright;
- class CDVDMediaCodecInfo;
- typedef void* EGLImageKHR;
- @@ -75,8 +73,7 @@ struct DVDVideoPicture
- };
-
- struct {
- - COpenMax *openMax;
- - OpenMaxVideoBuffer *openMaxBuffer;
- + COpenMaxVideoBuffer *openMaxBuffer;
- };
-
- struct {
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp
- index b2e7816..7d33192 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp
- @@ -29,113 +29,43 @@
- #include "DVDStreamInfo.h"
- #include "DVDVideoCodecOpenMax.h"
- #include "OpenMaxVideo.h"
- +#include "settings/Settings.h"
- #include "utils/log.h"
-
- -#define CLASSNAME "COpenMax"
- +#define CLASSNAME "CDVDVideoCodecOpenMax"
- ////////////////////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////////////////
- -CDVDVideoCodecOpenMax::CDVDVideoCodecOpenMax() : CDVDVideoCodec()
- +CDVDVideoCodecOpenMax::CDVDVideoCodecOpenMax()
- {
- m_omx_decoder = NULL;
- - m_pFormatName = "omx-xxxx";
- -
- - m_convert_bitstream = false;
- - memset(&m_videobuffer, 0, sizeof(DVDVideoPicture));
- + CLog::Log(LOGDEBUG, "%s::%s %p\n", CLASSNAME, __func__, this);
- }
-
- CDVDVideoCodecOpenMax::~CDVDVideoCodecOpenMax()
- {
- + CLog::Log(LOGDEBUG, "%s::%s %p\n", CLASSNAME, __func__, this);
- Dispose();
- }
-
- bool CDVDVideoCodecOpenMax::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
- {
- - // we always qualify even if DVDFactoryCodec does this too.
- - if (CSettings::Get().GetBool("videoplayer.useomx") && !hints.software)
- - {
- - m_convert_bitstream = false;
- -
- - switch (hints.codec)
- - {
- - case AV_CODEC_ID_H264:
- - {
- - m_pFormatName = "omx-h264";
- - if (hints.extrasize < 7 || hints.extradata == NULL)
- - {
- - CLog::Log(LOGNOTICE,
- - "%s::%s - avcC data too small or missing", CLASSNAME, __func__);
- - return false;
- - }
- - // valid avcC data (bitstream) always starts with the value 1 (version)
- - if ( *(char*)hints.extradata == 1 )
- - m_convert_bitstream = bitstream_convert_init(hints.extradata, hints.extrasize);
- - }
- - break;
- - case AV_CODEC_ID_MPEG4:
- - m_pFormatName = "omx-mpeg4";
- - break;
- - case AV_CODEC_ID_MPEG2VIDEO:
- - m_pFormatName = "omx-mpeg2";
- - break;
- - case AV_CODEC_ID_VC1:
- - m_pFormatName = "omx-vc1";
- - break;
- - default:
- - return false;
- - break;
- - }
- -
- - m_omx_decoder = new COpenMaxVideo;
- - if (!m_omx_decoder->Open(hints))
- - {
- - CLog::Log(LOGERROR,
- - "%s::%s - failed to open, codec(%d), profile(%d), level(%d)",
- - CLASSNAME, __func__, hints.codec, hints.profile, hints.level);
- - return false;
- - }
- -
- - // allocate a YV12 DVDVideoPicture buffer.
- - // first make sure all properties are reset.
- - memset(&m_videobuffer, 0, sizeof(DVDVideoPicture));
- -
- - m_videobuffer.dts = DVD_NOPTS_VALUE;
- - m_videobuffer.pts = DVD_NOPTS_VALUE;
- - //m_videobuffer.format = RENDER_FMT_YUV420P;
- - m_videobuffer.format = RENDER_FMT_OMXEGL;
- - m_videobuffer.color_range = 0;
- - m_videobuffer.color_matrix = 4;
- - m_videobuffer.iFlags = DVP_FLAG_ALLOCATED;
- - m_videobuffer.iWidth = hints.width;
- - m_videobuffer.iHeight = hints.height;
- - m_videobuffer.iDisplayWidth = hints.width;
- - m_videobuffer.iDisplayHeight = hints.height;
- -
- - return true;
- - }
- + m_omx_decoder = new COpenMaxVideo;
- + return m_omx_decoder->Open(hints, options);
- +}
-
- - return false;
- +const char* CDVDVideoCodecOpenMax::GetName(void)
- +{
- + return m_omx_decoder ? m_omx_decoder->GetName() : "omx-xxx";
- }
-
- void CDVDVideoCodecOpenMax::Dispose()
- {
- if (m_omx_decoder)
- {
- - m_omx_decoder->Close();
- + m_omx_decoder->Dispose();
- delete m_omx_decoder;
- m_omx_decoder = NULL;
- }
- - if (m_videobuffer.iFlags & DVP_FLAG_ALLOCATED)
- - {
- - m_videobuffer.iFlags = 0;
- - }
- - if (m_convert_bitstream)
- - {
- - if (m_sps_pps_context.sps_pps_data)
- - {
- - free(m_sps_pps_context.sps_pps_data);
- - m_sps_pps_context.sps_pps_data = NULL;
- - }
- - }
- }
-
- void CDVDVideoCodecOpenMax::SetDropState(bool bDrop)
- @@ -145,37 +75,12 @@ void CDVDVideoCodecOpenMax::SetDropState(bool bDrop)
-
- int CDVDVideoCodecOpenMax::Decode(uint8_t* pData, int iSize, double dts, double pts)
- {
- - if (pData)
- - {
- - int rtn;
- - int demuxer_bytes = iSize;
- - uint8_t *demuxer_content = pData;
- - bool bitstream_convered = false;
- -
- - if (m_convert_bitstream)
- - {
- - // convert demuxer packet from bitstream to bytestream (AnnexB)
- - int bytestream_size = 0;
- - uint8_t *bytestream_buff = NULL;
- -
- - bitstream_convert(demuxer_content, demuxer_bytes, &bytestream_buff, &bytestream_size);
- - if (bytestream_buff && (bytestream_size > 0))
- - {
- - bitstream_convered = true;
- - demuxer_bytes = bytestream_size;
- - demuxer_content = bytestream_buff;
- - }
- - }
- -
- - rtn = m_omx_decoder->Decode(demuxer_content, demuxer_bytes, dts, pts);
- -
- - if (bitstream_convered)
- - free(demuxer_content);
- + return m_omx_decoder->Decode(pData, iSize, dts, pts);
- +}
-
- - return rtn;
- - }
- -
- - return VC_BUFFER;
- +unsigned CDVDVideoCodecOpenMax::GetAllowedReferences()
- +{
- + return m_omx_decoder->GetAllowedReferences();
- }
-
- void CDVDVideoCodecOpenMax::Reset(void)
- @@ -185,172 +90,12 @@ void CDVDVideoCodecOpenMax::Reset(void)
-
- bool CDVDVideoCodecOpenMax::GetPicture(DVDVideoPicture* pDvdVideoPicture)
- {
- - m_omx_decoder->GetPicture(&m_videobuffer);
- - *pDvdVideoPicture = m_videobuffer;
- -
- - return VC_PICTURE | VC_BUFFER;
- -}
- -
- -////////////////////////////////////////////////////////////////////////////////////////////
- -bool CDVDVideoCodecOpenMax::bitstream_convert_init(void *in_extradata, int in_extrasize)
- -{
- - // based on h264_mp4toannexb_bsf.c (ffmpeg)
- - // which is Copyright (c) 2007 Benoit Fouet <benoit.fouet@free.fr>
- - // and Licensed GPL 2.1 or greater
- -
- - m_sps_pps_size = 0;
- - m_sps_pps_context.sps_pps_data = NULL;
- -
- - // nothing to filter
- - if (!in_extradata || in_extrasize < 6)
- - return false;
- -
- - uint16_t unit_size;
- - uint32_t total_size = 0;
- - uint8_t *out = NULL, unit_nb, sps_done = 0;
- - const uint8_t *extradata = (uint8_t*)in_extradata + 4;
- - static const uint8_t nalu_header[4] = {0, 0, 0, 1};
- -
- - // retrieve length coded size
- - m_sps_pps_context.length_size = (*extradata++ & 0x3) + 1;
- - if (m_sps_pps_context.length_size == 3)
- - return false;
- -
- - // retrieve sps and pps unit(s)
- - unit_nb = *extradata++ & 0x1f; // number of sps unit(s)
- - if (!unit_nb)
- - {
- - unit_nb = *extradata++; // number of pps unit(s)
- - sps_done++;
- - }
- - while (unit_nb--)
- - {
- - unit_size = extradata[0] << 8 | extradata[1];
- - total_size += unit_size + 4;
- - if ( (extradata + 2 + unit_size) > ((uint8_t*)in_extradata + in_extrasize) )
- - {
- - free(out);
- - return false;
- - }
- - uint8_t* new_out = (uint8_t*)realloc(out, total_size);
- - if (new_out)
- - {
- - out = new_out;
- - }
- - else
- - {
- - CLog::Log(LOGERROR, "bitstream_convert_init failed - %s : could not realloc the buffer out", __FUNCTION__);
- - free(out);
- - return false;
- - }
- -
- - memcpy(out + total_size - unit_size - 4, nalu_header, 4);
- - memcpy(out + total_size - unit_size, extradata + 2, unit_size);
- - extradata += 2 + unit_size;
- -
- - if (!unit_nb && !sps_done++)
- - unit_nb = *extradata++; // number of pps unit(s)
- - }
- -
- - m_sps_pps_context.sps_pps_data = out;
- - m_sps_pps_context.size = total_size;
- - m_sps_pps_context.first_idr = 1;
- -
- - return true;
- -}
- -
- -bool CDVDVideoCodecOpenMax::bitstream_convert(uint8_t* pData, int iSize, uint8_t **poutbuf, int *poutbuf_size)
- -{
- - // based on h264_mp4toannexb_bsf.c (ffmpeg)
- - // which is Copyright (c) 2007 Benoit Fouet <benoit.fouet@free.fr>
- - // and Licensed GPL 2.1 or greater
- -
- - uint8_t *buf = pData;
- - uint32_t buf_size = iSize;
- - uint8_t unit_type;
- - int32_t nal_size;
- - uint32_t cumul_size = 0;
- - const uint8_t *buf_end = buf + buf_size;
- -
- - do
- - {
- - if (buf + m_sps_pps_context.length_size > buf_end)
- - goto fail;
- -
- - if (m_sps_pps_context.length_size == 1)
- - nal_size = buf[0];
- - else if (m_sps_pps_context.length_size == 2)
- - nal_size = buf[0] << 8 | buf[1];
- - else
- - nal_size = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
- -
- - buf += m_sps_pps_context.length_size;
- - unit_type = *buf & 0x1f;
- -
- - if (buf + nal_size > buf_end || nal_size < 0)
- - goto fail;
- -
- - // prepend only to the first type 5 NAL unit of an IDR picture
- - if (m_sps_pps_context.first_idr && unit_type == 5)
- - {
- - bitstream_alloc_and_copy(poutbuf, poutbuf_size,
- - m_sps_pps_context.sps_pps_data, m_sps_pps_context.size, buf, nal_size);
- - m_sps_pps_context.first_idr = 0;
- - }
- - else
- - {
- - bitstream_alloc_and_copy(poutbuf, poutbuf_size, NULL, 0, buf, nal_size);
- - if (!m_sps_pps_context.first_idr && unit_type == 1)
- - m_sps_pps_context.first_idr = 1;
- - }
- -
- - buf += nal_size;
- - cumul_size += nal_size + m_sps_pps_context.length_size;
- - } while (cumul_size < buf_size);
- -
- - return true;
- -
- -fail:
- - free(*poutbuf);
- - *poutbuf = NULL;
- - *poutbuf_size = 0;
- - return false;
- + return m_omx_decoder->GetPicture(pDvdVideoPicture);
- }
-
- -void CDVDVideoCodecOpenMax::bitstream_alloc_and_copy(
- - uint8_t **poutbuf, int *poutbuf_size,
- - const uint8_t *sps_pps, uint32_t sps_pps_size,
- - const uint8_t *in, uint32_t in_size)
- +bool CDVDVideoCodecOpenMax::ClearPicture(DVDVideoPicture* pDvdVideoPicture)
- {
- - // based on h264_mp4toannexb_bsf.c (ffmpeg)
- - // which is Copyright (c) 2007 Benoit Fouet <benoit.fouet@free.fr>
- - // and Licensed GPL 2.1 or greater
- -
- - #define CHD_WB32(p, d) { \
- - ((uint8_t*)(p))[3] = (d); \
- - ((uint8_t*)(p))[2] = (d) >> 8; \
- - ((uint8_t*)(p))[1] = (d) >> 16; \
- - ((uint8_t*)(p))[0] = (d) >> 24; }
- -
- - uint32_t offset = *poutbuf_size;
- - uint8_t nal_header_size = offset ? 3 : 4;
- -
- - *poutbuf_size += sps_pps_size + in_size + nal_header_size;
- - *poutbuf = (uint8_t*)realloc(*poutbuf, *poutbuf_size);
- - if (sps_pps)
- - memcpy(*poutbuf + offset, sps_pps, sps_pps_size);
- -
- - memcpy(*poutbuf + sps_pps_size + nal_header_size + offset, in, in_size);
- - if (!offset)
- - {
- - CHD_WB32(*poutbuf + sps_pps_size, 1);
- - }
- - else
- - {
- - (*poutbuf + offset + sps_pps_size)[0] = 0;
- - (*poutbuf + offset + sps_pps_size)[1] = 0;
- - (*poutbuf + offset + sps_pps_size)[2] = 1;
- - }
- + return m_omx_decoder->ClearPicture(pDvdVideoPicture);
- }
-
- #endif
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h
- index fb80d02..67cc235 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h
- @@ -23,7 +23,7 @@
-
- #include "DVDVideoCodec.h"
-
- -class COpenVideoMax;
- +class COpenMaxVideo;
- class CDVDVideoCodecOpenMax : public CDVDVideoCodec
- {
- public:
- @@ -36,39 +36,13 @@ class CDVDVideoCodecOpenMax : public CDVDVideoCodec
- virtual int Decode(uint8_t *pData, int iSize, double dts, double pts);
- virtual void Reset(void);
- virtual bool GetPicture(DVDVideoPicture *pDvdVideoPicture);
- + virtual bool ClearPicture(DVDVideoPicture* pDvdVideoPicture);
- + virtual unsigned GetAllowedReferences();
- virtual void SetDropState(bool bDrop);
- - virtual const char* GetName(void) { return (const char*)m_pFormatName; }
- + virtual const char* GetName(void);
-
- protected:
- - const char *m_pFormatName;
- COpenMaxVideo *m_omx_decoder;
- - DVDVideoPicture m_videobuffer;
- -
- - // bitstream to bytestream (Annex B) conversion support.
- - bool bitstream_convert_init(void *in_extradata, int in_extrasize);
- - bool bitstream_convert(uint8_t* pData, int iSize, uint8_t **poutbuf, int *poutbuf_size);
- - static void bitstream_alloc_and_copy( uint8_t **poutbuf, int *poutbuf_size,
- - const uint8_t *sps_pps, uint32_t sps_pps_size, const uint8_t *in, uint32_t in_size);
- -
- - typedef struct omx_bitstream_ctx {
- - uint8_t length_size;
- - uint8_t first_idr;
- - uint8_t *sps_pps_data;
- - uint32_t size;
- -
- - omx_bitstream_ctx()
- - {
- - length_size = 0;
- - first_idr = 0;
- - sps_pps_data = NULL;
- - size = 0;
- - }
- -
- - } omx_bitstream_ctx;
- -
- - uint32_t m_sps_pps_size;
- - omx_bitstream_ctx m_sps_pps_context;
- - bool m_convert_bitstream;
- };
-
- #endif
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in
- index 8a97889..ebf7123 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in
- @@ -20,7 +20,6 @@ SRCS += DVDVideoCodecVDA.cpp
- SRCS += VDA.cpp
- endif
- ifeq (@USE_OPENMAX@,1)
- -SRCS += OpenMax.cpp
- SRCS += OpenMaxVideo.cpp
- SRCS += DVDVideoCodecOpenMax.cpp
- endif
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMax.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMax.cpp
- deleted file mode 100644
- index 7b0a0c2ef..0000000
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMax.cpp
- +++ /dev/null
- @@ -1,269 +0,0 @@
- -/*
- - * Copyright (C) 2010-2013 Team XBMC
- - * http://xbmc.org
- - *
- - * This Program is free software; you can redistribute it and/or modify
- - * it under the terms of the GNU General Public License as published by
- - * the Free Software Foundation; either version 2, or (at your option)
- - * any later version.
- - *
- - * This Program is distributed in the hope that it will be useful,
- - * but WITHOUT ANY WARRANTY; without even the implied warranty of
- - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- - * GNU General Public License for more details.
- - *
- - * You should have received a copy of the GNU General Public License
- - * along with XBMC; see the file COPYING. If not, see
- - * <http://www.gnu.org/licenses/>.
- - *
- - */
- -
- -#if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
- - #include "config.h"
- -#elif defined(TARGET_WINDOWS)
- -#include "system.h"
- -#endif
- -
- -#if defined(HAVE_LIBOPENMAX)
- -#include "OpenMax.h"
- -#include "DynamicDll.h"
- -#include "DVDClock.h"
- -#include "DVDStreamInfo.h"
- -#include "windowing/WindowingFactory.h"
- -#include "DVDVideoCodec.h"
- -#include "utils/log.h"
- -#include "utils/TimeUtils.h"
- -#include "ApplicationMessenger.h"
- -#include "Application.h"
- -
- -#include <OMX_Core.h>
- -#include <OMX_Component.h>
- -#include <OMX_Index.h>
- -#include <OMX_Image.h>
- -
- -#define CLASSNAME "COpenMax"
- -
- -
- -////////////////////////////////////////////////////////////////////////////////////////////
- -class DllLibOpenMaxInterface
- -{
- -public:
- - virtual ~DllLibOpenMaxInterface() {}
- -
- - virtual OMX_ERRORTYPE OMX_Init(void) = 0;
- - virtual OMX_ERRORTYPE OMX_Deinit(void) = 0;
- - virtual OMX_ERRORTYPE OMX_GetHandle(
- - OMX_HANDLETYPE *pHandle, OMX_STRING cComponentName, OMX_PTR pAppData, OMX_CALLBACKTYPE *pCallBacks) = 0;
- - virtual OMX_ERRORTYPE OMX_FreeHandle(OMX_HANDLETYPE hComponent) = 0;
- - virtual OMX_ERRORTYPE OMX_GetComponentsOfRole(OMX_STRING role, OMX_U32 *pNumComps, OMX_U8 **compNames) = 0;
- - virtual OMX_ERRORTYPE OMX_GetRolesOfComponent(OMX_STRING compName, OMX_U32 *pNumRoles, OMX_U8 **roles) = 0;
- - virtual OMX_ERRORTYPE OMX_ComponentNameEnum(OMX_STRING cComponentName, OMX_U32 nNameLength, OMX_U32 nIndex) = 0;
- -};
- -
- -class DllLibOpenMax : public DllDynamic, DllLibOpenMaxInterface
- -{
- - DECLARE_DLL_WRAPPER(DllLibOpenMax, "/usr/lib/libnvomx.so")
- -
- - DEFINE_METHOD0(OMX_ERRORTYPE, OMX_Init)
- - DEFINE_METHOD0(OMX_ERRORTYPE, OMX_Deinit)
- - DEFINE_METHOD4(OMX_ERRORTYPE, OMX_GetHandle, (OMX_HANDLETYPE *p1, OMX_STRING p2, OMX_PTR p3, OMX_CALLBACKTYPE *p4))
- - DEFINE_METHOD1(OMX_ERRORTYPE, OMX_FreeHandle, (OMX_HANDLETYPE p1))
- - DEFINE_METHOD3(OMX_ERRORTYPE, OMX_GetComponentsOfRole, (OMX_STRING p1, OMX_U32 *p2, OMX_U8 **p3))
- - DEFINE_METHOD3(OMX_ERRORTYPE, OMX_GetRolesOfComponent, (OMX_STRING p1, OMX_U32 *p2, OMX_U8 **p3))
- - DEFINE_METHOD3(OMX_ERRORTYPE, OMX_ComponentNameEnum, (OMX_STRING p1, OMX_U32 p2, OMX_U32 p3))
- - BEGIN_METHOD_RESOLVE()
- - RESOLVE_METHOD(OMX_Init)
- - RESOLVE_METHOD(OMX_Deinit)
- - RESOLVE_METHOD(OMX_GetHandle)
- - RESOLVE_METHOD(OMX_FreeHandle)
- - RESOLVE_METHOD(OMX_GetComponentsOfRole)
- - RESOLVE_METHOD(OMX_GetRolesOfComponent)
- - RESOLVE_METHOD(OMX_ComponentNameEnum)
- - END_METHOD_RESOLVE()
- -};
- -
- -////////////////////////////////////////////////////////////////////////////////////////////
- -#define OMX_INIT_STRUCTURE(a) \
- - memset(&(a), 0, sizeof(a)); \
- - (a).nSize = sizeof(a); \
- - (a).nVersion.s.nVersionMajor = OMX_VERSION_MAJOR; \
- - (a).nVersion.s.nVersionMinor = OMX_VERSION_MINOR; \
- - (a).nVersion.s.nRevision = OMX_VERSION_REVISION; \
- - (a).nVersion.s.nStep = OMX_VERSION_STEP
- -
- -////////////////////////////////////////////////////////////////////////////////////////////
- -////////////////////////////////////////////////////////////////////////////////////////////
- -COpenMax::COpenMax()
- -{
- - #if defined(OMX_DEBUG_VERBOSE)
- - CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__);
- - #endif
- - m_dll = new DllLibOpenMax;
- - m_dll->Load();
- - m_is_open = false;
- -
- - m_omx_decoder = NULL;
- - m_omx_client_state = DEAD;
- - m_omx_decoder_state = 0;
- - sem_init(m_omx_decoder_state_change, 0, 0);
- - /*
- - m_omx_flush_input = (sem_t*)malloc(sizeof(sem_t));
- - sem_init(m_omx_flush_input, 0, 0);
- - m_omx_flush_output = (sem_t*)malloc(sizeof(sem_t));
- - sem_init(m_omx_flush_output, 0, 0);
- - */
- -}
- -
- -COpenMax::~COpenMax()
- -{
- - #if defined(OMX_DEBUG_VERBOSE)
- - CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__);
- - #endif
- - /*
- - sem_destroy(m_omx_flush_input);
- - free(m_omx_flush_input);
- - sem_destroy(m_omx_flush_output);
- - free(m_omx_flush_output);
- - */
- - delete m_dll;
- -}
- -
- -
- -
- -
- -////////////////////////////////////////////////////////////////////////////////////////////
- -// DecoderEventHandler -- OMX event callback
- -OMX_ERRORTYPE COpenMax::DecoderEventHandlerCallback(
- - OMX_HANDLETYPE hComponent,
- - OMX_PTR pAppData,
- - OMX_EVENTTYPE eEvent,
- - OMX_U32 nData1,
- - OMX_U32 nData2,
- - OMX_PTR pEventData)
- -{
- - COpenMax *ctx = (COpenMax*)pAppData;
- - return ctx->DecoderEventHandler(hComponent, pAppData, eEvent, nData1, nData2, pEventData);
- -}
- -
- -// DecoderEmptyBufferDone -- OpenMax input buffer has been emptied
- -OMX_ERRORTYPE COpenMax::DecoderEmptyBufferDoneCallback(
- - OMX_HANDLETYPE hComponent,
- - OMX_PTR pAppData,
- - OMX_BUFFERHEADERTYPE* pBuffer)
- -{
- - COpenMax *ctx = (COpenMax*)pAppData;
- - return ctx->DecoderEmptyBufferDone( hComponent, pAppData, pBuffer);
- -}
- -
- -// DecoderFillBufferDone -- OpenMax output buffer has been filled
- -OMX_ERRORTYPE COpenMax::DecoderFillBufferDoneCallback(
- - OMX_HANDLETYPE hComponent,
- - OMX_PTR pAppData,
- - OMX_BUFFERHEADERTYPE* pBuffer)
- -{
- - COpenMax *ctx = (COpenMax*)pAppData;
- - return ctx->DecoderFillBufferDone(hComponent, pAppData, pBuffer);
- -}
- -
- -
- -
- -// Wait for a component to transition to the specified state
- -OMX_ERRORTYPE COpenMax::WaitForState(OMX_STATETYPE state)
- -{
- - OMX_STATETYPE test_state;
- - int tries = 0;
- - struct timespec timeout;
- - OMX_ERRORTYPE omx_error = OMX_GetState(m_omx_decoder, &test_state);
- -
- - #if defined(OMX_DEBUG_VERBOSE)
- - CLog::Log(LOGDEBUG, "%s::%s - waiting for state(%d)\n", CLASSNAME, __func__, state);
- - #endif
- - while ((omx_error == OMX_ErrorNone) && (test_state != state))
- - {
- - clock_gettime(CLOCK_REALTIME, &timeout);
- - timeout.tv_sec += 1;
- - sem_timedwait(m_omx_decoder_state_change, &timeout);
- - if (errno == ETIMEDOUT)
- - tries++;
- - if (tries > 5)
- - return OMX_ErrorUndefined;
- -
- - omx_error = OMX_GetState(m_omx_decoder, &test_state);
- - }
- -
- - return omx_error;
- -}
- -
- -// SetStateForAllComponents
- -// Blocks until all state changes have completed
- -OMX_ERRORTYPE COpenMax::SetStateForComponent(OMX_STATETYPE state)
- -{
- - OMX_ERRORTYPE omx_err;
- -
- - #if defined(OMX_DEBUG_VERBOSE)
- - CLog::Log(LOGDEBUG, "%s::%s - state(%d)\n", CLASSNAME, __func__, state);
- - #endif
- - omx_err = OMX_SendCommand(m_omx_decoder, OMX_CommandStateSet, state, 0);
- - if (omx_err)
- - CLog::Log(LOGERROR, "%s::%s - OMX_CommandStateSet failed with omx_err(0x%x)\n",
- - CLASSNAME, __func__, omx_err);
- - else
- - omx_err = WaitForState(state);
- -
- - return omx_err;
- -}
- -
- -bool COpenMax::Initialize( const CStdString &decoder_name)
- -{
- - OMX_ERRORTYPE omx_err = m_dll->OMX_Init();
- - if (omx_err)
- - {
- - CLog::Log(LOGERROR,
- - "%s::%s - OpenMax failed to init, status(%d), ", // codec(%d), profile(%d), level(%d)
- - CLASSNAME, __func__, omx_err );//, hints.codec, hints.profile, hints.level);
- - return false;
- - }
- -
- - // Get video decoder handle setting up callbacks, component is in loaded state on return.
- - static OMX_CALLBACKTYPE decoder_callbacks = {
- - &DecoderEventHandlerCallback, &DecoderEmptyBufferDoneCallback, &DecoderFillBufferDoneCallback };
- - omx_err = m_dll->OMX_GetHandle(&m_omx_decoder, (char*)decoder_name.c_str(), this, &decoder_callbacks);
- - if (omx_err)
- - {
- - CLog::Log(LOGERROR,
- - "%s::%s - could not get decoder handle\n", CLASSNAME, __func__);
- - m_dll->OMX_Deinit();
- - return false;
- - }
- -
- - return true;
- -}
- -
- -void COpenMax::Deinitialize()
- -{
- - CLog::Log(LOGERROR,
- - "%s::%s - failed to get component port parameter\n", CLASSNAME, __func__);
- - m_dll->OMX_FreeHandle(m_omx_decoder);
- - m_omx_decoder = NULL;
- - m_dll->OMX_Deinit();
- -}
- -
- -// OpenMax decoder callback routines.
- -OMX_ERRORTYPE COpenMax::DecoderEventHandler(OMX_HANDLETYPE hComponent, OMX_PTR pAppData,
- - OMX_EVENTTYPE eEvent, OMX_U32 nData1, OMX_U32 nData2, OMX_PTR pEventData)
- -{
- - return OMX_ErrorNone;
- -}
- -
- -OMX_ERRORTYPE COpenMax::DecoderEmptyBufferDone(OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBuffer)
- -{
- - return OMX_ErrorNone;
- -}
- -
- -OMX_ERRORTYPE COpenMax::DecoderFillBufferDone(OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBufferHeader)
- -{
- - return OMX_ErrorNone;
- -}
- -
- -#endif
- -
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMax.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMax.h
- deleted file mode 100644
- index 0d9ff18..0000000
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMax.h
- +++ /dev/null
- @@ -1,116 +0,0 @@
- -#pragma once
- -/*
- - * Copyright (C) 2010-2013 Team XBMC
- - * http://xbmc.org
- - *
- - * This Program is free software; you can redistribute it and/or modify
- - * it under the terms of the GNU General Public License as published by
- - * the Free Software Foundation; either version 2, or (at your option)
- - * any later version.
- - *
- - * This Program is distributed in the hope that it will be useful,
- - * but WITHOUT ANY WARRANTY; without even the implied warranty of
- - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- - * GNU General Public License for more details.
- - *
- - * You should have received a copy of the GNU General Public License
- - * along with XBMC; see the file COPYING. If not, see
- - * <http://www.gnu.org/licenses/>.
- - *
- - */
- -
- -#if defined(HAVE_LIBOPENMAX)
- -
- -#include "cores/dvdplayer/DVDStreamInfo.h"
- -#include "DVDVideoCodec.h"
- -#include "threads/Event.h"
- -
- -#include <queue>
- -#include <semaphore.h>
- -#include <OMX_Core.h>
- -
- -////////////////////////////////////////////////////////////////////////////////////////////
- -// debug spew defines
- -#if 0
- -#define OMX_DEBUG_VERBOSE
- -#define OMX_DEBUG_EVENTHANDLER
- -#define OMX_DEBUG_FILLBUFFERDONE
- -#define OMX_DEBUG_EMPTYBUFFERDONE
- -#endif
- -
- -typedef struct omx_codec_capability {
- - // level is OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE,
- - // or OMX_VIDEO_MPEG4PROFILETYPE depending on context.
- - OMX_U32 level;
- - // level is OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE,
- - // or OMX_VIDEO_MPEG4PROFILETYPE depending on context.
- - OMX_U32 profile;
- -} omx_codec_capability;
- -
- -typedef struct omx_demux_packet {
- - OMX_U8 *buff;
- - int size;
- - double dts;
- - double pts;
- -} omx_demux_packet;
- -
- -class DllLibOpenMax;
- -class COpenMax
- -{
- -public:
- - COpenMax();
- - virtual ~COpenMax();
- -
- -protected:
- - enum OMX_CLIENT_STATE {
- - DEAD,
- - LOADED,
- - LOADED_TO_IDLE,
- - IDLE_TO_EXECUTING,
- - EXECUTING,
- - EXECUTING_TO_IDLE,
- - IDLE_TO_LOADED,
- - RECONFIGURING,
- - ERROR
- - };
- -
- - // initialize OpenMax and get decoder component
- - bool Initialize( const CStdString &decoder_name);
- - void Deinitialize();
- -
- - // OpenMax Decoder delegate callback routines.
- - static OMX_ERRORTYPE DecoderEventHandlerCallback(OMX_HANDLETYPE hComponent, OMX_PTR pAppData,
- - OMX_EVENTTYPE eEvent, OMX_U32 nData1, OMX_U32 nData2, OMX_PTR pEventData);
- - static OMX_ERRORTYPE DecoderEmptyBufferDoneCallback(
- - OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBuffer);
- - static OMX_ERRORTYPE DecoderFillBufferDoneCallback(
- - OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBufferHeader);
- -
- - // OpenMax decoder callback routines.
- - virtual OMX_ERRORTYPE DecoderEventHandler(OMX_HANDLETYPE hComponent, OMX_PTR pAppData,
- - OMX_EVENTTYPE eEvent, OMX_U32 nData1, OMX_U32 nData2, OMX_PTR pEventData);
- - virtual OMX_ERRORTYPE DecoderEmptyBufferDone(
- - OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBuffer);
- - virtual OMX_ERRORTYPE DecoderFillBufferDone(
- - OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBufferHeader);
- -
- - // OpenMax helper routines
- - OMX_ERRORTYPE WaitForState(OMX_STATETYPE state);
- - OMX_ERRORTYPE SetStateForComponent(OMX_STATETYPE state);
- -
- - DllLibOpenMax *m_dll;
- - bool m_is_open;
- - OMX_HANDLETYPE m_omx_decoder; // openmax decoder component reference
- -
- - // OpenMax state tracking
- - OMX_CLIENT_STATE m_omx_client_state;
- - volatile int m_omx_decoder_state;
- - sem_t *m_omx_decoder_state_change;
- - std::vector<omx_codec_capability> m_omx_decoder_capabilities;
- -
- -private:
- - COpenMax(const COpenMax& other);
- - COpenMax& operator=(const COpenMax&);
- -};
- -
- -#endif
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- index dcbdb1e..aca2e0d 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- @@ -32,673 +32,891 @@
- #include "DVDVideoCodec.h"
- #include "utils/log.h"
- #include "utils/TimeUtils.h"
- +#include "settings/Settings.h"
- #include "ApplicationMessenger.h"
- #include "Application.h"
- +#include "threads/Atomics.h"
-
- -#include <OMX_Core.h>
- -#include <OMX_Component.h>
- -#include <OMX_Index.h>
- -#include <OMX_Image.h>
- +#include <IL/OMX_Core.h>
- +#include <IL/OMX_Component.h>
- +#include <IL/OMX_Index.h>
- +#include <IL/OMX_Image.h>
-
- +#include "cores/omxplayer/OMXImage.h"
- +
- +#define DTS_QUEUE
- +
- +#define DEFAULT_TIMEOUT 1000
- +#ifdef _DEBUG
- +#define OMX_DEBUG_VERBOSE
- +#endif
-
- #define CLASSNAME "COpenMaxVideo"
-
- -// TODO: These are Nvidia Tegra2 dependent, need to dynamiclly find the
- -// right codec matched to video format.
- -#define OMX_H264BASE_DECODER "OMX.Nvidia.h264.decode"
- -// OMX.Nvidia.h264ext.decode segfaults, not sure why.
- -//#define OMX_H264MAIN_DECODER "OMX.Nvidia.h264ext.decode"
- -#define OMX_H264MAIN_DECODER "OMX.Nvidia.h264.decode"
- -#define OMX_H264HIGH_DECODER "OMX.Nvidia.h264ext.decode"
- -#define OMX_MPEG4_DECODER "OMX.Nvidia.mp4.decode"
- -#define OMX_MPEG4EXT_DECODER "OMX.Nvidia.mp4ext.decode"
- -#define OMX_MPEG2V_DECODER "OMX.Nvidia.mpeg2v.decode"
- -#define OMX_VC1_DECODER "OMX.Nvidia.vc1.decode"
- -
- -// EGL extension functions
- -static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
- -static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
- -#define GETEXTENSION(type, ext) \
- -do \
- -{ \
- - ext = (type) eglGetProcAddress(#ext); \
- - if (!ext) \
- - { \
- - CLog::Log(LOGERROR, "%s::%s - ERROR getting proc addr of " #ext "\n", CLASSNAME, __func__); \
- - } \
- -} while (0);
- -
- -#define OMX_INIT_STRUCTURE(a) \
- - memset(&(a), 0, sizeof(a)); \
- - (a).nSize = sizeof(a); \
- - (a).nVersion.s.nVersionMajor = OMX_VERSION_MAJOR; \
- - (a).nVersion.s.nVersionMinor = OMX_VERSION_MINOR; \
- - (a).nVersion.s.nRevision = OMX_VERSION_REVISION; \
- - (a).nVersion.s.nStep = OMX_VERSION_STEP
- +COpenMaxVideoBuffer::COpenMaxVideoBuffer(COpenMaxVideo *omv)
- + : m_omv(omv), m_refs(0)
- +{
- + CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this);
- + omx_buffer = NULL;
- + width = 0;
- + height = 0;
- + index = 0;
- + egl_image = 0;
- + texture_id = 0;
- +}
- +
- +COpenMaxVideoBuffer::~COpenMaxVideoBuffer()
- +{
- + CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this);
- +}
-
-
- -COpenMaxVideo::COpenMaxVideo()
- +// DecoderFillBufferDone -- OpenMax output buffer has been filled
- +static OMX_ERRORTYPE DecoderFillBufferDoneCallback(
- + OMX_HANDLETYPE hComponent,
- + OMX_PTR pAppData,
- + OMX_BUFFERHEADERTYPE* pBuffer)
- +{
- + COpenMaxVideoBuffer *pic = static_cast<COpenMaxVideoBuffer*>(pBuffer->pAppPrivate);
- + COpenMaxVideo *ctx = pic->m_omv;
- + return ctx->DecoderFillBufferDone(hComponent, pBuffer);
- +}
- +
- +
- +COpenMaxVideoBuffer* COpenMaxVideoBuffer::Acquire()
- +{
- + long count = AtomicIncrement(&m_refs);
- + #if defined(OMX_DEBUG_VERBOSE)
- + CLog::Log(LOGDEBUG, "%s::%s %p ref:%ld", CLASSNAME, __func__, this, count);
- + #endif
- + (void)count;
- + return this;
- +}
- +
- +long COpenMaxVideoBuffer::Release()
- {
- - m_portChanging = false;
- + long count = AtomicDecrement(&m_refs);
- + if (count == 0)
- + {
- + m_omv->ReleaseOpenMaxBuffer(this);
- + }
- +
- + #if defined(OMX_DEBUG_VERBOSE)
- + CLog::Log(LOGDEBUG, "%s::%s %p ref:%ld", CLASSNAME, __func__, this, count);
- + #endif
- + return count;
- +}
-
- - pthread_mutex_init(&m_omx_input_mutex, NULL);
- +void COpenMaxVideoBuffer::Sync()
- +{
- + #if defined(OMX_DEBUG_VERBOSE)
- + CLog::Log(LOGDEBUG, "%s::%s %p ref:%ld", CLASSNAME, __func__, this, m_refs);
- + #endif
- + Release();
- +}
- +
- +COpenMaxVideo::COpenMaxVideo()
- +{
- + CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this);
- pthread_mutex_init(&m_omx_output_mutex, NULL);
-
- - m_omx_decoder_state_change = (sem_t*)malloc(sizeof(sem_t));
- - sem_init(m_omx_decoder_state_change, 0, 0);
- - memset(&m_videobuffer, 0, sizeof(DVDVideoPicture));
- m_drop_state = false;
- m_decoded_width = 0;
- m_decoded_height = 0;
- - m_omx_input_eos = false;
- - m_omx_input_port = 0;
- - m_omx_output_eos = false;
- - m_omx_output_port = 0;
- - m_videoplayback_done = false;
- + m_egl_buffer_count = 0;
- +
- + m_port_settings_changed = false;
- + m_pFormatName = "omx-xxxx";
- }
-
- COpenMaxVideo::~COpenMaxVideo()
- {
- #if defined(OMX_DEBUG_VERBOSE)
- - CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__);
- + CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this);
- #endif
- - if (m_is_open)
- - Close();
- - pthread_mutex_destroy(&m_omx_input_mutex);
- + if (m_omx_decoder.IsInitialized())
- + {
- + if (m_omx_tunnel.IsInitialized())
- + m_omx_tunnel.Deestablish();
- +
- + StopDecoder();
- +
- + if (m_omx_egl_render.IsInitialized())
- + m_omx_egl_render.Deinitialize();
- + if (m_omx_decoder.IsInitialized())
- + m_omx_decoder.Deinitialize();
- + }
- pthread_mutex_destroy(&m_omx_output_mutex);
- - sem_destroy(m_omx_decoder_state_change);
- - free(m_omx_decoder_state_change);
- }
-
- -bool COpenMaxVideo::Open(CDVDStreamInfo &hints)
- +bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
- {
- #if defined(OMX_DEBUG_VERBOSE)
- - CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__);
- + CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
- #endif
-
- + // we always qualify even if DVDFactoryCodec does this too.
- + if (!CSettings::Get().GetBool("videoplayer.useomx") || hints.software)
- + return false;
- +
- OMX_ERRORTYPE omx_err = OMX_ErrorNone;
- - std::string decoder_name;
-
- m_decoded_width = hints.width;
- m_decoded_height = hints.height;
-
- + m_egl_display = g_Windowing.GetEGLDisplay();
- + m_egl_context = g_Windowing.GetEGLContext();
- + m_egl_buffer_count = 4;
- +
- + m_codingType = OMX_VIDEO_CodingUnused;
- +
- switch (hints.codec)
- {
- case AV_CODEC_ID_H264:
- - {
- - switch(hints.profile)
- - {
- - case FF_PROFILE_H264_BASELINE:
- - // (role name) video_decoder.avc
- - // H.264 Baseline profile
- - decoder_name = OMX_H264BASE_DECODER;
- - break;
- - case FF_PROFILE_H264_MAIN:
- - // (role name) video_decoder.avc
- - // H.264 Main profile
- - decoder_name = OMX_H264MAIN_DECODER;
- - break;
- - case FF_PROFILE_H264_HIGH:
- - // (role name) video_decoder.avc
- - // H.264 Main profile
- - decoder_name = OMX_H264HIGH_DECODER;
- - break;
- - default:
- - return false;
- - break;
- - }
- - }
- + // H.264
- + m_codingType = OMX_VIDEO_CodingAVC;
- + m_pFormatName = "omx-h264";
- break;
- + case AV_CODEC_ID_H263:
- case AV_CODEC_ID_MPEG4:
- - // (role name) video_decoder.mpeg4
- - // MPEG-4, DivX 4/5 and Xvid compatible
- - decoder_name = OMX_MPEG4_DECODER;
- - break;
- - /*
- - TODO: what mpeg4 formats are "ext" ????
- - case NvxStreamType_MPEG4Ext:
- - // (role name) video_decoder.mpeg4
- // MPEG-4, DivX 4/5 and Xvid compatible
- - decoder_name = OMX_MPEG4EXT_DECODER;
- + m_codingType = OMX_VIDEO_CodingMPEG4;
- m_pFormatName = "omx-mpeg4";
- break;
- - */
- + case AV_CODEC_ID_MPEG1VIDEO:
- case AV_CODEC_ID_MPEG2VIDEO:
- - // (role name) video_decoder.mpeg2
- // MPEG-2
- - decoder_name = OMX_MPEG2V_DECODER;
- + m_codingType = OMX_VIDEO_CodingMPEG2;
- + m_pFormatName = "omx-mpeg2";
- + break;
- + case AV_CODEC_ID_VP6:
- + // this form is encoded upside down
- + // fall through
- + case AV_CODEC_ID_VP6F:
- + case AV_CODEC_ID_VP6A:
- + // VP6
- + m_codingType = OMX_VIDEO_CodingVP6;
- + m_pFormatName = "omx-vp6";
- + break;
- + case AV_CODEC_ID_VP8:
- + // VP8
- + m_codingType = OMX_VIDEO_CodingVP8;
- + m_pFormatName = "omx-vp8";
- + break;
- + case AV_CODEC_ID_THEORA:
- + // theora
- + m_codingType = OMX_VIDEO_CodingTheora;
- + m_pFormatName = "omx-theora";
- + break;
- + case AV_CODEC_ID_MJPEG:
- + case AV_CODEC_ID_MJPEGB:
- + // mjpg
- + m_codingType = OMX_VIDEO_CodingMJPEG;
- + m_pFormatName = "omx-mjpg";
- break;
- case AV_CODEC_ID_VC1:
- - // (role name) video_decoder.vc1
- + case AV_CODEC_ID_WMV3:
- // VC-1, WMV9
- - decoder_name = OMX_VC1_DECODER;
- - break;
- + m_codingType = OMX_VIDEO_CodingWMV;
- + m_pFormatName = "omx-vc1";
- + break;
- default:
- + CLog::Log(LOGERROR, "%s::%s : Video codec unknown: %x", CLASSNAME, __func__, hints.codec);
- return false;
- break;
- }
-
- // initialize OpenMAX.
- - if (!Initialize(decoder_name))
- + if (!m_omx_decoder.Initialize("OMX.broadcom.video_decode", OMX_IndexParamVideoInit))
- {
- + CLog::Log(LOGERROR, "%s::%s error m_omx_decoder.Initialize", CLASSNAME, __func__);
- return false;
- }
-
- - // TODO: Find component from role name.
- - // Get the port information. This will obtain information about the
- - // number of ports and index of the first port.
- - OMX_PORT_PARAM_TYPE port_param;
- - OMX_INIT_STRUCTURE(port_param);
- - omx_err = OMX_GetParameter(m_omx_decoder, OMX_IndexParamVideoInit, &port_param);
- - if (omx_err)
- + omx_err = m_omx_decoder.SetStateForComponent(OMX_StateIdle);
- + if (omx_err != OMX_ErrorNone)
- {
- - Deinitialize();
- + CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetStateForComponent omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- return false;
- }
- - m_omx_input_port = port_param.nStartPortNumber;
- - m_omx_output_port = m_omx_input_port + 1;
- - #if defined(OMX_DEBUG_VERBOSE)
- - CLog::Log(LOGDEBUG,
- - "%s::%s - decoder_component(0x%p), input_port(0x%x), output_port(0x%x)\n",
- - CLASSNAME, __func__, m_omx_decoder, m_omx_input_port, m_omx_output_port);
- - #endif
-
- - // TODO: Set role for the component because components could have multiple roles.
- - //QueryCodec();
- + OMX_VIDEO_PARAM_PORTFORMATTYPE formatType;
- + OMX_INIT_STRUCTURE(formatType);
- + formatType.nPortIndex = m_omx_decoder.GetInputPort();
- + formatType.eCompressionFormat = m_codingType;
- +
- + omx_err = m_omx_decoder.SetParameter(OMX_IndexParamVideoPortFormat, &formatType);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- + OMX_PARAM_PORTDEFINITIONTYPE portParam;
- + OMX_INIT_STRUCTURE(portParam);
- + portParam.nPortIndex = m_omx_decoder.GetInputPort();
- +
- + omx_err = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &portParam);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s error OMX_IndexParamPortDefinition omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- +
- + portParam.nPortIndex = m_omx_decoder.GetInputPort();
- + portParam.nBufferCountActual = 20;
- + portParam.format.video.nFrameWidth = m_decoded_width;
- + portParam.format.video.nFrameHeight = m_decoded_height;
- +
- + omx_err = m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &portParam);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s error OMX_IndexParamPortDefinition omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- +
- + // request portsettingschanged on aspect ratio change
- + OMX_CONFIG_REQUESTCALLBACKTYPE notifications;
- + OMX_INIT_STRUCTURE(notifications);
- + notifications.nPortIndex = m_omx_decoder.GetOutputPort();
- + notifications.nIndex = OMX_IndexParamBrcmPixelAspectRatio;
- + notifications.bEnable = OMX_TRUE;
- +
- + omx_err = m_omx_decoder.SetParameter((OMX_INDEXTYPE)OMX_IndexConfigRequestCallback, ¬ifications);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s OMX_IndexConfigRequestCallback error (0%08x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- +
- + if (NaluFormatStartCodes(hints.codec, (uint8_t *)hints.extradata, hints.extrasize))
- + {
- + OMX_NALSTREAMFORMATTYPE nalStreamFormat;
- + OMX_INIT_STRUCTURE(nalStreamFormat);
- + nalStreamFormat.nPortIndex = m_omx_decoder.GetInputPort();
- + nalStreamFormat.eNaluFormat = OMX_NaluFormatStartCodes;
- +
- + omx_err = m_omx_decoder.SetParameter((OMX_INDEXTYPE)OMX_IndexParamNalStreamFormatSelect, &nalStreamFormat);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s OMX_IndexParamNalStreamFormatSelect error (0%08x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- + }
-
- - // Component will be in OMX_StateLoaded now so we can alloc omx input/output buffers.
- - // we can only alloc them in OMX_StateLoaded state or if the component port is disabled
- // Alloc buffers for the omx input port.
- - omx_err = AllocOMXInputBuffers();
- - if (omx_err)
- + omx_err = m_omx_decoder.AllocInputBuffers();
- + if (omx_err != OMX_ErrorNone)
- {
- - Deinitialize();
- + CLog::Log(LOGERROR, "%s::%s AllocInputBuffers error (0%08x)", CLASSNAME, __func__, omx_err);
- return false;
- }
- - // Alloc buffers for the omx output port.
- - m_egl_display = g_Windowing.GetEGLDisplay();
- - m_egl_context = g_Windowing.GetEGLContext();
- - omx_err = AllocOMXOutputBuffers();
- - if (omx_err)
- +
- + omx_err = m_omx_decoder.SetStateForComponent(OMX_StateExecuting);
- + if (omx_err != OMX_ErrorNone)
- {
- - FreeOMXInputBuffers(false);
- - Deinitialize();
- + CLog::Log(LOGERROR, "%s::%s error m_omx_decoder.SetStateForComponent error (0%08x)", CLASSNAME, __func__, omx_err);
- return false;
- }
-
- - m_is_open = true;
- - m_drop_state = false;
- - m_videoplayback_done = false;
- + if (!SendDecoderConfig((uint8_t *)hints.extradata, hints.extrasize))
- + return false;
-
- - // crank it up.
- - StartDecoder();
- + m_drop_state = false;
-
- return true;
- }
-
- -void COpenMaxVideo::Close()
- +void COpenMaxVideo::Dispose()
- {
- #if defined(OMX_DEBUG_VERBOSE)
- - CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__);
- + CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
- #endif
- - if (m_omx_decoder)
- - {
- - if (m_omx_decoder_state != OMX_StateLoaded)
- - StopDecoder();
- - Deinitialize();
- - }
- - m_is_open = false;
- }
-
- void COpenMaxVideo::SetDropState(bool bDrop)
- {
- +#if defined(OMX_DEBUG_VERBOSE)
- + if (m_drop_state != bDrop)
- + CLog::Log(LOGDEBUG, "%s::%s - m_drop_state(%d)",
- + CLASSNAME, __func__, bDrop);
- +#endif
- m_drop_state = bDrop;
- +}
-
- - if (m_drop_state)
- +bool COpenMaxVideo::SendDecoderConfig(uint8_t *extradata, int extrasize)
- +{
- + OMX_ERRORTYPE omx_err = OMX_ErrorNone;
- +
- + /* send decoder config */
- + if (extrasize > 0 && extradata != NULL)
- {
- - OMX_ERRORTYPE omx_err;
- + OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_decoder.GetInputBuffer();
-
- - // blow all but the last ready video frame
- - pthread_mutex_lock(&m_omx_output_mutex);
- - while (m_omx_output_ready.size() > 1)
- + if (omx_buffer == NULL)
- {
- - m_dts_queue.pop();
- - OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_output_ready.front()->omx_buffer;
- - m_omx_output_ready.pop();
- - // return the omx buffer back to OpenMax to fill.
- - omx_err = OMX_FillThisBuffer(m_omx_decoder, omx_buffer);
- - if (omx_err)
- - CLog::Log(LOGERROR, "%s::%s - OMX_FillThisBuffer, omx_err(0x%x)\n",
- - CLASSNAME, __func__, omx_err);
- + CLog::Log(LOGERROR, "%s::%s - buffer error 0x%08x", CLASSNAME, __func__, omx_err);
- + return false;
- }
- - pthread_mutex_unlock(&m_omx_output_mutex);
-
- - #if defined(OMX_DEBUG_VERBOSE)
- - CLog::Log(LOGDEBUG, "%s::%s - m_drop_state(%d)\n",
- - CLASSNAME, __func__, m_drop_state);
- - #endif
- + omx_buffer->nOffset = 0;
- + omx_buffer->nFilledLen = extrasize;
- + if (omx_buffer->nFilledLen > omx_buffer->nAllocLen)
- + {
- + CLog::Log(LOGERROR, "%s::%s - omx_buffer->nFilledLen > omx_buffer->nAllocLen", CLASSNAME, __func__);
- + return false;
- + }
- +
- + memcpy((unsigned char *)omx_buffer->pBuffer, extradata, omx_buffer->nFilledLen);
- + omx_buffer->nFlags = OMX_BUFFERFLAG_CODECCONFIG | OMX_BUFFERFLAG_ENDOFFRAME;
- +
- +//CLog::Log(LOGINFO, "%s::%s - Empty(%d,%x)", CLASSNAME, __func__, omx_buffer->nFilledLen, omx_buffer->nFlags); CLog::MemDump((char *)omx_buffer->pBuffer, std::min(64U, omx_buffer->nFilledLen));
- + omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s - OMX_EmptyThisBuffer() failed with result(0x%x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- }
- + return true;
- }
-
- -int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
- +bool COpenMaxVideo::NaluFormatStartCodes(enum AVCodecID codec, uint8_t *extradata, int extrasize)
- +{
- + switch(codec)
- + {
- + case AV_CODEC_ID_H264:
- + if (extrasize < 7 || extradata == NULL)
- + return true;
- + // valid avcC atom data always starts with the value 1 (version), otherwise annexb
- + else if ( *extradata != 1 )
- + return true;
- + default: break;
- + }
- + return false;
- +}
- +
- +bool COpenMaxVideo::PortSettingsChanged()
- {
- - if (pData)
- + OMX_ERRORTYPE omx_err = OMX_ErrorNone;
- +
- + if (m_port_settings_changed)
- + {
- + m_omx_decoder.DisablePort(m_omx_decoder.GetOutputPort(), true);
- + }
- +
- + OMX_PARAM_PORTDEFINITIONTYPE port_def;
- + OMX_INIT_STRUCTURE(port_def);
- + port_def.nPortIndex = m_omx_decoder.GetOutputPort();
- + omx_err = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s - error m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- +
- + OMX_CONFIG_POINTTYPE pixel_aspect;
- + OMX_INIT_STRUCTURE(pixel_aspect);
- + pixel_aspect.nPortIndex = m_omx_decoder.GetOutputPort();
- + omx_err = m_omx_decoder.GetParameter(OMX_IndexParamBrcmPixelAspectRatio, &pixel_aspect);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s - error m_omx_decoder.GetParameter(OMX_IndexParamBrcmPixelAspectRatio) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- +
- + if (m_port_settings_changed)
- {
- - int demuxer_bytes = iSize;
- - uint8_t *demuxer_content = pData;
- + m_omx_decoder.EnablePort(m_omx_decoder.GetOutputPort(), true);
- + return true;
- + }
- +
- + // convert in stripes
- + port_def.format.video.nSliceHeight = 16;
- + port_def.format.video.nStride = 0;
- +
- + omx_err = m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetParameter result(0x%x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- +
- + OMX_CALLBACKTYPE callbacks = { NULL, NULL, DecoderFillBufferDoneCallback };
- + if (!m_omx_egl_render.Initialize("OMX.broadcom.egl_render", OMX_IndexParamVideoInit, &callbacks))
- + {
- + CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.Initialize", CLASSNAME, __func__);
- + return false;
- + }
- +
- + OMX_CONFIG_PORTBOOLEANTYPE discardMode;
- + OMX_INIT_STRUCTURE(discardMode);
- + discardMode.nPortIndex = m_omx_egl_render.GetInputPort();
- + discardMode.bEnabled = OMX_FALSE;
- + omx_err = m_omx_egl_render.SetParameter(OMX_IndexParamBrcmVideoEGLRenderDiscardMode, &discardMode);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s - error m_omx_egl_render.SetParameter(OMX_IndexParamBrcmVideoEGLRenderDiscardMode) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- +
- + m_omx_egl_render.ResetEos();
- +
- + CLog::Log(LOGDEBUG, "%s::%s - %dx%d@%.2f interlace:%d deinterlace:%d", CLASSNAME, __func__,
- + port_def.format.video.nFrameWidth, port_def.format.video.nFrameHeight,
- + port_def.format.video.xFramerate / (float)(1<<16), 0,0);
- +
- + m_omx_tunnel.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_egl_render, m_omx_egl_render.GetInputPort());
- +
- + omx_err = m_omx_tunnel.Establish();
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s - m_omx_tunnel.Establish omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- +
- + // Obtain the information about the output port.
- + OMX_PARAM_PORTDEFINITIONTYPE port_format;
- + OMX_INIT_STRUCTURE(port_format);
- + port_format.nPortIndex = m_omx_egl_render.GetOutputPort();
- + omx_err = m_omx_egl_render.GetParameter(OMX_IndexParamPortDefinition, &port_format);
- + if (omx_err != OMX_ErrorNone)
- + CLog::Log(LOGERROR, "%s::%s - m_omx_egl_render.GetParameter OMX_IndexParamPortDefinition omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- +
- + port_format.nBufferCountActual = m_egl_buffer_count;
- + omx_err = m_omx_egl_render.SetParameter(OMX_IndexParamPortDefinition, &port_format);
- + if (omx_err != OMX_ErrorNone)
- + CLog::Log(LOGERROR, "%s::%s - m_omx_egl_render.SetParameter OMX_IndexParamPortDefinition omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- +
- + #if defined(OMX_DEBUG_VERBOSE)
- + CLog::Log(LOGDEBUG,
- + "%s::%s (1) - oport(%d), nFrameWidth(%u), nFrameHeight(%u), nStride(%x), nBufferCountMin(%u), nBufferCountActual(%u), nBufferSize(%u)",
- + CLASSNAME, __func__, m_omx_egl_render.GetOutputPort(),
- + port_format.format.video.nFrameWidth, port_format.format.video.nFrameHeight,port_format.format.video.nStride,
- + port_format.nBufferCountMin, port_format.nBufferCountActual, port_format.nBufferSize);
- + #endif
- +
-
- - // we need to queue then de-queue the demux packet, seems silly but
- - // omx might not have a omx input buffer avaliable when we are called
- - // and we must store the demuxer packet and try again later.
- + omx_err = m_omx_egl_render.EnablePort(m_omx_egl_render.GetOutputPort(), false);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s - m_omx_egl_render.EnablePort omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- +
- + if (!AllocOMXOutputBuffers())
- + {
- + CLog::Log(LOGERROR, "%s::%s - AllocOMXOutputBuffers failed", CLASSNAME, __func__);
- + return false;
- + }
- +
- + omx_err = m_omx_egl_render.WaitForCommand(OMX_CommandPortEnable, m_omx_egl_render.GetOutputPort());
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s m_omx_egl_render.WaitForCommand(OMX_CommandPortEnable) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- +
- + assert(m_omx_output_busy.empty());
- + assert(m_omx_output_ready.empty());
- +
- + omx_err = m_omx_egl_render.SetStateForComponent(OMX_StateExecuting);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s - m_omx_egl_render.SetStateForComponent omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- +
- + omx_err = PrimeFillBuffers();
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s - m_omx_egl_render.PrimeFillBuffers omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- +
- + m_port_settings_changed = true;
- + return true;
- +}
- +
- +
- +int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
- +{
- + #if defined(OMX_DEBUG_VERBOSE)
- + CLog::Log(LOGDEBUG, "%s::%s - %-8p %-6d dts:%.3f pts:%.3f demux_queue(%d) dts_queue(%d) ready_queue(%d) busy_queue(%d)",
- + CLASSNAME, __func__, pData, iSize, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, m_demux_queue.size(), m_dts_queue.size(), m_omx_output_ready.size(), m_omx_output_busy.size());
- + #endif
- +
- + OMX_ERRORTYPE omx_err;
- + unsigned int demuxer_bytes = 0;
- + uint8_t *demuxer_content = NULL;
- +
- + // we need to queue then de-queue the demux packet, seems silly but
- + // omx might not have a omx input buffer available when we are called
- + // and we must store the demuxer packet and try again later.
- + if (pData && m_demux_queue.empty() && m_omx_decoder.GetInputBufferSpace() >= (unsigned int)iSize)
- + {
- + demuxer_bytes = iSize;
- + demuxer_content = pData;
- + }
- + else if (pData && iSize)
- + {
- omx_demux_packet demux_packet;
- demux_packet.dts = dts;
- demux_packet.pts = pts;
- -
- - demux_packet.size = demuxer_bytes;
- - demux_packet.buff = new OMX_U8[demuxer_bytes];
- - memcpy(demux_packet.buff, demuxer_content, demuxer_bytes);
- + demux_packet.size = iSize;
- + demux_packet.buff = new OMX_U8[iSize];
- + memcpy(demux_packet.buff, pData, iSize);
- m_demux_queue.push(demux_packet);
- + }
-
- - // we can look at m_omx_input_avaliable.empty without needing to lock/unlock
- + OMX_U8 *buffer_to_free = NULL;
- + while (1)
- + {
- // try to send any/all demux packets to omx decoder.
- - while (!m_omx_input_avaliable.empty() && !m_demux_queue.empty() )
- + if (!demuxer_bytes && !m_demux_queue.empty())
- {
- - OMX_ERRORTYPE omx_err;
- - OMX_BUFFERHEADERTYPE* omx_buffer;
- -
- - demux_packet = m_demux_queue.front();
- - m_demux_queue.pop();
- - // need to lock here to retreve an input buffer and pop the queue
- - pthread_mutex_lock(&m_omx_input_mutex);
- - omx_buffer = m_omx_input_avaliable.front();
- - m_omx_input_avaliable.pop();
- - pthread_mutex_unlock(&m_omx_input_mutex);
- -
- - // delete the previous demuxer buffer
- - delete [] omx_buffer->pBuffer;
- - // setup a new omx_buffer.
- - omx_buffer->nFlags = m_omx_input_eos ? OMX_BUFFERFLAG_EOS : 0;
- + omx_demux_packet &demux_packet = m_demux_queue.front();
- + if (m_omx_decoder.GetInputBufferSpace() >= (unsigned int)demux_packet.size)
- + {
- + // need to lock here to retrieve an input buffer and pop the queue
- + m_demux_queue.pop();
- + demuxer_bytes = (unsigned int)demux_packet.size;
- + demuxer_content = demux_packet.buff;
- + buffer_to_free = demux_packet.buff;
- + dts = demux_packet.dts;
- + pts = demux_packet.pts;
- + }
- + }
- +
- + if (demuxer_content)
- + {
- + // 500ms timeout
- + OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_decoder.GetInputBuffer(500);
- + if (omx_buffer == NULL)
- + {
- + CLog::Log(LOGERROR, "%s::%s - m_omx_decoder.GetInputBuffer timeout", CLASSNAME, __func__);
- + return VC_ERROR;
- + }
- + #if defined(OMX_DEBUG_VERBOSE)
- + //CLog::Log(LOGDEBUG, "%s::%s - omx_buffer=%p", CLASSNAME, __func__, omx_buffer);
- + #endif
- + omx_buffer->nFlags = 0;
- omx_buffer->nOffset = 0;
- - omx_buffer->pBuffer = demux_packet.buff;
- - omx_buffer->nAllocLen = demux_packet.size;
- - omx_buffer->nFilledLen = demux_packet.size;
- - omx_buffer->nTimeStamp = (demux_packet.pts == DVD_NOPTS_VALUE) ? 0 : demux_packet.pts * 1000.0; // in microseconds;
- +
- + omx_buffer->nFilledLen = (demuxer_bytes > omx_buffer->nAllocLen) ? omx_buffer->nAllocLen : demuxer_bytes;
- + omx_buffer->nTimeStamp = ToOMXTime((uint64_t)(pts == DVD_NOPTS_VALUE) ? 0 : pts);
- omx_buffer->pAppPrivate = omx_buffer;
- - omx_buffer->nInputPortIndex = m_omx_input_port;
- + memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen);
-
- - #if defined(OMX_DEBUG_EMPTYBUFFERDONE)
- - CLog::Log(LOGDEBUG,
- - "%s::%s - feeding decoder, omx_buffer->pBuffer(0x%p), demuxer_bytes(%d)\n",
- - CLASSNAME, __func__, omx_buffer->pBuffer, demuxer_bytes);
- - #endif
- - // Give this omx_buffer to OpenMax to be decoded.
- - omx_err = OMX_EmptyThisBuffer(m_omx_decoder, omx_buffer);
- - if (omx_err)
- + demuxer_bytes -= omx_buffer->nFilledLen;
- + demuxer_content += omx_buffer->nFilledLen;
- +
- + if (demuxer_bytes == 0)
- + omx_buffer->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
- + if (pts == DVD_NOPTS_VALUE)
- + omx_buffer->nFlags |= OMX_BUFFERFLAG_TIME_UNKNOWN;
- + if (m_drop_state) // hijack an omx flag to signal this frame to be dropped - it will be returned with the picture (but otherwise ignored)
- + omx_buffer->nFlags |= OMX_BUFFERFLAG_DATACORRUPT;
- +
- +#if defined(OMX_DEBUG_VERBOSE)
- + CLog::Log(LOGDEBUG, "%s::%s - %-6d dts:%.3f pts:%.3f flags:%x",
- + CLASSNAME, __func__, omx_buffer->nFilledLen, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, omx_buffer->nFlags);
- +#endif
- +
- + omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
- + if (omx_err != OMX_ErrorNone)
- {
- - CLog::Log(LOGDEBUG,
- - "%s::%s - OMX_EmptyThisBuffer() failed with result(0x%x)\n",
- - CLASSNAME, __func__, omx_err);
- + CLog::Log(LOGERROR, "%s::%s - OMX_EmptyThisBuffer() failed with result(0x%x)", CLASSNAME, __func__, omx_err);
- return VC_ERROR;
- }
- - // only push if we are successful with feeding OMX_EmptyThisBuffer
- - m_dts_queue.push(demux_packet.dts);
- -
- - // if m_omx_input_avaliable and/or demux_queue are now empty,
- - // wait up to 20ms for OpenMax to consume a demux packet
- - if (m_omx_input_avaliable.empty() || m_demux_queue.empty())
- - m_input_consumed_event.WaitMSec(1);
- + if (demuxer_bytes == 0)
- + {
- +#ifdef DTS_QUEUE
- + // only push if we are successful with feeding OMX_EmptyThisBuffer
- + m_dts_queue.push(dts);
- + assert(m_dts_queue.size() < 32);
- +#endif
- + if (buffer_to_free)
- + {
- + delete [] buffer_to_free;
- + buffer_to_free = NULL;
- + demuxer_content = NULL;
- + continue;
- + }
- + }
- + }
- + omx_err = m_omx_decoder.WaitForEvent(OMX_EventPortSettingsChanged, 0);
- + if (omx_err == OMX_ErrorNone)
- + {
- + if (!PortSettingsChanged())
- + {
- + CLog::Log(LOGERROR, "%s::%s - error PortSettingsChanged omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- + return VC_ERROR;
- + }
- + }
- + else if (omx_err != OMX_ErrorTimeout)
- + {
- + CLog::Log(LOGERROR, "%s::%s - video not supported omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- + return VC_ERROR;
- }
- - if (m_omx_input_avaliable.empty() && !m_demux_queue.empty())
- - m_input_consumed_event.WaitMSec(1);
- -
- - #if defined(OMX_DEBUG_VERBOSE)
- - if (m_omx_input_avaliable.empty())
- - CLog::Log(LOGDEBUG,
- - "%s::%s - buffering demux, m_demux_queue_size(%d), demuxer_bytes(%d)\n",
- - CLASSNAME, __func__, m_demux_queue.size(), demuxer_bytes);
- - #endif
- + omx_err = m_omx_decoder.WaitForEvent(OMX_EventParamOrConfigChanged, 0);
- + if (omx_err == OMX_ErrorNone)
- + {
- + if (!PortSettingsChanged())
- + {
- + CLog::Log(LOGERROR, "%s::%s - error PortSettingsChanged (EventParamOrConfigChanged) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- + return VC_ERROR;
- + }
- + }
- + else if (omx_err == OMX_ErrorStreamCorrupt)
- + {
- + CLog::Log(LOGERROR, "%s::%s - video not supported 2 omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- + return VC_ERROR;
- + }
- + if (!demuxer_bytes)
- + break;
- }
-
- +#if defined(OMX_DEBUG_VERBOSE)
- + if (!m_omx_decoder.GetInputBufferSpace())
- + CLog::Log(LOGDEBUG,
- + "%s::%s - buffering demux, m_demux_queue_size(%d), demuxer_bytes(%d) m_dts_queue.size(%d)",
- + CLASSNAME, __func__, m_demux_queue.size(), demuxer_bytes, m_dts_queue.size());
- + #endif
- +
- if (m_omx_output_ready.empty())
- + {
- + //CLog::Log(LOGDEBUG, "%s::%s - empty: buffers:%d", CLASSNAME, __func__, m_omx_output_ready.size());
- return VC_BUFFER;
- + }
-
- - return VC_PICTURE | VC_BUFFER;
- + //CLog::Log(LOGDEBUG, "%s::%s - full: buffers:%d", CLASSNAME, __func__, m_omx_output_ready.size());
- + return VC_PICTURE;
- }
-
- void COpenMaxVideo::Reset(void)
- {
- #if defined(OMX_DEBUG_VERBOSE)
- - CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__);
- + CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
- #endif
- -/*
- - // only reset OpenMax decoder if it's running
- - if (m_omx_decoder_state == OMX_StateExecuting)
- + m_omx_egl_render.FlushAll();
- + m_omx_decoder.FlushAll();
- + // blow all ready video frames
- + while (!m_omx_output_ready.empty())
- {
- - OMX_ERRORTYPE omx_err;
- -
- - omx_err = StopDecoder();
- - // Alloc OpenMax input buffers.
- - omx_err = AllocOMXInputBuffers();
- - // Alloc OpenMax output buffers.
- - omx_err = AllocOMXOutputBuffers();
- -
- - omx_err = StartDecoder();
- + pthread_mutex_lock(&m_omx_output_mutex);
- + COpenMaxVideoBuffer *pic = m_omx_output_ready.front();
- + m_omx_output_ready.pop();
- + pthread_mutex_unlock(&m_omx_output_mutex);
- + // return the omx buffer back to OpenMax to fill.
- + ReturnOpenMaxBuffer(pic);
- }
- -*/
- - ::Sleep(100);
- +#ifdef DTS_QUEUE
- + while (!m_dts_queue.empty())
- + m_dts_queue.pop();
- +#endif
- +
- + while (!m_demux_queue.empty())
- + m_demux_queue.pop();
- }
-
- -bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture)
- +
- +OMX_ERRORTYPE COpenMaxVideo::ReturnOpenMaxBuffer(COpenMaxVideoBuffer *buffer)
- {
- - while (m_omx_output_busy.size() > 1)
- + OMX_ERRORTYPE omx_err = OMX_ErrorNone;
- +#if defined(OMX_DEBUG_VERBOSE)
- + CLog::Log(LOGDEBUG, "%s::%s %p (%d)", CLASSNAME, __func__, buffer, m_omx_output_busy.size());
- +#endif
- + bool done = buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_EOS;
- + if (!done)
- {
- - // fetch a output buffer and pop it off the busy list
- - pthread_mutex_lock(&m_omx_output_mutex);
- - OpenMaxVideoBuffer *buffer = m_omx_output_busy.front();
- - m_omx_output_busy.pop();
- - pthread_mutex_unlock(&m_omx_output_mutex);
- + // return the omx buffer back to OpenMax to fill.
- + buffer->omx_buffer->nFlags = 0;
- + buffer->omx_buffer->nFilledLen = 0;
-
- - bool done = buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_EOS;
- - if (!done)
- - {
- - // return the omx buffer back to OpenMax to fill.
- - OMX_ERRORTYPE omx_err = OMX_FillThisBuffer(m_omx_decoder, buffer->omx_buffer);
- - if (omx_err)
- - CLog::Log(LOGERROR, "%s::%s - OMX_FillThisBuffer, omx_err(0x%x)\n",
- - CLASSNAME, __func__, omx_err);
- - }
- + assert(buffer->omx_buffer->nOutputPortIndex == m_omx_egl_render.GetOutputPort());
- +#if defined(OMX_DEBUG_VERBOSE)
- + CLog::Log(LOGDEBUG, "%s::%s FillThisBuffer(%p) %p->%ld", CLASSNAME, __func__, buffer, buffer->omx_buffer, buffer->m_refs);
- +#endif
- + OMX_ERRORTYPE omx_err = m_omx_egl_render.FillThisBuffer(buffer->omx_buffer);
- +
- + if (omx_err)
- + CLog::Log(LOGERROR, "%s::%s - OMX_FillThisBuffer, omx_err(0x%x)", CLASSNAME, __func__, omx_err);
- }
- + return omx_err;
- +}
- +
- +void COpenMaxVideo::ReleaseOpenMaxBuffer(COpenMaxVideoBuffer *buffer)
- +{
- + // remove from busy list
- + pthread_mutex_lock(&m_omx_output_mutex);
- + m_omx_output_busy.erase(std::remove(m_omx_output_busy.begin(), m_omx_output_busy.end(), buffer), m_omx_output_busy.end());
- + pthread_mutex_unlock(&m_omx_output_mutex);
- + ReturnOpenMaxBuffer(buffer);
- +}
- +
- +bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture)
- +{
- + //CLog::Log(LOGDEBUG, "%s::%s - m_omx_output_busy.size()=%d m_omx_output_ready.size()=%d", CLASSNAME, __func__, m_omx_output_busy.size(), m_omx_output_ready.size());
- + //CLog::Log(LOGDEBUG, "%s::%s - full: buffers:%d", CLASSNAME, __func__, m_omx_output_ready.size());
-
- if (!m_omx_output_ready.empty())
- {
- - OpenMaxVideoBuffer *buffer;
- + COpenMaxVideoBuffer *buffer;
- // fetch a output buffer and pop it off the ready list
- pthread_mutex_lock(&m_omx_output_mutex);
- buffer = m_omx_output_ready.front();
- m_omx_output_ready.pop();
- - m_omx_output_busy.push(buffer);
- + m_omx_output_busy.push_back(buffer);
- pthread_mutex_unlock(&m_omx_output_mutex);
-
- + memset(pDvdVideoPicture, 0, sizeof *pDvdVideoPicture);
- pDvdVideoPicture->dts = DVD_NOPTS_VALUE;
- pDvdVideoPicture->pts = DVD_NOPTS_VALUE;
- pDvdVideoPicture->format = RENDER_FMT_OMXEGL;
- - pDvdVideoPicture->openMax = this;
- pDvdVideoPicture->openMaxBuffer = buffer;
- -
- + pDvdVideoPicture->color_range = 0;
- + pDvdVideoPicture->color_matrix = 4;
- + pDvdVideoPicture->iWidth = m_decoded_width;
- + pDvdVideoPicture->iHeight = m_decoded_height;
- + pDvdVideoPicture->iDisplayWidth = m_decoded_width;
- + pDvdVideoPicture->iDisplayHeight = m_decoded_height;
- +
- +#ifdef DTS_QUEUE
- if (!m_dts_queue.empty())
- {
- pDvdVideoPicture->dts = m_dts_queue.front();
- m_dts_queue.pop();
- }
- +#endif
- // nTimeStamp is in microseconds
- - pDvdVideoPicture->pts = (buffer->omx_buffer->nTimeStamp == 0) ? DVD_NOPTS_VALUE : (double)buffer->omx_buffer->nTimeStamp / 1000.0;
- + double ts = FromOMXTime(buffer->omx_buffer->nTimeStamp);
- + pDvdVideoPicture->pts = (ts == 0) ? DVD_NOPTS_VALUE : ts;
- + pDvdVideoPicture->openMaxBuffer->Acquire();
- + pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED;
- + if (buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_DATACORRUPT)
- + pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED;
- +#if defined(OMX_DEBUG_VERBOSE)
- + CLog::Log(LOGINFO, "%s::%s dts:%.3f pts:%.3f flags:%x:%x openMaxBuffer:%p omx_buffer:%p egl_image:%p texture_id:%x", CLASSNAME, __func__,
- + pDvdVideoPicture->dts == DVD_NOPTS_VALUE ? 0.0 : pDvdVideoPicture->dts*1e-6, pDvdVideoPicture->pts == DVD_NOPTS_VALUE ? 0.0 : pDvdVideoPicture->pts*1e-6,
- + pDvdVideoPicture->iFlags, buffer->omx_buffer->nFlags, pDvdVideoPicture->openMaxBuffer, pDvdVideoPicture->openMaxBuffer->omx_buffer, pDvdVideoPicture->openMaxBuffer->egl_image, pDvdVideoPicture->openMaxBuffer->texture_id);
- +#endif
- }
- - #if defined(OMX_DEBUG_VERBOSE)
- else
- {
- - CLog::Log(LOGDEBUG, "%s::%s - called but m_omx_output_ready is empty\n",
- - CLASSNAME, __func__);
- + CLog::Log(LOGERROR, "%s::%s - called but m_omx_output_ready is empty", CLASSNAME, __func__);
- + return false;
- }
- - #endif
- -
- - pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED;
- - pDvdVideoPicture->iFlags |= m_drop_state ? DVP_FLAG_DROPPED : 0;
- -
- return true;
- }
-
- -
- -// DecoderEmptyBufferDone -- OpenMax input buffer has been emptied
- -OMX_ERRORTYPE COpenMaxVideo::DecoderEmptyBufferDone(
- - OMX_HANDLETYPE hComponent,
- - OMX_PTR pAppData,
- - OMX_BUFFERHEADERTYPE* pBuffer)
- +bool COpenMaxVideo::ClearPicture(DVDVideoPicture* pDvdVideoPicture)
- {
- - COpenMaxVideo *ctx = static_cast<COpenMaxVideo*>(pAppData);
- -/*
- - #if defined(OMX_DEBUG_EMPTYBUFFERDONE)
- - CLog::Log(LOGDEBUG, "%s::%s - buffer_size(%lu), timestamp(%f)\n",
- - CLASSNAME, __func__, pBuffer->nFilledLen, (double)pBuffer->nTimeStamp / 1000.0);
- - #endif
- -*/
- - // queue free input buffer to avaliable list.
- - pthread_mutex_lock(&ctx->m_omx_input_mutex);
- - ctx->m_omx_input_avaliable.push(pBuffer);
- - ctx->m_input_consumed_event.Set();
- - pthread_mutex_unlock(&ctx->m_omx_input_mutex);
- -
- - return OMX_ErrorNone;
- +#if defined(OMX_DEBUG_VERBOSE)
- + CLog::Log(LOGDEBUG, "%s::%s - %p", CLASSNAME, __func__, pDvdVideoPicture->openMaxBuffer);
- +#endif
- + if (pDvdVideoPicture->format == RENDER_FMT_OMXEGL)
- + pDvdVideoPicture->openMaxBuffer->Release();
- + memset(pDvdVideoPicture, 0, sizeof *pDvdVideoPicture);
- + return true;
- }
-
- -// DecoderFillBufferDone -- OpenMax output buffer has been filled
- + // DecoderFillBufferDone -- OpenMax output buffer has been filled
- OMX_ERRORTYPE COpenMaxVideo::DecoderFillBufferDone(
- OMX_HANDLETYPE hComponent,
- - OMX_PTR pAppData,
- OMX_BUFFERHEADERTYPE* pBuffer)
- {
- - COpenMaxVideo *ctx = static_cast<COpenMaxVideo*>(pAppData);
- - OpenMaxVideoBuffer *buffer = (OpenMaxVideoBuffer*)pBuffer->pAppPrivate;
- + COpenMaxVideoBuffer *buffer = (COpenMaxVideoBuffer*)pBuffer->pAppPrivate;
-
- - #if defined(OMX_DEBUG_FILLBUFFERDONE)
- - CLog::Log(LOGDEBUG, "%s::%s - buffer_size(%lu), timestamp(%f)\n",
- - CLASSNAME, __func__, pBuffer->nFilledLen, (double)pBuffer->nTimeStamp / 1000.0);
- + #if defined(OMX_DEBUG_VERBOSE)
- + CLog::Log(LOGDEBUG, "%s::%s - %p (%p,%p) buffer_size(%u), pts:%.3f",
- + CLASSNAME, __func__, buffer, pBuffer, buffer->omx_buffer, pBuffer->nFilledLen, (double)FromOMXTime(buffer->omx_buffer->nTimeStamp)*1e-6);
- #endif
-
- - if (!ctx->m_portChanging)
- - {
- - // queue output omx buffer to ready list.
- - pthread_mutex_lock(&ctx->m_omx_output_mutex);
- - ctx->m_omx_output_ready.push(buffer);
- - pthread_mutex_unlock(&ctx->m_omx_output_mutex);
- - }
- + // queue output omx buffer to ready list.
- + pthread_mutex_lock(&m_omx_output_mutex);
- + m_omx_output_ready.push(buffer);
- + pthread_mutex_unlock(&m_omx_output_mutex);
-
- return OMX_ErrorNone;
- }
-
- -void COpenMaxVideo::QueryCodec(void)
- -{
- - OMX_ERRORTYPE omx_err = OMX_ErrorNone;
- - OMX_VIDEO_PARAM_PROFILELEVELTYPE port_param;
- - OMX_INIT_STRUCTURE(port_param);
- -
- - port_param.nPortIndex = m_omx_input_port;
- -
- - for (port_param.nProfileIndex = 0;; port_param.nProfileIndex++)
- - {
- - omx_err = OMX_GetParameter(m_omx_decoder,
- - OMX_IndexParamVideoProfileLevelQuerySupported, &port_param);
- - if (omx_err)
- - break;
- -
- - omx_codec_capability omx_capability;
- - omx_capability.level = port_param.eLevel;
- - omx_capability.profile = port_param.eProfile;
- - m_omx_decoder_capabilities.push_back(omx_capability);
- - }
- -}
- -
- OMX_ERRORTYPE COpenMaxVideo::PrimeFillBuffers(void)
- {
- OMX_ERRORTYPE omx_err = OMX_ErrorNone;
- - OpenMaxVideoBuffer *buffer;
- + COpenMaxVideoBuffer *buffer;
-
- #if defined(OMX_DEBUG_VERBOSE)
- - CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__);
- + CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
- #endif
- // tell OpenMax to start filling output buffers
- for (size_t i = 0; i < m_omx_output_buffers.size(); i++)
- {
- buffer = m_omx_output_buffers[i];
- // always set the port index.
- - buffer->omx_buffer->nOutputPortIndex = m_omx_output_port;
- - // Need to clear the EOS flag.
- - buffer->omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS;
- + buffer->omx_buffer->nOutputPortIndex = m_omx_egl_render.GetOutputPort();
- buffer->omx_buffer->pAppPrivate = buffer;
- -
- - omx_err = OMX_FillThisBuffer(m_omx_decoder, buffer->omx_buffer);
- - if (omx_err)
- - CLog::Log(LOGERROR, "%s::%s - OMX_FillThisBuffer failed with omx_err(0x%x)\n",
- - CLASSNAME, __func__, omx_err);
- + omx_err = ReturnOpenMaxBuffer(buffer);
- }
- -
- return omx_err;
- }
-
- -OMX_ERRORTYPE COpenMaxVideo::AllocOMXInputBuffers(void)
- -{
- - OMX_ERRORTYPE omx_err = OMX_ErrorNone;
- -
- - // Obtain the information about the decoder input port.
- - OMX_PARAM_PORTDEFINITIONTYPE port_format;
- - OMX_INIT_STRUCTURE(port_format);
- - port_format.nPortIndex = m_omx_input_port;
- - OMX_GetParameter(m_omx_decoder, OMX_IndexParamPortDefinition, &port_format);
- -
- - #if defined(OMX_DEBUG_VERBOSE)
- - CLog::Log(LOGDEBUG,
- - "%s::%s - iport(%d), nBufferCountMin(%lu), nBufferSize(%lu)\n",
- - CLASSNAME, __func__, m_omx_input_port, port_format.nBufferCountMin, port_format.nBufferSize);
- - #endif
- - for (size_t i = 0; i < port_format.nBufferCountMin; i++)
- - {
- - OMX_BUFFERHEADERTYPE *buffer = NULL;
- - // use an external buffer that's sized according to actual demux
- - // packet size, start at internal's buffer size, will get deleted when
- - // we start pulling demuxer packets and using demux packet sized buffers.
- - OMX_U8* data = new OMX_U8[port_format.nBufferSize];
- - omx_err = OMX_UseBuffer(m_omx_decoder, &buffer, m_omx_input_port, NULL, port_format.nBufferSize, data);
- - if (omx_err)
- - {
- - CLog::Log(LOGERROR, "%s::%s - OMX_UseBuffer failed with omx_err(0x%x)\n",
- - CLASSNAME, __func__, omx_err);
- - return(omx_err);
- - }
- - m_omx_input_buffers.push_back(buffer);
- - // don't have to lock/unlock here, we are not decoding
- - m_omx_input_avaliable.push(buffer);
- - }
- - m_omx_input_eos = false;
- -
- - return(omx_err);
- -}
- -OMX_ERRORTYPE COpenMaxVideo::FreeOMXInputBuffers(bool wait)
- +OMX_ERRORTYPE COpenMaxVideo::FreeOMXInputBuffers(void)
- {
- OMX_ERRORTYPE omx_err = OMX_ErrorNone;
-
- - /*
- - omx_err = OMX_SendCommand(m_omx_decoder, OMX_CommandFlush, m_omx_input_port, 0);
- - if (omx_err)
- - CLog::Log(LOGERROR, "%s::%s - OMX_CommandFlush failed with omx_err(0x%x)\n",
- - CLASSNAME, __func__, omx_err);
- - else if (wait)
- - sem_wait(m_omx_flush_input);
- - */
- -
- - // free omx input port buffers.
- - for (size_t i = 0; i < m_omx_input_buffers.size(); i++)
- - {
- - // using external buffers (OMX_UseBuffer), free our external buffers
- - // before calling OMX_FreeBuffer which frees the omx buffer.
- - delete [] m_omx_input_buffers[i]->pBuffer;
- - m_omx_input_buffers[i]->pBuffer = NULL;
- - omx_err = OMX_FreeBuffer(m_omx_decoder, m_omx_input_port, m_omx_input_buffers[i]);
- - }
- - m_omx_input_buffers.clear();
- -
- // empty input buffer queue. not decoding so don't need lock/unlock.
- - while (!m_omx_input_avaliable.empty())
- - m_omx_input_avaliable.pop();
- while (!m_demux_queue.empty())
- m_demux_queue.pop();
- +#ifdef DTS_QUEUE
- while (!m_dts_queue.empty())
- m_dts_queue.pop();
- -
- +#endif
- return(omx_err);
- }
-
- -void COpenMaxVideo::CallbackAllocOMXEGLTextures(void *userdata)
- +bool COpenMaxVideo::CallbackAllocOMXEGLTextures(void *userdata)
- {
- COpenMaxVideo *omx = static_cast<COpenMaxVideo*>(userdata);
- - omx->AllocOMXOutputEGLTextures();
- + return omx->AllocOMXOutputEGLTextures() == OMX_ErrorNone;
- }
-
- -void COpenMaxVideo::CallbackFreeOMXEGLTextures(void *userdata)
- +bool COpenMaxVideo::CallbackFreeOMXEGLTextures(void *userdata)
- {
- COpenMaxVideo *omx = static_cast<COpenMaxVideo*>(userdata);
- - omx->FreeOMXOutputEGLTextures(true);
- + return omx->FreeOMXOutputEGLTextures() == OMX_ErrorNone;
- }
-
- -OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputBuffers(void)
- +bool COpenMaxVideo::AllocOMXOutputBuffers(void)
- {
- - OMX_ERRORTYPE omx_err;
- -
- - if ( g_application.IsCurrentThread() )
- - {
- - omx_err = AllocOMXOutputEGLTextures();
- - }
- - else
- - {
- - ThreadMessageCallback callbackData;
- - callbackData.callback = &CallbackAllocOMXEGLTextures;
- - callbackData.userptr = (void *)this;
- -
- - ThreadMessage tMsg;
- - tMsg.dwMessage = TMSG_CALLBACK;
- - tMsg.lpVoid = (void*)&callbackData;
- -
- - g_application.getApplicationMessenger().SendMessage(tMsg, true);
- -
- - omx_err = OMX_ErrorNone;
- - }
- -
- - return omx_err;
- + return g_OMXImage.SendMessage(CallbackAllocOMXEGLTextures, (void *)this);
- }
-
- -OMX_ERRORTYPE COpenMaxVideo::FreeOMXOutputBuffers(bool wait)
- +bool COpenMaxVideo::FreeOMXOutputBuffers(void)
- {
- - OMX_ERRORTYPE omx_err = FreeOMXOutputEGLTextures(wait);
- -
- - return omx_err;
- + return g_OMXImage.SendMessage(CallbackFreeOMXEGLTextures, (void *)this);
- }
-
- OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void)
- {
- - OMX_ERRORTYPE omx_err;
- -
- - if (!eglCreateImageKHR)
- - {
- - GETEXTENSION(PFNEGLCREATEIMAGEKHRPROC, eglCreateImageKHR);
- - }
- -
- + OMX_ERRORTYPE omx_err = OMX_ErrorNone;
- EGLint attrib = EGL_NONE;
- - OpenMaxVideoBuffer *egl_buffer;
- -
- - // Obtain the information about the output port.
- - OMX_PARAM_PORTDEFINITIONTYPE port_format;
- - OMX_INIT_STRUCTURE(port_format);
- - port_format.nPortIndex = m_omx_output_port;
- - omx_err = OMX_GetParameter(m_omx_decoder, OMX_IndexParamPortDefinition, &port_format);
- -
- - #if defined(OMX_DEBUG_VERBOSE)
- - CLog::Log(LOGDEBUG,
- - "%s::%s (1) - oport(%d), nFrameWidth(%lu), nFrameHeight(%lu), nStride(%lx), nBufferCountMin(%lu), nBufferSize(%lu)\n",
- - CLASSNAME, __func__, m_omx_output_port,
- - port_format.format.video.nFrameWidth, port_format.format.video.nFrameHeight,port_format.format.video.nStride,
- - port_format.nBufferCountMin, port_format.nBufferSize);
- - #endif
- + COpenMaxVideoBuffer *egl_buffer;
-
- glActiveTexture(GL_TEXTURE0);
-
- - for (size_t i = 0; i < port_format.nBufferCountMin; i++)
- + for (size_t i = 0; i < m_egl_buffer_count; i++)
- {
- - egl_buffer = new OpenMaxVideoBuffer;
- - memset(egl_buffer, 0, sizeof(*egl_buffer));
- + egl_buffer = new COpenMaxVideoBuffer(this);
- egl_buffer->width = m_decoded_width;
- egl_buffer->height = m_decoded_height;
-
- glGenTextures(1, &egl_buffer->texture_id);
- glBindTexture(GL_TEXTURE_2D, egl_buffer->texture_id);
-
- + // no mipmaps
- + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- +
- // create space for buffer with a texture
- glTexImage2D(
- GL_TEXTURE_2D, // target
- @@ -710,8 +928,6 @@ OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void)
- GL_RGBA, // format
- GL_UNSIGNED_BYTE, // type
- NULL); // pixels -- will be provided later
- - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-
- // create EGLImage from texture
- egl_buffer->egl_image = eglCreateImageKHR(
- @@ -722,49 +938,40 @@ OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void)
- &attrib);
- if (!egl_buffer->egl_image)
- {
- - CLog::Log(LOGERROR, "%s::%s - ERROR creating EglImage\n", CLASSNAME, __func__);
- + CLog::Log(LOGERROR, "%s::%s - ERROR creating EglImage", CLASSNAME, __func__);
- return(OMX_ErrorUndefined);
- }
- egl_buffer->index = i;
-
- // tell decoder output port that it will be using EGLImage
- - omx_err = OMX_UseEGLImage(
- - m_omx_decoder, &egl_buffer->omx_buffer, m_omx_output_port, egl_buffer, egl_buffer->egl_image);
- + omx_err = m_omx_egl_render.UseEGLImage(
- + &egl_buffer->omx_buffer, m_omx_egl_render.GetOutputPort(), egl_buffer, egl_buffer->egl_image);
- if (omx_err)
- {
- - CLog::Log(LOGERROR, "%s::%s - OMX_UseEGLImage failed with omx_err(0x%x)\n",
- + CLog::Log(LOGERROR, "%s::%s - OMX_UseEGLImage failed with omx_err(0x%x)",
- CLASSNAME, __func__, omx_err);
- return(omx_err);
- }
- m_omx_output_buffers.push_back(egl_buffer);
-
- - CLog::Log(LOGDEBUG, "%s::%s - Texture %p Width %d Height %d\n",
- + CLog::Log(LOGDEBUG, "%s::%s - Texture %p Width %d Height %d",
- CLASSNAME, __func__, egl_buffer->egl_image, egl_buffer->width, egl_buffer->height);
- }
- - m_omx_output_eos = false;
- - while (!m_omx_output_busy.empty())
- - m_omx_output_busy.pop();
- - while (!m_omx_output_ready.empty())
- - m_omx_output_ready.pop();
- -
- return omx_err;
- }
-
- -OMX_ERRORTYPE COpenMaxVideo::FreeOMXOutputEGLTextures(bool wait)
- +OMX_ERRORTYPE COpenMaxVideo::FreeOMXOutputEGLTextures(void)
- {
- OMX_ERRORTYPE omx_err = OMX_ErrorNone;
- - OpenMaxVideoBuffer *egl_buffer;
- -
- - if (!eglDestroyImageKHR)
- - {
- - GETEXTENSION(PFNEGLDESTROYIMAGEKHRPROC, eglDestroyImageKHR);
- - }
- + COpenMaxVideoBuffer *egl_buffer;
-
- for (size_t i = 0; i < m_omx_output_buffers.size(); i++)
- {
- egl_buffer = m_omx_output_buffers[i];
- // tell decoder output port to stop using the EGLImage
- - omx_err = OMX_FreeBuffer(m_omx_decoder, m_omx_output_port, egl_buffer->omx_buffer);
- + omx_err = m_omx_egl_render.FreeOutputBuffer(egl_buffer->omx_buffer);
- + if (omx_err != OMX_ErrorNone)
- + CLog::Log(LOGERROR, "%s::%s m_omx_egl_render.FreeOutputBuffer(%p) omx_err(0x%08x)", CLASSNAME, __func__, egl_buffer->omx_buffer, omx_err);
- // destroy egl_image
- eglDestroyImageKHR(m_egl_display, egl_buffer->egl_image);
- // free texture
- @@ -777,274 +984,45 @@ OMX_ERRORTYPE COpenMaxVideo::FreeOMXOutputEGLTextures(bool wait)
- }
-
-
- -////////////////////////////////////////////////////////////////////////////////////////////
- -// DecoderEventHandler -- OMX event callback
- -OMX_ERRORTYPE COpenMaxVideo::DecoderEventHandler(
- - OMX_HANDLETYPE hComponent,
- - OMX_PTR pAppData,
- - OMX_EVENTTYPE eEvent,
- - OMX_U32 nData1,
- - OMX_U32 nData2,
- - OMX_PTR pEventData)
- -{
- - OMX_ERRORTYPE omx_err;
- - COpenMaxVideo *ctx = static_cast<COpenMaxVideo*>(pAppData);
- -
- -/*
- - #if defined(OMX_DEBUG_VERBOSE)
- - CLog::Log(LOGDEBUG,
- - "COpenMax::%s - hComponent(0x%p), eEvent(0x%x), nData1(0x%lx), nData2(0x%lx), pEventData(0x%p)\n",
- - __func__, hComponent, eEvent, nData1, nData2, pEventData);
- - #endif
- -*/
- -
- - switch (eEvent)
- - {
- - case OMX_EventCmdComplete:
- - switch(nData1)
- - {
- - case OMX_CommandStateSet:
- - ctx->m_omx_decoder_state = (int)nData2;
- - switch (ctx->m_omx_decoder_state)
- - {
- - case OMX_StateInvalid:
- - CLog::Log(LOGDEBUG, "%s::%s - OMX_StateInvalid\n", CLASSNAME, __func__);
- - break;
- - case OMX_StateLoaded:
- - CLog::Log(LOGDEBUG, "%s::%s - OMX_StateLoaded\n", CLASSNAME, __func__);
- - break;
- - case OMX_StateIdle:
- - CLog::Log(LOGDEBUG, "%s::%s - OMX_StateIdle\n", CLASSNAME, __func__);
- - break;
- - case OMX_StateExecuting:
- - CLog::Log(LOGDEBUG, "%s::%s - OMX_StateExecuting\n", CLASSNAME, __func__);
- - break;
- - case OMX_StatePause:
- - CLog::Log(LOGDEBUG, "%s::%s - OMX_StatePause\n", CLASSNAME, __func__);
- - break;
- - case OMX_StateWaitForResources:
- - CLog::Log(LOGDEBUG, "%s::%s - OMX_StateWaitForResources\n", CLASSNAME, __func__);
- - break;
- - default:
- - CLog::Log(LOGDEBUG,
- - "%s::%s - Unknown OMX_Statexxxxx, state(%d)\n",
- - CLASSNAME, __func__, ctx->m_omx_decoder_state);
- - break;
- - }
- - sem_post(ctx->m_omx_decoder_state_change);
- - break;
- - case OMX_CommandFlush:
- - /*
- - if (OMX_ALL == (int)nData2)
- - {
- - sem_post(ctx->m_omx_flush_input);
- - sem_post(ctx->m_omx_flush_output);
- - CLog::Log(LOGDEBUG, "COpenMax::%s - OMX_CommandFlush input/output\n",__func__);
- - }
- - else if (ctx->m_omx_input_port == (int)nData2)
- - {
- - sem_post(ctx->m_omx_flush_input);
- - CLog::Log(LOGDEBUG, "COpenMax::%s - OMX_CommandFlush input\n",__func__);
- - }
- - else if (ctx->m_omx_output_port == (int)nData2)
- - {
- - sem_post(ctx->m_omx_flush_output);
- - CLog::Log(LOGDEBUG, "COpenMax::%s - OMX_CommandFlush ouput\n",__func__);
- - }
- - else
- - */
- - {
- - #if defined(OMX_DEBUG_EVENTHANDLER)
- - CLog::Log(LOGDEBUG,
- - "%s::%s - OMX_CommandFlush, nData2(0x%lx)\n",
- - CLASSNAME, __func__, nData2);
- - #endif
- - }
- - break;
- - case OMX_CommandPortDisable:
- - #if defined(OMX_DEBUG_EVENTHANDLER)
- - CLog::Log(LOGDEBUG,
- - "%s::%s - OMX_CommandPortDisable, nData1(0x%lx), nData2(0x%lx)\n",
- - CLASSNAME, __func__, nData1, nData2);
- - #endif
- - if (ctx->m_omx_output_port == (int)nData2)
- - {
- - // Got OMX_CommandPortDisable event, alloc new buffers for the output port.
- - ctx->AllocOMXOutputBuffers();
- - omx_err = OMX_SendCommand(ctx->m_omx_decoder, OMX_CommandPortEnable, ctx->m_omx_output_port, NULL);
- - }
- - break;
- - case OMX_CommandPortEnable:
- - #if defined(OMX_DEBUG_EVENTHANDLER)
- - CLog::Log(LOGDEBUG,
- - "%s::%s - OMX_CommandPortEnable, nData1(0x%lx), nData2(0x%lx)\n",
- - CLASSNAME, __func__, nData1, nData2);
- - #endif
- - if (ctx->m_omx_output_port == (int)nData2)
- - {
- - // Got OMX_CommandPortEnable event.
- - // OMX_CommandPortDisable will have re-alloced new ones so re-prime
- - ctx->PrimeFillBuffers();
- - }
- - ctx->m_portChanging = false;
- - break;
- - #if defined(OMX_DEBUG_EVENTHANDLER)
- - case OMX_CommandMarkBuffer:
- - CLog::Log(LOGDEBUG,
- - "%s::%s - OMX_CommandMarkBuffer, nData1(0x%lx), nData2(0x%lx)\n",
- - CLASSNAME, __func__, nData1, nData2);
- - break;
- - #endif
- - }
- - break;
- - case OMX_EventBufferFlag:
- - if (ctx->m_omx_decoder == hComponent && (nData2 & OMX_BUFFERFLAG_EOS)) {
- - #if defined(OMX_DEBUG_EVENTHANDLER)
- - if(ctx->m_omx_input_port == (int)nData1)
- - CLog::Log(LOGDEBUG, "%s::%s - OMX_EventBufferFlag(input)\n",
- - CLASSNAME, __func__);
- - #endif
- - if(ctx->m_omx_output_port == (int)nData1)
- - {
- - ctx->m_videoplayback_done = true;
- - #if defined(OMX_DEBUG_EVENTHANDLER)
- - CLog::Log(LOGDEBUG, "%s::%s - OMX_EventBufferFlag(output)\n",
- - CLASSNAME, __func__);
- - #endif
- - }
- - }
- - break;
- - case OMX_EventPortSettingsChanged:
- - #if defined(OMX_DEBUG_EVENTHANDLER)
- - CLog::Log(LOGDEBUG,
- - "%s::%s - OMX_EventPortSettingsChanged(output)\n", CLASSNAME, __func__);
- - #endif
- - // not sure nData2 is the input/output ports in this call, docs don't say
- - if (ctx->m_omx_output_port == (int)nData2)
- - {
- - // free the current OpenMax output buffers, you must do this before sending
- - // OMX_CommandPortDisable to component as it expects output buffers
- - // to be freed before it will issue a OMX_CommandPortDisable event.
- - ctx->m_portChanging = true;
- - OMX_SendCommand(ctx->m_omx_decoder, OMX_CommandPortDisable, ctx->m_omx_output_port, NULL);
- - omx_err = ctx->FreeOMXOutputBuffers(false);
- - }
- - break;
- - #if defined(OMX_DEBUG_EVENTHANDLER)
- - case OMX_EventMark:
- - CLog::Log(LOGDEBUG, "%s::%s - OMX_EventMark\n", CLASSNAME, __func__);
- - break;
- - case OMX_EventResourcesAcquired:
- - CLog::Log(LOGDEBUG, "%s::%s - OMX_EventResourcesAcquired\n", CLASSNAME, __func__);
- - break;
- - #endif
- - case OMX_EventError:
- - switch((OMX_S32)nData1)
- - {
- - case OMX_ErrorInsufficientResources:
- - CLog::Log(LOGERROR, "%s::%s - OMX_EventError, insufficient resources\n",
- - CLASSNAME, __func__);
- - // we are so frack'ed
- - //exit(0);
- - break;
- - case OMX_ErrorFormatNotDetected:
- - CLog::Log(LOGERROR, "%s::%s - OMX_EventError, cannot parse input stream\n",
- - CLASSNAME, __func__);
- - break;
- - case OMX_ErrorPortUnpopulated:
- - // silently ignore these. We can get them when setting OMX_CommandPortDisable
- - // on the output port and the component flushes the output buffers.
- - break;
- - case OMX_ErrorStreamCorrupt:
- - CLog::Log(LOGERROR, "%s::%s - OMX_EventError, Bitstream corrupt\n",
- - CLASSNAME, __func__);
- - ctx->m_videoplayback_done = true;
- - break;
- - default:
- - CLog::Log(LOGERROR, "%s::%s - OMX_EventError detected, nData1(0x%lx), nData2(0x%lx)\n",
- - CLASSNAME, __func__, nData1, nData2);
- - break;
- - }
- - // do this so we don't hang on errors
- - /*
- - sem_post(ctx->m_omx_flush_input);
- - sem_post(ctx->m_omx_flush_output);
- - */
- - sem_post(ctx->m_omx_decoder_state_change);
- - break;
- - default:
- - CLog::Log(LOGWARNING,
- - "%s::%s - Unknown eEvent(0x%x), nData1(0x%lx), nData2(0x%lx)\n",
- - CLASSNAME, __func__, eEvent, nData1, nData2);
- - break;
- - }
- -
- - return OMX_ErrorNone;
- -}
- -
- -// StartPlayback -- Kick off video playback.
- -OMX_ERRORTYPE COpenMaxVideo::StartDecoder(void)
- -{
- - OMX_ERRORTYPE omx_err;
- -
- - #if defined(OMX_DEBUG_VERBOSE)
- - CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__);
- - #endif
- -
- - // transition decoder component to IDLE state
- - omx_err = SetStateForComponent(OMX_StateIdle);
- - if (omx_err)
- - {
- - CLog::Log(LOGERROR, "%s::%s - setting OMX_StateIdle failed with omx_err(0x%x)\n",
- - CLASSNAME, __func__, omx_err);
- - return omx_err;
- - }
- -
- - // transition decoder component to executing state
- - omx_err = SetStateForComponent(OMX_StateExecuting);
- - if (omx_err)
- - {
- - CLog::Log(LOGERROR, "%s::%s - setting OMX_StateExecuting failed with omx_err(0x%x)\n",
- - CLASSNAME, __func__, omx_err);
- - return omx_err;
- - }
- -
- - //prime the omx output buffers.
- - PrimeFillBuffers();
- -
- - return omx_err;
- -}
- -
- // StopPlayback -- Stop video playback
- OMX_ERRORTYPE COpenMaxVideo::StopDecoder(void)
- {
- - OMX_ERRORTYPE omx_err;
- + OMX_ERRORTYPE omx_err = OMX_ErrorNone;
-
- #if defined(OMX_DEBUG_VERBOSE)
- - CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__);
- + CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
- #endif
- +
- // transition decoder component from executing to idle
- - omx_err = SetStateForComponent(OMX_StateIdle);
- - if (omx_err)
- + if (m_omx_decoder.IsInitialized())
- {
- - CLog::Log(LOGERROR, "%s::%s - setting OMX_StateIdle failed with omx_err(0x%x)\n",
- - CLASSNAME, __func__, omx_err);
- - return omx_err;
- + omx_err = m_omx_decoder.SetStateForComponent(OMX_StateIdle);
- + if (omx_err)
- + CLog::Log(LOGERROR, "%s::%s - setting OMX_StateIdle failed with omx_err(0x%x)",
- + CLASSNAME, __func__, omx_err);
- }
-
- // we can free our allocated port buffers in OMX_StateIdle state.
- // free OpenMax input buffers.
- - FreeOMXInputBuffers(true);
- - // free OpenMax output buffers.
- - FreeOMXOutputBuffers(true);
- + FreeOMXInputBuffers();
- +
- + if (m_omx_egl_render.IsInitialized())
- + {
- + omx_err = m_omx_egl_render.SetStateForComponent(OMX_StateIdle);
- + if (omx_err)
- + CLog::Log(LOGERROR, "%s::%s - setting egl OMX_StateIdle failed with omx_err(0x%x)",
- + CLASSNAME, __func__, omx_err);
- + // free OpenMax output buffers.
- + omx_err = m_omx_egl_render.DisablePort(m_omx_egl_render.GetOutputPort(), false);
- + if (omx_err != OMX_ErrorNone)
- + CLog::Log(LOGERROR, "%s::%s m_omx_egl_render.DisablePort(%d) omx_err(0x%08x)", CLASSNAME, __func__, m_omx_egl_render.GetOutputPort(), omx_err);
-
- - // transition decoder component from idle to loaded
- - omx_err = SetStateForComponent(OMX_StateLoaded);
- - if (omx_err)
- - CLog::Log(LOGERROR,
- - "%s::%s - setting OMX_StateLoaded failed with omx_err(0x%x)\n",
- - CLASSNAME, __func__, omx_err);
- + FreeOMXOutputBuffers();
-
- + omx_err = m_omx_egl_render.WaitForCommand(OMX_CommandPortDisable, m_omx_egl_render.GetOutputPort());
- + if (omx_err != OMX_ErrorNone)
- + CLog::Log(LOGERROR, "%s::%s WaitForCommand:OMX_CommandPortDisable omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- + }
- return omx_err;
- }
-
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
- index e06c41d..9079c13 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
- @@ -21,12 +21,35 @@
-
- #if defined(HAVE_LIBOPENMAX)
-
- -#include "OpenMax.h"
- +#include "system_gl.h"
- #include <EGL/egl.h>
- #include <EGL/eglext.h>
-
- +#include "linux/OMXCore.h"
- +#include "linux/OMXClock.h"
- +
- +#include "cores/dvdplayer/DVDStreamInfo.h"
- +#include "DVDVideoCodec.h"
- +#include "threads/Event.h"
- +
- +#include <queue>
- +#include <semaphore.h>
- +
- +typedef struct omx_demux_packet {
- + OMX_U8 *buff;
- + int size;
- + double dts;
- + double pts;
- +} omx_demux_packet;
- +
- +class COpenMaxVideo;
- // an omx egl video frame
- -typedef struct OpenMaxVideoBuffer {
- +class COpenMaxVideoBuffer
- +{
- +public:
- + COpenMaxVideoBuffer(COpenMaxVideo *omv);
- + virtual ~COpenMaxVideoBuffer();
- +
- OMX_BUFFERHEADERTYPE *omx_buffer;
- int width;
- int height;
- @@ -35,79 +58,86 @@ typedef struct OpenMaxVideoBuffer {
- // used for egl based rendering if active
- EGLImageKHR egl_image;
- GLuint texture_id;
- -} OpenMaxVideoBuffer;
- + // reference counting
- + COpenMaxVideoBuffer* Acquire();
- + long Release();
- + void Sync();
- +
- + COpenMaxVideo *m_omv;
- + long m_refs;
- +private:
- +};
-
- -class COpenMaxVideo : public COpenMax
- +class COpenMaxVideo
- {
- public:
- COpenMaxVideo();
- virtual ~COpenMaxVideo();
-
- // Required overrides
- - bool Open(CDVDStreamInfo &hints);
- - void Close(void);
- - int Decode(uint8_t *pData, int iSize, double dts, double pts);
- - void Reset(void);
- - bool GetPicture(DVDVideoPicture *pDvdVideoPicture);
- - void SetDropState(bool bDrop);
- + virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options);
- + virtual void Dispose(void);
- + virtual int Decode(uint8_t *pData, int iSize, double dts, double pts);
- + virtual void Reset(void);
- + virtual bool GetPicture(DVDVideoPicture *pDvdVideoPicture);
- + virtual bool ClearPicture(DVDVideoPicture* pDvdVideoPicture);
- + virtual unsigned GetAllowedReferences() { return 2; }
- + virtual void SetDropState(bool bDrop);
- + virtual const char* GetName(void) { return (const char*)m_pFormatName; }
- +
- + // OpenMax decoder callback routines.
- + OMX_ERRORTYPE DecoderFillBufferDone(OMX_HANDLETYPE hComponent, OMX_BUFFERHEADERTYPE* pBuffer);
- + void ReleaseOpenMaxBuffer(COpenMaxVideoBuffer *buffer);
- +
- protected:
- void QueryCodec(void);
- OMX_ERRORTYPE PrimeFillBuffers(void);
- OMX_ERRORTYPE AllocOMXInputBuffers(void);
- - OMX_ERRORTYPE FreeOMXInputBuffers(bool wait);
- - OMX_ERRORTYPE AllocOMXOutputBuffers(void);
- - OMX_ERRORTYPE FreeOMXOutputBuffers(bool wait);
- - static void CallbackAllocOMXEGLTextures(void*);
- + OMX_ERRORTYPE FreeOMXInputBuffers(void);
- + bool AllocOMXOutputBuffers(void);
- + bool FreeOMXOutputBuffers(void);
- + static bool CallbackAllocOMXEGLTextures(void*);
- OMX_ERRORTYPE AllocOMXOutputEGLTextures(void);
- - static void CallbackFreeOMXEGLTextures(void*);
- - OMX_ERRORTYPE FreeOMXOutputEGLTextures(bool wait);
- -
- - // TODO Those should move into the base class. After start actions can be executed by callbacks.
- - OMX_ERRORTYPE StartDecoder(void);
- + static bool CallbackFreeOMXEGLTextures(void*);
- + OMX_ERRORTYPE FreeOMXOutputEGLTextures(void);
- OMX_ERRORTYPE StopDecoder(void);
- -
- - // OpenMax decoder callback routines.
- - virtual OMX_ERRORTYPE DecoderEventHandler(OMX_HANDLETYPE hComponent, OMX_PTR pAppData,
- - OMX_EVENTTYPE eEvent, OMX_U32 nData1, OMX_U32 nData2, OMX_PTR pEventData);
- - virtual OMX_ERRORTYPE DecoderEmptyBufferDone(
- - OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBuffer);
- - virtual OMX_ERRORTYPE DecoderFillBufferDone(
- - OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBufferHeader);
- + OMX_ERRORTYPE ReturnOpenMaxBuffer(COpenMaxVideoBuffer *buffer);
-
- // EGL Resources
- EGLDisplay m_egl_display;
- EGLContext m_egl_context;
-
- // Video format
- - DVDVideoPicture m_videobuffer;
- bool m_drop_state;
- int m_decoded_width;
- int m_decoded_height;
- + unsigned int m_egl_buffer_count;
- +
- + bool m_port_settings_changed;
- + const char *m_pFormatName;
-
- std::queue<double> m_dts_queue;
- std::queue<omx_demux_packet> m_demux_queue;
-
- - // OpenMax input buffers (demuxer packets)
- - pthread_mutex_t m_omx_input_mutex;
- - std::queue<OMX_BUFFERHEADERTYPE*> m_omx_input_avaliable;
- - std::vector<OMX_BUFFERHEADERTYPE*> m_omx_input_buffers;
- - bool m_omx_input_eos;
- - int m_omx_input_port;
- - //sem_t *m_omx_flush_input;
- - CEvent m_input_consumed_event;
- -
- // OpenMax output buffers (video frames)
- pthread_mutex_t m_omx_output_mutex;
- - std::queue<OpenMaxVideoBuffer*> m_omx_output_busy;
- - std::queue<OpenMaxVideoBuffer*> m_omx_output_ready;
- - std::vector<OpenMaxVideoBuffer*> m_omx_output_buffers;
- - bool m_omx_output_eos;
- - int m_omx_output_port;
- - //sem_t *m_omx_flush_output;
- + std::vector<COpenMaxVideoBuffer*> m_omx_output_busy;
- + std::queue<COpenMaxVideoBuffer*> m_omx_output_ready;
- + std::vector<COpenMaxVideoBuffer*> m_omx_output_buffers;
- +
- + // initialize OpenMax and get decoder component
- + bool Initialize( const CStdString &decoder_name);
- +
- + // Components
- + COMXCoreComponent m_omx_decoder;
- + COMXCoreComponent m_omx_egl_render;
-
- - bool m_portChanging;
- + COMXCoreTunel m_omx_tunnel;
- + OMX_VIDEO_CODINGTYPE m_codingType;
-
- - volatile bool m_videoplayback_done;
- + bool PortSettingsChanged();
- + bool SendDecoderConfig(uint8_t *extradata, int extrasize);
- + bool NaluFormatStartCodes(enum AVCodecID codec, uint8_t *extradata, int extrasize);
- };
-
- // defined(HAVE_LIBOPENMAX)
- diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
- index a485275..d607f55 100644
- --- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
- +++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
- @@ -2988,7 +2988,9 @@ bool CDVDPlayer::OpenVideoStream(int iStream, int source, bool reset)
- hint.aspect = aspect;
- hint.forced_aspect = true;
- }
- +#ifndef TARGET_RASPBERRY_PI
- hint.software = true;
- +#endif
- }
-
- boost::shared_ptr<CPVRClient> client;
- diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
- index 99b3155..fddb7f7 100644
- --- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
- +++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
- @@ -325,6 +325,9 @@ void CDVDPlayerVideo::Process()
-
- while (!m_bStop)
- {
- + DemuxPacket staticPacket = {};
- + DemuxPacket* pPacket = NULL;
- + bool bPacketDrop = false;
- int iQueueTimeOut = (int)(m_stalled ? frametime / 4 : frametime * 10) / 1000;
- int iPriority = (m_speed == DVD_PLAYSPEED_PAUSE && m_started) ? 1 : 0;
-
- @@ -361,8 +364,10 @@ void CDVDPlayerVideo::Process()
- OutputPicture(&picture, pts);
- pts+= frametime;
- }
- -
- - continue;
- + pPacket = &staticPacket;
- + bPacketDrop = false;
- + goto submit_empty_packet;
- + //continue;
- }
-
- if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE))
- @@ -489,9 +494,12 @@ void CDVDPlayerVideo::Process()
-
- if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET))
- {
- - DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket();
- - bool bPacketDrop = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop();
- -
- + pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket();
- + bPacketDrop = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop();
- + }
- +submit_empty_packet:
- + if (ret == MSGQ_TIMEOUT || pMsg->IsType(CDVDMsg::DEMUXER_PACKET))
- + {
- if (m_stalled)
- {
- CLog::Log(LOGINFO, "CDVDPlayerVideo - Stillframe left, switching to normal playback");
- @@ -749,7 +757,8 @@ void CDVDPlayerVideo::Process()
- }
-
- // all data is used by the decoder, we can safely free it now
- - pMsg->Release();
- + if (ret != MSGQ_TIMEOUT)
- + pMsg->Release();
- }
-
- // we need to let decoder release any picture retained resources.
- diff --git a/xbmc/linux/OMXCore.cpp b/xbmc/linux/OMXCore.cpp
- index 6e7d9a9..99e407a 100644
- --- a/xbmc/linux/OMXCore.cpp
- +++ b/xbmc/linux/OMXCore.cpp
- @@ -460,7 +460,12 @@ void COMXCoreComponent::FlushInput()
- CLog::Log(LOGERROR, "COMXCoreComponent::FlushInput - Error on component %s omx_err(0x%08x)",
- m_componentName.c_str(), (int)omx_err);
- }
- - WaitForCommand(OMX_CommandFlush, m_input_port);
- + omx_err = WaitForCommand(OMX_CommandFlush, m_input_port);
- + if(omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "COMXCoreComponent::FlushInput - %s WaitForCommand omx_err(0x%08x)",
- + m_componentName.c_str(), (int)omx_err);
- + }
- }
-
- void COMXCoreComponent::FlushOutput()
- @@ -477,7 +482,12 @@ void COMXCoreComponent::FlushOutput()
- CLog::Log(LOGERROR, "COMXCoreComponent::FlushOutput - Error on component %s omx_err(0x%08x)",
- m_componentName.c_str(), (int)omx_err);
- }
- - WaitForCommand(OMX_CommandFlush, m_output_port);
- + omx_err = WaitForCommand(OMX_CommandFlush, m_output_port);
- + if(omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "COMXCoreComponent::FlushOutput - %s WaitForCommand omx_err(0x%08x)",
- + m_componentName.c_str(), (int)omx_err);
- + }
- }
-
- // timeout in milliseconds
- @@ -1149,7 +1159,12 @@ OMX_STATETYPE COMXCoreComponent::GetState()
-
- OMX_STATETYPE state;
-
- - OMX_GetState(m_handle, &state);
- + OMX_ERRORTYPE omx_err = OMX_GetState(m_handle, &state);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "COMXCoreComponent::GetState - %s failed with omx_err(0x%x)\n",
- + m_componentName.c_str(), omx_err);
- + }
- return state;
- }
-
- @@ -1307,6 +1322,8 @@ OMX_ERRORTYPE COMXCoreComponent::DisablePort(unsigned int port, bool wait)
-
- OMX_ERRORTYPE COMXCoreComponent::UseEGLImage(OMX_BUFFERHEADERTYPE** ppBufferHdr, OMX_U32 nPortIndex, OMX_PTR pAppPrivate, void* eglImage)
- {
- +if (m_callbacks.FillBufferDone == &COMXCoreComponent::DecoderFillBufferDoneCallback)
- +{
- OMX_ERRORTYPE omx_err = OMX_ErrorNone;
-
- if(!m_handle)
- @@ -1383,8 +1400,21 @@ OMX_ERRORTYPE COMXCoreComponent::UseEGLImage(OMX_BUFFERHEADERTYPE** ppBufferHdr,
-
- return omx_err;
- }
- +else
- +{
- + OMX_ERRORTYPE omx_err;
- + omx_err = OMX_UseEGLImage(m_handle, ppBufferHdr, nPortIndex, pAppPrivate, eglImage);
- + if(omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s - %s failed with omx_err(0x%x)\n",
- + CLASSNAME, __func__, m_componentName.c_str(), omx_err);
- + return omx_err;
- + }
- + return omx_err;
- +}
- +}
-
- -bool COMXCoreComponent::Initialize( const std::string &component_name, OMX_INDEXTYPE index)
- +bool COMXCoreComponent::Initialize( const std::string &component_name, OMX_INDEXTYPE index, OMX_CALLBACKTYPE *callbacks)
- {
- OMX_ERRORTYPE omx_err;
-
- @@ -1419,6 +1449,13 @@ bool COMXCoreComponent::Initialize( const std::string &component_name, OMX_INDEX
- m_callbacks.EmptyBufferDone = &COMXCoreComponent::DecoderEmptyBufferDoneCallback;
- m_callbacks.FillBufferDone = &COMXCoreComponent::DecoderFillBufferDoneCallback;
-
- + if (callbacks && callbacks->EventHandler)
- + m_callbacks.EventHandler = callbacks->EventHandler;
- + if (callbacks && callbacks->EmptyBufferDone)
- + m_callbacks.EmptyBufferDone = callbacks->EmptyBufferDone;
- + if (callbacks && callbacks->FillBufferDone)
- + m_callbacks.FillBufferDone = callbacks->FillBufferDone;
- +
- // Get video component handle setting up callbacks, component is in loaded state on return.
- if(!m_handle)
- {
- diff --git a/xbmc/linux/OMXCore.h b/xbmc/linux/OMXCore.h
- index 54d35aa..5b9c2f9 100644
- --- a/xbmc/linux/OMXCore.h
- +++ b/xbmc/linux/OMXCore.h
- @@ -109,7 +109,7 @@ class COMXCoreComponent
- OMX_ERRORTYPE DisablePort(unsigned int port, bool wait = true);
- OMX_ERRORTYPE UseEGLImage(OMX_BUFFERHEADERTYPE** ppBufferHdr, OMX_U32 nPortIndex, OMX_PTR pAppPrivate, void* eglImage);
-
- - bool Initialize( const std::string &component_name, OMX_INDEXTYPE index);
- + bool Initialize( const std::string &component_name, OMX_INDEXTYPE index, OMX_CALLBACKTYPE *callbacks = NULL);
- bool IsInitialized();
- bool Deinitialize();
-
- --
- 1.9.3
- From e9b71fb1ee80896444d3301f919bf315a96530a3 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Sat, 3 May 2014 11:57:25 +0100
- Subject: [PATCH 43/94] [omxcodec] Enable for dvd menus
- ---
- xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp | 4 ++++
- 1 file changed, 4 insertions(+)
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
- index 18b8e3a..c85c8d2 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
- @@ -194,6 +194,10 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne
-
- CLog::Log(LOGDEBUG, "CDVDFactoryCodec: compiled in hardware support: %s", hwSupport.c_str());
-
- +#if defined(HAVE_LIBOPENMAX)
- + // libopenmax can handle dvd playback including stills
- + if (!CSettings::Get().GetBool("videoplayer.useomx"))
- +#endif
- if (hint.stills && (hint.codec == AV_CODEC_ID_MPEG2VIDEO || hint.codec == AV_CODEC_ID_MPEG1VIDEO))
- {
- // If dvd is an mpeg2 and hint.stills
- --
- 1.9.3
- From a7a4ccc26d85d1362a77b718564ddb1f08ca1246 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Mon, 3 Feb 2014 22:27:44 +0000
- Subject: [PATCH 44/94] [omxcodec] Add omx specific texture
- create/upload/delete functions
- ---
- xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 33 +++++++++++++++++++++++++
- xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 4 +++
- 2 files changed, 37 insertions(+)
- diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
- index 6d879e3..279aa90 100644
- --- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
- +++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
- @@ -805,6 +805,12 @@ void CLinuxRendererGLES::LoadShaders(int field)
- m_textureCreate = &CLinuxRendererGLES::CreateNV12Texture;
- m_textureDelete = &CLinuxRendererGLES::DeleteNV12Texture;
- }
- + else if (m_format == RENDER_FMT_OMXEGL)
- + {
- + m_textureUpload = &CLinuxRendererGLES::UploadOMXEGLTexture;
- + m_textureCreate = &CLinuxRendererGLES::CreateOMXEGLTexture;
- + m_textureDelete = &CLinuxRendererGLES::DeleteOMXEGLTexture;
- + }
- else
- {
- // default to YV12 texture handlers
- @@ -2487,6 +2493,33 @@ bool CLinuxRendererGLES::CreateSurfaceTexture(int index)
- return true;
- }
-
- +//********************************************************************************************************
- +// SurfaceTexture creation, deletion, copying + clearing
- +//********************************************************************************************************
- +void CLinuxRendererGLES::UploadOMXEGLTexture(int index)
- +{
- +#ifdef HAVE_LIBOPENMAX
- + YUVBUFFER &buf = m_buffers[index];
- + if (buf.openMaxBuffer)
- + {
- + //buf.openMaxBuffer->Sync();
- + }
- +#endif
- +}
- +void CLinuxRendererGLES::DeleteOMXEGLTexture(int index)
- +{
- +#ifdef HAVE_LIBOPENMAX
- + YUVBUFFER &buf = m_buffers[index];
- + if (buf.openMaxBuffer)
- + SAFE_RELEASE(buf.openMaxBuffer);
- +#endif
- +}
- +bool CLinuxRendererGLES::CreateOMXEGLTexture(int index)
- +{
- + DeleteOMXEGLTexture(index);
- + return true;
- +}
- +
- void CLinuxRendererGLES::SetTextureFilter(GLenum method)
- {
- for (int i = 0 ; i<m_NumYV12Buffers ; i++)
- diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
- index 0ca56a2..f3dd3d3 100644
- --- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
- +++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
- @@ -212,6 +212,10 @@ class CLinuxRendererGLES : public CBaseRenderer
- void DeleteSurfaceTexture(int index);
- bool CreateSurfaceTexture(int index);
-
- + void UploadOMXEGLTexture(int index);
- + void DeleteOMXEGLTexture(int index);
- + bool CreateOMXEGLTexture(int index);
- +
- void CalculateTextureSourceRects(int source, int num_planes);
-
- // renderers
- --
- 1.9.3
- From 6a8bd5509ada85a05ad4672a33b76418573382ea Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Mon, 3 Feb 2014 22:50:43 +0000
- Subject: [PATCH 45/94] [omxcodec] Add shared pointer to delay shutdown of
- codec until buffers are returned
- ---
- .../DVDCodecs/Video/DVDVideoCodecOpenMax.cpp | 13 +++----------
- .../DVDCodecs/Video/DVDVideoCodecOpenMax.h | 3 ++-
- .../dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 21 ++++++++++++++++++++-
- xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h | 5 ++++-
- 4 files changed, 29 insertions(+), 13 deletions(-)
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp
- index 7d33192..ef10555 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp
- @@ -28,7 +28,6 @@
- #include "DVDClock.h"
- #include "DVDStreamInfo.h"
- #include "DVDVideoCodecOpenMax.h"
- -#include "OpenMaxVideo.h"
- #include "settings/Settings.h"
- #include "utils/log.h"
-
- @@ -36,8 +35,8 @@
- ////////////////////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////////////////
- CDVDVideoCodecOpenMax::CDVDVideoCodecOpenMax()
- + : m_omx_decoder( new COpenMaxVideo )
- {
- - m_omx_decoder = NULL;
- CLog::Log(LOGDEBUG, "%s::%s %p\n", CLASSNAME, __func__, this);
- }
-
- @@ -49,8 +48,7 @@ CDVDVideoCodecOpenMax::~CDVDVideoCodecOpenMax()
-
- bool CDVDVideoCodecOpenMax::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
- {
- - m_omx_decoder = new COpenMaxVideo;
- - return m_omx_decoder->Open(hints, options);
- + return m_omx_decoder->Open(hints, options, m_omx_decoder);
- }
-
- const char* CDVDVideoCodecOpenMax::GetName(void)
- @@ -60,12 +58,7 @@ const char* CDVDVideoCodecOpenMax::GetName(void)
-
- void CDVDVideoCodecOpenMax::Dispose()
- {
- - if (m_omx_decoder)
- - {
- - m_omx_decoder->Dispose();
- - delete m_omx_decoder;
- - m_omx_decoder = NULL;
- - }
- + m_omx_decoder->Dispose();
- }
-
- void CDVDVideoCodecOpenMax::SetDropState(bool bDrop)
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h
- index 67cc235..b7c0c1b 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h
- @@ -22,6 +22,7 @@
- #if defined(HAVE_LIBOPENMAX)
-
- #include "DVDVideoCodec.h"
- +#include "OpenMaxVideo.h"
-
- class COpenMaxVideo;
- class CDVDVideoCodecOpenMax : public CDVDVideoCodec
- @@ -42,7 +43,7 @@ class CDVDVideoCodecOpenMax : public CDVDVideoCodec
- virtual const char* GetName(void);
-
- protected:
- - COpenMaxVideo *m_omx_decoder;
- + OpenMaxVideoPtr m_omx_decoder;
- };
-
- #endif
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- index aca2e0d..29b5bb9 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- @@ -126,6 +126,7 @@ COpenMaxVideo::COpenMaxVideo()
- m_egl_buffer_count = 0;
-
- m_port_settings_changed = false;
- + m_finished = false;
- m_pFormatName = "omx-xxxx";
- }
-
- @@ -134,6 +135,7 @@ COpenMaxVideo::~COpenMaxVideo()
- #if defined(OMX_DEBUG_VERBOSE)
- CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this);
- #endif
- + assert(m_finished);
- if (m_omx_decoder.IsInitialized())
- {
- if (m_omx_tunnel.IsInitialized())
- @@ -149,7 +151,7 @@ COpenMaxVideo::~COpenMaxVideo()
- pthread_mutex_destroy(&m_omx_output_mutex);
- }
-
- -bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
- +bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenMaxVideoPtr myself)
- {
- #if defined(OMX_DEBUG_VERBOSE)
- CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
- @@ -161,6 +163,7 @@ bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
-
- OMX_ERRORTYPE omx_err = OMX_ErrorNone;
-
- + m_myself = myself;
- m_decoded_width = hints.width;
- m_decoded_height = hints.height;
-
- @@ -331,6 +334,15 @@ void COpenMaxVideo::Dispose()
- #if defined(OMX_DEBUG_VERBOSE)
- CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
- #endif
- + // we are happy to exit, but let last shared pointer being deleted trigger the destructor
- + bool done = false;
- + pthread_mutex_lock(&m_omx_output_mutex);
- + if (m_omx_output_busy.empty())
- + done = true;
- + m_finished = true;
- + pthread_mutex_unlock(&m_omx_output_mutex);
- + if (done)
- + m_myself.reset();
- }
-
- void COpenMaxVideo::SetDropState(bool bDrop)
- @@ -752,6 +764,13 @@ void COpenMaxVideo::ReleaseOpenMaxBuffer(COpenMaxVideoBuffer *buffer)
- m_omx_output_busy.erase(std::remove(m_omx_output_busy.begin(), m_omx_output_busy.end(), buffer), m_omx_output_busy.end());
- pthread_mutex_unlock(&m_omx_output_mutex);
- ReturnOpenMaxBuffer(buffer);
- + bool done = false;
- + pthread_mutex_lock(&m_omx_output_mutex);
- + if (m_finished && m_omx_output_busy.empty())
- + done = true;
- + pthread_mutex_unlock(&m_omx_output_mutex);
- + if (done)
- + m_myself.reset();
- }
-
- bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture)
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
- index 9079c13..0975e8a 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
- @@ -43,6 +43,7 @@ typedef struct omx_demux_packet {
- } omx_demux_packet;
-
- class COpenMaxVideo;
- +typedef boost::shared_ptr<COpenMaxVideo> OpenMaxVideoPtr;
- // an omx egl video frame
- class COpenMaxVideoBuffer
- {
- @@ -75,7 +76,7 @@ class COpenMaxVideo
- virtual ~COpenMaxVideo();
-
- // Required overrides
- - virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options);
- + virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenMaxVideoPtr myself);
- virtual void Dispose(void);
- virtual int Decode(uint8_t *pData, int iSize, double dts, double pts);
- virtual void Reset(void);
- @@ -112,9 +113,11 @@ class COpenMaxVideo
- int m_decoded_width;
- int m_decoded_height;
- unsigned int m_egl_buffer_count;
- + bool m_finished;
-
- bool m_port_settings_changed;
- const char *m_pFormatName;
- + OpenMaxVideoPtr m_myself;
-
- std::queue<double> m_dts_queue;
- std::queue<omx_demux_packet> m_demux_queue;
- --
- 1.9.3
- From e8f40e625203fe4113e2687d3730c38770cc0857 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Mon, 3 Feb 2014 23:11:31 +0000
- Subject: [PATCH 46/94] [omxcodec] Fix for aspect ratio in non-square pixel
- modes
- ---
- xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 17 +++++++++++++++++
- xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h | 3 +++
- 2 files changed, 20 insertions(+)
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- index 29b5bb9..7e23c87 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- @@ -63,6 +63,7 @@ COpenMaxVideoBuffer::COpenMaxVideoBuffer(COpenMaxVideo *omv)
- index = 0;
- egl_image = 0;
- texture_id = 0;
- + m_aspect_ratio = 0.0f;
- }
-
- COpenMaxVideoBuffer::~COpenMaxVideoBuffer()
- @@ -166,6 +167,8 @@ bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenM
- m_myself = myself;
- m_decoded_width = hints.width;
- m_decoded_height = hints.height;
- + m_forced_aspect_ratio = hints.forced_aspect;
- + m_aspect_ratio = hints.aspect;
-
- m_egl_display = g_Windowing.GetEGLDisplay();
- m_egl_context = g_Windowing.GetEGLContext();
- @@ -435,6 +438,9 @@ bool COpenMaxVideo::PortSettingsChanged()
- CLog::Log(LOGERROR, "%s::%s - error m_omx_decoder.GetParameter(OMX_IndexParamBrcmPixelAspectRatio) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- return false;
- }
- + if (!m_forced_aspect_ratio && pixel_aspect.nX && pixel_aspect.nY)
- + m_aspect_ratio = (float)pixel_aspect.nX * port_def.format.video.nFrameWidth /
- + ((float)pixel_aspect.nY * port_def.format.video.nFrameHeight);
-
- if (m_port_settings_changed)
- {
- @@ -800,6 +806,16 @@ bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture)
- pDvdVideoPicture->iDisplayWidth = m_decoded_width;
- pDvdVideoPicture->iDisplayHeight = m_decoded_height;
-
- + if (buffer->m_aspect_ratio > 0.0 && !m_forced_aspect_ratio)
- + {
- + pDvdVideoPicture->iDisplayWidth = ((int)lrint(pDvdVideoPicture->iHeight * buffer->m_aspect_ratio)) & -3;
- + if (pDvdVideoPicture->iDisplayWidth > pDvdVideoPicture->iWidth)
- + {
- + pDvdVideoPicture->iDisplayWidth = pDvdVideoPicture->iWidth;
- + pDvdVideoPicture->iDisplayHeight = ((int)lrint(pDvdVideoPicture->iWidth / buffer->m_aspect_ratio)) & -3;
- + }
- + }
- +
- #ifdef DTS_QUEUE
- if (!m_dts_queue.empty())
- {
- @@ -853,6 +869,7 @@ OMX_ERRORTYPE COpenMaxVideo::DecoderFillBufferDone(
-
- // queue output omx buffer to ready list.
- pthread_mutex_lock(&m_omx_output_mutex);
- + buffer->m_aspect_ratio = m_aspect_ratio;
- m_omx_output_ready.push(buffer);
- pthread_mutex_unlock(&m_omx_output_mutex);
-
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
- index 0975e8a..9138a20 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
- @@ -54,6 +54,7 @@ class COpenMaxVideoBuffer
- OMX_BUFFERHEADERTYPE *omx_buffer;
- int width;
- int height;
- + float m_aspect_ratio;
- int index;
-
- // used for egl based rendering if active
- @@ -114,6 +115,8 @@ class COpenMaxVideo
- int m_decoded_height;
- unsigned int m_egl_buffer_count;
- bool m_finished;
- + float m_aspect_ratio;
- + bool m_forced_aspect_ratio;
-
- bool m_port_settings_changed;
- const char *m_pFormatName;
- --
- 1.9.3
- From e42ca92b464ad88dbe0f8b0d86080d64d52e08a8 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Mon, 3 Feb 2014 23:19:22 +0000
- Subject: [PATCH 47/94] [omxcodec] Report error when codec not enabled
- ---
- xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 10 +++++++++-
- 1 file changed, 9 insertions(+), 1 deletion(-)
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- index 7e23c87..2ae722b 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- @@ -43,6 +43,7 @@
- #include <IL/OMX_Image.h>
-
- #include "cores/omxplayer/OMXImage.h"
- +#include "linux/RBP.h"
-
- #define DTS_QUEUE
-
- @@ -155,7 +156,7 @@ COpenMaxVideo::~COpenMaxVideo()
- bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenMaxVideoPtr myself)
- {
- #if defined(OMX_DEBUG_VERBOSE)
- - CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
- + CLog::Log(LOGDEBUG, "%s::%s useomx:%d software:%d", CLASSNAME, __func__, CSettings::Get().GetBool("videoplayer.useomx"), hints.software);
- #endif
-
- // we always qualify even if DVDFactoryCodec does this too.
- @@ -232,6 +233,13 @@ bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenM
- break;
- }
-
- + if ( (m_codingType == OMX_VIDEO_CodingMPEG2 && !g_RBP.GetCodecMpg2() ) ||
- + (m_codingType == OMX_VIDEO_CodingWMV && !g_RBP.GetCodecWvc1() ) )
- + {
- + CLog::Log(LOGWARNING, "%s::%s Codec %s is not supported\n", CLASSNAME, __func__, m_pFormatName);
- + return false;
- + }
- +
- // initialize OpenMAX.
- if (!m_omx_decoder.Initialize("OMX.broadcom.video_decode", OMX_IndexParamVideoInit))
- {
- --
- 1.9.3
- From 55b0b157ba32d03ca0ec854b7935aee5601810d8 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Tue, 4 Feb 2014 17:29:37 +0000
- Subject: [PATCH 48/94] [omxcodec] Add deinterlace support
- ---
- xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 2 +-
- .../dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 106 ++++++++++++++++++---
- .../cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h | 9 +-
- 3 files changed, 103 insertions(+), 14 deletions(-)
- diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
- index 279aa90..a57abe4 100644
- --- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
- +++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
- @@ -2607,7 +2607,7 @@ bool CLinuxRendererGLES::Supports(EDEINTERLACEMODE mode)
- return true;
-
- if(m_renderMethod & RENDER_OMXEGL)
- - return false;
- + return true;
-
- if(m_renderMethod & RENDER_EGLIMG)
- return false;
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- index 2ae722b..fbf1458 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- @@ -33,6 +33,7 @@
- #include "utils/log.h"
- #include "utils/TimeUtils.h"
- #include "settings/Settings.h"
- +#include "settings/MediaSettings.h"
- #include "ApplicationMessenger.h"
- #include "Application.h"
- #include "threads/Atomics.h"
- @@ -130,6 +131,10 @@ COpenMaxVideo::COpenMaxVideo()
- m_port_settings_changed = false;
- m_finished = false;
- m_pFormatName = "omx-xxxx";
- +
- + m_deinterlace = false;
- + m_deinterlace_request = VS_DEINTERLACEMODE_OFF;
- + m_deinterlace_second_field = false;
- }
-
- COpenMaxVideo::~COpenMaxVideo()
- @@ -140,13 +145,17 @@ COpenMaxVideo::~COpenMaxVideo()
- assert(m_finished);
- if (m_omx_decoder.IsInitialized())
- {
- - if (m_omx_tunnel.IsInitialized())
- - m_omx_tunnel.Deestablish();
- + if (m_omx_tunnel_decoder.IsInitialized())
- + m_omx_tunnel_decoder.Deestablish();
- + if (m_omx_tunnel_image_fx.IsInitialized())
- + m_omx_tunnel_image_fx.Deestablish();
-
- StopDecoder();
-
- if (m_omx_egl_render.IsInitialized())
- m_omx_egl_render.Deinitialize();
- + if (m_omx_image_fx.IsInitialized())
- + m_omx_image_fx.Deinitialize();
- if (m_omx_decoder.IsInitialized())
- m_omx_decoder.Deinitialize();
- }
- @@ -165,6 +174,8 @@ bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenM
-
- OMX_ERRORTYPE omx_err = OMX_ErrorNone;
-
- + m_deinterlace_request = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
- +
- m_myself = myself;
- m_decoded_width = hints.width;
- m_decoded_height = hints.height;
- @@ -467,6 +478,49 @@ bool COpenMaxVideo::PortSettingsChanged()
- return false;
- }
-
- + OMX_CONFIG_INTERLACETYPE interlace;
- + OMX_INIT_STRUCTURE(interlace);
- + interlace.nPortIndex = m_omx_decoder.GetOutputPort();
- + omx_err = m_omx_decoder.GetConfig(OMX_IndexConfigCommonInterlace, &interlace);
- +
- + if (m_deinterlace_request == VS_DEINTERLACEMODE_FORCE)
- + m_deinterlace = true;
- + else if (m_deinterlace_request == VS_DEINTERLACEMODE_OFF)
- + m_deinterlace = false;
- + else
- + m_deinterlace = interlace.eMode != OMX_InterlaceProgressive;
- +
- + CLog::Log(LOGDEBUG, "%s::%s - %dx%d@%.2f interlace:%d deinterlace:%d",
- + CLASSNAME, __func__, port_def.format.video.nFrameWidth, port_def.format.video.nFrameHeight, port_def.format.video.xFramerate / (float) (1 << 16),
- + interlace.eMode, m_deinterlace);
- +
- + if (m_deinterlace)
- + {
- + if (!m_omx_image_fx.Initialize("OMX.broadcom.image_fx", OMX_IndexParamImageInit))
- + {
- + CLog::Log(LOGERROR, "%s::%s error m_omx_image_fx.Initialize", CLASSNAME, __func__);
- + return false;
- + }
- + }
- +
- + if (m_deinterlace)
- + {
- + OMX_CONFIG_IMAGEFILTERPARAMSTYPE image_filter;
- + OMX_INIT_STRUCTURE(image_filter);
- +
- + image_filter.nPortIndex = m_omx_image_fx.GetOutputPort();
- + image_filter.nNumParams = 1;
- + image_filter.nParams[0] = 3;
- + image_filter.eImageFilter = OMX_ImageFilterDeInterlaceAdvanced;
- +
- + omx_err = m_omx_image_fx.SetConfig(OMX_IndexConfigCommonImageFilterParameters, &image_filter);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s - OMX_IndexConfigCommonImageFilterParameters omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- + }
- +
- OMX_CALLBACKTYPE callbacks = { NULL, NULL, DecoderFillBufferDoneCallback };
- if (!m_omx_egl_render.Initialize("OMX.broadcom.egl_render", OMX_IndexParamVideoInit, &callbacks))
- {
- @@ -487,19 +541,40 @@ bool COpenMaxVideo::PortSettingsChanged()
-
- m_omx_egl_render.ResetEos();
-
- - CLog::Log(LOGDEBUG, "%s::%s - %dx%d@%.2f interlace:%d deinterlace:%d", CLASSNAME, __func__,
- - port_def.format.video.nFrameWidth, port_def.format.video.nFrameHeight,
- - port_def.format.video.xFramerate / (float)(1<<16), 0,0);
- -
- - m_omx_tunnel.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_egl_render, m_omx_egl_render.GetInputPort());
- + if (m_deinterlace)
- + {
- + m_omx_tunnel_decoder.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_image_fx, m_omx_image_fx.GetInputPort());
- + m_omx_tunnel_image_fx.Initialize(&m_omx_image_fx, m_omx_image_fx.GetOutputPort(), &m_omx_egl_render, m_omx_egl_render.GetInputPort());
- + }
- + else
- + {
- + m_omx_tunnel_decoder.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_egl_render, m_omx_egl_render.GetInputPort());
- + }
-
- - omx_err = m_omx_tunnel.Establish();
- + omx_err = m_omx_tunnel_decoder.Establish();
- if (omx_err != OMX_ErrorNone)
- {
- - CLog::Log(LOGERROR, "%s::%s - m_omx_tunnel.Establish omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- + CLog::Log(LOGERROR, "%s::%s - m_omx_tunnel_decoder.Establish omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- return false;
- }
-
- + if (m_deinterlace)
- + {
- + omx_err = m_omx_tunnel_image_fx.Establish();
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s - m_omx_tunnel_image_fx.Establish omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- + omx_err = m_omx_image_fx.SetStateForComponent(OMX_StateExecuting);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s - m_omx_image_fx.SetStateForComponent omx_err(0x%08x)",
- + CLASSNAME, __func__, omx_err);
- + return false;
- + }
- + }
- +
- // Obtain the information about the output port.
- OMX_PARAM_PORTDEFINITIONTYPE port_format;
- OMX_INIT_STRUCTURE(port_format);
- @@ -724,8 +799,12 @@ void COpenMaxVideo::Reset(void)
- #if defined(OMX_DEBUG_VERBOSE)
- CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
- #endif
- - m_omx_egl_render.FlushAll();
- - m_omx_decoder.FlushAll();
- + if (m_omx_egl_render.IsInitialized())
- + m_omx_egl_render.FlushAll();
- + if (m_omx_image_fx.IsInitialized())
- + m_omx_image_fx.FlushAll();
- + if (m_omx_decoder.IsInitialized())
- + m_omx_decoder.FlushAll();
- // blow all ready video frames
- while (!m_omx_output_ready.empty())
- {
- @@ -825,11 +904,14 @@ bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture)
- }
-
- #ifdef DTS_QUEUE
- - if (!m_dts_queue.empty())
- + if (!m_deinterlace_second_field)
- {
- + assert(!m_dts_queue.empty());
- pDvdVideoPicture->dts = m_dts_queue.front();
- m_dts_queue.pop();
- }
- + if (m_deinterlace)
- + m_deinterlace_second_field = !m_deinterlace_second_field;
- #endif
- // nTimeStamp is in microseconds
- double ts = FromOMXTime(buffer->omx_buffer->nTimeStamp);
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
- index 9138a20..c8ad4d8 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
- @@ -31,6 +31,7 @@
- #include "cores/dvdplayer/DVDStreamInfo.h"
- #include "DVDVideoCodec.h"
- #include "threads/Event.h"
- +#include "xbmc/settings/VideoSettings.h"
-
- #include <queue>
- #include <semaphore.h>
- @@ -136,11 +137,17 @@ class COpenMaxVideo
-
- // Components
- COMXCoreComponent m_omx_decoder;
- + COMXCoreComponent m_omx_image_fx;
- COMXCoreComponent m_omx_egl_render;
-
- - COMXCoreTunel m_omx_tunnel;
- + COMXCoreTunel m_omx_tunnel_decoder;
- + COMXCoreTunel m_omx_tunnel_image_fx;
- OMX_VIDEO_CODINGTYPE m_codingType;
-
- + bool m_deinterlace;
- + EDEINTERLACEMODE m_deinterlace_request;
- + bool m_deinterlace_second_field;
- +
- bool PortSettingsChanged();
- bool SendDecoderConfig(uint8_t *extradata, int extrasize);
- bool NaluFormatStartCodes(enum AVCodecID codec, uint8_t *extradata, int extrasize);
- --
- 1.9.3
- From 0701b41709e6a18567b9f6bfd0d491285546eedc Mon Sep 17 00:00:00 2001
- From: Ben Avison <bavison@riscosopen.org>
- Date: Wed, 12 Feb 2014 18:43:14 +0000
- Subject: [PATCH 49/94] Improved file buffering in CArchive.
- CArchive already did some file buffering, but only on writes. Added the
- equivalent code for reads. Also improved the write buffer case so that it
- only ever issues sector-aligned writes (the read code does this from the
- start). Shuffled various bits of code into the header file to squeeze a bit
- more performance out of it.
- Profiled the effect on CFileItemList::Archive(), which is one of the slow
- parts of the process of reopening a media library, on a non-overclocked
- Raspberry Pi. Times are in seconds:
- TV shows (253 items)
- Before After
- Mean StdDev Mean StdDev Confidence Change
- 0.394 0.005 0.151 0.005 100.0% +159.8%
- Songs (4115 items)
- Before After
- Mean StdDev Mean StdDev Confidence Change
- 2.931 0.045 0.690 0.019 100.0% +324.4%
- ---
- xbmc/utils/Archive.cpp | 158 ++++++++++++++++++-------------------------------
- xbmc/utils/Archive.h | 130 ++++++++++++++++++++++++++++++++++------
- 2 files changed, 172 insertions(+), 116 deletions(-)
- diff --git a/xbmc/utils/Archive.cpp b/xbmc/utils/Archive.cpp
- index 4519e19..b2ad273 100644
- --- a/xbmc/utils/Archive.cpp
- +++ b/xbmc/utils/Archive.cpp
- @@ -30,24 +30,29 @@
-
- using namespace XFILE;
-
- -#define BUFFER_MAX 4096
- -
- CArchive::CArchive(CFile* pFile, int mode)
- {
- m_pFile = pFile;
- m_iMode = mode;
-
- - m_pBuffer = new uint8_t[BUFFER_MAX];
- - memset(m_pBuffer, 0, BUFFER_MAX);
- -
- - m_BufferPos = 0;
- + m_pBuffer = new uint8_t[CARCHIVE_BUFFER_MAX];
- + memset(m_pBuffer, 0, CARCHIVE_BUFFER_MAX);
- + if (mode == load)
- + {
- + m_BufferPos = m_pBuffer + CARCHIVE_BUFFER_MAX;
- + m_BufferRemain = 0;
- + }
- + else
- + {
- + m_BufferPos = m_pBuffer;
- + m_BufferRemain = CARCHIVE_BUFFER_MAX;
- + }
- }
-
- CArchive::~CArchive()
- {
- FlushBuffer();
- delete[] m_pBuffer;
- - m_BufferPos = 0;
- }
-
- void CArchive::Close()
- @@ -214,89 +219,6 @@ CArchive& CArchive::operator<<(const std::vector<int>& iArray)
- return *this;
- }
-
- -inline CArchive& CArchive::streamout(const void* dataPtr, size_t size)
- -{
- - const uint8_t* ptr = (const uint8_t*)dataPtr;
- -
- - if (size + m_BufferPos >= BUFFER_MAX)
- - {
- - FlushBuffer();
- - while (size >= BUFFER_MAX)
- - {
- - memcpy(m_pBuffer, ptr, BUFFER_MAX);
- - m_BufferPos = BUFFER_MAX;
- - ptr += BUFFER_MAX;
- - size -= BUFFER_MAX;
- - FlushBuffer();
- - }
- - }
- -
- - memcpy(m_pBuffer + m_BufferPos, ptr, size);
- - m_BufferPos += size;
- -
- - return *this;
- -}
- -
- -CArchive& CArchive::operator>>(float& f)
- -{
- - return streamin(&f, sizeof(f));
- -}
- -
- -CArchive& CArchive::operator>>(double& d)
- -{
- - return streamin(&d, sizeof(d));
- -}
- -
- -CArchive& CArchive::operator>>(short int& s)
- -{
- - return streamin(&s, sizeof(s));
- -}
- -
- -CArchive& CArchive::operator>>(unsigned short int& us)
- -{
- - return streamin(&us, sizeof(us));
- -}
- -
- -CArchive& CArchive::operator>>(int& i)
- -{
- - return streamin(&i, sizeof(i));
- -}
- -
- -CArchive& CArchive::operator>>(unsigned int& ui)
- -{
- - return streamin(&ui, sizeof(ui));
- -}
- -
- -CArchive& CArchive::operator>>(long int& l)
- -{
- - return streamin(&l, sizeof(l));
- -}
- -
- -CArchive& CArchive::operator>>(unsigned long int& ul)
- -{
- - return streamin(&ul, sizeof(ul));
- -}
- -
- -CArchive& CArchive::operator>>(long long int& ll)
- -{
- - return streamin(&ll, sizeof(ll));
- -}
- -
- -CArchive& CArchive::operator>>(unsigned long long int& ull)
- -{
- - return streamin(&ull, sizeof(ull));
- -}
- -
- -CArchive& CArchive::operator>>(bool& b)
- -{
- - return streamin(&b, sizeof(b));
- -}
- -
- -CArchive& CArchive::operator>>(char& c)
- -{
- - return streamin(&c, sizeof(c));
- -}
- -
- CArchive& CArchive::operator>>(std::string& str)
- {
- size_t iLength = 0;
- @@ -450,23 +372,61 @@ CArchive& CArchive::operator>>(std::vector<int>& iArray)
- return *this;
- }
-
- -inline CArchive& CArchive::streamin(void* dataPtr, const size_t size)
- +void CArchive::FlushBuffer()
- {
- - size_t read = m_pFile->Read(dataPtr, size);
- - if (read < size)
- + if (m_iMode == store && m_BufferPos != m_pBuffer)
- {
- - CLog::Log(LOGERROR, "%s: can't stream out: requested %lu bytes, was read %lu bytes", __FUNCTION__, (unsigned long)size, (unsigned long)read);
- - memset(dataPtr, 0, size);
- + m_pFile->Write(m_pBuffer, m_BufferPos - m_pBuffer);
- + m_BufferPos = m_pBuffer;
- + m_BufferRemain = CARCHIVE_BUFFER_MAX;
- }
- +}
-
- +CArchive &CArchive::streamout_bufferwrap(const uint8_t *ptr, size_t size)
- +{
- + do
- + {
- + size_t chunkSize = std::min(size, m_BufferRemain);
- + m_BufferPos = std::copy(ptr, ptr + chunkSize, m_BufferPos);
- + ptr += chunkSize;
- + size -= chunkSize;
- + m_BufferRemain -= chunkSize;
- + if (m_BufferRemain == 0)
- + FlushBuffer();
- + } while (size > 0);
- return *this;
- }
-
- -void CArchive::FlushBuffer()
- +void CArchive::FillBuffer()
- {
- - if (m_BufferPos > 0)
- + if (m_iMode == load && m_BufferRemain == 0)
- {
- - m_pFile->Write(m_pBuffer, m_BufferPos);
- - m_BufferPos = 0;
- + m_BufferRemain = m_pFile->Read(m_pBuffer, CARCHIVE_BUFFER_MAX);
- + m_BufferPos = m_pBuffer;
- }
- }
- +
- +CArchive &CArchive::streamin_bufferwrap(uint8_t *ptr, size_t size)
- +{
- + uint8_t *orig_ptr = ptr;
- + size_t orig_size = size;
- + do
- + {
- + if (m_BufferRemain == 0)
- + {
- + FillBuffer();
- + if (m_BufferRemain < CARCHIVE_BUFFER_MAX && m_BufferRemain < size)
- + {
- + CLog::Log(LOGERROR, "%s: can't stream in: requested %lu bytes, was read %lu bytes", __FUNCTION__, (unsigned long) orig_size, (unsigned long) (ptr - orig_ptr + m_BufferRemain));
- + memset(orig_ptr, 0, orig_size);
- + return *this;
- + }
- + }
- + size_t chunkSize = std::min(size, m_BufferRemain);
- + ptr = std::copy(m_BufferPos, m_BufferPos + chunkSize, ptr);
- + m_BufferPos += chunkSize;
- + m_BufferRemain -= chunkSize;
- + size -= chunkSize;
- + } while (size > 0);
- + return *this;
- +}
- diff --git a/xbmc/utils/Archive.h b/xbmc/utils/Archive.h
- index 0148fcb..5b25be5 100644
- --- a/xbmc/utils/Archive.h
- +++ b/xbmc/utils/Archive.h
- @@ -24,6 +24,8 @@
- #include <vector>
- #include "PlatformDefs.h" // for SYSTEMTIME
-
- +#define CARCHIVE_BUFFER_MAX 4096
- +
- namespace XFILE
- {
- class CFile;
- @@ -77,18 +79,66 @@ class CArchive
- CArchive& operator<<(const std::vector<int>& iArray);
-
- // loading
- - CArchive& operator>>(float& f);
- - CArchive& operator>>(double& d);
- - CArchive& operator>>(short int& s);
- - CArchive& operator>>(unsigned short int& us);
- - CArchive& operator>>(int& i);
- - CArchive& operator>>(unsigned int& ui);
- - CArchive& operator>>(long int& l);
- - CArchive& operator>>(unsigned long int& ul);
- - CArchive& operator>>(long long int& ll);
- - CArchive& operator>>(unsigned long long int& ull);
- - CArchive& operator>>(bool& b);
- - CArchive& operator>>(char& c);
- + inline CArchive& operator>>(float& f)
- + {
- + return streamin(&f, sizeof(f));
- + }
- +
- + inline CArchive& operator>>(double& d)
- + {
- + return streamin(&d, sizeof(d));
- + }
- +
- + inline CArchive& operator>>(short int& s)
- + {
- + return streamin(&s, sizeof(s));
- + }
- +
- + inline CArchive& operator>>(unsigned short int& us)
- + {
- + return streamin(&us, sizeof(us));
- + }
- +
- + inline CArchive& operator>>(int& i)
- + {
- + return streamin(&i, sizeof(i));
- + }
- +
- + inline CArchive& operator>>(unsigned int& ui)
- + {
- + return streamin(&ui, sizeof(ui));
- + }
- +
- + inline CArchive& operator>>(long int& l)
- + {
- + return streamin(&l, sizeof(l));
- + }
- +
- + inline CArchive& operator>>(unsigned long int& ul)
- + {
- + return streamin(&ul, sizeof(ul));
- + }
- +
- + inline CArchive& operator>>(long long int& ll)
- + {
- + return streamin(&ll, sizeof(ll));
- + }
- +
- + inline CArchive& operator>>(unsigned long long int& ull)
- + {
- + return streamin(&ull, sizeof(ull));
- + }
- +
- + inline CArchive& operator>>(bool& b)
- + {
- + return streamin(&b, sizeof(b));
- + }
- +
- + inline CArchive& operator>>(char& c)
- + {
- + return streamin(&c, sizeof(c));
- + }
- +
- CArchive& operator>>(std::string &str);
- CArchive& operator>>(std::wstring& wstr);
- CArchive& operator>>(SYSTEMTIME& time);
- @@ -105,12 +155,58 @@ class CArchive
- enum Mode {load = 0, store};
-
- protected:
- - CArchive& streamout(const void* dataPtr, size_t size);
- - CArchive& streamin(void* dataPtr, const size_t size);
- - void FlushBuffer();
- + inline CArchive &streamout(const void *dataPtr, size_t size)
- + {
- + const uint8_t *ptr = (const uint8_t *) dataPtr;
- + /* Note, the buffer is flushed as soon as it is full (m_BufferRemain == size) rather
- + * than waiting until we attempt to put more data into an already full buffer */
- + if (m_BufferRemain > size)
- + {
- + switch (size)
- + {
- + case 1: *m_BufferPos++ = *ptr; m_BufferRemain--; break;
- + case 2: *(uint16_t *) m_BufferPos = *(const uint16_t *) ptr; m_BufferPos += 2; m_BufferRemain -= 2; break;
- + case 4: *(uint32_t *) m_BufferPos = *(const uint32_t *) ptr; m_BufferPos += 4; m_BufferRemain -= 4; break;
- + default: m_BufferPos = std::copy(ptr, ptr + size, m_BufferPos); m_BufferRemain -= size; break;
- + }
- + return *this;
- + }
- + else
- + {
- + return streamout_bufferwrap(ptr, size);
- + }
- + }
- +
- + inline CArchive &streamin(void *dataPtr, size_t size)
- + {
- + uint8_t *ptr = (uint8_t *) dataPtr;
- + /* Note, refilling the buffer is deferred until we know we need to read more from it */
- + if (m_BufferRemain >= size)
- + {
- + switch (size)
- + {
- + case 1: *ptr = *m_BufferPos++; m_BufferRemain--; break;
- + case 2: *(uint16_t *) ptr = *(const uint16_t *) m_BufferPos; m_BufferPos += 2; m_BufferRemain -= 2; break;
- + case 4: *(uint32_t *) ptr = *(const uint32_t *) m_BufferPos; m_BufferPos += 4; m_BufferRemain -= 4; break;
- + default: std::copy(m_BufferPos, m_BufferPos + size, ptr); m_BufferPos += size; m_BufferRemain -= size; break;
- + }
- + return *this;
- + }
- + else
- + {
- + return streamin_bufferwrap(ptr, size);
- + }
- + }
- +
- XFILE::CFile* m_pFile;
- int m_iMode;
- uint8_t *m_pBuffer;
- - int m_BufferPos;
- -};
- + uint8_t *m_BufferPos;
- + size_t m_BufferRemain;
-
- +private:
- + void FlushBuffer();
- + CArchive &streamout_bufferwrap(const uint8_t *ptr, size_t size);
- + void FillBuffer();
- + CArchive &streamin_bufferwrap(uint8_t *ptr, size_t size);
- +};
- --
- 1.9.3
- From 2ae9667952e98ab91b0056094231e923570fa64b Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Wed, 5 Feb 2014 11:46:33 +0000
- Subject: [PATCH 50/94] [rbp/settings] Allow av sync type to be enabled
- It works for dvdplayer
- ---
- system/settings/rbp.xml | 7 -------
- 1 file changed, 7 deletions(-)
- diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml
- index 2b7d0a6..1429256 100644
- --- a/system/settings/rbp.xml
- +++ b/system/settings/rbp.xml
- @@ -1,13 +1,6 @@
- <?xml version="1.0" encoding="utf-8" ?>
- <settings>
- <section id="videos">
- - <category id="videoplayer">
- - <group id="2">
- - <setting id="videoplayer.synctype">
- - <visible>false</visible>
- - </setting>
- - </group>
- - </category>
- <category id="videoacceleration">
- <group id="1">
- <visible>false</visible>
- --
- 1.9.3
- From 4fb1419b986a36f2e53a5bca71caf90bd13443ba Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Sun, 16 Feb 2014 17:38:05 +0000
- Subject: [PATCH 51/94] [omxcodec] Only do essential calls in texture thread
- [omxcodec] Fix for files with no valid pts values. [omxcodec] Fix stall on
- seek/trickplay - need to reset start flag [omxcodec] Make sure we have a
- valid context when video decode starts before first fanart is decoded
- [omxcodec] More care with dropping frames quickly
- ---
- .../dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 127 ++++++++++++++-------
- .../cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h | 14 +--
- 2 files changed, 89 insertions(+), 52 deletions(-)
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- index fbf1458..71d19af 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- @@ -55,6 +55,9 @@
-
- #define CLASSNAME "COpenMaxVideo"
-
- +#define OMX_BUFFERFLAG_PTS_INVALID (1<<28)
- +#define OMX_BUFFERFLAG_DROPPED (1<<29)
- +
- COpenMaxVideoBuffer::COpenMaxVideoBuffer(COpenMaxVideo *omv)
- : m_omv(omv), m_refs(0)
- {
- @@ -120,7 +123,9 @@ void COpenMaxVideoBuffer::Sync()
-
- COpenMaxVideo::COpenMaxVideo()
- {
- + #if defined(OMX_DEBUG_VERBOSE)
- CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this);
- + #endif
- pthread_mutex_init(&m_omx_output_mutex, NULL);
-
- m_drop_state = false;
- @@ -135,6 +140,7 @@ COpenMaxVideo::COpenMaxVideo()
- m_deinterlace = false;
- m_deinterlace_request = VS_DEINTERLACEMODE_OFF;
- m_deinterlace_second_field = false;
- + m_startframe = false;
- }
-
- COpenMaxVideo::~COpenMaxVideo()
- @@ -182,8 +188,6 @@ bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenM
- m_forced_aspect_ratio = hints.forced_aspect;
- m_aspect_ratio = hints.aspect;
-
- - m_egl_display = g_Windowing.GetEGLDisplay();
- - m_egl_context = g_Windowing.GetEGLContext();
- m_egl_buffer_count = 4;
-
- m_codingType = OMX_VIDEO_CodingUnused;
- @@ -347,6 +351,7 @@ bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenM
- return false;
-
- m_drop_state = false;
- + m_startframe = false;
-
- return true;
- }
- @@ -375,6 +380,25 @@ void COpenMaxVideo::SetDropState(bool bDrop)
- CLASSNAME, __func__, bDrop);
- #endif
- m_drop_state = bDrop;
- + if (m_drop_state)
- + {
- + while (1)
- + {
- + COpenMaxVideoBuffer *buffer = NULL;
- + pthread_mutex_lock(&m_omx_output_mutex);
- + // fetch a output buffer and pop it off the ready list
- + if (!m_omx_output_ready.empty())
- + {
- + buffer = m_omx_output_ready.front();
- + m_omx_output_ready.pop();
- + }
- + pthread_mutex_unlock(&m_omx_output_mutex);
- + if (buffer)
- + ReturnOpenMaxBuffer(buffer);
- + else
- + break;
- + }
- + }
- }
-
- bool COpenMaxVideo::SendDecoderConfig(uint8_t *extradata, int extrasize)
- @@ -713,10 +737,13 @@ int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
-
- if (demuxer_bytes == 0)
- omx_buffer->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
- - if (pts == DVD_NOPTS_VALUE)
- + // openmax doesn't like an unknown timestamp as first frame
- + if (pts == DVD_NOPTS_VALUE && m_startframe)
- omx_buffer->nFlags |= OMX_BUFFERFLAG_TIME_UNKNOWN;
- + if (pts == DVD_NOPTS_VALUE) // hijack an omx flag to indicate there wasn't a real timestamp - it will be returned with the picture (but otherwise ignored)
- + omx_buffer->nFlags |= OMX_BUFFERFLAG_PTS_INVALID;
- if (m_drop_state) // hijack an omx flag to signal this frame to be dropped - it will be returned with the picture (but otherwise ignored)
- - omx_buffer->nFlags |= OMX_BUFFERFLAG_DATACORRUPT;
- + omx_buffer->nFlags |= OMX_BUFFERFLAG_DECODEONLY | OMX_BUFFERFLAG_DROPPED;
-
- #if defined(OMX_DEBUG_VERBOSE)
- CLog::Log(LOGDEBUG, "%s::%s - %-6d dts:%.3f pts:%.3f flags:%x",
- @@ -731,10 +758,14 @@ int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
- }
- if (demuxer_bytes == 0)
- {
- + m_startframe = true;
- #ifdef DTS_QUEUE
- - // only push if we are successful with feeding OMX_EmptyThisBuffer
- - m_dts_queue.push(dts);
- - assert(m_dts_queue.size() < 32);
- + if (!m_drop_state)
- + {
- + // only push if we are successful with feeding OMX_EmptyThisBuffer
- + m_dts_queue.push(dts);
- + assert(m_dts_queue.size() < 32);
- + }
- #endif
- if (buffer_to_free)
- {
- @@ -806,15 +837,8 @@ void COpenMaxVideo::Reset(void)
- if (m_omx_decoder.IsInitialized())
- m_omx_decoder.FlushAll();
- // blow all ready video frames
- - while (!m_omx_output_ready.empty())
- - {
- - pthread_mutex_lock(&m_omx_output_mutex);
- - COpenMaxVideoBuffer *pic = m_omx_output_ready.front();
- - m_omx_output_ready.pop();
- - pthread_mutex_unlock(&m_omx_output_mutex);
- - // return the omx buffer back to OpenMax to fill.
- - ReturnOpenMaxBuffer(pic);
- - }
- + SetDropState(true);
- + SetDropState(false);
- #ifdef DTS_QUEUE
- while (!m_dts_queue.empty())
- m_dts_queue.pop();
- @@ -822,6 +846,7 @@ void COpenMaxVideo::Reset(void)
-
- while (!m_demux_queue.empty())
- m_demux_queue.pop();
- + m_startframe = false;
- }
-
-
- @@ -914,17 +939,17 @@ bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture)
- m_deinterlace_second_field = !m_deinterlace_second_field;
- #endif
- // nTimeStamp is in microseconds
- - double ts = FromOMXTime(buffer->omx_buffer->nTimeStamp);
- - pDvdVideoPicture->pts = (ts == 0) ? DVD_NOPTS_VALUE : ts;
- + pDvdVideoPicture->pts = FromOMXTime(buffer->omx_buffer->nTimeStamp);
- pDvdVideoPicture->openMaxBuffer->Acquire();
- pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED;
- - if (buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_DATACORRUPT)
- - pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED;
- + if (buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_PTS_INVALID)
- + pDvdVideoPicture->pts = DVD_NOPTS_VALUE;
- #if defined(OMX_DEBUG_VERBOSE)
- CLog::Log(LOGINFO, "%s::%s dts:%.3f pts:%.3f flags:%x:%x openMaxBuffer:%p omx_buffer:%p egl_image:%p texture_id:%x", CLASSNAME, __func__,
- pDvdVideoPicture->dts == DVD_NOPTS_VALUE ? 0.0 : pDvdVideoPicture->dts*1e-6, pDvdVideoPicture->pts == DVD_NOPTS_VALUE ? 0.0 : pDvdVideoPicture->pts*1e-6,
- pDvdVideoPicture->iFlags, buffer->omx_buffer->nFlags, pDvdVideoPicture->openMaxBuffer, pDvdVideoPicture->openMaxBuffer->omx_buffer, pDvdVideoPicture->openMaxBuffer->egl_image, pDvdVideoPicture->openMaxBuffer->texture_id);
- #endif
- + assert(!(buffer->omx_buffer->nFlags & (OMX_BUFFERFLAG_DECODEONLY | OMX_BUFFERFLAG_DROPPED)));
- }
- else
- {
- @@ -953,10 +978,11 @@ OMX_ERRORTYPE COpenMaxVideo::DecoderFillBufferDone(
- COpenMaxVideoBuffer *buffer = (COpenMaxVideoBuffer*)pBuffer->pAppPrivate;
-
- #if defined(OMX_DEBUG_VERBOSE)
- - CLog::Log(LOGDEBUG, "%s::%s - %p (%p,%p) buffer_size(%u), pts:%.3f",
- - CLASSNAME, __func__, buffer, pBuffer, buffer->omx_buffer, pBuffer->nFilledLen, (double)FromOMXTime(buffer->omx_buffer->nTimeStamp)*1e-6);
- + CLog::Log(LOGDEBUG, "%s::%s - %p (%p,%p) buffer_size(%u), pts:%.3f flags:%x",
- + CLASSNAME, __func__, buffer, pBuffer, buffer->omx_buffer, pBuffer->nFilledLen, (double)FromOMXTime(buffer->omx_buffer->nTimeStamp)*1e-6, buffer->omx_buffer->nFlags);
- #endif
-
- + assert(!(buffer->omx_buffer->nFlags & (OMX_BUFFERFLAG_DECODEONLY | OMX_BUFFERFLAG_DROPPED)));
- // queue output omx buffer to ready list.
- pthread_mutex_lock(&m_omx_output_mutex);
- buffer->m_aspect_ratio = m_aspect_ratio;
- @@ -1000,41 +1026,60 @@ OMX_ERRORTYPE COpenMaxVideo::FreeOMXInputBuffers(void)
- return(omx_err);
- }
-
- -bool COpenMaxVideo::CallbackAllocOMXEGLTextures(void *userdata)
- +bool COpenMaxVideo::CallbackAllocOMXEGLTextures(EGLDisplay egl_display, EGLContext egl_context, void *userdata)
- {
- COpenMaxVideo *omx = static_cast<COpenMaxVideo*>(userdata);
- - return omx->AllocOMXOutputEGLTextures() == OMX_ErrorNone;
- + return omx->AllocOMXOutputEGLTextures(egl_display, egl_context) == OMX_ErrorNone;
- }
-
- -bool COpenMaxVideo::CallbackFreeOMXEGLTextures(void *userdata)
- +bool COpenMaxVideo::CallbackFreeOMXEGLTextures(EGLDisplay egl_display, EGLContext egl_context, void *userdata)
- {
- COpenMaxVideo *omx = static_cast<COpenMaxVideo*>(userdata);
- - return omx->FreeOMXOutputEGLTextures() == OMX_ErrorNone;
- + return omx->FreeOMXOutputEGLTextures(egl_display, egl_context) == OMX_ErrorNone;
- }
-
- bool COpenMaxVideo::AllocOMXOutputBuffers(void)
- {
- - return g_OMXImage.SendMessage(CallbackAllocOMXEGLTextures, (void *)this);
- + pthread_mutex_lock(&m_omx_output_mutex);
- + for (size_t i = 0; i < m_egl_buffer_count; i++)
- + {
- + COpenMaxVideoBuffer *egl_buffer = new COpenMaxVideoBuffer(this);
- + egl_buffer->width = m_decoded_width;
- + egl_buffer->height = m_decoded_height;
- + egl_buffer->index = i;
- + m_omx_output_buffers.push_back(egl_buffer);
- + }
- + bool ret = g_OMXImage.SendMessage(CallbackAllocOMXEGLTextures, (void *)this);
- + pthread_mutex_unlock(&m_omx_output_mutex);
- + return ret;
- }
-
- bool COpenMaxVideo::FreeOMXOutputBuffers(void)
- {
- - return g_OMXImage.SendMessage(CallbackFreeOMXEGLTextures, (void *)this);
- + pthread_mutex_lock(&m_omx_output_mutex);
- + bool ret = g_OMXImage.SendMessage(CallbackFreeOMXEGLTextures, (void *)this);
- +
- + for (size_t i = 0; i < m_omx_output_buffers.size(); i++)
- + {
- + COpenMaxVideoBuffer *egl_buffer = m_omx_output_buffers[i];
- + delete egl_buffer;
- + }
- +
- + m_omx_output_buffers.clear();
- + pthread_mutex_unlock(&m_omx_output_mutex);
- + return ret;
- }
-
- -OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void)
- +OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(EGLDisplay egl_display, EGLContext egl_context)
- {
- OMX_ERRORTYPE omx_err = OMX_ErrorNone;
- EGLint attrib = EGL_NONE;
- - COpenMaxVideoBuffer *egl_buffer;
-
- glActiveTexture(GL_TEXTURE0);
-
- for (size_t i = 0; i < m_egl_buffer_count; i++)
- {
- - egl_buffer = new COpenMaxVideoBuffer(this);
- - egl_buffer->width = m_decoded_width;
- - egl_buffer->height = m_decoded_height;
- + COpenMaxVideoBuffer *egl_buffer = m_omx_output_buffers[i];
-
- glGenTextures(1, &egl_buffer->texture_id);
- glBindTexture(GL_TEXTURE_2D, egl_buffer->texture_id);
- @@ -1057,8 +1102,8 @@ OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void)
-
- // create EGLImage from texture
- egl_buffer->egl_image = eglCreateImageKHR(
- - m_egl_display,
- - m_egl_context,
- + egl_display,
- + egl_context,
- EGL_GL_TEXTURE_2D_KHR,
- (EGLClientBuffer)(egl_buffer->texture_id),
- &attrib);
- @@ -1067,7 +1112,6 @@ OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void)
- CLog::Log(LOGERROR, "%s::%s - ERROR creating EglImage", CLASSNAME, __func__);
- return(OMX_ErrorUndefined);
- }
- - egl_buffer->index = i;
-
- // tell decoder output port that it will be using EGLImage
- omx_err = m_omx_egl_render.UseEGLImage(
- @@ -1078,7 +1122,6 @@ OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void)
- CLASSNAME, __func__, omx_err);
- return(omx_err);
- }
- - m_omx_output_buffers.push_back(egl_buffer);
-
- CLog::Log(LOGDEBUG, "%s::%s - Texture %p Width %d Height %d",
- CLASSNAME, __func__, egl_buffer->egl_image, egl_buffer->width, egl_buffer->height);
- @@ -1086,26 +1129,22 @@ OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void)
- return omx_err;
- }
-
- -OMX_ERRORTYPE COpenMaxVideo::FreeOMXOutputEGLTextures(void)
- +OMX_ERRORTYPE COpenMaxVideo::FreeOMXOutputEGLTextures(EGLDisplay egl_display, EGLContext egl_context)
- {
- OMX_ERRORTYPE omx_err = OMX_ErrorNone;
- - COpenMaxVideoBuffer *egl_buffer;
-
- for (size_t i = 0; i < m_omx_output_buffers.size(); i++)
- {
- - egl_buffer = m_omx_output_buffers[i];
- + COpenMaxVideoBuffer *egl_buffer = m_omx_output_buffers[i];
- // tell decoder output port to stop using the EGLImage
- omx_err = m_omx_egl_render.FreeOutputBuffer(egl_buffer->omx_buffer);
- if (omx_err != OMX_ErrorNone)
- CLog::Log(LOGERROR, "%s::%s m_omx_egl_render.FreeOutputBuffer(%p) omx_err(0x%08x)", CLASSNAME, __func__, egl_buffer->omx_buffer, omx_err);
- // destroy egl_image
- - eglDestroyImageKHR(m_egl_display, egl_buffer->egl_image);
- + eglDestroyImageKHR(egl_display, egl_buffer->egl_image);
- // free texture
- glDeleteTextures(1, &egl_buffer->texture_id);
- - delete egl_buffer;
- }
- - m_omx_output_buffers.clear();
- -
- return omx_err;
- }
-
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
- index c8ad4d8..f234f6d 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
- @@ -99,17 +99,13 @@ class COpenMaxVideo
- OMX_ERRORTYPE FreeOMXInputBuffers(void);
- bool AllocOMXOutputBuffers(void);
- bool FreeOMXOutputBuffers(void);
- - static bool CallbackAllocOMXEGLTextures(void*);
- - OMX_ERRORTYPE AllocOMXOutputEGLTextures(void);
- - static bool CallbackFreeOMXEGLTextures(void*);
- - OMX_ERRORTYPE FreeOMXOutputEGLTextures(void);
- + static bool CallbackAllocOMXEGLTextures(EGLDisplay egl_display, EGLContext egl_context, void*);
- + OMX_ERRORTYPE AllocOMXOutputEGLTextures(EGLDisplay egl_display, EGLContext egl_context);
- + static bool CallbackFreeOMXEGLTextures(EGLDisplay egl_display, EGLContext egl_context, void*);
- + OMX_ERRORTYPE FreeOMXOutputEGLTextures(EGLDisplay egl_display, EGLContext egl_context);
- OMX_ERRORTYPE StopDecoder(void);
- OMX_ERRORTYPE ReturnOpenMaxBuffer(COpenMaxVideoBuffer *buffer);
-
- - // EGL Resources
- - EGLDisplay m_egl_display;
- - EGLContext m_egl_context;
- -
- // Video format
- bool m_drop_state;
- int m_decoded_width;
- @@ -148,6 +144,8 @@ class COpenMaxVideo
- EDEINTERLACEMODE m_deinterlace_request;
- bool m_deinterlace_second_field;
-
- + bool m_startframe;
- +
- bool PortSettingsChanged();
- bool SendDecoderConfig(uint8_t *extradata, int extrasize);
- bool NaluFormatStartCodes(enum AVCodecID codec, uint8_t *extradata, int extrasize);
- --
- 1.9.3
- From 182b137323347482bfca46dbb857813e4f984298 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Sat, 1 Mar 2014 14:24:08 +0000
- Subject: [PATCH 52/94] [omxplayer] Allow small audio packets to be
- concatenated to make better use of audio fifo
- Some audio codecs produce small packets which causes a high overhead when submitting to GPU, and doesn't make full use of GPU side buffering.
- TrueHD in particular can produce packets with 40 samples (so 1200 packets per second) which causes very high overhead.
- What this aims to do is to concatenate audio packets until they approach the ideal audio packet size,
- and then deal with the awkardness of concatenated planar formats.
- ---
- xbmc/cores/omxplayer/OMXAudio.cpp | 67 +++++++++++++++++++---------
- xbmc/cores/omxplayer/OMXAudio.h | 3 +-
- xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp | 72 +++++++++++++++++++++----------
- xbmc/cores/omxplayer/OMXAudioCodecOMX.h | 9 +++-
- xbmc/cores/omxplayer/OMXPlayerAudio.cpp | 9 ++--
- 5 files changed, 110 insertions(+), 50 deletions(-)
- diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp
- index dd80412..e67dc94 100644
- --- a/xbmc/cores/omxplayer/OMXAudio.cpp
- +++ b/xbmc/cores/omxplayer/OMXAudio.cpp
- @@ -43,6 +43,10 @@
-
- using namespace std;
-
- +// the size of the audio_render output port buffers
- +#define AUDIO_DECODE_OUTPUT_BUFFER (32*1024)
- +static const char rounded_up_channels_shift[] = {0,0,1,2,2,3,3,3,3};
- +
- static const uint16_t AC3Bitrates[] = {32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640};
- static const uint16_t AC3FSCod [] = {48000, 44100, 32000, 0};
-
- @@ -61,6 +65,7 @@ COMXAudio::COMXAudio() :
- m_Passthrough (false ),
- m_HWDecode (false ),
- m_BytesPerSec (0 ),
- + m_InputBytesPerSec(0 ),
- m_BufferLen (0 ),
- m_ChunkLen (0 ),
- m_InputChannels (0 ),
- @@ -490,11 +495,15 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
-
- m_SampleRate = m_format.m_sampleRate;
- m_BitsPerSample = CAEUtil::DataFormatToBits(m_format.m_dataFormat);
- - m_BufferLen = m_BytesPerSec = m_format.m_sampleRate * (16 >> 3) * m_InputChannels;
- - m_BufferLen *= AUDIO_BUFFER_SECONDS;
- + m_BytesPerSec = m_SampleRate * 2 << rounded_up_channels_shift[m_InputChannels];
- + m_BufferLen = m_BytesPerSec * AUDIO_BUFFER_SECONDS;
- + m_InputBytesPerSec = m_SampleRate * m_BitsPerSample * m_InputChannels >> 3;
- +
- + // should be big enough that common formats (e.g. 6 channel DTS) fit in a single packet.
- + // we don't mind less common formats being split (e.g. ape/wma output large frames)
- // the audio_decode output buffer size is 32K, and typically we convert from
- - // 6 channel 32bpp float to 8 channel 16bpp in, so a full 48K input buffer will fit the outbut buffer
- - m_ChunkLen = 48*1024;
- + // 6 channel 32bpp float to 8 channel 16bpp in, so a full 48K input buffer will fit the output buffer
- + m_ChunkLen = AUDIO_DECODE_OUTPUT_BUFFER * (m_InputChannels * m_BitsPerSample) >> (rounded_up_channels_shift[m_InputChannels] + 4);
-
- m_wave_header.Samples.wSamplesPerBlock = 0;
- m_wave_header.Format.nChannels = m_InputChannels;
- @@ -682,7 +691,7 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
- m_maxLevel = 0.0f;
-
- CLog::Log(LOGDEBUG, "COMXAudio::Initialize Input bps %d samplerate %d channels %d buffer size %d bytes per second %d",
- - (int)m_pcm_input.nBitPerSample, (int)m_pcm_input.nSamplingRate, (int)m_pcm_input.nChannels, m_BufferLen, m_BytesPerSec);
- + (int)m_pcm_input.nBitPerSample, (int)m_pcm_input.nSamplingRate, (int)m_pcm_input.nChannels, m_BufferLen, m_InputBytesPerSec);
- PrintPCM(&m_pcm_input, std::string("input"));
- CLog::Log(LOGDEBUG, "COMXAudio::Initialize device passthrough %d hwdecode %d",
- m_Passthrough, m_HWDecode);
- @@ -865,11 +874,11 @@ bool COMXAudio::ApplyVolume(void)
- //***********************************************************************************************
- unsigned int COMXAudio::AddPackets(const void* data, unsigned int len)
- {
- - return AddPackets(data, len, 0, 0);
- + return AddPackets(data, len, 0, 0, 0);
- }
-
- //***********************************************************************************************
- -unsigned int COMXAudio::AddPackets(const void* data, unsigned int len, double dts, double pts)
- +unsigned int COMXAudio::AddPackets(const void* data, unsigned int len, double dts, double pts, unsigned int frame_size)
- {
- CSingleLock lock (m_critSection);
-
- @@ -916,24 +925,40 @@ unsigned int COMXAudio::AddPackets(const void* data, unsigned int len, double dt
- omx_buffer->nOffset = 0;
- omx_buffer->nFlags = 0;
-
- + // we want audio_decode output buffer size to be no more than AUDIO_DECODE_OUTPUT_BUFFER.
- + // it will be 16-bit and rounded up to next power of 2 in channels
- + unsigned int max_buffer = AUDIO_DECODE_OUTPUT_BUFFER * (m_InputChannels * m_BitsPerSample) >> (rounded_up_channels_shift[m_InputChannels] + 4);
- +
- unsigned int remaining = demuxer_samples-demuxer_samples_sent;
- - unsigned int samples_space = omx_buffer->nAllocLen/pitch;
- + unsigned int samples_space = std::min(max_buffer, omx_buffer->nAllocLen)/pitch;
- unsigned int samples = std::min(remaining, samples_space);
-
- omx_buffer->nFilledLen = samples * pitch;
-
- - if (samples < demuxer_samples && m_BitsPerSample==32 && !(m_Passthrough || m_HWDecode))
- + unsigned int frames = frame_size ? len/frame_size:0;
- + if ((samples < demuxer_samples || frames > 1) && m_BitsPerSample==32 && !(m_Passthrough || m_HWDecode))
- {
- - uint8_t *dst = omx_buffer->pBuffer;
- - uint8_t *src = demuxer_content + demuxer_samples_sent * (m_BitsPerSample >> 3);
- - // we need to extract samples from planar audio, so the copying needs to be done per plane
- - for (int i=0; i<(int)m_InputChannels; i++)
- - {
- - memcpy(dst, src, omx_buffer->nFilledLen / m_InputChannels);
- - dst += omx_buffer->nFilledLen / m_InputChannels;
- - src += demuxer_samples * (m_BitsPerSample >> 3);
- - }
- - assert(dst <= omx_buffer->pBuffer + m_ChunkLen);
- + const unsigned int sample_pitch = m_BitsPerSample >> 3;
- + const unsigned int frame_samples = frame_size / pitch;
- + const unsigned int plane_size = frame_samples * sample_pitch;
- + const unsigned int out_plane_size = samples * sample_pitch;
- + //CLog::Log(LOGDEBUG, "%s::%s samples:%d/%d ps:%d ops:%d fs:%d pitch:%d filled:%d frames=%d", CLASSNAME, __func__, samples, demuxer_samples, plane_size, out_plane_size, frame_size, pitch, omx_buffer->nFilledLen, frames);
- + for (unsigned int sample = 0; sample < samples; )
- + {
- + unsigned int frame = (demuxer_samples_sent + sample) / frame_samples;
- + unsigned int sample_in_frame = (demuxer_samples_sent + sample) - frame * frame_samples;
- + int out_remaining = std::min(std::min(frame_samples - sample_in_frame, samples), samples-sample);
- + uint8_t *src = demuxer_content + frame*frame_size + sample_in_frame * sample_pitch;
- + uint8_t *dst = (uint8_t *)omx_buffer->pBuffer + sample * sample_pitch;
- + for (unsigned int channel = 0; channel < m_InputChannels; channel++)
- + {
- + //CLog::Log(LOGDEBUG, "%s::%s copy(%d,%d,%d) (s:%d f:%d sin:%d c:%d)", CLASSNAME, __func__, dst-(uint8_t *)omx_buffer->pBuffer, src-demuxer_content, out_remaining, sample, frame, sample_in_frame, channel);
- + memcpy(dst, src, out_remaining * sample_pitch);
- + src += plane_size;
- + dst += out_plane_size;
- + }
- + sample += out_remaining;
- + }
- }
- else
- {
- @@ -1114,7 +1139,9 @@ float COMXAudio::GetCacheTime()
-
- float COMXAudio::GetCacheTotal()
- {
- - return m_BytesPerSec ? (float)m_BufferLen / (float)m_BytesPerSec : 0.0f;
- + float audioplus_buffer = m_SampleRate ? 0.0f : 32.0f * 512.0f / m_SampleRate;
- + float input_buffer = (float)m_omx_decoder.GetInputBufferSize() / (float)m_InputBytesPerSec;
- + return AUDIO_BUFFER_SECONDS + input_buffer + audioplus_buffer;
- }
-
- //***********************************************************************************************
- diff --git a/xbmc/cores/omxplayer/OMXAudio.h b/xbmc/cores/omxplayer/OMXAudio.h
- index 804bd2a..b0264d8 100644
- --- a/xbmc/cores/omxplayer/OMXAudio.h
- +++ b/xbmc/cores/omxplayer/OMXAudio.h
- @@ -66,7 +66,7 @@ class COMXAudio
- ~COMXAudio();
-
- unsigned int AddPackets(const void* data, unsigned int len);
- - unsigned int AddPackets(const void* data, unsigned int len, double dts, double pts);
- + unsigned int AddPackets(const void* data, unsigned int len, double dts, double pts, unsigned int frame_size);
- unsigned int GetSpace();
- bool Deinitialize();
-
- @@ -114,6 +114,7 @@ class COMXAudio
- bool m_Passthrough;
- bool m_HWDecode;
- unsigned int m_BytesPerSec;
- + unsigned int m_InputBytesPerSec;
- unsigned int m_BufferLen;
- unsigned int m_ChunkLen;
- unsigned int m_InputChannels;
- diff --git a/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp b/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp
- index 5503a0e..557e847 100644
- --- a/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp
- +++ b/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp
- @@ -26,10 +26,15 @@
-
- #include "cores/AudioEngine/Utils/AEUtil.h"
-
- +// the size of the audio_render output port buffers
- +#define AUDIO_DECODE_OUTPUT_BUFFER (32*1024)
- +static const char rounded_up_channels_shift[] = {0,0,1,2,2,3,3,3,3};
- +
- COMXAudioCodecOMX::COMXAudioCodecOMX()
- {
- m_pBufferOutput = NULL;
- m_iBufferOutputAlloced = 0;
- + m_iBufferOutputUsed = 0;
-
- m_pCodecContext = NULL;
- m_pConvert = NULL;
- @@ -37,7 +42,10 @@ COMXAudioCodecOMX::COMXAudioCodecOMX()
-
- m_channels = 0;
- m_pFrame1 = NULL;
- + m_frameSize = 0;
- m_bGotFrame = false;
- + m_bNoConcatenate = false;
- +
- m_iSampleFormat = AV_SAMPLE_FMT_NONE;
- m_desiredSampleFormat = AV_SAMPLE_FMT_NONE;
- }
- @@ -47,6 +55,7 @@ COMXAudioCodecOMX::~COMXAudioCodecOMX()
- m_dllAvUtil.av_free(m_pBufferOutput);
- m_pBufferOutput = NULL;
- m_iBufferOutputAlloced = 0;
- + m_iBufferOutputUsed = 0;
- Dispose();
- }
-
- @@ -83,6 +92,10 @@ bool COMXAudioCodecOMX::Open(CDVDStreamInfo &hints)
- m_pCodecContext->bit_rate = hints.bitrate;
- m_pCodecContext->bits_per_coded_sample = hints.bitspersample;
-
- + // vorbis has variable sized planar output, so skip concatenation
- + if (hints.codec == AV_CODEC_ID_VORBIS)
- + m_bNoConcatenate = true;
- +
- if(m_pCodecContext->bits_per_coded_sample == 0)
- m_pCodecContext->bits_per_coded_sample = 16;
-
- @@ -132,7 +145,7 @@ void COMXAudioCodecOMX::Dispose()
- m_bGotFrame = false;
- }
-
- -int COMXAudioCodecOMX::Decode(BYTE* pData, int iSize)
- +int COMXAudioCodecOMX::Decode(BYTE* pData, int iSize, double dts, double pts)
- {
- int iBytesUsed, got_frame;
- if (!m_pCodecContext) return -1;
- @@ -167,10 +180,15 @@ int COMXAudioCodecOMX::Decode(BYTE* pData, int iSize)
- }
-
- m_bGotFrame = true;
- + if (!m_iBufferOutputUsed)
- + {
- + m_dts = dts;
- + m_pts = pts;
- + }
- return iBytesUsed;
- }
-
- -int COMXAudioCodecOMX::GetData(BYTE** dst)
- +int COMXAudioCodecOMX::GetData(BYTE** dst, double &dts, double &pts)
- {
- if (!m_bGotFrame)
- return 0;
- @@ -179,13 +197,11 @@ int COMXAudioCodecOMX::GetData(BYTE** dst)
- int inputSize = m_dllAvUtil.av_samples_get_buffer_size(&inLineSize, m_pCodecContext->channels, m_pFrame1->nb_samples, m_pCodecContext->sample_fmt, 0);
- /* output audio will be packed */
- int outputSize = m_dllAvUtil.av_samples_get_buffer_size(&outLineSize, m_pCodecContext->channels, m_pFrame1->nb_samples, m_desiredSampleFormat, 1);
- - bool cont = !m_pFrame1->data[1] || (m_pFrame1->data[1] == m_pFrame1->data[0] + inLineSize && inLineSize == outLineSize && inLineSize * m_pCodecContext->channels == inputSize);
-
- - if (m_iBufferOutputAlloced < outputSize)
- + if (m_iBufferOutputAlloced < m_iBufferOutputUsed + outputSize)
- {
- - m_dllAvUtil.av_free(m_pBufferOutput);
- - m_pBufferOutput = (BYTE*)m_dllAvUtil.av_malloc(outputSize + FF_INPUT_BUFFER_PADDING_SIZE);
- - m_iBufferOutputAlloced = outputSize;
- + m_pBufferOutput = (BYTE*)m_dllAvUtil.av_realloc(m_pBufferOutput, m_iBufferOutputUsed + outputSize + FF_INPUT_BUFFER_PADDING_SIZE);
- + m_iBufferOutputAlloced = m_iBufferOutputUsed + outputSize;
- }
- *dst = m_pBufferOutput;
-
- @@ -217,7 +233,7 @@ int COMXAudioCodecOMX::GetData(BYTE** dst)
-
- /* use unaligned flag to keep output packed */
- uint8_t *out_planes[m_pCodecContext->channels];
- - if(m_dllAvUtil.av_samples_fill_arrays(out_planes, NULL, m_pBufferOutput, m_pCodecContext->channels, m_pFrame1->nb_samples, m_desiredSampleFormat, 1) < 0 ||
- + if(m_dllAvUtil.av_samples_fill_arrays(out_planes, NULL, m_pBufferOutput + m_iBufferOutputUsed, m_pCodecContext->channels, m_pFrame1->nb_samples, m_desiredSampleFormat, 1) < 0 ||
- m_dllSwResample.swr_convert(m_pConvert, out_planes, m_pFrame1->nb_samples, (const uint8_t **)m_pFrame1->data, m_pFrame1->nb_samples) < 0)
- {
- CLog::Log(LOGERROR, "COMXAudioCodecOMX::Decode - Unable to convert format %d to %d", (int)m_pCodecContext->sample_fmt, m_desiredSampleFormat);
- @@ -226,35 +242,45 @@ int COMXAudioCodecOMX::GetData(BYTE** dst)
- }
- else
- {
- - /* if it is already contiguous, just return decoded frame */
- - if (cont)
- - {
- - *dst = m_pFrame1->data[0];
- - }
- - else
- + /* copy to a contiguous buffer */
- + uint8_t *out_planes[m_pCodecContext->channels];
- + if (m_dllAvUtil.av_samples_fill_arrays(out_planes, NULL, m_pBufferOutput + m_iBufferOutputUsed, m_pCodecContext->channels, m_pFrame1->nb_samples, m_desiredSampleFormat, 1) < 0 ||
- + m_dllAvUtil.av_samples_copy(out_planes, m_pFrame1->data, 0, 0, m_pFrame1->nb_samples, m_pCodecContext->channels, m_desiredSampleFormat) < 0 )
- {
- - /* copy to a contiguous buffer */
- - uint8_t *out_planes[m_pCodecContext->channels];
- - if (m_dllAvUtil.av_samples_fill_arrays(out_planes, NULL, m_pBufferOutput, m_pCodecContext->channels, m_pFrame1->nb_samples, m_desiredSampleFormat, 1) < 0 ||
- - m_dllAvUtil.av_samples_copy(out_planes, m_pFrame1->data, 0, 0, m_pFrame1->nb_samples, m_pCodecContext->channels, m_desiredSampleFormat) < 0 )
- - {
- - outputSize = 0;
- - }
- + outputSize = 0;
- }
- }
- + int desired_size = AUDIO_DECODE_OUTPUT_BUFFER * (m_pCodecContext->channels * GetBitsPerSample()) >> (rounded_up_channels_shift[m_pCodecContext->channels] + 4);
-
- if (m_bFirstFrame)
- {
- - CLog::Log(LOGDEBUG, "COMXAudioCodecOMX::GetData size=%d/%d line=%d/%d cont=%d buf=%p", inputSize, outputSize, inLineSize, outLineSize, cont, *dst);
- + CLog::Log(LOGDEBUG, "COMXAudioCodecOMX::GetData size=%d/%d line=%d/%d buf=%p, desired=%d", inputSize, outputSize, inLineSize, outLineSize, *dst, desired_size);
- m_bFirstFrame = false;
- }
- - return outputSize;
- + m_iBufferOutputUsed += outputSize;
- +
- + if (!m_bNoConcatenate && m_pCodecContext->sample_fmt == AV_SAMPLE_FMT_FLTP && m_frameSize && (int)m_frameSize != outputSize)
- + CLog::Log(LOGERROR, "COMXAudioCodecOMX::GetData Unexpected change of size (%d->%d)", m_frameSize, outputSize);
- + m_frameSize = outputSize;
- +
- + // if next buffer submitted won't fit then flush it out
- + if (m_iBufferOutputUsed + outputSize > desired_size || m_bNoConcatenate)
- + {
- + int ret = m_iBufferOutputUsed;
- + m_bGotFrame = false;
- + m_iBufferOutputUsed = 0;
- + dts = m_dts;
- + pts = m_pts;
- + return ret;
- + }
- + return 0;
- }
-
- void COMXAudioCodecOMX::Reset()
- {
- if (m_pCodecContext) m_dllAvCodec.avcodec_flush_buffers(m_pCodecContext);
- m_bGotFrame = false;
- + m_iBufferOutputUsed = 0;
- }
-
- int COMXAudioCodecOMX::GetChannels()
- diff --git a/xbmc/cores/omxplayer/OMXAudioCodecOMX.h b/xbmc/cores/omxplayer/OMXAudioCodecOMX.h
- index 343465c..66e5b4a 100644
- --- a/xbmc/cores/omxplayer/OMXAudioCodecOMX.h
- +++ b/xbmc/cores/omxplayer/OMXAudioCodecOMX.h
- @@ -36,8 +36,8 @@ class COMXAudioCodecOMX
- virtual ~COMXAudioCodecOMX();
- bool Open(CDVDStreamInfo &hints);
- void Dispose();
- - int Decode(BYTE* pData, int iSize);
- - int GetData(BYTE** dst);
- + int Decode(BYTE* pData, int iSize, double dts, double pts);
- + int GetData(BYTE** dst, double &dts, double &pts);
- void Reset();
- int GetChannels();
- uint64_t GetChannelMap();
- @@ -45,6 +45,7 @@ class COMXAudioCodecOMX
- int GetBitsPerSample();
- static const char* GetName() { return "FFmpeg"; }
- int GetBitRate();
- + unsigned int GetFrameSize() { return m_frameSize; }
-
- protected:
- AVCodecContext* m_pCodecContext;
- @@ -55,6 +56,7 @@ class COMXAudioCodecOMX
- AVFrame* m_pFrame1;
-
- BYTE *m_pBufferOutput;
- + int m_iBufferOutputUsed;
- int m_iBufferOutputAlloced;
-
- bool m_bOpenedCodec;
- @@ -63,6 +65,9 @@ class COMXAudioCodecOMX
-
- bool m_bFirstFrame;
- bool m_bGotFrame;
- + bool m_bNoConcatenate;
- + unsigned int m_frameSize;
- + double m_dts, m_pts;
- DllAvCodec m_dllAvCodec;
- DllAvUtil m_dllAvUtil;
- DllSwResample m_dllSwResample;
- diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
- index 8219015..a4c11777 100644
- --- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
- +++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
- @@ -227,9 +227,10 @@ bool OMXPlayerAudio::Decode(DemuxPacket *pkt, bool bDropPacket)
-
- if(!OMX_IS_RAW(m_format.m_dataFormat) && !bDropPacket)
- {
- + double dts = pkt->dts, pts=pkt->pts;
- while(!m_bStop && data_len > 0)
- {
- - int len = m_pAudioCodec->Decode((BYTE *)data_dec, data_len);
- + int len = m_pAudioCodec->Decode((BYTE *)data_dec, data_len, dts, pts);
- if( (len < 0) || (len > data_len) )
- {
- m_pAudioCodec->Reset();
- @@ -240,7 +241,7 @@ bool OMXPlayerAudio::Decode(DemuxPacket *pkt, bool bDropPacket)
- data_len -= len;
-
- uint8_t *decoded;
- - int decoded_size = m_pAudioCodec->GetData(&decoded);
- + int decoded_size = m_pAudioCodec->GetData(&decoded, dts, pts);
-
- if(decoded_size <=0)
- continue;
- @@ -274,7 +275,7 @@ bool OMXPlayerAudio::Decode(DemuxPacket *pkt, bool bDropPacket)
- if(m_silence)
- memset(decoded, 0x0, decoded_size);
-
- - ret = m_omxAudio.AddPackets(decoded, decoded_size, m_audioClock, m_audioClock);
- + ret = m_omxAudio.AddPackets(decoded, decoded_size, dts, pts, m_pAudioCodec->GetFrameSize());
-
- if(ret != decoded_size)
- {
- @@ -312,7 +313,7 @@ bool OMXPlayerAudio::Decode(DemuxPacket *pkt, bool bDropPacket)
- if(m_silence)
- memset(pkt->pData, 0x0, pkt->iSize);
-
- - m_omxAudio.AddPackets(pkt->pData, pkt->iSize, m_audioClock, m_audioClock);
- + m_omxAudio.AddPackets(pkt->pData, pkt->iSize, m_audioClock, m_audioClock, 0);
- }
-
- m_audioStats.AddSampleBytes(pkt->iSize);
- --
- 1.9.3
- From 10a9d6134a624bf59096831851ee12191f658da1 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Wed, 5 Mar 2014 22:10:01 +0000
- Subject: [PATCH 53/94] [omxplayer] Use media for determing audio delay and
- cache time
- I've also added caching to the call to OMXMediaTime as the GPU round trip is expensive when called too frequently
- ---
- xbmc/cores/omxplayer/OMXAudio.cpp | 33 ++++++++++++++-------
- xbmc/linux/OMXClock.cpp | 62 +++++++++++++++++++++++++++------------
- xbmc/linux/OMXClock.h | 2 ++
- 3 files changed, 68 insertions(+), 29 deletions(-)
- diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp
- index e67dc94..3e64de0 100644
- --- a/xbmc/cores/omxplayer/OMXAudio.cpp
- +++ b/xbmc/cores/omxplayer/OMXAudio.cpp
- @@ -1118,29 +1118,40 @@ void COMXAudio::UpdateAttenuation()
- //***********************************************************************************************
- unsigned int COMXAudio::GetSpace()
- {
- - int free = m_omx_decoder.GetInputBufferSpace();
- - return free;
- + return m_omx_decoder.GetInputBufferSpace();
- }
-
- float COMXAudio::GetDelay()
- {
- - unsigned int free = m_omx_decoder.GetInputBufferSize() - m_omx_decoder.GetInputBufferSpace();
- - return m_BytesPerSec ? (float)free / (float)m_BytesPerSec : 0.0f;
- + CSingleLock lock (m_critSection);
- + double stamp = DVD_NOPTS_VALUE;
- + double ret = 0.0;
- + if (m_last_pts != DVD_NOPTS_VALUE && m_av_clock)
- + stamp = m_av_clock->OMXMediaTime();
- + // if possible the delay is current media time - time of last submitted packet
- + if (stamp != DVD_NOPTS_VALUE)
- + {
- + ret = (m_last_pts - stamp) * (1.0 / DVD_TIME_BASE);
- + //CLog::Log(LOGINFO, "%s::%s - %.2f %.0f %.0f", CLASSNAME, __func__, ret, stamp, m_last_pts);
- + }
- + else // just measure the input fifo
- + {
- + unsigned int used = m_omx_decoder.GetInputBufferSize() - m_omx_decoder.GetInputBufferSpace();
- + float ret = m_InputBytesPerSec ? (float)used / (float)m_InputBytesPerSec : 0.0f;
- + //CLog::Log(LOGINFO, "%s::%s - %.2f %d, %d, %d", CLASSNAME, __func__, ret, used, m_omx_decoder.GetInputBufferSize(), m_omx_decoder.GetInputBufferSpace());
- + }
- + return ret;
- }
-
- float COMXAudio::GetCacheTime()
- {
- - float fBufferLenFull = (float)m_BufferLen - (float)GetSpace();
- - if(fBufferLenFull < 0)
- - fBufferLenFull = 0;
- - float ret = m_BytesPerSec ? fBufferLenFull / (float)m_BytesPerSec : 0.0f;
- - return ret;
- + return GetDelay();
- }
-
- float COMXAudio::GetCacheTotal()
- {
- - float audioplus_buffer = m_SampleRate ? 0.0f : 32.0f * 512.0f / m_SampleRate;
- - float input_buffer = (float)m_omx_decoder.GetInputBufferSize() / (float)m_InputBytesPerSec;
- + float audioplus_buffer = m_SampleRate ? 32.0f * 512.0f / m_SampleRate : 0.0f;
- + float input_buffer = m_InputBytesPerSec ? (float)m_omx_decoder.GetInputBufferSize() / (float)m_InputBytesPerSec : 0;
- return AUDIO_BUFFER_SECONDS + input_buffer + audioplus_buffer;
- }
-
- diff --git a/xbmc/linux/OMXClock.cpp b/xbmc/linux/OMXClock.cpp
- index 241657b..bee7bac 100644
- --- a/xbmc/linux/OMXClock.cpp
- +++ b/xbmc/linux/OMXClock.cpp
- @@ -45,6 +45,8 @@ OMXClock::OMXClock()
- m_eState = OMX_TIME_ClockStateStopped;
- m_eClock = OMX_TIME_RefClockNone;
- m_clock = NULL;
- + m_last_media_time = 0.0f;
- + m_last_media_time_read = 0.0f;
-
- pthread_mutex_init(&m_lock, NULL);
- }
- @@ -113,6 +115,7 @@ bool OMXClock::OMXSetReferenceClock(bool has_audio, bool lock /* = true */)
- }
- m_eClock = refClock.eClock;
- }
- + m_last_media_time = 0.0f;
- if(lock)
- UnLock();
-
- @@ -142,6 +145,7 @@ void OMXClock::OMXDeinitialize()
- m_omx_clock.Deinitialize();
-
- m_omx_speed = DVD_PLAYSPEED_NORMAL;
- + m_last_media_time = 0.0f;
- }
-
- bool OMXClock::OMXStateExecute(bool lock /* = true */)
- @@ -169,6 +173,7 @@ bool OMXClock::OMXStateExecute(bool lock /* = true */)
- }
- }
-
- + m_last_media_time = 0.0f;
- if(lock)
- UnLock();
-
- @@ -186,6 +191,7 @@ void OMXClock::OMXStateIdle(bool lock /* = true */)
- if(m_omx_clock.GetState() != OMX_StateIdle)
- m_omx_clock.SetStateForComponent(OMX_StateIdle);
-
- + m_last_media_time = 0.0f;
- if(lock)
- UnLock();
- }
- @@ -222,6 +228,7 @@ bool OMXClock::OMXStop(bool lock /* = true */)
- }
- m_eState = clock.eState;
-
- + m_last_media_time = 0.0f;
- if(lock)
- UnLock();
-
- @@ -252,6 +259,7 @@ bool OMXClock::OMXStep(int steps /* = 1 */, bool lock /* = true */)
- return false;
- }
-
- + m_last_media_time = 0.0f;
- if(lock)
- UnLock();
-
- @@ -302,6 +310,7 @@ bool OMXClock::OMXReset(bool has_video, bool has_audio, bool lock /* = true */)
- }
- }
-
- + m_last_media_time = 0.0f;
- if(lock)
- UnLock();
-
- @@ -310,33 +319,45 @@ bool OMXClock::OMXReset(bool has_video, bool has_audio, bool lock /* = true */)
-
- double OMXClock::OMXMediaTime(bool lock /* = true */)
- {
- + double pts = 0.0;
- if(m_omx_clock.GetComponent() == NULL)
- return 0;
-
- - if(lock)
- - Lock();
- + double now = GetAbsoluteClock();
- + if (now - m_last_media_time_read > DVD_MSEC_TO_TIME(100) || m_last_media_time == 0.0)
- + {
- + if(lock)
- + Lock();
-
- - OMX_ERRORTYPE omx_err = OMX_ErrorNone;
- - double pts = 0;
- + OMX_ERRORTYPE omx_err = OMX_ErrorNone;
-
- - OMX_TIME_CONFIG_TIMESTAMPTYPE timeStamp;
- - OMX_INIT_STRUCTURE(timeStamp);
- - timeStamp.nPortIndex = m_omx_clock.GetInputPort();
- + OMX_TIME_CONFIG_TIMESTAMPTYPE timeStamp;
- + OMX_INIT_STRUCTURE(timeStamp);
- + timeStamp.nPortIndex = m_omx_clock.GetInputPort();
- +
- + omx_err = m_omx_clock.GetConfig(OMX_IndexConfigTimeCurrentMediaTime, &timeStamp);
- + if(omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "OMXClock::MediaTime error getting OMX_IndexConfigTimeCurrentMediaTime\n");
- + if(lock)
- + UnLock();
- + return 0;
- + }
- +
- + pts = FromOMXTime(timeStamp.nTimestamp);
- + //CLog::Log(LOGINFO, "OMXClock::MediaTime %.2f (%.2f, %.2f)", pts, m_last_media_time, now - m_last_media_time_read);
- + m_last_media_time = pts;
- + m_last_media_time_read = now;
-
- - omx_err = m_omx_clock.GetConfig(OMX_IndexConfigTimeCurrentMediaTime, &timeStamp);
- - if(omx_err != OMX_ErrorNone)
- - {
- - CLog::Log(LOGERROR, "OMXClock::MediaTime error getting OMX_IndexConfigTimeCurrentMediaTime\n");
- if(lock)
- UnLock();
- - return 0;
- }
- -
- - pts = FromOMXTime(timeStamp.nTimestamp);
- -
- - if(lock)
- - UnLock();
- -
- + else
- + {
- + double speed = m_pause ? 0.0 : (double)m_omx_speed / DVD_PLAYSPEED_NORMAL;
- + pts = m_last_media_time + (now - m_last_media_time_read) * speed;
- + //CLog::Log(LOGINFO, "OMXClock::MediaTime cached %.2f (%.2f, %.2f)", pts, m_last_media_time, now - m_last_media_time_read);
- + }
- return pts;
- }
-
- @@ -409,6 +430,7 @@ bool OMXClock::OMXMediaTime(double pts, bool lock /* = true*/)
- CLog::Log(LOGDEBUG, "OMXClock::OMXMediaTime set config %s = %.2f", index == OMX_IndexConfigTimeCurrentAudioReference ?
- "OMX_IndexConfigTimeCurrentAudioReference":"OMX_IndexConfigTimeCurrentVideoReference", pts);
-
- + m_last_media_time = 0.0f;
- if(lock)
- UnLock();
-
- @@ -428,6 +450,7 @@ bool OMXClock::OMXPause(bool lock /* = true */)
- if (OMXSetSpeed(0, false, true))
- m_pause = true;
-
- + m_last_media_time = 0.0f;
- if(lock)
- UnLock();
- }
- @@ -447,6 +470,7 @@ bool OMXClock::OMXResume(bool lock /* = true */)
- if (OMXSetSpeed(m_omx_speed, false, true))
- m_pause = false;
-
- + m_last_media_time = 0.0f;
- if(lock)
- UnLock();
- }
- @@ -485,6 +509,7 @@ bool OMXClock::OMXSetSpeed(int speed, bool lock /* = true */, bool pause_resume
- if (!pause_resume)
- m_omx_speed = speed;
-
- + m_last_media_time = 0.0f;
- if(lock)
- UnLock();
-
- @@ -521,6 +546,7 @@ bool OMXClock::HDMIClockSync(bool lock /* = true */)
- return false;
- }
-
- + m_last_media_time = 0.0f;
- if(lock)
- UnLock();
-
- diff --git a/xbmc/linux/OMXClock.h b/xbmc/linux/OMXClock.h
- index d7d06fe..f83074a 100644
- --- a/xbmc/linux/OMXClock.h
- +++ b/xbmc/linux/OMXClock.h
- @@ -58,6 +58,8 @@ class OMXClock
- CDVDClock *m_clock;
- private:
- COMXCoreComponent m_omx_clock;
- + double m_last_media_time;
- + double m_last_media_time_read;
- public:
- OMXClock();
- ~OMXClock();
- --
- 1.9.3
- From 29c5c42b2f5be546c242bc8ef02dc06a8dd0fd17 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Mon, 3 Mar 2014 22:24:19 +0000
- Subject: [PATCH 54/94] [omx] Skip the resize when not needed when decoding
- jpegs
- The decode to texture path almost always uses cached jpegs that are the correct size, so the resize is rarely needed.
- The re-enc path usually needs resizing, but may not where the source is small.
- Skipping the resize stage saves a little time and memory on GPU and also saves some setup time.
- ---
- xbmc/cores/omxplayer/OMXImage.cpp | 262 ++++++++++++++++++++++----------------
- 1 file changed, 152 insertions(+), 110 deletions(-)
- diff --git a/xbmc/cores/omxplayer/OMXImage.cpp b/xbmc/cores/omxplayer/OMXImage.cpp
- index 4456fdb..262a004 100644
- --- a/xbmc/cores/omxplayer/OMXImage.cpp
- +++ b/xbmc/cores/omxplayer/OMXImage.cpp
- @@ -1477,9 +1477,22 @@ bool COMXImageReEnc::HandlePortSettingChange(unsigned int resize_width, unsigned
- return false;
- }
-
- + if (resize_width != port_def.format.image.nFrameWidth || resize_height != port_def.format.image.nFrameHeight || (orientation & 4))
- + {
- + if(!m_omx_resize.Initialize("OMX.broadcom.resize", OMX_IndexParamImageInit))
- + {
- + CLog::Log(LOGERROR, "%s::%s error m_omx_resize.Initialize\n", CLASSNAME, __func__);
- + return false;
- + }
- + }
- +
- // TODO: jpeg decoder can decimate by factors of 2
- port_def.format.image.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
- - port_def.format.image.nSliceHeight = 16;//(port_def.format.image.nFrameHeight+15) & ~15;
- + if (m_omx_resize.IsInitialized())
- + port_def.format.image.nSliceHeight = 16;
- + else
- + port_def.format.image.nSliceHeight = (resize_height+15) & ~15;
- +
- port_def.format.image.nStride = 0;
-
- m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
- @@ -1489,38 +1502,35 @@ bool COMXImageReEnc::HandlePortSettingChange(unsigned int resize_width, unsigned
- return false;
- }
-
- - if(!m_omx_resize.Initialize("OMX.broadcom.resize", OMX_IndexParamImageInit))
- + if (m_omx_resize.IsInitialized())
- {
- - CLog::Log(LOGERROR, "%s::%s error m_omx_resize.Initialize\n", CLASSNAME, __func__);
- - return false;
- - }
- -
- - port_def.nPortIndex = m_omx_resize.GetInputPort();
- + port_def.nPortIndex = m_omx_resize.GetInputPort();
-
- - m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
- - if(omx_err != OMX_ErrorNone)
- - {
- - CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
- - return false;
- - }
- + m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
- + if(omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
- + return false;
- + }
-
- - port_def.nPortIndex = m_omx_resize.GetOutputPort();
- - m_omx_resize.GetParameter(OMX_IndexParamPortDefinition, &port_def);
- - if(omx_err != OMX_ErrorNone)
- - {
- - CLog::Log(LOGERROR, "%s::%s m_omx_resize.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
- - return false;
- - }
- - port_def.format.image.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
- - port_def.format.image.nFrameWidth = resize_width;
- - port_def.format.image.nFrameHeight = resize_height;
- - port_def.format.image.nSliceHeight = (resize_height+15) & ~15;
- - port_def.format.image.nStride = 0;
- - m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
- - if(omx_err != OMX_ErrorNone)
- - {
- - CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
- - return false;
- + port_def.nPortIndex = m_omx_resize.GetOutputPort();
- + m_omx_resize.GetParameter(OMX_IndexParamPortDefinition, &port_def);
- + if(omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s m_omx_resize.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- + port_def.format.image.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
- + port_def.format.image.nFrameWidth = resize_width;
- + port_def.format.image.nFrameHeight = resize_height;
- + port_def.format.image.nSliceHeight = (resize_height+15) & ~15;
- + port_def.format.image.nStride = 0;
- + m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
- + if(omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- }
-
- if(!m_omx_encoder.Initialize("OMX.broadcom.image_encode", OMX_IndexParamImageInit))
- @@ -1621,31 +1631,44 @@ bool COMXImageReEnc::HandlePortSettingChange(unsigned int resize_width, unsigned
- return false;
- }
-
- - m_omx_tunnel_decode.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_resize, m_omx_resize.GetInputPort());
- -
- - omx_err = m_omx_tunnel_decode.Establish();
- - if(omx_err != OMX_ErrorNone)
- + if (m_omx_resize.IsInitialized())
- {
- - CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_decode.Establish\n", CLASSNAME, __func__);
- - return false;
- - }
- + m_omx_tunnel_decode.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_resize, m_omx_resize.GetInputPort());
-
- - m_omx_tunnel_resize.Initialize(&m_omx_resize, m_omx_resize.GetOutputPort(), &m_omx_encoder, m_omx_encoder.GetInputPort());
- + omx_err = m_omx_tunnel_decode.Establish();
- + if(omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_decode.Establish\n", CLASSNAME, __func__);
- + return false;
- + }
-
- - omx_err = m_omx_tunnel_resize.Establish();
- - if(omx_err != OMX_ErrorNone)
- - {
- - CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_resize.Establish\n", CLASSNAME, __func__);
- - return false;
- - }
- + m_omx_tunnel_resize.Initialize(&m_omx_resize, m_omx_resize.GetOutputPort(), &m_omx_encoder, m_omx_encoder.GetInputPort());
-
- - omx_err = m_omx_resize.SetStateForComponent(OMX_StateExecuting);
- - if(omx_err != OMX_ErrorNone)
- - {
- - CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
- - return false;
- + omx_err = m_omx_tunnel_resize.Establish();
- + if(omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_resize.Establish\n", CLASSNAME, __func__);
- + return false;
- + }
- +
- + omx_err = m_omx_resize.SetStateForComponent(OMX_StateExecuting);
- + if(omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- }
- + else
- + {
- + m_omx_tunnel_decode.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_encoder, m_omx_encoder.GetInputPort());
-
- + omx_err = m_omx_tunnel_decode.Establish();
- + if(omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_decode.Establish\n", CLASSNAME, __func__);
- + return false;
- + }
- + }
- omx_err = m_omx_encoder.SetStateForComponent(OMX_StateExecuting);
- if (omx_err != OMX_ErrorNone)
- {
- @@ -1662,24 +1685,27 @@ bool COMXImageReEnc::HandlePortSettingChange(unsigned int resize_width, unsigned
- // a little surprising, make a note
- CLog::Log(LOGDEBUG, "%s::%s m_omx_resize second port changed event\n", CLASSNAME, __func__);
- m_omx_decoder.DisablePort(m_omx_decoder.GetOutputPort(), true);
- - m_omx_resize.DisablePort(m_omx_resize.GetInputPort(), true);
- + if (m_omx_resize.IsInitialized())
- + {
- + m_omx_resize.DisablePort(m_omx_resize.GetInputPort(), true);
-
- - OMX_PARAM_PORTDEFINITIONTYPE port_def;
- - OMX_INIT_STRUCTURE(port_def);
- + OMX_PARAM_PORTDEFINITIONTYPE port_def;
- + OMX_INIT_STRUCTURE(port_def);
-
- - port_def.nPortIndex = m_omx_decoder.GetOutputPort();
- - m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
- - port_def.nPortIndex = m_omx_resize.GetInputPort();
- - m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
- + port_def.nPortIndex = m_omx_decoder.GetOutputPort();
- + m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
- + port_def.nPortIndex = m_omx_resize.GetInputPort();
- + m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
-
- - omx_err = m_omx_resize.WaitForEvent(OMX_EventPortSettingsChanged);
- - if(omx_err != OMX_ErrorNone)
- - {
- - CLog::Log(LOGERROR, "%s::%s m_omx_resize.WaitForEvent=%x\n", CLASSNAME, __func__, omx_err);
- - return false;
- + omx_err = m_omx_resize.WaitForEvent(OMX_EventPortSettingsChanged);
- + if(omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s m_omx_resize.WaitForEvent=%x\n", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- + m_omx_resize.EnablePort(m_omx_resize.GetInputPort(), true);
- }
- m_omx_decoder.EnablePort(m_omx_decoder.GetOutputPort(), true);
- - m_omx_resize.EnablePort(m_omx_resize.GetInputPort(), true);
- }
- return true;
- }
- @@ -1918,42 +1944,45 @@ bool COMXTexture::HandlePortSettingChange(unsigned int resize_width, unsigned in
- CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
- return false;
- }
- -
- - if (!m_omx_resize.Initialize("OMX.broadcom.resize", OMX_IndexParamImageInit))
- + if (resize_width != port_def.format.image.nFrameWidth || resize_height != port_def.format.image.nFrameHeight)
- {
- - CLog::Log(LOGERROR, "%s::%s error m_omx_resize.Initialize", CLASSNAME, __func__);
- - return false;
- + if (!m_omx_resize.Initialize("OMX.broadcom.resize", OMX_IndexParamImageInit))
- + {
- + CLog::Log(LOGERROR, "%s::%s error m_omx_resize.Initialize", CLASSNAME, __func__);
- + return false;
- + }
- }
- -
- - port_def.nPortIndex = m_omx_resize.GetInputPort();
- -
- - omx_err = m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
- - if (omx_err != OMX_ErrorNone)
- + if (m_omx_resize.IsInitialized())
- {
- - CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
- - return false;
- - }
- + port_def.nPortIndex = m_omx_resize.GetInputPort();
-
- - port_def.nPortIndex = m_omx_resize.GetOutputPort();
- - omx_err = m_omx_resize.GetParameter(OMX_IndexParamPortDefinition, &port_def);
- - if (omx_err != OMX_ErrorNone)
- - {
- - CLog::Log(LOGERROR, "%s::%s m_omx_resize.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
- - return false;
- - }
- + omx_err = m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
- + return false;
- + }
-
- - port_def.format.image.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
- - port_def.format.image.nFrameWidth = resize_width;
- - port_def.format.image.nFrameHeight = resize_height;
- - port_def.format.image.nSliceHeight = 16;
- - port_def.format.image.nStride = 0;
- - omx_err = m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
- - if (omx_err != OMX_ErrorNone)
- - {
- - CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
- - return false;
- - }
- + port_def.nPortIndex = m_omx_resize.GetOutputPort();
- + omx_err = m_omx_resize.GetParameter(OMX_IndexParamPortDefinition, &port_def);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s m_omx_resize.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
- + return false;
- + }
-
- + port_def.format.image.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
- + port_def.format.image.nFrameWidth = resize_width;
- + port_def.format.image.nFrameHeight = resize_height;
- + port_def.format.image.nSliceHeight = 16;
- + port_def.format.image.nStride = 0;
- + omx_err = m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- + }
- if (!m_omx_egl_render.Initialize("OMX.broadcom.egl_render", OMX_IndexParamVideoInit))
- {
- CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.Initialize", CLASSNAME, __func__);
- @@ -1983,30 +2012,43 @@ bool COMXTexture::HandlePortSettingChange(unsigned int resize_width, unsigned in
- CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.UseEGLImage (%x)", CLASSNAME, __func__, omx_err);
- return false;
- }
- + if (m_omx_resize.IsInitialized())
- + {
- + m_omx_tunnel_decode.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_resize, m_omx_resize.GetInputPort());
-
- - m_omx_tunnel_decode.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_resize, m_omx_resize.GetInputPort());
- + omx_err = m_omx_tunnel_decode.Establish();
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_decode.Establish (%x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
-
- - omx_err = m_omx_tunnel_decode.Establish();
- - if (omx_err != OMX_ErrorNone)
- - {
- - CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_decode.Establish (%x)", CLASSNAME, __func__, omx_err);
- - return false;
- - }
- + m_omx_tunnel_egl.Initialize(&m_omx_resize, m_omx_resize.GetOutputPort(), &m_omx_egl_render, m_omx_egl_render.GetInputPort());
-
- - m_omx_tunnel_egl.Initialize(&m_omx_resize, m_omx_resize.GetOutputPort(), &m_omx_egl_render, m_omx_egl_render.GetInputPort());
- + omx_err = m_omx_tunnel_egl.Establish();
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_egl.Establish (%x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
-
- - omx_err = m_omx_tunnel_egl.Establish();
- - if (omx_err != OMX_ErrorNone)
- - {
- - CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_egl.Establish (%x)", CLASSNAME, __func__, omx_err);
- - return false;
- + omx_err = m_omx_resize.SetStateForComponent(OMX_StateExecuting);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.GetParameter (%x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- }
- -
- - omx_err = m_omx_resize.SetStateForComponent(OMX_StateExecuting);
- - if (omx_err != OMX_ErrorNone)
- + else
- {
- - CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.GetParameter (%x)", CLASSNAME, __func__, omx_err);
- - return false;
- + m_omx_tunnel_decode.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_egl_render, m_omx_egl_render.GetInputPort());
- +
- + omx_err = m_omx_tunnel_decode.Establish();
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_decode.Establish (%x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- }
-
- omx_err = m_omx_egl_render.SetStateForComponent(OMX_StateExecuting);
- --
- 1.9.3
- From 1156d9abfac43de458d4ba66e5494c1d027e0f17 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Sat, 8 Mar 2014 15:36:06 +0000
- Subject: [PATCH 55/94] [hifiberry] Hack: force it to be recognised as IEC958
- capable to enable passthrough options
- ---
- xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp | 4 ++++
- 1 file changed, 4 insertions(+)
- diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
- index b48a4fc..d9897e5 100644
- --- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
- +++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
- @@ -932,6 +932,10 @@ void CAESinkALSA::EnumerateDevice(AEDeviceInfoList &list, const std::string &dev
- if (snd_card_get_name(cardNr, &cardName) == 0)
- info.m_displayName = cardName;
-
- + // hack: hifiberry digi doesn't correctly report as iec958 device. Needs fixing in kernel driver
- + if (info.m_displayName == "snd_rpi_hifiberry_digi")
- + info.m_deviceType = AE_DEVTYPE_IEC958;
- +
- if (info.m_deviceType == AE_DEVTYPE_HDMI && info.m_displayName.size() > 5 &&
- info.m_displayName.substr(info.m_displayName.size()-5) == " HDMI")
- {
- --
- 1.9.3
- From 03aa9ebf0993f06d24a34f8dd7d86a183ebd2dcd Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Tue, 11 Mar 2014 18:50:23 +0000
- Subject: [PATCH 56/94] [dvdplayer] Use inexact seeking like omxplayer
- ---
- xbmc/cores/dvdplayer/DVDPlayer.cpp | 11 +++++++++++
- 1 file changed, 11 insertions(+)
- diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
- index d607f55..1d4ba52 100644
- --- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
- +++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
- @@ -1935,7 +1935,11 @@ void CDVDPlayer::CheckAutoSceneSkip()
- /*
- * Seeking is NOT flushed so any content up to the demux point is retained when playing forwards.
- */
- +#ifdef TARGET_RASPBERRY_PI
- + m_messenger.Put(new CDVDMsgPlayerSeek((int)seek, true, true, true, false, true));
- +#else
- m_messenger.Put(new CDVDMsgPlayerSeek((int)seek, true, false, true, false, true));
- +#endif
- /*
- * Seek doesn't always work reliably. Last physical seek time is recorded to prevent looping
- * if there was an error with seeking and it landed somewhere unexpected, perhaps back in the
- @@ -1953,7 +1957,11 @@ void CDVDPlayer::CheckAutoSceneSkip()
- /*
- * Seeking is NOT flushed so any content up to the demux point is retained when playing forwards.
- */
- +#ifdef TARGET_RASPBERRY_PI
- + m_messenger.Put(new CDVDMsgPlayerSeek(cut.end + 1, true, false, true, false, true));
- +#else
- m_messenger.Put(new CDVDMsgPlayerSeek(cut.end + 1, true, false, true, false, true));
- +#endif
- /*
- * Each commercial break is only skipped once so poorly detected commercial breaks can be
- * manually re-entered. Start and end are recorded to prevent looping and to allow seeking back
- @@ -3293,9 +3301,12 @@ bool CDVDPlayer::CloseTeletextStream(bool bWaitForBuffers)
- void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate)
- {
- double startpts;
- +#ifndef TARGET_RASPBERRY_PI
- + /* for now, ignore accurate flag as it discards keyframes and causes corrupt frames */
- if(accurate)
- startpts = pts;
- else
- +#endif
- startpts = DVD_NOPTS_VALUE;
-
- /* call with demuxer pts */
- --
- 1.9.3
- From d4487b87819003a44f59a607074a41108f644915 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Thu, 13 Mar 2014 16:08:46 +0000
- Subject: [PATCH 57/94] [omxplayer] Make use of TrueHD fastpath when downmixing
- The TrueHD codec actually works in 3 stages. It decodes the downmixed stereo. It then decodes the differences required to produce 5.1.
- It then decodes the differences required to produce 7.1.
- Many users end up downmixing this 7.1 stream back to 2.0.
- Much better to tell the codec we only need the 2.0 stream. It saves about 50% of the CPU required
- ---
- xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
- diff --git a/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp b/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp
- index 557e847..7f6ef6e 100644
- --- a/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp
- +++ b/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp
- @@ -25,6 +25,8 @@
- #include "utils/log.h"
-
- #include "cores/AudioEngine/Utils/AEUtil.h"
- +#include "settings/Settings.h"
- +#include "PCMRemap.h"
-
- // the size of the audio_render output port buffers
- #define AUDIO_DECODE_OUTPUT_BUFFER (32*1024)
- @@ -91,6 +93,16 @@ bool COMXAudioCodecOMX::Open(CDVDStreamInfo &hints)
- m_pCodecContext->block_align = hints.blockalign;
- m_pCodecContext->bit_rate = hints.bitrate;
- m_pCodecContext->bits_per_coded_sample = hints.bitspersample;
- + enum PCMLayout layout = (enum PCMLayout)std::max(0, CSettings::Get().GetInt("audiooutput.channels")-1);
- + if (hints.codec == AV_CODEC_ID_TRUEHD)
- + {
- + if (layout == PCM_LAYOUT_2_0)
- + m_pCodecContext->request_channel_layout = AV_CH_LAYOUT_STEREO;
- + else if (layout <= PCM_LAYOUT_5_1)
- + m_pCodecContext->request_channel_layout = AV_CH_LAYOUT_5POINT1;
- + }
- + if (m_pCodecContext->request_channel_layout)
- + CLog::Log(LOGNOTICE,"COMXAudioCodecOMX::Open() Requesting channel layout of %d", (unsigned)m_pCodecContext->request_channel_layout);
-
- // vorbis has variable sized planar output, so skip concatenation
- if (hints.codec == AV_CODEC_ID_VORBIS)
- --
- 1.9.3
- From 8dedad4307cbca1416262af9e2ac2404c7490713 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Sat, 15 Mar 2014 19:38:38 +0000
- Subject: [PATCH 58/94] [omxplayer] When in dual audio mode, make one output
- the slave
- May help audio sync between the two outputs
- ---
- xbmc/cores/omxplayer/OMXAudio.cpp | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
- diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp
- index 3e64de0..72e42ec 100644
- --- a/xbmc/cores/omxplayer/OMXAudio.cpp
- +++ b/xbmc/cores/omxplayer/OMXAudio.cpp
- @@ -245,7 +245,7 @@ bool COMXAudio::PortSettingsChanged()
- {
- // By default audio_render is the clock master, and if output samples don't fit the timestamps, it will speed up/slow down the clock.
- // This tends to be better for maintaining audio sync and avoiding audio glitches, but can affect video/display sync
- - if(CSettings::Get().GetBool("videoplayer.usedisplayasclock"))
- + if(CSettings::Get().GetBool("videoplayer.usedisplayasclock") || (CSettings::Get().GetBool("audiooutput.dualaudio") && CSettings::Get().GetString("audiooutput.audiodevice") != "PI:Analogue"))
- {
- OMX_CONFIG_BOOLEANTYPE configBool;
- OMX_INIT_STRUCTURE(configBool);
- @@ -271,7 +271,7 @@ bool COMXAudio::PortSettingsChanged()
- {
- // By default audio_render is the clock master, and if output samples don't fit the timestamps, it will speed up/slow down the clock.
- // This tends to be better for maintaining audio sync and avoiding audio glitches, but can affect video/display sync
- - if(CSettings::Get().GetBool("videoplayer.usedisplayasclock"))
- + if(CSettings::Get().GetBool("videoplayer.usedisplayasclock") || (CSettings::Get().GetBool("audiooutput.dualaudio") && CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Analogue"))
- {
- OMX_CONFIG_BOOLEANTYPE configBool;
- OMX_INIT_STRUCTURE(configBool);
- --
- 1.9.3
- From 96842193cb39ac3625a1dcbdd67388141733a5ee Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Mon, 30 Dec 2013 12:02:14 +0000
- Subject: [PATCH 59/94] [rbp] Hardware accelerated resampling
- This replaces the format conversion, up/down mixing and resampling code from ActiveAE with a GPU accelerated version.
- Should significantly reduce CPU when using paplayer or dvdplayer.
- Requires updated firmware
- ---
- .../Engines/ActiveAE/ActiveAEResample.cpp | 5 +
- .../Engines/ActiveAE/ActiveAEResample.h | 9 +
- .../Engines/ActiveAE/ActiveAEResamplePi.cpp | 592 +++++++++++++++++++++
- .../Engines/ActiveAE/ActiveAEResamplePi.h | 65 +++
- xbmc/cores/AudioEngine/Makefile.in | 1 +
- xbmc/linux/OMXCore.cpp | 4 +-
- 6 files changed, 674 insertions(+), 2 deletions(-)
- create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
- create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h
- diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp
- index e131f16..94b69a0 100644
- --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp
- +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp
- @@ -18,6 +18,10 @@
- *
- */
-
- +#include "system.h"
- +
- +#if !defined(TARGET_RASPBERRY_PI)
- +
- #include "ActiveAEResample.h"
-
- using namespace ActiveAE;
- @@ -344,3 +348,4 @@ int CActiveAEResample::GetAVChannelIndex(enum AEChannel aechannel, uint64_t layo
- {
- return m_dllAvUtil.av_get_channel_layout_channel_index(layout, GetAVChannel(aechannel));
- }
- +#endif
- diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h
- index 1e0e342..6a8949b 100644
- --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h
- +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h
- @@ -21,11 +21,18 @@
-
- #include "DllAvUtil.h"
- #include "DllSwResample.h"
- +
- +#include "system.h"
- +
- #include "cores/AudioEngine/Utils/AEChannelInfo.h"
- #include "cores/AudioEngine/Utils/AEAudioFormat.h"
- #include "cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.h"
- #include "cores/AudioEngine/Interfaces/AE.h"
-
- +#if defined(TARGET_RASPBERRY_PI)
- +#include "ActiveAEResamplePi.h"
- +#else
- +
- namespace ActiveAE
- {
-
- @@ -62,3 +69,5 @@ class CActiveAEResample
- };
-
- }
- +
- +#endif
- diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
- new file mode 100644
- index 0000000..1d7b425
- --- /dev/null
- +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
- @@ -0,0 +1,592 @@
- +/*
- + * Copyright (C) 2010-2013 Team XBMC
- + * http://xbmc.org
- + *
- + * This Program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License as published by
- + * the Free Software Foundation; either version 2, or (at your option)
- + * any later version.
- + *
- + * This Program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with XBMC; see the file COPYING. If not, see
- + * <http://www.gnu.org/licenses/>.
- + *
- + */
- +
- +#include "system.h"
- +
- +#if defined(TARGET_RASPBERRY_PI)
- +
- +#include "ActiveAEResample.h"
- +#include "linux/RBP.h"
- +#include "cores/omxplayer/PCMRemap.h"
- +#include "settings/Settings.h"
- +#include "utils/log.h"
- +
- +//#define DEBUG_VERBOSE
- +
- +#define CLASSNAME "CActiveAEResamplePi"
- +
- +#define BUFFERSIZE (32*1024*2*8)
- +
- +//#define BENCHMARKING
- +#ifdef BENCHMARKING
- +#define LOGTIMEINIT(f) \
- + struct timespec now; \
- + uint64_t Start, End; \
- + clock_gettime(CLOCK_MONOTONIC, &now); \
- + Start = ((int64_t)now.tv_sec * 1000000000L) + now.tv_nsec; \
- + const char *_filename = f;
- +
- +#define LOGTIME(n) \
- + clock_gettime(CLOCK_MONOTONIC, &now); \
- + End = ((int64_t)now.tv_sec * 1000000000L) + now.tv_nsec; \
- + CLog::Log(LOGNOTICE, "ActiveAE::%s %d - resample %s took %.0fms", __FUNCTION__, n, _filename, (End-Start)*1e-6); \
- + Start=End;
- +#else
- +#define LOGTIMEINIT(f)
- +#define LOGTIME(n)
- +#endif
- +
- +using namespace ActiveAE;
- +
- +CActiveAEResample::CActiveAEResample()
- +{
- + CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
- + m_loaded = false;
- +
- + if (m_dllAvUtil.Load() && m_dllSwResample.Load())
- + m_loaded = true;
- +
- + m_Initialized = false;
- + m_last_src_fmt = AV_SAMPLE_FMT_NONE;
- + m_last_dst_fmt = AV_SAMPLE_FMT_NONE;
- + m_last_src_channels = 0;
- + m_last_dst_channels = 0;
- +}
- +
- +CActiveAEResample::~CActiveAEResample()
- +{
- + CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
- + DeInit();
- + m_dllAvUtil.Unload();
- + m_dllSwResample.Unload();
- +}
- +
- +void CActiveAEResample::DeInit()
- +{
- + CLog::Log(LOGDEBUG, "%s:%s", CLASSNAME, __func__);
- + if (m_Initialized)
- + {
- + m_omx_mixer.FlushAll();
- + m_omx_mixer.Deinitialize();
- + m_Initialized = false;
- + }
- +}
- +
- +bool CActiveAEResample::Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality)
- +{
- + LOGTIMEINIT("x");
- +
- + CLog::Log(LOGINFO, "%s::%s remap:%p chan:%d->%d rate:%d->%d format:%d->%d bits:%d->%d norm:%d upmix:%d", CLASSNAME, __func__, remapLayout, src_channels, dst_channels, src_rate, dst_rate, src_fmt, dst_fmt, src_bits, dst_bits, normalize, upmix);
- + if (!m_loaded)
- + return false;
- +
- + m_dst_chan_layout = dst_chan_layout;
- + m_dst_channels = dst_channels;
- + m_dst_rate = dst_rate;
- + m_dst_fmt = dst_fmt;
- + m_dst_bits = dst_bits ? dst_bits : 8;
- + m_src_chan_layout = src_chan_layout;
- + m_src_channels = src_channels;
- + m_src_rate = src_rate;
- + m_src_fmt = src_fmt;
- + m_src_bits = src_bits ? src_bits : 8;
- +
- + if (m_dst_chan_layout == 0)
- + m_dst_chan_layout = m_dllAvUtil.av_get_default_channel_layout(m_dst_channels);
- + if (m_src_chan_layout == 0)
- + m_src_chan_layout = m_dllAvUtil.av_get_default_channel_layout(m_src_channels);
- +
- + OMX_CONFIG_BRCMAUDIODOWNMIXCOEFFICIENTS8x8 mix;
- + OMX_INIT_STRUCTURE(mix);
- +
- + assert(sizeof(mix.coeff)/sizeof(mix.coeff[0]) == 64);
- +
- + LOGTIME(1);
- +// this code is just uses ffmpeg to produce the 8x8 mixing matrix
- +{
- + // dummy sample rate and format, as we only care about channel mapping
- + SwrContext *m_pContext = m_dllSwResample.swr_alloc_set_opts(NULL, m_dst_chan_layout, AV_SAMPLE_FMT_FLT, 48000,
- + m_src_chan_layout, AV_SAMPLE_FMT_FLT, 48000, 0, NULL);
- + if (!m_pContext)
- + {
- + CLog::Log(LOGERROR, "CActiveAEResample::Init - create context failed");
- + return false;
- + }
- + // tell resampler to clamp float values
- + // not required for sink stage (remapLayout == true)
- + if (!remapLayout && normalize)
- + {
- + m_dllAvUtil.av_opt_set_double(m_pContext, "rematrix_maxval", 1.0, 0);
- + }
- +
- + if (remapLayout)
- + {
- + // one-to-one mapping of channels
- + // remapLayout is the layout of the sink, if the channel is in our src layout
- + // the channel is mapped by setting coef 1.0
- + double m_rematrix[AE_CH_MAX][AE_CH_MAX];
- + memset(m_rematrix, 0, sizeof(m_rematrix));
- + m_dst_chan_layout = 0;
- + for (unsigned int out=0; out<remapLayout->Count(); out++)
- + {
- + m_dst_chan_layout += (uint64_t) (1 << out);
- + int idx = GetAVChannelIndex((*remapLayout)[out], m_src_chan_layout);
- + if (idx >= 0)
- + {
- + m_rematrix[out][idx] = 1.0;
- + }
- + }
- +
- + m_dllAvUtil.av_opt_set_int(m_pContext, "out_channel_count", m_dst_channels, 0);
- + m_dllAvUtil.av_opt_set_int(m_pContext, "out_channel_layout", m_dst_chan_layout, 0);
- +
- + if (m_dllSwResample.swr_set_matrix(m_pContext, (const double*)m_rematrix, AE_CH_MAX) < 0)
- + {
- + CLog::Log(LOGERROR, "CActiveAEResample::Init - setting channel matrix failed");
- + return false;
- + }
- + }
- + // stereo upmix
- + else if (upmix && m_src_channels == 2 && m_dst_channels > 2)
- + {
- + double m_rematrix[AE_CH_MAX][AE_CH_MAX];
- + memset(m_rematrix, 0, sizeof(m_rematrix));
- + for (int out=0; out<m_dst_channels; out++)
- + {
- + uint64_t out_chan = m_dllAvUtil.av_channel_layout_extract_channel(m_dst_chan_layout, out);
- + switch(out_chan)
- + {
- + case AV_CH_FRONT_LEFT:
- + case AV_CH_BACK_LEFT:
- + case AV_CH_SIDE_LEFT:
- + m_rematrix[out][0] = 1.0;
- + break;
- + case AV_CH_FRONT_RIGHT:
- + case AV_CH_BACK_RIGHT:
- + case AV_CH_SIDE_RIGHT:
- + m_rematrix[out][1] = 1.0;
- + break;
- + case AV_CH_FRONT_CENTER:
- + m_rematrix[out][0] = 0.5;
- + m_rematrix[out][1] = 0.5;
- + break;
- + case AV_CH_LOW_FREQUENCY:
- + m_rematrix[out][0] = 0.5;
- + m_rematrix[out][1] = 0.5;
- + break;
- + default:
- + break;
- + }
- + }
- +
- + if (m_dllSwResample.swr_set_matrix(m_pContext, (const double*)m_rematrix, AE_CH_MAX) < 0)
- + {
- + CLog::Log(LOGERROR, "CActiveAEResample::Init - setting channel matrix failed");
- + return false;
- + }
- + }
- +
- + if (m_dllSwResample.swr_init(m_pContext) < 0)
- + {
- + CLog::Log(LOGERROR, "CActiveAEResample::Init - init resampler failed");
- + return false;
- + }
- +
- + const int samples = 8;
- + uint8_t *output, *input;
- + av_samples_alloc(&output, NULL, m_dst_channels, samples, AV_SAMPLE_FMT_FLT, 1);
- + av_samples_alloc(&input , NULL, m_src_channels, samples, AV_SAMPLE_FMT_FLT, 1);
- +
- + // Produce "identity" samples
- + float *f = (float *)input;
- + for (int j=0; j < samples; j++)
- + for (int i=0; i < m_src_channels; i++)
- + *f++ = i == j ? 1.0f : 0.0f;
- +
- + int ret = m_dllSwResample.swr_convert(m_pContext, &output, samples, (const uint8_t **)&input, samples);
- + if (ret < 0)
- + CLog::Log(LOGERROR, "CActiveAEResample::Resample - resample failed");
- +
- + f = (float *)output;
- + for (int j=0; j < samples; j++)
- + for (int i=0; i < m_dst_channels; i++)
- + mix.coeff[8*i+j] = *f++ * (1<<16);
- +
- + for (int j=0; j < 8; j++)
- + {
- + char s[128] = {}, *t=s;
- + for (int i=0; i < 8; i++)
- + t += sprintf(t, "% 6.2f ", mix.coeff[j*8+i] * (1.0/0x10000));
- + CLog::Log(LOGINFO, "%s::%s %s", CLASSNAME, __func__, s);
- + }
- + av_freep(&input);
- + av_freep(&output);
- + m_dllSwResample.swr_free(&m_pContext);
- +}
- + LOGTIME(2);
- +
- + // This may be called before Application calls g_RBP.Initialise, so call it here too
- + g_RBP.Initialize();
- +
- + OMX_ERRORTYPE omx_err = OMX_ErrorNone;
- +
- + if (!m_omx_mixer.Initialize("OMX.broadcom.audio_mixer", OMX_IndexParamAudioInit))
- + CLog::Log(LOGERROR, "%s::%s - m_omx_mixer.Initialize omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- +
- + LOGTIME(3);
- +
- + OMX_INIT_STRUCTURE(m_pcm_input);
- + m_pcm_input.nPortIndex = m_omx_mixer.GetInputPort();
- + m_pcm_input.eNumData = OMX_NumericalDataSigned;
- + m_pcm_input.eEndian = OMX_EndianLittle;
- + m_pcm_input.bInterleaved = OMX_TRUE;
- + m_pcm_input.nBitPerSample = m_src_bits;
- + m_pcm_input.ePCMMode = m_src_fmt == AV_SAMPLE_FMT_FLT ? (OMX_AUDIO_PCMMODETYPE)0x8000 : OMX_AUDIO_PCMModeLinear;
- + m_pcm_input.nChannels = src_channels;
- + m_pcm_input.nSamplingRate = src_rate;
- +
- + omx_err = m_omx_mixer.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input);
- + if (omx_err != OMX_ErrorNone)
- + CLog::Log(LOGERROR, "%s::%s - error m_omx_mixer in SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- +
- + OMX_INIT_STRUCTURE(m_pcm_output);
- + m_pcm_output.nPortIndex = m_omx_mixer.GetOutputPort();
- + m_pcm_output.eNumData = OMX_NumericalDataSigned;
- + m_pcm_output.eEndian = OMX_EndianLittle;
- + m_pcm_output.bInterleaved = OMX_TRUE;
- + m_pcm_output.nBitPerSample = m_dst_bits;
- + m_pcm_output.ePCMMode = m_dst_fmt == AV_SAMPLE_FMT_FLT ? (OMX_AUDIO_PCMMODETYPE)0x8000 : OMX_AUDIO_PCMModeLinear;
- + m_pcm_output.nChannels = dst_channels;
- + m_pcm_output.nSamplingRate = dst_rate;
- +
- + omx_err = m_omx_mixer.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_output);
- + if (omx_err != OMX_ErrorNone)
- + CLog::Log(LOGERROR, "%s::%s - error m_omx_mixer out SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- +
- + LOGTIME(4);
- +
- + mix.nPortIndex = m_omx_mixer.GetInputPort();
- + omx_err = m_omx_mixer.SetConfig(OMX_IndexConfigBrcmAudioDownmixCoefficients8x8, &mix);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s - error setting mixer OMX_IndexConfigBrcmAudioDownmixCoefficients, error 0x%08x\n",
- + CLASSNAME, __func__, omx_err);
- + return false;
- + }
- +
- + // set up the number/size of buffers for decoder input
- + OMX_PARAM_PORTDEFINITIONTYPE port_param;
- + OMX_INIT_STRUCTURE(port_param);
- + port_param.nPortIndex = m_omx_mixer.GetInputPort();
- +
- + omx_err = m_omx_mixer.GetParameter(OMX_IndexParamPortDefinition, &port_param);
- + if (omx_err != OMX_ErrorNone)
- + CLog::Log(LOGERROR, "%s:%s - error get OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- +
- + port_param.nBufferCountActual = std::max((unsigned int)port_param.nBufferCountMin, (unsigned int)1);
- + port_param.nBufferSize = BUFFERSIZE;
- +
- + omx_err = m_omx_mixer.SetParameter(OMX_IndexParamPortDefinition, &port_param);
- + if (omx_err != OMX_ErrorNone)
- + CLog::Log(LOGERROR, "%s:%s - error set OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- +
- + LOGTIME(5);
- +
- + omx_err = m_omx_mixer.AllocInputBuffers();
- + if (omx_err != OMX_ErrorNone)
- + CLog::Log(LOGERROR, "%s:%s - Error alloc buffers 0x%08x", CLASSNAME, __func__, omx_err);
- +
- + LOGTIME(6);
- +
- + // set up the number/size of buffers for decoder output
- + OMX_INIT_STRUCTURE(port_param);
- + port_param.nPortIndex = m_omx_mixer.GetOutputPort();
- +
- + omx_err = m_omx_mixer.GetParameter(OMX_IndexParamPortDefinition, &port_param);
- + if (omx_err != OMX_ErrorNone)
- + CLog::Log(LOGERROR, "%s:%s - error get OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- +
- + port_param.nBufferCountActual = std::max((unsigned int)port_param.nBufferCountMin, (unsigned int)1);
- + port_param.nBufferSize = BUFFERSIZE;
- +
- + omx_err = m_omx_mixer.SetParameter(OMX_IndexParamPortDefinition, &port_param);
- + if (omx_err != OMX_ErrorNone)
- + CLog::Log(LOGERROR, "%s:%s - error set OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- +
- + LOGTIME(7);
- +
- + omx_err = m_omx_mixer.AllocOutputBuffers();
- + if (omx_err != OMX_ErrorNone)
- + CLog::Log(LOGERROR, "%s:%s - Error alloc buffers 0x%08x", CLASSNAME, __func__, omx_err);
- +
- + LOGTIME(8);
- +
- + omx_err = m_omx_mixer.SetStateForComponent(OMX_StateExecuting);
- + if (omx_err != OMX_ErrorNone)
- + CLog::Log(LOGERROR, "%s:%s - m_omx_mixer OMX_StateExecuting omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- +
- + LOGTIME(9);
- +
- + m_Initialized = true;
- +
- + return true;
- +}
- +
- +int CActiveAEResample::Resample(uint8_t **dst_buffer, int dst_samples, uint8_t **src_buffer, int src_samples, double ratio)
- +{
- + #ifdef DEBUG_VERBOSE
- + CLog::Log(LOGINFO, "%s::%s samples:%d->%d (%.2f)", CLASSNAME, __func__, src_samples, dst_samples, ratio);
- + #endif
- + if (!m_Initialized)
- + return 0;
- + OMX_ERRORTYPE omx_err = OMX_ErrorNone;
- +
- + const int s_pitch = m_pcm_input.nChannels * m_src_bits >> 3;
- + const int d_pitch = m_pcm_output.nChannels * m_dst_bits >> 3;
- + int sent = 0;
- + int received = 0;
- + while (sent < src_samples)
- + {
- + OMX_BUFFERHEADERTYPE *omx_buffer = NULL;
- + OMX_BUFFERHEADERTYPE *m_encoded_buffer = NULL;
- +
- + omx_buffer = m_omx_mixer.GetInputBuffer(1000);
- + if (omx_buffer == NULL)
- + return false;
- +
- + const int max_src_samples = BUFFERSIZE / s_pitch;
- + const int max_dst_samples = (long long)(BUFFERSIZE/d_pitch) * m_src_rate / (m_dst_rate + m_src_rate-1);
- + int send = std::min(std::min(max_dst_samples, max_src_samples), src_samples - sent);
- +
- + omx_buffer->nOffset = 0;
- + omx_buffer->nFlags = OMX_BUFFERFLAG_EOS;
- + omx_buffer->nFilledLen = send * s_pitch;
- +
- + assert(omx_buffer->nFilledLen > 0 && omx_buffer->nFilledLen <= omx_buffer->nAllocLen);
- +
- + if (omx_buffer->nFilledLen)
- + {
- + memcpy(omx_buffer->pBuffer, src_buffer[0] + sent * s_pitch, omx_buffer->nFilledLen);
- + sent += send;
- + }
- +
- + omx_err = m_omx_mixer.EmptyThisBuffer(omx_buffer);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s OMX_EmptyThisBuffer() failed with result(0x%x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- +
- + m_encoded_buffer = m_omx_mixer.GetOutputBuffer();
- +
- + if (!m_encoded_buffer)
- + {
- + CLog::Log(LOGERROR, "%s::%s no output buffer", CLASSNAME, __func__);
- + return false;
- + }
- +
- + omx_err = m_omx_mixer.FillThisBuffer(m_encoded_buffer);
- + if (omx_err != OMX_ErrorNone)
- + return false;
- +
- + omx_err = m_omx_mixer.WaitForOutputDone(1000);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "%s::%s m_omx_mixer.WaitForOutputDone result(0x%x)", CLASSNAME, __func__, omx_err);
- + return false;
- + }
- + assert(m_encoded_buffer->nFilledLen > 0 && m_encoded_buffer->nFilledLen <= m_encoded_buffer->nAllocLen);
- +
- + if (m_omx_mixer.BadState())
- + {
- + CLog::Log(LOGERROR, "%s::%s m_omx_mixer.BadState", CLASSNAME, __func__);
- + return false;
- + }
- +
- + if (m_encoded_buffer->nFilledLen)
- + {
- + memcpy(dst_buffer[0] + received * d_pitch, m_encoded_buffer->pBuffer, m_encoded_buffer->nFilledLen);
- + received += m_encoded_buffer->nFilledLen / d_pitch;
- + }
- + }
- + #ifdef DEBUG_VERBOSE
- + CLog::Log(LOGINFO, "%s::%s format:%d->%d rate:%d->%d chan:%d->%d samples %d->%d (%f) %d =%d", CLASSNAME, __func__,
- + (int)m_src_fmt, (int)m_dst_fmt, m_src_rate, m_dst_rate, m_src_channels, m_dst_channels, src_samples, dst_samples, ratio, m_Initialized, received);
- + #endif
- + return received;
- +}
- +
- +int64_t CActiveAEResample::GetDelay(int64_t base)
- +{
- + int ret = 0;
- + #ifdef DEBUG_VERBOSE
- + CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret);
- + #endif
- + return ret;
- +}
- +
- +int CActiveAEResample::GetBufferedSamples()
- +{
- + int ret = 0;
- + #ifdef DEBUG_VERBOSE
- + CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret);
- + #endif
- + return ret;
- +}
- +
- +int CActiveAEResample::CalcDstSampleCount(int src_samples, int dst_rate, int src_rate)
- +{
- + int ret = ((long long)src_samples * dst_rate + src_rate-1) / src_rate;
- + #ifdef DEBUG_VERBOSE
- + CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret);
- + #endif
- + return ret;
- +}
- +
- +int CActiveAEResample::GetSrcBufferSize(int samples)
- +{
- + int ret = 0;
- + #ifdef DEBUG_VERBOSE
- + CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret);
- + #endif
- + return ret;
- +}
- +
- +int CActiveAEResample::GetDstBufferSize(int samples)
- +{
- + int ret = CalcDstSampleCount(samples, m_dst_rate, m_src_rate);
- + #ifdef DEBUG_VERBOSE
- + CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret);
- + #endif
- + return ret;
- +}
- +
- +uint64_t CActiveAEResample::GetAVChannelLayout(CAEChannelInfo &info)
- +{
- + #ifdef DEBUG_VERBOSE
- + CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
- + #endif
- + uint64_t channelLayout = 0;
- + if (info.HasChannel(AE_CH_FL)) channelLayout |= AV_CH_FRONT_LEFT;
- + if (info.HasChannel(AE_CH_FR)) channelLayout |= AV_CH_FRONT_RIGHT;
- + if (info.HasChannel(AE_CH_FC)) channelLayout |= AV_CH_FRONT_CENTER;
- + if (info.HasChannel(AE_CH_LFE)) channelLayout |= AV_CH_LOW_FREQUENCY;
- + if (info.HasChannel(AE_CH_BL)) channelLayout |= AV_CH_BACK_LEFT;
- + if (info.HasChannel(AE_CH_BR)) channelLayout |= AV_CH_BACK_RIGHT;
- + if (info.HasChannel(AE_CH_FLOC)) channelLayout |= AV_CH_FRONT_LEFT_OF_CENTER;
- + if (info.HasChannel(AE_CH_FROC)) channelLayout |= AV_CH_FRONT_RIGHT_OF_CENTER;
- + if (info.HasChannel(AE_CH_BC)) channelLayout |= AV_CH_BACK_CENTER;
- + if (info.HasChannel(AE_CH_SL)) channelLayout |= AV_CH_SIDE_LEFT;
- + if (info.HasChannel(AE_CH_SR)) channelLayout |= AV_CH_SIDE_RIGHT;
- + if (info.HasChannel(AE_CH_TC)) channelLayout |= AV_CH_TOP_CENTER;
- + if (info.HasChannel(AE_CH_TFL)) channelLayout |= AV_CH_TOP_FRONT_LEFT;
- + if (info.HasChannel(AE_CH_TFC)) channelLayout |= AV_CH_TOP_FRONT_CENTER;
- + if (info.HasChannel(AE_CH_TFR)) channelLayout |= AV_CH_TOP_FRONT_RIGHT;
- + if (info.HasChannel(AE_CH_TBL)) channelLayout |= AV_CH_TOP_BACK_LEFT;
- + if (info.HasChannel(AE_CH_TBC)) channelLayout |= AV_CH_TOP_BACK_CENTER;
- + if (info.HasChannel(AE_CH_TBR)) channelLayout |= AV_CH_TOP_BACK_RIGHT;
- +
- + return channelLayout;
- +}
- +
- +AVSampleFormat CActiveAEResample::GetAVSampleFormat(AEDataFormat format)
- +{
- + #ifdef DEBUG_VERBOSE
- + CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
- + #endif
- + if (format == AE_FMT_U8) return AV_SAMPLE_FMT_U8;
- + else if (format == AE_FMT_S16NE) return AV_SAMPLE_FMT_S16;
- + else if (format == AE_FMT_S32NE) return AV_SAMPLE_FMT_S32;
- + else if (format == AE_FMT_S24NE4) return AV_SAMPLE_FMT_S32;
- + else if (format == AE_FMT_FLOAT) return AV_SAMPLE_FMT_FLT;
- + else if (format == AE_FMT_DOUBLE) return AV_SAMPLE_FMT_DBL;
- +
- + else if (format == AE_FMT_U8P) return AV_SAMPLE_FMT_U8P;
- + else if (format == AE_FMT_S16NEP) return AV_SAMPLE_FMT_S16P;
- + else if (format == AE_FMT_S32NEP) return AV_SAMPLE_FMT_S32P;
- + else if (format == AE_FMT_S24NE4P) return AV_SAMPLE_FMT_S32P;
- + else if (format == AE_FMT_FLOATP) return AV_SAMPLE_FMT_FLTP;
- + else if (format == AE_FMT_DOUBLEP) return AV_SAMPLE_FMT_DBLP;
- +
- + return AV_SAMPLE_FMT_FLT;
- +}
- +
- +AEDataFormat CActiveAEResample::GetAESampleFormat(AVSampleFormat format, int bits)
- +{
- + #ifdef DEBUG_VERBOSE
- + CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
- + #endif
- + if (format == AV_SAMPLE_FMT_U8) return AE_FMT_U8;
- + else if (format == AV_SAMPLE_FMT_S16) return AE_FMT_S16NE;
- + else if (format == AV_SAMPLE_FMT_S32 && bits == 32) return AE_FMT_S32NE;
- + else if (format == AV_SAMPLE_FMT_S32 && bits == 24) return AE_FMT_S24NE4;
- + else if (format == AV_SAMPLE_FMT_FLT) return AE_FMT_FLOAT;
- + else if (format == AV_SAMPLE_FMT_DBL) return AE_FMT_DOUBLE;
- +
- + else if (format == AV_SAMPLE_FMT_U8P) return AE_FMT_U8P;
- + else if (format == AV_SAMPLE_FMT_S16P) return AE_FMT_S16NEP;
- + else if (format == AV_SAMPLE_FMT_S32P && bits == 32) return AE_FMT_S32NEP;
- + else if (format == AV_SAMPLE_FMT_S32P && bits == 24) return AE_FMT_S24NE4P;
- + else if (format == AV_SAMPLE_FMT_FLTP) return AE_FMT_FLOATP;
- + else if (format == AV_SAMPLE_FMT_DBLP) return AE_FMT_DOUBLEP;
- +
- + CLog::Log(LOGERROR, "CActiveAEResample::GetAESampleFormat - format not supported");
- + return AE_FMT_INVALID;
- +}
- +
- +uint64_t CActiveAEResample::GetAVChannel(enum AEChannel aechannel)
- +{
- + #ifdef DEBUG_VERBOSE
- + CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
- + #endif
- + switch (aechannel)
- + {
- + case AE_CH_FL: return AV_CH_FRONT_LEFT;
- + case AE_CH_FR: return AV_CH_FRONT_RIGHT;
- + case AE_CH_FC: return AV_CH_FRONT_CENTER;
- + case AE_CH_LFE: return AV_CH_LOW_FREQUENCY;
- + case AE_CH_BL: return AV_CH_BACK_LEFT;
- + case AE_CH_BR: return AV_CH_BACK_RIGHT;
- + case AE_CH_FLOC: return AV_CH_FRONT_LEFT_OF_CENTER;
- + case AE_CH_FROC: return AV_CH_FRONT_RIGHT_OF_CENTER;
- + case AE_CH_BC: return AV_CH_BACK_CENTER;
- + case AE_CH_SL: return AV_CH_SIDE_LEFT;
- + case AE_CH_SR: return AV_CH_SIDE_RIGHT;
- + case AE_CH_TC: return AV_CH_TOP_CENTER;
- + case AE_CH_TFL: return AV_CH_TOP_FRONT_LEFT;
- + case AE_CH_TFC: return AV_CH_TOP_FRONT_CENTER;
- + case AE_CH_TFR: return AV_CH_TOP_FRONT_RIGHT;
- + case AE_CH_TBL: return AV_CH_TOP_BACK_LEFT;
- + case AE_CH_TBC: return AV_CH_TOP_BACK_CENTER;
- + case AE_CH_TBR: return AV_CH_TOP_BACK_RIGHT;
- + default:
- + return 0;
- + }
- +}
- +
- +int CActiveAEResample::GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout)
- +{
- + #ifdef DEBUG_VERBOSE
- + CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
- + #endif
- + return m_dllAvUtil.av_get_channel_layout_channel_index(layout, GetAVChannel(aechannel));
- +}
- +
- +#endif
- diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h
- new file mode 100644
- index 0000000..8371c33
- --- /dev/null
- +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h
- @@ -0,0 +1,65 @@
- +#pragma once
- +/*
- + * Copyright (C) 2010-2013 Team XBMC
- + * http://xbmc.org
- + *
- + * This Program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License as published by
- + * the Free Software Foundation; either version 2, or (at your option)
- + * any later version.
- + *
- + * This Program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with XBMC; see the file COPYING. If not, see
- + * <http://www.gnu.org/licenses/>.
- + *
- + */
- +
- +#include "linux/OMXCore.h"
- +
- +namespace ActiveAE
- +{
- +
- +class CActiveAEResample
- +{
- +public:
- + CActiveAEResample();
- + virtual ~CActiveAEResample();
- + bool Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality);
- + int Resample(uint8_t **dst_buffer, int dst_samples, uint8_t **src_buffer, int src_samples, double ratio);
- + int64_t GetDelay(int64_t base);
- + int GetBufferedSamples();
- + int CalcDstSampleCount(int src_samples, int dst_rate, int src_rate);
- + int GetSrcBufferSize(int samples);
- + int GetDstBufferSize(int samples);
- + static uint64_t GetAVChannelLayout(CAEChannelInfo &info);
- +// static CAEChannelInfo GetAEChannelLayout(uint64_t layout);
- + static AVSampleFormat GetAVSampleFormat(AEDataFormat format);
- + static AEDataFormat GetAESampleFormat(AVSampleFormat format, int bits);
- + static uint64_t GetAVChannel(enum AEChannel aechannel);
- + int GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout);
- +
- +protected:
- + void DeInit();
- + DllAvUtil m_dllAvUtil;
- + DllSwResample m_dllSwResample;
- + bool m_loaded;
- + uint64_t m_src_chan_layout, m_dst_chan_layout;
- + int m_src_rate, m_dst_rate;
- + int m_src_channels, m_dst_channels;
- + AVSampleFormat m_src_fmt, m_dst_fmt;
- + int m_src_bits, m_dst_bits;
- +
- + OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_input;
- + OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_output;
- + COMXCoreComponent m_omx_mixer;
- + bool m_Initialized;
- + AVSampleFormat m_last_src_fmt, m_last_dst_fmt;
- + int m_last_src_channels, m_last_dst_channels;
- +};
- +
- +}
- diff --git a/xbmc/cores/AudioEngine/Makefile.in b/xbmc/cores/AudioEngine/Makefile.in
- index b49c3cc..2ba50f9 100644
- --- a/xbmc/cores/AudioEngine/Makefile.in
- +++ b/xbmc/cores/AudioEngine/Makefile.in
- @@ -31,6 +31,7 @@ SRCS += Engines/ActiveAE/ActiveAESink.cpp
- SRCS += Engines/ActiveAE/ActiveAEStream.cpp
- SRCS += Engines/ActiveAE/ActiveAESound.cpp
- SRCS += Engines/ActiveAE/ActiveAEResample.cpp
- +SRCS += Engines/ActiveAE/ActiveAEResamplePi.cpp
- SRCS += Engines/ActiveAE/ActiveAEBuffer.cpp
-
- ifeq (@USE_ANDROID@,1)
- diff --git a/xbmc/linux/OMXCore.cpp b/xbmc/linux/OMXCore.cpp
- index 99e407a..8d3c86a 100644
- --- a/xbmc/linux/OMXCore.cpp
- +++ b/xbmc/linux/OMXCore.cpp
- @@ -448,7 +448,7 @@ void COMXCoreComponent::FlushAll()
-
- void COMXCoreComponent::FlushInput()
- {
- - if(!m_handle)
- + if(!m_handle || m_resource_error)
- return;
-
- OMX_ERRORTYPE omx_err = OMX_ErrorNone;
- @@ -470,7 +470,7 @@ void COMXCoreComponent::FlushInput()
-
- void COMXCoreComponent::FlushOutput()
- {
- - if(!m_handle)
- + if(!m_handle || m_resource_error)
- return;
-
- OMX_ERRORTYPE omx_err = OMX_ErrorNone;
- --
- 1.9.3
- From 07042c916d780bf4acb742e174005aa1e38f3a13 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Thu, 27 Mar 2014 00:22:05 +0000
- Subject: [PATCH 60/94] [PiResample] Work around AE not providing correct
- src_bits
- ---
- .../AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp | 13 +++++++++++--
- 1 file changed, 11 insertions(+), 2 deletions(-)
- diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
- index 1d7b425..a91e208 100644
- --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
- +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
- @@ -97,16 +97,25 @@ bool CActiveAEResample::Init(uint64_t dst_chan_layout, int dst_channels, int dst
- if (!m_loaded)
- return false;
-
- + if (src_bits == 0)
- + {
- + if (src_fmt == AV_SAMPLE_FMT_U8) src_bits = 8;
- + else if (src_fmt == AV_SAMPLE_FMT_S16) src_bits = 16;
- + else if (src_fmt == AV_SAMPLE_FMT_S32) src_bits = 32;
- + else if (src_fmt == AV_SAMPLE_FMT_FLT) src_bits = 32;
- + }
- + assert(src_bits && dst_bits);
- +
- m_dst_chan_layout = dst_chan_layout;
- m_dst_channels = dst_channels;
- m_dst_rate = dst_rate;
- m_dst_fmt = dst_fmt;
- - m_dst_bits = dst_bits ? dst_bits : 8;
- + m_dst_bits = dst_bits;
- m_src_chan_layout = src_chan_layout;
- m_src_channels = src_channels;
- m_src_rate = src_rate;
- m_src_fmt = src_fmt;
- - m_src_bits = src_bits ? src_bits : 8;
- + m_src_bits = src_bits;
-
- if (m_dst_chan_layout == 0)
- m_dst_chan_layout = m_dllAvUtil.av_get_default_channel_layout(m_dst_channels);
- --
- 1.9.3
- From 16e8c9550b1afc0a4f5c050cc10c2c19ec9cea38 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Tue, 25 Mar 2014 19:43:07 +0000
- Subject: [PATCH 61/94] [ffmpeg] Speed up wtv index creation
- The index creation is O(N^2) with number of entries (typically thousands).
- On a Pi this can take more than 60 seconds to execute for a recording of a few hours.
- By replacing with an O(N) loop, this takes virtually zero time
- ---
- lib/ffmpeg/libavformat/wtvdec.c | 18 ++++++++++--------
- 1 file changed, 10 insertions(+), 8 deletions(-)
- diff --git a/lib/ffmpeg/libavformat/wtvdec.c b/lib/ffmpeg/libavformat/wtvdec.c
- index e423370..70898bd 100644
- --- a/lib/ffmpeg/libavformat/wtvdec.c
- +++ b/lib/ffmpeg/libavformat/wtvdec.c
- @@ -980,21 +980,23 @@ static int read_header(AVFormatContext *s)
- pb = wtvfile_open(s, root, root_size, ff_timeline_table_0_entries_Events_le16);
- if (pb) {
- int i;
- + AVIndexEntry *e = wtv->index_entries;
- + AVIndexEntry *e_end = wtv->index_entries + wtv->nb_index_entries - 1;
- + uint64_t last_position = 0;
- while (1) {
- uint64_t frame_nb = avio_rl64(pb);
- uint64_t position = avio_rl64(pb);
- + while (frame_nb > e->size && e <= e_end) {
- + e->pos = last_position;
- + e++;
- + }
- if (url_feof(pb))
- break;
- - for (i = wtv->nb_index_entries - 1; i >= 0; i--) {
- - AVIndexEntry *e = wtv->index_entries + i;
- - if (frame_nb > e->size)
- - break;
- - if (position > e->pos)
- - e->pos = position;
- - }
- + last_position = position;
- }
- + e_end->pos = last_position;
- wtvfile_close(pb);
- - st->duration = wtv->index_entries[wtv->nb_index_entries - 1].timestamp;
- + st->duration = e_end->timestamp;
- }
- }
- }
- --
- 1.9.3
- From c95293a4cfd39a5296b434c330c3e6e24831bb6e Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Mon, 7 Apr 2014 18:19:32 +0100
- Subject: [PATCH 62/94] [rbp/omxplayer] When opening a stream don't try to
- update gui so often
- ---
- xbmc/dialogs/GUIDialogBusy.cpp | 4 ++++
- 1 file changed, 4 insertions(+)
- diff --git a/xbmc/dialogs/GUIDialogBusy.cpp b/xbmc/dialogs/GUIDialogBusy.cpp
- index e9ba7d3..0fdc3c2 100644
- --- a/xbmc/dialogs/GUIDialogBusy.cpp
- +++ b/xbmc/dialogs/GUIDialogBusy.cpp
- @@ -64,7 +64,11 @@ bool CGUIDialogBusy::WaitOnEvent(CEvent &event, unsigned int displaytime /* = 10
- if (dialog)
- {
- dialog->Show();
- +#ifdef TARGET_RASPBERRY_PI
- + while(!event.WaitMSec(100))
- +#else
- while(!event.WaitMSec(1))
- +#endif
- {
- g_windowManager.ProcessRenderLoop(false);
- if (allowCancel && dialog->IsCanceled())
- --
- 1.9.3
- From 9420d803f17902c7d9f1e6734ab42a78c5d67572 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Mon, 7 Apr 2014 15:28:57 +0100
- Subject: [PATCH 63/94] [omxcodec] Clamp video texture at edges to avoid image
- wrapping
- ---
- xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 2 ++
- 1 file changed, 2 insertions(+)
- diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
- index a57abe4..e22a153 100644
- --- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
- +++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
- @@ -1339,6 +1339,8 @@ void CLinuxRendererGLES::RenderOpenMax(int index, int field)
- GLint filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR;
- glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter);
- glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter);
- + glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- + glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA);
-
- --
- 1.9.3
- From 49c65c8d083952be840d8730f3fa40cfd5e0211c Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Mon, 7 Apr 2014 17:36:19 +0100
- Subject: [PATCH 64/94] [PiSink] Remove unneeded header and use CAEChannelInfo
- directly
- ---
- .../AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp | 1 -
- xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp | 14 +++++++-------
- 2 files changed, 7 insertions(+), 8 deletions(-)
- diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
- index a91e208..60c5e04 100644
- --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
- +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
- @@ -24,7 +24,6 @@
-
- #include "ActiveAEResample.h"
- #include "linux/RBP.h"
- -#include "cores/omxplayer/PCMRemap.h"
- #include "settings/Settings.h"
- #include "utils/log.h"
-
- diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
- index 9ce00e3..070e6eb 100644
- --- a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
- +++ b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
- @@ -78,9 +78,9 @@ static void SetAudioProps(bool stream_channels, uint32_t channel_map)
- CLog::Log(LOGDEBUG, "%s:%s hdmi_stream_channels %d hdmi_channel_map %08x", CLASSNAME, __func__, stream_channels, channel_map);
- }
-
- -static uint32_t GetChannelMap(AEAudioFormat &format, bool passthrough)
- +static uint32_t GetChannelMap(const CAEChannelInfo &channelLayout, bool passthrough)
- {
- - unsigned int channels = format.m_channelLayout.Count();
- + unsigned int channels = channelLayout.Count();
- uint32_t channel_map = 0;
- if (passthrough)
- return 0;
- @@ -119,12 +119,12 @@ static uint32_t GetChannelMap(AEAudioFormat &format, bool passthrough)
- // According to CEA-861-D only RL and RR are known. In case of a format having SL and SR channels
- // but no BR BL channels, we use the wide map in order to open only the num of channels really
- // needed.
- - if (format.m_channelLayout.HasChannel(AE_CH_BL) && !format.m_channelLayout.HasChannel(AE_CH_SL))
- + if (channelLayout.HasChannel(AE_CH_BL) && !channelLayout.HasChannel(AE_CH_SL))
- map = map_back;
-
- for (unsigned int i = 0; i < channels; ++i)
- {
- - AEChannel c = format.m_channelLayout[i];
- + AEChannel c = channelLayout[i];
- unsigned int chan = 0;
- if ((unsigned int)c < sizeof map_normal / sizeof *map_normal)
- chan = map[(unsigned int)c];
- @@ -155,9 +155,9 @@ static uint32_t GetChannelMap(AEAudioFormat &format, bool passthrough)
- 0xff, // 7
- 0x13, // 7.1
- };
- - uint8_t cea = format.m_channelLayout.HasChannel(AE_CH_LFE) ? cea_map_lfe[channels] : cea_map[channels];
- + uint8_t cea = channelLayout.HasChannel(AE_CH_LFE) ? cea_map_lfe[channels] : cea_map[channels];
- if (cea == 0xff)
- - CLog::Log(LOGERROR, "%s::%s - Unexpected CEA mapping %d,%d", CLASSNAME, __func__, format.m_channelLayout.HasChannel(AE_CH_LFE), channels);
- + CLog::Log(LOGERROR, "%s::%s - Unexpected CEA mapping %d,%d", CLASSNAME, __func__, channelLayout.HasChannel(AE_CH_LFE), channels);
-
- channel_map |= cea << 24;
-
- @@ -189,7 +189,7 @@ bool CAESinkPi::Initialize(AEAudioFormat &format, std::string &device)
- format.m_frames = format.m_sampleRate * AUDIO_PLAYBUFFER;
- format.m_frameSamples = format.m_frames * channels;
-
- - SetAudioProps(m_passthrough, GetChannelMap(format, m_passthrough));
- + SetAudioProps(m_passthrough, GetChannelMap(format.m_channelLayout, m_passthrough));
-
- m_format = format;
- m_sinkbuffer_sec_per_byte = 1.0 / (double)(m_format.m_frameSize * m_format.m_sampleRate);
- --
- 1.9.3
- From 6ce35e828b39e0a8f2d81cb6fb6162edd53468a8 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Mon, 7 Apr 2014 17:37:41 +0100
- Subject: [PATCH 65/94] [omxplayer] Remove PCMRemap and handle multichannel
- mixing like ActiveAE does
- ---
- tools/buildsteps/rbpi/config-xbmc-makefile | 4 +-
- tools/depends/target/alsa-lib/Makefile | 2 +-
- tools/depends/target/libcec/Makefile | 2 +-
- xbmc/cores/omxplayer/Makefile.in | 1 -
- xbmc/cores/omxplayer/OMXAudio.cpp | 395 +++++++++-----
- xbmc/cores/omxplayer/OMXAudio.h | 9 +-
- xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp | 39 +-
- xbmc/cores/omxplayer/OMXAudioCodecOMX.h | 5 +-
- xbmc/cores/omxplayer/OMXPlayerAudio.cpp | 4 +-
- xbmc/cores/omxplayer/PCMRemap.cpp | 813 -----------------------------
- xbmc/cores/omxplayer/PCMRemap.h | 151 ------
- 11 files changed, 294 insertions(+), 1131 deletions(-)
- delete mode 100644 xbmc/cores/omxplayer/PCMRemap.cpp
- delete mode 100644 xbmc/cores/omxplayer/PCMRemap.h
- diff --git a/tools/buildsteps/rbpi/config-xbmc-makefile b/tools/buildsteps/rbpi/config-xbmc-makefile
- index 761a3b4..18600e2 100644
- --- a/tools/buildsteps/rbpi/config-xbmc-makefile
- +++ b/tools/buildsteps/rbpi/config-xbmc-makefile
- @@ -12,10 +12,10 @@ CONFIGURE = cp -f $(CONFIG_SUB) $(CONFIG_GUESS) build-aux/ ;\
- --disable-gl --enable-gles --enable-airplay \
- --enable-airtunes --enable-libcec --enable-player=omxplayer \
- --disable-sdl --disable-x11 --disable-xrandr --disable-openmax \
- - --disable-optical-drive --disable-dvdcss --disable-joystick \
- + --disable-optical-drive --enable-dvdcss --enable-openmax --disable-joystick \
- --disable-crystalhd --disable-vtbdecoder --disable-vaapi \
- --disable-vdpau --disable-projectm --disable-rsxs --disable-fishbmc \
- - --disable-alsa
- + --enable-alsa
-
- all: $(SOURCE)/libxbmc.so
-
- diff --git a/tools/depends/target/alsa-lib/Makefile b/tools/depends/target/alsa-lib/Makefile
- index b03fc19..a04d933 100644
- --- a/tools/depends/target/alsa-lib/Makefile
- +++ b/tools/depends/target/alsa-lib/Makefile
- @@ -19,7 +19,7 @@ CONFIGURE=cp -f $(CONFIG_SUB) $(CONFIG_GUESS) .; \
- --with-ctl-plugins=ext \
- --with-pcm-plugins="copy,linear,route,mulaw,alaw,adpcm,rate,plug,multi,file,null,empty,share,meter,hooks,lfloat,ladspa,asym,iec958,softvol,extplug,ioplug,mmap_emul" \
- --disable-resmgr --enable-aload --enable-mixer --enable-pcm --disable-rawmidi --enable-hwdep --disable-seq --disable-alisp --disable-old-symbols --disable-python \
- - --with-softfloat=yes --with-libdl=yes --with-pthread=yes --with-librt=no --disable-shared \
- + --with-softfloat=yes --with-libdl=yes --with-pthread=yes --with-librt=no --enable-shared \
-
- LIBDYLIB=$(PLATFORM)/src/.libs/$(LIBNAME).a
-
- diff --git a/tools/depends/target/libcec/Makefile b/tools/depends/target/libcec/Makefile
- index 16fec1b..d18f1c8 100644
- --- a/tools/depends/target/libcec/Makefile
- +++ b/tools/depends/target/libcec/Makefile
- @@ -8,7 +8,7 @@ SOURCE=$(LIBNAME)-$(VERSION)-2
- ARCHIVE=$(SOURCE).tar.gz
-
- # configuration settings
- -CONFIGURE=./configure --prefix=$(PREFIX) --disable-rpi \
- +CONFIGURE=./configure --prefix=$(PREFIX) --enable-rpi \
-
- LIBDYLIB=$(PLATFORM)/src/lib/.libs/libcec.la
-
- diff --git a/xbmc/cores/omxplayer/Makefile.in b/xbmc/cores/omxplayer/Makefile.in
- index 3163282..e5cad70 100644
- --- a/xbmc/cores/omxplayer/Makefile.in
- +++ b/xbmc/cores/omxplayer/Makefile.in
- @@ -7,7 +7,6 @@ SRCS += OMXAudioCodecOMX.cpp
- SRCS += OMXPlayerAudio.cpp
- SRCS += OMXPlayerVideo.cpp
- SRCS += OMXImage.cpp
- -SRCS += PCMRemap.cpp
-
- LIB = omxplayer.a
-
- diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp
- index 72e42ec..d9beb68 100644
- --- a/xbmc/cores/omxplayer/OMXAudio.cpp
- +++ b/xbmc/cores/omxplayer/OMXAudio.cpp
- @@ -29,6 +29,7 @@
- #include "OMXAudio.h"
- #include "Application.h"
- #include "utils/log.h"
- +#include "linux/RBP.h"
-
- #define CLASSNAME "COMXAudio"
-
- @@ -40,6 +41,7 @@
- #include "guilib/LocalizeStrings.h"
- #include "cores/AudioEngine/Utils/AEConvert.h"
- #include "cores/AudioEngine/AEFactory.h"
- +#include "DllSwResample.h"
-
- using namespace std;
-
- @@ -404,28 +406,147 @@ bool COMXAudio::PortSettingsChanged()
- return true;
- }
-
- -static unsigned count_bits(int64_t value)
- +static uint64_t GetAVChannelLayout(CAEChannelInfo &info)
- {
- - unsigned bits = 0;
- - for(;value;++bits)
- - value &= value - 1;
- - return bits;
- + #ifdef DEBUG_VERBOSE
- + CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
- + #endif
- + uint64_t channelLayout = 0;
- + if (info.HasChannel(AE_CH_FL)) channelLayout |= AV_CH_FRONT_LEFT;
- + if (info.HasChannel(AE_CH_FR)) channelLayout |= AV_CH_FRONT_RIGHT;
- + if (info.HasChannel(AE_CH_FC)) channelLayout |= AV_CH_FRONT_CENTER;
- + if (info.HasChannel(AE_CH_LFE)) channelLayout |= AV_CH_LOW_FREQUENCY;
- + if (info.HasChannel(AE_CH_BL)) channelLayout |= AV_CH_BACK_LEFT;
- + if (info.HasChannel(AE_CH_BR)) channelLayout |= AV_CH_BACK_RIGHT;
- + if (info.HasChannel(AE_CH_FLOC)) channelLayout |= AV_CH_FRONT_LEFT_OF_CENTER;
- + if (info.HasChannel(AE_CH_FROC)) channelLayout |= AV_CH_FRONT_RIGHT_OF_CENTER;
- + if (info.HasChannel(AE_CH_BC)) channelLayout |= AV_CH_BACK_CENTER;
- + if (info.HasChannel(AE_CH_SL)) channelLayout |= AV_CH_SIDE_LEFT;
- + if (info.HasChannel(AE_CH_SR)) channelLayout |= AV_CH_SIDE_RIGHT;
- + if (info.HasChannel(AE_CH_TC)) channelLayout |= AV_CH_TOP_CENTER;
- + if (info.HasChannel(AE_CH_TFL)) channelLayout |= AV_CH_TOP_FRONT_LEFT;
- + if (info.HasChannel(AE_CH_TFC)) channelLayout |= AV_CH_TOP_FRONT_CENTER;
- + if (info.HasChannel(AE_CH_TFR)) channelLayout |= AV_CH_TOP_FRONT_RIGHT;
- + if (info.HasChannel(AE_CH_TBL)) channelLayout |= AV_CH_TOP_BACK_LEFT;
- + if (info.HasChannel(AE_CH_TBC)) channelLayout |= AV_CH_TOP_BACK_CENTER;
- + if (info.HasChannel(AE_CH_TBR)) channelLayout |= AV_CH_TOP_BACK_RIGHT;
- +
- + return channelLayout;
- +}
- +
- +static void SetAudioProps(bool stream_channels, uint32_t channel_map)
- +{
- + char command[80], response[80];
- +
- + sprintf(command, "hdmi_stream_channels %d", stream_channels ? 1 : 0);
- + vc_gencmd(response, sizeof response, command);
- +
- + sprintf(command, "hdmi_channel_map 0x%08x", channel_map);
- + vc_gencmd(response, sizeof response, command);
- +
- + CLog::Log(LOGDEBUG, "%s:%s hdmi_stream_channels %d hdmi_channel_map %08x", CLASSNAME, __func__, stream_channels, channel_map);
- +}
- +
- +static uint32_t GetChannelMap(const CAEChannelInfo &channelLayout, bool passthrough)
- +{
- + unsigned int channels = channelLayout.Count();
- + uint32_t channel_map = 0;
- + if (passthrough)
- + return 0;
- +
- + static const unsigned char map_normal[] =
- + {
- + 0, //AE_CH_RAW ,
- + 1, //AE_CH_FL
- + 2, //AE_CH_FR
- + 4, //AE_CH_FC
- + 3, //AE_CH_LFE
- + 7, //AE_CH_BL
- + 8, //AE_CH_BR
- + 1, //AE_CH_FLOC,
- + 2, //AE_CH_FROC,
- + 4, //AE_CH_BC,
- + 5, //AE_CH_SL
- + 6, //AE_CH_SR
- + };
- + static const unsigned char map_back[] =
- + {
- + 0, //AE_CH_RAW ,
- + 1, //AE_CH_FL
- + 2, //AE_CH_FR
- + 4, //AE_CH_FC
- + 3, //AE_CH_LFE
- + 5, //AE_CH_BL
- + 6, //AE_CH_BR
- + 1, //AE_CH_FLOC,
- + 2, //AE_CH_FROC,
- + 4, //AE_CH_BC,
- + 5, //AE_CH_SL
- + 6, //AE_CH_SR
- + };
- + const unsigned char *map = map_normal;
- + // According to CEA-861-D only RL and RR are known. In case of a format having SL and SR channels
- + // but no BR BL channels, we use the wide map in order to open only the num of channels really
- + // needed.
- + if (channelLayout.HasChannel(AE_CH_BL) && !channelLayout.HasChannel(AE_CH_SL))
- + map = map_back;
- +
- + for (unsigned int i = 0; i < channels; ++i)
- + {
- + AEChannel c = channelLayout[i];
- + unsigned int chan = 0;
- + if ((unsigned int)c < sizeof map_normal / sizeof *map_normal)
- + chan = map[(unsigned int)c];
- + if (chan > 0)
- + channel_map |= (chan-1) << (3*i);
- + }
- + // These numbers are from Table 28 Audio InfoFrame Data byte 4 of CEA 861
- + // and describe the speaker layout
- + static const uint8_t cea_map[] = {
- + 0xff, // 0
- + 0xff, // 1
- + 0x00, // 2.0
- + 0x02, // 3.0
- + 0x08, // 4.0
- + 0x0a, // 5.0
- + 0xff, // 6
- + 0x12, // 7.0
- + 0xff, // 8
- + };
- + static const uint8_t cea_map_lfe[] = {
- + 0xff, // 0
- + 0xff, // 1
- + 0xff, // 2
- + 0x01, // 2.1
- + 0x03, // 3.1
- + 0x09, // 4.1
- + 0x0b, // 5.1
- + 0xff, // 7
- + 0x13, // 7.1
- + };
- + uint8_t cea = channelLayout.HasChannel(AE_CH_LFE) ? cea_map_lfe[channels] : cea_map[channels];
- + if (cea == 0xff)
- + CLog::Log(LOGERROR, "%s::%s - Unexpected CEA mapping %d,%d", CLASSNAME, __func__, channelLayout.HasChannel(AE_CH_LFE), channels);
- +
- + channel_map |= cea << 24;
- +
- + return channel_map;
- }
-
- -bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo &hints, uint64_t channelMap, bool bUsePassthrough, bool bUseHWDecode)
- +bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo &hints, CAEChannelInfo channelMap, bool bUsePassthrough, bool bUseHWDecode)
- {
- CSingleLock lock (m_critSection);
- OMX_ERRORTYPE omx_err;
-
- Deinitialize();
-
- - if(!m_dllAvUtil.Load())
- + if (!m_dllAvUtil.Load())
- return false;
-
- m_HWDecode = bUseHWDecode;
- m_Passthrough = bUsePassthrough;
-
- - m_InputChannels = count_bits(channelMap);
- + m_InputChannels = channelMap.Count();
- m_format = format;
-
- if(m_InputChannels == 0)
- @@ -471,26 +592,133 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
-
- if (!m_Passthrough)
- {
- - enum PCMChannels inLayout[OMX_AUDIO_MAXCHANNELS];
- - enum PCMChannels outLayout[OMX_AUDIO_MAXCHANNELS];
- - enum PCMLayout layout = (enum PCMLayout)std::max(0, CSettings::Get().GetInt("audiooutput.channels")-1);
- + bool upmix = CSettings::Get().GetBool("audiooutput.stereoupmix");
- + bool normalize = CSettings::Get().GetBool("audiooutput.normalizelevels");
- + void *remapLayout = NULL;
- +
- + CAEChannelInfo stdLayout = (enum AEStdChLayout)CSettings::Get().GetInt("audiooutput.channels");
- +
- // ignore layout setting for analogue
- if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Analogue")
- - layout = PCM_LAYOUT_2_0;
- + stdLayout = AE_CH_LAYOUT_2_0;
-
- // force out layout to stereo if input is not multichannel - it gives the receiver a chance to upmix
- - if (channelMap == (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT) || channelMap == AV_CH_FRONT_CENTER)
- - layout = PCM_LAYOUT_2_0;
- - BuildChannelMap(inLayout, channelMap);
- - m_OutputChannels = BuildChannelMapCEA(outLayout, GetChannelLayout(layout));
- - CPCMRemap m_remap;
- - m_remap.Reset();
- - /*outLayout = */m_remap.SetInputFormat (m_InputChannels, inLayout, CAEUtil::DataFormatToBits(m_format.m_dataFormat) / 8, m_format.m_sampleRate, layout);
- - m_remap.SetOutputFormat(m_OutputChannels, outLayout);
- - m_remap.GetDownmixMatrix(m_downmix_matrix);
- - m_wave_header.dwChannelMask = channelMap;
- - BuildChannelMapOMX(m_input_channels, channelMap);
- - BuildChannelMapOMX(m_output_channels, GetChannelLayout(layout));
- + if (m_InputChannels <= 2)
- + stdLayout = AE_CH_LAYOUT_2_0;
- +
- + uint64_t m_dst_chan_layout = GetAVChannelLayout(stdLayout);
- + uint64_t m_src_chan_layout = GetAVChannelLayout(channelMap);
- + m_OutputChannels = stdLayout.Count();
- +
- + int m_dst_channels = m_OutputChannels;
- + int m_src_channels = m_InputChannels;
- + SetAudioProps(m_Passthrough, GetChannelMap(stdLayout, m_Passthrough));
- +
- + CLog::Log(LOGINFO, "%s::%s remap:%p chan:%d->%d norm:%d upmix:%d %llx:%llx", CLASSNAME, __func__, remapLayout, m_src_channels, m_dst_channels, normalize, upmix, m_src_chan_layout, m_dst_chan_layout);
- +
- + // this code is just uses ffmpeg to produce the 8x8 mixing matrix
- + // dummy sample rate and format, as we only care about channel mapping
- + DllSwResample m_dllSwResample;
- + if (!m_dllSwResample.Load())
- + return false;
- +
- + SwrContext *m_pContext = m_dllSwResample.swr_alloc_set_opts(NULL, m_dst_chan_layout, AV_SAMPLE_FMT_FLT, 48000,
- + m_src_chan_layout, AV_SAMPLE_FMT_FLT, 48000, 0, NULL);
- + if(!m_pContext)
- + {
- + CLog::Log(LOGERROR, "COMXAudio::Init - create context failed");
- + return false;
- + }
- + // tell resampler to clamp float values
- + // not required for sink stage (remapLayout == true)
- + if (!remapLayout && normalize)
- + {
- + av_opt_set_double(m_pContext, "rematrix_maxval", 1.0, 0);
- + }
- +
- + // stereo upmix
- + if (upmix && m_src_channels == 2 && m_dst_channels > 2)
- + {
- + double m_rematrix[AE_CH_MAX][AE_CH_MAX];
- + memset(m_rematrix, 0, sizeof(m_rematrix));
- + for (int out=0; out<m_dst_channels; out++)
- + {
- + uint64_t out_chan = m_dllAvUtil.av_channel_layout_extract_channel(m_dst_chan_layout, out);
- + switch(out_chan)
- + {
- + case AV_CH_FRONT_LEFT:
- + case AV_CH_BACK_LEFT:
- + case AV_CH_SIDE_LEFT:
- + m_rematrix[out][0] = 1.0;
- + break;
- + case AV_CH_FRONT_RIGHT:
- + case AV_CH_BACK_RIGHT:
- + case AV_CH_SIDE_RIGHT:
- + m_rematrix[out][1] = 1.0;
- + break;
- + case AV_CH_FRONT_CENTER:
- + m_rematrix[out][0] = 0.5;
- + m_rematrix[out][1] = 0.5;
- + break;
- + case AV_CH_LOW_FREQUENCY:
- + m_rematrix[out][0] = 0.5;
- + m_rematrix[out][1] = 0.5;
- + break;
- + default:
- + break;
- + }
- + }
- +
- + if (m_dllSwResample.swr_set_matrix(m_pContext, (const double*)m_rematrix, AE_CH_MAX) < 0)
- + {
- + CLog::Log(LOGERROR, "COMXAudio::Init - setting channel matrix failed");
- + return false;
- + }
- + }
- +
- + if (m_dllSwResample.swr_init(m_pContext) < 0)
- + {
- + CLog::Log(LOGERROR, "COMXAudio::Init - init resampler failed");
- + return false;
- + }
- +
- + const int samples = 8;
- + uint8_t *output, *input;
- + av_samples_alloc(&output, NULL, m_dst_channels, samples, AV_SAMPLE_FMT_FLT, 1);
- + av_samples_alloc(&input , NULL, m_src_channels, samples, AV_SAMPLE_FMT_FLT, 1);
- +
- + // Produce "identity" samples
- + float *f = (float *)input;
- + for (int j=0; j < samples; j++)
- + for (int i=0; i < m_src_channels; i++)
- + *f++ = i == j ? 1.0f : 0.0f;
- +
- + int ret = m_dllSwResample.swr_convert(m_pContext, &output, samples, (const uint8_t **)&input, samples);
- + if (ret < 0)
- + CLog::Log(LOGERROR, "COMXAudio::Resample - resample failed");
- +
- + f = (float *)output;
- + for (int j=0; j < 8; j++)
- + {
- + for (int i=0; i < m_dst_channels; i++)
- + m_downmix_matrix[8*i+j] = *f++;
- + for (int i=m_dst_channels; i < 8; i++)
- + m_downmix_matrix[8*i+j] = 0.0f;
- + }
- +
- + for (int j=0; j < 8; j++)
- + {
- + char s[128] = {}, *t=s;
- + for (int i=0; i < 8; i++)
- + t += sprintf(t, "% 6.2f ", m_downmix_matrix[j*8+i]);
- + CLog::Log(LOGINFO, "%s::%s %s", CLASSNAME, __func__, s);
- + }
- + av_freep(&input);
- + av_freep(&output);
- + m_dllSwResample.swr_free(&m_pContext);
- + m_dllSwResample.Unload();
- +
- + m_wave_header.dwChannelMask = m_src_chan_layout;
- }
-
- m_SampleRate = m_format.m_sampleRate;
- @@ -1605,122 +1833,3 @@ void COMXAudio::CheckOutputBufferSize(void **buffer, int *oldSize, int newSize)
- }
- memset(*buffer, 0x0, *oldSize);
- }
- -
- -void COMXAudio::BuildChannelMap(enum PCMChannels *channelMap, uint64_t layout)
- -{
- - int index = 0;
- - if (layout & AV_CH_FRONT_LEFT ) channelMap[index++] = PCM_FRONT_LEFT ;
- - if (layout & AV_CH_FRONT_RIGHT ) channelMap[index++] = PCM_FRONT_RIGHT ;
- - if (layout & AV_CH_FRONT_CENTER ) channelMap[index++] = PCM_FRONT_CENTER ;
- - if (layout & AV_CH_LOW_FREQUENCY ) channelMap[index++] = PCM_LOW_FREQUENCY ;
- - if (layout & AV_CH_BACK_LEFT ) channelMap[index++] = PCM_BACK_LEFT ;
- - if (layout & AV_CH_BACK_RIGHT ) channelMap[index++] = PCM_BACK_RIGHT ;
- - if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) channelMap[index++] = PCM_FRONT_LEFT_OF_CENTER ;
- - if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) channelMap[index++] = PCM_FRONT_RIGHT_OF_CENTER;
- - if (layout & AV_CH_BACK_CENTER ) channelMap[index++] = PCM_BACK_CENTER ;
- - if (layout & AV_CH_SIDE_LEFT ) channelMap[index++] = PCM_SIDE_LEFT ;
- - if (layout & AV_CH_SIDE_RIGHT ) channelMap[index++] = PCM_SIDE_RIGHT ;
- - if (layout & AV_CH_TOP_CENTER ) channelMap[index++] = PCM_TOP_CENTER ;
- - if (layout & AV_CH_TOP_FRONT_LEFT ) channelMap[index++] = PCM_TOP_FRONT_LEFT ;
- - if (layout & AV_CH_TOP_FRONT_CENTER ) channelMap[index++] = PCM_TOP_FRONT_CENTER ;
- - if (layout & AV_CH_TOP_FRONT_RIGHT ) channelMap[index++] = PCM_TOP_FRONT_RIGHT ;
- - if (layout & AV_CH_TOP_BACK_LEFT ) channelMap[index++] = PCM_TOP_BACK_LEFT ;
- - if (layout & AV_CH_TOP_BACK_CENTER ) channelMap[index++] = PCM_TOP_BACK_CENTER ;
- - if (layout & AV_CH_TOP_BACK_RIGHT ) channelMap[index++] = PCM_TOP_BACK_RIGHT ;
- - while (index<OMX_AUDIO_MAXCHANNELS)
- - channelMap[index++] = PCM_INVALID;
- -}
- -
- -// See CEA spec: Table 20, Audio InfoFrame data byte 4 for the ordering here
- -int COMXAudio::BuildChannelMapCEA(enum PCMChannels *channelMap, uint64_t layout)
- -{
- - int index = 0;
- - if (layout & AV_CH_FRONT_LEFT ) channelMap[index++] = PCM_FRONT_LEFT;
- - if (layout & AV_CH_FRONT_RIGHT ) channelMap[index++] = PCM_FRONT_RIGHT;
- - if (layout & AV_CH_LOW_FREQUENCY ) channelMap[index++] = PCM_LOW_FREQUENCY;
- - if (layout & AV_CH_FRONT_CENTER ) channelMap[index++] = PCM_FRONT_CENTER;
- - if (layout & AV_CH_BACK_LEFT ) channelMap[index++] = PCM_BACK_LEFT;
- - if (layout & AV_CH_BACK_RIGHT ) channelMap[index++] = PCM_BACK_RIGHT;
- - if (layout & AV_CH_SIDE_LEFT ) channelMap[index++] = PCM_SIDE_LEFT;
- - if (layout & AV_CH_SIDE_RIGHT ) channelMap[index++] = PCM_SIDE_RIGHT;
- -
- - while (index<OMX_AUDIO_MAXCHANNELS)
- - channelMap[index++] = PCM_INVALID;
- -
- - int num_channels = 0;
- - for (index=0; index<OMX_AUDIO_MAXCHANNELS; index++)
- - if (channelMap[index] != PCM_INVALID)
- - num_channels = index+1;
- - return num_channels;
- -}
- -
- -void COMXAudio::BuildChannelMapOMX(enum OMX_AUDIO_CHANNELTYPE * channelMap, uint64_t layout)
- -{
- - int index = 0;
- -
- - if (layout & AV_CH_FRONT_LEFT ) channelMap[index++] = OMX_AUDIO_ChannelLF;
- - if (layout & AV_CH_FRONT_RIGHT ) channelMap[index++] = OMX_AUDIO_ChannelRF;
- - if (layout & AV_CH_FRONT_CENTER ) channelMap[index++] = OMX_AUDIO_ChannelCF;
- - if (layout & AV_CH_LOW_FREQUENCY ) channelMap[index++] = OMX_AUDIO_ChannelLFE;
- - if (layout & AV_CH_BACK_LEFT ) channelMap[index++] = OMX_AUDIO_ChannelLR;
- - if (layout & AV_CH_BACK_RIGHT ) channelMap[index++] = OMX_AUDIO_ChannelRR;
- - if (layout & AV_CH_SIDE_LEFT ) channelMap[index++] = OMX_AUDIO_ChannelLS;
- - if (layout & AV_CH_SIDE_RIGHT ) channelMap[index++] = OMX_AUDIO_ChannelRS;
- - if (layout & AV_CH_BACK_CENTER ) channelMap[index++] = OMX_AUDIO_ChannelCS;
- - // following are not in openmax spec, but gpu does accept them
- - if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)10;
- - if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)11;
- - if (layout & AV_CH_TOP_CENTER ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)12;
- - if (layout & AV_CH_TOP_FRONT_LEFT ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)13;
- - if (layout & AV_CH_TOP_FRONT_CENTER ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)14;
- - if (layout & AV_CH_TOP_FRONT_RIGHT ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)15;
- - if (layout & AV_CH_TOP_BACK_LEFT ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)16;
- - if (layout & AV_CH_TOP_BACK_CENTER ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)17;
- - if (layout & AV_CH_TOP_BACK_RIGHT ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)18;
- -
- - while (index<OMX_AUDIO_MAXCHANNELS)
- - channelMap[index++] = OMX_AUDIO_ChannelNone;
- -}
- -
- -uint64_t COMXAudio::GetChannelLayout(enum PCMLayout layout)
- -{
- - uint64_t layouts[] = {
- - /* 2.0 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT,
- - /* 2.1 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_LOW_FREQUENCY,
- - /* 3.0 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER,
- - /* 3.1 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER | 1<<PCM_LOW_FREQUENCY,
- - /* 4.0 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT,
- - /* 4.1 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT | 1<<PCM_LOW_FREQUENCY,
- - /* 5.0 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT,
- - /* 5.1 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT | 1<<PCM_LOW_FREQUENCY,
- - /* 7.0 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER | 1<<PCM_SIDE_LEFT | 1<<PCM_SIDE_RIGHT | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT,
- - /* 7.1 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER | 1<<PCM_SIDE_LEFT | 1<<PCM_SIDE_RIGHT | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT | 1<<PCM_LOW_FREQUENCY
- - };
- - return (int)layout < 10 ? layouts[(int)layout] : 0;
- -}
- -
- -CAEChannelInfo COMXAudio::GetAEChannelLayout(uint64_t layout)
- -{
- - CAEChannelInfo m_channelLayout;
- - m_channelLayout.Reset();
- -
- - if (layout & AV_CH_FRONT_LEFT ) m_channelLayout += AE_CH_FL ;
- - if (layout & AV_CH_FRONT_RIGHT ) m_channelLayout += AE_CH_FR ;
- - if (layout & AV_CH_FRONT_CENTER ) m_channelLayout += AE_CH_FC ;
- - if (layout & AV_CH_LOW_FREQUENCY ) m_channelLayout += AE_CH_LFE ;
- - if (layout & AV_CH_BACK_LEFT ) m_channelLayout += AE_CH_BL ;
- - if (layout & AV_CH_BACK_RIGHT ) m_channelLayout += AE_CH_BR ;
- - if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) m_channelLayout += AE_CH_FLOC;
- - if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) m_channelLayout += AE_CH_FROC;
- - if (layout & AV_CH_BACK_CENTER ) m_channelLayout += AE_CH_BC ;
- - if (layout & AV_CH_SIDE_LEFT ) m_channelLayout += AE_CH_SL ;
- - if (layout & AV_CH_SIDE_RIGHT ) m_channelLayout += AE_CH_SR ;
- - if (layout & AV_CH_TOP_CENTER ) m_channelLayout += AE_CH_TC ;
- - if (layout & AV_CH_TOP_FRONT_LEFT ) m_channelLayout += AE_CH_TFL ;
- - if (layout & AV_CH_TOP_FRONT_CENTER ) m_channelLayout += AE_CH_TFC ;
- - if (layout & AV_CH_TOP_FRONT_RIGHT ) m_channelLayout += AE_CH_TFR ;
- - if (layout & AV_CH_TOP_BACK_LEFT ) m_channelLayout += AE_CH_BL ;
- - if (layout & AV_CH_TOP_BACK_CENTER ) m_channelLayout += AE_CH_BC ;
- - if (layout & AV_CH_TOP_BACK_RIGHT ) m_channelLayout += AE_CH_BR ;
- - return m_channelLayout;
- -}
- diff --git a/xbmc/cores/omxplayer/OMXAudio.h b/xbmc/cores/omxplayer/OMXAudio.h
- index b0264d8..a1c59da 100644
- --- a/xbmc/cores/omxplayer/OMXAudio.h
- +++ b/xbmc/cores/omxplayer/OMXAudio.h
- @@ -38,7 +38,6 @@
- #include "OMXCore.h"
- #include "DllAvCodec.h"
- #include "DllAvUtil.h"
- -#include "PCMRemap.h"
-
- #include "threads/CriticalSection.h"
-
- @@ -61,7 +60,7 @@ class COMXAudio
- float GetCacheTime();
- float GetCacheTotal();
- COMXAudio();
- - bool Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo &hints, uint64_t channelMap, bool bUsePassthrough, bool bUseHWDecode);
- + bool Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo &hints, CAEChannelInfo channelMap, bool bUsePassthrough, bool bUseHWDecode);
- bool PortSettingsChanged();
- ~COMXAudio();
-
- @@ -99,12 +98,6 @@ class COMXAudio
- unsigned int GetAudioRenderingLatency();
- float GetMaxLevel(double &pts);
-
- - void BuildChannelMap(enum PCMChannels *channelMap, uint64_t layout);
- - int BuildChannelMapCEA(enum PCMChannels *channelMap, uint64_t layout);
- - void BuildChannelMapOMX(enum OMX_AUDIO_CHANNELTYPE *channelMap, uint64_t layout);
- - uint64_t GetChannelLayout(enum PCMLayout layout);
- - CAEChannelInfo GetAEChannelLayout(uint64_t layout);
- -
- private:
- IAudioCallback* m_pCallback;
- bool m_Initialized;
- diff --git a/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp b/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp
- index 7f6ef6e..5e47317 100644
- --- a/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp
- +++ b/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp
- @@ -26,7 +26,6 @@
-
- #include "cores/AudioEngine/Utils/AEUtil.h"
- #include "settings/Settings.h"
- -#include "PCMRemap.h"
-
- // the size of the audio_render output port buffers
- #define AUDIO_DECODE_OUTPUT_BUFFER (32*1024)
- @@ -93,12 +92,11 @@ bool COMXAudioCodecOMX::Open(CDVDStreamInfo &hints)
- m_pCodecContext->block_align = hints.blockalign;
- m_pCodecContext->bit_rate = hints.bitrate;
- m_pCodecContext->bits_per_coded_sample = hints.bitspersample;
- - enum PCMLayout layout = (enum PCMLayout)std::max(0, CSettings::Get().GetInt("audiooutput.channels")-1);
- if (hints.codec == AV_CODEC_ID_TRUEHD)
- {
- - if (layout == PCM_LAYOUT_2_0)
- + if (CSettings::Get().GetInt("audiooutput.channels") == AE_CH_LAYOUT_2_0)
- m_pCodecContext->request_channel_layout = AV_CH_LAYOUT_STEREO;
- - else if (layout <= PCM_LAYOUT_5_1)
- + else if (CSettings::Get().GetInt("audiooutput.channels") == AE_CH_LAYOUT_5_1)
- m_pCodecContext->request_channel_layout = AV_CH_LAYOUT_5POINT1;
- }
- if (m_pCodecContext->request_channel_layout)
- @@ -323,7 +321,7 @@ int COMXAudioCodecOMX::GetBitRate()
- return m_pCodecContext->bit_rate;
- }
-
- -static unsigned count_bits(int64_t value)
- +static unsigned count_bits(uint64_t value)
- {
- unsigned bits = 0;
- for(;value;++bits)
- @@ -331,9 +329,10 @@ static unsigned count_bits(int64_t value)
- return bits;
- }
-
- -uint64_t COMXAudioCodecOMX::GetChannelMap()
- +void COMXAudioCodecOMX::BuildChannelMap()
- {
- uint64_t layout;
- +
- int bits = count_bits(m_pCodecContext->channel_layout);
- if (bits == m_pCodecContext->channels)
- layout = m_pCodecContext->channel_layout;
- @@ -342,5 +341,31 @@ uint64_t COMXAudioCodecOMX::GetChannelMap()
- CLog::Log(LOGINFO, "COMXAudioCodecOMX::GetChannelMap - FFmpeg reported %d channels, but the layout contains %d ignoring", m_pCodecContext->channels, bits);
- layout = m_dllAvUtil.av_get_default_channel_layout(m_pCodecContext->channels);
- }
- - return layout;
- +
- + m_channelLayout.Reset();
- +
- + if (layout & AV_CH_FRONT_LEFT ) m_channelLayout += AE_CH_FL ;
- + if (layout & AV_CH_FRONT_RIGHT ) m_channelLayout += AE_CH_FR ;
- + if (layout & AV_CH_FRONT_CENTER ) m_channelLayout += AE_CH_FC ;
- + if (layout & AV_CH_LOW_FREQUENCY ) m_channelLayout += AE_CH_LFE ;
- + if (layout & AV_CH_BACK_LEFT ) m_channelLayout += AE_CH_BL ;
- + if (layout & AV_CH_BACK_RIGHT ) m_channelLayout += AE_CH_BR ;
- + if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) m_channelLayout += AE_CH_FLOC;
- + if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) m_channelLayout += AE_CH_FROC;
- + if (layout & AV_CH_BACK_CENTER ) m_channelLayout += AE_CH_BC ;
- + if (layout & AV_CH_SIDE_LEFT ) m_channelLayout += AE_CH_SL ;
- + if (layout & AV_CH_SIDE_RIGHT ) m_channelLayout += AE_CH_SR ;
- + if (layout & AV_CH_TOP_CENTER ) m_channelLayout += AE_CH_TC ;
- + if (layout & AV_CH_TOP_FRONT_LEFT ) m_channelLayout += AE_CH_TFL ;
- + if (layout & AV_CH_TOP_FRONT_CENTER ) m_channelLayout += AE_CH_TFC ;
- + if (layout & AV_CH_TOP_FRONT_RIGHT ) m_channelLayout += AE_CH_TFR ;
- + if (layout & AV_CH_TOP_BACK_LEFT ) m_channelLayout += AE_CH_BL ;
- + if (layout & AV_CH_TOP_BACK_CENTER ) m_channelLayout += AE_CH_BC ;
- + if (layout & AV_CH_TOP_BACK_RIGHT ) m_channelLayout += AE_CH_BR ;
- +}
- +
- +CAEChannelInfo COMXAudioCodecOMX::GetChannelMap()
- +{
- + BuildChannelMap();
- + return m_channelLayout;
- }
- diff --git a/xbmc/cores/omxplayer/OMXAudioCodecOMX.h b/xbmc/cores/omxplayer/OMXAudioCodecOMX.h
- index 66e5b4a..6e6b226 100644
- --- a/xbmc/cores/omxplayer/OMXAudioCodecOMX.h
- +++ b/xbmc/cores/omxplayer/OMXAudioCodecOMX.h
- @@ -40,7 +40,8 @@ class COMXAudioCodecOMX
- int GetData(BYTE** dst, double &dts, double &pts);
- void Reset();
- int GetChannels();
- - uint64_t GetChannelMap();
- + void BuildChannelMap();
- + CAEChannelInfo GetChannelMap();
- int GetSampleRate();
- int GetBitsPerSample();
- static const char* GetName() { return "FFmpeg"; }
- @@ -62,7 +63,7 @@ class COMXAudioCodecOMX
- bool m_bOpenedCodec;
-
- int m_channels;
- -
- + CAEChannelInfo m_channelLayout;
- bool m_bFirstFrame;
- bool m_bGotFrame;
- bool m_bNoConcatenate;
- diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
- index a4c11777..d3348ec 100644
- --- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
- +++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
- @@ -567,13 +567,13 @@ bool OMXPlayerAudio::OpenDecoder()
- /* GetDataFormat is setting up evrything */
- m_format.m_dataFormat = GetDataFormat(m_hints);
-
- - uint64_t channelMap = 0;
- + CAEChannelInfo channelMap;
- if (m_pAudioCodec && !m_passthrough)
- channelMap = m_pAudioCodec->GetChannelMap();
- else if (m_passthrough)
- // we just want to get the channel count right to stop OMXAudio.cpp rejecting stream
- // the actual layout is not used
- - channelMap = (1<<m_nChannels)-1;
- + channelMap = AE_CH_LAYOUT_5_1;
- bool bAudioRenderOpen = m_omxAudio.Initialize(m_format, m_av_clock, m_hints, channelMap, m_passthrough, m_hw_decode);
-
- m_codec_name = "";
- diff --git a/xbmc/cores/omxplayer/PCMRemap.cpp b/xbmc/cores/omxplayer/PCMRemap.cpp
- deleted file mode 100644
- index f8acfcc..0000000
- --- a/xbmc/cores/omxplayer/PCMRemap.cpp
- +++ /dev/null
- @@ -1,813 +0,0 @@
- -/*
- - * Copyright (C) 2005-2010 Team XBMC
- - * http://xbmc.org
- - *
- - * This Program is free software; you can redistribute it and/or modify
- - * it under the terms of the GNU General Public License as published by
- - * the Free Software Foundation; either version 2, or (at your option)
- - * any later version.
- - *
- - * This Program is distributed in the hope that it will be useful,
- - * but WITHOUT ANY WARRANTY; without even the implied warranty of
- - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- - * GNU General Public License for more details.
- - *
- - * You should have received a copy of the GNU General Public License
- - * along with XBMC; see the file COPYING. If not, write to
- - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- - * http://www.gnu.org/copyleft/gpl.html
- - *
- - */
- -
- -#ifndef __STDC_LIMIT_MACROS
- -#define __STDC_LIMIT_MACROS
- -#endif
- -
- -#include <cstdlib>
- -#include <string.h>
- -#include <stdio.h>
- -#include <math.h>
- -
- -//#include "MathUtils.h"
- -#include "PCMRemap.h"
- -#include "utils/log.h"
- -#include "utils/StringUtils.h"
- -#include "settings/Settings.h"
- -#include "settings/AdvancedSettings.h"
- -#ifdef _WIN32
- -#include "../win32/PlatformDefs.h"
- -#endif
- -
- -static enum PCMChannels PCMLayoutMap[PCM_MAX_LAYOUT][PCM_MAX_CH + 1] =
- -{
- - /* 2.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_INVALID},
- - /* 2.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_LOW_FREQUENCY, PCM_INVALID},
- - /* 3.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_INVALID},
- - /* 3.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_LOW_FREQUENCY, PCM_INVALID},
- - /* 4.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_INVALID},
- - /* 4.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_LOW_FREQUENCY, PCM_INVALID},
- - /* 5.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_INVALID},
- - /* 5.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_LOW_FREQUENCY, PCM_INVALID},
- - /* 7.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_SIDE_LEFT, PCM_SIDE_RIGHT, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_INVALID},
- - /* 7.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_SIDE_LEFT, PCM_SIDE_RIGHT, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_LOW_FREQUENCY, PCM_INVALID}
- -};
- -
- -/*
- - map missing output into channel @ volume level
- - the order of this table is important, mix tables can not depend on channels that have not been defined yet
- - eg, FC can only be mixed into FL, FR as they are the only channels that have been defined
- -*/
- -#define PCM_MAX_MIX 3
- -static struct PCMMapInfo PCMDownmixTable[PCM_MAX_CH][PCM_MAX_MIX] =
- -{
- - /* PCM_FRONT_LEFT */
- - {
- - {PCM_INVALID}
- - },
- - /* PCM_FRONT_RIGHT */
- - {
- - {PCM_INVALID}
- - },
- - /* PCM_FRONT_CENTER */
- - {
- - {PCM_FRONT_LEFT_OF_CENTER , 1.0},
- - {PCM_FRONT_RIGHT_OF_CENTER, 1.0},
- - {PCM_INVALID}
- - },
- - /* PCM_LOW_FREQUENCY */
- - {
- - /*
- - A/52B 7.8 paragraph 2 recomends +10db
- - but due to horrible clipping when normalize
- - is disabled we set this to 1.0
- - */
- - {PCM_FRONT_LEFT , 1.0},//3.5},
- - {PCM_FRONT_RIGHT , 1.0},//3.5},
- - {PCM_INVALID}
- - },
- - /* PCM_BACK_LEFT */
- - {
- - {PCM_FRONT_LEFT , 1.0},
- - {PCM_INVALID}
- - },
- - /* PCM_BACK_RIGHT */
- - {
- - {PCM_FRONT_RIGHT , 1.0},
- - {PCM_INVALID}
- - },
- - /* PCM_FRONT_LEFT_OF_CENTER */
- - {
- - {PCM_FRONT_LEFT , 1.0},
- - {PCM_FRONT_CENTER , 1.0, true},
- - {PCM_INVALID}
- - },
- - /* PCM_FRONT_RIGHT_OF_CENTER */
- - {
- - {PCM_FRONT_RIGHT , 1.0},
- - {PCM_FRONT_CENTER , 1.0, true},
- - {PCM_INVALID}
- - },
- - /* PCM_BACK_CENTER */
- - {
- - {PCM_BACK_LEFT , 1.0},
- - {PCM_BACK_RIGHT , 1.0},
- - {PCM_INVALID}
- - },
- - /* PCM_SIDE_LEFT */
- - {
- - {PCM_FRONT_LEFT , 1.0},
- - {PCM_BACK_LEFT , 1.0},
- - {PCM_INVALID}
- - },
- - /* PCM_SIDE_RIGHT */
- - {
- - {PCM_FRONT_RIGHT , 1.0},
- - {PCM_BACK_RIGHT , 1.0},
- - {PCM_INVALID}
- - },
- - /* PCM_TOP_FRONT_LEFT */
- - {
- - {PCM_FRONT_LEFT , 1.0},
- - {PCM_INVALID}
- - },
- - /* PCM_TOP_FRONT_RIGHT */
- - {
- - {PCM_FRONT_RIGHT , 1.0},
- - {PCM_INVALID}
- - },
- - /* PCM_TOP_FRONT_CENTER */
- - {
- - {PCM_TOP_FRONT_LEFT , 1.0},
- - {PCM_TOP_FRONT_RIGHT , 1.0},
- - {PCM_INVALID}
- - },
- - /* PCM_TOP_CENTER */
- - {
- - {PCM_TOP_FRONT_LEFT , 1.0},
- - {PCM_TOP_FRONT_RIGHT , 1.0},
- - {PCM_INVALID}
- - },
- - /* PCM_TOP_BACK_LEFT */
- - {
- - {PCM_BACK_LEFT , 1.0},
- - {PCM_INVALID}
- - },
- - /* PCM_TOP_BACK_RIGHT */
- - {
- - {PCM_BACK_RIGHT , 1.0},
- - {PCM_INVALID}
- - },
- - /* PCM_TOP_BACK_CENTER */
- - {
- - {PCM_TOP_BACK_LEFT , 1.0},
- - {PCM_TOP_BACK_RIGHT , 1.0},
- - {PCM_INVALID}
- - }
- -};
- -
- -CPCMRemap::CPCMRemap() :
- - m_inSet (false),
- - m_outSet (false),
- - m_inChannels (0),
- - m_outChannels (0),
- - m_inSampleSize(0),
- - m_ignoreLayout(false),
- - m_buf(NULL),
- - m_bufsize(0),
- - m_attenuation (1.0),
- - m_attenuationInc(0.0),
- - m_attenuationMin(1.0),
- - m_sampleRate (48000.0), //safe default
- - m_holdCounter (0),
- - m_limiterEnabled(false)
- -{
- - Dispose();
- -}
- -
- -CPCMRemap::~CPCMRemap()
- -{
- - Dispose();
- -}
- -
- -void CPCMRemap::Dispose()
- -{
- - free(m_buf);
- - m_buf = NULL;
- - m_bufsize = 0;
- -}
- -
- -/* resolves the channels recursively and returns the new index of tablePtr */
- -struct PCMMapInfo* CPCMRemap::ResolveChannel(enum PCMChannels channel, float level, bool ifExists, std::vector<enum PCMChannels> path, struct PCMMapInfo *tablePtr)
- -{
- - if (channel == PCM_INVALID) return tablePtr;
- -
- - /* if its a 1 to 1 mapping, return */
- - if (m_useable[channel])
- - {
- - tablePtr->channel = channel;
- - tablePtr->level = level;
- -
- - ++tablePtr;
- - tablePtr->channel = PCM_INVALID;
- - return tablePtr;
- - } else
- - if (ifExists)
- - level /= 2;
- -
- - struct PCMMapInfo *info;
- - std::vector<enum PCMChannels>::iterator itt;
- -
- - for(info = PCMDownmixTable[channel]; info->channel != PCM_INVALID; ++info)
- - {
- - /* make sure we are not about to recurse into ourself */
- - bool found = false;
- - for(itt = path.begin(); itt != path.end(); ++itt)
- - if (*itt == info->channel)
- - {
- - found = true;
- - break;
- - }
- -
- - if (found)
- - continue;
- -
- - path.push_back(channel);
- - float l = (info->level * (level / 100)) * 100;
- - tablePtr = ResolveChannel(info->channel, l, info->ifExists, path, tablePtr);
- - path.pop_back();
- - }
- -
- - return tablePtr;
- -}
- -
- -/*
- - Builds a lookup table without extra adjustments, useful if we simply
- - want to find out which channels are active.
- - For final adjustments, BuildMap() is used.
- -*/
- -void CPCMRemap::ResolveChannels()
- -{
- - unsigned int in_ch, out_ch;
- - bool hasSide = false;
- - bool hasBack = false;
- -
- - memset(m_useable, 0, sizeof(m_useable));
- -
- - if (!m_outSet)
- - {
- - /* Output format is not known yet, assume the full configured map.
- - * Note that m_ignoreLayout-using callers normally ignore the result of
- - * this function when !m_outSet, when it is called only for an advice for
- - * the caller of SetInputFormat about the best possible output map, and
- - * they can still set their output format arbitrarily in their call to
- - * SetOutputFormat. */
- - for (enum PCMChannels *chan = PCMLayoutMap[m_channelLayout]; *chan != PCM_INVALID; ++chan)
- - m_useable[*chan] = true;
- - }
- - else if (m_ignoreLayout)
- - {
- - for(out_ch = 0; out_ch < m_outChannels; ++out_ch)
- - m_useable[m_outMap[out_ch]] = true;
- - }
- - else
- - {
- - /* figure out what channels we have and can use */
- - for(enum PCMChannels *chan = PCMLayoutMap[m_channelLayout]; *chan != PCM_INVALID; ++chan)
- - {
- - for(out_ch = 0; out_ch < m_outChannels; ++out_ch)
- - if (m_outMap[out_ch] == *chan)
- - {
- - m_useable[*chan] = true;
- - break;
- - }
- - }
- - }
- -
- - /* force mono audio to front left and front right */
- - if (!m_ignoreLayout && m_inChannels == 1 && m_inMap[0] == PCM_FRONT_CENTER
- - && m_useable[PCM_FRONT_LEFT] && m_useable[PCM_FRONT_RIGHT])
- - {
- - CLog::Log(LOGDEBUG, "CPCMRemap: Mapping mono audio to front left and front right");
- - m_useable[PCM_FRONT_CENTER] = false;
- - m_useable[PCM_FRONT_LEFT_OF_CENTER] = false;
- - m_useable[PCM_FRONT_RIGHT_OF_CENTER] = false;
- - }
- -
- - /* see if our input has side/back channels */
- - for(in_ch = 0; in_ch < m_inChannels; ++in_ch)
- - switch(m_inMap[in_ch])
- - {
- - case PCM_SIDE_LEFT:
- - case PCM_SIDE_RIGHT:
- - hasSide = true;
- - break;
- -
- - case PCM_BACK_LEFT:
- - case PCM_BACK_RIGHT:
- - hasBack = true;
- - break;
- -
- - default:;
- - }
- -
- - /* if our input has side, and not back channels, and our output doesnt have side channels */
- - if (hasSide && !hasBack && (!m_useable[PCM_SIDE_LEFT] || !m_useable[PCM_SIDE_RIGHT]))
- - {
- - CLog::Log(LOGDEBUG, "CPCMRemap: Forcing side channel map to back channels");
- - for(in_ch = 0; in_ch < m_inChannels; ++in_ch)
- - if (m_inMap[in_ch] == PCM_SIDE_LEFT ) m_inMap[in_ch] = PCM_BACK_LEFT;
- - else if (m_inMap[in_ch] == PCM_SIDE_RIGHT) m_inMap[in_ch] = PCM_BACK_RIGHT;
- - }
- -
- - /* resolve all the channels */
- - struct PCMMapInfo table[PCM_MAX_CH + 1], *info, *dst;
- - std::vector<enum PCMChannels> path;
- -
- - for (int i = 0; i < PCM_MAX_CH + 1; i++)
- - {
- - for (int j = 0; j < PCM_MAX_CH + 1; j++)
- - m_lookupMap[i][j].channel = PCM_INVALID;
- - }
- -
- - memset(m_counts, 0, sizeof(m_counts));
- - for(in_ch = 0; in_ch < m_inChannels; ++in_ch) {
- -
- - for (int i = 0; i < PCM_MAX_CH + 1; i++)
- - table[i].channel = PCM_INVALID;
- -
- - ResolveChannel(m_inMap[in_ch], 1.0f, false, path, table);
- - for(info = table; info->channel != PCM_INVALID; ++info)
- - {
- - /* find the end of the table */
- - for(dst = m_lookupMap[info->channel]; dst->channel != PCM_INVALID; ++dst);
- -
- - /* append it to the table and set its input offset */
- - dst->channel = m_inMap[in_ch];
- - dst->in_offset = in_ch * 2;
- - dst->level = info->level;
- - m_counts[dst->channel]++;
- - }
- - }
- -}
- -
- -/*
- - builds a lookup table to convert from the input mapping to the output
- - mapping, this decreases the amount of work per sample to remap it.
- -*/
- -void CPCMRemap::BuildMap()
- -{
- - struct PCMMapInfo *dst;
- - unsigned int out_ch;
- -
- - if (!m_inSet || !m_outSet) return;
- -
- - m_inStride = m_inSampleSize * m_inChannels ;
- - m_outStride = m_inSampleSize * m_outChannels;
- -
- - /* see if we need to normalize the levels */
- - bool dontnormalize = !CSettings::Get().GetBool("audiooutput.normalizelevels");
- - CLog::Log(LOGDEBUG, "CPCMRemap: Downmix normalization is %s", (dontnormalize ? "disabled" : "enabled"));
- -
- - ResolveChannels();
- -
- - /* convert the levels into RMS values */
- - float loudest = 0.0;
- - bool hasLoudest = false;
- -
- - for(out_ch = 0; out_ch < m_outChannels; ++out_ch)
- - {
- - float scale = 0;
- - int count = 0;
- - for(dst = m_lookupMap[m_outMap[out_ch]]; dst->channel != PCM_INVALID; ++dst)
- - {
- - dst->copy = false;
- - dst->level = dst->level / sqrt((float)m_counts[dst->channel]);
- - scale += dst->level;
- - ++count;
- - }
- -
- - /* if there is only 1 channel to mix, and the level is 1.0, then just copy the channel */
- - dst = m_lookupMap[m_outMap[out_ch]];
- - if (count == 1 && dst->level > 0.99 && dst->level < 1.01)
- - dst->copy = true;
- -
- - /* normalize the levels if it is turned on */
- - if (!dontnormalize)
- - for(dst = m_lookupMap[m_outMap[out_ch]]; dst->channel != PCM_INVALID; ++dst)
- - {
- - dst->level /= scale;
- - /* find the loudest output level we have that is not 1-1 */
- - if (dst->level < 1.0 && loudest < dst->level)
- - {
- - loudest = dst->level;
- - hasLoudest = true;
- - }
- - }
- - }
- -
- - /* adjust the channels that are too loud */
- - for(out_ch = 0; out_ch < m_outChannels; ++out_ch)
- - {
- - CStdString s = "", f;
- - for(dst = m_lookupMap[m_outMap[out_ch]]; dst->channel != PCM_INVALID; ++dst)
- - {
- - if (hasLoudest && dst->copy)
- - {
- - dst->level = loudest;
- - dst->copy = false;
- - }
- -
- - f = StringUtils::Format("%s(%f%s) ", PCMChannelStr(dst->channel).c_str(), dst->level, dst->copy ? "*" : "");
- - s += f;
- - }
- - CLog::Log(LOGDEBUG, "CPCMRemap: %s = %s\n", PCMChannelStr(m_outMap[out_ch]).c_str(), s.c_str());
- - }
- -}
- -
- -void CPCMRemap::DumpMap(CStdString info, unsigned int channels, enum PCMChannels *channelMap)
- -{
- - if (channelMap == NULL)
- - {
- - CLog::Log(LOGINFO, "CPCMRemap: %s channel map: NULL", info.c_str());
- - return;
- - }
- -
- - CStdString mapping;
- - for(unsigned int i = 0; i < channels; ++i)
- - mapping += ((i == 0) ? "" : ",") + PCMChannelStr(channelMap[i]);
- -
- - CLog::Log(LOGINFO, "CPCMRemap: %s channel map: %s\n", info.c_str(), mapping.c_str());
- -}
- -
- -void CPCMRemap::Reset()
- -{
- - m_inSet = false;
- - m_outSet = false;
- - Dispose();
- -}
- -
- -/* sets the input format, and returns the requested channel layout */
- -enum PCMChannels *CPCMRemap::SetInputFormat(unsigned int channels, enum PCMChannels *channelMap, unsigned int sampleSize, unsigned int sampleRate, PCMLayout layout)
- -{
- - m_inChannels = channels;
- - m_inSampleSize = sampleSize;
- - m_sampleRate = sampleRate;
- - m_inSet = channelMap != NULL;
- - if (channelMap)
- - memcpy(m_inMap, channelMap, sizeof(enum PCMChannels) * channels);
- -
- - /* get the audio layout, and count the channels in it */
- - m_channelLayout = layout;
- - if (m_channelLayout >= PCM_MAX_LAYOUT) m_channelLayout = PCM_LAYOUT_2_0;
- -
- -
- - DumpMap("I", channels, channelMap);
- - BuildMap();
- -
- - /* now remove the empty channels from PCMLayoutMap;
- - * we don't perform upmixing so we want the minimum amount of those */
- - if (channelMap) {
- - if (!m_outSet)
- - ResolveChannels(); /* Do basic channel resolving to find out the empty channels;
- - * If m_outSet == true, this was done already by BuildMap() above */
- - int i = 0;
- - for (enum PCMChannels *chan = PCMLayoutMap[m_channelLayout]; *chan != PCM_INVALID; ++chan)
- - if (m_lookupMap[*chan][0].channel != PCM_INVALID) {
- - /* something is mapped here, so add the channel */
- - m_layoutMap[i++] = *chan;
- - }
- - m_layoutMap[i] = PCM_INVALID;
- - } else
- - memcpy(m_layoutMap, PCMLayoutMap[m_channelLayout], sizeof(PCMLayoutMap[m_channelLayout]));
- -
- - m_attenuation = 1.0;
- - m_attenuationInc = 1.0;
- - m_holdCounter = 0;
- -
- - return m_layoutMap;
- -}
- -
- -/* sets the output format supported by the audio renderer */
- -void CPCMRemap::SetOutputFormat(unsigned int channels, enum PCMChannels *channelMap, bool ignoreLayout/* = false */)
- -{
- - m_outChannels = channels;
- - m_outSet = channelMap != NULL;
- - m_ignoreLayout = ignoreLayout;
- - if (channelMap)
- - memcpy(m_outMap, channelMap, sizeof(enum PCMChannels) * channels);
- -
- - DumpMap("O", channels, channelMap);
- - BuildMap();
- -
- - m_attenuation = 1.0;
- - m_attenuationInc = 1.0;
- - m_holdCounter = 0;
- -}
- -
- -#if 0
- -void CPCMRemap::Remap(void *data, void *out, unsigned int samples, long drc)
- -{
- - float gain = 1.0f;
- - if (drc > 0)
- - gain = pow(10.0f, (float)drc / 2000.0f);
- -
- - Remap(data, out, samples, gain);
- -}
- -
- -/* remap the supplied data into out, which must be pre-allocated */
- -void CPCMRemap::Remap(void *data, void *out, unsigned int samples, float gain /*= 1.0f*/)
- -{
- - CheckBufferSize(samples * m_outChannels * sizeof(float));
- -
- - //set output buffer to 0
- - memset(out, 0, samples * m_outChannels * m_inSampleSize);
- -
- - //set intermediate buffer to 0
- - memset(m_buf, 0, m_bufsize);
- -
- - ProcessInput(data, out, samples, gain);
- - AddGain(m_buf, samples * m_outChannels, gain);
- - ProcessLimiter(samples, gain);
- - ProcessOutput(out, samples, gain);
- -}
- -
- -void CPCMRemap::CheckBufferSize(int size)
- -{
- - if (m_bufsize < size)
- - {
- - m_bufsize = size;
- - m_buf = (float*)realloc(m_buf, m_bufsize);
- - }
- -}
- -
- -void CPCMRemap::ProcessInput(void* data, void* out, unsigned int samples, float gain)
- -{
- - for (unsigned int ch = 0; ch < m_outChannels; ch++)
- - {
- - struct PCMMapInfo *info = m_lookupMap[m_outMap[ch]];
- - if (info->channel == PCM_INVALID)
- - continue;
- -
- - if (info->copy && gain == 1.0f) //do direct copy
- - {
- - uint8_t* src = (uint8_t*)data + info->in_offset;
- - uint8_t* dst = (uint8_t*)out + ch * m_inSampleSize;
- - uint8_t* dstend = dst + samples * m_outStride;
- - while (dst != dstend)
- - {
- - *(int16_t*)dst = *(int16_t*)src;
- - src += m_inStride;
- - dst += m_outStride;
- - }
- - }
- - else //needs some volume change or mixing, put into intermediate buffer
- - {
- - for(; info->channel != PCM_INVALID; info++)
- - {
- - uint8_t* src = (uint8_t*)data + info->in_offset;
- - float* dst = m_buf + ch;
- - float* dstend = dst + samples * m_outChannels;
- - while (dst != dstend)
- - {
- - *dst += (float)(*(int16_t*)src) * info->level;
- - src += m_inStride;
- - dst += m_outChannels;
- - }
- - }
- - }
- - }
- -}
- -
- -void CPCMRemap::AddGain(float* buf, unsigned int samples, float gain)
- -{
- - if (gain != 1.0f) //needs a gain change
- - {
- - float* ptr = m_buf;
- - float* end = m_buf + samples;
- - while (ptr != end)
- - *(ptr++) *= gain;
- - }
- -}
- -
- -void CPCMRemap::ProcessLimiter(unsigned int samples, float gain)
- -{
- - //check total gain for each output channel
- - float highestgain = 1.0f;
- - for (unsigned int ch = 0; ch < m_outChannels; ch++)
- - {
- - struct PCMMapInfo *info = m_lookupMap[m_outMap[ch]];
- - if (info->channel == PCM_INVALID)
- - continue;
- -
- - float chgain = 0.0f;
- - for(; info->channel != PCM_INVALID; info++)
- - chgain += info->level * gain;
- -
- - if (chgain > highestgain)
- - highestgain = chgain;
- - }
- -
- - m_attenuationMin = 1.0f;
- -
- - //if one of the channels can clip, enable a limiter
- - if (highestgain > 1.0001f)
- - {
- - m_attenuationMin = m_attenuation;
- -
- - if (!m_limiterEnabled)
- - {
- - CLog::Log(LOGDEBUG, "CPCMRemap:: max gain: %f, enabling limiter", highestgain);
- - m_limiterEnabled = true;
- - }
- -
- - for (unsigned int i = 0; i < samples; i++)
- - {
- - //for each collection of samples, get the highest absolute value
- - float maxAbs = 0.0f;
- - for (unsigned int outch = 0; outch < m_outChannels; outch++)
- - {
- - float absval = fabs(m_buf[i * m_outChannels + outch]) / 32768.0f;
- - if (maxAbs < absval)
- - maxAbs = absval;
- - }
- -
- - //if attenuatedAbs is higher than 1.0f, audio is clipping
- - float attenuatedAbs = maxAbs * m_attenuation;
- - if (attenuatedAbs > 1.0f)
- - {
- - //set m_attenuation so that m_attenuation * sample is the maximum output value
- - m_attenuation = 1.0f / maxAbs;
- - if (m_attenuation < m_attenuationMin)
- - m_attenuationMin = m_attenuation;
- - //value to add to m_attenuation to make it 1.0f
- - m_attenuationInc = 1.0f - m_attenuation;
- - //amount of samples to hold m_attenuation
- - m_holdCounter = MathUtils::round_int(m_sampleRate * g_advancedSettings.m_limiterHold);
- - }
- - else if (m_attenuation < 1.0f && attenuatedAbs > 0.95f)
- - {
- - //if we're attenuating and we get within 5% of clipping, hold m_attenuation
- - m_attenuationInc = 1.0f - m_attenuation;
- - m_holdCounter = MathUtils::round_int(m_sampleRate * g_advancedSettings.m_limiterHold);
- - }
- -
- - //apply attenuation
- - for (unsigned int outch = 0; outch < m_outChannels; outch++)
- - m_buf[i * m_outChannels + outch] *= m_attenuation;
- -
- - if (m_holdCounter)
- - {
- - //hold m_attenuation
- - m_holdCounter--;
- - }
- - else if (m_attenuationInc > 0.0f)
- - {
- - //move m_attenuation to 1.0 in g_advancedSettings.m_limiterRelease seconds
- - m_attenuation += m_attenuationInc / m_sampleRate / g_advancedSettings.m_limiterRelease;
- - if (m_attenuation > 1.0f)
- - {
- - m_attenuation = 1.0f;
- - m_attenuationInc = 0.0f;
- - }
- - }
- - }
- - }
- - else
- - {
- - if (m_limiterEnabled)
- - {
- - CLog::Log(LOGDEBUG, "CPCMRemap:: max gain: %f, disabling limiter", highestgain);
- - m_limiterEnabled = false;
- - }
- -
- - //reset the limiter
- - m_attenuation = 1.0f;
- - m_attenuationInc = 0.0f;
- - m_holdCounter = 0;
- - }
- -}
- -
- -void CPCMRemap::ProcessOutput(void* out, unsigned int samples, float gain)
- -{
- - //copy from intermediate buffer to output
- - for (unsigned int ch = 0; ch < m_outChannels; ch++)
- - {
- - struct PCMMapInfo *info = m_lookupMap[m_outMap[ch]];
- - if (info->channel == PCM_INVALID)
- - continue;
- -
- - if (!info->copy || gain != 1.0f)
- - {
- - float* src = m_buf + ch;
- - uint8_t* dst = (uint8_t*)out + ch * m_inSampleSize;
- - uint8_t* dstend = dst + samples * m_outStride;
- -
- - while(dst != dstend)
- - {
- - *(int16_t*)dst = MathUtils::round_int(std::min(std::max(*src, (float)INT16_MIN), (float)INT16_MAX));
- - src += m_outChannels;
- - dst += m_outStride;
- - }
- - }
- - }
- -}
- -
- -bool CPCMRemap::CanRemap()
- -{
- - return (m_inSet && m_outSet);
- -}
- -
- -int CPCMRemap::InBytesToFrames(int bytes)
- -{
- - return bytes / m_inSampleSize / m_inChannels;
- -}
- -
- -int CPCMRemap::FramesToOutBytes(int frames)
- -{
- - return frames * m_inSampleSize * m_outChannels;
- -}
- -
- -int CPCMRemap::FramesToInBytes(int frames)
- -{
- - return frames * m_inSampleSize * m_inChannels;
- -}
- -#endif
- -CStdString CPCMRemap::PCMChannelStr(enum PCMChannels ename)
- -{
- - const char* PCMChannelName[] =
- - {
- - "FL",
- - "FR",
- - "CE",
- - "LFE",
- - "BL",
- - "BR",
- - "FLOC",
- - "FROC",
- - "BC",
- - "SL",
- - "SR",
- - "TFL",
- - "TFR",
- - "TFC",
- - "TC",
- - "TBL",
- - "TBR",
- - "TBC"
- - };
- -
- - int namepos = (int)ename;
- - CStdString namestr;
- -
- - if (namepos < 0 || namepos >= (int)(sizeof(PCMChannelName) / sizeof(const char*)))
- - namestr = StringUtils::Format("UNKNOWN CHANNEL:%i", namepos);
- - else
- - namestr = PCMChannelName[namepos];
- -
- - return namestr;
- -}
- -#if 0
- -CStdString CPCMRemap::PCMLayoutStr(enum PCMLayout ename)
- -{
- - const char* PCMLayoutName[] =
- - {
- - "2.0",
- - "2.1",
- - "3.0",
- - "3.1",
- - "4.0",
- - "4.1",
- - "5.0",
- - "5.1",
- - "7.0",
- - "7.1"
- - };
- -
- - int namepos = (int)ename;
- - CStdString namestr;
- -
- - if (namepos < 0 || namepos >= (int)(sizeof(PCMLayoutName) / sizeof(const char*)))
- - namestr.Format("UNKNOWN LAYOUT:%i", namepos);
- - else
- - namestr = PCMLayoutName[namepos];
- -
- - return namestr;
- -}
- -#endif
- -
- -
- -void CPCMRemap::GetDownmixMatrix(float *downmix)
- -{
- - for (int i=0; i<8*8; i++)
- - downmix[i] = 0.0f;
- -
- - for (unsigned int ch = 0; ch < m_outChannels; ch++)
- - {
- - struct PCMMapInfo *info = m_lookupMap[m_outMap[ch]];
- - if (info->channel == PCM_INVALID)
- - continue;
- -
- - for(; info->channel != PCM_INVALID; info++)
- - downmix[8*ch + (info->in_offset>>1)] = info->level;
- - }
- -}
- diff --git a/xbmc/cores/omxplayer/PCMRemap.h b/xbmc/cores/omxplayer/PCMRemap.h
- deleted file mode 100644
- index a273cd1..0000000
- --- a/xbmc/cores/omxplayer/PCMRemap.h
- +++ /dev/null
- @@ -1,151 +0,0 @@
- -#ifndef __PCM_REMAP__H__
- -#define __PCM_REMAP__H__
- -
- -/*
- - * Copyright (C) 2005-2010 Team XBMC
- - * http://xbmc.org
- - *
- - * This Program is free software; you can redistribute it and/or modify
- - * it under the terms of the GNU General Public License as published by
- - * the Free Software Foundation; either version 2, or (at your option)
- - * any later version.
- - *
- - * This Program is distributed in the hope that it will be useful,
- - * but WITHOUT ANY WARRANTY; without even the implied warranty of
- - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- - * GNU General Public License for more details.
- - *
- - * You should have received a copy of the GNU General Public License
- - * along with XBMC; see the file COPYING. If not, write to
- - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- - * http://www.gnu.org/copyleft/gpl.html
- - *
- - */
- -
- -#include <stdint.h>
- -#include <vector>
- -#include "utils/StdString.h"
- -
- -#define PCM_MAX_CH 18
- -enum PCMChannels
- -{
- - PCM_INVALID = -1,
- - PCM_FRONT_LEFT,
- - PCM_FRONT_RIGHT,
- - PCM_FRONT_CENTER,
- - PCM_LOW_FREQUENCY,
- - PCM_BACK_LEFT,
- - PCM_BACK_RIGHT,
- - PCM_FRONT_LEFT_OF_CENTER,
- - PCM_FRONT_RIGHT_OF_CENTER,
- - PCM_BACK_CENTER,
- - PCM_SIDE_LEFT,
- - PCM_SIDE_RIGHT,
- - PCM_TOP_FRONT_LEFT,
- - PCM_TOP_FRONT_RIGHT,
- - PCM_TOP_FRONT_CENTER,
- - PCM_TOP_CENTER,
- - PCM_TOP_BACK_LEFT,
- - PCM_TOP_BACK_RIGHT,
- - PCM_TOP_BACK_CENTER
- -};
- -
- -#define PCM_MAX_LAYOUT 10
- -enum PCMLayout
- -{
- - PCM_LAYOUT_2_0 = 0,
- - PCM_LAYOUT_2_1,
- - PCM_LAYOUT_3_0,
- - PCM_LAYOUT_3_1,
- - PCM_LAYOUT_4_0,
- - PCM_LAYOUT_4_1,
- - PCM_LAYOUT_5_0,
- - PCM_LAYOUT_5_1,
- - PCM_LAYOUT_7_0,
- - PCM_LAYOUT_7_1
- -};
- -
- -struct PCMMapInfo
- -{
- - enum PCMChannels channel;
- - float level;
- - bool ifExists;
- - int in_offset;
- - bool copy;
- -};
- -
- -//! Channels remapper class
- -/*!
- - The usual set-up process:
- - - user calls SetInputFormat with the input channels information
- - - SetInputFormat responds with a channelmap corresponding to the speaker
- - layout that the user has configured, with empty (according to information
- - calculated from the input channelmap) channels removed
- - - user uses this information to create the desired output channelmap,
- - and calls SetOutputFormat to set it (if the channelmap contains channels
- - that do not exist in the configured speaker layout, they will contain
- - only silence unless ignoreLayout is true)
- - */
- -
- -class CPCMRemap
- -{
- -protected:
- - bool m_inSet, m_outSet;
- - enum PCMLayout m_channelLayout;
- - unsigned int m_inChannels, m_outChannels;
- - unsigned int m_inSampleSize;
- - enum PCMChannels m_inMap [PCM_MAX_CH];
- - enum PCMChannels m_outMap[PCM_MAX_CH];
- - enum PCMChannels m_layoutMap[PCM_MAX_CH + 1];
- -
- - bool m_ignoreLayout;
- - bool m_useable [PCM_MAX_CH];
- - int m_inStride, m_outStride;
- - struct PCMMapInfo m_lookupMap[PCM_MAX_CH + 1][PCM_MAX_CH + 1];
- - int m_counts[PCM_MAX_CH];
- -
- - float* m_buf;
- - int m_bufsize;
- - float m_attenuation;
- - float m_attenuationInc;
- - float m_attenuationMin; //lowest attenuation value during a call of Remap(), used for the codec info
- - float m_sampleRate;
- - unsigned int m_holdCounter;
- - bool m_limiterEnabled;
- - bool m_dontnormalize;
- -
- - struct PCMMapInfo* ResolveChannel(enum PCMChannels channel, float level, bool ifExists, std::vector<enum PCMChannels> path, struct PCMMapInfo *tablePtr);
- - void ResolveChannels(); //!< Partial BuildMap(), just enough to see which output channels are active
- - void BuildMap();
- - void DumpMap(CStdString info, int unsigned channels, enum PCMChannels *channelMap);
- - void Dispose();
- - CStdString PCMChannelStr(enum PCMChannels ename);
- - CStdString PCMLayoutStr(enum PCMLayout ename);
- -
- - void CheckBufferSize(int size);
- - void ProcessInput(void* data, void* out, unsigned int samples, float gain);
- - void AddGain(float* buf, unsigned int samples, float gain);
- - void ProcessLimiter(unsigned int samples, float gain);
- - void ProcessOutput(void* out, unsigned int samples, float gain);
- -
- -public:
- -
- - CPCMRemap();
- - ~CPCMRemap();
- -
- - void Reset();
- - enum PCMChannels *SetInputFormat (unsigned int channels, enum PCMChannels *channelMap, unsigned int sampleSize, unsigned int sampleRate, PCMLayout layout);
- - void SetOutputFormat(unsigned int channels, enum PCMChannels *channelMap, bool ignoreLayout = false);
- -#if 0
- - void Remap(void *data, void *out, unsigned int samples, long drc);
- - void Remap(void *data, void *out, unsigned int samples, float gain = 1.0f);
- - bool CanRemap();
- - int InBytesToFrames (int bytes );
- - int FramesToOutBytes(int frames);
- - int FramesToInBytes (int frames);
- -#endif
- - float GetCurrentAttenuation() { return m_attenuationMin; }
- - void GetDownmixMatrix(float *downmix);
- -};
- -
- -#endif
- --
- 1.9.3
- From f642e8eac4fb16039ce662a8a170908efd43ebf8 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Thu, 10 Apr 2014 17:19:18 +0100
- Subject: [PATCH 66/94] [omxplayer] Remove unused framerate functions
- ---
- xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 4 +---
- xbmc/linux/OMXClock.cpp | 35 ---------------------------------
- xbmc/linux/OMXClock.h | 4 ----
- 3 files changed, 1 insertion(+), 42 deletions(-)
- diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- index a5620da..019f4b2 100644
- --- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- +++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- @@ -527,7 +527,7 @@ bool OMXPlayerVideo::OpenDecoder()
- return false;
-
- if (m_hints.fpsrate && m_hints.fpsscale)
- - m_fFrameRate = DVD_TIME_BASE / OMXClock::NormalizeFrameduration((double)DVD_TIME_BASE * m_hints.fpsscale / m_hints.fpsrate);
- + m_fFrameRate = DVD_TIME_BASE / CDVDCodecUtils::NormalizeFrameduration((double)DVD_TIME_BASE * m_hints.fpsscale / m_hints.fpsrate);
- else
- m_fFrameRate = 25;
-
- @@ -564,8 +564,6 @@ bool OMXPlayerVideo::OpenDecoder()
- sprintf(command, "hdmi_ntsc_freqs %d", bNtscFreq);
- CLog::Log(LOGINFO, "OMXPlayerVideo::OpenDecoder fps: %f %s\n", m_fFrameRate, command);
- m_DllBcmHost.vc_gencmd(response, sizeof response, command);
- -
- - m_av_clock->SetRefreshRate(m_fFrameRate);
- }
-
- // start from assuming all recent frames had valid pts
- diff --git a/xbmc/linux/OMXClock.cpp b/xbmc/linux/OMXClock.cpp
- index bee7bac..c631ab6 100644
- --- a/xbmc/linux/OMXClock.cpp
- +++ b/xbmc/linux/OMXClock.cpp
- @@ -39,7 +39,6 @@ OMXClock::OMXClock()
- {
- m_pause = false;
-
- - m_fps = 25.0f;
- m_omx_speed = DVD_PLAYSPEED_NORMAL;
- m_WaitMask = 0;
- m_eState = OMX_TIME_ClockStateStopped;
- @@ -565,38 +564,4 @@ int64_t OMXClock::CurrentHostFrequency(void)
- return( (int64_t)1000000000L );
- }
-
- -int OMXClock::GetRefreshRate(double* interval)
- -{
- - if(!interval)
- - return false;
- -
- - *interval = m_fps;
- - return true;
- -}
- -
- -double OMXClock::NormalizeFrameduration(double frameduration)
- -{
- - //if the duration is within 20 microseconds of a common duration, use that
- - const double durations[] = {DVD_TIME_BASE * 1.001 / 24.0, DVD_TIME_BASE / 24.0, DVD_TIME_BASE / 25.0,
- - DVD_TIME_BASE * 1.001 / 30.0, DVD_TIME_BASE / 30.0, DVD_TIME_BASE / 50.0,
- - DVD_TIME_BASE * 1.001 / 60.0, DVD_TIME_BASE / 60.0};
- -
- - double lowestdiff = DVD_TIME_BASE;
- - int selected = -1;
- - for (size_t i = 0; i < sizeof(durations) / sizeof(durations[0]); i++)
- - {
- - double diff = fabs(frameduration - durations[i]);
- - if (diff < DVD_MSEC_TO_TIME(0.02) && diff < lowestdiff)
- - {
- - selected = i;
- - lowestdiff = diff;
- - }
- - }
- -
- - if (selected != -1)
- - return durations[selected];
- - else
- - return frameduration;
- -}
- -
- #endif
- diff --git a/xbmc/linux/OMXClock.h b/xbmc/linux/OMXClock.h
- index f83074a..7bb6d4d 100644
- --- a/xbmc/linux/OMXClock.h
- +++ b/xbmc/linux/OMXClock.h
- @@ -50,7 +50,6 @@ class OMXClock
- protected:
- bool m_pause;
- pthread_mutex_t m_lock;
- - double m_fps;
- int m_omx_speed;
- OMX_U32 m_WaitMask;
- OMX_TIME_CLOCKSTATE m_eState;
- @@ -91,9 +90,6 @@ class OMXClock
- static int64_t CurrentHostCounter(void);
- static int64_t CurrentHostFrequency(void);
-
- - int GetRefreshRate(double* interval = NULL);
- - void SetRefreshRate(double fps) { m_fps = fps; };
- -
- static double NormalizeFrameduration(double frameduration);
- };
-
- --
- 1.9.3
- From 652d09aff0c0ed4cab08ab7ebbe0da37118c53ba Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Sun, 30 Mar 2014 15:54:34 +0100
- Subject: [PATCH 67/94] [omxplayer] Make the sharpness control act as a
- sharpness control.
- This fixes scaling kernel as Mitchell Netravali, and varies sharpness over range B=[5/3,0] C=[-1/3,1/2]
- ---
- xbmc/cores/omxplayer/OMXPlayer.cpp | 338 +++++++++++++++++++++++++++++++++++++
- 1 file changed, 338 insertions(+)
- diff --git a/xbmc/cores/omxplayer/OMXPlayer.cpp b/xbmc/cores/omxplayer/OMXPlayer.cpp
- index 2515fa1..b09e8e0 100644
- --- a/xbmc/cores/omxplayer/OMXPlayer.cpp
- +++ b/xbmc/cores/omxplayer/OMXPlayer.cpp
- @@ -1051,6 +1051,334 @@ bool COMXPlayer::IsBetterStream(COMXCurrentStream& current, CDemuxStream* stream
- return false;
- }
-
- +static void SetSharpness(float sharpness)
- +{
- + const int16_t mitchells[][32] =
- + {
- + { // B=1.66667 C=-0.33333
- + 0, 3, 8, 15, 24, 35, 49, 55, 70, 92,100,107,109,113,113,114,114,113,113,109,107,100, 92, 70, 55, 49, 35, 24, 15, 8, 3, 0,
- + },
- + { // B=1.64000 C=-0.32000
- + 0, 3, 7, 14, 24, 34, 48, 54, 69, 91,100,107,111,114,116,116,116,116,114,111,107,100, 91, 69, 54, 48, 34, 24, 14, 7, 3, 0,
- + },
- + { // B=1.61333 C=-0.30667
- + 0, 3, 7, 14, 23, 34, 47, 53, 68, 90, 99,107,112,115,118,118,118,118,115,112,107, 99, 90, 68, 53, 47, 34, 23, 14, 7, 3, 0,
- + },
- + { // B=1.58667 C=-0.29333
- + 0, 2, 7, 14, 22, 33, 46, 52, 67, 89, 99,107,113,117,119,121,121,119,117,113,107, 99, 89, 67, 52, 46, 33, 22, 14, 7, 2, 0,
- + },
- + { // B=1.56000 C=-0.28000
- + 0, 2, 7, 13, 22, 32, 45, 51, 66, 88, 98,107,114,119,121,123,123,121,119,114,107, 98, 88, 66, 51, 45, 32, 22, 13, 7, 2, 0,
- + },
- + { // B=1.53333 C=-0.26667
- + 0, 2, 7, 12, 21, 31, 44, 50, 65, 87, 98,108,114,120,123,125,125,123,120,114,108, 98, 87, 65, 50, 44, 31, 21, 12, 7, 2, 0,
- + },
- + { // B=1.50667 C=-0.25333
- + 0, 2, 6, 12, 20, 30, 43, 49, 64, 86, 98,108,116,122,125,127,127,125,122,116,108, 98, 86, 64, 49, 43, 30, 20, 12, 6, 2, 0,
- + },
- + { // B=1.48000 C=-0.24000
- + 0, 2, 6, 12, 19, 29, 42, 47, 63, 85, 98,108,117,123,127,130,130,127,123,117,108, 98, 85, 63, 47, 42, 29, 19, 12, 6, 2, 0,
- + },
- + { // B=1.45333 C=-0.22667
- + 0, 2, 6, 11, 19, 28, 41, 46, 62, 85, 97,108,118,125,129,132,132,129,125,118,108, 97, 85, 62, 46, 41, 28, 19, 11, 6, 2, 0,
- + },
- + { // B=1.42667 C=-0.21333
- + 0, 2, 5, 11, 18, 28, 40, 45, 61, 84, 97,108,119,126,131,134,134,131,126,119,108, 97, 84, 61, 45, 40, 28, 18, 11, 5, 2, 0,
- + },
- + { // B=1.40000 C=-0.20000
- + 0, 2, 5, 10, 18, 27, 39, 44, 60, 84, 96,109,119,127,134,136,136,134,127,119,109, 96, 84, 60, 44, 39, 27, 18, 10, 5, 2, 0,
- + },
- + { // B=1.37333 C=-0.18667
- + 0, 1, 5, 10, 17, 26, 38, 43, 58, 82, 96,109,120,129,135,139,139,135,129,120,109, 96, 82, 58, 43, 38, 26, 17, 10, 5, 1, 0,
- + },
- + { // B=1.34667 C=-0.17333
- + 0, 2, 4, 10, 16, 25, 37, 42, 57, 81, 96,109,121,131,137,141,141,137,131,121,109, 96, 81, 57, 42, 37, 25, 16, 10, 4, 2, 0,
- + },
- + { // B=1.32000 C=-0.16000
- + 0, 1, 4, 9, 15, 24, 36, 41, 56, 81, 95,110,122,132,139,143,143,139,132,122,110, 95, 81, 56, 41, 36, 24, 15, 9, 4, 1, 0,
- + },
- + { // B=1.29333 C=-0.14667
- + 0, 1, 4, 8, 15, 23, 35, 40, 55, 80, 95,110,123,133,141,146,146,141,133,123,110, 95, 80, 55, 40, 35, 23, 15, 8, 4, 1, 0,
- + },
- + { // B=1.26667 C=-0.13333
- + 0, 1, 4, 8, 14, 22, 33, 38, 54, 79, 95,110,124,135,143,148,148,143,135,124,110, 95, 79, 54, 38, 33, 22, 14, 8, 4, 1, 0,
- + },
- + { // B=1.24000 C=-0.12000
- + 0, 1, 4, 7, 14, 21, 33, 37, 53, 78, 94,110,125,136,145,150,150,145,136,125,110, 94, 78, 53, 37, 33, 21, 14, 7, 4, 1, 0,
- + },
- + { // B=1.21333 C=-0.10667
- + 0, 1, 3, 7, 13, 20, 32, 36, 52, 77, 94,110,127,138,147,152,152,147,138,127,110, 94, 77, 52, 36, 32, 20, 13, 7, 3, 1, 0,
- + },
- + { // B=1.18667 C=-0.09333
- + 0, 1, 3, 7, 12, 20, 30, 35, 51, 77, 93,111,125,140,149,155,155,149,140,125,111, 93, 77, 51, 35, 30, 20, 12, 7, 3, 1, 0,
- + },
- + { // B=1.16000 C=-0.08000
- + 0, 1, 3, 6, 11, 19, 29, 34, 50, 76, 93,111,128,141,151,157,157,151,141,128,111, 93, 76, 50, 34, 29, 19, 11, 6, 3, 1, 0,
- + },
- + { // B=1.13333 C=-0.06667
- + 0, 1, 3, 5, 11, 18, 28, 33, 49, 75, 93,111,129,143,153,159,159,153,143,129,111, 93, 75, 49, 33, 28, 18, 11, 5, 3, 1, 0,
- + },
- + { // B=1.10667 C=-0.05333
- + 0, 1, 2, 5, 10, 17, 27, 32, 48, 74, 93,111,130,144,155,161,161,155,144,130,111, 93, 74, 48, 32, 27, 17, 10, 5, 2, 1, 0,
- + },
- + { // B=1.08000 C=-0.04000
- + 0, 1, 2, 5, 9, 16, 26, 31, 46, 73, 92,112,130,145,157,164,164,157,145,130,112, 92, 73, 46, 31, 26, 16, 9, 5, 2, 1, 0,
- + },
- + { // B=1.05333 C=-0.02667
- + 0, 0, 2, 4, 9, 15, 25, 29, 45, 72, 92,112,131,147,159,166,166,159,147,131,112, 92, 72, 45, 29, 25, 15, 9, 4, 2, 0, 0,
- + },
- + { // B=1.02667 C=-0.01333
- + 0, 0, 1, 4, 8, 14, 24, 28, 44, 72, 92,112,132,148,161,168,168,161,148,132,112, 92, 72, 44, 28, 24, 14, 8, 4, 1, 0, 0,
- + },
- + { // B=1.00000 C=0.00000
- + 0, 0, 1, 4, 7, 14, 23, 27, 43, 71, 91,112,133,150,163,170,170,163,150,133,112, 91, 71, 43, 27, 23, 14, 7, 4, 1, 0, 0,
- + },
- + { // B=0.97333 C=0.01333
- + 0, 0, 1, 3, 7, 12, 22, 26, 42, 70, 91,113,133,152,165,173,173,165,152,133,113, 91, 70, 42, 26, 22, 12, 7, 3, 1, 0, 0,
- + },
- + { // B=0.94667 C=0.02667
- + 0, 0, 1, 2, 6, 12, 21, 25, 41, 69, 90,113,135,153,167,175,175,167,153,135,113, 90, 69, 41, 25, 21, 12, 6, 2, 1, 0, 0,
- + },
- + { // B=0.92000 C=0.04000
- + 0, 0, 0, 2, 5, 11, 20, 24, 40, 68, 90,113,136,154,169,177,177,169,154,136,113, 90, 68, 40, 24, 20, 11, 5, 2, 0, 0, 0,
- + },
- + { // B=0.89333 C=0.05333
- + 0, 0, 0, 1, 5, 10, 19, 23, 39, 67, 90,114,136,156,171,179,179,171,156,136,114, 90, 67, 39, 23, 19, 10, 5, 1, 0, 0, 0,
- + },
- + { // B=0.86667 C=0.06667
- + 0, 0, 0, 1, 4, 9, 18, 22, 38, 66, 89,114,137,157,173,182,182,173,157,137,114, 89, 66, 38, 22, 18, 9, 4, 1, 0, 0, 0,
- + },
- + { // B=0.84000 C=0.08000
- + 0, 0, -1, 1, 3, 9, 17, 21, 37, 65, 89,114,138,159,175,184,184,175,159,138,114, 89, 65, 37, 21, 17, 9, 3, 1, -1, 0, 0,
- + },
- + { // B=0.81333 C=0.09333
- + 0, 0, -1, 0, 3, 7, 16, 19, 36, 65, 89,114,139,160,177,186,186,177,160,139,114, 89, 65, 36, 19, 16, 7, 3, 0, -1, 0, 0,
- + },
- + { // B=0.78667 C=0.10667
- + 0, -1, -1, 0, 2, 6, 15, 18, 35, 64, 88,115,139,162,179,188,188,179,162,139,115, 88, 64, 35, 18, 15, 6, 2, 0, -1, -1, 0,
- + },
- + { // B=0.76000 C=0.12000
- + 0, -1, -1, -1, 1, 6, 14, 17, 33, 63, 88,115,141,163,181,191,191,181,163,141,115, 88, 63, 33, 17, 14, 6, 1, -1, -1, -1, 0,
- + },
- + { // B=0.73333 C=0.13333
- + 0, -1, -1, -1, 0, 5, 13, 16, 32, 62, 87,115,142,165,183,193,193,183,165,142,115, 87, 62, 32, 16, 13, 5, 0, -1, -1, -1, 0,
- + },
- + { // B=0.70667 C=0.14667
- + 0, -1, -1, -2, 0, 4, 12, 15, 31, 61, 87,115,143,166,185,195,195,185,166,143,115, 87, 61, 31, 15, 12, 4, 0, -2, -1, -1, 0,
- + },
- + { // B=0.68000 C=0.16000
- + 0, -1, -2, -2, -1, 3, 11, 14, 30, 61, 87,116,142,168,187,197,197,187,168,142,116, 87, 61, 30, 14, 11, 3, -1, -2, -2, -1, 0,
- + },
- + { // B=0.65333 C=0.17333
- + 0, -1, -2, -3, -1, 2, 10, 13, 29, 60, 86,116,144,169,189,200,200,189,169,144,116, 86, 60, 29, 13, 10, 2, -1, -3, -2, -1, 0,
- + },
- + { // B=0.62667 C=0.18667
- + 0, -1, -3, -3, -2, 1, 9, 12, 28, 59, 86,116,145,171,191,202,202,191,171,145,116, 86, 59, 28, 12, 9, 1, -2, -3, -3, -1, 0,
- + },
- + { // B=0.60000 C=0.20000
- + 0, -1, -3, -3, -3, 0, 8, 10, 27, 58, 86,116,146,172,193,204,204,193,172,146,116, 86, 58, 27, 10, 8, 0, -3, -3, -3, -1, 0,
- + },
- + { // B=0.57333 C=0.21333
- + 0, -1, -3, -4, -3, -1, 7, 9, 26, 57, 86,116,147,174,194,207,207,194,174,147,116, 86, 57, 26, 9, 7, -1, -3, -4, -3, -1, 0,
- + },
- + { // B=0.54667 C=0.22667
- + 0, -2, -3, -5, -4, -1, 5, 8, 25, 57, 85,117,148,176,196,209,209,196,176,148,117, 85, 57, 25, 8, 5, -1, -4, -5, -3, -2, 0,
- + },
- + { // B=0.52000 C=0.24000
- + 0, -1, -4, -5, -5, -2, 4, 7, 24, 55, 85,117,149,177,199,211,211,199,177,149,117, 85, 55, 24, 7, 4, -2, -5, -5, -4, -1, 0,
- + },
- + { // B=0.49333 C=0.25333
- + 0, -2, -4, -5, -6, -3, 3, 6, 23, 55, 84,117,150,178,200,214,214,200,178,150,117, 84, 55, 23, 6, 3, -3, -6, -5, -4, -2, 0,
- + },
- + { // B=0.46667 C=0.26667
- + 0, -2, -4, -6, -6, -4, 2, 6, 22, 54, 84,118,150,180,202,216,216,202,180,150,118, 84, 54, 22, 6, 2, -4, -6, -6, -4, -2, 0,
- + },
- + { // B=0.44000 C=0.28000
- + 0, -2, -4, -6, -7, -5, 2, 5, 21, 53, 83,118,150,181,205,218,218,205,181,150,118, 83, 53, 21, 5, 2, -5, -7, -6, -4, -2, 0,
- + },
- + { // B=0.41333 C=0.29333
- + 0, -2, -4, -7, -7, -6, 0, 5, 20, 53, 83,118,152,183,207,220,220,207,183,152,118, 83, 53, 20, 5, 0, -6, -7, -7, -4, -2, 0,
- + },
- + { // B=0.38667 C=0.30667
- + 0, -2, -5, -7, -8, -7, -1, 4, 19, 52, 83,118,153,185,208,223,223,208,185,153,118, 83, 52, 19, 4, -1, -7, -8, -7, -5, -2, 0,
- + },
- + { // B=0.36000 C=0.32000
- + 0, -2, -5, -8, -8, -8, -2, 3, 19, 51, 83,118,155,186,210,225,225,210,186,155,118, 83, 51, 19, 3, -2, -8, -8, -8, -5, -2, 0,
- + },
- + { // B=0.33333 C=0.33333
- + 0, -2, -6, -8,-10, -8, -3, 2, 18, 50, 82,119,155,187,213,227,227,213,187,155,119, 82, 50, 18, 2, -3, -8,-10, -8, -6, -2, 0,
- + },
- + { // B=0.32667 C=0.33667
- + 0, -2, -6, -8,-10, -8, -3, 2, 18, 49, 82,119,155,188,213,228,228,213,188,155,119, 82, 49, 18, 2, -3, -8,-10, -8, -6, -2, 0,
- + },
- + { // B=0.32000 C=0.34000
- + 0, -2, -6, -8,-10, -9, -3, 2, 18, 49, 82,119,155,188,214,228,228,214,188,155,119, 82, 49, 18, 2, -3, -9,-10, -8, -6, -2, 0,
- + },
- + { // B=0.31333 C=0.34333
- + 0, -2, -6, -8,-10, -9, -4, 1, 18, 49, 82,119,155,188,214,229,229,214,188,155,119, 82, 49, 18, 1, -4, -9,-10, -8, -6, -2, 0,
- + },
- + { // B=0.30667 C=0.34667
- + 0, -2, -6, -9,-10, -9, -4, 1, 18, 49, 82,119,156,189,214,229,229,214,189,156,119, 82, 49, 18, 1, -4, -9,-10, -9, -6, -2, 0,
- + },
- + { // B=0.30000 C=0.35000
- + 0, -3, -5, -9,-10,-10, -4, 1, 18, 49, 82,119,156,189,215,230,230,215,189,156,119, 82, 49, 18, 1, -4,-10,-10, -9, -5, -3, 0,
- + },
- + { // B=0.29333 C=0.35333
- + 0, -2, -6, -9,-10,-10, -4, 1, 17, 48, 82,119,156,190,215,231,231,215,190,156,119, 82, 48, 17, 1, -4,-10,-10, -9, -6, -2, 0,
- + },
- + { // B=0.28667 C=0.35667
- + 0, -2, -6, -9,-11,-10, -5, 1, 17, 48, 82,119,157,190,216,231,231,216,190,157,119, 82, 48, 17, 1, -5,-10,-11, -9, -6, -2, 0,
- + },
- + { // B=0.28000 C=0.36000
- + 0, -3, -6, -9,-11,-10, -5, 0, 17, 48, 82,119,157,190,217,231,231,217,190,157,119, 82, 48, 17, 0, -5,-10,-11, -9, -6, -3, 0,
- + },
- + { // B=0.27333 C=0.36333
- + 0, -3, -6, -9,-11,-11, -5, 0, 17, 48, 82,119,157,191,217,232,232,217,191,157,119, 82, 48, 17, 0, -5,-11,-11, -9, -6, -3, 0,
- + },
- + { // B=0.26667 C=0.36667
- + 0, -3, -6, -9,-11,-11, -5, 0, 17, 48, 81,119,157,191,217,233,233,217,191,157,119, 81, 48, 17, 0, -5,-11,-11, -9, -6, -3, 0,
- + },
- + { // B=0.26000 C=0.37000
- + 0, -3, -6,-10,-11,-11, -5, 0, 16, 47, 81,120,156,191,218,233,233,218,191,156,120, 81, 47, 16, 0, -5,-11,-11,-10, -6, -3, 0,
- + },
- + { // B=0.25333 C=0.37333
- + 0, -3, -6, -9,-12,-11, -6, 0, 16, 47, 81,119,158,192,218,234,234,218,192,158,119, 81, 47, 16, 0, -6,-11,-12, -9, -6, -3, 0,
- + },
- + { // B=0.24667 C=0.37667
- + 0, -3, -6,-10,-12,-11, -6, 0, 16, 47, 81,120,157,192,219,234,234,219,192,157,120, 81, 47, 16, 0, -6,-11,-12,-10, -6, -3, 0,
- + },
- + { // B=0.24000 C=0.38000
- + 0, -3, -6,-10,-12,-12, -6, -1, 16, 47, 81,120,158,193,219,235,235,219,193,158,120, 81, 47, 16, -1, -6,-12,-12,-10, -6, -3, 0,
- + },
- + { // B=0.23333 C=0.38333
- + 0, -3, -6,-10,-12,-12, -6, -1, 16, 46, 81,120,158,193,220,236,236,220,193,158,120, 81, 46, 16, -1, -6,-12,-12,-10, -6, -3, 0,
- + },
- + { // B=0.22667 C=0.38667
- + 0, -3, -6,-10,-12,-12, -7, -1, 15, 47, 80,120,158,194,220,236,236,220,194,158,120, 80, 47, 15, -1, -7,-12,-12,-10, -6, -3, 0,
- + },
- + { // B=0.22000 C=0.39000
- + 0, -3, -6,-10,-13,-12, -7, -1, 15, 46, 80,120,159,194,221,237,237,221,194,159,120, 80, 46, 15, -1, -7,-12,-13,-10, -6, -3, 0,
- + },
- + { // B=0.21333 C=0.39333
- + 0, -3, -6,-10,-13,-12, -8, -1, 15, 46, 80,120,159,194,221,237,237,221,194,159,120, 80, 46, 15, -1, -8,-12,-13,-10, -6, -3, 0,
- + },
- + { // B=0.20667 C=0.39667
- + 0, -3, -7,-10,-13,-12, -8, -2, 15, 46, 80,120,159,194,222,238,238,222,194,159,120, 80, 46, 15, -2, -8,-12,-13,-10, -7, -3, 0,
- + },
- + { // B=0.20000 C=0.40000
- + 0, -3, -7,-10,-13,-13, -8, -2, 15, 45, 81,120,159,195,222,238,238,222,195,159,120, 81, 45, 15, -2, -8,-13,-13,-10, -7, -3, 0,
- + },
- + { // B=0.19333 C=0.40333
- + 0, -3, -7,-11,-13,-13, -8, -2, 15, 45, 81,120,160,195,223,239,239,223,195,160,120, 81, 45, 15, -2, -8,-13,-13,-11, -7, -3, 0,
- + },
- + { // B=0.18667 C=0.40667
- + 0, -3, -7,-10,-14,-13, -9, -2, 14, 45, 80,120,160,196,223,240,240,223,196,160,120, 80, 45, 14, -2, -9,-13,-14,-10, -7, -3, 0,
- + },
- + { // B=0.18000 C=0.41000
- + 0, -3, -7,-11,-13,-13, -9, -2, 14, 45, 80,120,160,196,224,240,240,224,196,160,120, 80, 45, 14, -2, -9,-13,-13,-11, -7, -3, 0,
- + },
- + { // B=0.17333 C=0.41333
- + 0, -3, -7,-11,-13,-14, -9, -3, 14, 45, 80,120,160,196,225,240,240,225,196,160,120, 80, 45, 14, -3, -9,-14,-13,-11, -7, -3, 0,
- + },
- + { // B=0.16667 C=0.41667
- + 0, -3, -7,-11,-14,-14, -9, -3, 14, 44, 80,120,161,197,225,241,241,225,197,161,120, 80, 44, 14, -3, -9,-14,-14,-11, -7, -3, 0,
- + },
- + { // B=0.16000 C=0.42000
- + 0, -3, -7,-11,-14,-14,-10, -3, 14, 44, 80,120,161,197,225,242,242,225,197,161,120, 80, 44, 14, -3,-10,-14,-14,-11, -7, -3, 0,
- + },
- + { // B=0.15333 C=0.42333
- + 0, -3, -7,-11,-14,-14,-10, -3, 13, 44, 80,120,161,197,226,242,242,226,197,161,120, 80, 44, 13, -3,-10,-14,-14,-11, -7, -3, 0,
- + },
- + { // B=0.14667 C=0.42667
- + 0, -3, -7,-11,-15,-14,-10, -4, 14, 43, 80,120,163,198,226,243,243,226,198,163,120, 80, 43, 14, -4,-10,-14,-15,-11, -7, -3, 0,
- + },
- + { // B=0.14000 C=0.43000
- + 0, -3, -7,-12,-14,-15,-10, -4, 14, 43, 80,120,163,198,227,243,243,227,198,163,120, 80, 43, 14, -4,-10,-15,-14,-12, -7, -3, 0,
- + },
- + { // B=0.13333 C=0.43333
- + 0, -3, -7,-12,-14,-15,-11, -4, 13, 43, 79,121,161,199,227,244,244,227,199,161,121, 79, 43, 13, -4,-11,-15,-14,-12, -7, -3, 0,
- + },
- + { // B=0.12667 C=0.43667
- + 0, -3, -7,-12,-14,-15,-11, -4, 13, 43, 79,120,163,199,228,245,245,228,199,163,120, 79, 43, 13, -4,-11,-15,-14,-12, -7, -3, 0,
- + },
- + { // B=0.12000 C=0.44000
- + 0, -3, -7,-12,-15,-15,-12, -5, 13, 43, 79,121,162,199,228,245,245,228,199,162,121, 79, 43, 13, -5,-12,-15,-15,-12, -7, -3, 0,
- + },
- + { // B=0.11333 C=0.44333
- + 0, -3, -7,-12,-15,-16,-11, -5, 13, 42, 79,121,162,200,229,246,246,229,200,162,121, 79, 42, 13, -5,-11,-16,-15,-12, -7, -3, 0,
- + },
- + { // B=0.10667 C=0.44667
- + 0, -3, -8,-12,-15,-16,-12, -5, 13, 42, 79,121,162,200,229,246,246,229,200,162,121, 79, 42, 13, -5,-12,-16,-15,-12, -8, -3, 0,
- + },
- + { // B=0.10000 C=0.45000
- + 0, -3, -8,-12,-16,-16,-12, -6, 13, 42, 79,121,163,200,230,247,247,230,200,163,121, 79, 42, 13, -6,-12,-16,-16,-12, -8, -3, 0,
- + },
- + { // B=0.09333 C=0.45333
- + 0, -3, -8,-12,-16,-16,-13, -5, 12, 42, 79,121,163,201,230,248,248,230,201,163,121, 79, 42, 12, -5,-13,-16,-16,-12, -8, -3, 0,
- + },
- + { // B=0.08667 C=0.45667
- + 0, -3, -8,-12,-16,-16,-13, -5, 12, 41, 79,121,163,201,231,248,248,231,201,163,121, 79, 41, 12, -5,-13,-16,-16,-12, -8, -3, 0,
- + },
- + { // B=0.08000 C=0.46000
- + 0, -3, -8,-12,-16,-17,-13, -6, 12, 41, 79,121,163,201,232,248,248,232,201,163,121, 79, 41, 12, -6,-13,-17,-16,-12, -8, -3, 0,
- + },
- + { // B=0.07333 C=0.46333
- + 0, -3, -8,-13,-16,-17,-13, -6, 12, 41, 79,121,164,202,232,249,249,232,202,164,121, 79, 41, 12, -6,-13,-17,-16,-13, -8, -3, 0,
- + },
- + { // B=0.06667 C=0.46667
- + 0, -3, -8,-13,-16,-17,-14, -6, 11, 41, 79,121,164,202,233,249,249,233,202,164,121, 79, 41, 11, -6,-14,-17,-16,-13, -8, -3, 0,
- + },
- + { // B=0.06000 C=0.47000
- + 0, -3, -8,-13,-16,-18,-14, -6, 11, 40, 79,121,164,203,233,250,250,233,203,164,121, 79, 40, 11, -6,-14,-18,-16,-13, -8, -3, 0,
- + },
- + { // B=0.05333 C=0.47333
- + 0, -3, -8,-13,-17,-18,-14, -6, 11, 40, 79,121,165,203,233,251,251,233,203,165,121, 79, 40, 11, -6,-14,-18,-17,-13, -8, -3, 0,
- + },
- + { // B=0.04667 C=0.47667
- + 0, -4, -8,-13,-17,-18,-14, -7, 11, 40, 79,121,166,203,234,251,251,234,203,166,121, 79, 40, 11, -7,-14,-18,-17,-13, -8, -4, 0,
- + },
- + { // B=0.04000 C=0.48000
- + 0, -4, -8,-13,-17,-18,-14, -7, 11, 40, 78,121,166,204,234,251,251,234,204,166,121, 78, 40, 11, -7,-14,-18,-17,-13, -8, -4, 0,
- + },
- + { // B=0.03333 C=0.48333
- + 0, -4, -8,-14,-17,-18,-15, -7, 11, 40, 78,122,164,204,235,252,252,235,204,164,122, 78, 40, 11, -7,-15,-18,-17,-14, -8, -4, 0,
- + },
- + { // B=0.02667 C=0.48667
- + 0, -4, -8,-14,-17,-19,-15, -7, 10, 40, 78,122,164,205,235,253,253,235,205,164,122, 78, 40, 10, -7,-15,-19,-17,-14, -8, -4, 0,
- + },
- + { // B=0.02000 C=0.49000
- + 0, -4, -8,-14,-17,-19,-15, -7, 10, 39, 78,122,164,205,236,253,253,236,205,164,122, 78, 39, 10, -7,-15,-19,-17,-14, -8, -4, 0,
- + },
- + { // B=0.01333 C=0.49333
- + 0, -4, -8,-14,-18,-19,-16, -7, 9, 40, 78,122,165,205,236,254,254,236,205,165,122, 78, 40, 9, -7,-16,-19,-18,-14, -8, -4, 0,
- + },
- + { // B=0.00667 C=0.49667
- + 0, -4, -9,-14,-18,-19,-15, -8, 10, 39, 78,122,166,206,236,254,254,236,206,166,122, 78, 39, 10, -8,-15,-19,-18,-14, -9, -4, 0,
- + },
- + { // B=0.00000 C=0.50000
- + 0, -4, -8,-14,-18,-19,-16, -8, 9, 39, 77,122,166,206,237,255,255,237,206,166,122, 77, 39, 9, -8,-16,-19,-18,-14, -8, -4, 0,
- + },
- + };
- + int index = (sharpness + 1.0f) * 50.0f + 0.5f;
- + if (index >=0 && index <= 100)
- + {
- + const int16_t *coef = mitchells[index];
- +
- + char command[33*12];
- + char response[33*12];
- + unsigned int len = sprintf(command, "scaling_kernel ");
- + for (int i=0; i < 32; i++) {
- + if (len + 12 < sizeof command)
- + len += sprintf(command+len, "%d ", coef[i]);
- + }
- + // no interpolate flag
- + if (len + 12 < sizeof command)
- + len += sprintf(command+len, " %d", 0);
- + //printf("%i: %s\n", index, command);
- + vc_gencmd(response, sizeof response, command);
- + }
- +}
- +
- void COMXPlayer::Process()
- {
- bool bOmxWaitVideo = false;
- @@ -1183,6 +1511,8 @@ void COMXPlayer::Process()
- SetCaching(CACHESTATE_FLUSH);
-
- EDEINTERLACEMODE current_deinterlace = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
- + float current_sharpness = CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness;
- + SetSharpness(current_sharpness);
-
- while (!m_bAbortRequest)
- {
- @@ -1214,6 +1544,13 @@ void COMXPlayer::Process()
- current_deinterlace = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
- }
-
- + // if sharpness setting has changed, we should update it
- + if (current_sharpness != CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness)
- + {
- + current_sharpness = CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness;
- + SetSharpness(current_sharpness);
- + }
- +
- m_video_fifo = (int)(100.0*(m_omxPlayerVideo.GetDecoderBufferSize()-m_omxPlayerVideo.GetDecoderFreeSpace())/m_omxPlayerVideo.GetDecoderBufferSize());
- m_audio_fifo = (int)(100.0*audio_fifo/m_omxPlayerAudio.GetCacheTotal());
-
- @@ -4577,6 +4914,7 @@ void COMXPlayer::GetRenderFeatures(std::vector<int> &renderFeatures)
- renderFeatures.push_back(RENDERFEATURE_CROP);
- renderFeatures.push_back(RENDERFEATURE_PIXEL_RATIO);
- renderFeatures.push_back(RENDERFEATURE_ZOOM);
- + renderFeatures.push_back(RENDERFEATURE_SHARPNESS);
- }
-
- void COMXPlayer::GetDeinterlaceMethods(std::vector<int> &deinterlaceMethods)
- --
- 1.9.3
- From 97a3f2347e45eee8f960a2190891d4bd9de3dda0 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Thu, 10 Apr 2014 17:24:51 +0100
- Subject: [PATCH 68/94] [rpi] Include ntsc frequencies in list of supported
- resolutions
- ---
- xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 8 ------
- xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 35 ++++++++++++++++++++++++-
- xbmc/windowing/egl/WinSystemEGL.cpp | 3 ++-
- 3 files changed, 36 insertions(+), 10 deletions(-)
- diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- index 019f4b2..b8a3871 100644
- --- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- +++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- @@ -556,14 +556,6 @@ bool OMXPlayerVideo::OpenDecoder()
- m_omxVideo.GetDecoderName().c_str() , m_hints.width, m_hints.height, m_hints.profile, m_fFrameRate);
-
- m_codecname = m_omxVideo.GetDecoderName();
- -
- - // if we are closer to ntsc version of framerate, let gpu know
- - int iFrameRate = (int)(m_fFrameRate + 0.5f);
- - bool bNtscFreq = fabs(m_fFrameRate * 1001.0f / 1000.0f - iFrameRate) < fabs(m_fFrameRate - iFrameRate);
- - char response[80], command[80];
- - sprintf(command, "hdmi_ntsc_freqs %d", bNtscFreq);
- - CLog::Log(LOGINFO, "OMXPlayerVideo::OpenDecoder fps: %f %s\n", m_fFrameRate, command);
- - m_DllBcmHost.vc_gencmd(response, sizeof response, command);
- }
-
- // start from assuming all recent frames had valid pts
- diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
- index dc47095..21b8cc4 100644
- --- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
- +++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
- @@ -20,6 +20,7 @@
- #include "system.h"
-
- #include <EGL/egl.h>
- +#include <math.h>
- #include "EGLNativeTypeRaspberryPI.h"
- #include "utils/log.h"
- #include "guilib/gui3d.h"
- @@ -236,6 +237,18 @@ bool CEGLNativeTypeRaspberryPI::SetNativeResolution(const RESOLUTION_INFO &res)
- property.param2 = 0;
- vc_tv_hdmi_set_property(&property);
- }
- +
- + HDMI_PROPERTY_PARAM_T property;
- + property.property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE;
- + // if we are closer to ntsc version of framerate, let gpu know
- + int iFrameRate = (int)(res.fRefreshRate + 0.5f);
- + if (fabsf(res.fRefreshRate * (1001.0f / 1000.0f) - iFrameRate) < fabsf(res.fRefreshRate - iFrameRate))
- + property.param1 = HDMI_PIXEL_CLOCK_TYPE_NTSC;
- + else
- + property.param1 = HDMI_PIXEL_CLOCK_TYPE_PAL;
- + property.param2 = 0;
- + vc_tv_hdmi_set_property(&property);
- +
- int success = m_DllBcmHost->vc_tv_hdmi_power_on_explicit_new(HDMI_MODE_HDMI, GETFLAGS_GROUP(res.dwFlags), GETFLAGS_MODE(res.dwFlags));
-
- if (success == 0)
- @@ -442,7 +455,10 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
- m_desktopRes.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
- m_desktopRes.fPixelRatio *= 0.5;
- }
- - m_desktopRes.fRefreshRate = (float)tv_state.display.hdmi.frame_rate;
- + HDMI_PROPERTY_PARAM_T property;
- + property.property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE;
- + vc_tv_hdmi_get_property(&property);
- + m_desktopRes.fRefreshRate = property.param1 == HDMI_PIXEL_CLOCK_TYPE_NTSC ? tv_state.display.hdmi.frame_rate * (1000.0f/1001.0f) : tv_state.display.hdmi.frame_rate;
- }
- else // sdtv
- {
- @@ -576,6 +592,12 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
- res.iSubtitles = (int)(0.965 * res.iHeight);
-
- AddUniqueResolution(res, resolutions);
- + if (tv->frame_rate == 24 || tv->frame_rate == 30 || tv->frame_rate == 60)
- + {
- + RESOLUTION_INFO res2 = res;
- + res2.fRefreshRate = (float)tv->frame_rate * (1000.0f/1001.0f);
- + AddUniqueResolution(res2, resolutions);
- + }
-
- // Also add 3D versions of modes
- if (tv->struct_3d_mask & HDMI_3D_STRUCT_SIDE_BY_SIDE_HALF_HORIZONTAL)
- @@ -590,6 +612,11 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
- res2.iSubtitles = (int)(0.965 * res2.iHeight);
-
- AddUniqueResolution(res2, resolutions);
- + if (tv->frame_rate == 24 || tv->frame_rate == 30 || tv->frame_rate == 60)
- + {
- + res2.fRefreshRate = (float)tv->frame_rate * (1000.0f/1001.0f);
- + AddUniqueResolution(res2, resolutions);
- + }
- }
- if (tv->struct_3d_mask & HDMI_3D_STRUCT_TOP_AND_BOTTOM)
- {
- @@ -603,6 +630,12 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
- res2.iSubtitles = (int)(0.965 * res2.iHeight);
-
- AddUniqueResolution(res2, resolutions);
- + if (tv->frame_rate == 24 || tv->frame_rate == 30 || tv->frame_rate == 60)
- + {
- + res2.fRefreshRate = (float)tv->frame_rate * (1000.0f/1001.0f);
- + AddUniqueResolution(res2, resolutions);
- + }
- +
- }
- }
- }
- diff --git a/xbmc/windowing/egl/WinSystemEGL.cpp b/xbmc/windowing/egl/WinSystemEGL.cpp
- index 0c32947..258a293 100644
- --- a/xbmc/windowing/egl/WinSystemEGL.cpp
- +++ b/xbmc/windowing/egl/WinSystemEGL.cpp
- @@ -34,6 +34,7 @@
- #include "EGLWrapper.h"
- #include "EGLQuirks.h"
- #include <vector>
- +#include <float.h>
- ////////////////////////////////////////////////////////////////////////////////////////////
- CWinSystemEGL::CWinSystemEGL() : CWinSystemBase()
- {
- @@ -399,7 +400,7 @@ void CWinSystemEGL::UpdateResolutions()
- resDesktop.iScreenWidth == resolutions[i].iScreenWidth &&
- resDesktop.iScreenHeight == resolutions[i].iScreenHeight &&
- (resDesktop.dwFlags & D3DPRESENTFLAG_MODEMASK) == (resolutions[i].dwFlags & D3DPRESENTFLAG_MODEMASK) &&
- - resDesktop.fRefreshRate == resolutions[i].fRefreshRate)
- + fabs(resDesktop.fRefreshRate - resolutions[i].fRefreshRate) < FLT_EPSILON)
- {
- ResDesktop = res_index;
- }
- --
- 1.9.3
- From 6e000e35a42863a9db644692246c43300e4ab948 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Thu, 10 Apr 2014 17:26:20 +0100
- Subject: [PATCH 69/94] [omxplayer] Allow a framerate callback from GPU to
- trigger a hdmi mode change
- ---
- xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 8 +++++---
- xbmc/cores/omxplayer/OMXPlayerVideo.h | 4 ++--
- xbmc/cores/omxplayer/OMXVideo.cpp | 35 +++++++++++++++++----------------
- xbmc/cores/omxplayer/OMXVideo.h | 2 +-
- 4 files changed, 26 insertions(+), 23 deletions(-)
- diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- index b8a3871..e9010b1 100644
- --- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- +++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- @@ -694,7 +694,7 @@ void OMXPlayerVideo::RenderUpdateCallBack(const void *ctx, const CRect &SrcRect,
- player->SetVideoRect(SrcRect, DestRect);
- }
-
- -void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, float display_aspect)
- +void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, float framerate, float display_aspect)
- {
- RESOLUTION res = g_graphicsContext.GetVideoResolution();
- uint32_t video_width = CDisplaySettings::Get().GetResolutionInfo(res).iScreenWidth;
- @@ -743,6 +743,8 @@ void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, f
- else if( display_aspect != 0.0f )
- iDisplayWidth = (int) (iDisplayHeight * display_aspect);
-
- + m_fFrameRate = DVD_TIME_BASE / CDVDCodecUtils::NormalizeFrameduration((double)DVD_TIME_BASE / framerate);
- +
- CLog::Log(LOGDEBUG,"%s - change configuration. video:%dx%d. framerate: %4.2f. %dx%d format: BYPASS",
- __FUNCTION__, video_width, video_height, m_fFrameRate, iDisplayWidth, iDisplayHeight);
-
- @@ -757,9 +759,9 @@ void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, f
- g_renderManager.RegisterRenderUpdateCallBack((const void*)this, RenderUpdateCallBack);
- }
-
- -void OMXPlayerVideo::ResolutionUpdateCallBack(void *ctx, uint32_t width, uint32_t height, float display_aspect)
- +void OMXPlayerVideo::ResolutionUpdateCallBack(void *ctx, uint32_t width, uint32_t height, float framerate, float display_aspect)
- {
- OMXPlayerVideo *player = static_cast<OMXPlayerVideo*>(ctx);
- - player->ResolutionUpdateCallBack(width, height, display_aspect);
- + player->ResolutionUpdateCallBack(width, height, framerate, display_aspect);
- }
-
- diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.h b/xbmc/cores/omxplayer/OMXPlayerVideo.h
- index b49748f..33564dd 100644
- --- a/xbmc/cores/omxplayer/OMXPlayerVideo.h
- +++ b/xbmc/cores/omxplayer/OMXPlayerVideo.h
- @@ -125,7 +125,7 @@ class OMXPlayerVideo : public CThread
- int GetFreeSpace();
- void SetVideoRect(const CRect &SrcRect, const CRect &DestRect);
- static void RenderUpdateCallBack(const void *ctx, const CRect &SrcRect, const CRect &DestRect);
- - void ResolutionUpdateCallBack(uint32_t width, uint32_t height, float pixel_aspect);
- - static void ResolutionUpdateCallBack(void *ctx, uint32_t width, uint32_t height, float pixel_aspect);
- + void ResolutionUpdateCallBack(uint32_t width, uint32_t height, float framerate, float pixel_aspect);
- + static void ResolutionUpdateCallBack(void *ctx, uint32_t width, uint32_t height, float framerate, float pixel_aspect);
- };
- #endif
- diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp
- index 66a351d..10a7530 100644
- --- a/xbmc/cores/omxplayer/OMXVideo.cpp
- +++ b/xbmc/cores/omxplayer/OMXVideo.cpp
- @@ -171,6 +171,22 @@ bool COMXVideo::PortSettingsChanged()
- CLog::Log(LOGERROR, "%s::%s - error m_omx_decoder.GetParameter(OMX_IndexParamBrcmPixelAspectRatio) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
- }
-
- + OMX_CONFIG_INTERLACETYPE interlace;
- + OMX_INIT_STRUCTURE(interlace);
- + interlace.nPortIndex = m_omx_decoder.GetOutputPort();
- + omx_err = m_omx_decoder.GetConfig(OMX_IndexConfigCommonInterlace, &interlace);
- +
- + if(m_deinterlace_request == VS_DEINTERLACEMODE_FORCE)
- + m_deinterlace = true;
- + else if(m_deinterlace_request == VS_DEINTERLACEMODE_OFF)
- + m_deinterlace = false;
- + else
- + m_deinterlace = interlace.eMode != OMX_InterlaceProgressive;
- +
- + CLog::Log(LOGDEBUG, "%s::%s - %dx%d@%.2f interlace:%d deinterlace:%d", CLASSNAME, __func__,
- + port_image.format.video.nFrameWidth, port_image.format.video.nFrameHeight,
- + port_image.format.video.xFramerate / (float)(1<<16), interlace.eMode, m_deinterlace);
- +
- // let OMXPlayerVideo know about resolution so it can inform RenderManager
- if (m_res_callback)
- {
- @@ -178,7 +194,8 @@ bool COMXVideo::PortSettingsChanged()
- if (pixel_aspect.nX && pixel_aspect.nY)
- display_aspect = (float)pixel_aspect.nX * port_image.format.video.nFrameWidth /
- ((float)pixel_aspect.nY * port_image.format.video.nFrameHeight);
- - m_res_callback(m_res_ctx, port_image.format.video.nFrameWidth, port_image.format.video.nFrameHeight, display_aspect);
- + m_res_callback(m_res_ctx, port_image.format.video.nFrameWidth, port_image.format.video.nFrameHeight,
- + port_image.format.video.xFramerate / (float)(1<<16), display_aspect);
- }
-
- if (m_settings_changed)
- @@ -187,27 +204,11 @@ bool COMXVideo::PortSettingsChanged()
- return true;
- }
-
- - OMX_CONFIG_INTERLACETYPE interlace;
- - OMX_INIT_STRUCTURE(interlace);
- - interlace.nPortIndex = m_omx_decoder.GetOutputPort();
- - omx_err = m_omx_decoder.GetConfig(OMX_IndexConfigCommonInterlace, &interlace);
- -
- - if(m_deinterlace_request == VS_DEINTERLACEMODE_FORCE)
- - m_deinterlace = true;
- - else if(m_deinterlace_request == VS_DEINTERLACEMODE_OFF)
- - m_deinterlace = false;
- - else
- - m_deinterlace = interlace.eMode != OMX_InterlaceProgressive;
- -
- if(!m_omx_render.Initialize("OMX.broadcom.video_render", OMX_IndexParamVideoInit))
- return false;
-
- m_omx_render.ResetEos();
-
- - CLog::Log(LOGDEBUG, "%s::%s - %dx%d@%.2f interlace:%d deinterlace:%d", CLASSNAME, __func__,
- - port_image.format.video.nFrameWidth, port_image.format.video.nFrameHeight,
- - port_image.format.video.xFramerate / (float)(1<<16), interlace.eMode, m_deinterlace);
- -
- if(!m_omx_sched.Initialize("OMX.broadcom.video_scheduler", OMX_IndexParamVideoInit))
- return false;
-
- diff --git a/xbmc/cores/omxplayer/OMXVideo.h b/xbmc/cores/omxplayer/OMXVideo.h
- index d69f854..fd23e70 100644
- --- a/xbmc/cores/omxplayer/OMXVideo.h
- +++ b/xbmc/cores/omxplayer/OMXVideo.h
- @@ -38,7 +38,7 @@
-
- #define CLASSNAME "COMXVideo"
-
- -typedef void (*ResolutionUpdateCallBackFn)(void *ctx, uint32_t width, uint32_t height, float display_aspect);
- +typedef void (*ResolutionUpdateCallBackFn)(void *ctx, uint32_t width, uint32_t height, float framerate, float display_aspect);
-
- class COMXVideo
- {
- --
- 1.9.3
- From 7d8653f297a2aeea7b10bf36732892878ae89334 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Fri, 11 Apr 2014 19:01:26 +0100
- Subject: [PATCH 70/94] [omxplayer] Request to be notified about framerate
- changes
- ---
- xbmc/cores/omxplayer/OMXVideo.cpp | 14 ++++++++++++--
- 1 file changed, 12 insertions(+), 2 deletions(-)
- diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp
- index 10a7530..148b16f 100644
- --- a/xbmc/cores/omxplayer/OMXVideo.cpp
- +++ b/xbmc/cores/omxplayer/OMXVideo.cpp
- @@ -183,7 +183,7 @@ bool COMXVideo::PortSettingsChanged()
- else
- m_deinterlace = interlace.eMode != OMX_InterlaceProgressive;
-
- - CLog::Log(LOGDEBUG, "%s::%s - %dx%d@%.2f interlace:%d deinterlace:%d", CLASSNAME, __func__,
- + CLog::Log(LOGDEBUG, "%s::%s - %dx%d@%.2f interlace:%d deinterlace:%d", CLASSNAME, __func__,
- port_image.format.video.nFrameWidth, port_image.format.video.nFrameHeight,
- port_image.format.video.xFramerate / (float)(1<<16), interlace.eMode, m_deinterlace);
-
- @@ -558,7 +558,17 @@ bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, EDEINTERLACEMODE de
- CLog::Log(LOGERROR, "COMXVideo::Open OMX_IndexConfigRequestCallback error (0%08x)\n", omx_err);
- return false;
- }
- -
- + // request portsettingschanged on refresh rate change
- + if (CSettings::Get().GetInt("videoplayer.adjustrefreshrate") == ADJUST_REFRESHRATE_ALWAYS)
- + {
- + notifications.nIndex = OMX_IndexParamPortDefinition;
- + omx_err = m_omx_decoder.SetParameter((OMX_INDEXTYPE)OMX_IndexConfigRequestCallback, ¬ifications);
- + if (omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "COMXVideo::Open OMX_IndexConfigRequestCallback error (0%08x)\n", omx_err);
- + //return false;
- + }
- + }
- OMX_PARAM_BRCMVIDEODECODEERRORCONCEALMENTTYPE concanParam;
- OMX_INIT_STRUCTURE(concanParam);
- if(g_advancedSettings.m_omxDecodeStartWithValidFrame)
- --
- 1.9.3
- From 12a54cc9ca0c0500f1d86173df0c8466270bd766 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Mon, 14 Apr 2014 17:04:57 +0100
- Subject: [PATCH 71/94] [omxplayer] Support stereo view modes with scaling
- The Pi only supported a single view rectangle, which is sufficient for all mono view modes,
- but only supports a subset of stereo modes.
- To work around this, the scaling rectangles were ignored in 3D modes and 3D video was treated as unscaled.
- While this worked or square pixel, 16:9 content on a 16:9 display, it went wrong is various other conditions.
- @sraue reported that mono view of SBS/TAB content wasn't scaled correctly, and other forum reports
- aspect ratio errors in widescreen 3D videos.
- As it wasn't trivial to work around these bug reports, I've added a new stereo flags to the firmware
- that allows a second display region to be created for the second eye, allowing scaling to work.
- I've been through the video stereo modes (none, sbs, tab) and the display stereo modes (mono, sbs, tab)
- and all the zoom modes, and compared the scaling to xbmc on windows and all seem to match
- Requires udpated firmware.
- ---
- xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 103 +++++++++++++++++++++-----------
- xbmc/cores/omxplayer/OMXPlayerVideo.h | 4 +-
- xbmc/cores/omxplayer/OMXVideo.cpp | 45 ++++++++------
- xbmc/cores/omxplayer/OMXVideo.h | 3 +-
- 4 files changed, 100 insertions(+), 55 deletions(-)
- diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- index e9010b1..d5f3bec 100644
- --- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- +++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- @@ -97,6 +97,9 @@ OMXPlayerVideo::OMXPlayerVideo(OMXClock *av_clock,
-
- m_src_rect.SetRect(0, 0, 0, 0);
- m_dst_rect.SetRect(0, 0, 0, 0);
- + m_video_stereo_mode = RENDER_STEREO_MODE_OFF;
- + m_display_stereo_mode = RENDER_STEREO_MODE_OFF;
- + m_StereoInvert = false;
- m_started = false;
- m_iCurrentPts = DVD_NOPTS_VALUE;
- m_nextOverlay = DVD_NOPTS_VALUE;
- @@ -120,6 +123,9 @@ bool OMXPlayerVideo::OpenStream(CDVDStreamInfo &hints)
- // force SetVideoRect to be called initially
- m_src_rect.SetRect(0, 0, 0, 0);
- m_dst_rect.SetRect(0, 0, 0, 0);
- + m_video_stereo_mode = RENDER_STEREO_MODE_OFF;
- + m_display_stereo_mode = RENDER_STEREO_MODE_OFF;
- + m_StereoInvert = false;
-
- if (!m_DllBcmHost.Load())
- return false;
- @@ -634,58 +640,85 @@ int OMXPlayerVideo::GetFreeSpace()
-
- void OMXPlayerVideo::SetVideoRect(const CRect &InSrcRect, const CRect &InDestRect)
- {
- - CRect SrcRect = InSrcRect, DestRect = InDestRect;
- + // we get called twice a frame for left/right. Can ignore the rights.
- + if (g_graphicsContext.GetStereoView() == RENDER_STEREO_VIEW_RIGHT)
- + return;
-
- - // in 3d modes skip this - we get called as the gui switches from left eye to right eye
- + CRect SrcRect = InSrcRect, DestRect = InDestRect;
- unsigned flags = GetStereoModeFlags(GetStereoMode());
- -
- - if (CONF_FLAGS_STEREO_MODE_MASK(flags))
- - {
- - if (g_graphicsContext.GetStereoMode() == RENDER_STEREO_MODE_MONO)
- - {
- - if (GetStereoMode() == "left_right")
- - SrcRect.SetRect(0, 0, m_hints.width>>1, m_hints.height);
- - else if (GetStereoMode() == "right_left")
- - SrcRect.SetRect(m_hints.width>>1, 0, m_hints.width, m_hints.height);
- - else if (GetStereoMode() == "top_bottom")
- - SrcRect.SetRect(0, 0, m_hints.width, m_hints.height>>1);
- - else if (GetStereoMode() == "bottom_top")
- - SrcRect.SetRect(0, m_hints.height>>1, m_hints.width, m_hints.height);
- - }
- - else
- - SrcRect.SetRect(0, 0, m_hints.width, m_hints.height);
- - // interpreted as fullscreen
- - DestRect.SetRect(0, 0, 0, 0);
- - }
- + RENDER_STEREO_MODE video_stereo_mode = (flags & CONF_FLAGS_STEREO_MODE_SBS) ? RENDER_STEREO_MODE_SPLIT_VERTICAL :
- + (flags & CONF_FLAGS_STEREO_MODE_TAB) ? RENDER_STEREO_MODE_SPLIT_HORIZONTAL : RENDER_STEREO_MODE_OFF;
- + bool stereo_invert = (flags & CONF_FLAGS_STEREO_CADANCE_RIGHT_LEFT) ? true : false;
- + RENDER_STEREO_MODE display_stereo_mode = g_graphicsContext.GetStereoMode();
-
- // check if destination rect or video view mode has changed
- - if (m_dst_rect != DestRect || m_src_rect != SrcRect)
- - {
- - m_src_rect = SrcRect;
- - m_dst_rect = DestRect;
- - }
- - else
- - {
- + if (!(m_dst_rect != DestRect) && !(m_src_rect != SrcRect) && m_video_stereo_mode == video_stereo_mode && m_display_stereo_mode == display_stereo_mode && m_StereoInvert == stereo_invert)
- return;
- - }
- +
- + CLog::Log(LOGDEBUG, "OMXPlayerVideo::%s %d,%d,%d,%d -> %d,%d,%d,%d (%d,%d,%d,%d,%s)", __func__,
- + (int)SrcRect.x1, (int)SrcRect.y1, (int)SrcRect.x2, (int)SrcRect.y2,
- + (int)DestRect.x1, (int)DestRect.y1, (int)DestRect.x2, (int)DestRect.y2,
- + video_stereo_mode, display_stereo_mode, CMediaSettings::Get().GetCurrentVideoSettings().m_StereoInvert, g_graphicsContext.GetStereoView(), OMXPlayerVideo::GetStereoMode().c_str());
- +
- + m_src_rect = SrcRect;
- + m_dst_rect = DestRect;
- + m_video_stereo_mode = video_stereo_mode;
- + m_display_stereo_mode = display_stereo_mode;
- + m_StereoInvert = stereo_invert;
-
- // might need to scale up m_dst_rect to display size as video decodes
- // to separate video plane that is at display size.
- RESOLUTION res = g_graphicsContext.GetVideoResolution();
- CRect gui(0, 0, CDisplaySettings::Get().GetResolutionInfo(res).iWidth, CDisplaySettings::Get().GetResolutionInfo(res).iHeight);
- CRect display(0, 0, CDisplaySettings::Get().GetResolutionInfo(res).iScreenWidth, CDisplaySettings::Get().GetResolutionInfo(res).iScreenHeight);
- - CRect dst_rect(m_dst_rect);
- +
- + switch (video_stereo_mode)
- + {
- + case RENDER_STEREO_MODE_SPLIT_VERTICAL:
- + // optimisation - use simpler display mode in common case of unscaled 3d with same display mode
- + if (video_stereo_mode == display_stereo_mode && DestRect.x1 == 0.0f && DestRect.x2 * 2.0f == gui.Width() && !stereo_invert)
- + {
- + SrcRect.x2 *= 2.0f;
- + DestRect.x2 *= 2.0f;
- + video_stereo_mode = RENDER_STEREO_MODE_OFF;
- + display_stereo_mode = RENDER_STEREO_MODE_OFF;
- + }
- + else if (stereo_invert)
- + {
- + SrcRect.x1 += m_hints.width / 2;
- + SrcRect.x2 += m_hints.width / 2;
- + }
- + break;
- +
- + case RENDER_STEREO_MODE_SPLIT_HORIZONTAL:
- + // optimisation - use simpler display mode in common case of unscaled 3d with same display mode
- + if (video_stereo_mode == display_stereo_mode && DestRect.y1 == 0.0f && DestRect.y2 * 2.0f == gui.Height() && !stereo_invert)
- + {
- + SrcRect.y2 *= 2.0f;
- + DestRect.y2 *= 2.0f;
- + video_stereo_mode = RENDER_STEREO_MODE_OFF;
- + display_stereo_mode = RENDER_STEREO_MODE_OFF;
- + }
- + else if (stereo_invert)
- + {
- + SrcRect.y1 += m_hints.height / 2;
- + SrcRect.y2 += m_hints.height / 2;
- + }
- + break;
- +
- + default: break;
- + }
-
- if (gui != display)
- {
- float xscale = display.Width() / gui.Width();
- float yscale = display.Height() / gui.Height();
- - dst_rect.x1 *= xscale;
- - dst_rect.x2 *= xscale;
- - dst_rect.y1 *= yscale;
- - dst_rect.y2 *= yscale;
- + DestRect.x1 *= xscale;
- + DestRect.x2 *= xscale;
- + DestRect.y1 *= yscale;
- + DestRect.y2 *= yscale;
- }
- - m_omxVideo.SetVideoRect(SrcRect, dst_rect);
- + m_omxVideo.SetVideoRect(SrcRect, DestRect, video_stereo_mode, display_stereo_mode);
- }
-
- void OMXPlayerVideo::RenderUpdateCallBack(const void *ctx, const CRect &SrcRect, const CRect &DestRect)
- diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.h b/xbmc/cores/omxplayer/OMXPlayerVideo.h
- index 33564dd..6f19395 100644
- --- a/xbmc/cores/omxplayer/OMXPlayerVideo.h
- +++ b/xbmc/cores/omxplayer/OMXPlayerVideo.h
- @@ -69,7 +69,9 @@ class OMXPlayerVideo : public CThread
-
- CRect m_src_rect;
- CRect m_dst_rect;
- -
- + RENDER_STEREO_MODE m_video_stereo_mode;
- + RENDER_STEREO_MODE m_display_stereo_mode;
- + bool m_StereoInvert;
- uint32_t m_history_valid_pts;
- DllBcmHost m_DllBcmHost;
-
- diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp
- index 148b16f..dceb8bf 100644
- --- a/xbmc/cores/omxplayer/OMXVideo.cpp
- +++ b/xbmc/cores/omxplayer/OMXVideo.cpp
- @@ -836,7 +836,7 @@ void COMXVideo::Reset(void)
- }
-
- ///////////////////////////////////////////////////////////////////////////////////////////
- -void COMXVideo::SetVideoRect(const CRect& SrcRect, const CRect& DestRect)
- +void COMXVideo::SetVideoRect(const CRect& SrcRect, const CRect& DestRect, RENDER_STEREO_MODE video_mode, RENDER_STEREO_MODE display_mode)
- {
- CSingleLock lock (m_critSection);
- if(!m_is_open)
- @@ -846,27 +846,36 @@ void COMXVideo::SetVideoRect(const CRect& SrcRect, const CRect& DestRect)
-
- OMX_INIT_STRUCTURE(configDisplay);
- configDisplay.nPortIndex = m_omx_render.GetInputPort();
- - configDisplay.set = (OMX_DISPLAYSETTYPE)(OMX_DISPLAY_SET_DEST_RECT|OMX_DISPLAY_SET_SRC_RECT|OMX_DISPLAY_SET_FULLSCREEN|OMX_DISPLAY_SET_NOASPECT);
- - configDisplay.dest_rect.x_offset = (int)(DestRect.x1+0.5f);
- - configDisplay.dest_rect.y_offset = (int)(DestRect.y1+0.5f);
- - configDisplay.dest_rect.width = (int)(DestRect.Width()+0.5f);
- - configDisplay.dest_rect.height = (int)(DestRect.Height()+0.5f);
- -
- - configDisplay.src_rect.x_offset = (int)(SrcRect.x1+0.5f);
- - configDisplay.src_rect.y_offset = (int)(SrcRect.y1+0.5f);
- - configDisplay.src_rect.width = (int)(SrcRect.Width()+0.5f);
- - configDisplay.src_rect.height = (int)(SrcRect.Height()+0.5f);
- -
- - if (configDisplay.dest_rect.width == 0 || configDisplay.dest_rect.height == 0)
- - configDisplay.fullscreen = OMX_TRUE;
- + configDisplay.set = (OMX_DISPLAYSETTYPE)(OMX_DISPLAY_SET_DEST_RECT|OMX_DISPLAY_SET_SRC_RECT|OMX_DISPLAY_SET_FULLSCREEN|OMX_DISPLAY_SET_NOASPECT|OMX_DISPLAY_SET_MODE);
- + configDisplay.dest_rect.x_offset = lrintf(DestRect.x1);
- + configDisplay.dest_rect.y_offset = lrintf(DestRect.y1);
- + configDisplay.dest_rect.width = lrintf(DestRect.Width());
- + configDisplay.dest_rect.height = lrintf(DestRect.Height());
- +
- + configDisplay.src_rect.x_offset = lrintf(SrcRect.x1);
- + configDisplay.src_rect.y_offset = lrintf(SrcRect.y1);
- + configDisplay.src_rect.width = lrintf(SrcRect.Width());
- + configDisplay.src_rect.height = lrintf(SrcRect.Height());
- +
- + configDisplay.fullscreen = OMX_FALSE;
- + configDisplay.noaspect = OMX_TRUE;
- +
- + if (video_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL && display_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
- + configDisplay.mode = OMX_DISPLAY_MODE_STEREO_TOP_TO_TOP;
- + else if (video_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL && display_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
- + configDisplay.mode = OMX_DISPLAY_MODE_STEREO_TOP_TO_LEFT;
- + else if (video_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL && display_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
- + configDisplay.mode = OMX_DISPLAY_MODE_STEREO_LEFT_TO_TOP;
- + else if (video_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL && display_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
- + configDisplay.mode = OMX_DISPLAY_MODE_STEREO_LEFT_TO_LEFT;
- else
- - configDisplay.noaspect = OMX_TRUE;
- + configDisplay.mode = OMX_DISPLAY_MODE_LETTERBOX;
-
- m_omx_render.SetConfig(OMX_IndexConfigDisplayRegion, &configDisplay);
-
- - CLog::Log(LOGDEBUG, "dest_rect.x_offset %d dest_rect.y_offset %d dest_rect.width %d dest_rect.height %d\n",
- - configDisplay.dest_rect.x_offset, configDisplay.dest_rect.y_offset,
- - configDisplay.dest_rect.width, configDisplay.dest_rect.height);
- + CLog::Log(LOGDEBUG, "%s::%s %d,%d,%d,%d -> %d,%d,%d,%d mode:%d", CLASSNAME, __func__,
- + configDisplay.src_rect.x_offset, configDisplay.src_rect.y_offset, configDisplay.src_rect.width, configDisplay.src_rect.height,
- + configDisplay.dest_rect.x_offset, configDisplay.dest_rect.y_offset, configDisplay.dest_rect.width, configDisplay.dest_rect.height, configDisplay.mode);
- }
-
- int COMXVideo::GetInputBufferSize()
- diff --git a/xbmc/cores/omxplayer/OMXVideo.h b/xbmc/cores/omxplayer/OMXVideo.h
- index fd23e70..226000e 100644
- --- a/xbmc/cores/omxplayer/OMXVideo.h
- +++ b/xbmc/cores/omxplayer/OMXVideo.h
- @@ -32,6 +32,7 @@
- #include "DVDDemuxers/DVDDemux.h"
- #include "xbmc/settings/VideoSettings.h"
- #include "threads/CriticalSection.h"
- +#include "xbmc/rendering/RenderSystem.h"
- #include <string>
-
- #define VIDEO_BUFFERS 60
- @@ -58,7 +59,7 @@ class COMXVideo
- void Reset(void);
- void SetDropState(bool bDrop);
- std::string GetDecoderName() { return m_video_codec_name; };
- - void SetVideoRect(const CRect& SrcRect, const CRect& DestRect);
- + void SetVideoRect(const CRect& SrcRect, const CRect& DestRect, RENDER_STEREO_MODE video_mode, RENDER_STEREO_MODE display_mode);
- int GetInputBufferSize();
- void SubmitEOS();
- bool IsEOS();
- --
- 1.9.3
- From 716400b7b3cf13c6546bba6a0d0a2f47825f9117 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Wed, 16 Apr 2014 21:18:06 +0100
- Subject: [PATCH 72/94] [omxplayer] Don't propagate 3d flags based on supported
- 3d modes
- ---
- xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 29 ++++-------------------------
- 1 file changed, 4 insertions(+), 25 deletions(-)
- diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- index d5f3bec..e9f86f3 100644
- --- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- +++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- @@ -736,36 +736,15 @@ void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, f
- unsigned flags = 0;
- ERenderFormat format = RENDER_FMT_BYPASS;
-
- + /* figure out steremode expected based on user settings and hints */
- + unsigned int stereo_flags = GetStereoModeFlags(GetStereoMode());
- +
- if(m_bAllowFullscreen)
- {
- flags |= CONF_FLAGS_FULLSCREEN;
- m_bAllowFullscreen = false; // only allow on first configure
- }
- -
- - flags |= GetStereoModeFlags(GetStereoMode());
- -
- - if(flags & CONF_FLAGS_STEREO_MODE_SBS)
- - {
- - if(g_Windowing.Support3D(video_width, video_height, D3DPRESENTFLAG_MODE3DSBS))
- - CLog::Log(LOGNOTICE, "3DSBS movie found");
- - else
- - {
- - flags &= ~CONF_FLAGS_STEREO_MODE_MASK(~0);
- - CLog::Log(LOGNOTICE, "3DSBS movie found but not supported");
- - }
- - }
- - else if(flags & CONF_FLAGS_STEREO_MODE_TAB)
- - {
- - if(g_Windowing.Support3D(video_width, video_height, D3DPRESENTFLAG_MODE3DTB))
- - CLog::Log(LOGNOTICE, "3DTB movie found");
- - else
- - {
- - flags &= ~CONF_FLAGS_STEREO_MODE_MASK(~0);
- - CLog::Log(LOGNOTICE, "3DTB movie found but not supported");
- - }
- - }
- - else
- - CLog::Log(LOGNOTICE, "not a 3D movie");
- + flags |= stereo_flags;
-
- unsigned int iDisplayWidth = width;
- unsigned int iDisplayHeight = height;
- --
- 1.9.3
- From 7f2220746d9efeb3e8cfc4524479a615db5b710c Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Thu, 17 Apr 2014 13:00:52 +0100
- Subject: [PATCH 73/94] [graphics] Don't set stereo mode based on resolution
- The resolution change should follow stereo mode
- ---
- xbmc/guilib/GraphicContext.cpp | 22 ----------------------
- 1 file changed, 22 deletions(-)
- diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp
- index 5bffdf5..7e4fdd4 100644
- --- a/xbmc/guilib/GraphicContext.cpp
- +++ b/xbmc/guilib/GraphicContext.cpp
- @@ -418,28 +418,6 @@ void CGraphicContext::SetVideoResolution(RESOLUTION res, bool forceUpdate)
- Lock();
-
- RESOLUTION_INFO info_org = CDisplaySettings::Get().GetResolutionInfo(res);
- - RESOLUTION_INFO info_last = CDisplaySettings::Get().GetResolutionInfo(lastRes);
- -
- - RENDER_STEREO_MODE stereo_mode = m_stereoMode;
- -
- - // if the new mode is an actual stereo mode, switch to that
- - // if the old mode was an actual stereo mode, switch to no 3d mode
- - if (info_org.dwFlags & D3DPRESENTFLAG_MODE3DTB)
- - stereo_mode = RENDER_STEREO_MODE_SPLIT_HORIZONTAL;
- - else if (info_org.dwFlags & D3DPRESENTFLAG_MODE3DSBS)
- - stereo_mode = RENDER_STEREO_MODE_SPLIT_VERTICAL;
- - else if ((info_last.dwFlags & D3DPRESENTFLAG_MODE3DSBS) != 0
- - || (info_last.dwFlags & D3DPRESENTFLAG_MODE3DTB) != 0)
- - stereo_mode = RENDER_STEREO_MODE_OFF;
- -
- - if(stereo_mode != m_stereoMode)
- - {
- - m_stereoView = RENDER_STEREO_VIEW_OFF;
- - m_stereoMode = stereo_mode;
- - m_nextStereoMode = stereo_mode;
- - CSettings::Get().SetInt("videoscreen.stereoscopicmode", (int)m_stereoMode);
- - }
- -
- RESOLUTION_INFO info_mod = GetResInfo(res);
-
- m_iScreenWidth = info_mod.iWidth;
- --
- 1.9.3
- From 7885d90283809ccbcdb9c39809682dfc099049c4 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Thu, 17 Apr 2014 13:01:51 +0100
- Subject: [PATCH 74/94] [graphics] Allow switching to a more suitable 3D
- resolution
- ---
- xbmc/guilib/GraphicContext.cpp | 41 ++++++++++++++++++++++++++++++++++++++++-
- xbmc/guilib/GraphicContext.h | 1 +
- 2 files changed, 41 insertions(+), 1 deletion(-)
- diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp
- index 7e4fdd4..886b612 100644
- --- a/xbmc/guilib/GraphicContext.cpp
- +++ b/xbmc/guilib/GraphicContext.cpp
- @@ -35,6 +35,7 @@
- #include "utils/JobManager.h"
- #include "video/VideoReferenceClock.h"
- #include "cores/IPlayer.h"
- +#include <float.h>
-
- using namespace std;
-
- @@ -459,6 +460,44 @@ RESOLUTION CGraphicContext::GetVideoResolution() const
- return m_Resolution;
- }
-
- +RESOLUTION CGraphicContext::Get3DVideoResolution(RENDER_STEREO_MODE mode) const
- +{
- + RESOLUTION best = m_Resolution;
- + RESOLUTION_INFO curr = CDisplaySettings::Get().GetResolutionInfo(best);
- +
- + // Find closest refresh rate
- + for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++)
- + {
- + const RESOLUTION_INFO info = CDisplaySettings::Get().GetResolutionInfo((RESOLUTION)i);
- +
- + //discard resolutions that are not the same width and height (and interlaced/3D flags)
- + //or have a too low refreshrate
- + if (info.iScreenWidth != curr.iScreenWidth
- + || info.iScreenHeight != curr.iScreenHeight
- + || info.iScreen != curr.iScreen
- + || (info.dwFlags & D3DPRESENTFLAG_INTERLACED) != (curr.dwFlags & D3DPRESENTFLAG_INTERLACED)
- + || fabs(info.fRefreshRate - curr.fRefreshRate) >= FLT_EPSILON)
- + continue;
- +
- + if (mode == RENDER_STEREO_MODE_SPLIT_VERTICAL && info.dwFlags & D3DPRESENTFLAG_MODE3DSBS)
- + {
- + best = (RESOLUTION)i;
- + break;
- + }
- + else if (mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL && info.dwFlags & D3DPRESENTFLAG_MODE3DTB)
- + {
- + best = (RESOLUTION)i;
- + break;
- + }
- + else if ((mode == RENDER_STEREO_MODE_OFF || mode == RENDER_STEREO_MODE_MONO) && !(info.dwFlags & (D3DPRESENTFLAG_MODE3DSBS|D3DPRESENTFLAG_MODE3DTB)))
- + {
- + best = (RESOLUTION)i;
- + break;
- + }
- + }
- + return best;
- +}
- +
- void CGraphicContext::ResetOverscan(RESOLUTION_INFO &res)
- {
- res.Overscan.left = 0;
- @@ -996,7 +1035,7 @@ void CGraphicContext::Flip(const CDirtyRegionList& dirty)
- if(m_stereoMode != m_nextStereoMode)
- {
- m_stereoMode = m_nextStereoMode;
- - SetVideoResolution(GetVideoResolution(), true);
- + SetVideoResolution(Get3DVideoResolution(m_stereoMode), true);
- g_windowManager.SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_RENDERER_RESET);
- }
- }
- diff --git a/xbmc/guilib/GraphicContext.h b/xbmc/guilib/GraphicContext.h
- index 0a27643..df55e92 100644
- --- a/xbmc/guilib/GraphicContext.h
- +++ b/xbmc/guilib/GraphicContext.h
- @@ -108,6 +108,7 @@ class CGraphicContext : public CCriticalSection,
- bool IsValidResolution(RESOLUTION res);
- void SetVideoResolution(RESOLUTION res, bool forceUpdate = false);
- RESOLUTION GetVideoResolution() const;
- + RESOLUTION Get3DVideoResolution(RENDER_STEREO_MODE mode) const;
- void ResetOverscan(RESOLUTION res, OVERSCAN &overscan);
- void ResetOverscan(RESOLUTION_INFO &resinfo);
- void ResetScreenParameters(RESOLUTION res);
- --
- 1.9.3
- From 49438256c57d11b415f6a90f653857e7fae16a1d Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Thu, 17 Apr 2014 13:38:55 +0100
- Subject: [PATCH 75/94] [3D] Support switching to 3D resolutions
- Include matching 3D flags (SBS/TAB) in the score of a resolution to switch to, to enable switching to 3d modes.
- Also remove the old code that treated 3D modes differently when assigning a score.
- ---
- xbmc/cores/VideoRenderers/BaseRenderer.cpp | 47 +++++++++++-------------------
- 1 file changed, 17 insertions(+), 30 deletions(-)
- diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.cpp b/xbmc/cores/VideoRenderers/BaseRenderer.cpp
- index 970b822..9ca1be1 100644
- --- a/xbmc/cores/VideoRenderers/BaseRenderer.cpp
- +++ b/xbmc/cores/VideoRenderers/BaseRenderer.cpp
- @@ -222,10 +222,14 @@ void CBaseRenderer::FindResolutionFromFpsMatch(float fps, float& weight)
- RESOLUTION CBaseRenderer::FindClosestResolution(float fps, float multiplier, RESOLUTION current, float& weight)
- {
- RESOLUTION_INFO curr = g_graphicsContext.GetResInfo(current);
- + RENDER_STEREO_MODE stereo_mode = g_graphicsContext.GetStereoMode();
-
- float fRefreshRate = fps;
-
- - float last_diff = fRefreshRate;
- + int c_weight = MathUtils::round_int(RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier) * 1000.0);
- + if (!(stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL) != !(curr.dwFlags & D3DPRESENTFLAG_MODE3DSBS) ||
- + !(stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL) != !(curr.dwFlags & D3DPRESENTFLAG_MODE3DTB))
- + c_weight += 1000;
-
- // Find closest refresh rate
- for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++)
- @@ -241,40 +245,23 @@ RESOLUTION CBaseRenderer::FindClosestResolution(float fps, float multiplier, RES
- || info.fRefreshRate < (fRefreshRate * multiplier / 1.001) - 0.001)
- continue;
-
- - // For 3D choose the closest refresh rate
- - if(CONF_FLAGS_STEREO_MODE_MASK(m_iFlags))
- - {
- - float diff = (info.fRefreshRate - fRefreshRate);
- - if(diff < 0)
- - diff *= -1.0f;
- + int i_weight = MathUtils::round_int(RefreshWeight(info.fRefreshRate, fRefreshRate * multiplier) * 1000.0);
-
- - if(diff < last_diff)
- - {
- - last_diff = diff;
- - current = (RESOLUTION)i;
- - curr = info;
- - }
- - }
- - else
- - {
- - int c_weight = MathUtils::round_int(RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier) * 1000.0);
- - int i_weight = MathUtils::round_int(RefreshWeight(info.fRefreshRate, fRefreshRate * multiplier) * 1000.0);
- + if (!(stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL) != !(info.dwFlags & D3DPRESENTFLAG_MODE3DSBS) ||
- + !(stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL) != !(info.dwFlags & D3DPRESENTFLAG_MODE3DTB))
- + i_weight += 1000;
-
- - // Closer the better, prefer higher refresh rate if the same
- - if ((i_weight < c_weight)
- - || (i_weight == c_weight && info.fRefreshRate > curr.fRefreshRate))
- - {
- - current = (RESOLUTION)i;
- - curr = info;
- - }
- + // Closer the better, prefer higher refresh rate if the same
- + if ((i_weight < c_weight)
- + || (i_weight == c_weight && info.fRefreshRate > curr.fRefreshRate))
- + {
- + current = (RESOLUTION)i;
- + curr = info;
- + c_weight = i_weight;
- }
- }
-
- - // For 3D overwrite weight
- - if(CONF_FLAGS_STEREO_MODE_MASK(m_iFlags))
- - weight = 0;
- - else
- - weight = RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier);
- + weight = RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier);
-
- return current;
- }
- --
- 1.9.3
- From bd077947037288550a8e68efed630a3477a16564 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Wed, 23 Apr 2014 00:05:07 +0100
- Subject: [PATCH 76/94] [graphics] Make pixel ratio for 3d modes consistent
- Note: Use the stored stereo flags from lists of resolutions.
- Use current stereo mode for current resolution.
- ---
- xbmc/cores/VideoRenderers/BaseRenderer.cpp | 10 ++++----
- xbmc/guilib/GraphicContext.cpp | 32 ++++++++++---------------
- xbmc/guilib/GraphicContext.h | 4 ++--
- xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 8 -------
- 4 files changed, 19 insertions(+), 35 deletions(-)
- diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.cpp b/xbmc/cores/VideoRenderers/BaseRenderer.cpp
- index 9ca1be1..6bf42bf 100644
- --- a/xbmc/cores/VideoRenderers/BaseRenderer.cpp
- +++ b/xbmc/cores/VideoRenderers/BaseRenderer.cpp
- @@ -119,7 +119,7 @@ bool CBaseRenderer::FindResolutionFromOverride(float fps, float& weight, bool fa
-
- for (size_t j = (int)RES_DESKTOP; j < CDisplaySettings::Get().ResolutionInfoSize(); j++)
- {
- - RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)j);
- + RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)j, false);
-
- if (info.iScreenWidth == curr.iScreenWidth
- && info.iScreenHeight == curr.iScreenHeight
- @@ -179,7 +179,7 @@ void CBaseRenderer::FindResolutionFromFpsMatch(float fps, float& weight)
- //get the resolution with the refreshrate closest to 60 hertz
- for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++)
- {
- - RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i);
- + RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i, false);
-
- if (MathUtils::round_int(info.fRefreshRate) == 60
- && info.iScreenWidth == curr.iScreenWidth
- @@ -200,7 +200,7 @@ void CBaseRenderer::FindResolutionFromFpsMatch(float fps, float& weight)
- CLog::Log(LOGDEBUG, "60 hertz refreshrate not available, choosing highest");
- for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++)
- {
- - RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i);
- + RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i, false);
-
- if (info.fRefreshRate > curr.fRefreshRate
- && info.iScreenWidth == curr.iScreenWidth
- @@ -234,14 +234,14 @@ RESOLUTION CBaseRenderer::FindClosestResolution(float fps, float multiplier, RES
- // Find closest refresh rate
- for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++)
- {
- - const RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i);
- + const RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i, false);
-
- //discard resolutions that are not the same width and height (and interlaced/3D flags)
- //or have a too low refreshrate
- if (info.iScreenWidth != curr.iScreenWidth
- || info.iScreenHeight != curr.iScreenHeight
- || info.iScreen != curr.iScreen
- - || (info.dwFlags & D3DPRESENTFLAG_MODEMASK) != (curr.dwFlags & D3DPRESENTFLAG_MODEMASK)
- + || (info.dwFlags & D3DPRESENTFLAG_INTERLACED) != (curr.dwFlags & D3DPRESENTFLAG_INTERLACED)
- || info.fRefreshRate < (fRefreshRate * multiplier / 1.001) - 0.001)
- continue;
-
- diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp
- index 886b612..40a6362 100644
- --- a/xbmc/guilib/GraphicContext.cpp
- +++ b/xbmc/guilib/GraphicContext.cpp
- @@ -707,32 +707,26 @@ void CGraphicContext::ApplyStateBlock()
- g_Windowing.ApplyStateBlock();
- }
-
- -const RESOLUTION_INFO CGraphicContext::GetResInfo(RESOLUTION res) const
- +const RESOLUTION_INFO CGraphicContext::GetResInfo(RESOLUTION res, bool use_current_3d /*= true*/) const
- {
- RESOLUTION_INFO info = CDisplaySettings::Get().GetResolutionInfo(res);
-
- - if(m_stereoMode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
- + if(use_current_3d ? m_stereoMode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL : (info.dwFlags & D3DPRESENTFLAG_MODE3DTB))
- {
- - if((info.dwFlags & D3DPRESENTFLAG_MODE3DTB) == 0)
- - {
- - info.fPixelRatio /= 2;
- - info.iBlanking = 0;
- - info.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
- - }
- + info.fPixelRatio /= 2;
- + info.iBlanking = 0;
- + info.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
- info.iHeight = (info.iHeight - info.iBlanking) / 2;
- info.Overscan.top /= 2;
- info.Overscan.bottom = (info.Overscan.bottom - info.iBlanking) / 2;
- info.iSubtitles = (info.iSubtitles - info.iBlanking) / 2;
- }
-
- - if(m_stereoMode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
- + if(use_current_3d ? m_stereoMode == RENDER_STEREO_MODE_SPLIT_VERTICAL : (info.dwFlags & D3DPRESENTFLAG_MODE3DSBS))
- {
- - if((info.dwFlags & D3DPRESENTFLAG_MODE3DSBS) == 0)
- - {
- - info.fPixelRatio *= 2;
- - info.iBlanking = 0;
- - info.dwFlags |= D3DPRESENTFLAG_MODE3DSBS;
- - }
- + info.fPixelRatio *= 2;
- + info.iBlanking = 0;
- + info.dwFlags |= D3DPRESENTFLAG_MODE3DSBS;
- info.iWidth = (info.iWidth - info.iBlanking) / 2;
- info.Overscan.left /= 2;
- info.Overscan.right = (info.Overscan.right - info.iBlanking) / 2;
- @@ -740,7 +734,7 @@ const RESOLUTION_INFO CGraphicContext::GetResInfo(RESOLUTION res) const
- return info;
- }
-
- -void CGraphicContext::SetResInfo(RESOLUTION res, const RESOLUTION_INFO& info)
- +void CGraphicContext::SetResInfo(RESOLUTION res, const RESOLUTION_INFO& info, bool use_current_3d /*= true*/)
- {
- RESOLUTION_INFO& curr = CDisplaySettings::Get().GetResolutionInfo(res);
- curr.Overscan = info.Overscan;
- @@ -750,16 +744,14 @@ void CGraphicContext::SetResInfo(RESOLUTION res, const RESOLUTION_INFO& info)
- if(info.dwFlags & D3DPRESENTFLAG_MODE3DSBS)
- {
- curr.Overscan.right = info.Overscan.right * 2 + info.iBlanking;
- - if((curr.dwFlags & D3DPRESENTFLAG_MODE3DSBS) == 0)
- - curr.fPixelRatio /= 2.0;
- + curr.fPixelRatio /= 2.0;
- }
-
- if(info.dwFlags & D3DPRESENTFLAG_MODE3DTB)
- {
- curr.Overscan.bottom = info.Overscan.bottom * 2 + info.iBlanking;
- curr.iSubtitles = info.iSubtitles * 2 + info.iBlanking;
- - if((curr.dwFlags & D3DPRESENTFLAG_MODE3DTB) == 0)
- - curr.fPixelRatio *= 2.0;
- + curr.fPixelRatio *= 2.0;
- }
- }
-
- diff --git a/xbmc/guilib/GraphicContext.h b/xbmc/guilib/GraphicContext.h
- index df55e92..c77f2ff 100644
- --- a/xbmc/guilib/GraphicContext.h
- +++ b/xbmc/guilib/GraphicContext.h
- @@ -124,8 +124,8 @@ class CGraphicContext : public CCriticalSection,
- {
- return GetResInfo(m_Resolution);
- }
- - const RESOLUTION_INFO GetResInfo(RESOLUTION res) const;
- - void SetResInfo(RESOLUTION res, const RESOLUTION_INFO& info);
- + const RESOLUTION_INFO GetResInfo(RESOLUTION res, bool use_current_3d = true) const;
- + void SetResInfo(RESOLUTION res, const RESOLUTION_INFO& info, bool use_current_3d = true);
-
- /* \brief Get UI scaling information from a given resolution to the screen resolution.
- Takes account of overscan and UI zooming.
- diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
- index 21b8cc4..f57b22b 100644
- --- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
- +++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
- @@ -446,15 +446,9 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
- m_desktopRes.fPixelRatio = get_display_aspect_ratio((HDMI_ASPECT_T)tv_state.display.hdmi.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
- // Also add 3D flags
- if (tv_state.display.hdmi.format_3d == HDMI_3D_FORMAT_SBS_HALF)
- - {
- m_desktopRes.dwFlags |= D3DPRESENTFLAG_MODE3DSBS;
- - m_desktopRes.fPixelRatio *= 2.0;
- - }
- else if (tv_state.display.hdmi.format_3d == HDMI_3D_FORMAT_TB_HALF)
- - {
- m_desktopRes.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
- - m_desktopRes.fPixelRatio *= 0.5;
- - }
- HDMI_PROPERTY_PARAM_T property;
- property.property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE;
- vc_tv_hdmi_get_property(&property);
- @@ -605,7 +599,6 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
- RESOLUTION_INFO res2 = res;
- res2.dwFlags |= D3DPRESENTFLAG_MODE3DSBS;
- res2.fPixelRatio = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight);
- - res2.fPixelRatio *= 2.0f;
- SetResolutionString(res2);
- CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f)\n", i, res2.strMode.c_str(), res2.fPixelRatio);
-
- @@ -623,7 +616,6 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
- RESOLUTION_INFO res2 = res;
- res2.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
- res2.fPixelRatio = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight);
- - res2.fPixelRatio *= 0.5f;
- SetResolutionString(res2);
- CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f)\n", i, res2.strMode.c_str(), res2.fPixelRatio);
-
- --
- 1.9.3
- From 7464b116a5db0be0c2b50314fcf703529d6f646e Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Wed, 23 Apr 2014 21:07:51 +0100
- Subject: [PATCH 77/94] [PiSink] More attempts to reduce underrun audio
- glitches with multichannl and high samplerate
- ---
- xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp | 79 +++++++++++--------------------
- 1 file changed, 27 insertions(+), 52 deletions(-)
- diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
- index 070e6eb..133b9f6 100644
- --- a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
- +++ b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
- @@ -186,7 +186,7 @@ bool CAESinkPi::Initialize(AEAudioFormat &format, std::string &device)
- unsigned int sample_size = CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3;
- format.m_frameSize = sample_size * channels;
- format.m_sampleRate = std::max(8000U, std::min(192000U, format.m_sampleRate));
- - format.m_frames = format.m_sampleRate * AUDIO_PLAYBUFFER;
- + format.m_frames = format.m_sampleRate * AUDIO_PLAYBUFFER / NUM_OMX_BUFFERS;
- format.m_frameSamples = format.m_frames * channels;
-
- SetAudioProps(m_passthrough, GetChannelMap(format.m_channelLayout, m_passthrough));
- @@ -232,7 +232,7 @@ bool CAESinkPi::Initialize(AEAudioFormat &format, std::string &device)
- CLog::Log(LOGERROR, "%s:%s - error get OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
-
- port_param.nBufferCountActual = std::max((unsigned int)port_param.nBufferCountMin, (unsigned int)NUM_OMX_BUFFERS);
- - port_param.nBufferSize = m_format.m_frameSize * m_format.m_frames / port_param.nBufferCountActual;
- + port_param.nBufferSize = m_format.m_frameSize * m_format.m_frames;
-
- omx_err = m_omx_render.SetParameter(OMX_IndexParamPortDefinition, &port_param);
- if (omx_err != OMX_ErrorNone)
- @@ -308,63 +308,38 @@ double CAESinkPi::GetCacheTotal()
-
- unsigned int CAESinkPi::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking)
- {
- - unsigned int sent = 0;
- -
- - if (!m_Initialized)
- + if (!m_Initialized || !frames)
- return frames;
-
- OMX_ERRORTYPE omx_err = OMX_ErrorNone;
- OMX_BUFFERHEADERTYPE *omx_buffer = NULL;
- - while (sent < frames)
- +
- + double delay = GetDelay();
- + if (delay <= 0.0 && m_submitted)
- + CLog::Log(LOGNOTICE, "%s:%s Underrun (delay:%.2f frames:%d)", CLASSNAME, __func__, delay, frames);
- +
- + omx_buffer = m_omx_render.GetInputBuffer(1000);
- + if (omx_buffer == NULL)
- {
- - double delay = GetDelay();
- - double ideal_submission_time = AUDIO_PLAYBUFFER - delay;
- - // ideal amount of audio we'd like submit (to make delay match AUDIO_PLAYBUFFER)
- - int timeout = blocking ? 1000 : 0;
- - int ideal_submission_samples = ideal_submission_time / (m_sinkbuffer_sec_per_byte * m_format.m_frameSize);
- - // if we are almost full then sleep (to avoid repeatedly sending a few samples)
- - bool too_laggy = ideal_submission_time < 0.25 * AUDIO_PLAYBUFFER;
- - int sleeptime = (int)(AUDIO_PLAYBUFFER * 0.25 * 1000.0);
- - if (too_laggy)
- - {
- - if (blocking)
- - {
- - Sleep(sleeptime);
- - continue;
- - }
- - break;
- - }
- - omx_buffer = m_omx_render.GetInputBuffer(timeout);
- - if (omx_buffer == NULL)
- - {
- - if (blocking)
- - CLog::Log(LOGERROR, "COMXAudio::Decode timeout");
- - break;
- - }
- -
- - unsigned int space = omx_buffer->nAllocLen / m_format.m_frameSize;
- - unsigned int samples = std::min(std::min(space, (unsigned int)ideal_submission_samples), frames - sent);
- -
- - omx_buffer->nFilledLen = samples * m_format.m_frameSize;
- - omx_buffer->nTimeStamp = ToOMXTime(0);
- - omx_buffer->nFlags = 0;
- - memcpy(omx_buffer->pBuffer, (uint8_t *)data + sent * m_format.m_frameSize, omx_buffer->nFilledLen);
- -
- - sent += samples;
- -
- - if (sent == frames)
- - omx_buffer->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
- -
- - if (delay <= 0.0 && m_submitted)
- - CLog::Log(LOGNOTICE, "%s:%s Underrun (delay:%.2f frames:%d)", CLASSNAME, __func__, delay, frames);
- -
- - omx_err = m_omx_render.EmptyThisBuffer(omx_buffer);
- - if (omx_err != OMX_ErrorNone)
- - CLog::Log(LOGERROR, "%s:%s frames=%d err=%x", CLASSNAME, __func__, frames, omx_err);
- - m_submitted++;
- + CLog::Log(LOGERROR, "CAESinkPi::AddPackets timeout");
- + return 0;
- }
-
- - return sent;
- + omx_buffer->nFilledLen = frames * m_format.m_frameSize;
- + // must be true
- + assert(omx_buffer->nFilledLen <= omx_buffer->nAllocLen);
- + omx_buffer->nTimeStamp = ToOMXTime(0);
- + omx_buffer->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
- + memcpy(omx_buffer->pBuffer, data, omx_buffer->nFilledLen);
- +
- + omx_err = m_omx_render.EmptyThisBuffer(omx_buffer);
- + if (omx_err != OMX_ErrorNone)
- + CLog::Log(LOGERROR, "%s:%s frames=%d err=%x", CLASSNAME, __func__, frames, omx_err);
- + m_submitted++;
- + delay = GetDelay();
- + if (delay > AUDIO_PLAYBUFFER)
- + Sleep((int)(1000.0f * (delay - AUDIO_PLAYBUFFER)));
- + return frames;
- }
-
- void CAESinkPi::Drain()
- --
- 1.9.3
- From 508c32de290d09c429d73b2497408b930550f1a3 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Wed, 23 Apr 2014 22:36:01 +0100
- Subject: [PATCH 78/94] [omxplayer] Fix for aspect ratio of portrait videos
- ---
- xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 10 ++++++++++
- 1 file changed, 10 insertions(+)
- diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- index e9f86f3..7e2c644 100644
- --- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- +++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- @@ -651,6 +651,16 @@ void OMXPlayerVideo::SetVideoRect(const CRect &InSrcRect, const CRect &InDestRec
- bool stereo_invert = (flags & CONF_FLAGS_STEREO_CADANCE_RIGHT_LEFT) ? true : false;
- RENDER_STEREO_MODE display_stereo_mode = g_graphicsContext.GetStereoMode();
-
- + // fix up transposed video
- + if (m_hints.orientation == 90 || m_hints.orientation == 270)
- + {
- + float diff = (DestRect.Height() - DestRect.Width()) * 0.5f;
- + DestRect.x1 -= diff;
- + DestRect.x2 += diff;
- + DestRect.y1 += diff;
- + DestRect.y2 -= diff;
- + }
- +
- // check if destination rect or video view mode has changed
- if (!(m_dst_rect != DestRect) && !(m_src_rect != SrcRect) && m_video_stereo_mode == video_stereo_mode && m_display_stereo_mode == display_stereo_mode && m_StereoInvert == stereo_invert)
- return;
- --
- 1.9.3
- From fe9fea7a1aac545aa601b71aae01651bc42a5376 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Tue, 22 Apr 2014 12:23:23 +0100
- Subject: [PATCH 79/94] [omxplayer] Make dvdplayer the default for dvd images
- ---
- xbmc/cores/omxplayer/omxplayer_advancedsettings.xml | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
- diff --git a/xbmc/cores/omxplayer/omxplayer_advancedsettings.xml b/xbmc/cores/omxplayer/omxplayer_advancedsettings.xml
- index 77c6a15..51c0daf 100644
- --- a/xbmc/cores/omxplayer/omxplayer_advancedsettings.xml
- +++ b/xbmc/cores/omxplayer/omxplayer_advancedsettings.xml
- @@ -2,6 +2,6 @@
- <advancedsettings>
- <video>
- <defaultplayer>omxplayer</defaultplayer>
- - <defaultdvdplayer>omxplayer</defaultdvdplayer>
- + <defaultdvdplayer>dvdplayer</defaultdvdplayer>
- </video>
- </advancedsettings>
- --
- 1.9.3
- From f417d7d303eaa5113edba8ba562cb61ed8a6c59a Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Sat, 26 Apr 2014 17:27:52 +0100
- Subject: [PATCH 80/94] [cec] Don't suspend pi on tv switch off - it can't wake
- up
- ---
- system/peripherals.xml | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
- diff --git a/system/peripherals.xml b/system/peripherals.xml
- index a906628..9b5271a 100644
- --- a/system/peripherals.xml
- +++ b/system/peripherals.xml
- @@ -16,7 +16,7 @@
- <setting key="send_inactive_source" type="bool" value="1" label="36025" order="5" />
- <setting key="cec_standby_screensaver" type="bool" value="0" label="36009" order="6" />
- <setting key="cec_wake_screensaver" type="bool" value="1" label="36010" order="7" />
- - <setting key="standby_pc_on_tv_standby" type="enum" value="13011" label="36029" order="8" lvalues="36028|13005|13011" />
- + <setting key="standby_pc_on_tv_standby" type="enum" value="36028" label="36029" order="8" lvalues="36028|13005|13011" />
- <setting key="standby_tv_on_pc_standby" type="bool" value="1" label="36026" order="9" />
- <setting key="use_tv_menu_language" type="bool" value="1" label="36018" order="10" />
- <setting key="pause_playback_on_deactivate" type="bool" value="1" label="36033" order="11" />
- --
- 1.9.3
- From 0563f1df1295ac5600fd330fb201e854ad900e02 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Sat, 12 Apr 2014 17:57:19 +0100
- Subject: [PATCH 81/94] [omxplayer] Ignore occasionally valid pts values, they
- cause live tv stutter
- ---
- xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
- diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- index 7e2c644..b3786f6 100644
- --- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- +++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- @@ -490,7 +490,7 @@ void OMXPlayerVideo::Process()
- // if a stream has had more than 4 valid pts values in the last 16, the use UNKNOWN, otherwise use dts
- m_history_valid_pts = (m_history_valid_pts << 1) | (pPacket->pts != DVD_NOPTS_VALUE);
- double pts = pPacket->pts;
- - if(pPacket->pts == DVD_NOPTS_VALUE && count_bits(m_history_valid_pts & 0xffff) < 4)
- + if(count_bits(m_history_valid_pts & 0xffff) < 4)
- pts = pPacket->dts;
-
- if (pts != DVD_NOPTS_VALUE)
- --
- 1.9.3
- From cddc5f27f9aa11dfb65e16ec1f84a809cf79c68b Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Wed, 7 May 2014 14:54:41 +0100
- Subject: [PATCH 82/94] [Pi] Fix naming of refresh rates to avoid lost
- calibration settings
- ---
- xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 13 ++++---------
- xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h | 2 +-
- 2 files changed, 5 insertions(+), 10 deletions(-)
- diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
- index f57b22b..5b26b20 100644
- --- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
- +++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
- @@ -58,6 +58,7 @@
- # define DLOG(fmt, args...)
- #endif
-
- +static void SetResolutionString(RESOLUTION_INFO &res);
-
- CEGLNativeTypeRaspberryPI::CEGLNativeTypeRaspberryPI()
- {
- @@ -194,8 +195,9 @@ int CEGLNativeTypeRaspberryPI::FindMatchingResolution(const RESOLUTION_INFO &res
- #endif
-
- #if defined(TARGET_RASPBERRY_PI)
- -int CEGLNativeTypeRaspberryPI::AddUniqueResolution(const RESOLUTION_INFO &res, std::vector<RESOLUTION_INFO> &resolutions)
- +int CEGLNativeTypeRaspberryPI::AddUniqueResolution(RESOLUTION_INFO &res, std::vector<RESOLUTION_INFO> &resolutions)
- {
- + SetResolutionString(res);
- int i = FindMatchingResolution(res, resolutions);
- if (i>=0)
- { // don't replace a progressive resolution with an interlaced one of same resolution
- @@ -467,10 +469,7 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
- m_desktopRes.fPixelRatio = get_display_aspect_ratio((SDTV_ASPECT_T)tv_state.display.sdtv.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
- }
-
- - m_desktopRes.strMode = StringUtils::Format("%dx%d", m_desktopRes.iScreenWidth, m_desktopRes.iScreenHeight);
- -
- - if((int)m_desktopRes.fRefreshRate > 1)
- - SetResolutionString(m_desktopRes);
- + SetResolutionString(m_desktopRes);
-
- m_initDesktopRes = false;
-
- @@ -578,8 +577,6 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
- res.iScreenHeight = tv->height;
- res.fPixelRatio = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res.iScreenWidth / (float)res.iScreenHeight);
-
- - SetResolutionString(res);
- -
- CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f) %s%s:%x\n", i, res.strMode.c_str(), res.fPixelRatio,
- tv->native ? "N" : "", tv->scan_mode ? "I" : "", tv->code);
-
- @@ -599,7 +596,6 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
- RESOLUTION_INFO res2 = res;
- res2.dwFlags |= D3DPRESENTFLAG_MODE3DSBS;
- res2.fPixelRatio = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight);
- - SetResolutionString(res2);
- CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f)\n", i, res2.strMode.c_str(), res2.fPixelRatio);
-
- res2.iSubtitles = (int)(0.965 * res2.iHeight);
- @@ -616,7 +612,6 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
- RESOLUTION_INFO res2 = res;
- res2.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
- res2.fPixelRatio = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight);
- - SetResolutionString(res2);
- CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f)\n", i, res2.strMode.c_str(), res2.fPixelRatio);
-
- res2.iSubtitles = (int)(0.965 * res2.iHeight);
- diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h
- index d1ebb81..59401f5 100644
- --- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h
- +++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h
- @@ -71,6 +71,6 @@ class CEGLNativeTypeRaspberryPI : public CEGLNativeType
-
- void DestroyDispmaxWindow();
- int FindMatchingResolution(const RESOLUTION_INFO &res, const std::vector<RESOLUTION_INFO> &resolutions);
- - int AddUniqueResolution(const RESOLUTION_INFO &res, std::vector<RESOLUTION_INFO> &resolutions);
- + int AddUniqueResolution(RESOLUTION_INFO &res, std::vector<RESOLUTION_INFO> &resolutions);
- #endif
- };
- --
- 1.9.3
- From a4c36a4925e780b63d9821fb04504453ac982205 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Sat, 10 May 2014 11:40:41 +0100
- Subject: [PATCH 83/94] [omxplayer] Skip out of submit loop when closing.
- Avoids a permanent hang at EOF when using IPTV streams
- ---
- xbmc/cores/omxplayer/OMXPlayerAudio.cpp | 7 +++++--
- xbmc/cores/omxplayer/OMXPlayerAudio.h | 1 +
- xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 7 +++++--
- xbmc/cores/omxplayer/OMXPlayerVideo.h | 1 +
- 4 files changed, 12 insertions(+), 4 deletions(-)
- diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
- index d3348ec..4435d22 100644
- --- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
- +++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
- @@ -89,6 +89,7 @@ OMXPlayerAudio::OMXPlayerAudio(OMXClock *av_clock, CDVDMessageQueue& parent)
- m_hw_decode = false;
- m_silence = false;
- m_flush = false;
- + m_bClose = false;
- }
-
-
- @@ -145,11 +146,13 @@ void OMXPlayerAudio::OpenStream(CDVDStreamInfo &hints, COMXAudioCodecOMX *codec)
- m_format.m_dataFormat = GetDataFormat(m_hints);
- m_format.m_sampleRate = 0;
- m_format.m_channelLayout = 0;
- + m_bClose = false;
- }
-
- bool OMXPlayerAudio::CloseStream(bool bWaitForBuffers)
- {
- // wait until buffers are empty
- + m_bClose = true;
- if (bWaitForBuffers && m_speed > 0) m_messageQueue.WaitUntilEmpty();
-
- m_messageQueue.Abort();
- @@ -259,8 +262,8 @@ bool OMXPlayerAudio::Decode(DemuxPacket *pkt, bool bDropPacket)
-
- while(!m_bStop)
- {
- - // discard if flushing as clocks may be stopped and we'll never submit it
- - if(m_flush)
- + // discard if flushing or closing as clocks may be stopped and we'll never submit it
- + if(m_flush || m_bClose)
- break;
-
- if(m_omxAudio.GetSpace() < (unsigned int)decoded_size)
- diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.h b/xbmc/cores/omxplayer/OMXPlayerAudio.h
- index 685a686..7b55e48 100644
- --- a/xbmc/cores/omxplayer/OMXPlayerAudio.h
- +++ b/xbmc/cores/omxplayer/OMXPlayerAudio.h
- @@ -70,6 +70,7 @@ class OMXPlayerAudio : public CThread
- bool m_DecoderOpen;
-
- bool m_bad_state;
- + bool m_bClose;
-
- virtual void OnStartup();
- virtual void OnExit();
- diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- index b3786f6..61b884e 100644
- --- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- +++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- @@ -104,6 +104,7 @@ OMXPlayerVideo::OMXPlayerVideo(OMXClock *av_clock,
- m_iCurrentPts = DVD_NOPTS_VALUE;
- m_nextOverlay = DVD_NOPTS_VALUE;
- m_flush = false;
- + m_bClose = false;
- m_history_valid_pts = 0;
- }
-
- @@ -118,6 +119,7 @@ bool OMXPlayerVideo::OpenStream(CDVDStreamInfo &hints)
- m_hdmi_clock_sync = (CSettings::Get().GetInt("videoplayer.adjustrefreshrate") != ADJUST_REFRESHRATE_OFF);
- m_started = false;
- m_flush = false;
- + m_bClose = false;
- m_stalled = m_messageQueue.GetPacketCount(CDVDMsg::DEMUXER_PACKET) == 0;
- m_nextOverlay = DVD_NOPTS_VALUE;
- // force SetVideoRect to be called initially
- @@ -161,6 +163,7 @@ bool OMXPlayerVideo::OpenStream(CDVDStreamInfo &hints, COMXVideo *codec)
- bool OMXPlayerVideo::CloseStream(bool bWaitForBuffers)
- {
- // wait until buffers are empty
- + m_bClose = true;
- if (bWaitForBuffers && m_speed > 0) m_messageQueue.WaitUntilEmpty();
-
- m_messageQueue.Abort();
- @@ -469,8 +472,8 @@ void OMXPlayerVideo::Process()
-
- while (!m_bStop)
- {
- - // discard if flushing as clocks may be stopped and we'll never submit it
- - if (m_flush)
- + // discard if flushing or closing as clocks may be stopped and we'll never submit it
- + if (m_flush || m_bClose)
- break;
-
- if((int)m_omxVideo.GetFreeSpace() < pPacket->iSize)
- diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.h b/xbmc/cores/omxplayer/OMXPlayerVideo.h
- index 6f19395..8eff32f 100644
- --- a/xbmc/cores/omxplayer/OMXPlayerVideo.h
- +++ b/xbmc/cores/omxplayer/OMXPlayerVideo.h
- @@ -66,6 +66,7 @@ class OMXPlayerVideo : public CThread
-
- float m_fForcedAspectRatio;
- unsigned m_flags;
- + bool m_bClose;
-
- CRect m_src_rect;
- CRect m_dst_rect;
- --
- 1.9.3
- From b90562b8ffc29c1d9e037e94b0c92b3b0b67413b Mon Sep 17 00:00:00 2001
- From: xbmc <fernetmenta@online.de>
- Date: Mon, 28 May 2012 10:34:39 +0200
- Subject: [PATCH 84/94] videoplayer: adapt lateness detection and dropping to
- buffering
- ---
- xbmc/cores/VideoRenderers/RenderManager.cpp | 16 +-
- xbmc/cores/VideoRenderers/RenderManager.h | 12 +-
- .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 38 +++-
- .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 41 +++++
- .../DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 7 +
- xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 197 +++++++++++++++++----
- xbmc/cores/dvdplayer/DVDPlayerVideo.h | 23 +++
- 7 files changed, 296 insertions(+), 38 deletions(-)
- diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
- index 3503988..4ca74f8 100644
- --- a/xbmc/cores/VideoRenderers/RenderManager.cpp
- +++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
- @@ -286,6 +286,8 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi
- m_bIsStarted = true;
- m_bReconfigured = true;
- m_presentstep = PRESENT_IDLE;
- + m_presentpts = DVD_NOPTS_VALUE;
- + m_sleeptime = 1.0;
- m_presentevent.notifyAll();
-
- m_firstFlipPage = false; // tempfix
- @@ -629,7 +631,7 @@ void CXBMCRenderManager::SetViewMode(int iViewMode)
- m_pRenderer->SetViewMode(iViewMode);
- }
-
- -void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0LL*/, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/)
- +void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0LL*/, double pts /* = 0 */, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/)
- {
- { CSharedLock lock(m_sharedSection);
-
- @@ -697,6 +699,7 @@ void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0L
- m.timestamp = timestamp;
- m.presentfield = sync;
- m.presentmethod = presentmethod;
- + m.pts = pts;
- requeue(m_queued, m_free);
-
- /* signal to any waiters to check state */
- @@ -1065,6 +1068,8 @@ void CXBMCRenderManager::PrepareNextRender()
- m_discard.push_back(m_presentsource);
- m_presentsource = idx;
- m_queued.pop_front();
- + m_sleeptime = m_Queue[idx].timestamp - clocktime;
- + m_presentpts = m_Queue[idx].pts;
- m_presentevent.notifyAll();
- }
- }
- @@ -1081,3 +1086,12 @@ void CXBMCRenderManager::DiscardBuffer()
- m_presentstep = PRESENT_IDLE;
- m_presentevent.notifyAll();
- }
- +
- +bool CXBMCRenderManager::GetStats(double &sleeptime, double &pts, int &bufferLevel)
- +{
- + CSingleLock lock(m_presentlock);
- + sleeptime = m_sleeptime;
- + pts = m_presentpts;
- + bufferLevel = m_queued.size() + m_discard.size();
- + return true;
- +}
- diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h
- index c469795..949c652b 100644
- --- a/xbmc/cores/VideoRenderers/RenderManager.h
- +++ b/xbmc/cores/VideoRenderers/RenderManager.h
- @@ -98,10 +98,11 @@ class CXBMCRenderManager
- *
- * @param bStop reference to stop flag of calling thread
- * @param timestamp of frame delivered with AddVideoPicture
- + * @param pts used for lateness detection
- * @param source depreciated
- * @param sync signals frame, top, or bottom field
- */
- - void FlipPage(volatile bool& bStop, double timestamp = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE);
- + void FlipPage(volatile bool& bStop, double timestamp = 0.0, double pts = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE);
- unsigned int PreInit();
- void UnInit();
- bool Flush();
- @@ -176,6 +177,12 @@ class CXBMCRenderManager
- int WaitForBuffer(volatile bool& bStop, int timeout = 100);
-
- /**
- + * Can be called by player for lateness detection. This is done best by
- + * looking at the end of the queue.
- + */
- + bool GetStats(double &sleeptime, double &pts, int &bufferLevel);
- +
- + /**
- * Video player call this on flush in oder to discard any queued frames
- */
- void DiscardBuffer();
- @@ -222,6 +229,7 @@ class CXBMCRenderManager
-
- struct SPresent
- {
- + double pts;
- double timestamp;
- EFIELDSYNC presentfield;
- EPRESENTMETHOD presentmethod;
- @@ -233,6 +241,8 @@ class CXBMCRenderManager
-
- ERenderFormat m_format;
-
- + double m_sleeptime;
- + double m_presentpts;
- double m_presentcorr;
- double m_presenterr;
- double m_errorbuff[ERRORBUFFSIZE];
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
- index dc047d7..c09939c 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
- @@ -129,6 +129,10 @@ struct DVDVideoUserData
- #define DVP_FLAG_NOSKIP 0x00000010 // indicate this picture should never be dropped
- #define DVP_FLAG_DROPPED 0x00000020 // indicate that this picture has been dropped in decoder stage, will have no data
-
- +#define DVP_FLAG_DROPDEINT 0x00000040 // indicate that this picture was requested to have been dropped in deint stage
- +#define DVP_FLAG_NO_POSTPROC 0x00000100 // see GetCodecStats
- +#define DVP_FLAG_DRAIN 0x00000200 // see GetCodecStats
- +
- // DVP_FLAG 0x00000100 - 0x00000f00 is in use by libmpeg2!
-
- #define DVP_QSCALE_UNKNOWN 0
- @@ -146,6 +150,8 @@ class CDVDCodecOptions;
- #define VC_PICTURE 0x00000004 // the decoder got a picture, call Decode(NULL, 0) again to parse the rest of the data
- #define VC_USERDATA 0x00000008 // the decoder found some userdata, call Decode(NULL, 0) again to parse the rest of the data
- #define VC_FLUSHED 0x00000010 // the decoder lost it's state, we need to restart decoding again
- +#define VC_DROPPED 0x00000020 // needed to identify if a picture was dropped
- +
- class CDVDVideoCodec
- {
- public:
- @@ -263,7 +269,6 @@ class CDVDVideoCodec
- return 0;
- }
-
- -
- /**
- * Number of references to old pictures that are allowed to
- * be retained when calling decode on the next demux packet
- @@ -280,4 +285,35 @@ class CDVDVideoCodec
- * Interact with user settings so that user disabled codecs are disabled
- */
- static bool IsCodecDisabled(DVDCodecAvailableType* map, unsigned int size, AVCodecID id);
- +
- + /* For calculation of dropping requirements player asks for some information.
- + *
- + * - pts : right after decoder, used to detect gaps (dropped frames in decoder)
- + * - droppedPics : indicates if decoder has dropped a picture
- + * -1 means that decoder has no info on this.
- + *
- + * If codec does not implement this method, pts of decoded frame at input
- + * video player is used. In case decoder does post-proc and de-interlacing there
- + * may be quite some frames queued up between exit decoder and entry player.
- + */
- + virtual bool GetCodecStats(double &pts, int &droppedPics)
- + {
- + droppedPics= -1;
- + return false;
- + }
- +
- + /**
- + * Codec can be informed by player with the following flags:
- + *
- + * DVP_FLAG_NO_POSTPROC : if speed is not normal the codec can switch off
- + * postprocessing and de-interlacing
- + *
- + * DVP_FLAG_DRAIN : codecs may do postprocessing and de-interlacing.
- + * If video buffers in RenderManager are about to run dry,
- + * this is signaled to codec. Codec can wait for post-proc
- + * to be finished instead of returning empty and getting another
- + * packet.
- + *
- + */
- + virtual void SetCodecControl(int flags) {}
- };
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
- index 9b6a34d..81fe0cf 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
- @@ -164,6 +164,7 @@ CDVDVideoCodecFFmpeg::CDVDVideoCodecFFmpeg() : CDVDVideoCodec()
- m_iLastKeyframe = 0;
- m_dts = DVD_NOPTS_VALUE;
- m_started = false;
- + m_decoderPts = DVD_NOPTS_VALUE;
- }
-
- CDVDVideoCodecFFmpeg::~CDVDVideoCodecFFmpeg()
- @@ -355,6 +356,14 @@ void CDVDVideoCodecFFmpeg::SetDropState(bool bDrop)
- {
- if( m_pCodecContext )
- {
- + if (bDrop && m_pHardware && m_pHardware->CanSkipDeint())
- + {
- + m_requestSkipDeint = true;
- + bDrop = false;
- + }
- + else
- + m_requestSkipDeint = false;
- +
- // i don't know exactly how high this should be set
- // couldn't find any good docs on it. think it varies
- // from codec to codec on what it does
- @@ -556,6 +565,7 @@ int CDVDVideoCodecFFmpeg::Decode(uint8_t* pData, int iSize, double dts, double p
- void CDVDVideoCodecFFmpeg::Reset()
- {
- m_started = false;
- + m_decoderPts = DVD_NOPTS_VALUE;
- m_iLastKeyframe = m_pCodecContext->has_b_frames;
- m_dllAvCodec.avcodec_flush_buffers(m_pCodecContext);
-
- @@ -665,6 +675,22 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture)
- else
- pDvdVideoPicture->pts = DVD_NOPTS_VALUE;
-
- + if (pDvdVideoPicture->pts != DVD_NOPTS_VALUE)
- + m_decoderPts = pDvdVideoPicture->pts;
- + else
- + m_decoderPts = m_dts;
- +
- + if (m_requestSkipDeint)
- + {
- + pDvdVideoPicture->iFlags |= DVP_FLAG_DROPDEINT;
- + m_skippedDeint = 1;
- + }
- + else
- + m_skippedDeint = 0;
- +
- + m_requestSkipDeint = false;
- + pDvdVideoPicture->iFlags |= m_codecControlFlags;
- +
- if(!m_started)
- pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED;
-
- @@ -924,3 +950,18 @@ unsigned CDVDVideoCodecFFmpeg::GetAllowedReferences()
- else
- return 0;
- }
- +
- +bool CDVDVideoCodecFFmpeg::GetCodecStats(double &pts, int &droppedPics)
- +{
- + pts = m_decoderPts;
- + if (m_skippedDeint)
- + droppedPics = m_skippedDeint;
- + else
- + droppedPics = -1;
- + return true;
- +}
- +
- +void CDVDVideoCodecFFmpeg::SetCodecControl(int flags)
- +{
- + m_codecControlFlags = flags;
- +}
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
- index 2287031..827c9507 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
- @@ -45,6 +45,7 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec
- virtual int Check (AVCodecContext* avctx) = 0;
- virtual void Reset () {}
- virtual unsigned GetAllowedReferences() { return 0; }
- + virtual bool CanSkipDeint() {return false; }
- virtual const std::string Name() = 0;
- virtual CCriticalSection* Section() { return NULL; }
- };
- @@ -62,6 +63,8 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec
- virtual const char* GetName() { return m_name.c_str(); }; // m_name is never changed after open
- virtual unsigned GetConvergeCount();
- virtual unsigned GetAllowedReferences();
- + virtual bool GetCodecStats(double &pts, int &droppedPics);
- + virtual void SetCodecControl(int flags);
-
- bool IsHardwareAllowed() { return !m_bSoftware; }
- IHardwareDecoder * GetHardware() { return m_pHardware; };
- @@ -127,4 +130,8 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec
- double m_dts;
- bool m_started;
- std::vector<PixelFormat> m_formats;
- + double m_decoderPts, m_decoderInterval;
- + int m_skippedDeint;
- + bool m_requestSkipDeint;
- + int m_codecControlFlags;
- };
- diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
- index fddb7f7..181ff74 100644
- --- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
- +++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
- @@ -38,6 +38,7 @@
- #include "DVDCodecs/DVDCodecs.h"
- #include "DVDCodecs/Overlay/DVDOverlayCodecCC.h"
- #include "DVDCodecs/Overlay/DVDOverlaySSA.h"
- +#include "guilib/GraphicContext.h"
- #include <sstream>
- #include <iomanip>
- #include <numeric>
- @@ -320,8 +321,10 @@ void CDVDPlayerVideo::Process()
-
- int iDropped = 0; //frames dropped in a row
- bool bRequestDrop = false;
- + int iDropDirective;
-
- m_videoStats.Start();
- + m_droppingStats.Reset();
-
- while (!m_bStop)
- {
- @@ -436,6 +439,7 @@ void CDVDPlayerVideo::Process()
- picture.iFlags &= ~DVP_FLAG_ALLOCATED;
- m_packets.clear();
- m_started = false;
- + m_droppingStats.Reset();
- }
- else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (CDVDPlayerVideo::Flush())
- {
- @@ -448,6 +452,7 @@ void CDVDPlayerVideo::Process()
- //we need to recalculate the framerate
- //TODO: this needs to be set on a streamchange instead
- ResetFrameRateCalc();
- + m_droppingStats.Reset();
-
- m_stalled = true;
- m_started = false;
- @@ -467,6 +472,7 @@ void CDVDPlayerVideo::Process()
- m_iNrOfPicturesNotToSkip = 0;
- if (m_pVideoCodec)
- m_pVideoCodec->SetSpeed(m_speed);
- + m_droppingStats.Reset();
- }
- else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED))
- {
- @@ -515,6 +521,28 @@ void CDVDPlayerVideo::Process()
- m_iNrOfPicturesNotToSkip = 1;
- }
-
- + bRequestDrop = false;
- + iDropDirective = CalcDropRequirement(pts);
- + if (iDropDirective & EOS_VERYLATE)
- + {
- + if (m_bAllowDrop)
- + {
- + m_pullupCorrection.Flush();
- + bRequestDrop = true;
- + }
- + }
- + int codecControl = 0;
- + if (iDropDirective & EOS_BUFFER_LEVEL)
- + codecControl |= DVP_FLAG_DRAIN;
- + if (m_speed > DVD_PLAYSPEED_NORMAL)
- + codecControl |= DVP_FLAG_NO_POSTPROC;
- + m_pVideoCodec->SetCodecControl(codecControl);
- + if (iDropDirective & EOS_DROPPED)
- + {
- + m_iDroppedFrames++;
- + iDropped++;
- + }
- +
- if (m_messageQueue.GetDataSize() == 0
- || m_speed < 0)
- {
- @@ -567,15 +595,7 @@ void CDVDPlayerVideo::Process()
- }
-
- m_videoStats.AddSampleBytes(pPacket->iSize);
- - // assume decoder dropped a picture if it didn't give us any
- - // picture from a demux packet, this should be reasonable
- - // for libavformat as a demuxer as it normally packetizes
- - // pictures when they come from demuxer
- - if(bRequestDrop && !bPacketDrop && (iDecoderState & VC_BUFFER) && !(iDecoderState & VC_PICTURE))
- - {
- - m_iDroppedFrames++;
- - iDropped++;
- - }
- +
- // reset the request, the following while loop may break before
- // setting the flag to a new value
- bRequestDrop = false;
- @@ -1185,33 +1205,12 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
- m_FlipTimeStamp += max(0.0, iSleepTime);
- m_FlipTimeStamp += iFrameDuration;
-
- - if (iSleepTime <= 0 && m_speed)
- - m_iLateFrames++;
- - else
- - m_iLateFrames = 0;
- -
- - // ask decoder to drop frames next round, as we are very late
- - if(m_iLateFrames > 10)
- + if ((pPicture->iFlags & DVP_FLAG_DROPPED))
- {
- - if (!(pPicture->iFlags & DVP_FLAG_NOSKIP))
- - {
- - //if we're calculating the framerate,
- - //don't drop frames until we've calculated a stable framerate
- - if (m_bAllowDrop || m_speed != DVD_PLAYSPEED_NORMAL)
- - {
- - result |= EOS_VERYLATE;
- - m_pullupCorrection.Flush(); //dropped frames mess up the pattern, so just flush it
- - }
- - m_iDroppedRequest++;
- - }
- - }
- - else
- - {
- - m_iDroppedRequest = 0;
- - }
- -
- - if( (pPicture->iFlags & DVP_FLAG_DROPPED) )
- + m_droppingStats.AddOutputDropGain(pts, 1/m_fFrameRate);
- + CLog::Log(LOGDEBUG,"%s - dropped in output", __FUNCTION__);
- return result | EOS_DROPPED;
- + }
-
- // set fieldsync if picture is interlaced
- EFIELDSYNC mDisplayField = FS_NONE;
- @@ -1244,7 +1243,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
- if (index < 0)
- return EOS_DROPPED;
-
- - g_renderManager.FlipPage(CThread::m_bStop, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, -1, mDisplayField);
- + g_renderManager.FlipPage(CThread::m_bStop, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, pts, -1, mDisplayField);
-
- return result;
- #else
- @@ -1544,3 +1543,131 @@ void CDVDPlayerVideo::CalcFrameRate()
- m_iFrameRateCount = 0;
- }
- }
- +
- +int CDVDPlayerVideo::CalcDropRequirement(double pts)
- +{
- + int result = 0;
- + double iSleepTime;
- + double iDecoderPts, iRenderPts;
- + double iInterval;
- + double iGain;
- + double iLateness;
- + bool bNewFrame;
- + int iDroppedPics = -1;
- + int iBufferLevel;
- +
- + // get decoder stats
- + if (!m_pVideoCodec->GetCodecStats(iDecoderPts, iDroppedPics))
- + iDecoderPts = pts;
- + if (iDecoderPts == DVD_NOPTS_VALUE)
- + iDecoderPts = pts;
- +
- + // get render stats
- + g_renderManager.GetStats(iSleepTime, iRenderPts, iBufferLevel);
- +
- + if (iBufferLevel < 0)
- + result |= EOS_BUFFER_LEVEL;
- + else if (iBufferLevel < 2)
- + {
- + result |= EOS_BUFFER_LEVEL;
- + CLog::Log(LOGDEBUG,"CDVDPlayerVideo::CalcDropRequirement - hurry: %d", iBufferLevel);
- + }
- +
- + bNewFrame = iDecoderPts != m_droppingStats.m_lastDecoderPts;
- +
- + iInterval = 1/m_fFrameRate*(double)DVD_TIME_BASE;
- +
- + m_FlipTimeStamp = m_pClock->GetAbsoluteClock() + max(0.0, iSleepTime) + iInterval;
- +
- + if (m_stalled)
- + m_iCurrentPts = DVD_NOPTS_VALUE;
- + else
- + m_iCurrentPts = iRenderPts - max(0.0, iSleepTime);
- +
- + if (m_droppingStats.m_lastDecoderPts > 0
- + && bNewFrame
- + && m_bAllowDrop)
- + {
- + iGain = (iDecoderPts - m_droppingStats.m_lastDecoderPts - iInterval)/(double)DVD_TIME_BASE;
- + if (iDroppedPics > 0)
- + {
- + CDroppingStats::CGain gain;
- + gain.gain = iDroppedPics * 1/m_fFrameRate;
- + gain.pts = iDecoderPts;
- + m_droppingStats.m_gain.push_back(gain);
- + m_droppingStats.m_totalGain += gain.gain;
- + result |= EOS_DROPPED;
- + m_droppingStats.m_dropRequests = 0;
- + CLog::Log(LOGDEBUG,"CDVDPlayerVideo::CalcDropRequirement - dropped pictures, Sleeptime: %f, Bufferlevel: %d, Gain: %f", iSleepTime, iBufferLevel, iGain);
- + }
- + else if (iDroppedPics < 0 && iGain > 1/m_fFrameRate)
- + {
- + CDroppingStats::CGain gain;
- + gain.gain = iGain;
- + gain.pts = iDecoderPts;
- + m_droppingStats.m_gain.push_back(gain);
- + m_droppingStats.m_totalGain += iGain;
- + result |= EOS_DROPPED;
- + m_droppingStats.m_dropRequests = 0;
- + CLog::Log(LOGDEBUG,"CDVDPlayerVideo::CalcDropRequirement - dropped in decoder, Sleeptime: %f, Bufferlevel: %d, Gain: %f", iSleepTime, iBufferLevel, iGain);
- + }
- + }
- + m_droppingStats.m_lastDecoderPts = iDecoderPts;
- +
- + // subtract gains
- + while (!m_droppingStats.m_gain.empty() &&
- + iRenderPts >= m_droppingStats.m_gain.front().pts)
- + {
- + m_droppingStats.m_totalGain -= m_droppingStats.m_gain.front().gain;
- + m_droppingStats.m_gain.pop_front();
- + }
- +
- + // calculate lateness
- + iLateness = iSleepTime + m_droppingStats.m_totalGain;
- + if (iLateness < 0 && m_speed)
- + {
- + if (bNewFrame)
- + m_droppingStats.m_lateFrames++;
- +
- + // if lateness is smaller than frametime, we observe this state
- + // for 10 cycles
- + if (m_droppingStats.m_lateFrames > 10 || iLateness < -2/m_fFrameRate)
- + {
- + // is frame allowed to skip
- + if (m_iNrOfPicturesNotToSkip <= 0)
- + {
- + if (bNewFrame || m_droppingStats.m_dropRequests < 5)
- + {
- + result |= EOS_VERYLATE;
- + }
- + m_droppingStats.m_dropRequests++;
- + }
- + }
- + }
- + else
- + {
- + m_droppingStats.m_dropRequests = 0;
- + m_droppingStats.m_lateFrames = 0;
- + }
- + m_droppingStats.m_lastRenderPts = iRenderPts;
- + return result;
- +}
- +
- +void CDroppingStats::Reset()
- +{
- + m_gain.clear();
- + m_totalGain = 0;
- + m_lastDecoderPts = 0;
- + m_lastRenderPts = 0;
- + m_lateFrames = 0;
- + m_dropRequests = 0;
- +}
- +
- +void CDroppingStats::AddOutputDropGain(double pts, double frametime)
- +{
- + CDroppingStats::CGain gain;
- + gain.gain = frametime;
- + gain.pts = pts;
- + m_gain.push_back(gain);
- + m_totalGain += frametime;
- +}
- diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
- index f8ad541..186e271 100644
- --- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h
- +++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
- @@ -36,6 +36,25 @@ class CDVDOverlayCodecCC;
-
- #define VIDEO_PICTURE_QUEUE_SIZE 1
-
- +class CDroppingStats
- +{
- +public:
- + void Reset();
- + void AddOutputDropGain(double pts, double frametime);
- + struct CGain
- + {
- + double gain;
- + double pts;
- + };
- + std::deque<CGain> m_gain;
- + double m_totalGain;
- + double m_lastDecoderPts;
- + double m_lastRenderPts;
- + unsigned int m_lateFrames;
- + unsigned int m_dropRequests;
- +};
- +
- +
- class CDVDPlayerVideo : public CThread
- {
- public:
- @@ -104,6 +123,7 @@ class CDVDPlayerVideo : public CThread
- #define EOS_ABORT 1
- #define EOS_DROPPED 2
- #define EOS_VERYLATE 4
- +#define EOS_BUFFER_LEVEL 8
-
- void AutoCrop(DVDVideoPicture* pPicture);
- void AutoCrop(DVDVideoPicture *pPicture, RECT &crop);
- @@ -129,6 +149,7 @@ class CDVDPlayerVideo : public CThread
-
- void ResetFrameRateCalc();
- void CalcFrameRate();
- + int CalcDropRequirement(double pts);
-
- double m_fFrameRate; //framerate of the video currently playing
- bool m_bCalcFrameRate; //if we should calculate the framerate from the timestamps
- @@ -182,5 +203,7 @@ class CDVDPlayerVideo : public CThread
- CPullupCorrection m_pullupCorrection;
-
- std::list<DVDMessageListItem> m_packets;
- +
- + CDroppingStats m_droppingStats;
- };
-
- --
- 1.9.3
- From 16d2c2ee305eb2cd3ec42fd0aad474dbf356d75d Mon Sep 17 00:00:00 2001
- From: xbmc <fernetmenta@online.de>
- Date: Sun, 2 Sep 2012 16:05:21 +0200
- Subject: [PATCH 85/94] video player: present correct pts to user for a/v sync
- (after buffering in renderer)
- ---
- xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 16 ++++++++++++++++
- xbmc/cores/dvdplayer/DVDPlayerVideo.h | 2 +-
- 2 files changed, 17 insertions(+), 1 deletion(-)
- diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
- index 181ff74..01757cc 100644
- --- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
- +++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
- @@ -1463,6 +1463,22 @@ void CDVDPlayerVideo::ResetFrameRateCalc()
- g_advancedSettings.m_videoFpsDetect == 0;
- }
-
- +double CDVDPlayerVideo::GetCurrentPts()
- +{
- + double iSleepTime, iRenderPts;
- + int iBufferLevel;
- +
- + // get render stats
- + g_renderManager.GetStats(iSleepTime, iRenderPts, iBufferLevel);
- +
- + if( m_stalled )
- + iRenderPts = DVD_NOPTS_VALUE;
- + else
- + iRenderPts = iRenderPts - max(0.0, iSleepTime);
- +
- + return iRenderPts;
- +}
- +
- #define MAXFRAMERATEDIFF 0.01
- #define MAXFRAMESERR 1000
-
- diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
- index 186e271..59c7f09 100644
- --- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h
- +++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
- @@ -100,7 +100,7 @@ class CDVDPlayerVideo : public CThread
-
- bool InitializedOutputDevice();
-
- - double GetCurrentPts() { return m_iCurrentPts; }
- + double GetCurrentPts();
- int GetPullupCorrection() { return m_pullupCorrection.GetPatternLength(); }
-
- double GetOutputDelay(); /* returns the expected delay, from that a packet is put in queue */
- --
- 1.9.3
- From afa38b57afee02720263e2db79d20e1411461433 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Mon, 12 May 2014 23:06:43 +0100
- Subject: [PATCH 86/94] [omxcodec] Updates to work better with dropping and
- lateness detection
- ---
- .../DVDCodecs/Video/DVDVideoCodecOpenMax.cpp | 5 ++
- .../DVDCodecs/Video/DVDVideoCodecOpenMax.h | 1 +
- .../dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 95 ++++++++++++++++------
- .../cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h | 9 +-
- 4 files changed, 84 insertions(+), 26 deletions(-)
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp
- index ef10555..8323497 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp
- @@ -91,4 +91,9 @@ bool CDVDVideoCodecOpenMax::ClearPicture(DVDVideoPicture* pDvdVideoPicture)
- return m_omx_decoder->ClearPicture(pDvdVideoPicture);
- }
-
- +bool CDVDVideoCodecOpenMax::GetCodecStats(double &pts, int &droppedPics)
- +{
- + return m_omx_decoder->GetCodecStats(pts, droppedPics);
- +}
- +
- #endif
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h
- index b7c0c1b..4f243df 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h
- @@ -41,6 +41,7 @@ class CDVDVideoCodecOpenMax : public CDVDVideoCodec
- virtual unsigned GetAllowedReferences();
- virtual void SetDropState(bool bDrop);
- virtual const char* GetName(void);
- + virtual bool GetCodecStats(double &pts, int &droppedPics);
-
- protected:
- OpenMaxVideoPtr m_omx_decoder;
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- index 71d19af..93cf521 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- @@ -37,6 +37,7 @@
- #include "ApplicationMessenger.h"
- #include "Application.h"
- #include "threads/Atomics.h"
- +#include "guilib/GUIWindowManager.h"
-
- #include <IL/OMX_Core.h>
- #include <IL/OMX_Component.h>
- @@ -57,6 +58,7 @@
-
- #define OMX_BUFFERFLAG_PTS_INVALID (1<<28)
- #define OMX_BUFFERFLAG_DROPPED (1<<29)
- +#define OMX_BUFFERFLAG_FIRST_FIELD (1<<30)
-
- COpenMaxVideoBuffer::COpenMaxVideoBuffer(COpenMaxVideo *omv)
- : m_omv(omv), m_refs(0)
- @@ -139,8 +141,11 @@ COpenMaxVideo::COpenMaxVideo()
-
- m_deinterlace = false;
- m_deinterlace_request = VS_DEINTERLACEMODE_OFF;
- - m_deinterlace_second_field = false;
- m_startframe = false;
- + m_decoderPts = DVD_NOPTS_VALUE;
- + m_droppedPics = 0;
- + m_decode_frame_number = 1;
- + m_skipDeinterlaceFields = false;
- }
-
- COpenMaxVideo::~COpenMaxVideo()
- @@ -369,7 +374,10 @@ void COpenMaxVideo::Dispose()
- m_finished = true;
- pthread_mutex_unlock(&m_omx_output_mutex);
- if (done)
- + {
- + assert(m_dts_queue.empty());
- m_myself.reset();
- + }
- }
-
- void COpenMaxVideo::SetDropState(bool bDrop)
- @@ -730,6 +738,7 @@ int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
- omx_buffer->nFilledLen = (demuxer_bytes > omx_buffer->nAllocLen) ? omx_buffer->nAllocLen : demuxer_bytes;
- omx_buffer->nTimeStamp = ToOMXTime((uint64_t)(pts == DVD_NOPTS_VALUE) ? 0 : pts);
- omx_buffer->pAppPrivate = omx_buffer;
- + omx_buffer->pMarkData = (OMX_PTR)m_decode_frame_number;
- memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen);
-
- demuxer_bytes -= omx_buffer->nFilledLen;
- @@ -742,12 +751,18 @@ int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
- omx_buffer->nFlags |= OMX_BUFFERFLAG_TIME_UNKNOWN;
- if (pts == DVD_NOPTS_VALUE) // hijack an omx flag to indicate there wasn't a real timestamp - it will be returned with the picture (but otherwise ignored)
- omx_buffer->nFlags |= OMX_BUFFERFLAG_PTS_INVALID;
- - if (m_drop_state) // hijack an omx flag to signal this frame to be dropped - it will be returned with the picture (but otherwise ignored)
- + if (m_drop_state)
- + {
- + // hijack an omx flag to signal this frame to be dropped - it will be returned with the picture (but otherwise ignored)
- omx_buffer->nFlags |= OMX_BUFFERFLAG_DECODEONLY | OMX_BUFFERFLAG_DROPPED;
- + m_droppedPics += m_deinterlace ? 2:1;
- + }
- + // always set this flag on input. It won't be set on second field of interlaced video.
- + omx_buffer->nFlags |= OMX_BUFFERFLAG_FIRST_FIELD;
-
- #if defined(OMX_DEBUG_VERBOSE)
- - CLog::Log(LOGDEBUG, "%s::%s - %-6d dts:%.3f pts:%.3f flags:%x",
- - CLASSNAME, __func__, omx_buffer->nFilledLen, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, omx_buffer->nFlags);
- + CLog::Log(LOGDEBUG, "%s::%s - %-6d dts:%.3f pts:%.3f flags:%x frame:%d",
- + CLASSNAME, __func__, omx_buffer->nFilledLen, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, omx_buffer->nFlags, (int)omx_buffer->pMarkData);
- #endif
-
- omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
- @@ -758,13 +773,16 @@ int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
- }
- if (demuxer_bytes == 0)
- {
- + m_decode_frame_number++;
- m_startframe = true;
- #ifdef DTS_QUEUE
- if (!m_drop_state)
- {
- // only push if we are successful with feeding OMX_EmptyThisBuffer
- + pthread_mutex_lock(&m_omx_output_mutex);
- m_dts_queue.push(dts);
- assert(m_dts_queue.size() < 32);
- + pthread_mutex_unlock(&m_omx_output_mutex);
- }
- #endif
- if (buffer_to_free)
- @@ -840,13 +858,18 @@ void COpenMaxVideo::Reset(void)
- SetDropState(true);
- SetDropState(false);
- #ifdef DTS_QUEUE
- + pthread_mutex_lock(&m_omx_output_mutex);
- while (!m_dts_queue.empty())
- m_dts_queue.pop();
- + pthread_mutex_unlock(&m_omx_output_mutex);
- #endif
-
- while (!m_demux_queue.empty())
- m_demux_queue.pop();
- m_startframe = false;
- + m_decoderPts = DVD_NOPTS_VALUE;
- + m_droppedPics = 0;
- + m_decode_frame_number = 1;
- }
-
-
- @@ -928,26 +951,17 @@ bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture)
- }
- }
-
- -#ifdef DTS_QUEUE
- - if (!m_deinterlace_second_field)
- - {
- - assert(!m_dts_queue.empty());
- - pDvdVideoPicture->dts = m_dts_queue.front();
- - m_dts_queue.pop();
- - }
- - if (m_deinterlace)
- - m_deinterlace_second_field = !m_deinterlace_second_field;
- -#endif
- // nTimeStamp is in microseconds
- + pDvdVideoPicture->dts = buffer->dts;
- pDvdVideoPicture->pts = FromOMXTime(buffer->omx_buffer->nTimeStamp);
- pDvdVideoPicture->openMaxBuffer->Acquire();
- pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED;
- if (buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_PTS_INVALID)
- pDvdVideoPicture->pts = DVD_NOPTS_VALUE;
- #if defined(OMX_DEBUG_VERBOSE)
- - CLog::Log(LOGINFO, "%s::%s dts:%.3f pts:%.3f flags:%x:%x openMaxBuffer:%p omx_buffer:%p egl_image:%p texture_id:%x", CLASSNAME, __func__,
- + CLog::Log(LOGINFO, "%s::%s dts:%.3f pts:%.3f flags:%x:%x frame:%d openMaxBuffer:%p omx_buffer:%p egl_image:%p texture_id:%x", CLASSNAME, __func__,
- pDvdVideoPicture->dts == DVD_NOPTS_VALUE ? 0.0 : pDvdVideoPicture->dts*1e-6, pDvdVideoPicture->pts == DVD_NOPTS_VALUE ? 0.0 : pDvdVideoPicture->pts*1e-6,
- - pDvdVideoPicture->iFlags, buffer->omx_buffer->nFlags, pDvdVideoPicture->openMaxBuffer, pDvdVideoPicture->openMaxBuffer->omx_buffer, pDvdVideoPicture->openMaxBuffer->egl_image, pDvdVideoPicture->openMaxBuffer->texture_id);
- + pDvdVideoPicture->iFlags, buffer->omx_buffer->nFlags, (int)buffer->omx_buffer->pMarkData, pDvdVideoPicture->openMaxBuffer, pDvdVideoPicture->openMaxBuffer->omx_buffer, pDvdVideoPicture->openMaxBuffer->egl_image, pDvdVideoPicture->openMaxBuffer->texture_id);
- #endif
- assert(!(buffer->omx_buffer->nFlags & (OMX_BUFFERFLAG_DECODEONLY | OMX_BUFFERFLAG_DROPPED)));
- }
- @@ -956,6 +970,12 @@ bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture)
- CLog::Log(LOGERROR, "%s::%s - called but m_omx_output_ready is empty", CLASSNAME, __func__);
- return false;
- }
- +
- + if (pDvdVideoPicture->pts != DVD_NOPTS_VALUE)
- + m_decoderPts = pDvdVideoPicture->pts;
- + else
- + m_decoderPts = pDvdVideoPicture->dts; // xxx is DVD_NOPTS_VALUE better?
- +
- return true;
- }
-
- @@ -970,25 +990,54 @@ bool COpenMaxVideo::ClearPicture(DVDVideoPicture* pDvdVideoPicture)
- return true;
- }
-
- +bool COpenMaxVideo::GetCodecStats(double &pts, int &droppedPics)
- +{
- + pts = m_decoderPts;
- + droppedPics = m_droppedPics;
- + m_droppedPics = 0;
- + CLog::Log(LOGDEBUG, "%s::%s - pts:%.0f droppedPics:%d", CLASSNAME, __func__, pts, droppedPics);
- + return true;
- +}
- +
- // DecoderFillBufferDone -- OpenMax output buffer has been filled
- OMX_ERRORTYPE COpenMaxVideo::DecoderFillBufferDone(
- OMX_HANDLETYPE hComponent,
- OMX_BUFFERHEADERTYPE* pBuffer)
- {
- COpenMaxVideoBuffer *buffer = (COpenMaxVideoBuffer*)pBuffer->pAppPrivate;
- + bool skipDeinterlaceFields = m_skipDeinterlaceFields || g_windowManager.HasDialogOnScreen();
-
- #if defined(OMX_DEBUG_VERBOSE)
- - CLog::Log(LOGDEBUG, "%s::%s - %p (%p,%p) buffer_size(%u), pts:%.3f flags:%x",
- - CLASSNAME, __func__, buffer, pBuffer, buffer->omx_buffer, pBuffer->nFilledLen, (double)FromOMXTime(buffer->omx_buffer->nTimeStamp)*1e-6, buffer->omx_buffer->nFlags);
- + CLog::Log(LOGDEBUG, "%s::%s - %p (%p,%p) buffer_size(%u), pts:%.3f flags:%x frame:%d win:%x",
- + CLASSNAME, __func__, buffer, pBuffer, buffer->omx_buffer, pBuffer->nFilledLen, (double)FromOMXTime(buffer->omx_buffer->nTimeStamp)*1e-6, buffer->omx_buffer->nFlags, (int)buffer->omx_buffer->pMarkData, skipDeinterlaceFields);
- #endif
-
- assert(!(buffer->omx_buffer->nFlags & (OMX_BUFFERFLAG_DECODEONLY | OMX_BUFFERFLAG_DROPPED)));
- - // queue output omx buffer to ready list.
- - pthread_mutex_lock(&m_omx_output_mutex);
- - buffer->m_aspect_ratio = m_aspect_ratio;
- - m_omx_output_ready.push(buffer);
- - pthread_mutex_unlock(&m_omx_output_mutex);
-
- +
- + // flags have OMX_BUFFERFLAG_FIRST_FIELD set if this is a direct result of a submitted frame,
- + // clear for second field of deinterlaced frame. They are zero when frame is returned due to a flush.
- +#ifdef DTS_QUEUE
- + if ((!m_deinterlace || (buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_FIRST_FIELD)) && buffer->omx_buffer->nFlags)
- + {
- + pthread_mutex_lock(&m_omx_output_mutex);
- + assert(!m_dts_queue.empty());
- + buffer->dts = m_dts_queue.front();
- + m_dts_queue.pop();
- + pthread_mutex_unlock(&m_omx_output_mutex);
- + }
- +#endif
- + if (m_drop_state || (m_deinterlace && skipDeinterlaceFields && !(buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_FIRST_FIELD)))
- + {
- + ReturnOpenMaxBuffer(buffer);
- + }
- + else
- + {
- + buffer->m_aspect_ratio = m_aspect_ratio;
- + pthread_mutex_lock(&m_omx_output_mutex);
- + m_omx_output_ready.push(buffer);
- + pthread_mutex_unlock(&m_omx_output_mutex);
- + }
- return OMX_ErrorNone;
- }
-
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
- index f234f6d..adf53b5 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
- @@ -57,6 +57,7 @@ class COpenMaxVideoBuffer
- int height;
- float m_aspect_ratio;
- int index;
- + double dts;
-
- // used for egl based rendering if active
- EGLImageKHR egl_image;
- @@ -87,6 +88,7 @@ class COpenMaxVideo
- virtual unsigned GetAllowedReferences() { return 2; }
- virtual void SetDropState(bool bDrop);
- virtual const char* GetName(void) { return (const char*)m_pFormatName; }
- + virtual bool GetCodecStats(double &pts, int &droppedPics);
-
- // OpenMax decoder callback routines.
- OMX_ERRORTYPE DecoderFillBufferDone(OMX_HANDLETYPE hComponent, OMX_BUFFERHEADERTYPE* pBuffer);
- @@ -142,10 +144,11 @@ class COpenMaxVideo
-
- bool m_deinterlace;
- EDEINTERLACEMODE m_deinterlace_request;
- - bool m_deinterlace_second_field;
- -
- bool m_startframe;
- -
- + unsigned int m_decode_frame_number;
- + double m_decoderPts;
- + unsigned int m_droppedPics;
- + bool m_skipDeinterlaceFields;
- bool PortSettingsChanged();
- bool SendDecoderConfig(uint8_t *extradata, int extrasize);
- bool NaluFormatStartCodes(enum AVCodecID codec, uint8_t *extradata, int extrasize);
- --
- 1.9.3
- From 4dd2fcf0f479b6b18dac9a496ddf1788b82388f2 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Sun, 11 May 2014 16:13:45 +0100
- Subject: [PATCH 87/94] [rbp] Add config.txt settings to log file
- ---
- xbmc/linux/RBP.cpp | 8 +++++++-
- 1 file changed, 7 insertions(+), 1 deletion(-)
- diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp
- index 49dcbb8..9a5e9cb 100644
- --- a/xbmc/linux/RBP.cpp
- +++ b/xbmc/linux/RBP.cpp
- @@ -79,11 +79,17 @@ bool CRBP::Initialize()
-
- void CRBP::LogFirmwareVerison()
- {
- - char response[160];
- + char response[1024];
- m_DllBcmHost->vc_gencmd(response, sizeof response, "version");
- response[sizeof(response) - 1] = '\0';
- CLog::Log(LOGNOTICE, "Raspberry PI firmware version: %s", response);
- CLog::Log(LOGNOTICE, "ARM mem: %dMB GPU mem: %dMB MPG2:%d WVC1:%d", m_arm_mem, m_gpu_mem, m_codec_mpg2_enabled, m_codec_wvc1_enabled);
- + m_DllBcmHost->vc_gencmd(response, sizeof response, "get_config int");
- + response[sizeof(response) - 1] = '\0';
- + CLog::Log(LOGNOTICE, "Config:\n%s", response);
- + m_DllBcmHost->vc_gencmd(response, sizeof response, "get_config str");
- + response[sizeof(response) - 1] = '\0';
- + CLog::Log(LOGNOTICE, "Config:\n%s", response);
- }
-
- void CRBP::GetDisplaySize(int &width, int &height)
- --
- 1.9.3
- From eb2cba833f1399befcbd60901f3d97a08e3a2781 Mon Sep 17 00:00:00 2001
- From: Alex Deryskyba <alex@codesnake.com>
- Date: Thu, 8 May 2014 18:54:54 +0300
- Subject: [PATCH 88/94] Reset display region when video stream properties
- change
- Currently when video stream properties change, e.g. when user switches to next or previous Live TV channel, and has the same frame width and height, the COMXVideo::SetVideoRect() method is not called, causing the video to play back with default source and destination rectangles, not respecting the user-defined zoom settings.
- This commit fixes the issue.
- ---
- xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 3 +++
- 1 file changed, 3 insertions(+)
- diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- index 61b884e..eaa1e34 100644
- --- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- +++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
- @@ -781,6 +781,9 @@ void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, f
- return;
- }
-
- + m_src_rect.SetRect(0, 0, 0, 0);
- + m_dst_rect.SetRect(0, 0, 0, 0);
- +
- g_renderManager.RegisterRenderUpdateCallBack((const void*)this, RenderUpdateCallBack);
- }
-
- --
- 1.9.3
- From 7c369ba5ec4e700f5c06e1caa20095bc26e61195 Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Wed, 28 May 2014 23:44:11 +0100
- Subject: [PATCH 89/94] [omxplayer] Fix for mapping of multichannel PCM audio
- ---
- xbmc/cores/omxplayer/OMXAudio.cpp | 11 ++++++++---
- 1 file changed, 8 insertions(+), 3 deletions(-)
- diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp
- index d9beb68..75eff26 100644
- --- a/xbmc/cores/omxplayer/OMXAudio.cpp
- +++ b/xbmc/cores/omxplayer/OMXAudio.cpp
- @@ -606,13 +606,18 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
- if (m_InputChannels <= 2)
- stdLayout = AE_CH_LAYOUT_2_0;
-
- - uint64_t m_dst_chan_layout = GetAVChannelLayout(stdLayout);
- +
- + CAEChannelInfo resolvedMap = channelMap;
- + resolvedMap.ResolveChannels(stdLayout);
- + uint64_t m_dst_chan_layout = GetAVChannelLayout(resolvedMap);
- uint64_t m_src_chan_layout = GetAVChannelLayout(channelMap);
- - m_OutputChannels = stdLayout.Count();
- +
- + m_InputChannels = channelMap.Count();
- + m_OutputChannels = resolvedMap.Count();
-
- int m_dst_channels = m_OutputChannels;
- int m_src_channels = m_InputChannels;
- - SetAudioProps(m_Passthrough, GetChannelMap(stdLayout, m_Passthrough));
- + SetAudioProps(m_Passthrough, GetChannelMap(resolvedMap, m_Passthrough));
-
- CLog::Log(LOGINFO, "%s::%s remap:%p chan:%d->%d norm:%d upmix:%d %llx:%llx", CLASSNAME, __func__, remapLayout, m_src_channels, m_dst_channels, normalize, upmix, m_src_chan_layout, m_dst_chan_layout);
-
- --
- 1.9.3
- From 458ec80741e4aa1ae95fe616f5953e1268a4802e Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Fri, 30 May 2014 14:15:10 +0100
- Subject: [PATCH 90/94] [pi] Fix for logged resolutions
- ---
- xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 15 +++++----------
- 1 file changed, 5 insertions(+), 10 deletions(-)
- diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
- index 5b26b20..a3edf0e 100644
- --- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
- +++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
- @@ -483,10 +483,8 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
-
- if(resolutions.size() == 0)
- {
- - RESOLUTION_INFO res;
- - CLog::Log(LOGDEBUG, "EGL probe resolution %s:%x\n", m_desktopRes.strMode.c_str(), m_desktopRes.dwFlags);
- -
- AddUniqueResolution(m_desktopRes, resolutions);
- + CLog::Log(LOGDEBUG, "EGL probe resolution %s:%x\n", m_desktopRes.strMode.c_str(), m_desktopRes.dwFlags);
- }
-
- if(resolutions.size() < 2)
- @@ -576,13 +574,12 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
- res.iScreenWidth = tv->width;
- res.iScreenHeight = tv->height;
- res.fPixelRatio = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res.iScreenWidth / (float)res.iScreenHeight);
- + res.iSubtitles = (int)(0.965 * res.iHeight);
-
- + AddUniqueResolution(res, resolutions);
- CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f) %s%s:%x\n", i, res.strMode.c_str(), res.fPixelRatio,
- tv->native ? "N" : "", tv->scan_mode ? "I" : "", tv->code);
-
- - res.iSubtitles = (int)(0.965 * res.iHeight);
- -
- - AddUniqueResolution(res, resolutions);
- if (tv->frame_rate == 24 || tv->frame_rate == 30 || tv->frame_rate == 60)
- {
- RESOLUTION_INFO res2 = res;
- @@ -596,11 +593,10 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
- RESOLUTION_INFO res2 = res;
- res2.dwFlags |= D3DPRESENTFLAG_MODE3DSBS;
- res2.fPixelRatio = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight);
- - CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f)\n", i, res2.strMode.c_str(), res2.fPixelRatio);
- -
- res2.iSubtitles = (int)(0.965 * res2.iHeight);
-
- AddUniqueResolution(res2, resolutions);
- + CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f)\n", i, res2.strMode.c_str(), res2.fPixelRatio);
- if (tv->frame_rate == 24 || tv->frame_rate == 30 || tv->frame_rate == 60)
- {
- res2.fRefreshRate = (float)tv->frame_rate * (1000.0f/1001.0f);
- @@ -612,11 +608,10 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
- RESOLUTION_INFO res2 = res;
- res2.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
- res2.fPixelRatio = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight);
- - CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f)\n", i, res2.strMode.c_str(), res2.fPixelRatio);
- -
- res2.iSubtitles = (int)(0.965 * res2.iHeight);
-
- AddUniqueResolution(res2, resolutions);
- + CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f)\n", i, res2.strMode.c_str(), res2.fPixelRatio);
- if (tv->frame_rate == 24 || tv->frame_rate == 30 || tv->frame_rate == 60)
- {
- res2.fRefreshRate = (float)tv->frame_rate * (1000.0f/1001.0f);
- --
- 1.9.3
- From 9eb0d69eb1f319421780025cefe6df3ade40c4dc Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Sat, 7 Jun 2014 16:55:41 +0100
- Subject: [PATCH 91/94] [omx] Remove logging for texture jobs
- This causes a lot of log spam which hasn't proved useful so far.
- ---
- xbmc/cores/omxplayer/OMXImage.cpp | 5 -----
- 1 file changed, 5 deletions(-)
- diff --git a/xbmc/cores/omxplayer/OMXImage.cpp b/xbmc/cores/omxplayer/OMXImage.cpp
- index 262a004..d529b20 100644
- --- a/xbmc/cores/omxplayer/OMXImage.cpp
- +++ b/xbmc/cores/omxplayer/OMXImage.cpp
- @@ -210,13 +210,11 @@ bool COMXImage::SendMessage(bool (*callback)(EGLDisplay egl_display, EGLContext
- mess.sync.Reset();
- {
- CSingleLock lock(m_texqueue_lock);
- - CLog::Log(LOGDEBUG, "%s: texture job: %p:%p", __func__, &mess, mess.callback);
- m_texqueue.push(&mess);
- m_texqueue_cond.notifyAll();
- }
- // wait for function to have finished (in texture thread)
- mess.sync.Wait();
- - CLog::Log(LOGDEBUG, "%s: texture job done: %p:%p = %d", __func__, &mess, mess.callback, mess.result);
- // need to ensure texture thread has returned from mess.sync.Set() before we exit and free tex
- CSingleLock lock(m_texqueue_lock);
- return mess.result;
- @@ -429,15 +427,12 @@ void COMXImage::Process()
- struct callbackinfo *mess = m_texqueue.front();
- m_texqueue.pop();
- lock.Leave();
- - CLog::Log(LOGDEBUG, "%s: texture job: %p:%p:%p", __func__, mess, mess->callback, mess->cookie);
-
- mess->result = mess->callback(g_Windowing.GetEGLDisplay(), GetEGLContext(), mess->cookie);
- - CLog::Log(LOGDEBUG, "%s: texture job about to Set: %p:%p:%p", __func__, mess, mess->callback, mess->cookie);
- {
- CSingleLock lock(m_texqueue_lock);
- mess->sync.Set();
- }
- - CLog::Log(LOGDEBUG, "%s: texture job: %p done", __func__, mess);
- }
- }
- }
- --
- 1.9.3
- From 4c7a42273416f4053a5bb90755ea45cc0a5f7a0b Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Sun, 15 Jun 2014 13:20:53 +0100
- Subject: [PATCH 92/94] gles: Avoid crash when capturing snapshot when using
- dvdplayer
- Note: snapshot will be blank, but that's better than crashing
- ---
- xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 2 ++
- 1 file changed, 2 insertions(+)
- diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
- index e22a153..0cff2c5 100644
- --- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
- +++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
- @@ -1600,7 +1600,9 @@ bool CLinuxRendererGLES::RenderCapture(CRenderCapture* capture)
- return false;
-
- // If rendered directly by the hardware
- +#ifndef TARGET_RASPBERRY_PI
- if (m_renderMethod & RENDER_BYPASS)
- +#endif
- {
- capture->BeginRender();
- capture->EndRender();
- --
- 1.9.3
- From 9805b1c9b218f8ba15c41752cc88f6e8bc3223ad Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Wed, 28 May 2014 18:30:51 +0100
- Subject: [PATCH 93/94] [omxcodec] Reduce GPU memory use by 2 video frames
- ---
- xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 14 ++++++++++++++
- 1 file changed, 14 insertions(+)
- diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- index 93cf521..cc45570 100644
- --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
- @@ -308,6 +308,20 @@ bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenM
- return false;
- }
-
- + {
- + // as we aren't tunnelled to display, we can save memory by setting extrabuffers to 0
- + OMX_PARAM_U32TYPE extra_buffers;
- + OMX_INIT_STRUCTURE(extra_buffers);
- + extra_buffers.nU32 = 0;
- +
- + omx_err = m_omx_decoder.SetParameter(OMX_IndexParamBrcmExtraBuffers, &extra_buffers);
- + if(omx_err != OMX_ErrorNone)
- + {
- + CLog::Log(LOGERROR, "COMXVideo::Open error OMX_IndexParamBrcmExtraBuffers omx_err(0x%08x)\n", omx_err);
- + return false;
- + }
- + }
- +
- // request portsettingschanged on aspect ratio change
- OMX_CONFIG_REQUESTCALLBACKTYPE notifications;
- OMX_INIT_STRUCTURE(notifications);
- --
- 1.9.3
- From 1b49a6f5b1655918e26d84ca4260fc249c00022f Mon Sep 17 00:00:00 2001
- From: popcornmix <popcornmix@gmail.com>
- Date: Wed, 18 Jun 2014 23:11:28 +0100
- Subject: [PATCH 94/94] [rbp] Reduce GPU memory use when limited
- Switching from default triple buffered output to double buffered saves 8M with 1080p GUI.
- This may slightly reduce framerate, but is likely to be minimal.
- Assume if gpu_mem is set below the default 128M that this memory reduction is wanted
- ---
- xbmc/linux/RBP.cpp | 3 +++
- 1 file changed, 3 insertions(+)
- diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp
- index 9a5e9cb..50d5186 100644
- --- a/xbmc/linux/RBP.cpp
- +++ b/xbmc/linux/RBP.cpp
- @@ -72,6 +72,9 @@ bool CRBP::Initialize()
- if (vc_gencmd(response, sizeof response, "codec_enabled WVC1") == 0)
- m_codec_wvc1_enabled = strcmp("WVC1=enabled", response) == 0;
-
- + if (m_gpu_mem < 128)
- + setenv("V3D_DOUBLE_BUFFER", "1", 1);
- +
- g_OMXImage.Initialize();
- m_omx_image_init = true;
- return true;
- --
- 1.9.3
|