-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
342 additions
and
108 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
namespace PlayMobic.Tests.Video; | ||
using PlayMobic.Video.Mobiclip; | ||
|
||
[TestFixture] | ||
public class HuffmanFactoryTests | ||
{ | ||
[Test] | ||
[TestCase(0, 0x000, 0x03, 8)] | ||
[TestCase(0, 0x001, 0x02, 3)] | ||
[TestCase(0, 0x002, 0x0F, 5)] | ||
[TestCase(0, 0x021, 0x06, 4)] | ||
[TestCase(0, 0x081, 0x0C, 6)] | ||
[TestCase(0, 0x801, 0x07, 5)] | ||
[TestCase(0, 0x802, 0x19, 10)] | ||
[TestCase(0, 0x821, 0x0F, 7)] | ||
[TestCase(0, 0x841, 0x0E, 7)] | ||
[TestCase(0, 0x8E1, 0x11, 8)] | ||
[TestCase(1, 0x000, 0x03, 8)] | ||
[TestCase(1, 0x801, 0x07, 5)] | ||
public void TestTreeFromTable(int tableIdx, int value, int expectedCode, int expectedBitCount) | ||
{ | ||
string name = typeof(Huffman).Namespace + $".huffman_residual_table{tableIdx}.bin"; | ||
var huffman = HuffmanFactory.CreateFromResidualTable(name); | ||
|
||
HuffmanCodeword codeword = huffman.GetCodeword(value); | ||
Assert.Multiple(() => { | ||
Assert.That(codeword.Value, Is.EqualTo(value)); | ||
Assert.That(codeword.Code, Is.EqualTo(expectedCode)); | ||
Assert.That(codeword.BitCount, Is.EqualTo(expectedBitCount)); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
namespace PlayMobic.Video.Mobiclip; | ||
|
||
public readonly struct HuffmanCodeword | ||
{ | ||
public HuffmanCodeword(int code, int bitCount, int value) | ||
{ | ||
Code = code; | ||
BitCount = bitCount; | ||
Value = value; | ||
} | ||
|
||
public int Code { get; } | ||
|
||
public int BitCount { get; } | ||
|
||
public int Value { get; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
namespace PlayMobic.Video.Mobiclip; | ||
using System; | ||
using System.Reflection; | ||
using Yarhl.IO; | ||
|
||
/// <summary> | ||
/// Factory of Huffman trees following the original binary tree definitions. | ||
/// </summary> | ||
internal static class HuffmanFactory | ||
{ | ||
public static Huffman CreateFromResidualTable(string resourceName) | ||
{ | ||
using Stream tableStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName) | ||
?? throw new FileNotFoundException("Missing huffman table"); | ||
|
||
// Format is for each 16-bits item: | ||
// index (13 bits max): codeword | ||
// bit0-3: number of codeword bits (to clean up the index) | ||
// bit4-15: value | ||
// this is a trick to decode huffman via a hash table lookup (fast reads) | ||
// it repeats the same value for all the variant of short codewords | ||
// so for a codeword of 10 bits, it will repeat the value for all combinations | ||
// of that codeword and its 3 remaining bits. | ||
int numItems = (int)(tableStream.Length / 2); | ||
var reader = new DataReader(tableStream); | ||
|
||
const int MaxCodewordLength = 13; | ||
var huffman = new Huffman(MaxCodewordLength); | ||
|
||
for (int i = 0; i < numItems; i++) { | ||
ushort item = reader.ReadUInt16(); | ||
|
||
int bitCount = item & 0xF; | ||
int value = item >> 4; | ||
int codeword = i >> (MaxCodewordLength - bitCount); | ||
|
||
if (bitCount == 1) { | ||
// padding | ||
continue; | ||
} | ||
|
||
huffman.InsertCodeword(codeword, bitCount, value); | ||
} | ||
|
||
// the codeword for 0 is "hard-coded" in code | ||
huffman.InsertCodeword(0b00000011, 8, 0); | ||
|
||
return huffman; | ||
} | ||
|
||
public static Huffman CreateFromSymbolsAndCountLists(byte[] symbols, byte[] bitCounts) | ||
{ | ||
// similar to above, the index gives the codeword for each symbol. | ||
// the value points also to the bits count of the codeword | ||
int maxCodewordLength = (int)Math.Log2(symbols.Length); | ||
|
||
var huffman = new Huffman(maxCodewordLength); | ||
for (int i = 0; i < symbols.Length; i++) { | ||
int symbol = symbols[i]; | ||
int bitCount = bitCounts[symbol]; | ||
int codeword = i >> (maxCodewordLength - bitCount); | ||
|
||
huffman.InsertCodeword(codeword, bitCount, symbol); | ||
} | ||
|
||
return huffman; | ||
} | ||
} |
Oops, something went wrong.