Methoden voor het verwerken van digitale video in de YCoCg-R-kleurenruimte met behulp van shaders

Vergelijkbare documenten
Video. Multimedia Rein van den Boomgaard Universiteit van Amsterdam

FOR DUTCH STUDENTS! ENGLISH VERSION NEXT PAGE. Toets Inleiding Kansrekening 1 8 februari 2010

Classification of triangles

Add the standing fingers to get the tens and multiply the closed fingers to get the units.

SAMPLE 11 = + 11 = + + Exploring Combinations of Ten + + = = + + = + = = + = = 11. Step Up. Step Ahead

EM7680 Firmware Update by OTA

MyDHL+ Van Non-Corporate naar Corporate

FOR DUTCH STUDENTS! ENGLISH VERSION NEXT PAGE

AVCHD (*) : alweer een nieuw video formaat!

FOR DUTCH STUDENTS! ENGLISH VERSION NEXT PAGE

ALGORITMIEK: answers exercise class 7

The genesis of the game is unclear. Possibly, dominoes originates from China and the stones were brought here by Marco Polo, but this is uncertain.

Analyse van pixelgroepering en antiblokfiltering in een GPU-gedreven H.264/AVC-decoder

Hertentamen 8D040 - Basis beeldverwerking

Pesten onder Leerlingen met Autisme Spectrum Stoornissen op de Middelbare School: de Participantrollen en het Verband met de Theory of Mind.

Het JPEG compressie algoritme, IS

04/11/2013. Sluitersnelheid: 1/50 sec = 0.02 sec. Frameduur= 2 x sluitersnelheid= 2/50 = 1/25 = 0.04 sec. Framerate= 1/0.

Preschool Kindergarten

A. Wat zijn digitale afbeeldingen? B. Bitonaal, grijswaarden of kleur en de bitdiepte C. Resolutie, bestandsgrootte, compressie en bestandsformaten

Puzzle. Fais ft. Afrojack Niveau 3a Song 6 Lesson A Worksheet. a Lees de omschrijvingen. Zet de Engelse woorden in de puzzel.

Academisch schrijven Inleiding

Studie en implementatie van de bewegingscompensatie in een H.264/AVC-decoder

EM7580 Firmware Update by Micro SD card

De Relatie tussen Mindfulness en Psychopathologie: de Mediërende. Rol van Globale en Contingente Zelfwaardering

EM7680 Firmware Auto-Update for Kodi 17.2

Compaq Desktop Wallpaper

Taco Schallenberg Acorel

Lichamelijke factoren als voorspeller voor psychisch. en lichamelijk herstel bij anorexia nervosa. Physical factors as predictors of psychological and

FOR DUTCH STUDENTS! ENGLISH VERSION NEXT PAGE

COGNITIEVE DISSONANTIE EN ROKERS COGNITIVE DISSONANCE AND SMOKERS

Luister alsjeblieft naar een opname als je de vragen beantwoordt of speel de stukken zelf!

L.Net s88sd16-n aansluitingen en programmering.

Screen Design. Deliverable 3 - Visual Design. Pepijn Gieles Docent: Jasper Schelling

Gebruik van het LOGO in geautomatiseerde verkiezingen

(1) De hoofdfunctie van ons gezelschap is het aanbieden van onderwijs. (2) Ons gezelschap is er om kunsteducatie te verbeteren

OPTIMALISATIE VAN MPEG-4-WAVELETCODE VOOR DE TRIMEDIAPROCESSOR

Ius Commune Training Programme Amsterdam Masterclass 15 June 2018

Hardware. Word. Anna van Kommer M3A

General info on using shopping carts with Ingenico epayments

FOR DUTCH STUDENTS! ENGLISH VERSION NEXT PAGE. Toets Inleiding Kansrekening 1 22 februari 2013

Geslacht, Emotionele Ontrouw en Seksdrive. Gender, Emotional Infidelity and Sex Drive

Handleiding Installatie ADS

Chromosomal crossover

Introductie in flowcharts

FRAME [UPRIGHT MODEL] / [DEPTH] / [HEIGHT] / [FINISH] TYPE OF BASEPLATE P Base plate BP80 / E alternatives: ZINC finish in all cases

L.Net s88sd16-n aansluitingen en programmering.


Opgave 2 Geef een korte uitleg van elk van de volgende concepten: De Yield-to-Maturity of a coupon bond.

2019 SUNEXCHANGE USER GUIDE LAST UPDATED

Ius Commune Training Programme Amsterdam Masterclass 22 June 2017

LONDEN MET 21 GEVARIEERDE STADSWANDELINGEN 480 PAGINAS WAARDEVOLE INFORMATIE RUIM 300 FOTOS KAARTEN EN PLATTEGRONDEN

DALISOFT. 33. Configuring DALI ballasts with the TDS20620V2 DALI Tool. Connect the TDS20620V2. Start DALISOFT

!!!! Wild!Peacock!Omslagdoek!! Vertaling!door!Eerlijke!Wol.!! Het!garen!voor!dit!patroon!is!te!verkrijgen!op! Benodigdheden:!!

ANGSTSTOORNISSEN EN HYPOCHONDRIE: DIAGNOSTIEK EN BEHANDELING (DUTCH EDITION) FROM BOHN STAFLEU VAN LOGHUM

Ontpopping. ORGACOM Thuis in het Museum

Het Effect van Verschil in Sociale Invloed van Ouders en Vrienden op het Alcoholgebruik van Adolescenten.

AVG / GDPR -Algemene verordening gegevensbescherming -General data Protection Regulation

IEEE 1394 firewire. Jan Genoe KHLim. I-link DV (digital video)

Effecten van een op MBSR gebaseerde training van. hospicemedewerkers op burnout, compassionele vermoeidheid en

RECEPTEERKUNDE: PRODUCTZORG EN BEREIDING VAN GENEESMIDDELEN (DUTCH EDITION) FROM BOHN STAFLEU VAN LOGHUM

Aim of this presentation. Give inside information about our commercial comparison website and our role in the Dutch and Spanish energy market

Wat is Interaction Design?

Workflow en screenshots Status4Sure

Today s class. Digital Logic. Informationsteknologi. Friday, October 19, 2007 Computer Architecture I - Class 8 1

Global TV Canada s Pulse 2011

dens het encoderen. Een hoge QP duidt op grove quantisatie van residuele data en leidt bijgevolg tot een lagere kwaliteit. Door de ruwere benadering

Multi user Setup. Firebird database op een windows (server)

Calculator spelling. Assignment

Cambridge Assessment International Education Cambridge International General Certificate of Secondary Education. Published

Software Processen. Ian Sommerville 2004 Software Engineering, 7th edition. Chapter 4 Slide 1. Het software proces

Academisch schrijven Inleiding

OUTDOOR HD BULLET IP CAMERA PRODUCT MANUAL

My Inspiration I got my inspiration from a lamp that I already had made 2 years ago. The lamp is the you can see on the right.

Risico s van Technologisch Succes in digitale transformatie S T R A T E G I C A D V I S O R

Media en creativiteit. Winter jaar vier Werkcollege 7

Chapter 4 Understanding Families. In this chapter, you will learn

Ius Commune Training Programme Amsterdam Masterclass 16 June 2016

Film in de pc laden.

After that, the digits are written after each other: first the row numbers, followed by the column numbers.

Invloed van het aantal kinderen op de seksdrive en relatievoorkeur

TECHNISCHE UNIVERSITEIT EINDHOVEN Faculteit Wiskunde en Informatica. Examination 2DL04 Friday 16 november 2007, hours.

FOR DUTCH STUDENTS! ENGLISH VERSION NEXT PAGE. Toets Inleiding Kansrekening 1 7 februari 2011

VOORSTEL TOT STATUTENWIJZIGING UNIQURE NV. Voorgesteld wordt om de artikelen 7.7.1, 8.6.1, en te wijzigen als volgt: Toelichting:

informatica. hardware. overzicht. moederbord CPU RAM GPU architectuur (vwo)

Denken en Doen Doen of Denken Het verband tussen seksueel risicovol gedrag en de impulsieve en reflectieve cognitie.

n-queens minimale dominantie verzamelingen Chessboard Domination on Programmable Graphics Hardware door Nathan Cournik

01/ M-Way. cables

Automated scoring in mathematics: tinning intelligence?

OUTDOOR HD DOME IP CAMERA PRODUCT MANUAL GB - NL

Verschil in Perceptie over Opvoeding tussen Ouders en Adolescenten en Alcoholgebruik van Adolescenten

i(i + 1) = xy + y = x + 1, y(1) = 2.

The first line of the input contains an integer $t \in \mathbb{n}$. This is followed by $t$ lines of text. This text consists of:

Sekseverschillen in Huilfrequentie en Psychosociale Problemen. bij Schoolgaande Kinderen van 6 tot 10 jaar

Opleiding PECB ISO 9001 Quality Manager.

Ae Table 1: Aircraft data. In horizontal steady flight, the equations of motion are L = W and T = D.

THE WORK HET WERK HARALD BERKHOUT

CTI SUITE TSP DETAILS

Adam Marciniec, Grzegorz Budzik Zaborniak

Transcriptie:

Faculteit Ingenieurswetenschappen Vakgroep Elektronica en Informatiesystemen Voorzitter: prof. dr. ir. J. Van Campenhout Methoden voor het verwerken van digitale video in de YCoCg-R-kleurenruimte met behulp van shaders door Stefaan Moens Promotor: Thesisbegeleiders: prof. dr. ir. R. Van de Walle lic. W. De Neve lic. K. De Wolf lic. D. Van Rijsselbergen Afstudeerwerk ingediend tot het behalen van de graad van Burgerlijk Ingenieur in de Computerwetenschappen Academiejaar 2005 2006

Dankwoord Mijn dank gaat uit naar iedereen die mij geholpen heeft bij het volbrengen van dit eindwerk. Daarbij denk ik vooreerst aan mijn promotor prof. dr. ir. R. Van de Walle omdat hij mij toeliet dit interessant onderwerp aan te snijden. Ik wil ook mijn dank betuigen aan het adres van lic. W. De Neve, lic. K. De Wolf en lic. D. Van Rijsselbergen. Zij zorgden voor een uitstekende begeleiding en de nodige steun wanneer niet alles volgens plan verliep. Verder wens ik ook mijn dankbaarheid te richten tot Bart Pieters met wie het aangenaam samenwerken was. Tot slot bedank ik ook mijn naasten voor hun interesse en steun doorheen dit drukke jaar. i

Toelating tot bruikleen De auteur geeft de toelating deze scriptie voor consultatie beschikbaar te stellen en delen van de scriptie te kopiëren voor persoonlijk gebruik. Elk ander gebruik valt onder de beperkingen van het auteursrecht, in het bijzonder met betrekking tot de verplichting de bron uitdrukkelijk te vermelden bij het aanhalen van resultaten uit deze scriptie. Stefaan Moens, 20 augustus 2006 ii

Methoden voor het verwerken van digitale video in de YCoCg-R-kleurenruimte met behulp van shaders door Stefaan Moens Afstudeerwerk ingediend tot het behalen van de graad van Burgerlijk Ingenieur in de Computerwetenschappen Academiejaar 2005 2006 Universiteit Gent Faculteit Ingenieurswetenschappen Vakgroep Elektronica en Informatiesystemen Voorzitter: prof. dr. ir. J. Van Campenhout Promotor: prof. dr. ir. R. Van de Walle Thesisbegeleiders: lic. W. De Neve, lic. K. De Wolf, lic. D. Van Rijsselbergen Samenvatting In dit eindwerk wordt bewegingsschatting toegepast op videobeelden in de YCoCg-Rkleurenruimte. Deze kleurenruimte is verliesloos en voordelig voor het gebruik in videocompressie vanwege de hogere potentiële graad van compressie. Deze beelden worden opgeslagen in een nieuw bestandsformaat dat vervolgens door een zelfontwikkelde decoder ingelezen kan worden. Deze decoder maakt zoveel mogelijk gebruik van de rekenkracht van de GPU om de bewegingscompensatie en beeldreconstructie toe te passen. Dit met het oog op het zoveel mogelijk ontlasten van de CPU en de prestatiewinst die krachtige hedendaagse grafische processors kunnen leveren. Er wordt gebruikgemaakt van shaders om de nodige functionaliteit te implementeren op de grafische hardware. Trefwoorden: bewegingscompensatie, Direct3D, GPU, shaders, videocompressie, YCoCg, YCoCg-R iii

Processing digital video in the YCoCg-R color space through shaders Stefaan Moens Supervisors: W. De Neve, D. Van Rijsselbergen, K. De Wolf, and R. Van de Walle Abstract In this thesis we tackle two issues of video coding. On the one hand we constantly thrive towards a more compact form of video images while retaining as much image quality as possible. On the other hand this better compaction requires an increasing need for computational power. It has been observed that the graphics processing unit (GPU) can help relieving the CPU from certain burdens of the video coding process. Therefore a decoder has been developed that performs motion compensation and color space conversion fully on the GPU. Returning to our first problem at hand, we are using the recently introduced YCoCg-R color space. This color space is lossless, has simple conversion rules and is said to establish a significant coding gain. Combining the benefits of the YCoCg-R color space and the processing power of the GPU, we ve set up an encoder-decoder structure. Intermediate file formats are used to store the residue images and motion vectors. The result consists of a hardware accelerated video playback in a new promising and lossless color space. Keywords Direct3D, GPU, motion compensation, shaders, videocompression, YCoCg, YCoCg-R I. INTRODUCTION MULTIMEDIA PC minimum standards are constantly evolving towards more powerful systems. The graphics processing units (GPUs) are no longer a rarity in today s home computers. While the well-known Moore s Law remains valid for CPUs, the GPUs are increasing their density in terms of transistors even more rapidly 1. This has led to the fact that graphics hardware outperforms recent CPUs in certain areas. Being mainly targeted by the game industry, these GPUs remain mostly unused by applications in other domains, such as video coding. The goal we ve set out for this thesis is to utilize the power of the GPU to perform motion compenstation in the recently introduced YCoCg-R color space. For this purposes an encoder was developed to provide us with YCoCg-R residue images and motion vectors. In contrast to the decoder, this encoder runs entirely on the CPU. In the second stage of the thesis the GPUassisted decoder was implemented. II. THE YCOCG-R COLOR SPACE RGB images can be converted to YCoCg-R and back in a lossless manner. The Y stands for luminance and the Co and Cg are the offset of orange and green. R points out that we are dealing with a lossless or reversible color transform. According to [1] the main reason to actually use this color space is its better compression performance and its simple transformation rules. The paper provides us with the following lossless integer arithmetic transformation: 1 It is also said that they follow the so-called Moore s Law Cubed since their density is doubled in six months instead of eighteen Co = R B t = B + (Co >> 1) Cg = G t Y = t + (Cg >> 1) t = Y (Cg >> 1) G = Cg + t B = t (Co >> 1) R = B + Co This comes at the price of the need for an extra bit for both the Co en Cg component, which brings their count to 9 instead of 8 for each. 8 bits Figure 8 bits1 illustrates 8 bits this at a full resolution scale. The overhead 10011001 of10011001 the two extra 10011001 bits is compensated by the coding Y Co Cg gain and the lossless nature of the transformation, thus making this color space interesting for practical use. 8 bits 9 bits 9 bits 10011001 110011001 110011001 Y Co Cg YCoCg YCoCg-R Fig. 1. The YCoCg-R color space at full resolution As a final remark we point out the importance of the preservation of the 8-bit precision for the luminance. This is especially interesting once motion estimation gets involved, since this is commonly done solely in the luma domain. III. MOTION PREDICTION AND COMPENSATION The general technique of motion prediction is applied in the encoder. The current image and the reference image are subdivided into macroblocks. For each block from the current frame a prediction is made based on the least differing reference macroblock. The motion vector points to the location of that reference macroblock. The residue image is filled with the differences between the macroblocks. To find the best matching reference macroblock a formula is used to calculate the minimal energy between the two blocks (e.g. the Mean Square Error). Usually the calculation is limited by the use of a search window. Figure 2 illustrates this procedure. In de decoder the reference macroblock is retrieved through the motion vector, after which the residue macroblock is added to it. (1) (2)

1 01 01010101 0010 110001 10010010 0000010 Y 010010000 01001001 01100100010 1001000011111 11010001 01010101 10010010 Co van 8 bits 01001001 per pixel 11010001 01010101 10010010 Cg 01001001 11010001 8 bits 1 bit extra Y 2 bits extra Co bitcollectors 2 bits extra Cg 8 bits 1 01 0010 110001 0000010 010010000 01100100010 1001000011111 reference image search window MSE current image macroblock search window Fig. 2. Illustration of motion estimation IV. THE ENCODER The main purpose of the encoder is to provide the decoder with motion vectors and residue images. Therefore intermediate file formats were needed. The file layout for the storage of the residue images consists of planes. First the lowest 8 bits of the components are stored in successive planes for each component of the same image. Then the bitcollectors are stored the same way. They contain the highest bits and combine them into bytes with the aim not to waste any storage space. Concerning the motion vectors we simply store them as a collection of integers. V. MOTION COMPENSATION ON THE GPU The GPU implements the stream programming model. It processes a stream of vertices through the vertex shaders and pixel shaders to eventually fill the pixels with the right color. The decoder developed in this thesis uses the assistance of the GPU to perform the motion compensation. The structure of the decoder is depicted in Figure 3. CPU bytes {gewone planes readresidue() YCoCgMCHardwareProducer YCoCgMemIntraResidueProducer8bitX2 The vertex and pixel shaders are playing a major role in the execution of the motion compensation on the GPU. By presenting each macroblock by a quad (combined from two triangles) in the vertex grid the vertex shader can manipulate the texture coordinates of the vertices so that the motion predicted reference image can be assembled. Therefore the motion vectors need to be uploaded to this vertex grid. Once this is done the following step consists of adding the residue image to the motion predicted reference image. This is done by the pixel shaders who add the residue texture to the reference texture. Again this implies the upload of the residue data. In the final stage the pixel shaders will transform the YCoCg- R-image to RGB, making it ready to be sent to the screen. VI. RESULTS We show the results of the performance tests in Table I. The tests were done with and without the use of triple buffering on an Intel Dual Core PC shipped with an nvidia GeForce 7800 GTX (256 MB). For the highest resolution triple buffering was not possible due to videomemory limitations. TABLE I THE PERFORMANCE OF THE DECODER File Resolution Triple buffer without with (FPS) (FPS) Pirates 768x318 163,20 154,23 Croft 720x480 99,14 113,12 Double Agent 768x576 78,59 89,86 Lara 1280x720 32,48 35,49 Viper2 1920x1080 17,50 Y { file format for residue images file format for motion vectors GPU Co Cg readmotionvectors() upload8bitx2singletexture(...) Textures residue image YCoCgMemMotionVectorProducer YCoCgMCHardwareRenderer YCoCgMemIntraResidueProducer8bitX2 YCoCgMemMotionVectorProducer uploadmotionvectors() Vertex buffer Vertex shader Vertex grid Pixel shader VII. CONCLUSION The results show that our GPU-assisted decoder can perform real-time up to a resolution of 1280 720 on an Intel Dual Core PC with an nvidia GeForce 7800 GTX. Although there are still improvements possible, this implementation realizes the first step towards an GPU-assisted encoder-decoder in the YCoCg-R color space. ACKNOWLEDGMENTS The author would like to acknowledge his promoter Rik Van de Walle who gave him the possibility to do research in this interesting domain, as well as Wesley De Neve, Dieter Van Rijsselbergen and Koen De Wolf for their excellent guidance and advice during this entire project. Y Co Cg Textures reference image Framebuffer Fig. 3. The GPU-assisted decoder REFERENCES [1] H. Malvar en G. Sullivan. YCoCg-R: A Color Space with RGB Reversibility and Low Dynamic Range. Juli 2003. JVT Doc. JVT-I014. [2] Guobin Shen, Guang-Ping Gao, Shipeng Li, Heung-Yeung Shum, and Ya- Qin Zhang. Accelerate Video Decoding With Generic GPU. IEEE Trans. Circuits Syst. Video Technol., 15(5):685 693, May 2005.

Inhoudsopgave 1 Inleiding 1 1.1 Situering..................................... 1 1.1.1 Toepassingen digitale video...................... 1 1.1.2 Historische achtergrond......................... 3 1.1.3 Probleemschets............................. 4 1.2 Aanpak en doelstellingen............................ 5 1.3 Aanverwant onderzoek............................. 6 1.4 Overzicht.................................... 8 2 YCoCg en aanverwante kleurenruimtes 9 2.1 Algemeen.................................... 9 2.2 De RGB-kleurenruimte............................. 10 2.3 De YCrCb/YUV-kleurenruimte........................ 10 2.4 De YCoCg-kleurenruimte............................ 12 2.5 De YCoCg-R-kleurenruimte.......................... 14 2.6 Verantwoording................................. 15 3 Over bewegingsschatting en bewegingscompensatie 16 3.1 Algemeen.................................... 17 3.2 Het residu.................................... 17 3.3 Bewegingsschatting............................... 19 3.3.1 Soorten gecodeerde beelden...................... 20 3.3.2 Keuze van referentiebeelden...................... 20 3.3.3 Macroblokken.............................. 21 3.3.4 Minimale energie............................ 22 3.3.5 Bewegingsvectoren........................... 24 iv

3.4 Bewegingscompensatie............................. 24 3.5 Uitbreidingen.................................. 25 3.5.1 Sub-pixel bewegingsschatting..................... 25 3.5.2 Bewegingsvectoren buiten het referentiebeeld............. 26 3.5.3 Variabele blokgroottes......................... 26 4 De encoder 27 4.1 Situering..................................... 27 4.2 Structuur van de applicatie.......................... 27 4.3 Algemene werking................................ 29 4.3.1 Bewegingsschatting toegepast..................... 29 4.3.2 Bestandsformaten............................ 32 4.4 Controlepunten................................. 36 4.5 Prestaties.................................... 36 4.6 Andere tools................................... 37 5 Over shaders, de GPU en Direct3D 39 5.1 De oorsprong van de GPU........................... 39 5.2 GPU vs. CPU.................................. 40 5.3 Het renderproces en zijn terminologie..................... 42 5.3.1 Het geometrische gedeelte....................... 43 5.3.2 Het pixelgedeelte............................ 44 5.3.3 Renderiteraties............................. 47 5.4 Systeemarchitectuur.............................. 47 5.5 Toegang tot de hardware via Direct3D.................... 49 5.5.1 De evolutie van DirectX........................ 49 5.5.2 De Direct3D 9 API........................... 50 5.6 De shaders.................................... 51 5.6.1 HLSL.................................. 51 5.6.2 De vertexshader............................. 52 5.6.3 De pixelshader............................. 53 5.6.4 Het Effects-raamwerk.......................... 55 5.7 Hedendaagse hardware............................. 57 v

6 De decoder 59 6.1 Structuur van de applicatie.......................... 59 6.2 Structuur van de libycocgrmc -bibliotheek................. 60 6.3 Macroblok en bewegingsvector op de GPU.................. 62 6.4 Bewegingscompensatie op de GPU...................... 64 6.4.1 Inlezen van de gegevens........................ 65 6.4.2 Het opladen naar de GPU....................... 65 6.4.3 De shaders in werking......................... 65 6.5 Het ontwikkelproces............................... 71 7 Prestatiemetingen 73 7.1 Hulpmiddelen.................................. 73 7.2 Meetmethode.................................. 74 7.2.1 Triple buffering............................. 74 7.3 De testsequenties................................ 75 7.4 Testopstelling.................................. 76 7.5 Resultaten.................................... 77 7.5.1 Prestaties van de decoder....................... 77 7.5.2 Gebruik videogeheugen......................... 82 7.6 Opzoek naar de flessenhals........................... 83 7.7 Vergelijking met ander onderzoekswerk.................... 84 7.8 Ruimte voor verbetering............................ 85 8 Besluit 86 Bibliografie 88 vi

Lijst van figuren 1.1 Reclame voor de digitale televisie van Telenet................ 2 1.2 Reclame voor de digitale televisie van Belgacom............... 2 1.3 Het principe van digitale video......................... 3 1.4 Schematische voorstelling van videoconferencing............... 5 1.5 Overzicht van de workflow van dit eindwerk................. 7 2.1 De RGB-kleurenruimte............................. 10 2.2 Illustratie van Cr- en Cb-component...................... 11 2.3 Onderbemonstering bij de YCrCb-kleurenruimte............... 12 2.4 De YCoCg-kleurenruimte zonder onderbemonstering............. 13 2.5 De YCoCg-R-kleurenruimte zonder onderbemonstering........... 15 3.1 Opeenvolgende beelden van een videosequentie................ 16 3.2 Algemene schematische voorstelling van een codec.............. 17 3.3 Energie in het residubeeld bij twee statische beelden............. 18 3.4 Algemene schematische voorstelling van een codec met decoding loop... 19 3.5 Energie in het residubeeld bij twee beelden met meer beweging....... 19 3.6 Voorbeeld van de verschillende soorten beelden................ 21 3.7 Illustratie macroblokken en het residu..................... 22 3.8 Illustratie van het zoekvenster......................... 24 3.9 Schema van codec met bewegingscompensatie en -schatting met decoding loop....................................... 25 4.1 Een summier UML-schema van de encoder.................. 28 4.2 Schematische voorstelling van de bewegingsschatting in MVCoder..... 31 4.3 Bestandsformaat voor gewone YCoCg-R-beelden............... 32 4.4 Bestandsformaat voor verschilbeelden in de YCoCg-R-kleurenruimte.... 34 vii

5.1 Voorbeeld van sprites.............................. 40 5.2 Een 3D-wereld afgebeeld............................ 40 5.3 De grafische pijplijn............................... 42 5.4 De vertex.................................... 43 5.5 Het draadmodel van een Romeins schip.................... 44 5.6 De pixels van een fragment........................... 45 5.7 Een 3D-scène.................................. 45 5.8 Een textuur die hout voorstelt......................... 46 5.9 Een 3D-scène met toepassing van een houten textuur............ 46 5.10 Het begrip pitch................................. 47 5.11 Architectuur van een AMD Athlon64 systeem................ 48 5.12 Lagenmodel van de Direct3D API....................... 51 5.13 Gedrag van de HLSL-compiler......................... 52 5.14 De vertexshader in het stroomproces..................... 53 5.15 De vertexshadermachine............................ 54 5.16 De pixelshader................................. 54 5.17 De pixelshadermachine............................. 55 5.18 De ATI Radeon x1900 Serie.......................... 57 5.19 De GeForce 7800 GTX 512........................... 58 6.1 De bibliotheken van VideoTex......................... 60 6.2 Structuur van het libycocgrmc-pakket................... 61 6.3 Vertexrooster voor macroblokken....................... 63 6.4 Algemene werking van de decoder....................... 64 6.5 Een foutief resultaat van de decoder...................... 72 7.1 Meten met NVPerfHUD 4........................... 75 7.2 Testresultaten zonder triple buffer....................... 78 7.3 Testresultaten met triple buffer........................ 78 7.4 Testresultaten met en zonder triple buffer.................. 80 7.5 Vergelijking met of zonder triple buffer in NVPerfHUD........... 81 7.6 Gebruik van videogeheugen met en zonder triple buffer........... 82 7.7 De viper2 -sequentie met NVPerfHUD..................... 83 viii

Lijst van tabellen 1.1 Illustratie van de grootordes van ongecomprimeerde data.......... 4 7.1 Het testpakket en zijn afmetingen....................... 75 7.2 Resultaten snelheidsmetingen......................... 77 7.3 Gebruik videogeheugen met en zonder triple buffer............. 82 ix

Hoofdstuk 1 Inleiding In dit inleidend hoofdstuk wordt dieper ingegaan op het probleem dat we als uitgangspunt kiezen voor dit eindwerk. Daarna beschouwen we mogelijke oplossingen om hieraan tegemoet te komen en bepalen we de concrete doelstellingen van deze thesis. Verder wensen we ook dit eindwerk te situeren tegenover voorafgaand onderzoek. Tenslotte geven we een beknopt overzicht over de inhoud van de volgende hoofdstukken. 1.1 Situering 1.1.1 Toepassingen digitale video Met de recente komst van de digitale televisie 1 is het des te meer duidelijk dat we in onze hedendaagse informatiemaatschappij worden overstelpt met digitale beelden. Samen met het internet zorgt deze nieuwe manier van televisie kijken ervoor dat de voordelen van het digitaal verwerken van beelden aan het grote publiek kenbaar worden gemaakt. Was het voor de toeschouwer voorheen niet zo belangrijk hoe hij zijn beelden kon bekijken, dan ziet hij nu nieuwe toepassingen op de markt komen die vroeger onmogelijk waren. Hedendaagse reclamecampagnes voor digitale televisie postuleren onder andere film op aanvraag en het onderbreken van rechtstreekse uitzendingen samen met een verhoogde beeldkwaliteit als belangrijkste voordelen van dit vernieuwde medium. In Figuur 1.1 en Figuur 1.2 zien we voorbeelden hiervan. De extra mogelijkheden strekken zich echter nog verder uit en daarmee gepaard gaan ook nog vele onontgonnen toepassingsgebieden. 1 De geïnteresseerde lezer verwijzen we graag door naar het online Museum of Television waar de geschiedenis van de televisie mooi in kaart is gebracht. Dit is te vinden op: http://www.mztv.com 1

Figuur 1.1: Reclame voor de digitale televisie van Telenet Figuur 1.2: Reclame voor de digitale televisie van Belgacom In dit eindwerk zullen we ons echter niet specifiek richten op de digitale televisie maar wel op een meer fundamenteel probleem. Het bewaren van digitale beelden vergt enorm veel plaats in termen van bits en bytes. De oorzaak hiervan is terug te vinden in de manier waarop we digitale video bijhouden. Zoals in Figuur 1.3 geïllustreerd wordt, houden we van elk beeld zoveel mogelijk monsters bij, zowel in de tijd als in de ruimte, om een zo hoog mogelijke kwaliteit te garanderen. Dit alles gaat hand in hand met de hoge nood aan netwerkbandbreedte, bijvoorbeeld vereis voor videostreaming over het Internet. Zelfs met de toenemende capaciteiten van harde schijven, de komst van de opvolger van de DVD 2 en breedbandnetwerken kunnen we niet zonder meer digitale video bijhouden. Dit zou aanleiding geven tot een te hoge kost om de beelden in de huiskamer te brengen of 2 Momenteel woedt er een strijd tussen twee standaarden: de Advanced Optical Disc ook de HD- DVD genaamd van Toshiba en Nec en de Blu-Ray van onder andere Sony. Deze schijven hebben een schijfruimte van om en bij de 25GB voor één laag. Voor meer info verwijzen we de lezen door naar http://www.blu-ray.com/ en http://www.tacp.toshiba.com/hddvd/. 2

Figuur 1.3: Het principe van digitale video intern op te slaan. Het was dan ook al in een vroeg stadium duidelijk dat digitale video een sterke nood had aan een vorm van compactie. De gegevens in Tabel 1.1 uit [1] tonen de grootordes van ongecomprimeerde data en illustreren zo de omvang van het gestelde probleem. 1.1.2 Historische achtergrond Volgens verscheidene bronnen 3 begon het verhaal van videocompressie reeds in de jaren 1960, toen men nog met analoge systemen werkte. Rond 1980 werden er voor het eerst commerciële toepassingen voor videoconferencing 4 gelanceerd. Hieronder verstaan we een systeem dat toelaat om van op afstand met elkaar te communiceren, niet alleen met geluid maar ook met beelden. In Figuur 1.4 is er een schema te zien dat de werking van een dergelijk systeem verduidelijkt en waarbij we opmerken dat de codec 5 een centrale rol speelt. De interesse van de professionele wereld was gewekt door de nieuwe mogelijkheden en de International Telecommunication Union (ITU) ontwikkelde zo de eerste videostandaarden met deze applicaties voor ogen. Zo kwam er in 1989 de opvolger van de H.120 codec, H.261 genaamd. Deze bood reeds een aanvaardbare kwaliteit voor het gebruik bij videoconferencing en hanteerde bitsnelheden die veelvouden zijn van 64 kbits/s. MPEG-1 werd gestandaardiseerd door de International Organization for Standardization en verbruikt een bitsnelheid van 1,5 Mbit/s. Deze technologie vond zijn 3 urlhttp://www.pha.jhu.edu/ sundar/intermediate/history.html en http://www.wiredred.com/ video-conferencing-history.html 4 Voor meer informatie over videoconferencing verwijzen we de lezer door naar [2]. 5 Codec staat voor coder en decoder. 3

Tabel 1.1: Illustratie van de grootordes van ongecomprimeerde data Bron Aard van gegevens Benodigde bits A4 blad met ASCII tekst 8 bits/karakter 28 kilobits 70 karakters/lijn 50 lijnen/pagina AudioCD kwaliteit 44100 samples/seconde/kanaal 14,1 Megabit 16 bits/sample 2 kanalen (10 seconden) Kleurenfoto hoge kwaliteit 1024 768 18,9 Megabits 24 bits/pixel Uitgezonden TV-kwaliteit 720 576 pixels/beeld 1,66 Gigabits 25 beelden/seconde 2 8 bits/pixel (10 seconden) toepassing in de VideoCD, de voorloper van de DVD. Deze DVD zelf bevat dan weer videobeelden die gecodeerd zijn met de H.262/MPEG-2 -standaard en biedt reeds een aanvaardbare kwaliteit voor een hedendaagse langspeelfilm. 1.1.3 Probleemschets Bij het ontwikkelen van een codec dient men steeds een afweging te maken tussen de rekenkracht die daarvoor nodig is en de effectieve compactie die men bekomt. Optimalisaties allerhande zijn nodig om de codecs sneller te laten coderen en decoderen. Men moet steeds voor ogen houden dat we een evenwicht zoeken tussen twee schaarse middelen, nl. rekentijd en opslagplaats. Aanvankelijk is vooral de rekentijd van de decoder van belang, aangezien elke gebruiker deze minstens in realtime moet kunnen uitvoeren om de video thuis te kunnen bekijken. Het is in deze optiek dat we de beschikbare bronnen zo goed mogelijk willen aanwenden om prestatiewinsten op te leveren. 4

P camera preprocessing & encoding public switched server or dedicated user decoding & postprocessing Figuur 1.4: Schematische voorstelling van videoconferencing 1.2 Aanpak en doelstellingen Om tegemoet te komen aan het probleem van de rekenkracht is het een goed idee om de Graphics Processing Unit (GPU) in te schakelen. Deze processor is alomtegenwoordig op hedendaagse videokaarten en dient vooral om 3D-werelden in spelletjes voor te stellen en CAD-toepassingen 6 te ondersteunen. De rekeneenheid is daarom gespecialiseerd in bewerkingen die vooral in grafische toepassingen voorkomen, zoals het tekenen van primitieven en uitvoeren van geometrische transformaties. In specificaties spreekt men van 200 biljoen operaties per seconde en het produceren van 17 miljoen driehoeken per seconde is geen uitzondering meer. Daarbij komt dat volgens een artikel op de site Modeling & Simulation 7 de rekenkracht van de GPUs sneller toeneemt dan die van de CPUs. Voor bepaalde toepassingen kan men zo een NVIDIA GeForce 5950FX vergelijken met een 10GHz Pentium IV processor. Deze enorme bron van rekenkracht blijft evenwel meestal 6 CAD staat voor Computer Aided Design. 7 Voor meer informatie zie: http://www.modelingandsimulation.org/issue9/theedge.html 5

onbenut in het 2D-domein van hedendaagse videotoepassingen en het is de bedoeling om in dit eindwerk daar een mouw aan te passen. We zullen ook de YCoCg-R-kleurenruimte gebruiken voor het opslaan van de videobeelden. Dit kadert in een verder onderzoek naar compactie van video, aangezien deze nieuwe kleurenruimte volgens de literatuur een betere en verliesloze compressie mogelijk zou maken. Deze kleurenruimte wordt verder toegelicht in Hoofdstuk 2. Deze twee elementen combinerend, is het de concrete bedoeling van dit eindwerk om een eerste stap in videocompressie te verwezenlijken in de YCoCg-R-kleurenruimte. We wensen over een eigen encoder en decoder te beschikken waarbij het de bedoeling is dat de beelden kunnen afgespeeld worden op de GPU van het systeem. Onder die eerste stap richting compressie verstaan we bewegingsschatting en -compensatie met behulp van bewegingsvectoren en residubeelden. Een overzicht van de te bekomen workflow is te zien in Figuur 1.5. In de tekening wordt gesuggereerd dat we vertrekken van een opname, waaruit typisch RGB-beelden verkregen worden. Deze beelden uit de RGB-kleurenruimte 8 wensen we dan om te zetten naar YCoCg-R-beelden voor compressie en opslag. Daarna wordt de bewegingsschatting uitgevoerd door de encoder en worden de bewegingsvectoren en residubeelden opgeslagen in een eigen bestandsformaat. Het decoderen bestaat er dan uit deze opgeslagen beelden uit het bestandsformaat te lezen en opnieuw af te spelen. Deze laatste stap wensen we op de GPU te doen omdat dit de prestaties ten goed zal komen. 1.3 Aanverwant onderzoek In deze sectie lichten we de relatie van dit eindwerk tot ander voorgaand en actueel onderzoek toe. Vooreerst werken we verder op het eindwerk van Dieter Van Rijsselbergen [3]. Dit handelde over het aanwenden van de GPU om videobeelden af te spelen die opgeslagen zijn in de YCoCg-R-kleurenruimte. We merken hierbij op dat het gaat over ongecomprimeerde beelden. Hierbij wensen we de bewegingsschatting in te passen in het reeds bestaande werk. Het eindwerk van Bart Pieters [4] kent als onderwerp het afspelen van bewegingsgecompenseerde beelden van de H.264/AVC-codec op de GPU. Het gaat hier voor alle duidelijkheid dan niet over YCoCg-beelden, maar over YUV-beelden 9. Mits aanpassingen moeten de shaders uit de thesis van Bart Pieters zijn thesis bruikbaar zijn 8 In het tweede hoofdstuk valt er ook meer te lezen over kleurenruimtes in het algmeen. 9 Zie Hoofdstuk 2 over de kleurenruimtes 6

scène camera YCoCg-R encoder op CPU bewegingsschatting bewegingsvectoren Residubeelden decoder op GPU 1 01 0010 110001 0000010 010010000 01100100010 1001000011111 bestandsformaat bewegingsvectoren bytes 01010101 10010010 Y 01001001 11010001 01010101 10010010 Co 01001001 11010001 01010101 10010010 Cg 01001001 11010001 8 bits 1 bit extra Y 2 bits extra Co 2 bits extra Cg 8 bits { 1 01 0010 110001 0000010 010010000 01100100010 1001000011111 {gewone planes van 8 bits per pixel bitcollectors bestandsformaat residu-beelden bewegingscompensatie + beeldreconstructie YCoCg-R Figuur 1.5: Overzicht van de workflow van dit eindwerk 7

in dit eindwerk. Het bestandsformaat waarvan eerder al sprake was, is dan ook in samenspraak met hem tot stand gekomen. Voor meer informatie over dit formaat verwijzen we de lezer door naar Hoofdstuk 4. 1.4 Overzicht Tot slot van dit hoofdstuk blikken we even vooruit op wat er volgt. In Hoofdstuk 2 stellen we de YCoCg-R-kleurenruimte voor, waarbij duidelijk moet worden waarom deze onze interesse wekt. We zetten de voor- en nadelen van deze recente kleurenruimte uiteen. In het hoofdstuk dat daarop volgt, komen de algemene principes van bewegingsschatting en bewegingscompensatie aan bod. Deze kennen hun toepassing in de encoder en de decoder. In Hoofdstuk 4 hebben we het dan over de werking en implementatie van de encoder. We hebben het onder meer over de interne structuur van deze applicatie. De werking van de grafische processor en de manier waarop we deze kunnen benutten voor het schrijven van de decoder worden besproken in Hoofdstuk 5. Nadien wordt de implementatie van de decoder besproken in Hoofdstuk 6. Tenslotte bespreken we de bekomen resultaten in het zevende en laatste hoofdstuk. 8

Hoofdstuk 2 YCoCg en aanverwante kleurenruimtes In dit hoofdstuk geven we uitleg over een aantal veel gebruikte kleurenruimtes die besproken worden door Richardson [5]. Daarnaast beschouwen we als hoofdzaak de YCoCg-en YCoCg-R-kleurenruimtes zoals die geïntroduceerd werden door Malvar en Sullivan [6]. De eigenschappen van deze laatste kleurenruimtes vormen de kern van dit hoofdstuk. We besteden hier aandacht aan omdat kleuromzettingen tussen verschillende kleurenruimtes een inherent gegeven zijn bij digitale videoverwerking. 2.1 Algemeen Bij een grijswaardenbeeld is het voldoende om één waarde per beeldpunt bij te houden. Wanneer we kleurenbeelden gebruiken, is dit niet langer voldoende. Verschillende kleurenruimtes lossen dit op op diverse manieren. Dit levert een waaier aan soorten op, die allen over specifieke eigenschappen beschikken. Over het algemeen neemt men aan uit experimenteel onderzoek dat 256 verschillende waarden (dit is voor te stellen door 8 bits of 1 byte) per kleurcomponent voldoende is voor het menselijke oog om een aanvaardbare kwaliteit te leveren. Hieronder zetten we een bespreking uiteen van twee veel gebruikte kleurenruimtes gevolgd door een overzicht van de YCoCg- en YCoCg-R-kleurenruimtes. 9

2.2 De RGB-kleurenruimte De RGB-kleurenruimte stelt een bepaalde kleur voor door van rood, groen en blauw de intensiteiten bij te houden die zich laten samenstellen tot die kleur. Omdat de drie kleurcomponenten ongeveer in dezelfde mate bijdragen tot de resulterende kleur worden ze voorgesteld met dezelfde precisie. RGB24 wordt redelijk courant gebruikt en neemt zo 3 8 = 24 bits in voor het geheel van de drie kleurencomponenten van de pixel. RGB wordt vooral aangewend voor het aansturen van beeldschermen en het opnemen van beelden, waardoor het nog steeds een belangrijke rol vervult. Toch bezit deze kleurenruimte niet de gewenste eigenschappen om videobeelden efficiënt op te slaan. Hieronder volgt meer daarover. Figuur 2.1: De RGB-kleurenruimte 2.3 De YCrCb/YUV-kleurenruimte Uit de studie van het menselijk oog is gebleken dat ons zicht minder gevoelig is voor kleurveranderingen dan voor variaties in lichtsterkte. De RGB-kleurenruimte kan dit gegeven niet benutten aangezien informatie over de luminantie verweven is doorheen de elke kleurcomponent. 10

De YCrCb-kleurenruimte bevat eveneens drie componenten 1. De Ystaat voor de helderheid of ook de luminantie genaamd. Cr en Cb staan voor chrominantie van rood en blauw respectievelijk en bepalen samen de eigenlijke kleur. 2 Figuur 2.2 laat de kleurverdeling van de YCrCb-kleurenruimte zien. Figuur 2.2: Illustratie van Cr- en Cb-component. Dankzij de opsplitsing van kleur en helderheid is het nu wel mogelijk om deze twee factoren apart te behandelen en de relatieve ongevoeligheid van het menselijk oog voor kleurveranderingen te gaan benutten. Daarom zien we vaak dat de chrominantiecomponenten onderbemonsterd worden. Dit komt vaak voor in verlieshebbende compressietechnieken en heeft een beperkte invloed op de beeldkwaliteit. Er volgt een kort overzicht van een aantal mogelijkheden voor onderbemonstering in Figuur 2.3. 4:2:0 wil zeggen dat de Cr- en Cb-componenten zowel verticaal als horizontaal onderbemonsterd worden aan de helft van de resolutie van de luminantie 4:2:2 duidt op het feit dat de chrominantiecomponenten enkel verticaal onderbemonsterd worden aan de helft van de resolutie van de luminantie 4:4:4 hierbij is geen onderbemonstering aanwezig en worden dus alles componenten in volledige resolutie vertegenwoordigd Tenslotte vermelden we ook de formules voor het omzetten van RGB naar YCrCb en omgekeerd. Hierbij vermelden we dat de omzettingen een fout kunnen introduceren. Beide kleurenruimtes bestrijken immers niet exact hetzelfde kleurenbereik. 1 Deze worden ook typisch voorgesteld door 8 bits per component. 2 Cr wordt ook U genoemd en voor de Cb hanteert men dan de letter V, wat aanleiding geeft tot de alternatieve benaming: de YUV-kleurenruimte. 11

4:4:4 4:2:2 4:2:0 Figuur 2.3: Onderbemonstering bij de YCrCb-kleurenruimte Y = 0, 299R + 0, 587G + 0, 114B (2.1) Cb = 0, 563(B Y ) (2.2) Cr = 0, 713(R Y ) (2.3) R = Y + 1, 402Cr (2.4) G = Y 0, 344Cb 0, 714Cr (2.5) B = Y + 1, 772Cb (2.6) 2.4 De YCoCg-kleurenruimte De kleurenruimte waarmee we hoofdzakelijk te maken krijgen in dit eindwerk staat bekend onder de naam YCoCg. Deze werd geïntroduceerd door Malvar en Sullivan [6]. In 2004 werd deze nieuwe kleurenruimte opgenomen als één van de uitbreidingen van de H.264/AVC-standaard. Deze uitbreidingen werden Fidelity Range Extensions (FRExt) genoemd en worden besproken door Sullican et al. [7]. Bij YCoCg staat Y nog steeds voor luminantie. Co staat voor chrominantie ten overstaan van oranje en Cg voor chrominantie ten overstaan van groen. Deze componenten kunnen eenvoudig berekend worden uit de RGB-waarden met behulp van volgende 12

transformatie: Y Co Cg = 1 4 1 1 2 1 4 2 0 1 2 1 4 1 2 1 4 R G B (2.7) Om opnieuw van YCoCg-beelden naar RGB-beelden te gaan, kunnen we onderstaande omzetting gebruiken: R G B = 1 1 1 1 0 1 1 1 1 Y Co Cg (2.8) In deze formules stellen we eenvoudigere operaties vast dan bij de YCrCb-kleurenruimte. Om van RGB naar YCoCg te gaan, heeft men voldoende aan optellingen en bitshifts en omgekeerd volstaan slechts 4 optellingen. Dit komt omdat we tot tweemaal toe te maken hebben met ofwel gehele coëfficiënten ofwel eenvoudige breuken. Het spreekt voor zich dat dit alles aanleiding geeft tot een reductie van de rekencomplexiteit. Nog volgens Malvar en Sullivan [6] is het voornaamste pluspunt van YCoCg de verbeterde prestaties die mogelijk worden met het oog op compactie van videobeelden. De YCoCg-kleurenruimte zou betere decorrelatie-eigenschappen bezitten dan de YCrCbkleurenruimte. Deze eigenschappen zijn van groot belang aangezien naburige beeldpunten juist de neiging hebben om in grote mate op elkaar te gelijken qua helderheid en kleur en dus juist sterk gecorreleerd zijn. Dat dit nefast is voor de compressie is bekend. Dit kan ook nagelezen worden in [5]. YCoCg 8 bits 8 bits 8 bits 10011001 10011001 10011001 Y Co Cg Figuur 2.4: De YCoCg-kleurenruimte zonder onderbemonstering YCoCg-R 8 bits 9 bits 9 bits 13 10011001 110011001 110011001 Y Co Cg

2.5 De YCoCg-R-kleurenruimte In de benaming van de YCoCg-R-kleurenruimte staat de R voor het reversibele of omkeerbare karakter. Dit houdt in dat we een RGB-kleur kunnen transformeren naar een YCoCg-R-kleur en deze opnieuw kunnen omzetten naar exact dezelfde RGB-kleur. Anders gezegd hebben we dus een bijectie tussen de RGB- en YCoCg-R-kleurenruimtes. Om dit te bekomen zou men alle elementen van de transformatiematrix in 2.7 kunnen vermenigvuldigen met een factor 4. Bij de inverse transformatie moeten de resultaten dan opnieuw gedeeld worden door eenzelfde factor 4. Dit heeft echter tot gevolg dat alle kleurcomponenten twee extra bits nodig zouden hebben. Een mogelijke winst aan compressie zou zo verloren gaan. Om dit te voorkomen werden de volgende formules geïntroduceerd: Co = R B t = B + (Co >> 1) Cg = G t Y = t + (Cg >> 1) (2.9) t = Y (Cg >> 1) G = Cg + t B = t (Co >> 1) R = B + Co (2.10) Deze formules zorgen voor een zogenaamde integer-reversible 3 transformatie van en naar YCoCg-R en vereisen slechts twee extra bits in totaal. Eén extra bit is nodig bij de Co-component en één extra bit is nodig voor de Cg-component. De luminantie wordt dus gevrijwaard wat een goede zaak is. Zoals we later zullen zien, wordt bewegingsschatting immers normaal uitgevoerd op enkel de luminantie. Daardoor kunnen bestaande technieken die bijvoorbeeld toegepast worden op de YCrCb-kleurenruimte ook analoog worden uitgevoerd op YCoCg-R-beelden. Desondanks de verbeteringen die Formule 2.9 en Formule 2.10 met zich meebrengen, hebben we nog steeds te kampen met een toename aan data van twee bits per pixel. Volgens Malvar en Sullivan [6] vormt dit nu geen probleem meer. De winst aan compressie dankzij de YCoCg-R-kleurenruimte rechtvaardigt volgens hen de kost van de extra bits. 3 Dit wil zeggen dat we de waarden in de formules als gehele getallen beschouwen. 14

8 bits 8 bits 8 bits 10011001 10011001 10011001 Y Co Cg YCoCg-R 8 bits 9 bits 9 bits 10011001 110011001 110011001 Y Co Cg Figuur 2.5: De YCoCg-R-kleurenruimte zonder onderbemonstering 2.6 Verantwoording Door het nastreven van kwaliteit en omwille van de concrete vraag naar verliesloze beeldcompressie 4 zullen we voor dit eindwerk kiezen om de beelden op te slaan in de YCoCg- R-kleurenruimte. Daarbij valt ook op in de illustraties in figuren 2.4 en?? dat we opteren om geen onderbemonstering toe te passen. Deze keuzes vormen eveneens een voortzetting op het werk verricht in [3] door Van Rijsselbergen. 4 Denk maar aan medische beeldverwerking waar het cruciaal is om beelden verliesloos bij te houden. Getuige hiervan is het artikel van Clunie te vinden op http://www.dclunie.com/papers/spie_mi_2000_ compression.pdf dat handelt over het verliesloos bijhouden van medisch beeldmateriaal. 15

Hoofdstuk 3 Over bewegingsschatting en bewegingscompensatie Dit hoofdstuk legt het algemene principe uit van bewegingsschatting en -compensatie. We zullen deze technieken gebruiken in de encoder en de decoder, wat meteen verklaart waarom we er een hoofdstuk aan wijden. Hierbij baseren we ons hoofdzakelijk op Richardson [5], [8] en Sullivan [9] 1. Aangezien dit onderwerp reeds aan bod kwam in tal van vorige eindwerken binnen deze onderzoeksgroep, trachten we ons hier vooral toe te spitsen op de praktische toepassingen voor dit eindwerk zonder daarbij de algemeenheid te schaden. t Figuur 3.1: Opeenvolgende beelden van een videosequentie 1 Op de site http://www.cs.sfu.ca/coursecentral/365/li/material/notes/chap4/chap4.3/ Chap4.3.html vinden we ook een beschouwelijke uitleg over video compressie. 16

3.1 Algemeen Een videosequentie is in essentie een opeenvolging van stilstaande beelden. Door deze beelden voldoende snel na elkaar af te spelen en te zorgen dat twee opeenvolgende beelden slechts in geringe mate verschillen, wordt de indruk gewekt van een vloeiend bewegend beeld. Dit houdt in dat er overheen een groep van opeenvolgende beelden veel overtollige informatie aanwezig is, zoals ook duidelijk te zien is in Figuur 3.1. Het uitbuiten van deze temporele redundantie is een belangrijk gegeven binnen videocodering. 3.2 Het residu CODEC Encoder Decoder Huidig beeld + - Beeld encoder Gecomprimeerd beeld Beeld decoder + + Huidig beeld Doe voorspelling Doe voorspelling Vorige beeld(en) Vorige beeld(en) Figuur 3.2: Algemene schematische voorstelling van een codec In Figuur 3.2 is een schematische voorstelling te zien van de bouwblokken van een videocodec. Eén van de onderdelen is de voorspelling van het volgende beeld. Zoals we in de voorgaande sectie reeds vermeldden, verschillen twee opeenvolgende beelden in vele gevallen slechts weinig van elkaar. Hierdoor vormt het voorgaande beeld een relatief goede voorspelling van het volgende. Op het moment van het decoderen van een beeld is het vorige beeld reeds voorhanden, waardoor enkel het verschil tussen het huidige en het voorgaande beeld moet doorgestuurd worden naar deze decoder. 17

Dit verschilbeeld (ook residu geheten) zal kleinere pixelwaarden bevatten en dus een lager energieniveau bezitten. Dit zal tot gevolg hebben dat de encoder het door minder bits kan voorstellen. In Figuur 3.3 zien we twee opeenvolgende beelden en hun residubeeld. De grijze pixels in het verschilbeeld wijzen op geen verandering en stellen de waarde 0 voor. Donkere pixels duiden op negatieve getalwaarden en lichte op positieve. - = Beeld 2 Beeld 1 Residubeeld Figuur 3.3: Energie in het residubeeld bij twee statische beelden Wanneer de decoder nu het residubeeld ontvangen heeft, zal hij het op zijn beurt decomprimeren. Daarna is het klaar om opgeteld te worden bij het vorige gedecodeerde beeld. Dit gedecodeerde beeld is zelf het resultaat van een vorig verschilbeeld opgeteld bij het voorgaande gedecodeerde beeld. Het is duidelijk dat indien het comprimeren en decomprimeren van de verschilbeelden niet geheel verliesloos verloopt, dat er dan fouten zullen geïntroduceerd worden in de sequentie. Deze fouten zullen zich makkelijk voortplanten doorheen de videosequentie, waardoor de kwaliteit drastisch kan dalen. Dat er fouten optreden is te wijten aan de quantisatiestap van de encoder. Een mogelijke oplossing voor het probleem van de propagatie van fouten is om in de encoder zelf een voorspelling te doen aan de hand van het gedecodeerde beeld. Dit is aangegeven in Figuur?? en noemt men een decodeerdlus. De fout die bij het comprimeren in het beeld sluipt, wordt zo niet overheen meerdere beelden doorgegeven. In dit eindwerk komen we nog niet toe aan het eigenlijke comprimeren van de data en voeren we dus geen quantisatiestap uit. De constructie die we opzetten zal zelfs zorgen voor een toename aan data en verloopt volledig verliesloos. Daardoor hebben we geen nood aan een decodeerlus in de encoder. 18

Encoder Huidig beeld + - Beeld encoder Gecomprimeerd beeld Doe voorspelling Vorige beeld(en) Beeld decoder Figuur 3.4: Algemene schematische voorstelling van een codec met decoding loop 3.3 Bewegingsschatting De techniek van het residubeeld werkt heel goed op statische beelden, waarbij er weinig beweging optreedt en vooral de achtergrond hetzelfde blijft. Hierbij denken we vooral aan scènes die met een vaste camera opgenomen zijn. Wanneer er echter veel beweging optreedt, zal het residubeeld nog steeds veel informatie bevatten en dus niet goed comprimeerbaar zijn. Dit wordt geïllustreerd door Figuur 3.5, waar het verschil genomen werd tussen twee beelden die meer actie vertonen. Het residubeeld bevat veel minder egaal grijs, wat duidt op een hoger energieniveau. - = Beeld 2 Beeld 1 Residubeeld Figuur 3.5: Energie in het residubeeld bij twee beelden met meer beweging De methode van bewegingsschatting en -compensatie is ontwikkeld om eveneens goed te presteren bij scènes waarin wel veel beweging vervat zit. Deze methode wordt in een aantal stappen verduidelijkt. 19

3.3.1 Soorten gecodeerde beelden Wil men bewegingsschatting toepassen op een beeld, dan moet men steeds vergelijken tegenover een ander videobeeld. Dit andere beeld noemt men het referentiebeeld en hoeft niet altijd het voorgaande beeld te zijn. Reeds vanaf de MPEG-1-standaard spreekt men van drie types gecodeerde beelden, al naargelang de manier waarop ze zich tot het referentiebeeld verhouden. I-beelden: De informatie van deze beelden wordt volledig in het gecodeerde beeld zelf bewaard. Zo worden ze zonder bewegingsschatting naar de verdere stadia in het codeerproces gestuurd. Ze kunnen gebruikt worden als referentiebeelden voor de onderstaande soorten. De letter I in de naam staat voor het feit dat ze ook intrabeelden genoemd worden. P-beelden: Waar de vorige soort van beelden intra-gecodeerd werd, worden P-beelden inter gecodeerd. Hierbij wordt er dus wel gebruikgemaakt van voorspellingen aan de hand van bewegingsschatting. Het gaat hier over voorwaartse predictie. Een P-beeld heeft steeds als referentie een ander P-beeld of I-beeld dat dit beeld zelf voorafgaat. B-beelden: Deze beelden vormen een uitbreiding op het concept van de P-beelden. Ze gebruiken namelijk voor de bewegingsschatting twee referentiebeelden. Hiervoor neemt men één P- of I-beeld voor en één P- of I-beeld na het huidige B-beeld. De B staat dan ook voor de bidirectionele verwijzingen die deze beelden bevatten naar hun referentiebeelden. Een voorbeeld van hoe deze verschillende soorten in een sequentie kunnen voorkomen, is te zien in Figuur 3.6. Hierin wijzen de pijlen naar de referentieblokken van het beschouwde macroblok. 3.3.2 Keuze van referentiebeelden Uit het bovenstaande blijkt dat de voorwaartse bewegingsschatting steeds een beeld uit het verleden zal gebruiken als referentie. Dit zal vaak, maar niet altijd een goed resultaat opleveren. Treedt er bijvoorbeeld een overgang op tussen twee scènes dan zal het vorige beeld geen goed referentiebeeld vormen. Een volgend intrabeeld zal meer aangewezen zijn 20

Figuur 3.6: Voorbeeld van de verschillende soorten beelden als kandidaat referentiebeeld. Sommige encoders gaan zelfs een stap verder en hanteren methodes voor scènedetectie om van het eerste beeld na een bruuske scèneovergang (ook een cut genaamd) een intrabeeld te maken. Hierbij zouden bijvoorbeeld technieken kunnen gebruikt worden die we reeds besproken hebben in [10]. Ook wanneer er geen cut optreedt, kan een voorwaartse voorspelling een slecht resultaat opleveren. Denken we bijvoorbeeld aan een deur die opengaat. Hetgeen zich achter de deur bevindt, zal niet te zien zijn in voorgaande beelden. Achterwaartse bewegingsschatting zal hier in beide gevallen de oplossing bieden. Hierbij kan namelijk een toekomstig beeld als referentiebeeld genomen worden. Dit houdt wel in dat de decoder dit referentiebeeld eerst ter beschikking moet hebben alvorens hij de vorige frames kan reconstrueren. Dit zal enig gebruik van buffers vergen. In bepaalde gevallen zal een bidirectionele bewegingsschatting nóg beter presteren. Dit houdt in dat we beide voorgaande principes verenigen en zowel een toekomstig als een beeld uit het verleden gaan gebruiken en deze zullen samennemen als referentie. Om nu concreet in de encoder een keuze te maken welke van de bovenstaande technieken we zouden gebruiken, kan de encoder deze alledrie uitproberen en diegene die de minimale energie oplevert eruit kiezen. Over minimale energie hebben we het in Sectie 3.3.4. 3.3.3 Macroblokken Voor een zo goed mogelijke voorspelling is het aangewezen videobeelden niet langer als één geheel te beschouwen. Daarom worden de beelden ingedeeld in zogenaamde macroblokken. In Figuur 3.6 is al aangegeven dat de predictie en de verwijzingen eigenlijk gebeuren tussen 21

stukken van de beelden in plaats van tussen de volledige beelden. Een macroblok is een vierkant van 16 16. Het van het Grieks afkomstige voorvoegsel macro duidt op het feit dat een macroblok verschillende kleinere blokken kan bevatten. Men noemt deze ook partities en deze hoeven op hun beurt geen vierkanten te zijn. In Figuur 3.7 zien we een illustratie van het opdelen van een beeld in macroblokken. residublok macroblok macroblok Figuur 3.7: Illustratie macroblokken en het residu 3.3.4 Minimale energie Het is nu de bedoeling om per macroblok in het huidig beeld op zoek te gaan naar een macroblok uit een ander beeld dat minimaal verschilt met het huidige. Als we het verschil nemen van beide blokken, bekomen we als het ware een residumacroblok met een minimale energie. In principe komt elk macroblok uit gelijk welk beeld in aanmerking. In de praktijk zullen we de zoekruimte moeten beperken vanwege het rekenintensieve karakter van het opzoekwerk. Daarbij komt ook dat we rekening moeten houden met de verschillende soorten beelden. Om twee macroblokken met elkaar te vergelijken en om zo de energie van het residumacroblok te minimaliseren, komen verschillende technieken in aanmerking. Hieronder geven we een paar mogelijkheden. In al deze formules staat de C ij voor een pixel van het 22

macroblok van het huidige frame, terwijl R ij staat voor de pixel van het referentiebeeld. Hierbij zullen we enkel de luminantie van de beelden beschouwen, aangezien we hierin veranderingen goed kunnen waarnemen en het minder zinvol is om ook de chrominantie in acht te nemen. Hieronder beschouwen we een drietal formules waarmee men de energie kan berekenen tussen twee macroblokken van de grootte N N. De MSE of Mean Square Error: MSE = 1 N 2 MAE staat voor Mean Absolute Error: MAE = 1 N 2 N 1 i=0 N 1 i=0 N 1 j=0 N 1 j=0 (C ij R ij ) 2 (3.1) C ij R ij (3.2) De afkorting SAE komt van Sum of Absolute Errors en wordt ook SAD of Sum of Absolute Differences genoemd: SAE = N 1 i=0 N 1 j=0 C ij R ij (3.3) MAE en SAE zijn in feite benaderingen van MSE. Zo heeft MAE geen kwadraat meer in de formule staan, waardoor deze makkelijker en sneller uit te rekenen is. In Formule 3.3 is de term 1 N 2 ook nog weggelaten, waardoor het rekenwerk nogmaals verlicht wordt. Het opzoeken van het referentieblok en de daarmee gepaard gaande berekeningen van de minimale energie zijn een cruciaal en tijdrovend proces bij bewegingsschatting. Daarom is een goede keuze aangewezen. Zo kan er in het volledige beeld gezocht worden naar het minimale blok. In praktische toepassingen zal men meestal een zoekvenster bepalen rond de positie van het macroblok in het huidige beeld. Dit zoekvenster gebruikt men in het referentiebeeld om daarin op zoek te gaan naar het macroblok dat daar het best overeenkomt. Heeft men het in de literatuur over een zogenaamd full search algoritme, dan bedoelt men meestal dat het volledige zoekvenster afgezocht wordt en niet het volledige beeld. Het beperken van de zoekruimte zal uiteraard niet altijd de optimale oplossing opleveren, en is naargelang de grootte van de zoekruimte nog steeds rekenintensief. Snellere methodes gaan eerder op zoek naar een lokaal minimum voor de residuele energie. Dit 23

wil zeggen dat ze niet de volledige zoekruimte zullen overlopen, maar slechts een aantal posities zullen onderzoeken. Voor een overzicht van deze snellere zoekalgoritmes verwijzen we graag naar [5]. zoeken naar minimale MSE macroblok zoekvenster zoekvenster referentiebeeld huidig beeld Figuur 3.8: Illustratie van het zoekvenster 3.3.5 Bewegingsvectoren Aan de decoder kant krijgt men enkel de residubeelden die bestaan uit residumacroblokken toegestuurd. Op deze blokken zal men bewegingscompensatie willen toepassen, zoals toegelicht wordt in wat volgt. Hiervoor moet de decoder weten welk macroblok uit welk referentiebeeld er bij dit residublok moet opgeteld worden. Daarvoor is er nog nood aan wat we bewegingsvectoren noemen. Deze bevatten precies de ontbrekende informatie. Naargelang de informatie die moet bijgehouden worden, kunnen de bewegingsvectoren verschillende vormen aannemen en er kunnen ook meerdere bewegingsvectoren per macroblok voorkomen, zoals dat het geval is bij B-beelden. 3.4 Bewegingscompensatie Onder bewegingscompensatie verstaat men het proces dat voor het wedersamenstellen zorgt van de residubeelden tot volwaardig gedecodeerde beelden. De verschilmacroblokken zullen dus opgeteld worden bij de juiste referentiemacroblokken om zo het beoogde originele beeld te bekomen. Als alle informatie voorhanden is, gaat het hier dus over een eenvoudige optelsom. Maar voor het ophalen van de juiste informatie is toch nog relatief veel tijd nodig, waardoor een groot deel van de decodeertijd hieraan gespendeerd wordt. 24

In Figuur?? tenslotte zien we een algemeen schema van een codec met bewegingsschatting bij de encoder en bewegingscompensatie bij de decoder. Dit geeft een globaal CODEC met bewegingsschatting overzicht van hoe de techniek werkt. en decoding loop Encoder Decoder Huidig beeld bewegingsgecompenseerde voorspelling + - Beeld encoder Gecomprimeerd beeld Beeld decoder + + Huidig beeld Doe voorspelling Bewegingsvectoren Doe voorspelling Bewegingsschatting Vorige beeld(en) Beeld decoder Vorige beeld(en) Figuur 3.9: Schema van codec met bewegingscompensatie en -schatting met decoding loop 3.5 Uitbreidingen Hier geven we een drietal uitbreidingen op het hierboven uiteengezette model. Uiteraard is dit niet sluitend en zijn er nog tal van andere mogelijkheden. 3.5.1 Sub-pixel bewegingsschatting In het voorgaande werd uitgegaan van macroblokken die tot op de pixels van het beeld nauwkeurig waren. Een object in een videosequentie beweegt zich echter niet noodzakelijk met een geheel aantal pixels. Daarom is het een goed idee om te werken met bewegingsvectoren die verwijzen naar macroblokken waarvan de grenzen zich tussen twee pixels kunnen bevinden. 25

Wil men nu bijvoorbeeld tot op een halve pixel nauwkeurig werken, dan zal men de videobeelden moeten interpoleren om een beeld te verkrijgen dat vier maal zo groot is. Dit doet uiteraard de complexiteit en het geheugengebruik toenemen, maar de kwaliteit van de bewegingsschatting kan wel sterk verbeteren. 3.5.2 Bewegingsvectoren buiten het referentiebeeld Tot nu toe konden macroblokken uit het referentiebeeld slechts binnen het beeld liggen. Maar als een object langzaam uit het beeld verdwijnt kan het beter zijn om de bewegingsvector naar een blok te laten verwijzen dat voor een stuk buiten het referentiebeeld ligt. 3.5.3 Variabele blokgroottes Hoe kleiner het macroblok hoe nauwkeuriger de bewegingsschatting, maar ook hoe meer informatie onder de vorm van bewegingsvectoren moet bijgehouden worden en hoe meer rekenwerk vereist is. Voor weinig complexe beelden zijn grote macroblokken aangewezen, maar dat geldt in de omgekeerde richting voor beelden van een hoge spatiale complexiteit. Daarom biedt de mogelijkheid om over te gaan van de ene blokgrootte naar de andere al naargelang de aard van de videobeelden een extra troef voor de bewegingsschatting. 26

Hoofdstuk 4 De encoder In dit hoofdstuk geven we uitleg bij de encoder die op YCoCg-R-beelden bewegingsschatting zal toepassen. 4.1 Situering Eerst en vooral was het de bedoeling om bewegingsschatting te introduceren in de YCoCg- R-kleurenruimte. Daartoe werd er een eigen toepassing geschreven die de naam MVCoder meekreeg. Denken we terug aan de workflow in Figuur 1.5 op pagina 7 dan zien we daarin dat de encoder reeds kan vertrekken van YCoCg-R-beelden. Het verkrijgen en stockeren van deze beelden in de YCoCg-R-kleurenruimte was immers het werk van Dieter Van Rijsselbergen [3]. MVCoder moet dus een stap zetten richting videocompressie en zal bewegingsvectoren en residubeelden berekenen en wegschrijven in een aangepast bestandsformaat. 4.2 Structuur van de applicatie Voor het implementeren van de functionaliteit van deze applicatie werd voor een gestructureerde aanpak gekozen. In Figuur 4.1 ziet men een vereenvoudigd UML-schema van de klassenstructuur van MVCoder. De klasse FrameCollector staat centraal in de applicatie. Hiermee worden de beelden ingelezen en bestanden die de bewegingsvectoren en residubeelden bevatten worden uit- 27

YCoCgReader Bitcollector FrameCollector 1 1 * Bitcollector ResidualWriter 1 1 +fillresidualframewindow() +getmotionvectors() +writeresidualframe() +writemotionvectorfile() +writedecodedsequencetofile() 1 1 * MotionVector MVWriter * 1 1 1 * YCoCgRFrame * 1 Bitcollector * residubeelden YCoCgRFrame YCoCgMacroBlock ingelezen beelden 1 * Figuur 4.1: Een summier UML-schema van de encoder geschreven. Hiervoor bevat de klasse publieke en private functies, waarvan er een aantal zijn afgebeeld op het schema. De methodenamen spreken voor zich en zijn bedoeld om de functionaliteit aan te geven van de klasse. Zo zijn er methoden voor het uitschrijven van de residubeelden en bewegingsvectoren, alsook voor het opvragen van deze gegevens. In een later stadium werd ook een decoder ingebouwd om de correctheid van de encoder te controleren. Getuige hiervan is de methode writedecodedsequencetofile(). De uitgeschreven bestanden kunnen dan via het binair vergelijken met de originele bestanden gecontroleerd worden op hun correctheid. YCoCgReader bevat de volgens zijn naam evidente functionaliteit dat het de ongecomprimeerde YCoCg-R-beelden inleest uit het bestandsformaat van Dieter Van Rijsselbergen [3]. De klasse YCoCgWriter schrijft objecten, geïnstantieerd van de klasse YCoCgRFrame, uit naar een bestand, waarbij het de bedoeling is dat deze gewone beelden voorstellen en geen verschilbeelden. Deze functie is voorzien om enerzijds het inlezen te testen. Zo konden we nakijken of het uitgeschreven bestand exact overeenkwam met het originele bestand. Want aangezien er gewerkt wordt met bitcollectors was dit niet zonder meer vanzelfsprekend. Anderzijds is de YCoCgWriter ook gebruikt voor het uitschrijven van 28

gedecodeerde beelden. Ook hier laat dit ons toe om de correctheid van de encoder te controleren. De klasse BitCollector vergemakkelijkt het gebruik van bitcollectors. Dit concept werd reeds gebruikt in het bestandsformaat vanwaar we vertrokken en wordt verder behandeld in sectie 4.3.2 waar we het over de gebruikte bestandsformaten hebben. Een object van de klasse YCoCgRFrame stelt een YCoCg-R-beeld voor en houdt de luminantie- en chrominantiegegevens bij in het geheugen. Hiermee samenhangend zijn er objecten van het type YCoCgMacroBlock die toelaten om de beeldgegevens van een bepaald macroblok te manipuleren. Deze laatste klasse houdt slechts verwijzingen bij naar de beelddata, waardoor bewerkingen op een macroblok onmiddellijk weerslag hebben op het videobeeld zelf, hier dan onder de vorm van een object van het type YCoCgRFrame. Zo wordt onnodig kopiëren van data en overdadig geheugengebruik vermeden. Wanneer we residubeelden berekenen, willen we de originele beelden wel nog behouden in het geheugen voor eventueel ander gebruik later in het proces. In dit geval zullen er dus wel kopieën genomen worden, maar wel heel bewust. Verder is er ook nog de klasse MotionVector die dient voor het bijhouden van de bewegingsvectoren en zijn er de writers voor de residubeelden en de bewegingsvectoren, respectievelijk de ResidualWriter en de MVWriter genaamd. Deze uiteenzetting die hopelijk enig inzicht verschaft in de structuur van MVCoder zou het een relatief makkelijk uitbreidbaar programma moeten maken. Zo kunnen bijvoorbeeld andere methodes ingepast worden voor de berekening van de bewegingsvectoren, zoals die bijvoorbeeld vermeld staan in Hoofdstuk 3 pagina 22. 4.3 Algemene werking 4.3.1 Bewegingsschatting toegepast In Hoofdstuk 3 kwam reeds de bewegingsschatting aan bod. Hier zullen we aangeven welke concrete weg we zullen volgen om tot de residubeelden en bewegingsvectoren te komen. Zoals hierboven reeds aangehaald is, staat de klasse FrameCollector centraal. De klasse biedt de volledige functionaliteit aan aan zijn gebruiker. Hierbij kunnen een aantal parameters meegegeven worden bij constructie. 29

FrameCollector* frames = new FrameCollector(decodedSequenceOutputFile, filename, residuoutputfile, motionvectoroutputfilename, width, height, numberofframes, neighbourpixelstosearch, widthmacroblock, heightmacroblock); Tal van bestandsnamen moeten gespecificeerd worden, waarbij filename het bronbestand aangeeft waar de YCoCg-R-beelden in vervat zitten. Andere bestandsnamen geven de locaties aan van de doelbestanden. Ook gedecodeerde beelden worden zo uitgeschreven. De afmetingen van de videobeelden zijn ook belangrijk en nemen ook twee argumenten in beslag. Het aantal beelden dat per keer gecodeerd zal worden, geeft men aan via numberofframes. Zo werkt men met een soort van venster van een vast aantal beelden dat telkens met dit aantal beelden verspringt over de hele sequentie. Voor de eenvoud zal het eerste beeld van het venster steeds intragecodeerd worden en de volgende beelden gebruiken steeds het voorgaande beeld als referentiebeeld. neighbourpixelstosearch geeft de zoekruimte aan voor de bewegingsschatting en duidt aan hoeveel naburige pixels er beschouwd worden rond het huidige macroblok. Tenslotte dienen ook de breedte en hoogte van de macroblokken meegegeven worden als argument. In de constructor van dit object worden meteen de benodigde YCoCg-R-beelden ingelezen in het werkgeheugen. De ingelezen beelden worden dan onmiddellijk gecodeerd. Hierbij zal telkens het eerste beeld van het ingelezen deel het intrabeeld zijn. Het wordt dus simpelweg gekopieerd. Elk volgende beeld gebruikt het voorgaande als referentie. Bewegingsvectoren zijn dus pas van toepassing vanaf het tweede beeld. Vertrekkende van dit tweede beeld, beschouwen we dan alle disjuncte macroblokken van de bepaalde grootte die samen het beeld opmaken. Voor elk van deze macroblokken gaan we opzoek naar een zo gelijkaardig mogelijk macroblok uit het zoekvenster van het referentiebeeld, dat hier het voorgaande beeld is. In dit zoekvenster beschouwen we alle mogelijke macroblokken en berekenen we de MSE van het huidige macroblok ten opzichte van datgene uit het referentiebeeld. Het macroblok dat de kleinste MSE-waarde oplevert, wordt gekozen als zijnde het referentiemacroblok. De bewegingsvectoren worden opgesteld en verwijzen naar de juiste positie van het referentiemacroblok. De afmetingen van de macroblokken zijn ook voor de decoder gekend en het referentiemacroblok komt steeds uit het voorgaande beeld, zodat we enkel de coördinaten van de linkerbovenhoek moeten kennen. Daarna berekenen we het verschil tussen deze twee macroblokken en vullen we dit in in het residubeeld op de plaats van het huidige macroblok. 30

1 01 0010 110001 0000010 010010000 01100100010 1001000011111 Passen we dit principe toe op alle beelden, dan verkrijgen we zo de bewegingsschatting op de hele sequentie. In Figuur 4.2 zien we een overzicht van de methode. 1 01 0010 110001 0000010 010010000 01100100010 1001000011111 FrameCollector YCoCg-R readnextframe() video.ycocg getmotionvectorarrayfromframe referentiemacroblok retrieveresidualframe - huidig macroblok residu MotionVector MotionVector MotionVector MotionVector MotionVector MotionVector MotionVector writemotionvectorwindowtofile() YCoCg-R 1 01 0010 110001 0000010 010010000 01100100010 1001000011111 video.mv writeresidualframewindowtofile() YCoCgRFrame YCoCgRFrame YCoCgRFrame YCoCgRFrame YCoCgRFrame YCoCgRFrame YCoCgRFrame video_residu.ycocg Figuur 4.2: Schematische voorstelling van de bewegingsschatting in MVCoder Tot slot van deze sectie vermelden we nog dat we hier met subpixel precisie werken. Daarvoor zouden we het huidige beeld en het referentiebeeld moeten interpoleren en ze daarna met elkaar vergelijken. Het is perfect mogelijk om dit in de bestaande structuur in te passen op een handige manier. 31

4.3.2 Bestandsformaten In deze sectie volgt de uitleg van de gekozen bestandsformaten. Er komt ook enige verantwoording aan bod wat betreft gemaakte keuzes. Ongecomprimeerd bestandsformaat Het ongecomprimeerde bestandsformaat vormt het vertrekpunt van MVCoder en is niet de verdienste van dit eindwerk. We hernemen het hier voor de volledigheid en ook om een subtiel maar belangrijk verschilpunt duidelijk te maken. Het bestandsformaat werd geïntroduceerd door Van Rijsselbergen [3]. In Figuur 4.3 staat het schematisch voorgesteld. Bestandsformaat Y Pixelformaat Y Co Cg Co Bit Collector 8 bits 1 bit Cg 8 bits 8 bytes 1 byte Figuur 4.3: Bestandsformaat voor gewone YCoCg-R-beelden De waarden voor de Y, Co en Cg worden in planes opgeslagen, wat wil zeggen dat we eerst alle Y-waarden van een frame wegschrijven achter elkaar en dan pas naar de volgende kleurcomponent overgaan. Dit bestandsformaat had nog niets te maken met bewegingsschatting en dus hebben we nood aan slechts 8 bits voor elke Y-waarde en 9 bits voor de Co- en Cg-waarden, zoals vermeld in Hoofdstuk 2 bij de paragraaf over de YCoCg- R-kleurenruimte. De Y-waarden worden dus zonder meer in het bestand weggeschreven door in C++ het type unsigned char te hanteren. Dit komt neer op het wegschrijven van bytes. 32

Bij de Co- en Cg-componenten volstaat het bijhouden van één byte per pixel dus niet. Voor het stockeren van de extra 9de bit werd geopteerd voor een zogenaamde bitcollector. Na 8 bytes zijn er eigenlijk net 8 1 bit te weinig geweest en dus houdt men een byte bij waarvan de eerste bit de ontbrekende bit is van de eerste byte, de tweede bit die van de tweede byte enz. In dit bestandsformaat wordt de byte van de bitcollector onmiddellijk bijgehouden na de desbetreffende 8 voorgaande bytes. Dankzij de bitcollector wordt er geen schijfruimte verspild, maar het samenstellen en ontrafelen van ervan vraagt wel enige rekentijd bij zowel het inlezen als het uitschrijven. Daarbij komt ook dat het de implementatie enigszins kan bemoeilijken. Wat de benodigde opslagruimte betreft, is het logisch dat dit bestandsformaat voor zijn Y-componenten breedte hoogte bytes inneemt en voor zijn Co- en Cg-componenten telkens breedte hoogte + breedte hoogte 8 bytes. In totaal levert dit volgende vergelijking: bytes totaal = (3 hoogte breedte) + (2 hoogte breedte ) (4.1) 8 Tot hiertoe verloopt alles gelijklopend met het bestandsformaat uit het voorgaande eindwerk van Dieter Van Rijsselbergen [3]. Als we nu echter de formules 2.7 ontleden, dan merken we op dat in tegenstelling tot de RGB-waarden, de YCoCg-R-waarden wel degelijk negatief kunnen zijn. Het waardenbereik breidt zich hierdoor uit van [0, 255] tot [ 255, 255]. Het is dus belangrijk om dit teken niet verloren te laten gaan bij de omzetting van RGB naar YCoCg-R. Daarom wordt de extra bit geïnterpreteerd als zijnde de tekenbit. Dit is niet het geval in het eindwerk van Dieter Van Rijsselbergen en vormt dus een belangrijk verschil dat ervoor zorgt dat er een compatibiliteitsprobleem ontstaat tussen beide bestanden. Daarom zijn er ook tools ontwikkeld om rechtstreeks van RGB naar dit YCoCg-R-bestand om te zetten, waarbij we dus niet meer vertrekken van het formaat van het voorgaande eindwerk. De reden dat we dit verschil toch behouden, is dat dit voordelen biedt aan de decoder. Zoals later duidelijk wordt, is het behoud van het correcte teken aan de decoder kant een goede zaak. Er valt zo een ingewikkelde afrondingsstap weg. Daarbij komt dat het beschouwen van een tekenbit ook consequent is met het bestandsformaat voor residubeelden 1. Dit laatste komt in de volgende sectie aan bod. 1 Het spreekt voor zich dat bij een verschilbeeld het teken van belang is. 33

Bestandsformaat voor residubeelden De verschilbeelden zijn in feite ook YCoCg-R-beelden en kunnen dus op een gelijkaardige manier opgeslagen worden. Maar het belangrijkste verschil ligt in het feite dat we een extra bit nodig hebben en dit bij elke component, aangezien het om een verschil gaat en we zeker het teken moet bijhouden. Voor de Y-component breidt het waardenbereik dus uit van [0, 255] naar [ 255, 255], wat we kunnen voorstellen door 9 bits. De Co- en Cg-component bestrijken nu het bereik van [ 511, 511] in de plaats van [ 255, 255]. Dit levert dus de nood 10 bits voor deze rwee laatste componenten. Het principe van de vorige paragraaf wordt nu opnieuw gebruikt voor de 9 bits en uitgebreid waar nodig om 10 bits precisie te bekomen. In Figuur 4.4 ziet met het bestandsformaat schematisch voorgesteld. bytes 01010101 10010010 Y 01001001 11010001 01010101 10010010 Co 01001001 11010001 01010101 10010010 Cg 01001001 11010001 8 bits 1 bit extra Y 2 bits extra Co 2 bits extra Cg 8 bits { 1 01 0010 110001 0000010 010010000 01100100010 1001000011111 {gewone planes van 8 bits per pixel bitcollectors Figuur 4.4: Bestandsformaat voor verschilbeelden in de YCoCg-R-kleurenruimte We gebruiken dus opnieuw bitcollectors op dezelfde manier als bij het vorige bestandsformaat, maar het belangrijkste verschil is dat we deze niet meteen in de plane van de component stoppen na de andere bytes maar dat we ze samennemen en na de planes van de drie componenten zetten. Zo kunnen we eerst gewoon alle bytes die de laagste 8 bits bevatten inlezen van de Y-,Co-en Cg-componenten. Dit versnelt dus het inlezen omdat 34

we meteen het ganse blok kunnen nemen en de bytes van de bitcollectors er niet meer hoeven uit te halen. Om 10 bits bij te houden is het logisch dat we nu 2 bytes nodig hebben voor onze bitcollector per 8 pixels en dit voor de Co- en Cg-component. Toen we deze uitbreiding maakten, leek het ons handig om het principe van de bitcollector in een klasse te gieten die dan de juiste bits uit de bytes kan puren en ook de bytes van collector opnieuw kan samenstellen. Dit is de klasse BitCollector die ook terug te vinden is in het UML-schema in Figuur 4.1. Bij constructie van een object van deze klasse kan men de precisie in aantal bits meegeven alsook het feit of we de meest significante bit als tekenbit beschouwen of niet, waardoor dit ook handig kan zijn voor andere toepassingen met een andere precisie. Een verschilbeeld zal dus door toedoen van het teken meer bits nodig hebben dan een gewoon YCoCg-R-beeld. We geven weer een formule voor het benodigde aantal bytes: bytes totaal = (3 hoogte breedte) + Bewegingsvectoren hoogte breedte 8 + (2 hoogte breedte ) (4.2) 4 Ook de bewegingsvectoren dienen nog opgeslagen te worden in een bestand. Aangezien we steeds het vorige beeld als referentie gebruiken, moeten we enkel de relatieve coördinaten bijhouden van het referentiemacroblok waarmee het residubeeld verkregen werd. Het gaat hier dus ook over mogelijk negatieve getallen. 2 De klasse MVWriter schrijft deze getallen uit als integers die zodoende telkens 4 bytes per getal, of dus 8 bytes per bewegingsvector innemen. We zijn er ons van bewust dat hier wel degelijk plaatsverspilling optreedt, maar hier hebben we voor de eenvoud van het inlezen en uitschrijven gekozen. Er zou dan ook op een makkelijke manier voor een compacter bestandsformaat kunnen gekozen worden, maar het nut blijft ook beperkt aangezien de bewegingsvectoren nog doorheen de volgende stadia van het codeerproces zullen verwerkt worden. Voor de verschilbeelden gaat het over veel grotere hoeveelheden van data, waardoor het onhandig zou zijn als we hierbij veel plaats zouden verspillen. 2 Aangezien we de X-as naar rechts en de Y-as naar onder beschouwen, verwijst een bewegingsvector met waarde (-1,1) bijvoorbeeld naar het macroblok 1 pixel naar links en 1 pixel naar boven. 35

4.4 Controlepunten MVCoder codeert niet enkel de YCoCg-R-beelden naar residubeelden en bewegingsvectoren. Er zitten ook controles in verwerkt om de correctheid te garanderen van de bewerkingen die het toepast. Dit is geen overbodige luxe want zoals bijvoorbeeld blijkt uit de hierboven beschouwde bitcollectors, moeten er vele zaken gebeuren op bitniveau. Het dient niet gezegd dat dit vaak zeer foutgevoelig is. Toch werd er ook voor gezorgd dat deze controles afgezet kunnen worden. We willen immers niet dat, eens we een correct werkende encoder hebben, hier extra rekentijd aan verloren gaat. De correctheid van de verschillende readers en writers werd gecontroleerd door onmiddellijk na inlezen de beelden opnieuw uit te schrijven en de resultaten te vergelijken. De belangrijkste controle bestaat er uit om na het coderen het proces volledig om te keren en de beelden terug te decoderen. Dit levert opnieuw gewone YCoCg-R-beelden op die opgeslagen worden in het formaat van sectie 4.3.2. Deze zullen we dan byte per byte vergelijken met het oorspronkelijke bestand via de klasse BinaryFileCompare. Aangezien we via extra tools (zie sectie 4.6) ook rechtstreeks van RGB-beelden kunnen vertrekken, is het ook aangewezen om deze YCoCg-R-beelden opnieuw om te zetten naar de RGB-kleurenruimte. Deze RGB-data wordt dan weggeschreven in opeenvolgende planes en op analoge wijze vergeleken met het originele bestand. is. Wanneer deze controles slagen, kan men er vanop aan dat het codeerproces geslaagd 4.5 Prestaties Het dient gezegd dat MVCoder geen snelheidsduivel is. Dit was ook niet hetgeen we voor ogen hadden bij het ontwerp van deze applicatie. De encoder moest ons vooral data aanleveren om later weer te kunnen decoderen. Zo werd er geopteerd voor een zo duidelijk mogelijke klassenstructuur om de code ook naar de toekomst bruikbaar te maken. De prestaties van MVCoder hangen nauw samen met de waarden van de parameters. Uiteraard speelt de grootte van de beelden een enorme rol, maar ook de grootte van de macroblokken, de zoekruimte en het aantal beelden dat in een keer in het geheugen geplaatst wordt. Al deze factoren zorgen ervoor dat MVCoder voor de ene instellingen 36

beelden codeert in ware-tijd en voor andere instellingen zeker een factor 1000 trager is. Prestatiemetingen van MVCoder zijn dan ook niet relevant voor dit eindwerk. Als mogelijke verbetering kunnen we wel een aantal zaken opmerken. Eerst en vooral is er de uitgebreide klassenstructuur. Als verantwoording voor deze keuze geldt de uitbreidbaarheid die daarmee gepaard gaat en ook de overzichtelijkheid die het opsporen van fouten vergemakkelijkt. Maar het nadeel is dat OO-programmering niet de meest snelle uitvoering is. Als tweede belangrijk punt is er het opsporen van het macroblok met minimale energie. In MVCoder gebeurt dit vooralsnog via de MSE te berekenen. We zouden dit ook kunnen doen met andere benaderende formules zoals vermeld in Hoofdstuk?? in sectie 3.3.4. Onze implementatie kijkt naar alle mogelijke macroblokken in het zoekvenster van het referentiebeeld, waardoor formule voor minimale energie elke keer weer moet berekend worden en dit een grote impact zal hebben op de prestaties. De zoekruimte beperken of niet volledig overlopen zal ook een positieve invloed hebben op de prestaties, maar zal de nauwkeurigheid van de bewegingsschatting niet ten goede komen. 4.6 Andere tools Er werden ook een aantal andere programma s ontwikkeld die aansluiten bij het codeerproces. Zij zorgen voor omzetting van bestandsformaten en dergelijke meer en zorgen ervoor dat we van RGB-beelden kunnen vertrekken in onze workflow en dienen ook voor een aantal testen. FullRGBImageProducer maakt RGB-beelden die alle mogelijke RGB-waarden bevatten. Er werd gekozen voor een formaat van 256 256 pixels en als we zo een sequentie van 256 beelden nemen dan kunnen we alle RGB-kleuren voorstellen. Een dergelijke sequentie is handig om te testen of alle kleuren wel goed afgespeeld worden door de decoder. Daarbij zijn het kleine beelden, waardoor het coderen en afspelen vlot gebeurd. RGBToYCoCgRConvertor zet RGB-beelden om naar YCoCg-R-beelden die compatibel zijn met de encoder en decoder van dit eindwerk. De RGB-data moet in één groot bestand opgeslagen zijn en in planes geordend zijn met telkens 8 bits precisie voor elke kleurcomponent. 37

RGBRawConvertor werd gemaakt omdat we een testsequentie kregen die in interleaved RGB-beelden opgeslagen was en in aparte bestanden. Om dit euvel te verhelpen, maakten we RGBRawConvertor die deze bestanden kan omzetten naar het gewenste formaat. ResidualImageCreator heeft minder te maken met het codeerproces, maar is gebruikt om residubeelden te maken om in het thesisboek te kunnen opnemen. De applicatie vertrekt van twee RGB-beelden in planes opgeslagen. 38

Hoofdstuk 5 Over shaders, de GPU en Direct3D Dit hoofdstuk draait rond de grafische rekeneenheid en shaders. Een aantal begrippen en concepten worden uitgelegd die nodig zijn voor het aanwenden van de rekenkracht van de GPU in de Direct3D-omgeving van DirectX. We baseerden ons vooral op de werken van Engel [11, 12], Gray [13], Luna [14] en Shen et al. [15], [16]. Daarnaast vormden ook voorgaande eindwerken zoals Van Rijsselbergen [3], Pieters [4] en Hollemeersch [17] een bron van inspiratie. 5.1 De oorsprong van de GPU Zoals reeds in het inleidende hoofdstuk aangehaald is, dient de grafische processor voor het weergeven van 3D-werelden. Dit speciaal stukje hardware moet zijn taak uiteraard op een snellere manier kunnen doen dan wanneer alleen een klassieke CPU voorhanden is. Het verhaal van de grafische processor begon reeds in de jaren 1970 en 1980. In die tijd zat je als gamer nog naar een platte 2D-wereld te kijken waar de pixels vingerdik op lagen. Toch werden er toen ook al inspanningen gedaan om de beelden snel genoeg weer te geven. De animaties in die tijd werden gemaakt door het weergeven van zogenaamde sprites. Een sprite is een 2D-beeld dat deel uitmaakt van de volledige scène. Door het tonen van opeenvolgende versies van deze sprites zoals in Figuur 5.1 te zien is, simuleerde men bijvoorbeeld de beweging van een figuurtje. Om dit efficiënt te doen, werden instructies voorzien die hele blokken van pixels konden kopiëren (ook blitting genaamd). 39

Figuur 5.1: Voorbeeld van sprites Zo ontstond de eerste versnelling in hardware voor grafische doeleinden. Als we vandaag het nieuwste spel uit de verpakking halen of de laatste blockbuster gaan bekijken, is het duidelijk dat digitale 3D-beelden niet meer weg te denken zijn. Het is ook niet langer enkel het werk van grote mainframes om deze 3D-wereld voor ons te visualiseren. Sinds de integratie van de GPU in de hedendaagse multimedia pc haalt de consument een krachtige coprocessor in huis, waarmee hij kan worden ondergedompeld in levensechte interactieve 3D-scènes. Figuur 5.2: Een 3D-wereld afgebeeld 5.2 GPU vs. CPU Als we de huidige CPU s van de mainstream computers even onder de loep nemen, zien we grosso modo twee soorten opduiken: de CISC-processor en de RISC-processor. CISC staat voor Complex Instruction Set Computer wat aangeeft dat het over ingewikkelde instructies gaat die relatief veel werk kunnen verrichten. Meestal nemen deze instructies dan ook meerdere klokcycli in beslag. Het concept vond zijn oorsprong in een tijd waar 40

het bouwen van compilers nog in zijn kinderschoenen stond. Hierdoor achtte men het eenvoudiger om de complexiteit naar de hardware te verschuiven. RISC staat voor Reduced Instruction Set Computer en werkt met eenvoudige instructies waardoor ze sneller kunnen uitgevoerd worden (bv. één instructie per klokcyclus). Voor hetzelfde rekenwerk heeft een RISC-processor echter wel meer instructies nodig dan een CISC-processor. Het grote voordeel van RISC uit zich wanneer men aan een pijplijn denkt om parallellismen uit te buiten. Het is dan belangrijk dat elke instructie een zo kort mogelijk aantal cycli in beslag neemt 1. De populaire x86-processoren van AMD en Intel hebben een CISC-architectuur en sjouwen veel ballast mee uit hun verleden. Zo moeten ze nog steeds in staat zijn om oude software te draaien. Deze legacy verhindert de ontwerpers in grote mate om een propere nieuwe architectuur te maken volgens de best practices van vandaag de dag. Verder is een CPU ook duidelijk bedoeld voor algemene berekeningen die in volgorde uitgevoerd moeten worden. Ook al hebben moderne CPU s vaak vele pijplijntrappen toch is het wenselijk voor de programmeur dat de instructies sequentieel uitgevoerd worden 2. Bij de GPU kon men wel vertrekken van een nieuw ontwerp waarbij men rekening kon houden met de toepassingen waarvoor deze processor zou moeten dienen. Omdat een grafische processor inwerkt op een grote hoeveelheid data en het vaak over dezelfde soort bewerkingen gaat, wou men optimaal gebruikmaken van parallellismen. Daardoor vertoont de GPU een sterk gepijplijnd gedrag en zal hij in feite het paradigma van het stroomproces implementeren. Dit paradigma beschouwt de data als een stroom die doorheen de verschillende stappen vloeit om zo omgevormd te worden tot zijn uiteindelijk resultaat. Elke stap heeft als input minstens één stroom en als output opnieuw minstens één stroom. De data van elke inputstroom wordt beschouwd al zijnde een homogeen geheel van eenzelfde type. wijzigen. GPU. Een bepaalde stap in het proces kan uiteraard wel de aard van de data In de volgende sectie bekijken we welke stappen de datastroom moet ondergaan op de 1 Moderne CISC-processoren zullen hun instructies omzetten naar een soort van RISC-instructies om zo toch een pijplijn te kunnen implementeren. Dit wordt echter afgeschermd van de gebruiker. 2 Aangezien niet alle instructies even lang duren, wordt de sequentiële uitvoer verzekerd door een reorder buffer. Hierdoor verlaten de instructies de pijplijn in dezelfde volgorde als waarin ze binnenkwamen. 41

5.3 Het renderproces en zijn terminologie De grafische processor beschouwt een scène in de driedimensionale wereld als verzameling van objecten die vanzelfsprekend ook drie dimensies bezitten. De taak van de GPU bestaat erin om deze objecten om te zetten naar een tweedimensionaal beeld dat we kunnen tonen op een scherm. Dit noemt men renderen. Het renderproces dat we hier uit de doeken doen, bestaat uit de stappen die nodig om dit te verwezenlijken. Figuur 5.3 geeft een overzicht van de grafische pijplijn. De data uit de applicatie zal hierin afdalen om uiteindelijk te worden afgebeeld op een scherm. Hieronder overlopen we deze stappen in dezelfde volgorde om de werking te verduidelijken. Applicatie Vertices Primitieven GEOMETRIE Vaste functionaliteit Tesselation Vertexshader { Transformaties & Belichting Knippen Culling Rasteren PIXELS Vaste functionaliteit Pixelshader Texture sampler Textuuroppervlak Framebuffer Presentatie Figuur 5.3: De grafische pijplijn 42

5.3.1 Het geometrische gedeelte Wanneer we werken met driedimensionale objecten hebben we nood aan de geometrische data die dit object voorstelt, ook het 3D-model genoemd. Het model zal een object benaderen door een aaneenschakeling van vlakjes bij te houden die samen zo goed mogelijk het object voorstellen. Deze vlakjes worden begrensd door willekeurige veelhoeken. Hierdoor heeft men nood aan het bijhouden van de hoekpunten, die we ook knopen of vertices noemen. De verbindingslijnen (ook bogen genaamd) tussen de knopen begrenzen de vlakjes. Met deze informatie wordt het zogenaamde draadmodel gevormd waarvan een voorbeeld te zien is in Figuur 5.5. boog vertex / knoop Figuur 5.4: De vertex In de praktijk zal men enkel met driehoeken werken in plaats van met willekeurige veelhoeken, zodat er indien nodig nog een triangularisatie moet gebeuren. Hiermee worden dan de veelhoeken, die geen driehoeken zijn, opgesplitst in driehoeken. Uit Figuur 5.5 leren we dat een driehoek vaak aan meerdere andere driehoeken grenst. Hierdoor hebben verschillende driehoeken eenzelfde knoop gemeen. Het zou dus niet verstandig zijn om deze knopen tweemaal bij te houden. Daarom wordt er gebruikgemaakt van een vertexbuffer en een indexbuffer. De eerste buffer houdt de verzameling van de verschillende vertices bij. De tweede bevat welke vertices samen de driehoek opmaken. Hiervoor worden de indices gebruikt uit de vertexbuffer. Beide buffers bevinden zich in het videogeheugen. Buiten een verzameling van vertices kunnen ook rechtstreeks primitieve vormen gebruikt worden zoals kubussen en cilinders. Deze worden dan ook nadien opgebouwd uit de nodige driehoeken. Hiervoor zorgt de tesselation stap. In de volgende fase zal de 3D-scène onder de vorm van vertices via een reeks van transformaties geprojecteerd worden op de viewport of ook het projectiescherm geheten. 43

Figuur 5.5: Het draadmodel van een Romeins schip Verder kan ook de belichting van elke vertex bepaald worden in deze stap. Al deze bewerkingen op vertices kunnen gebeuren in hardware aan de hand van de vaste functies die ingebakken zitten in de GPU of aan de hand van vertex shaders. Later volgt meer over deze schaders in sectie 5.6. Zij zorgen voor de programmeerbaarheid van dit stuk van de pijplijn en vormen zo de belangrijkste middelen die we kunnen gebruiken in de decoder. Dalen we verder af op Figuur 5.3 dan komen we bij de knipstap. Hierbij worden alle driehoeken die onzichtbaar zijn doordat ze buiten het projectievlak liggen, verwijderd. Dit impliceert dat alle driehoeken die buiten het beeld vallen niet meer verwerkt worden in de volgende stappen van de pijplijn. Dit is een belangrijke eigenschap waarvan we gebruik zullen maken bij de decoder in Hoofdstuk 6. Ook wanneer de positieve normaal van het oppervlak van een driehoek weggedraaid is van de kijker, is een driehoek niet zichtbaar. De driehoeken die in deze situatie verkeren, worden verwijderd in de culling-fase. 5.3.2 Het pixelgedeelte Het rasteren vormt het voorbereidende werk voor het inkleuren van de pixels van de driehoeken. Aangezien men elke driehoek op een andere manier kan inkleuren, worden de verzamelingen van pixels die behoren tot dezelfde driehoek gegroepeerd in fragmenten. 44

Dit betekent ook meteen dat de vertices hier moeten plaats ruimen voor de pixels. Die pixels zal men per fragment bijhouden zoals geïllustreerd staat in Figuur 5.6 (a). Men lijnt de driehoek af door op elke horizontale lijn de posities van beginpixel en eindpixel bij te houden. Het resultaat na opvulling is te zien in Figuur 5.6 (b). Er rest ons nog op te merken dat een fragment wel nog meer informatie bevat dan de pixels alleen. (a) Bijhouden van in te kleuren pixels (b) De ingekleurde driehoek Figuur 5.6: De pixels van een fragment Het inkleuren kan gebeuren met de kleuren die reeds werden toegekend aan de vertices, maar dit maakt dat objecten er redelijk onecht uitziet zoals in Figuur 5.7 (a). Echte objecten hebben immers buiten hun eigenlijke vorm vaak ook veel detail. (a) zonder texturen (b) met texturen Figuur 5.7: Een 3D-scène Eén mogelijkheid is het gevoelig opdrijven van de geometrische complexiteit van het object om zo de details weer te geven aan de hand van extra driehoeken. Dit zou echter leiden tot overdreven ingewikkelde objecten en vanzelfsprekend veel meer vertices. 3 Waar 3 Hierdoor wordt het opstellen van het 3D-model een veel complexere zaak en neemt de rekentijd bij het renderen ook aanzienlijk toe. 45

de geometrie tekortschiet, bieden texturen een aanvaardbare oplossing voor dit probleem. Figuur 5.7 (b) illustreert een realistisch beeld door toepassing van texturen (en belichting). In het algemeen is een textuur een bitmap van pixels die je kan maken met om het even welk tekenprogramma. Specifiek bedoelen we hier met texturen een speciaal soort beelden die kunnen geprojecteerd worden op de driehoeken van een object. Zodoende krijgt het object meer detail en ziet het er echter uit. De figuren 5.8 en 5.9 geven het principe weer. Figuur 5.8: Een textuur die hout voorstelt Figuur 5.9: Een 3D-scène met toepassing van een houten textuur Het inkleuren van de pixels kan gebeuren met de ingebouwde functionaliteit van de GPU, maar men kan het ook programmeren aan de hand van de pixel shaders. Meer hierover volgt in Sectie 5.6. 46

Op het einde van de grafische pijplijn zal het resulterende beeld worden uitgeschreven in het renderdoel. Meestal is dit de beeldbuffer, maar dit kan ook een andere surface zijn. Een surface is in feite niks anders dan een matrix van pixels waarmee 2D-informatie bijgehouden wordt in het videogeheugen. De breedte en hoogte van dit geheugenblok wordt uitgedrukt in pixels. Het begrip pitch duidt op het aantal bytes dat een rij van de matrix in de praktijk breed is. Dit kan meer zijn dan het aantal pixels, aangezien men omwille van efficiëntie redenen het geheugen gealigneerd wenst te houden op een bepaald aantal bytes. Wanneer men dus in de surface op zoek gaat naar de volgende lijn, moet men er steeds aan denken de pitch te gebruiken en niet de breedte in pixels. Figuur 5.10: Het begrip pitch Als men het beeld laat renderen naar een andere surface dan de framebuffer kan men zo het beeld opnieuw downloaden uit het videogeheugen. Het beeld dat uiteindelijk op het scherm getoond wordt, is wel afkomstig uit de framebuffer. 5.3.3 Renderiteraties Het gebeurt vaak dat het renderproces meerdere keren moet doorlopen worden om één beeld op het scherm te tonen. Men spreekt dan van renderiteraties. In elke iteratie wordt dan een deel van het renderdoel geschreven. 5.4 Systeemarchitectuur In de voorgaande sectie werd de grafische pijplijn ontleed. Helemaal bovenaan werd de geometrische data in de pijplijn gestopt om er onderaan uit te komen als een beeld dat getoond kan worden op het scherm. Deze geometrische gegevens bevinden zich aanvankelijk in de applicatie die de GPU aanstuurt en dus op de CPU draait. Dit impliceert dat deze nog moet opgeladen worden in het videogeheugen om zo de GPU effectief te bereiken. Hetzelfde geldt ook voor texturen. Deze 2D-data moet immers eveneens op de 47

een of andere manier beschikbaar zijn voor de GPU. Als deze texturen een hoge resolutie hebben, kan het gaan over aanzienlijke hoeveelheden data. Daardoor is het belangrijk te weten welke weg deze data moet afleggen. In deze sectie gaan we daar dieper op in door de algemene systeemarchitectuur te bekijken waarop de applicatie zal draaien. CPU +/- 8GB/s Systeemgeheugen +/- 6GB/s FSB Hypertransport North Bridge +/- 0,5GB/s South Bridge +/- 2GB/s of +/- 4GB/s AGP of PCI Express IDE SATA USB Videogeheugen +/- 54GB/s GPU Grafische kaart Figuur 5.11: Architectuur van een AMD Athlon64 systeem In Figuur 5.11 zien we een schema van de architectuur van een AMD Athlon64 systeem. Dit bevat Hypertransport tussen de CPU en het systeemgeheugen en is voorzien van een recente grafische kaart. De bussnelheden zijn indicatief voor een hedendaags systeem en kunnen afwijken van de realiteit. Ze moeten ons vooral een beeld geven van de verhoudingen van de snelheden tussen bepaalde onderdelen van het systeem. Zo is het duidelijk dat de bandbreedte van het videogeheugen van en naar de GPU een stuk groter is dan bijvoorbeeld de bandbreedte tussen de CPU en het systeemgeheugen. Wanneer we nu bijvoorbeeld texturen moet opladen naar het videogeheugen dan moet er een hele weg worden afgelegd. Uiteraard zal het ophalen vanop de harde schijf het meest tijd vergen. Als we vertrekken van texturen die in het systeemgeheugen zitten, dan is de verbinding tussen de North Bridge en het videogeheugen de zwakste schakel. 48

Daarom is hier ook veel aandacht aan besteed de voorbije jaren, met de versnelling van de AGP-bus en de recente komst van PCI Express die nu een bandbreedte toelaat van 4GB/s. Dit is echter nog steeds een pak trager dan de 54GB/s tussen de GPU en het videogeheugen. We leren uit deze korte beschouwing dat het opladen 4 van grote texturen een mogelijke bottleneck kan vormen voor onze decoder. 5.5 Toegang tot de hardware via Direct3D Om de rekenkracht van de GPU vanuit software te kunnen aanspreken, hebben we nood aan een Application Programming Interface (API). In dit eindwerk werd gekozen voor de Direct3D API dat onderdeel is van DirectX. 5.5.1 De evolutie van DirectX Met de komst van DirectX in 1995 zorgde Microsoft er voor dat spelontwikkelaars mogelijkheden kregen in Windows die voorheen enkel in DOS aanwezig waren. Direct3D kwam eraan in 1996 als onderdeel van DirectX 2.0 en moest zorgen voor apparaatonafhankelijke toegang tot 3D-hardwareversnellers. Tot aan de komst van DirectX 8.0 bestond Direct3D uit twee verschillende API s. De zogenaamde Retained Mode en de Immediate Mode. De Immediate Mode was een lowlevel API die heel flexibel was en zo efficiënt mogelijk draaide, maar was tegelijk moeilijk te gebruiken. De Retained Mode is bovenop de Immediate Mode gebouwd en bood extra services aan de programmeur waardoor het makkelijker aan te leren was. Het uitbrengen van DirectX 8.0 bracht de grootste verbeteringen met zich mee in de geschiedenis van Direct3D. De geheel nieuwe architectuur van Direct3D zorgde voor een eenvoudigere initialisatie, allocatie en beheer van data. DirectDraw en Direct3D smolten samen in één interface die men DirectX Graphics doopte. Dit leidde tot een lager geheugengebruik en een makkelijker te hanteren model voor de programmeur. Grote nieuwigheden waren onder andere Point Sprites die dienen om effecten toe te passen, texturen in drie dimensies en vooral van belang in dit eindwerk de vertex- en pixelshaders. 4 Het downloaden van beelden van het videogeheugen gaat nog veel trager en komt in de buurt van een 500MB/s. Het moet dus zoveel mogelijk vermeden worden. 49

Op het tijdstip van schrijven is DirectX 9c de recentste versie die beschikbaar is. DirectX 9 verschilt niet fundamenteel van zijn voorganger. Wel is er naar goede gewoonte gestreefd naar verbeteringen en uitbreidingen. Er zit ondermeer ondersteuning in van nieuwe vertex- en pixelshader standaarden. Voor de vertexshaders gaat het hier over de standaarden vs 2 0, vs 2 x en vs 3 0 en voor pixelshaders ps 2 0, ps 2 x en ps 3 0. Ook HLSL was iets nieuws dat toegevoegd werd in DirectX 9. 5.5.2 De Direct3D 9 API Nu we weer in het heden beland zijn, bespreken we de Direct3D API zoals die aanwezig is in DirectX 9. Het lagenmodel Direct3D zorgt voor een dunne laag software rond de grafische kaart. De Hardware Abstraction Layer (HAL) is daar een onderdeel van. Deze laag zorgt ervoor dat Direct3D toegang kan krijgen tot een hele waaier van verschillende grafische hardware. HAL spreekt op zijn beurt de Device Driver Interface (DDI) aan. Deze interface moet ondersteund worden door de driver van de kaart zelf. In Figuur 5.12 zien we aan de linkerkant een overzicht van de lagen die doorlopen moeten worden om vanuit een applicatie de grafische hardware te gebruiken. Rechts in de figuur krijgen we te zien via welke weg een gewone applicatie iets naar het scherm stuurt 5. Referentie apparaat Bij de Software Development Kit (SDK) van DirectX zit standaard een referentieapparaat. Dit apparaat draait in software en ondersteunt zo goed als alle mogelijkheden van Direct3D, ook als de grafische kaart dit niet doet. Daarom kan het ook gebruikt worden om zaken te testen die niet mogelijk zijn in hardware of waarvan men denkt dat er een fout zin in de driver. Dankzij het referentieapparaat kunnen we eveneens shaders debuggen. Dit is immers niet mogelijk als we alles door de hardware laten uitvoeren. 5 De Graphics Device Interface dient voor het weergeven van vensters en dergelijke meer in Windows 50

Win32 App Win32 App Direct3D API GDI HAL Device Device Driver Interface Graphics Hardware Figuur 5.12: Lagenmodel van de Direct3D API Aan dit alles zit wel een keerzijde. Doordat het refentieapparaat in software draait, kan het niet de snelheden van de hardware evenaren. Daarom wordt dit enkel gebruikt voor testdoeleinden. 5.6 De shaders Uit Sectie 5.3 maken we op dat shaders instaan voor de programmeerbaarheid van de grafische pijplijn. Shaders zijn in feite programma s die op de GPU draaien. Er bestaan verschillende versies van shaders. Momenteel ondersteunen de recentste grafische kaarten Shader Model 3.0, maar de specificaties van het Shader Model 4.0 zijn ook reeds gekend. Het is vanzelfsprekend dat een hogere versie meer mogelijkheden biedt. De shaderprogramma s mogen langer zijn en kunnen zo ingewikkeldere algoritmes uitvoeren. Het is ook de bedoeling om een shader gecompileerd te krijgen voor een zo laag mogelijke versie. Zo wordt het door meer hardware ondersteund. In dit eindwerk kunnen alle shaders gecompileerd worden voor versie 2.0. Een overzicht van de eigenschappen van de verschillende shaderversies is te vinden in de literatuur en is reeds aan bod gekomen in [3]. 51

Binaire ASM 5.6.1 HLSL Sinds de komst van DirectX 9 kunnen we shaders schrijven met behulp van High Level Shading Language (HLSL). Waar voorheen in assembler moest geprogrammeerd worden, beschikken we nu met HLSL over een C++-achtige taal. Zodoende kan de programmeur zich des te meer concentreren op de algoritmes en hoeft hij zich minder aan te trekken van de onderliggende instructies en registers. Als bijkomend voordeel kan de code geschreven in HLSL ook makkelijker herbruikt worden. Ook als er nieuwe shaderversies uitkomen, kan de oude code makkelijk gehercompileerd worden hiervoor. In Figuur 5.13 zien we hoe de applicatie de opdracht geeft aan de compiler om de shader naar binaire assemblercode om te zetten. Daarna wordt de binaire code doorgegeven aan de DirectX runtime voor uitvoering van de shader. HLSL-compiler Binaire ASM HLSL Applicatie (DirectX 9) Runtime (DirectX 9) Figuur 5.13: Gedrag van de HLSL-compiler Voor een uitgebreide inleiding op HLSL verwijzen we naar [11]. 52

Applicatie Vertexshader Pixelshader Beeldbuffer Vertex data Positie Textuurcoördinaten Vertex normalen Geïnterpoleerde waarden Textuurcoördinaten Normalen Kleur Pixels Kleur Diepte Figuur 5.14: De vertexshader in het stroomproces 5.6.2 De vertexshader De vertexshader werkt in op de knopen van de geometrische data. Zo wordt de scène van de 3D-ruimte naar het projectievlak getransformeerd. Een vertex bevat meer dan alleen maar zijn positie, maar bijvoorbeeld ook een bepaalde kleur en belichting. Ook deze extra informatie kan gemanipuleerd worden door de vertexshader. Een mogelijk structuur om een vertex bij te houden, ziet er uit als volgt: struct Vertex { D3DXVECTOR3 Position; D3DXVECTOR3 Normal; D3DXVECTOR3 TexCoord; D3DXVECTOR3 Tangent; } In dit eindwerk zal een vertex echter enkel zijn positie en één of meerdere textuurcoördinaten bevatten. In Figuur 5.15 zien we het schema van de virtuele vertexshadermachine. De vertices stromen van links naar rechts in het diagram. Dankzij HLSL krijgt de programmeur niet te maken met de onderliggende registeroperaties wanneer hij een vertexshader ontwikkelt. Toch is het belangrijk om weten dat er beperkingen zijn door toedoen van het eindig aantal registers dat aanwezig is. Dit aantal neemt weliswaar toe met elke nieuwe shaderversie. Zo zijn 256 instructies mogelijk in een vertexshader die gecompileerd wordt voor shaderversie 2. Dit bleek voldoende in dit eindwerk. 53

instructies vertices in objectruimte inputregisters ALU outputregisters vertices in projectieruimte tijdelijke registers constante registers adresregisters Figuur 5.15: De vertexshadermachine 5.6.3 De pixelshader Applicatie Vertexshader Pixelshader Beeldbuffer Vertex data Positie Textuurcoördinaten Vertex normalen Geïnterpoleerde waarden Textuurcoördinaten Normalen Kleur Pixels Kleur Diepte Figuur 5.16: De pixelshader De pixelshader zorgt voor de bepaling van de kleur van elke pixel die uiteindelijk op het beeld zal getoond worden. In Figuur 5.17 zien we naar analogie met de vertexshadermachine nu de pixelshadermachine. Het grootste verschil tussen beiden is het gebruik van texturen. De ALU kan zodoende kleuren uit de texturen opvragen en gebruiken om de pixelkleur te berekenen. In de figuur is aangegeven dat dit kan gedaan worden aan de hand van textuursamplers. Deze verwijzen naar de sampler registers in assembler. Een sampler bepaalt op een unieke wijze een textuuroppervlak. In HLSL kunnen we hiermee de data opvragen van de textuur. Daarbij merken we op dat wanneer we zo een pixelwaarde opvragen, deze een vlottend-komma-getal is dat een waarde tussen 0 en 1 aanneemt. Berekeningen kunnen dan ook afrondingsfouten introduceren. Daarbij komt dat men voor bepaalde berekeningen de waarde ook zullen moeten herschalen naar een bereik van [0, 255]. 54

Als men nu een bepaald stuk van een textuur wil mappen op een driehoek van pixels, is het duidelijk dat bijna nooit elke pixel van de textuur mooi zal overeenkomen met een pixel op de driehoek. Daarom spreekt men van texels 6 als men het heeft over de pixels van een textuur. instructies geïnterpoleerde vertexdata inputregisters ALU outputregisters pixelkleur tijdelijke registers constante registers Textuurcache Textuursampler Figuur 5.17: De pixelshadermachine Het resultaat van de pixelshader komt op het einde van de pijplijn terecht in een oppervlak in het videogeheugen. 5.6.4 Het Effects-raamwerk De werking van de grafische pijplijn wordt beïnvloed door een groot aantal instellingen en toestanden. Er zijn bijvoorbeeld de geometrische gegevens onder de vorm van vertices, de staat van de pijplijn en de gebruikte pixel- en vertexshaders. Om een enkele instelling te wijzigen, moet er telkens een functie-aanroep plaatsvinden. Dit is een flexibel systeem, maar wordt al snel onhandig voor een groot aantal instellingen. Het Effects-raamwerk helpt bij het organiseren van instellingen en toestanden van de shaders. Eén enkel effect kan de volledige toestand van de grafische pijplijn bevatten. Meestal bevat een effect meerdere technieken (Eng. techniques). Met deze technieken beschrijft men de staat van de pijplijn en de gebruikte vertex- en pixelshader. Per effect kan dit alles gebundeld worden in één bestand met de extensie.fx 6 Dit is een samentrekking van texture element. 55

Hieronder wordt een voorbeeld gegeven van hoe verschillende technieken gedefinieerd kunnen worden. #include "mc_ps_reconstruction_v1.fx" technique MC_FullSamples { pass P0 { vertexshader = compile vs_2_0 VS_YCoCgRCalcVertexTex(); pixelshader = compile ps_2_0 PS_FullSampleSampling(); Lighting = false; } } technique MC_Reconstruction { pass P0 { vertexshader = compile vs_2_0 VS_Ortho(); pixelshader = compile ps_2_0 PS_Reconstruction(); Lighting = false; } } Dit codefragment is afkomstig van de decoder en geeft aan hoe we een techniek kunnen beschrijven. Telkens wordt opgegeven welke methode er gebruikt wordt voor de vertexen pixelshader en voor welke shaderversie deze gecompileerd moet worden. De methodes kunnen zich in een ander.fx-bestand bevinden en worden geïncludeerd zoals dit ook in C++ het geval is. Wat de shaders precies doen, wordt uitgelegd in het volgende hoofdstuk. Vanuit de applicatie moeten we dan nog aangeven wanneer we dit effect wensen te gebruiken. Hiervoor vragen we een object van het type ID3DXEffect aan via de methode D3DXCreateEffectFromFile(..) waar we onder andere het gewenste.fx-bestand aan meegeven. Door de methode GetTechniqueByName( T( MC Reconstruction )) uit te voeren op dit object, verkrijgen we een D3DXHANDLE die ons toelaat de geselecteerde techniek nadien toe te passen. Dit geven we aan door de methode SetTechnique(..) waar 56

we de zonet verkregen D3DXHANDLE aan meegeven. Texturen worden ingesteld met de methode SetTexture(D3DXHANDLE,IDirect3DTexture9*). Eens alle zaken goed ingesteld staan, kan men dan overgaan tot het uitvoeren van het effect. Dit doen we bijvoorbeeld met onderstaand stukje code. UINT numpasses = 0; m_pmceffect->begin(&numpasses, 0); for(uint i = 0; i < numpasses; i++) { m_pmceffect->beginpass(i); m_pdevice->drawindexedprimitive(d3dpt_trianglelist, 0,0,m_cVertices,0,m_cTriangles); m_pmceffect->endpass(); } m_pmceffect->end(); Het effects-raamwerk werd gebruikt voor het ontwikkelen van de decoder. Een goede uiteenzetting van het raamwerk is te vinden in [14]. 5.7 Hedendaagse hardware We schetsen tot slot van dit hoofdstuk nog even welke grafische hardware er vandaag zoal te vinden is op de markt. Daarbij kijken we naar de twee grootste merken: ATI en nvidia. De ATI X1900 reeks Het laatste vlaggenschip van ATI bedoeld voor de thuisgebruiker heeft 384 miljoen transistors dankzij de 90nm technologie. De kaart bevat 8 vertexshader processors en 48 57

New cache design, latency improvements Next-Generation Image Quality Advanced High Dynamic Range rendering, 128-bit floating point precision Extreme anti-aliasing and texture filtering quality Avivo Revolutionary display, video, and connectivity capabilities Consumer electronics convergence features CrossFire Powerful parallel graphics processing support Radeon X1800 XT Figuur 5.18: De ATI Radeon x1900 Serie 2 pixelshader processors die het shadermodel 3.0 van DirectX 9 ondersteunen. Een PCI Express x16 interface zorgt voor de nodige bandbreedte. Daarbij komt dat er er 128-bit precisie voor floating point berekeningen wordt gegarandeerd in de shaders. De nvidia GeForce 7950 GX2 De GeForce 7 is de recentste generatie van nvidia en deze ondersteunt ook het DirectX 9.0 Shader Model 3.0 met eveneens een precisie van 128-bit floating points. Het aantal transistors bij deze kaart kan oplopen tot een 300 miljoen. De GeForce heeft tot 24 pixelshader processoren en 8 vertex shaders processoren. Figuur 5.19: De GeForce 7800 GTX 512 Beide kaarten zijn aan elkaar gewaagd en kunnen in theorie zo n 10 Gigapixels per seconde produceren. Verder valt er nog op te merken dat de kaarten van hetzelfde merk en type kunnen gebundeld worden. Zo is men op weg naar dual-gpu systemen of meer. Bij nvidia heet dit SLI of Scalable Link Interface en bij ATI heeft men het CrossFire gedoopt. 58

Hoofdstuk 6 De decoder Dit hoofdstuk bespreekt de decoder en de voornaamste aspecten van hoe we de bewegingsgecompenseerde YCoCg-R-beelden zullen afspelen met behulp van de GPU. De software is schatplichtig aan eerder verricht onderzoekswerk dat zich bundelt onder het onlangs zo gedoopte raamwerk persephone. De shaders kwamen tot stand dankzij een samenwerking met Bart Pieters [4] en er werd ook beroep gedaan op de kennis van Dieter Van Rijsselbergen in dit domein. 6.1 Structuur van de applicatie In Figuur 6.1 zien we een overzicht van de verschillende bibliotheken die voorhanden zijn. Het centrale pakket VideoTex vormt de basis van de decoder. Hiermee kunnen we gebruikmaken van de functionaliteit van persephone, dat in feite dient om tijdsmetingen uit te voeren. Dit wordt verder uitgelegd in het volgende hoofdstuk dat de prestatiemetingen bespreekt. Alle klassen die we hiervoor nodig hebben, bevinden zich in het libcore-pakket. Deze zijn afkomstig van het eindwerk van Hollemeersch [17]. libycocg is een resultaat van het eindwerk van Van Rijsselbergen [3]. Dit pakket dient om de ongecomprimeerde YCoCg-R-beelden af te spelen op de grafische processor. libavc en libhardwareavc zijn ontwikkeld in het eindwerk van Pieters [4]. Zoals de naam doet vermoeden, zorgen deze pakketten ervoor dat bewegingsgecompenseerde beelden conform de H.264/AVC-standaard kunnen afgespeeld worden. Het eerste pakket zal de beelden volledig door de CPU laten decoderen. Het tweede pakket zal de GPU inschakelen. Meer uitleg vindt men uiteraard in de respectievelijke eindwerken. 59

libycocgrmc libavc VideoTex libycocg libcore libhardwareavc Figuur 6.1: De bibliotheken van VideoTex Deze thesis voegde het pakket libycocgrmc toe aan het geheel. Deze bibliotheek bevat de functionaliteit nodig om bewegingsgecompenseerde YCoCg-R-beelden af te spelen op de GPU. 6.2 Structuur van de libycocgrmc -bibliotheek De structuur van de libycocgrmc -bibliotheek is voorgesteld in Figuur 6.2. YCoCgMCHardwareProducer zorgt voor het inlezen van de residubeelden en bewegingsvectoren vanop de harde schijf. Daarvoor worden de respectievelijke klassen YCoCgMem- IntraResidueProducer8bitX2 en YCoCgMemMotionVectorProducer gebruikt. Eén object van elk van deze klassen zal ervoor zorgen dat de nodige informatie bijgehouden wordt in het systeemgeheugen. Normaal passen alle bewegingsvectoren makkelijk in het geheugen. Een snelle berekening geeft ons een idee. Nemen we een beeld van 1920 1080 1 dan levert dit 480 270 = 129600 macroblokken van 4 4 op. Elk macroblok bezit precies één bewegingsvector, bestaande uit twee integers (met 4 bytes per integer). Het totaal voor één beeld komt dus op 1036800 bytes of ongeveer 1MB. Met de hedendaagse grootordes van 1 Dit is tevens de hoogste resolutie waarmee we gewerkt hebben tijdens dit eindwerk. 60

YCoCgMCHardwareProducer YCoCgMemIntraResidueProducer8bitX2 YCoCgMemMotionVectorProducer VideoTex YCoCgMCHardwareRenderer 2 YCoCgVideoPicture RGBMCWriter YCoCgMCWriter Figuur 6.2: Structuur van het libycocgrmc-pakket het systeemgeheugen kunnen we stellen dat de bewegingsvectoren van een paar tientallen beelden op deze manier probleemloos kunnen bijhouden worden. Anders is het gesteld met de residubeelden. Wanneer we opnieuw even uitrekenen, dan bezit een beeld van 1920 1080 maar liefst 2073600 pixels, wat ongeveer 2 Megapixel is. In drie kleurcomponenten is dit 6220800 integers of 24883200 bytes of nog 23MB aan data per beeld. Het is duidelijk dat dit al moeilijker in het systeemgeheugen past voor een paar tientallen beelden. Daarom kunnen we bij constructie van een object van de klasse YCoCgMemIntraResidueProducer8bitX2 het aantal beelden meegeven die in het geheugen worden ingelezen. Wanneer er een beeld opgevraagd wordt dat buiten deze buffer valt, wordt het volgende blok beelden ingelezen van de harde schijf. YCoCgMCHardwareRenderer is de tweede hoofdklasse van de bibliotheek. Hierin bevinden zich de functies die zorgen voor het afspelen van beelden op de GPU. Bij con- 61

structie dient een verwijzing naar een object van de klasse YCoCgMCHardwareProducer meegegeven te worden, aangezien hier de data in vervat zit. drawframe() is de belangrijkste publieke methode van YCoCgMCHardwareRenderer. Intern worden methodes voorzien voor het initialiseren van Direct3D, het aanmaken van de texturen waarnaar men de data zal kopiëren en dergelijke meer. De klasse YCoCgVideoPicture dient om de verwijzingen naar de texturen bij te houden en te beheren. We hebben nood aan twee objecten van dit type aangezien we een referentie- en residubeeld hebben. Deze objecten bevatten vooral datavelden van het type IDirect3DTexture9*. Verder zien we ook nog twee writers opduiken. Dit wijst er op dat we tijdens de ontwikkelfase ook testgegevens uitschreven. Zo controleerden we of de bewegingscompensatie opnieuw tot de originele YCoCg-R-beelden leidde en vergeleken we ook het uiteindelijke resultaat met de RGBbeelden. Dit impliceert dat we de data opnieuw uit het videogeheugen moest halen. Dit is nefast voor de prestaties vanwege de lage downloadsnelheden van GPU naar CPU. Daardoor is deze optie afgezet in het eindresultaat. 6.3 Macroblok en bewegingsvector op de GPU Vooraleer we overgaan tot het uiteenzetten van de bewegingscompensatie op de GPU, leggen we eerst uit hoe een macroblok en bewegingsvector voorgesteld worden op de GPU. Hiertoe stelt men een vertexrooster op zoals te zien is in figuur 6.3. Het videobeeld wordt opgebouwd uit een verzameling van quads of vierkanten. Uit Hoofdstuk 5 weten we dat een GPU enkel werkt met driehoeken. Daarom is elke quad samengesteld uit twee driehoeken. Een macroblok wordt nu rechtstreeks voorgesteld door zo een quad. Zoals nog te zien is op de figuur, bevat een quad vier vertices. Elke vertex draagt een aantal attributen met zich mee, waardoor het handig is om hier de bewegingsvector behorende bij het macroblok in te stoppen. Deze bewegingsvectoren zullen in de vertexshader beschouwd worden als textuurcoördinaten. De vertexshader heeft nu als doel om zijn textuurcoördinaten aan te passen zodat deze verwijzen naar het referentiemacroblok. De techniek wordt later besproken. Het vertexrooster zelf herbruiken we voor elk beeld, waardoor enkel de bewegingsvectoren aangepast moeten worden. Tot slot merken we nog op dat het belangrijk om weten is dat de positiecoördinaten 62

Y v1 positiecoördinaten X v2 v3 v4 U textuurcoördinaten V Figuur 6.3: Vertexrooster voor macroblokken volgens een ander assenstelsel voorgesteld worden dan de textuurcoördinaten. De X- en U-coördinaat komen wel overeen, maar de V-coördinaat bij de textuur is tegengesteld aan de Y-coördinaat van de positie. Dit is aangegeven in Figuur 6.3 en heeft zijn gevolgen bij de implementatie van de vertexshader. 63

8 bits 1 bit extra Y 2 bits extra Co 2 bits extra Cg 8 bits 1 01 0010 110001 0000010 010010000 01100100010 1001000011111 van 8 bits per pixel bitcollectors 1 01 0010 110001 0000010 010010000 01100100010 1001000011111 6.4 Bewegingscompensatie op de GPU CPU bytes 01010101 10010010 Y 01001001 11010001 01010101 10010010 Co 01001001 11010001 01010101 10010010 Cg 01001001 11010001 { {gewone planes bestandsformaat residubeelden readresidue() readmotionvectors() YCoCgMCHardwareProducer YCoCgMemIntraResidueProducer8bitX2 YCoCgMemMotionVectorProducer YCoCgMCHardwareRenderer YCoCgMemIntraResidueProducer8bitX2 Y bestandsformaat bewegingsvectoren GPU Co Cg upload8bitx2singletexture(...) Texturen residubeeld YCoCgMemMotionVectorProducer uploadmotionvectors() Vertexbuffer Vertexshader Vertexrooster Pixelshader Y Co Cg Texturen referentiebeeld Beeldbuffer Figuur 6.4: Algemene werking van de decoder 64

In deze paragraaf leggen we de verschillende stappen uit om tot de bewegingscompensatie te komen op de GPU. Hierbij respecteren we eveneens de volgorde waarin deze uitgevoerd worden. 6.4.1 Inlezen van de gegevens In Figuur 6.4 zien we een schematische voorstelling van de werking van de decoder. Hierin maken we onderscheid tussen het gedeelte dat op de CPU draait en het gedeelte dat op de GPU draait. De CPU zal zorgen voor het inlezen van de bewegingsvectoren en residubeelden. Zoals hierboven vermeld staat, is dit de taak van de YCoCgMCHardware- Producer. De functies readresidue() en readmotionvectors() spreken voor zich. 6.4.2 Het opladen naar de GPU Eens de gegevens in het systeemgeheugen aanwezig zijn, zal de applicatie de nodige data opladen naar het videogeheugen. Om de bewegingsschatting te kunnen toepassen, worden de bewegingsvectoren doorgegeven via de vertices van het vertexrooster. Dit gebeurt met de methode uploadmotionvectors() en is een functie van de klasse YCoCgMCHardware- Renderer. Ook het residubeeld moet de GPU bereiken en dit gebeurt door het opladen van drie texturen. Dit aantal is nodig omdat we weten uit Hoofdstuk 4 dat er 9 bits per pixel nodig zijn voor de luminantie en tweemaal 10 bits per pixel nodig zijn voor de chrominanties. Daarom gebruiken we één textuur per kleurcomponent en dit van het type D3DF MT A8R8G8B8. Dit formaat gebruikt 32 bits per pixel en is onderverdeeld in 4 kanalen van telkens 8 bits. Als we nu bijvoorbeeld 10 bits willen meegeven zullen we dit opsplitsen in een kanaal met 8 bits en een kanaal met 2 bits. In de pixelshaders zullen deze twee kanalen opnieuw samengesteld worden om zo één waarde per kleurcomponent te bekomen en daar een bewerking op uit te voeren. Als het om een tussenstap gaat en de data opnieuw in de textuur moet worden geplaatst, dan worden de waarden opnieuw opgesplitst. 6.4.3 De shaders in werking Eens alle data in het videogeheugen zit, zullen de shaders hun werk doen. Om deze aan te sturen, gebruiken we het Effects-raamwerk. We voeren hiermee drie technieken uit om het uiteindelijke beeld te kunnen tonen. 65

Het bewegingsgecompenseerd referentiebeeld De onderstaande techniek beschrijft welke vertex- en pixelshader er in actie komen. Na deze stap zullen we het referentiebeeld zodanig hebben aangepast dat het beeld een verzameling is van de referentiemacroblokken die reeds op de juiste plaats staan. Dit impliceert dat we in een volgende fase enkel nog het residubeeld hierbij moeten optellen om de bewegingscompensatie te voltooien. technique MC_FullSamples { pass P0 { vertexshader = compile vs_2_0 VS_YCoCgRCalcVertexTex(); pixelshader = compile ps_2_0 PS_FullSampleSampling(); Lighting = false; } } In deze techniek speelt de vertexshader een cruciale rol. We bekijken deze dan ook van naderbij. VS_OUTPUT VS_YCoCgRCalcVertexTex(VS_INPUT input) { VS_OUTPUT output = (VS_OUTPUT)0; float2 uvcoords = float2(input.position.x, 1.0f-input.position.y); // transform vertex position to world-view-projection space float4 position = mul(input.position + VertexGridOffset, WorldViewProjMatri // ouput texture coordinates output.uvcoordsmc = uvcoords + input.uvcoordsmv*pixeldimensioninsamples; // rule out when no motionvector present if (input.uvcoordsmv.x > 30000.0f) position.xy = position.xy + 10.0f; 66

output.position = position; } return output; Eerst worden de positiecoördinaten opgevraagd, waarbij we onmiddellijk zorgen dat de Y-coördinaat georiënteerd staat zoals bij de textuurcoördinaten. We houden dit alles bij als twee vlottende-komma-getallen in uvcoords. Daarna zetten we de positiecoördinaten van de vertex om naar de projectieruimte. De volgende lijn code stelt de textuurcoördinaten in als de som van de positiecoördinaten en de meegegeven bewegingsvectoren. Dit is logisch aangezien de bewegingsvectoren de relatieve verplaatsing beschrijven om van het huidige macroblok naar het referentiemacroblok te gaan. Zodoende zal het huidige macroblok na deze stap de pixels bevatten van het referentiemacroblok. Hiervoor moeten we dus als textuur het referentiebeeld gebruiken. Dit wil zeggen dat we voor de drie kleurcomponenten deze techniek apart zullen moeten uitvoeren. Daarna kijken we of de bewegingsvector niet een hele grote waarde bevat. Is dit het geval dat plaatsen we de vertex buiten beeld, waardoor deze geen rol speelt als referentiemacroblok. Dit dient voor het ondersteunen van een intragecodeerd beeld. Hierbij zullen immers geen bewegingsvectoren aanwezig zijn. De encoder zal dan zorgen dat de waarden op een heel groot getal staan 2. Het eerste beeld zal uiteraard altijd intragecodeerd zijn en de encoder ondersteunt ook intrabeelden op andere (vaste) plaatsen. Op het einde van de vertexshader worden dan de eerder berekende positiecoördinaten goed ingesteld en het resultaat wordt teruggegeven. De pixelshader is bij deze techniek een doorgeefluik van de pixels van de referentietexturen. Optellen van het residu Wat ons nu rest is het residubeeld op te tellen bij het aangepaste referentiebeeld. Dit gebeurt door de volgende techniek op elke kleurcomponent toe te passen. technique MC_Reconstruction { 2 Meer bepaald op 32768. 67

} pass P0 { vertexshader = compile vs_2_0 VS_Ortho(); pixelshader = compile ps_2_0 PS_Reconstruction(); Lighting = false; } Hierin is vooral de pixelshader van belang en we geven opnieuw uitleg bij zijn werking. PS_OUTPUT PS_Reconstruction( PS_INPUT input ) { PS_OUTPUT output = (PS_OUTPUT)0.0f; // retrieve residu and reference float4 r = tex2d(residuetexturesampler, input.tex0 )*255.0f; float4 ref = tex2d(referencetexturesampler, input.tex0 )*255.0f; // combine lower and higher bits float residue16bit = repack16bitycocgint(r.a, r.r); float ref16bit = repack16bitycocgint(ref.a, ref.r); float high, low; // add residue to reference and split lower and higher bits split16bitycocgint(residue16bit + ref16bit, low, high); output.diffuse = float4(high/255.0f, 0, 0, low/255.0f); return output; } Aanvankelijk wordt de uitvoer op nul gezet. Daarna worden uit de referentietextuur en de residutextuur de pixelwaarden opgevraagd. Dit geeft aanleiding tot twee waarden 68

tussen 0 en 1 per textuur. Deze worden vermenigvuldigd met 255 om gehele waarden te bekomen met het juiste bereik 3. De functie repack16bitycocgint zorgt voor het samenstellen van de laagste en de hoogste bits tot één waarde die nu een groter waardenbereik bestrijkt. Dit toepassen voor beide texturen levert ons de twee pixelwaarden op voor de beschouwde kleurcomponent. Daarna tellen we deze beide waarden op aangezien het om de residu- en referentiewaarde gaat. Het opnieuw opsplitsen van deze waarden laat ons toe dit opnieuw in twee kanalen van een textuur op te slaan. Voor dat opsplitsen zorgt de functie split16bitycocgint. Dan rest ons nog de waarden in de uitvoer te stoppen. Ze worden hier ook opnieuw herschaald om een waarde tussen 0 en 1 op te leveren. Het resultaat van deze pixelshader is een pixelwaarde die de bewegingscompensatie voltooid heeft. Kleuromzetting naar RGB Al het voorgaande gebeurde in de YCoCg-R-kleurenruimte. Om de pixel correct af te beelden op het scherm, moeten we zijn RGB-waarde kennen. Daartoe gebruiken we onderstaande pixelshader. PS_OUTPUT PS_YCoCgToRGB( PS_INPUT input ) { PS_OUTPUT output = (PS_OUTPUT)0; float t; float4 r=0; float3 ycocgr=0; // retrieve the three textures float4 ty = tex2d(screentexturesamplery, input.tex)*255.0f; float4 tco = tex2d(screentexturesampleru, input.tex)*255.0f; float4 tcg = tex2d(screentexturesamplerv, input.tex)*255.0f; // combine all values ycocgr.x = repack16bitycocgint(ty.a, ty.r); ycocgr.y = repack16bitycocgint(tco.a, tco.r); 3 We werken immers in bytes. 69

ycocgr.z = repack16bitycocgint(tcg.a, tcg.r); // apply transformation to RGB t = ycocgr.x - floor(ycocgr.z/2); r.g = t + ycocgr.z; r.b = t - floor(ycocgr.y /2); r.r = r.b + ycocgr.y; // rescale value r = r / 255.0f; // write RGB values output.diffuse.r = r.r; output.diffuse.g = r.g; output.diffuse.b = r.b; return output; } Deze pixelshader vraagt alledrie de texturen op en schaalt deze opnieuw naar een integer getal tussen 0 en 255. Daarna stellen we voor deze waarden de twee kanalen samen tot één waarde om zo de YCoCg-R-componenten te bekomen. Deze worden vervolgens omgezet met de transformatieformules. Deze zijn analoog aan die uit het eindwerk [3]. Daarna herschalen we deze waarde opnieuw naar een getal tussen 0 en 1 en geven we deze waarden door om ze als uitvoer te gebruiken. Nabeschouwingen We merken bij de laatste pixelshader een aantal verschillen op tegenover de kleurconversie bij Van Rijsselbergen [3]. Eerst en vooral wordt hier nergens een floor-functie gebruikt om afrondingsfouten weg te werken en wordt toch het juiste resultaat op het beeld getoond. Als tweede belangrijk verschil merken we op dat de ingewikkelde herschalingsformule r = frac(r/256) (256.0/255.0) hier vervangen is door de eenvoudige deling r = r/255.0f. 70

Dit is een gevolg van het behouden van het juiste teken doorheen de omzetting naar YCoCg-R en bij de bewegingsschatting in de encoder. Dit werd reeds aangekaart in Hoofdstuk 4 en bracht met zich mee dat het ongecomprimeerde bestandsformaat van dit eindwerk niet meer compatibel is met dat van het vorige eindwerk. Dit vormt echter geen bezwaar gezien het positieve effect van de eenvoudigere formule en het feit dat we RGB-beelden kunnen omzetten naar dit aangepaste bestandsformaat. Tot slot melden we ook nog een opmerkelijk feit met betrekking tot de grafische hardware. Voor het ontwikkelen van de decoder werd gewerkt op een Acer Aspire 5024 die over een Mobility Radeon X700 beschikt. Deze kaart ondersteunt het Shader Model 2.0 en was dus ook geschikt voor het uittesten van de decoder. Zoals in volgend hoofdstuk aan bod komt, hebben we de eigenlijke testen uitgevoerd op een krachtigere kaart, de GeForce 7800. Er is nu een verschil in hoe deze kaarten dezelfde shaders uitvoeren. Bij de GeForce 7800 bleken geen floor-functies of andere ingrepen nodig om afrondingsfouten weg te werken. De Radeon x700 daarentegen leverde met en zonder de floor verkeerde resultaten. Het referentie apparaat leverde wel juiste resultaten, waardoor onze blik toch richting de hardware ging. Het bestuderen van de gedownloade bewegingsgecompenseerde YCoCg-R-beelden deed ons vermoeden dat de waarden eerder te klein waren dat te groot. Een floor was dus zeker niet aangewezen en inderdaad een ceil bracht wel het juiste resultaat op het scherm bij de Radeon als we de hardware zijn werk lieten doen. Daardoor is er een verschil voor de code die werkt voor het referentie apparaat en diegene die werkt voor de hardware van de Radeon x700. Bij de GeForce 7800 bleef de code enkel werken zonder ceil of floor. Dit laatste vormt dan ook een elegantere oplossing, omdat we zowel voor de hardware als voor het referentie apparaat dezelfde code kunnen gebruiken. Dit fenomeen geeft ook het kwaliteitsverschil tussen beide grafische kaarten aan. 6.5 Het ontwikkelproces Het ontwikkelproces van de decoder kwam op gang na het implementeren van de encoder. In tegenstelling tot de encoder, werd er voor de decoder vertrokken van reeds bestaande code uit vorige eindwerken. Het aanpassen en deels herschrijven van de codefragmenten bleek dan ook een tijdrovend en foutgevoelig procedé, waarbij vooral veel energie uitging naar het bestuderen van de reeds geïmplementeerde functionaliteit. Zoals reeds vermeld, kwamen de shaders tot stand door een vlotte samenwerking met Bart Pieters. Het grootste deel van de tijd ging uit naar het opsporen van fouten en zoeken naar kleine 71

aanpassingen in de shaders om zo tot een correct beeld te komen. De meeste fouten waren een rechtstreeks gevolg van het werken met de extra bits in de YCoCg-R-kleurenruimte. Zo moesten er ook extra controlepunten worden ingebouwd in de encoder om correctheid te verzekeren. De decoder bleef echter ook hierna de verkeerde resultaten naar het scherm sturen, getuige Figuur 6.5. Figuur 6.5: Een foutief resultaat van de decoder Bepaalde delen werden nu wel al correct weergegeven. Er werden dan RGB-beelden opgesteld die de volledige kleurenruimte omvatten. Zodoende konden we meteen testen of alle kleuren correct afgespeeld konden worden. Wanneer het eerste correcte beeld een feit was via het referentie apparaat, volgde nog de kwestie van de hardware zoals we op het einde van de voorgaande paragraaf besproken hebben. 72

Hoofdstuk 7 Prestatiemetingen In dit hoofdstuk zullen we de prestatiemetingen van de decoder beschrijven. De hulpmiddelen om deze prestaties te meten en het testmateriaal komen aan bod. Daarna zetten we de resultaten uiteen en proberen we deze te verklaren waar nodig. 7.1 Hulpmiddelen Als we over de prestaties van een decoder spreken, dan denken we vooral aan de snelheid en dus het aantal beelden per seconde (Eng. Frames Per Second). Dit zullen we meten aan de hand van de PersephonePerformanceTimer waarvan we gebruikmaken in de applicatie zelf. Deze zit vervat in het pakket libcore. Met behulp van deze timers kunnen we de tijdsduur van bepaalde onderdelen van de decoder apart meten. Verder gebruiken we ook NVPerfHUD 4 1. Dit is een speciale tool ontwikkeld voor en door nvidia. Hiermee kunnen we eveneens de FPS aflezen en dit keer rechtstreeks van het scherm. Interessant zijn ook vooral de GPU- en CPU-activiteit die getoond worden samen met de hoeveelheid videogeheugen die gebruikt wordt. Om de applicatie op de CPU te bestuderen, maakten we gebruik van CodeAnalyst. Dit is een zogenaamde profiler waarmee we te weten kwamen welke stukken code op de CPU het meeste rekentijd in beslag nemen. 1 Zie http://developer.nvidia.com/object/nvperfhud_home.html 73

7.2 Meetmethode De meetmethode bestaat erin om 50 beelden uit het testbestand in te lezen in het systeemgeheugen. Daarna laten we deze beelden steeds opnieuw afspelen in een lus. Dit herhalen we een 50-tal keren, waarover we onze metingen uitvoeren. Door het op voorhand inlezen van de beelden in het systeemgeheugen treedt er geen vertraging op ten gevolge van het opvragen van de harde schijf, ook niet wanneer de beelden voor het eerst afgespeeld worden. Er wordt met andere woorden niet gerekend op het cachen van de beelden door windows zelf. De meetresultaten afkomstig van de PersephonePerformance- Timer worden op het einde van de test uitgeschreven naar een XML-bestand. Van daaruit kunnen ze makkelijk verwerkt worden. Het meten met NVPerfHUD gebeurde door het aflezen van de gegevens die op het scherm getoond werden. In Figuur 7.1 krijgen we een idee hoe dit eruitziet. Hierbij letten we vooral op een paar specifieke gegevens die getoond worden. Linksboven zien we de FPS en rechtsonder zien we het geheugengebruik van de grafische kaart. Verder krijgen we ook een grafiek te zien waarop de wachttijden van de CPU en GPU te zien zijn. Door het aflezen, kunnen deze metingen minder nauwkeurig zijn. Bij sommige sequenties schommelde de waarde voor de FPS immers flink. Toch wilden we ook op deze manier metingen doen om niet afhankelijk te zijn van één meetmethode. Zo kunnen we ook meer betrouwbare besluiten vormen als een bepaalde trend zich bij beide metingen voordoet. 7.2.1 Triple buffering Om de prestaties op te drijven, maken we ook gebruik van triple buffering. Dit wil zeggen dat we het aantal texturen verdrievoudigen op de grafische kaart. Daardoor kunnen we in drie opeenvolgende stappen naar een andere textuur opladen. Dit verbruikt wel meer videogeheugen, maar komt de prestaties ten goede. Het opladen van de data kan immers gebundeld worden voor het groter aantal texturen. Zo heeft de GPU sneller de nodige textuur ter beschikking. Of dit in de praktijk ook effectief snelheidswinst oplevert, zal moeten blijken uit de testresultaten. 74

FPS wachttijd GPU & CPU videogeheugen in gebruik Figuur 7.1: Meten met NVPerfHUD 4 7.3 De testsequenties Er werd telkens getest met sequenties die 250 beelden bevatten. De viper2 -beelden met een formaat van 1920 1080 werden ons aangereikt vanuit de onderzoeksgroep. Aangezien het echter belangrijk is om met verschillende afmetingen te testen, werden een aantal publiek beschikbare fragmenten met verschillende resoluties van het internet geplukt. In Tabel 7.1 staat een overzicht van de gebruikte sequenties. Tabel 7.1: Het testpakket en zijn afmetingen Bestandsnaam Resolutie Megapixel Pirates 768x318 0,24 Croft 720x480 0,34 Double Agent 768x576 0,44 Lara 1280x720 0,92 Viper2 1920x1080 2,07 Met de DirectShow-filter ffdshow en via graphedit konden de beelden naar bitmaps 75

omgezet worden. Via het programma XnView 2 transformeerden we deze dan naar RGBbestanden in een interleaved RAW-formaat. Vanaf dat punt konden we verderwerken met de tools die bij de encoder ontwikkeld zijn (zie Sectie 4.6). Daarmee worden eerst alle afzonderlijke RGB-beelden in één bestand opgeslagen. Hierin worden de kleurcomponenten in planes geordend 3. Daarna zetten we dit bestand om naar het formaat voor ongecomprimeerde YCoCg-R-beelden, zoals beschreven in Sectie 4.3.2. Tot slot laten we de encoder zijn werk doen om de residubeelden en de bewegingsvectoren te bekomen. Dit levert ons dan twee bestanden op die we kunnen laten afspelen door de encoder. 7.4 Testopstelling De testcomputer van dienst was DeBoeck die momenteel in VOP-ruimte (lokaal 3.17) staat. We beschrijven kort de specificaties van dit systeem. Hardware: Intel Pentium D 950 3.4 GHz, 2x2MB L2 Cache, 800 MHz FSB 4 GB DDR2 533 Mhz (Dual Channel) RAID 0 (stripe) Serial ATA RAID, 7200 RPM NVIDIA GeForce 7800 GTX (256 MB, PCI-Express 16x) Software: Microsoft Windows XP Pro SP2 Microsoft Visual Studio.NET 2003 Microsoft DirectX SDK Feb. 2006 (met bijgeleverde HLSL-compiler) NVIDIA Geforce Drivers v84.63 NVIDIA NVPerfHUD 4 2 http://www.xnview.com/ 3 Deze stap is uiteraard niet echt nodig. We zouden ook meteen de omzetting kunnen doen naar YCoCg-R-beelden. Dat we dit toch doen heeft alles te maken met het verloop van dit eindwerk. We zijn immers stap voor stap teruggekeerd tot we aan het interleaved RGB24-formaat kwamen. 76

7.5 Resultaten We geven nu een overzicht van de bekomen resultaten. Eerst beschouwen we de snelheid van de decoder in termen van beelden per seconde. Daarbij wordt het effect van de triple buffer bekeken. Daarna geven we een overzicht van het gebruik van het videogeheugen. 7.5.1 Prestaties van de decoder In Tabel 7.2 zien we de bekomen resultaten uitgedrukt in FPS. Hierbij zijn de sequenties geordend van klein naar groot. Bij de grootste beelden loopt de decoder niet meer in ware-tijd. De beelden met een resolutie 1280 720 halen wel nog meer dan 30 FPS. Bij de hoogste resolutie ontbreken ook de meetwaarden bij triple buffering. Er was immers te weinig videogeheugen om alle texturen op de grafische kaart te krijgen. Tabel 7.2: Resultaten snelheidsmetingen Bestand Mpixels PersephoneTimer NVPerfHUD 4 Zonder Met Zonder Met triple buffer triple buffer triple buffer triple buffer (FPS) (FPS) (FPS) (FPS) Pirates 0,24 163,20 154,23 125,7 125,7 Croft 0,34 99,14 113,12 87,7 98,2 Double Agent 0,44 78,59 89,86 71,0 80,2 Lara 0,92 32,48 35,49 33,3 35,5 Viper2 2,07 17,50 17,5 Vergelijking tussen Persephone en NVPerfHUD 4 In Figuur 7.2 zien we de beeldsnelheden zonder het gebruik van een triple buffer. Figuur 7.3 toont dezelfde meting maar met een triple buffer. Deze grafieken vergelijken beiden de metingen met enerzijds Persephone en anderzijds NVPerfHUD 4. Hieruit zien we dat NVPerfHUD 4 meestal lagere beeldsnelheden aangeeft. Dit is mogelijk te wijten aan de extra overhead die dit programma veroorzaakt 4. 4 NVPerfHUD meet meerdere zaken en brengt dit alles rechtstreeks op het scherm. Dit zal dus ook meer rekentijd vergen dan Persephone. 77

Perstatiemeting zonder triple buffer FPS 180,00 160,00 140,00 120,00 100,00 80,00 60,00 40,00 20,00 0,00 Pirates Croft Double Agent Testsequentie PersephonePerformanceTimer nvperfhud Lara Viper2 Perstatiemeting met triple buffer FPS 180,00 160,00 140,00 120,00 100,00 80,00 60,00 40,00 20,00 0,00 Figuur 7.2: Testresultaten zonder triple buffer PersephonePerformanceTimer nvperfhud Pirates Croft Double Agent Testsequentie Lara Viper2 Figuur 7.3: Testresultaten met triple buffer 78

Toch merken we dat de waargenomen trend 5 gelijk is bij beide meetmethoden. Naarmate de beelden groter worden, wijken de waarden steeds minder van elkaar af. Bij de hoogste resolutie zijn ze zelfs gelijk. Hieruit besluiten we dat beide meetmethoden evenwaardig zijn. In wat volgt zullen we werken met de meetwaarden bekomen met Persephone, tenzij anders vermeld. Vergelijking met en zonder triple buffering Figuur 7.4 vergelijkt de meetwaarden bekomen met en zonder gebruik van een triple buffer. We zien dat er in vele gevallen prestatiewinst geboekt wordt met de drievoudige buffering, maar niet altijd. Voor de kleinste videobeelden treedt er zelfs een verlies aan prestatie op. Dit is te verklaren doordat deze kleinere beelden zó snel kunnen opgeladen worden dat het veranderen van texturen en de extra overhead die daarmee gepaard gaat een grotere impact heeft op de prestaties dan het opladen van de data zelf. Voor de overige afmetingen is het wel nuttig om een triple buffer gebruiken, maar de prestatiewinst is eerder gering. Het gaat hier in het beste geval over een versnelling van een tiental beelden per seconde. Als we NVPerfHUD inschakelen, dan kunnen we ook de wachttijd van de GPU bekijken. Dit is telkens de groene lijn die uitvergroot staat in Figuur 7.5. De blauwe lijn geeft weer wanneer de CPU wacht op de GPU. Bij triple buffering zien we dat de CPU niet moet wachten op de GPU. Tevens is bij deze techniek de wachttijd van de GPU lager en vertoont de grafiek een egaal verloop. Zonder triple buffer zijn er nog veel schommelingen te zien op de grafiek. Dit geeft aan dat met triple buffering er een betere samenwerking is tussen CPU en GPU. stijgt. 5 Hierbij doelen we op de evidente vaststelling dat de decodeersnelheid daalt naarmate de resolutie 79

FPS 180,00 160,00 140,00 120,00 100,00 80,00 60,00 40,00 20,00 0,00 Perstatiemeting zonder en met triple buffer (Persephone) Pirates Croft Double Agent Testsequentie Lara zonder triple buffer met triplebuffer Viper2 Figuur 7.4: Testresultaten met en zonder triple buffer 80

zonder triple buffer met triple buffer Figuur 7.5: Vergelijking met of zonder triple buffer in NVPerfHUD 81

7.5.2 Gebruik videogeheugen Dankzij NVPerfHUD kunnen we ook zien hoeveel plaats in het videogeheugen ingenomen wordt. We zetten de resultaten uiteen in Tabel 7.6. Tabel 7.3: Gebruik videogeheugen met en zonder triple buffer Bestand Mpixels Videogeheugen Zonder triple buffer Met triple buffer (MB) (MB) Pirates 0,24 40 66 Croft 0,34 46 88 Double Agent 0,44 52 103 Lara 0,92 87 193 Viper2 2,07 180 zonder triple buffer 250 met triplebuffer 200 150 MB 100 50 0 Pirates Croft Double Agent Lara Viper2 Testsequentie Figuur 7.6: Gebruik van videogeheugen met en zonder triple buffer 82

7.6 Opzoek naar de flessenhals Uit het eindwerk van Pieters [4] en uit [16] is reeds gebleken dat de GPU-geassisteerde decoder prestatiewinst levert tegenover een decoder die enkel op de CPU draait. Onze eigen resultaten tonen aan dat via de hier voorgestelde implementatie een ware-tijd decoder tot op een zekere hoogte haalbaar is. We nemen nu opnieuw de viper2 -sequentie onder de loep met NVViperHUD 4 in Figuur 7.7. In de grafiek van de wachttijden zien we dat zowel de GPU als de CPU nog een tijd niets staan te doen. Wat de CPU betreft is dit geen enkel probleem. Het is net onze bedoeling dat de CPU zo weinig mogelijk werk heeft. Maar de GPU wensen we tenvolle te benutten. Dit fenomeen komt pas op de voorgrond met deze hoge resolutie. Figuur 7.7: De viper2 -sequentie met NVPerfHUD Om de bottleneck te vinden, gingen we op zoek met de profiler CodeAnalyst om te zien waar de CPU vooral tijd aan besteedt. Daarmee kwamen we te weten dat de overgrote tijd ging naar een memcpy-instructie. Dit was namelijk het opladen van de residubeelden 83