Kako radi video kodek? Dio 2. Što, zašto, kako

Prvi dio: Osnove rada s videom i slikama

Kako radi video kodek? Dio 2. Što, zašto, kako

Što je? Video kodek je softver/hardver koji komprimira i/ili dekomprimira digitalni video.

Za što? Unatoč određenim ograničenjima i u pogledu propusnosti i
A što se tiče prostora za pohranu, tržište zahtijeva sve kvalitetnije videozapise. Sjećate li se kako smo u prošloj objavi izračunali minimalni potreban broj za 30 sličica u sekundi, 24 bita po pikselu i rezoluciju od 480x240? Dobili smo 82,944 Mbps bez kompresije. Kompresija je trenutno jedini način za isporuku HD/FullHD/4K na TV ekrane i internet. Kako se to postiže? Sada ukratko pregledajmo glavne metode.

Kako radi video kodek? Dio 2. Što, zašto, kako

Prijevod je napravljen uz podršku EDISON Software.

Mi smo angažirani u integracija sustava video nadzoraI Razvijamo mikrotomograf.

Kodek u odnosu na kontejner

Uobičajena pogreška početnika je brkanje digitalnog video kodeka s digitalnim video spremnikom. Spremnik je određeni format, omotač koji sadrži video metapodatke (i moguće zvuk). Komprimirani video može se smatrati korisnim teretom spremnika.

Tipično, ekstenzija video datoteke označava vrstu spremnika. Na primjer, datoteka video.mp4 vjerojatno je spremnik MPEG-4, dio 14, a datoteka pod nazivom video.mkv je najvjerojatnije matrjoška lutkaDa biste bili potpuno sigurni u format kodeka i spremnika, možete koristiti FFmpeg ili MediaInfo.

Malo povijesti

Prije nego što prijeđemo na Kako?, zaronimo malo u povijest kako bismo bolje razumjeli neke od starijih kodeka.

Video kodek H.261 Pojavio se 1990. (tehnički, 1988.) i bio je dizajniran za rad s brzinom prijenosa podataka od 64 kbps. Već je koristio ideje poput chroma subsamplinga, makroblokova itd. Godine 1995. objavljen je standard video kodeka. H.263, koji se razvijao do 2001.

Prva verzija je završena 2003. godine. H.264 / AVCIste godine, TrueMotion je izdao svoj besplatni video kodek s gubitkom pod nazivom VP3Google je 2008. godine kupio tvrtku i objavio VP8 iste godine. U prosincu 2012. Google je objavio VP9, a podržava ga otprilike ¾ tržišta preglednika (uključujući mobilne uređaje).

AV1 je novi besplatni video kodek otvorenog koda koji je razvio Savez za otvorene medije (AOMedia), koji uključuje renomirane tvrtke poput Googlea, Mozille, Microsofta, Amazona, Netflixa, AMD-a, ARM-a, NVidie, Intela i Cisca. Prva verzija kodeka, verzija 0.1.0, objavljena je 7. travnja 2016.

Rođenje AV1

Početkom 2015. godine, Google je radio na VP10Xiph (koji je u vlasništvu Mozille) je radio na daala, a Cisco je napravio vlastiti besplatni video kodek pod nazivom Thor.

tada MPEG LA prvi objavljeni godišnji limiti za HEVC (H.265) i naknadu 8 puta veću nego za H.264, ali ubrzo su opet promijenili pravila:

bez godišnjeg ograničenja,
naknada za sadržaj (0,5% prihoda) i
Jedinična cijena je otprilike 10 puta veća od H.264.

Savez za otvorene medije kreirale su ga tvrtke iz raznih područja: proizvođači opreme (Intel, AMD, ARM, Nvidia, Cisco), pružatelji sadržaja (Google, Netflix, Amazon), kreatori preglednika (Google, Mozilla) i drugi.

Tvrtke su imale zajednički cilj: video kodek bez autorskih prava. Tada se pojavio AV1 s puno jednostavnijom patentnom licencom. Timothy B. Terryberry održao je zapanjujuću prezentaciju koja je postala izvor trenutnog AV1 koncepta i njegovog modela licenciranja.

Iznenadit ćete se kada saznate da AV1 kodek možete analizirati putem preglednika (zainteresirani mogu otići na adresu aomanalyzer.org).

Kako radi video kodek? Dio 2. Što, zašto, kako

Univerzalni kodek

Ispitajmo osnovne mehanizme koji leže u osnovi univerzalnog video kodeka. Većina ovih koncepata je korisna i koristi se u modernim kodecima, kao što su VP9, AV1 и HEVCImajte na umu da će mnoga objašnjenja biti pojednostavljena. Ponekad će se za demonstraciju tehnologija koristiti primjeri iz stvarnog svijeta (kao u slučaju H.264).

Korak 1 - Podjela slike

Prvi korak je podjela okvira na nekoliko dijelova, poddijelova i tako dalje.

Kako radi video kodek? Dio 2. Što, zašto, kako

Zašto? Postoji mnogo razloga. Kada podijelimo sliku, možemo preciznije predvidjeti vektor kretanja korištenjem manjih dijelova za male pokretne dijelove. Dok za statičnu pozadinu veći dijelovi mogu biti dovoljni.

Kodeci obično organiziraju ove dijelove u dijelove (ili fragmente), makroblokove (ili blokove stabla kodiranja) i više poddijelova. Maksimalna veličina ovih dijelova varira: HEVC specificira 64x64, dok AVC koristi 16x16, a poddijelovi mogu biti mali i do 4x4.

Sjećate se tipova okvira iz prošlog članka?! Isto se može primijeniti i na blokove, pa možemo imati I-fragment, B-blok, P-makroblok i tako dalje.

Za one koji žele vježbati, pogledajte kako je slika podijeljena na dijelove i poddijelove. Za to možete koristiti tehniku ​​spomenutu u prethodnom članku. Intel Video Pro analizator (ona koja se plaća, ali ima besplatnu probnu verziju koja ima ograničenje na prvih 10 kadrova). Evo analiziranih dijelova VP9:

Kako radi video kodek? Dio 2. Što, zašto, kako

Korak 2 - Predviđanje

Nakon što imamo dijelove, možemo za njih izrađivati ​​astrološke prognoze. INTER-prognoziranje mora se prenijeti vektori gibanja i ostatak, a za INTRA-prognoziranje se prenosi smjer prognoze i ostatak.

Korak 3 - Transformacija

Nakon što dobijemo rezidualni blok (predviđena particija → stvarna particija), možemo ga transformirati kako bismo odredili koji se pikseli mogu odbaciti uz zadržavanje ukupne kvalitete. Postoje neke transformacije koje osiguravaju precizno ponašanje.

Iako postoje i druge metode, pogledajmo ih detaljnije. diskretna kosinusna transformacija (DCT - od diskretna kosinusna transformacijaGlavne funkcije DCT-a:

  • Pretvara blokove piksela u blokove jednake veličine s frekvencijskim koeficijentima.
  • Smanjuje snagu, pomažući u uklanjanju prostorne redundantnosti.
  • Pruža reverzibilnost.

Dana 2. veljače 2017., Cintra, RJ i Bayer, FM objavili su rad o DCT-sličnoj transformaciji za kompresiju slike koja zahtijeva samo 14 popunjavanja.

Ne brinite ako ne razumijete prednosti svake točke. Sada pogledajmo njihovu pravu vrijednost s nekim konkretnim primjerima.

Uzmimo takav blok piksela 8x8:

Kako radi video kodek? Dio 2. Što, zašto, kako

Ovaj blok se renderira u sljedeću sliku veličine 8 x 8 piksela:

Kako radi video kodek? Dio 2. Što, zašto, kako

Primjenjujemo DCT na ovaj blok piksela i dobivamo blok koeficijenata veličine 8×8:

Kako radi video kodek? Dio 2. Što, zašto, kako

A ako prikažemo ovaj blok koeficijenata, dobit ćemo sljedeću sliku:

Kako radi video kodek? Dio 2. Što, zašto, kako

Kao što vidimo, ovo ne nalikuje originalnoj slici. Možete vidjeti da se prvi koeficijent značajno razlikuje od svih ostalih. Ovaj prvi koeficijent poznat je kao DC koeficijent, koji predstavlja sve uzorke u ulaznom nizu, nešto poput prosječne vrijednosti.

Ovaj blok koeficijenata ima zanimljivo svojstvo: odvaja visokofrekventne komponente od niskofrekventnih.

Kako radi video kodek? Dio 2. Što, zašto, kako

Na slici je većina snage koncentrirana na nižim frekvencijama, pa pretvaranjem slike u njezine frekvencijske komponente i odbacivanjem koeficijenata viših frekvencija možete smanjiti količinu podataka potrebnih za opis slike bez žrtvovanja prevelike kvalitete slike.

Frekvencija se odnosi na brzinu kojom se signal mijenja.

Pokušajmo primijeniti stečeno znanje u testnom primjeru transformirajući izvornu sliku u njezinu frekvenciju (blok koeficijenata) pomoću DCT-a, a zatim odbacivši neke od najmanje važnih koeficijenata.

Prvo, pretvaramo ga u frekvencijsku domenu.

Kako radi video kodek? Dio 2. Što, zašto, kako

Zatim odbacujemo dio (67%) koeficijenata, uglavnom donji desni dio.

Kako radi video kodek? Dio 2. Što, zašto, kako

Konačno, rekonstruiramo sliku iz ovog odbačenog bloka koeficijenata (zapamtite, mora biti invertibilan) i uspoređujemo je s originalom.

Kako radi video kodek? Dio 2. Što, zašto, kako

Vidimo da nalikuje originalnoj slici, ali postoje mnoge razlike u odnosu na original. Odbacili smo 67,1875% i ipak dobili nešto što nalikuje originalu. Mogli smo pažljivije odbaciti koeficijente kako bismo dobili još kvalitetniju sliku, ali to je tema za neki drugi dan.

Svaki koeficijent se formira korištenjem svih piksela

Važno: Svaki koeficijent nije izravno mapiran na jedan piksel, već je ponderirani zbroj svih piksela. Ovaj nevjerojatan graf prikazuje kako se prvi i drugi koeficijent izračunavaju pomoću težina jedinstvenih za svaki indeks.

Kako radi video kodek? Dio 2. Što, zašto, kako

Također možete pokušati vizualizirati DCT promatrajući jednostavno formiranje slike na temelju njega. Na primjer, evo simbola A formiranog korištenjem svake težine koeficijenta:

Kako radi video kodek? Dio 2. Što, zašto, kako

Korak 4 - Kvantizacija

Nakon što smo u prethodnom koraku odbacili neke koeficijente, u završnom koraku (transformaciji) provodimo poseban oblik kvantizacije. U ovoj fazi je prihvatljivo izgubiti informacije. Ili, jednostavnije rečeno, kvantizirat ćemo koeficijente kako bismo postigli kompresiju.

Kako možete kvantizirati blok koeficijenata? Jedna od najjednostavnijih metoda je uniformna kvantizacija, gdje uzmete blok, podijelite ga s jednom vrijednošću (s 10) i zaokružite dobivenu vrijednost.

Kako radi video kodek? Dio 2. Što, zašto, kako

Možemo li invertirati ovaj blok koeficijenata? Da, možemo, množenjem s istom vrijednošću s kojom smo podijelili.

Kako radi video kodek? Dio 2. Što, zašto, kako

Ovaj pristup nije idealan jer ne uzima u obzir važnost svakog koeficijenta. Umjesto jedne vrijednosti mogla bi se koristiti matrica kvantizatora, a ta matrica bi mogla iskoristiti DCT svojstvo kvantizacijom većine donjeg desnog i manjine gornjeg lijevog.

Korak 5 - Entropijsko kodiranje

Nakon što smo kvantizirali podatke (blokove slike, fragmente, okvire), još uvijek ih možemo komprimirati bez gubitaka. Postoje mnoge algoritamske metode za kompresiju podataka. Ukratko ćemo obraditi neke od njih; za dublje razumijevanje možete pročitati knjigu "Razumijevanje kompresije: Kompresija podataka za moderne programere" (Razumijevanje kompresije: Kompresija podataka za moderne programere").

Kodiranje videa pomoću VLC-a

Pretpostavimo da imamo niz znakova: a, e, r и tVjerojatnost (između 0 i 1) koliko se često svaki simbol pojavljuje u toku prikazana je u ovoj tablici.

aert
Vjerojatnost0,30,30,20,2

Najvjerojatnijima možemo dodijeliti jedinstvene binarne kodove (po mogućnosti male), a manje vjerojatnima veće kodove.

aert
Vjerojatnost0,30,30,20,2
Binarni kod0101101110

Komprimiramo stream, pretpostavljajući da ćemo na kraju potrošiti 8 bitova po simbolu. Bez kompresije, bilo bi potrebno 24 bita po simbolu. Zamjenom svakog simbola njegovim kodom štedimo prostor!

Prvi korak je kodiranje simbola e, što je 10, a drugi simbol je a, koji se dodaje (ne matematički): [10] [0], i konačno treći znak t, što naš konačni komprimirani bitstream čini jednakim [10] [0] [1110] ili 1001110, što zahtijeva samo 7 bitova (3,4 puta manje prostora od originala).

Imajte na umu da svaki kod mora biti jedinstveni kod s prefiksom. Huffmanov algoritam će vam pomoći pronaći te brojeve. Iako ova metoda nije bez nedostataka, postoje video kodeci koji i dalje nude ovu algoritamsku metodu kompresije.

I koder i dekoder moraju imati pristup tablici simbola sa svojim binarnim kodovima. Stoga tablica također mora biti uključena u ulazne podatke.

Aritmetičko kodiranje

Pretpostavimo da imamo niz znakova: a, e, r, s и t, a njihova vjerojatnost prikazana je u ovoj tablici.

aerst
Vjerojatnost0,30,30,150,050,2

Pomoću ove tablice konstruirat ćemo raspone koji sadrže sve moguće simbole, sortirane po najvećem broju.

Kako radi video kodek? Dio 2. Što, zašto, kako

Sada kodirajmo niz od tri simbola: jesti.

Prvo odaberite prvi znak e, koji se nalazi u podrasponu od 0,3 do 0,6 (ne uključujući). Uzimamo ovaj podraspon i ponovno ga dijelimo u istim omjerima kao i prije, ali za ovaj novi raspon.

Kako radi video kodek? Dio 2. Što, zašto, kako

Nastavimo kodirati naš stream jestiSada uzimamo drugi simbol. a, što je u novom podrasponu od 0,3 do 0,39, a zatim uzimamo naš posljednji simbol t i ponavljanjem istog postupka ponovno dobivamo posljednji podraspon od 0,354 do 0,372.

Kako radi video kodek? Dio 2. Što, zašto, kako

Jednostavno trebamo odabrati broj u posljednjem podrasponu između 0,354 i 0,372. Odaberimo 0,36 (ali moguć je i bilo koji drugi broj u ovom podrasponu). Samo s tim brojem možemo rekonstruirati naš izvorni stream. Kao da crtamo liniju unutar raspona kako bismo kodirali naš stream.

Kako radi video kodek? Dio 2. Što, zašto, kako

Obrnuta operacija (tj. dekodiranje) je jednako jednostavno: s našim brojem 0,36 i našim početnim rasponom možemo pokrenuti isti proces. Ali sada, koristeći ovaj broj, identificiramo tok kodiran tim brojem.

Kod prvog raspona primjećujemo da naš broj odgovara kriški, stoga je ovo naš prvi simbol. Sada ponovno dijelimo ovaj podraspon, slijedeći isti postupak kao i prije. Ovdje možete vidjeti da 0,36 odgovara simbolu a, i nakon ponavljanja postupka došli smo do posljednjeg simbola t (formiranje našeg izvornog kodiranog toka jesti).

I koder i dekoder moraju imati tablicu vjerojatnosti simbola, pa se ona mora poslati u ulaznim podacima.

Prilično elegantno, zar ne? Tko god se dosjetio ovog rješenja bio je prilično pametan. Neki video kodeci koriste ovu tehniku ​​(ili je barem nude kao opciju).

Ideja je komprimirati kvantizirani bitstream bez gubitaka. Ovaj članak vjerojatno propušta mnoštvo detalja, razloga, kompromisa itd. Ali ako ste programer, trebali biste znati više. Novi kodeci pokušavaju koristiti različite algoritme entropijskog kodiranja, kao što su ANS.

Korak 6 - Format bitstreama

Nakon što je sve ovo postignuto, preostaje samo dekomprimirati komprimirane okvire u kontekstu izvršenih koraka. Dekoder mora biti eksplicitno obaviješten o odlukama koje je donio koder. Dekoderu moraju biti dostavljene sve potrebne informacije: dubina bita, prostor boja, razlučivost, informacije o predviđanju (vektori kretanja, smjerno INTER predviđanje), profil, razina, brzina kadrova, tip okvira, broj okvira i još mnogo toga.

Površno ćemo pogledati bitni tok H.264Naš prvi korak je stvaranje minimalnog H.264 bitstreama (FFmpeg prema zadanim postavkama dodaje sve opcije kodiranja kao što su SEI NAL — saznat ćemo što je to malo kasnije. To možemo učiniti koristeći vlastiti repozitorij i FFmpeg.

./s/ffmpeg -i /files/i/minimal.png -pix_fmt yuv420p /files/v/minimal_yuv420.h264

Ova naredba će generirati sirovi bitstream. H.264 s jednim kadrom, rezolucijom 64×64, s prostorom boja YUV420U ovom slučaju, sljedeća slika se koristi kao okvir.

Kako radi video kodek? Dio 2. Što, zašto, kako

H.264 bitni tok

Norma AVC (H.264) određuje da će se informacije slati u makrookvirima (u mrežnom smislu), nazvanim nal (Ovo je sloj apstrakcije mreže). Glavni cilj NAL-a je pružiti "mrežno prilagođen" video prikaz. Ovaj standard trebao bi raditi na televizorima (bazirano na streamingu) i na internetu (bazirano na paketima).

Kako radi video kodek? Dio 2. Što, zašto, kako

Postoji oznaka sinkronizacije koja definira granice NAL elemenata. Svaka oznaka sinkronizacije sadrži vrijednost 0x00 0x00 0x01, osim prvog, koji je jednak 0x00 0x00 0x00 0x01. Ako pokrenemo hexdump Za generirani H.264 bitni tok, identificiramo barem tri NAL uzorka na početku datoteke.

Kako radi video kodek? Dio 2. Što, zašto, kako

Kao što je spomenuto, dekoder mora znati ne samo podatke o slici već i video, okvir, boju, korištene parametre i još mnogo toga. Prvi bajt svakog NAL-a definira njegovu kategoriju i tip.

Identifikator NAL tipaOpis
0Nepoznata vrsta
1Kodirani fragment slike bez IDR-a
2Odjeljak kodiranih podataka sličica A
3Odjeljak kodiranih podataka sličica B
4Odjeljak kodiranih podataka sličica C
5 Kodirani IDR fragment IDR slike
6Dodatne informacije o SEI proširenju
7Skup parametara SPS sekvence
8Skup parametara slike PPS-a
9Razdjelnik pristupa
10Kraj sekvence
11Kraj streama
......

Tipično, prvi NAL bitstreama je PLCOvaj NAL tip je odgovoran za komunikaciju uobičajenih varijabli kodiranja kao što su profil, razina, rezolucija itd.

Ako preskočimo prvi marker sinkronizacije, možemo dekodirati prvi bajt kako bismo saznali koji je NAL tip prvi.

Na primjer, prvi bajt nakon oznake sinkronizacije je 01100111, gdje je prvi bit (0) je u polju fzabranjeni_nulti_bitSljedeća 2 bita (11) nam govori polje nal_ref_idc, što označava je li ovo NAL referentno polje ili ne. A preostalih 5 bitova (00111) nam govori polje tip_nal_jedinice, u ovom slučaju to je SPS blok (7) NAL.

Drugi bajt (binarni=01100100, šest=0x64, prosinca=100) u SPS NAL je polje profil_idc, što prikazuje profil koji koristi koder. U ovom slučaju korišten je ograničeno visoki profil (tj. visoki profil bez dvosmjerne podrške za B-segment).

Kako radi video kodek? Dio 2. Što, zašto, kako

Ako pogledate specifikaciju bitstreama H.264 Za SPS NAL, naći ćemo mnogo vrijednosti za naziv parametra, kategoriju i opis. Na primjer, pogledajmo polja širina_pic_u_mbs_minus_1 и visina_pic_u_jedinicama_mape_minus_1.

Naziv parametraKategorijaOpis
širina_pic_u_mbs_minus_10ue(v)
visina_pic_u_jedinicama_mape_minus_10ue(v)

Ako izvršimo neke matematičke operacije nad vrijednostima ovih polja, dobivamo rezoluciju. Možemo prikazati 1920 x 1080 pomoću širina_pic_u_mbs_minus_1 s vrijednošću 119 ((119 + 1) * veličina_makrobloka = 120 * 16 = 1920). Ponovno, radi uštede prostora, umjesto kodiranja 1920, napravili smo to sa 119.

Ako nastavimo provjeravati naš kreirani video u binarnom obliku (na primjer: xxd -b -c 11 v/minimalni_yuv420.h264), tada možemo prijeći na posljednji NAL, koji je sam okvir.

Kako radi video kodek? Dio 2. Što, zašto, kako

Ovdje vidimo njegovih prvih 6 bajtnih vrijednosti: 01100101 10001000 10000100 00000000 00100001 11111111Budući da je poznato da prvi bajt označava NAL tip, u ovom slučaju (00101) ovo je IDR fragment (5), a zatim će ga biti moguće dalje istražiti:

Kako radi video kodek? Dio 2. Što, zašto, kako

Korištenjem informacija o specifikaciji, bit će moguće dekodirati tip fragmenta (vrsta_slice) i broj kadra (broj_okvira) među ostalim važnim područjima.

Da biste dobili vrijednosti nekih polja (ue(v), me(v), se(v) ili te(v)), moramo dekodirati fragment pomoću posebnog dekodera temeljenog na eksponencijalni Golombov kodOva metoda je vrlo učinkovita za kodiranje vrijednosti varijabli, posebno kada postoji mnogo zadanih vrijednosti.

značenje vrsta_slice и broj_okvira ovog videa su 7 (I-fragment) i 0 (prvi kadar).

Bitni tok se može smatrati protokolom. Ako želite saznati više o bitnom toku, trebali biste se obratiti specifikaciji. ITU H.264Evo makro dijagrama koji prikazuje gdje se nalaze podaci slike (YUV u komprimiranom obliku).

Kako radi video kodek? Dio 2. Što, zašto, kako

Mogu se istražiti i drugi bitstreamovi, kao što su VP9, H.265 (HEVC) ili čak naš novi najbolji bitstream AV1Jesu li svi slični? Ne, ali kad jednom shvatite barem jedan, puno je lakše razumjeti ostale.

Želite li vježbati? Istražite H.264 bitstream.

Možete generirati video s jednim kadrom i koristiti MediaInfo za ispitivanje bitstreama. H.264Zapravo, ništa vas ne sprječava da čak pogledate izvorni kod koji analizira bitni tok. H.264 (AVC).

Kako radi video kodek? Dio 2. Što, zašto, kako

Za vježbu možete koristiti Intel Video Pro Analyzer (već sam spomenuo da je program plaćen, ali postoji li besplatna probna verzija s ograničenjem od 10 sličica?).

Kako radi video kodek? Dio 2. Što, zašto, kako

Pregled

Imajte na umu da mnogi moderni kodeci koriste isti model koji smo upravo proučavali. Pogledajmo blok dijagram video kodeka. ThorSadrži sve korake koje smo poduzeli. Svrha ove objave je barem vam pružiti bolji uvid u inovacije i dokumentaciju u ovom području.

Kako radi video kodek? Dio 2. Što, zašto, kako

Prethodno smo izračunali da bi za pohranu video datoteke od sat vremena u 720p kvaliteti i 30 fps bilo potrebno 139 GB prostora na disku. Korištenjem metoda opisanih u ovom članku (međuframe i intraframe predikcija, transformacija, kvantizacija, entropijsko kodiranje itd.), možemo postići (pod pretpostavkom gustoće piksela od 0,031 bita) video prilično zadovoljavajuće kvalitete koji zauzima samo 367,82 MB, umjesto 139 GB.

Kako H.265 postiže bolju kompresiju od H.264?

Sada kada znamo više o tome kako kodeci rade, lakše je razumjeti kako novi kodeci mogu pružiti veću rezoluciju s manje bitova.

Ako usporedite AVC и HEVC, vrijedi zapamtiti da je gotovo uvijek izbor između većeg opterećenja CPU-a i omjera kompresije.

HEVC ima više opcija za odjeljke (i pododjeljke) nego AVC, više uputa za interno predviđanje, poboljšano entropijsko kodiranje i još mnogo toga. Sva ova poboljšanja omogućila su H.265 sposoban za kompresiju 50% više od H.264.

Kako radi video kodek? Dio 2. Što, zašto, kako

Prvi dio: Osnove rada s videom i slikama

Izvor: www.habr.com

Kupite pouzdan hosting za stranice s DDoS zaštitom, VPS VDS poslužiteljima 🔥 Kupite pouzdan web hosting sa DDoS zaštitom, VPS VDS servere | ProHoster