14Bit Chunks zu 16Bit wandeln.

chmee

verstaubtes inventar
Premium-User
Ich habe Daten-Chunks vor mir, die aus Bytefolgen bestehen, aber als Datum 14Bit lang und aneinandergereiht sind. Jetzt brauche ich sie aber in 16Bit Länge und möchte mit Nullen auffüllen um zu 16Bit-Chunks konvertieren. Ich will es in C# machen, aber erstmal wäre mir ein schneller Algorithmus von Nöten..

Im Moment habe ich ein Byte[]-Array - was nun? Nachtrag Wandeln nach memorystream und dann jeweils 14 Bit auslesen, Wert in Word[]-Array ablegen? Oder mit BitArray arbeiten? Primär geht es um Effizienz, diese Konversion wird pro Durchgang viele viele Male getätigt.

mfg chmee

Nachtrag Bild angehängt:)
BitConvert.jpg
 

Shakie

Erfahrenes Mitglied
Ich verstehe nicht, was du tun willst :)
Du hast ein Array, bestehend aus N Bytes und jedes Byte besteht aus 8 Bit? Oder 7 Bit? Ein C#-Byte besteht immer aus 8 Bits. Ich glaube, die Reihenfolge (Byte-Order) ist aber nicht vorgeschrieben und kann plattformabhängig sein (denke daran, dass es auch Dinge wie Mono gibt). Was meinst du also mit "Bytefolge"? Oder meintest du eigentlich 14 Byte statt 14 Bit?
 

sheel

I love Asm
Hi

Um es auf 7 und 8 Bit statt 14 und 16 runterzuschrauben,
und die verschiedenen Zahlen sind die einzelnen Werte:
Du hast also sowas:
11111112 22222233 33333444 44445555 ...
also immer 7 bit so zusammengestopft in 8bit-Bytes, und willst das auftrennen
01111111 02222222 03333333 04444444 05555555
oder...?
(nur eben 14 und 16 statt 7 und 8)
 

chmee

verstaubtes inventar
Premium-User
Etwas Licht ins Dunkel.. Es sind die RAW-Daten eines Fotosensors. Jeder Subpixel wirft 14Bit raus. Ich lese das ganze Bild als byte-Array ein. Würde ich sie - wie zuvor programmiert - mit den 14 Bit wieder rauswerfen, wäre das alles kein Thema. Rein. Raus. Egal, ob ich sie als Bytes im Speicher gecacht habe.. (Photoshop, AfterEffects, und andere Viewer kommen mit der Datei klar)

Nun habe ich aber bemerkt, dass die wichtigen Videoschnittprogramme (Resolve oder Speedgrade) die 14Bit gar nicht verstehen wollen, die kennen nur 8, 10 (uU 12) oder 16Bit. Ergo muß ich den Datenstrom doch anfassen und die 14Bit in 16Bit pro Chunk verpacken. (denn weniger wäre schlecht für die Bilddaten)

(7Bytes = 4 Subpixel (zu je 14Bit!) werden zu 4x16Bit = 8 Byte)

Ich hab grad Jetzt keine Lust mehr - morgen pack ich mal meinen ersten Versuch rein, der ganze Kladderadatsch mit Bitshift und &-Maskierung.. Im Moment wird die Datei angenommen, aber es ist ein Pixelchaos, irgendwo ein Denkfehler im Shiften oder Maskieren. Dennoch Danke erstmal für Euer Gehör.

mfg chmee
 

chmee

verstaubtes inventar
Premium-User
Code:
// -- input
// byte[] source - 14bit-Chunk stream
// int chunks - array length
// -- output
// byte[] Dest - 16Bit-Chunk stream

public static byte[] to16(byte[] source, int chunks)
        {
            // create output byte-array with new length
            byte[] Dest = new Byte[chunks/14*16];
            UInt16 firW, secW, thiW, fouW, tmpA, tmpB, tmpC;
            int tt =0;
            // KGT von 8 und 14 - 56bit - 7 Bytes werden benötigt um 4x14Bit umzuwandeln
            // Zeichnung im ersten Beitrag.
            for (var t = 0; t < chunks; t += 7)
            {
                //erstmal nach UInt16 zusammenfassen
                tmpA = (UInt16)((UInt16)(source[t])<<6);
                tmpB = (UInt16)((UInt16)(source[t + 1] >> 2));
                firW = (UInt16)(tmpA + tmpB);

                tmpA = (UInt16)((UInt16)(source[t + 1] & 00000011) << 12);
                tmpB = (UInt16)((UInt16)(source[t + 2]) << 4);
                tmpC = (UInt16)((UInt16)(source[t + 3] >> 4));
                secW = (UInt16)(tmpA+tmpB+tmpC);

                tmpA = (UInt16)((UInt16)(source[t + 3] & 00001111) << 10);
                tmpB = (UInt16)((UInt16)(source[t + 4]) << 2);
                tmpC = (UInt16)(source[t + 5] >> 6);
                thiW = (UInt16)(tmpA + tmpB + tmpC);

                tmpA = (UInt16)((UInt16)(source[t + 5] & 00111111) << 8);
                tmpB = (UInt16)(source[t + 6]);
                fouW = (UInt16)(tmpA + tmpB);

                // dann in jeweils zwei Bytes zerlegen
                Dest[tt++] = (byte)firW; 
                Dest[tt++] = (byte)(firW >> 8);
                Dest[tt++] = (byte)secW;
                Dest[tt++] = (byte)(secW >> 8);
                Dest[tt++] = (byte)thiW;
                Dest[tt++] = (byte)(thiW >> 8);
                Dest[tt++] = (byte)fouW;
                Dest[tt++] = (byte)(fouW >> 8);
                
            }
            return Dest;

        }
Da ist auf jeden Fall noch Datenwurst drin. Irgendwo in den Shifts und Masks. Ach ja, Geschwindigkeit, ich dachte das Ding würde die eigentliche Aufgabe (RAW nach DNG) deutlich verlangsamen, tut es aber nicht. Zum Glück.

mfg chmee
 

deepthroat

Erfahrenes Mitglied
Hi.

Du meinst vermutlich KGV, nicht KGT, oder?!

Deine Masken stimmen nicht. Du möchtest wohl 000000011 als Binärzahl auswerten? Dann mußt du die entsprechende Dezimalzahl oder Hexadezimalzahl (3 bzw. 0x3) angeben.

Statt + würde ich einfach das Binär-Oder verwenden.

Die UInt16 Casts kannst du weglassen; da du mit Integer (Literalen) operierst werden die UInt16 sowieso zu Int befördert - was mit den Byte auch passieren würde.

Und die ganze Choose erst in UInt16 zu sammeln, um sie dann wieder in Bytes zu teilen ist evtl. auch etwas zu kompliziert...
C#:
Dest[tt++] = (byte)(source[t] >> 2);
Dest[tt++] = (byte)((source[t] << 6) | (source[t + 1] >> 2));

Dest[tt++] = (byte)(((source[t + 1] & 0x3) << 4) | (source[t + 2] >> 4));
Dest[tt++] = (byte)((source[t + 2] << 4) | (source[t + 3] >> 4);

Dest[tt++] = (byte)(((source[t + 3] & 0xF) << 2) | (source[t + 4] >> 6));
Dest[tt++] = (byte)((source[t + 4] << 2) | (source[t + 5] >> 6);

... // usw.
 

chmee

verstaubtes inventar
Premium-User
Danke erstmal :) Brauche zunächst nen Kaffee.. (KGV, richtig). Ich probiers mal gleich aus. Beim Schreiben dieses ersten Codes hatte ich auch nen Denkfehler. Der Daten-Stream kommt natürlich MSB rein, nicht LSB, fängt mit dem niederwertigsten Bit an.

Beispiel Bitstellenstream

123456789ABCDE123456789ABCDE123456789ABCDE123456789ABCDE

sind im Bytestream (14er Chunks in 7 Bytes gespeichert)

12345678
9ABCDE12
3456789A
BCDE1234
56789ABC
DE123456
789ABCDE

sollen zu (14 zu 16)

00123456789ABCDE - bzw. 2 Bytes - 00123456 789ABCDE
00123456789ABCDE - bzw. 2 Bytes - 00123456 789ABCDE
00123456789ABCDE - bzw. 2 Bytes - 00123456 789ABCDE
00123456789ABCDE - bzw. 2 Bytes - 00123456 789ABCDE

werden (8 Bytes).

Nachtrag Und sie kommen doch MSB zuerst. Was eine verrückte Welt :)

mfg chmee
 

sheel

I love Asm
Mr ist zwar nicht ganz klar, wie die Byte/bitreihenfolgen bei welchen Daten nun sind,
aber vllt. deepthroats Code einfach ausprobieren?

Bzw. ergänzt um das Letzte:
C#:
for (int t = 0; t < chunks; t += 7)
{
    Dest[tt++] = (byte)(source[t] >> 2);
    Dest[tt++] = (byte)((source[t] << 6) | (source[t + 1] >> 2));
 
    Dest[tt++] = (byte)(((source[t + 1] & 0x3) << 4) | (source[t + 2] >> 4));
    Dest[tt++] = (byte)((source[t + 2] << 4) | (source[t + 3] >> 4);

    Dest[tt++] = (byte)(((source[t + 3] & 0xF) << 2) | (source[t + 4] >> 6));
    Dest[tt++] = (byte)((source[t + 4] << 2) | (source[t + 5] >> 6);

    Dest[tt++] = (byte)(source[t + 5] & 0x3F);
    Dest[tt++] = source[t + 6];
}
Oder, mit Zielendian umgedreht
C#:
int t, tt;
for (t = 0, tt = 0; t < chunks; t += 7, tt += 8) //grad keine Ahnung, ob das in C# erlaubt ist
{
    Dest[tt + 1] = (byte)(source[t] >> 2);
    Dest[tt] = (byte)((source[t] << 6) | (source[t + 1] >> 2));
 
    Dest[tt + 3] = (byte)(((source[t + 1] & 0x3) << 4) | (source[t + 2] >> 4));
    Dest[tt + 2] = (byte)((source[t + 2] << 4) | (source[t + 3] >> 4);

    Dest[tt + 5] = (byte)(((source[t + 3] & 0xF) << 2) | (source[t + 4] >> 6));
    Dest[tt + 4] = (byte)((source[t + 4] << 2) | (source[t + 5] >> 6);

    Dest[tt + 7] = (byte)(source[t + 5] & 0x3F);
    Dest[tt + 6] = source[t + 6];
}
 

chmee

verstaubtes inventar
Premium-User
Euch Beiden vielen Dank. Dennoch, irgendwo ist ein Fehler drin, den ich nicht finde. Es scheint, als ob meine Bit-Arie (ich hab unterdessen sogar Bool-Arrays benutzt, um mir sicher zu sein, dass Bit X an Stelle Y ist) oder Euer Shifting und Masking richtig ist und entweder Spalte 1 bzw. 2 irgendwie richtig aussehen (eine von Beiden sieht richtiger aus), Spalte 3 und 4 völlig chaotisch.


mfg chmee
 

deepthroat

Erfahrenes Mitglied
Hm, Beispieldaten wären nicht schlecht.

Oder hast du Spezifikationen über dein RAW Format, evlt. ist da noch ein Encoding (Huffman?) verwendet worden?