FLAC decoder en UTF-8 nummer

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • Alfredo
  • Registratie: Maart 2007
  • Laatst online: 31-07 19:40
De vraag is niet specifiek op een taal gericht, daarom heb ik er ook geen [brackets] bij geplaatst.

Ik ben bezig met het schrijven van een decoder voor FLAC bestanden, en bots op het volgende probleem.

Volgens de specificatie van de frame header, moet je op het einde het frame- en samplenummer kunnen achterhalen (zie: "UTF-8" coded frame number (decoded number is 31 bits)). Wat ik daarvan begrijp, is dat bij een fixed blocksize het framenummer tussen de 8 en 48 bits ruimte in beslag neemt. En dat dit de UTF-8 representatie is van een nummer. Dus met een range tussen 0x30 en 0x39.

Echter, daar aangekomen in het bestand, zie ik voor het eerste frame waarde 0x00 staan. Alle informatie die ik daarvoor heb opgehaald is correct (blocksize, sample size, channel assignment, ...), dus ik ben vrijwel zeker dat ik naar de juiste byte ben aan het kijken.
Als ik er een andere decoder bijhaal, zie ik bijvoorbeeld dit:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
private long readUtf8Int(BitInputStream source) throws IOException {

      long v=0;
      int x=0, i=0;

      x=source.getInt(8);

      if((x&0x80)==0) {
         v=x;
         i=0;
      }
      else if((x&0xe0)==0xc0) { /* 110xxxxx */
         v = x & 0x1f;
         i = 1;
      }
      else if((x&0xf0)==0xe0) { /* 1110xxxx */
         v = x & 0x0F;
         i = 2;
      }
      else if((x&0xf8)==0xf0) { /* 11110xxx */
         v = x & 0x07;
         i = 3;
      }
      else if((x&0xfc)==0xf8) { /* 111110xx */
         v = x & 0x03;
         i = 4;
      }
      else if((x&0xfe)==0xfc) { /* 1111110x */
         v = x & 0x01;
         i = 5;
      }
      else if(x==0xfe) { /* 11111110 */
         v = 0;
         i = 6;
      }
      else {
         return Long.MIN_VALUE;
      }

      for( ; i>0; i--) {
         x=source.getInt(8);

         if((x&0xc0)!=0x80) { /* 10xxxxxx */
            return Long.MIN_VALUE;
         }
         v <<= 6;
         v |= (x & 0x3f);
      }

      return v;
   }


Als ik in deze functie echter manueel 0x31 invoer (ik verwacht dus "1" als uitvoer), krijg ik een compleet ander resultaat. Waar is mijn denkwijze ergens compleet de mist ingegaan? Of wat voor data moet ik wel verwachten?

Acties:
  • 0 Henk 'm!

  • Ciqniz
  • Registratie: Oktober 2002
  • Laatst online: 07-09-2023

Ciqniz

On the move...

Afhankelijk van je compiler en hoe je jouw 0x31 meegeeft zal je wellicht door middel van een impliciete cast 1 meegeven (dus jouw 0x31 wordt gecompileerd naar 1, en komt dus door weer een impliciete cast in jouw functie als 0x01 terug). Misschien wel heel ver gezocht?

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 01:47
Wat krijg je er dan wel uit? Ik kan me voorstellen dat er iets mis gaat met de ordening van bits in een byte (omgedraaid bijvoorbeeld), maar dat is moeilijk te zeggen omdat je het bij een abstracte beschrijving laat en geen concreet geval geeft wat niet goed werkt.

Op deze manier kunnen we er weinig meer over zeggen dan dat de specificatie waarschijnlijk correct is en jij ergens een fout maakt. ;)

Die UTF-8 decodeerfunctie ziet er goed uit wat mij betreft, dus daar ligt het niet aan, maar als ik je goed begrijp dan gebruik jij juist een andere... dus wat schiet je daar mee op?

[ Voor 18% gewijzigd door Soultaker op 27-04-2010 22:48 ]


Acties:
  • 0 Henk 'm!

  • Alfredo
  • Registratie: Maart 2007
  • Laatst online: 31-07 19:40
Goed, iets meer uitleg. Het bestand dat ik probeer te decoden is DaFunk, komende uit een library met FLAC samples. Het eerste framenummer kom ik tegen als mijn bytearray op positie 4230 (1086h) staat. Volgens de specificatie moet ik daar een UTF-8 waarde terugvinden. Ik verwacht dus 0x30 of 0x31, respectievelijk 0 en 1 volgens UTF-8.
De waarden die ik op die positie echter uitlees, zijn 00 DD 14 FF ... En daar zie ik zo geen representatieve UTF-8 waarden in.

Als ik de functie overloop die van UTF-8 waarden ints moet maken, kom ik op dit uit (voorbeeld met 0x31):

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private long readUtf8Int(BitInputStream source) throws IOException {

      long v=0;
      int x=0, i=0;

      x=source.getInt(8); // x = 0x31

      if((x&0x80)==0) {
         v=x; // v = 0x31
         i=0;
      }
         v <<= 6; // v = 0x0C40
         v |= (x & 0x3f); // v = 0x0C71
      }

      return v; // Geeft 3185 terug, niet 1
   }

Of ik heb ergens iets fout gedaan, of bovenstaande functie decodeert geen UTF-8.

Als voetnoot staat er bij de FLAC specificatie: The "UTF-8" coding used for the sample/frame number is the same variable length code used to store compressed UCS-2, extended to handle larger input.
Met andere woorden, ze noemen het dus UTF-8, maar eigenlijk is het een gecomprimeerde vorm van UTF-16? Dan heb ik bovenstaande functie wel nodig, ook al begrijp ik niet wat ze nu eigenlijk doet...

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 01:47
Ik begin er nu iets van te begrijpen. Jij verwacht blijkbaar een UTF-8 gecodeerde tekst terug te krijgen, die vervolgens weer als getal is te interpreteren. Maar wat er volgens mij gebeurt is dat er een getal gecodeerd wordt met UTF-8. Getallen onder de 128 worden dus gewoon gerepresenteerd met één byte, terwijl bijvoorbeeld 128 wordt gecodeerd met twee bytes: 224, 128.

UTF-8 wordt hier dus niet gebruikt voor tekst, maar simpelweg om een getal te coderen met een variabel aantal bytes, zodat kleine waarden minder ruimte gebruiken. Tenminste, dat is hoe ik de specificatie interpreteer.

Tenslotte wat betreft de Java code: als je daar 0x31 in stopt dan match je alleen de eeerste case, dus v=0x31 en i=0 waardoor de while-loop nul keer wordt uitgevoerd. Regel 12-15 in je laatstgepostte code worden dus niet uitgevoerd en het resultaat is gewoon 31.

Die 0 in de invoer is dus conform de verwachtingen: dit is simpelweg het eerste frame/sample nummer.

Acties:
  • 0 Henk 'm!

  • Alfredo
  • Registratie: Maart 2007
  • Laatst online: 31-07 19:40
Ah, mijn fout, ik dacht dat die for loop eerder sloot.

Het principe (en nut) erachter ontgaat me nog steeds een beetje. Getallen onder 128 kunnen toch altijd met 1 byte voorgesteld worden?
Ik ga de functie eens porten en dan verder debuggen. Misschien wordt het me dan wel duidelijk. :)

Acties:
  • 0 Henk 'm!

  • Johnny
  • Registratie: December 2001
  • Laatst online: 17-09 16:59

Johnny

ondergewaardeerde internetguru

Alfredo schreef op woensdag 28 april 2010 @ 00:20:
Het principe (en nut) erachter ontgaat me nog steeds een beetje. Getallen onder 128 kunnen toch altijd met 1 byte voorgesteld worden?
Niet als je decoder uitgaat van een vaste hoeveelheid bytes (bijvoorbeeld 4) dan heb je dus ook voor getallen evenveel bytes nodig en wordt je bestand groter. Daarom staat er dus in de specificatie expliciet dat het om een variable lengte gaat.

Aan de inhoud van de bovenstaande tekst kunnen geen rechten worden ontleend, tenzij dit expliciet in dit bericht is verwoord.

Pagina: 1