Implement KVM websocket proxy in bmcweb

This patchset implements a KVM websocket proxy designed to interoperate
with phosphor-webui and KVM.  in short, IP address 127.0.0.1:5900 is
proxied to the websocket.  This allows someone to connect from a browser
session.

Requires patchset here for the phosphor-webui side:
https://gerrit.openbmc-project.xyz/#/c/openbmc/phosphor-webui/+/10268/
and requires the kvm patches here:
https://gerrit.openbmc-project.xyz/#/c/openbmc/meta-phosphor/+/13536/

Tested By:
Launched webui, observed KVM.  Moved mouse, and typed on keyboard,
changes appeared on host system.

Change-Id: I407488f4b16be208b188a0abc19954a0243af173
Signed-off-by: Ed Tanous <ed.tanous@intel.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6756575..a15e719 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,7 +9,7 @@
 option (YOCTO_DEPENDENCIES "Use YOCTO dependencies system" OFF)
 
 option (BMCWEB_ENABLE_KVM "Enable the KVM host video WebSocket.  Path is
-       '/kvmws'.  Video is from the BMC's '/dev/video' device." ON)
+       '/kvm/0'.  Video is from the BMC's '/dev/video' device." ON)
 option (BMCWEB_ENABLE_DBUS_REST "Enable Phosphor REST (D-Bus) APIs.  Paths
        directly map Phosphor D-Bus object paths, for example,
        '/xyz/openbmc_project/logging/entry/enumerate'.  See
@@ -248,9 +248,6 @@
 target_link_libraries (bmcweb tinyxml2)
 install (TARGETS bmcweb DESTINATION bin)
 
-add_executable (getvideo src/getvideo_main.cpp)
-target_link_libraries (getvideo pthread)
-
 target_compile_definitions (
     bmcweb PRIVATE
     $<$<BOOL:${BMCWEB_ENABLE_KVM}>: -DBMCWEB_ENABLE_KVM>
diff --git a/include/aspeed/JTABLES.H b/include/aspeed/JTABLES.H
deleted file mode 100644
index 641fcfb..0000000
--- a/include/aspeed/JTABLES.H
+++ /dev/null
@@ -1,299 +0,0 @@
-#pragma once

-static const unsigned char zigzag[64] = {

-    0,  1,  5,  6,  14, 15, 27, 28, 2,  4,  7,  13, 16, 26, 29, 42,

-    3,  8,  12, 17, 25, 30, 41, 43, 9,  11, 18, 24, 31, 40, 44, 53,

-    10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60,

-    21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63};

-

-static const unsigned char dezigzag[64 + 15] = {

-    0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40,

-    48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36,

-    29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61,

-    54, 47, 55, 62, 63,

-    // let corrupt input sample past end

-    63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63};

-

-static const unsigned char *stdLuminanceQt;

-static const unsigned char *stdChrominanceQt;

-

-// Standard Huffman tables (cf. JPEG standard section K.3) */

-

-static const unsigned char stdDcLuminanceNrcodes[17] = {

-    0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0};

-static const unsigned char stdDcLuminanceValues[12] = {0, 1, 2, 3, 4,  5,

-                                                          6, 7, 8, 9, 10, 11};

-

-static const unsigned char stdDcChrominanceNrcodes[17] = {

-    0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0};

-static const unsigned char stdDcChrominanceValues[12] = {0, 1, 2, 3, 4,  5,

-                                                            6, 7, 8, 9, 10, 11};

-

-static const unsigned char stdAcLuminanceNrcodes[17] = {

-    0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d};

-static const unsigned char stdAcLuminanceValues[162] = {

-    0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06,

-    0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,

-    0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72,

-    0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,

-    0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,

-    0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,

-    0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75,

-    0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,

-    0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,

-    0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,

-    0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,

-    0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,

-    0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4,

-    0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa};

-

-static const unsigned char stdAcChrominanceNrcodes[17] = {

-    0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77};

-static const unsigned char stdAcChrominanceValues[162] = {

-    0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,

-    0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,

-    0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1,

-    0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,

-    0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44,

-    0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,

-    0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74,

-    0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,

-    0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a,

-    0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,

-    0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,

-    0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,

-    0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,

-    0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa};

-

-static const unsigned short int dcLuminanceHuffmancode[13 * 2] = {

-    /* 0 */ 0x0000,  0,

-    /* 1 */ 0x4000,  2,

-    /* 2 */ 0x6000,  3,

-    /* 3 */ 0x8000,  3,

-    /* 4 */ 0xA000,  3,

-    /* 5 */ 0xC000,  3,

-    /* 6 */ 0xE000,  3,

-    /* 7 */ 0xF000,  4,

-    /* 8 */ 0xF800,  5,

-    /* 9 */ 0xFC00,  6,

-    /* 10 */ 0xFE00, 7,

-    /* 11 */ 0xFF00, 8,

-    /* 12 */ 0xFFFF, 9,

-};

-

-static const unsigned short int dcChrominanceHuffmancode[13 * 2] = {

-    /* 0 */ 0x0000,  0,

-    /* 1 */ 0x4000,  2,

-    /* 2 */ 0x8000,  2,

-    /* 3 */ 0xC000,  2,

-    /* 4 */ 0xE000,  3,

-    /* 5 */ 0xF000,  4,

-    /* 6 */ 0xF800,  5,

-    /* 7 */ 0xFC00,  6,

-    /* 8 */ 0xFE00,  7,

-    /* 9 */ 0xFF00,  8,

-    /* 10 */ 0xFF80, 9,

-    /* 11 */ 0xFFC0, 10,

-    /* 12 */ 0xFFFF, 11,

-};

-

-static const unsigned short int acLuminanceHuffmancode[39 * 2] = {

-    /* 0 */ 0x0000,  0,

-    /* 1 */ 0x4000,  2,

-    /* 2 */ 0x8000,  2,

-    /* 3 */ 0xA000,  3,

-    /* 4 */ 0xB000,  4,

-    /* 5 */ 0xC000,  4,

-    /* 6 */ 0xD000,  4,

-    /* 7 */ 0xD800,  5,

-    /* 8 */ 0xE000,  5,

-    /* 9 */ 0xE800,  5,

-    /* 10 */ 0xEC00, 6,

-    /* 11 */ 0xF000, 6,

-    /* 12 */ 0xF200, 7,

-    /* 13 */ 0xF400, 7,

-    /* 14 */ 0xF600, 7,

-    /* 15 */ 0xF800, 7,

-    /* 16 */ 0xF900, 8,

-    /* 17 */ 0xFA00, 8,

-    /* 18 */ 0xFB00, 8,

-    /* 19 */ 0xFB80, 9,

-    /* 20 */ 0xFC00, 9,

-    /* 21 */ 0xFC80, 9,

-    /* 22 */ 0xFD00, 9,

-    /* 23 */ 0xFD80, 9,

-    /* 24 */ 0xFDC0, 10,

-    /* 25 */ 0xFE00, 10,

-    /* 26 */ 0xFE40, 10,

-    /* 27 */ 0xFE80, 10,

-    /* 28 */ 0xFEC0, 10,

-    /* 29 */ 0xFEE0, 11,

-    /* 30 */ 0xFF00, 11,

-    /* 31 */ 0xFF20, 11,

-    /* 32 */ 0xFF40, 11,

-    /* 33 */ 0xFF50, 12,

-    /* 34 */ 0xFF60, 12,

-    /* 35 */ 0xFF70, 12,

-    /* 36 */ 0xFF80, 12,

-    /* 37 */ 0xFF82, 15,

-    /* 38 */ 0xFFFF, 16,

-};

-

-static const unsigned short int acChrominanceHuffmancode[45 * 2] = {

-    /* 0 */ 0x0000,  0,

-    /* 1 */ 0x4000,  2,

-    /* 2 */ 0x8000,  2,

-    /* 3 */ 0xA000,  3,

-    /* 4 */ 0xB000,  4,

-    /* 5 */ 0xC000,  4,

-    /* 6 */ 0xC800,  5,

-    /* 7 */ 0xD000,  5,

-    /* 8 */ 0xD800,  5,

-    /* 9 */ 0xE000,  5,

-    /* 10 */ 0xE400, 6,

-    /* 11 */ 0xE800, 6,

-    /* 12 */ 0xEC00, 6,

-    /* 13 */ 0xF000, 6,

-    /* 14 */ 0xF200, 7,

-    /* 15 */ 0xF400, 7,

-    /* 16 */ 0xF600, 7,

-    /* 17 */ 0xF700, 8,

-    /* 18 */ 0xF800, 8,

-    /* 19 */ 0xF900, 8,

-    /* 20 */ 0xFA00, 8,

-    /* 21 */ 0xFA80, 9,

-    /* 22 */ 0xFB00, 9,

-    /* 23 */ 0xFB80, 9,

-    /* 24 */ 0xFC00, 9,

-    /* 25 */ 0xFC80, 9,

-    /* 26 */ 0xFD00, 9,

-    /* 27 */ 0xFD80, 9,

-    /* 28 */ 0xFDC0, 10,

-    /* 29 */ 0xFE00, 10,

-    /* 30 */ 0xFE40, 10,

-    /* 31 */ 0xFE80, 10,

-    /* 32 */ 0xFEC0, 10,

-    /* 33 */ 0xFEE0, 11,

-    /* 34 */ 0xFF00, 11,

-    /* 35 */ 0xFF20, 11,

-    /* 36 */ 0xFF40, 11,

-    /* 37 */ 0xFF50, 12,

-    /* 38 */ 0xFF60, 12,

-    /* 39 */ 0xFF70, 12,

-    /* 40 */ 0xFF80, 12,

-    /* 41 */ 0xFF84, 14,

-    /* 42 */ 0xFF86, 15,

-    /* 43 */ 0xFF88, 15,

-    /* 44 */ 0xFFFF, 16,

-};

-

-//[100]=========================

-static const unsigned char tbl100Y[64] = {

-    2, 1, 1, 2,  3,  5,  6,  7,  1, 1,  1,  2,  3,  7,  7,  6,

-    1, 1, 2, 3,  5,  7,  8,  7,  1, 2,  2,  3,  6,  10, 10, 7,

-    2, 2, 4, 7,  8,  13, 12, 9,  3, 4,  6,  8,  10, 13, 14, 11,

-    6, 8, 9, 10, 12, 15, 15, 12, 9, 11, 11, 12, 14, 12, 12, 12};

-static const unsigned char tbl100Uv[64] = {

-    3,  3,  4,  8,  18, 18, 18, 18, 3,  3,  4,  12, 18, 18, 18, 18,

-    4,  4,  10, 18, 18, 18, 18, 18, 8,  12, 18, 18, 18, 18, 18, 18,

-    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,

-    18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18};

-

-//[086]=========================

-static const unsigned char tbl086Y[64] = {

-    3, 2,  1,  3,  4,  7,  9,  11, 2,  2,  2,  3,  4,  10, 11, 10,

-    2, 2,  3,  4,  7,  10, 12, 10, 2,  3,  4,  5,  9,  16, 15, 11,

-    3, 4,  6,  10, 12, 20, 19, 14, 4,  6,  10, 12, 15, 19, 21, 17,

-    9, 12, 14, 16, 19, 22, 22, 18, 13, 17, 17, 18, 21, 18, 19, 18};

-static const unsigned char tbl086Uv[64] = {

-    4,  5,  6,  13, 27, 27, 27, 27, 5,  5,  7,  18, 27, 27, 27, 27,

-    6,  7,  15, 27, 27, 27, 27, 27, 13, 18, 27, 27, 27, 27, 27, 27,

-    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,

-    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27};

-

-//[071]=========================

-static const unsigned char tbl071Y[64] = {

-    6,  4,  3,  6,  9,  15, 19, 22, 4,  4,  5,  7,  9,  21, 22, 20,

-    5,  4,  6,  9,  15, 21, 25, 21, 5,  6,  8,  10, 19, 32, 30, 23,

-    6,  8,  13, 21, 25, 40, 38, 28, 9,  13, 20, 24, 30, 39, 42, 34,

-    18, 24, 29, 32, 38, 45, 45, 37, 27, 34, 35, 36, 42, 37, 38, 37};

-static const unsigned char tbl071Uv[64] = {

-    9,  10, 13, 26, 55, 55, 55, 55, 10, 11, 14, 37, 55, 55, 55, 55,

-    13, 14, 31, 55, 55, 55, 55, 55, 26, 37, 55, 55, 55, 55, 55, 55,

-    55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,

-    55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55};

-//[057]=========================

-static const unsigned char tbl057Y[64] = {

-    9,  6,  5,  9,  13, 22, 28, 34, 6,  6,  7,  10, 14, 32, 33, 30,

-    7,  7,  9,  13, 22, 32, 38, 31, 7,  9,  12, 16, 28, 48, 45, 34,

-    10, 12, 20, 31, 38, 61, 57, 43, 13, 19, 30, 36, 45, 58, 63, 51,

-    27, 36, 43, 48, 57, 68, 67, 56, 40, 51, 53, 55, 63, 56, 57, 55};

-static const unsigned char tbl057Uv[64] = {

-    13, 14, 19, 38, 80, 80, 80, 80, 14, 17, 21, 53, 80, 80, 80, 80,

-    19, 21, 45, 80, 80, 80, 80, 80, 38, 53, 80, 80, 80, 80, 80, 80,

-    80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,

-    80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80};

-

-//[043]=========================

-static const unsigned char tbl043Y[64] = {

-    11, 7,  7,  11, 17, 28, 36, 43, 8,  8,  10, 13, 18, 41, 43, 39,

-    10, 9,  11, 17, 28, 40, 49, 40, 10, 12, 15, 20, 36, 62, 57, 44,

-    12, 15, 26, 40, 48, 78, 74, 55, 17, 25, 39, 46, 58, 74, 81, 66,

-    35, 46, 56, 62, 74, 86, 86, 72, 51, 66, 68, 70, 80, 71, 74, 71};

-static const unsigned char tbl043Uv[64] = {

-    18,  19,  26,  51,  108, 108, 108, 108, 19,  22,  28,  72,  108,

-    108, 108, 108, 26,  28,  61,  108, 108, 108, 108, 108, 51,  72,

-    108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108,

-    108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108,

-    108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108};

-

-//[029]=========================

-static const unsigned char tbl029Y[64] = {

-    14, 9,  9,  14, 21, 36,  46,  55, 10, 10, 12, 17, 23,  52, 54,  49,

-    12, 11, 14, 21, 36, 51,  62,  50, 12, 15, 19, 26, 46,  78, 72,  56,

-    16, 19, 33, 50, 61, 98,  93,  69, 21, 31, 49, 58, 73,  94, 102, 83,

-    44, 58, 70, 78, 93, 109, 108, 91, 65, 83, 86, 88, 101, 90, 93,  89};

-static const unsigned char tbl029Uv[64] = {

-    22,  24,  32,  63,  133, 133, 133, 133, 24,  28,  34,  88,  133,

-    133, 133, 133, 32,  34,  75,  133, 133, 133, 133, 133, 63,  88,

-    133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133,

-    133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133,

-    133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133};

-

-//[014]=========================

-static const unsigned char tbl014Y[64] = {

-    17, 12, 10, 17, 26,  43,  55,  66,  13, 13,  15,  20,  28,  63,  65,  60,

-    15, 14, 17, 26, 43,  62,  75,  61,  15, 18,  24,  31,  55,  95,  87,  67,

-    19, 24, 40, 61, 74,  119, 112, 84,  26, 38,  60,  70,  88,  113, 123, 100,

-    53, 70, 85, 95, 112, 132, 131, 110, 78, 100, 103, 107, 122, 109, 112, 108};

-static const unsigned char tbl014Uv[64] = {

-    27,  29,  39,  76,  160, 160, 160, 160, 29,  34,  42,  107, 160,

-    160, 160, 160, 39,  42,  91,  160, 160, 160, 160, 160, 76,  107,

-    160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,

-    160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,

-    160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160};

-//[000]=========================

-static const unsigned char tbl000Y[64] = {

-    20, 13, 12, 20,  30,  50,  63,  76,  15, 15,  17,  23,  32,  72,  75,  68,

-    17, 16, 20, 30,  50,  71,  86,  70,  17, 21,  27,  36,  63,  108, 100, 77,

-    22, 27, 46, 70,  85,  136, 128, 96,  30, 43,  68,  80,  101, 130, 141, 115,

-    61, 80, 97, 108, 128, 151, 150, 126, 90, 115, 118, 122, 140, 125, 128, 123};

-static const unsigned char tbl000Uv[64] = {

-    31,  33,  45,  88,  185, 185, 185, 185, 33,  39,  48,  123, 185,

-    185, 185, 185, 45,  48,  105, 185, 185, 185, 185, 185, 88,  123,

-    185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185,

-    185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185,

-    185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185};

-

-struct HuffmanTable {

-  unsigned char length[17];  // k =1-16 ; L[k] indicates the number of Huffman

-                             // codes of length k

-  unsigned short int minorCode[17];  // indicates the value of the smallest

-                                      // Huffman code of length k

-  unsigned short int majorCode[17];  // similar, but the highest code

-  unsigned char v[65536];  // V[k][j] = Value associated to the j-th Huffman

-                           // code of length k

-                           // High nibble = nr of previous 0 coefficients

-  // Low nibble = size (in bits) of the coefficient which will be taken from the

-  // data stream

-  unsigned char len[65536];

-};

diff --git a/include/ast_jpeg_decoder.hpp b/include/ast_jpeg_decoder.hpp
deleted file mode 100644
index e8bdddb..0000000
--- a/include/ast_jpeg_decoder.hpp
+++ /dev/null
@@ -1,1547 +0,0 @@
-#pragma once
-
-#include <aspeed/JTABLES.H>
-
-#include <array>
-#include <ast_video_types.hpp>
-#include <cassert>
-#include <cstdint>
-#include <cstring>
-#include <iostream>
-#include <vector>
-
-namespace ast_video
-{
-
-struct ColorCache
-{
-    ColorCache() :
-        color{0x008080, 0xFF8080, 0x808080, 0xC08080}, index{0, 1, 2, 3}
-    {
-    }
-
-    unsigned long color[4];
-    unsigned char index[4];
-    unsigned char bitMapBits{};
-};
-
-struct RGB
-{
-    unsigned char b;
-    unsigned char g;
-    unsigned char r;
-    unsigned char reserved;
-};
-
-enum class JpgBlock
-{
-    JPEG_NO_SKIP_CODE = 0x00,
-    JPEG_SKIP_CODE = 0x08,
-
-    JPEG_PASS2_CODE = 0x02,
-    JPEG_SKIP_PASS2_CODE = 0x0A,
-
-    LOW_JPEG_NO_SKIP_CODE = 0x04,
-    LOW_JPEG_SKIP_CODE = 0x0C,
-
-    VQ_NO_SKIP_1_COLOR_CODE = 0x05,
-    VQ_SKIP_1_COLOR_CODE = 0x0D,
-
-    VQ_NO_SKIP_2_COLOR_CODE = 0x06,
-    VQ_SKIP_2_COLOR_CODE = 0x0E,
-
-    VQ_NO_SKIP_4_COLOR_CODE = 0x07,
-    VQ_SKIP_4_COLOR_CODE = 0x0F,
-
-    FRAME_END_CODE = 0x09,
-
-};
-
-class AstJpegDecoder
-{
-  public:
-    AstJpegDecoder()
-    {
-        // TODO(ed) figure out how to init this in the constructor
-        yuvBuffer.resize(1920 * 1200);
-        outBuffer.resize(1920 * 1200);
-        for (auto &r : outBuffer)
-        {
-            r.r = 0x00;
-            r.g = 0x00;
-            r.b = 0x00;
-            r.reserved = 0xAA;
-        }
-
-        int qfactor = 16;
-
-        scalefactor = qfactor;
-        scalefactoruv = qfactor;
-        advancescalefactor = 16;
-        advancescalefactoruv = 16;
-        initJpgTable();
-    }
-
-    void loadQuantTable(std::array<long, 64> &quant_table)
-    {
-        float scalefactorF[8] = {1.0f,         1.387039845f, 1.306562965f,
-                                 1.175875602f, 1.0f,         0.785694958f,
-                                 0.541196100f, 0.275899379f};
-        uint8_t j, row, col;
-        std::array<uint8_t, 64> tempQT{};
-
-        // Load quantization coefficients from JPG file, scale them for DCT and
-        // reorder
-        // from zig-zag order
-        switch (ySelector)
-        {
-            case 0:
-                stdLuminanceQt = tbl000Y;
-                break;
-            case 1:
-                stdLuminanceQt = tbl014Y;
-                break;
-            case 2:
-                stdLuminanceQt = tbl029Y;
-                break;
-            case 3:
-                stdLuminanceQt = tbl043Y;
-                break;
-            case 4:
-                stdLuminanceQt = tbl057Y;
-                break;
-            case 5:
-                stdLuminanceQt = tbl071Y;
-                break;
-            case 6:
-                stdLuminanceQt = tbl086Y;
-                break;
-            case 7:
-                stdLuminanceQt = tbl100Y;
-                break;
-        }
-        setQuantTable(stdLuminanceQt, static_cast<uint8_t>(scalefactor),
-                      tempQT);
-
-        for (j = 0; j <= 63; j++)
-        {
-            quant_table[j] = tempQT[zigzag[j]];
-        }
-        j = 0;
-        for (row = 0; row <= 7; row++)
-        {
-            for (col = 0; col <= 7; col++)
-            {
-                quant_table[j] = static_cast<long>(
-                    (quant_table[j] * scalefactorF[row] * scalefactorF[col]) *
-                    65536);
-                j++;
-            }
-        }
-        bytePos += 64;
-    }
-
-    void loadQuantTableCb(std::array<long, 64> &quant_table)
-    {
-        float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
-                                1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
-        uint8_t j, row, col;
-        std::array<uint8_t, 64> tempQT{};
-
-        // Load quantization coefficients from JPG file, scale them for DCT and
-        // reorder from zig-zag order
-        if (mapping == 0)
-        {
-            switch (uvSelector)
-            {
-                case 0:
-                    stdChrominanceQt = tbl000Y;
-                    break;
-                case 1:
-                    stdChrominanceQt = tbl014Y;
-                    break;
-                case 2:
-                    stdChrominanceQt = tbl029Y;
-                    break;
-                case 3:
-                    stdChrominanceQt = tbl043Y;
-                    break;
-                case 4:
-                    stdChrominanceQt = tbl057Y;
-                    break;
-                case 5:
-                    stdChrominanceQt = tbl071Y;
-                    break;
-                case 6:
-                    stdChrominanceQt = tbl086Y;
-                    break;
-                case 7:
-                    stdChrominanceQt = tbl100Y;
-                    break;
-            }
-        }
-        else
-        {
-            switch (uvSelector)
-            {
-                case 0:
-                    stdChrominanceQt = tbl000Uv;
-                    break;
-                case 1:
-                    stdChrominanceQt = tbl014Uv;
-                    break;
-                case 2:
-                    stdChrominanceQt = tbl029Uv;
-                    break;
-                case 3:
-                    stdChrominanceQt = tbl043Uv;
-                    break;
-                case 4:
-                    stdChrominanceQt = tbl057Uv;
-                    break;
-                case 5:
-                    stdChrominanceQt = tbl071Uv;
-                    break;
-                case 6:
-                    stdChrominanceQt = tbl086Uv;
-                    break;
-                case 7:
-                    stdChrominanceQt = tbl100Uv;
-                    break;
-            }
-        }
-        setQuantTable(stdChrominanceQt, static_cast<uint8_t>(scalefactoruv),
-                      tempQT);
-
-        for (j = 0; j <= 63; j++)
-        {
-            quant_table[j] = tempQT[zigzag[j]];
-        }
-        j = 0;
-        for (row = 0; row <= 7; row++)
-        {
-            for (col = 0; col <= 7; col++)
-            {
-                quant_table[j] = static_cast<long>(
-                    (quant_table[j] * scalefactor[row] * scalefactor[col]) *
-                    65536);
-                j++;
-            }
-        }
-        bytePos += 64;
-    }
-    //  Note: Added for Dual_JPEG
-    void loadAdvanceQuantTable(std::array<long, 64> &quant_table)
-    {
-        float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
-                                1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
-        uint8_t j, row, col;
-        std::array<uint8_t, 64> tempQT{};
-
-        // Load quantization coefficients from JPG file, scale them for DCT and
-        // reorder
-        // from zig-zag order
-        switch (advanceSelector)
-        {
-            case 0:
-                stdLuminanceQt = tbl000Y;
-                break;
-            case 1:
-                stdLuminanceQt = tbl014Y;
-                break;
-            case 2:
-                stdLuminanceQt = tbl029Y;
-                break;
-            case 3:
-                stdLuminanceQt = tbl043Y;
-                break;
-            case 4:
-                stdLuminanceQt = tbl057Y;
-                break;
-            case 5:
-                stdLuminanceQt = tbl071Y;
-                break;
-            case 6:
-                stdLuminanceQt = tbl086Y;
-                break;
-            case 7:
-                stdLuminanceQt = tbl100Y;
-                break;
-        }
-        //  Note: pass ADVANCE SCALE FACTOR to sub-function in Dual-JPEG
-        setQuantTable(stdLuminanceQt, static_cast<uint8_t>(advancescalefactor),
-                      tempQT);
-
-        for (j = 0; j <= 63; j++)
-        {
-            quant_table[j] = tempQT[zigzag[j]];
-        }
-        j = 0;
-        for (row = 0; row <= 7; row++)
-        {
-            for (col = 0; col <= 7; col++)
-            {
-                quant_table[j] = static_cast<long>(
-                    (quant_table[j] * scalefactor[row] * scalefactor[col]) *
-                    65536);
-                j++;
-            }
-        }
-        bytePos += 64;
-    }
-
-    //  Note: Added for Dual-JPEG
-    void loadAdvanceQuantTableCb(std::array<long, 64> &quant_table)
-    {
-        float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
-                                1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
-        uint8_t j, row, col;
-        std::array<uint8_t, 64> tempQT{};
-
-        // Load quantization coefficients from JPG file, scale them for DCT and
-        // reorder
-        // from zig-zag order
-        if (mapping == 1)
-        {
-            switch (advanceSelector)
-            {
-                case 0:
-                    stdChrominanceQt = tbl000Y;
-                    break;
-                case 1:
-                    stdChrominanceQt = tbl014Y;
-                    break;
-                case 2:
-                    stdChrominanceQt = tbl029Y;
-                    break;
-                case 3:
-                    stdChrominanceQt = tbl043Y;
-                    break;
-                case 4:
-                    stdChrominanceQt = tbl057Y;
-                    break;
-                case 5:
-                    stdChrominanceQt = tbl071Y;
-                    break;
-                case 6:
-                    stdChrominanceQt = tbl086Y;
-                    break;
-                case 7:
-                    stdChrominanceQt = tbl100Y;
-                    break;
-            }
-        }
-        else
-        {
-            switch (advanceSelector)
-            {
-                case 0:
-                    stdChrominanceQt = tbl000Uv;
-                    break;
-                case 1:
-                    stdChrominanceQt = tbl014Uv;
-                    break;
-                case 2:
-                    stdChrominanceQt = tbl029Uv;
-                    break;
-                case 3:
-                    stdChrominanceQt = tbl043Uv;
-                    break;
-                case 4:
-                    stdChrominanceQt = tbl057Uv;
-                    break;
-                case 5:
-                    stdChrominanceQt = tbl071Uv;
-                    break;
-                case 6:
-                    stdChrominanceQt = tbl086Uv;
-                    break;
-                case 7:
-                    stdChrominanceQt = tbl100Uv;
-                    break;
-            }
-        }
-        //  Note: pass ADVANCE SCALE FACTOR to sub-function in Dual-JPEG
-        setQuantTable(stdChrominanceQt,
-                      static_cast<uint8_t>(advancescalefactoruv), tempQT);
-
-        for (j = 0; j <= 63; j++)
-        {
-            quant_table[j] = tempQT[zigzag[j]];
-        }
-        j = 0;
-        for (row = 0; row <= 7; row++)
-        {
-            for (col = 0; col <= 7; col++)
-            {
-                quant_table[j] = static_cast<long>(
-                    (quant_table[j] * scalefactor[row] * scalefactor[col]) *
-                    65536);
-                j++;
-            }
-        }
-        bytePos += 64;
-    }
-
-    void idctTransform(short *coef, uint8_t *data, uint8_t nBlock)
-    {
-#define FIX_1_082392200 ((int)277) /* FIX(1.082392200) */
-#define FIX_1_414213562 ((int)362) /* FIX(1.414213562) */
-#define FIX_1_847759065 ((int)473) /* FIX(1.847759065) */
-#define FIX_2_613125930 ((int)669) /* FIX(2.613125930) */
-
-#define MULTIPLY(var, cons) ((int)((var) * (cons)) >> 8)
-
-        int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
-        int tmp10, tmp11, tmp12, tmp13;
-        int z5, z10, z11, z12, z13;
-        int workspace[64]; /* buffers data between passes */
-
-        short *inptr = coef;
-        long *quantptr;
-        int *wsptr = workspace;
-        unsigned char *outptr;
-        unsigned char *rLimit = rlimitTable + 128;
-        int ctr, dcval, dctsize = 8;
-
-        quantptr = &qt[nBlock][0];
-
-        // Pass 1: process columns from input (inptr), store into work
-        // array(wsptr)
-
-        for (ctr = 8; ctr > 0; ctr--)
-        {
-            /* Due to quantization, we will usually find that many of the input
-             * coefficients are zero, especially the AC terms.  We can exploit
-             * this by short-circuiting the IDCT calculation for any column in
-             * which all the AC terms are zero.  In that case each output is
-             * equal to the DC coefficient (with scale factor as needed). With
-             * typical images and quantization tables, half or more of the
-             * column DCT calculations can be simplified this way.
-             */
-
-            if ((inptr[dctsize * 1] | inptr[dctsize * 2] | inptr[dctsize * 3] |
-                 inptr[dctsize * 4] | inptr[dctsize * 5] | inptr[dctsize * 6] |
-                 inptr[dctsize * 7]) == 0)
-            {
-                /* AC terms all zero */
-                dcval = static_cast<int>(
-                    (inptr[dctsize * 0] * quantptr[dctsize * 0]) >> 16);
-
-                wsptr[dctsize * 0] = dcval;
-                wsptr[dctsize * 1] = dcval;
-                wsptr[dctsize * 2] = dcval;
-                wsptr[dctsize * 3] = dcval;
-                wsptr[dctsize * 4] = dcval;
-                wsptr[dctsize * 5] = dcval;
-                wsptr[dctsize * 6] = dcval;
-                wsptr[dctsize * 7] = dcval;
-
-                inptr++; /* advance pointers to next column */
-                quantptr++;
-                wsptr++;
-                continue;
-            }
-
-            /* Even part */
-
-            tmp0 = (inptr[dctsize * 0] * quantptr[dctsize * 0]) >> 16;
-            tmp1 = (inptr[dctsize * 2] * quantptr[dctsize * 2]) >> 16;
-            tmp2 = (inptr[dctsize * 4] * quantptr[dctsize * 4]) >> 16;
-            tmp3 = (inptr[dctsize * 6] * quantptr[dctsize * 6]) >> 16;
-
-            tmp10 = tmp0 + tmp2; /* phase 3 */
-            tmp11 = tmp0 - tmp2;
-
-            tmp13 = tmp1 + tmp3; /* phases 5-3 */
-            tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */
-
-            tmp0 = tmp10 + tmp13; /* phase 2 */
-            tmp3 = tmp10 - tmp13;
-            tmp1 = tmp11 + tmp12;
-            tmp2 = tmp11 - tmp12;
-
-            /* Odd part */
-
-            tmp4 = (inptr[dctsize * 1] * quantptr[dctsize * 1]) >> 16;
-            tmp5 = (inptr[dctsize * 3] * quantptr[dctsize * 3]) >> 16;
-            tmp6 = (inptr[dctsize * 5] * quantptr[dctsize * 5]) >> 16;
-            tmp7 = (inptr[dctsize * 7] * quantptr[dctsize * 7]) >> 16;
-
-            z13 = tmp6 + tmp5; /* phase 6 */
-            z10 = tmp6 - tmp5;
-            z11 = tmp4 + tmp7;
-            z12 = tmp4 - tmp7;
-
-            tmp7 = z11 + z13;                             /* phase 5 */
-            tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
-
-            z5 = MULTIPLY(z10 + z12, FIX_1_847759065);    /* 2*c2 */
-            tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5;  /* 2*(c2-c6) */
-            tmp12 = MULTIPLY(z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */
-
-            tmp6 = tmp12 - tmp7; /* phase 2 */
-            tmp5 = tmp11 - tmp6;
-            tmp4 = tmp10 + tmp5;
-
-            wsptr[dctsize * 0] = (tmp0 + tmp7);
-            wsptr[dctsize * 7] = (tmp0 - tmp7);
-            wsptr[dctsize * 1] = (tmp1 + tmp6);
-            wsptr[dctsize * 6] = (tmp1 - tmp6);
-            wsptr[dctsize * 2] = (tmp2 + tmp5);
-            wsptr[dctsize * 5] = (tmp2 - tmp5);
-            wsptr[dctsize * 4] = (tmp3 + tmp4);
-            wsptr[dctsize * 3] = (tmp3 - tmp4);
-
-            inptr++; /* advance pointers to next column */
-            quantptr++;
-            wsptr++;
-        }
-
-/* Pass 2: process rows from work array, store into output array. */
-/* Note that we must descale the results by a factor of 8 == 2**3, */
-/* and also undo the PASS1_BITS scaling. */
-
-//#define RANGE_MASK 1023; //2 bits wider than legal samples
-#define PASS1_BITS 0
-#define IDESCALE(x, n) ((int)((x) >> (n)))
-
-        wsptr = workspace;
-        for (ctr = 0; ctr < dctsize; ctr++)
-        {
-            outptr = data + ctr * 8;
-
-            /* Rows of zeroes can be exploited in the same way as we did with
-             * columns. However, the column calculation has created many nonzero
-             * AC terms, so the simplification applies less often (typically 5%
-             * to 10% of the time). On machines with very fast multiplication,
-             * it's possible that the test takes more time than it's worth.  In
-             * that case this section may be commented out.
-             */
-            /* Even part */
-
-            tmp10 = (wsptr[0] + wsptr[4]);
-            tmp11 = (wsptr[0] - wsptr[4]);
-
-            tmp13 = (wsptr[2] + wsptr[6]);
-            tmp12 = MULTIPLY((int)wsptr[2] - (int)wsptr[6], FIX_1_414213562) -
-                    tmp13;
-
-            tmp0 = tmp10 + tmp13;
-            tmp3 = tmp10 - tmp13;
-            tmp1 = tmp11 + tmp12;
-            tmp2 = tmp11 - tmp12;
-
-            /* Odd part */
-
-            z13 = wsptr[5] + wsptr[3];
-            z10 = wsptr[5] - wsptr[3];
-            z11 = wsptr[1] + wsptr[7];
-            z12 = wsptr[1] - wsptr[7];
-
-            tmp7 = z11 + z13;                             /* phase 5 */
-            tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
-
-            z5 = MULTIPLY(z10 + z12, FIX_1_847759065);    /* 2*c2 */
-            tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5;  /* 2*(c2-c6) */
-            tmp12 = MULTIPLY(z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */
-
-            tmp6 = tmp12 - tmp7; /* phase 2 */
-            tmp5 = tmp11 - tmp6;
-            tmp4 = tmp10 + tmp5;
-
-            /* Final output stage: scale down by a factor of 8 and range-limit
-             */
-
-            outptr[0] =
-                rLimit[IDESCALE((tmp0 + tmp7), (PASS1_BITS + 3)) & 1023L];
-            outptr[7] =
-                rLimit[IDESCALE((tmp0 - tmp7), (PASS1_BITS + 3)) & 1023L];
-            outptr[1] =
-                rLimit[IDESCALE((tmp1 + tmp6), (PASS1_BITS + 3)) & 1023L];
-            outptr[6] =
-                rLimit[IDESCALE((tmp1 - tmp6), (PASS1_BITS + 3)) & 1023L];
-            outptr[2] =
-                rLimit[IDESCALE((tmp2 + tmp5), (PASS1_BITS + 3)) & 1023L];
-            outptr[5] =
-                rLimit[IDESCALE((tmp2 - tmp5), (PASS1_BITS + 3)) & 1023L];
-            outptr[4] =
-                rLimit[IDESCALE((tmp3 + tmp4), (PASS1_BITS + 3)) & 1023L];
-            outptr[3] =
-                rLimit[IDESCALE((tmp3 - tmp4), (PASS1_BITS + 3)) & 1023L];
-
-            wsptr += dctsize; /* advance pointer to next row */
-        }
-    }
-    void yuvToRgb(
-        int txb, int tyb,
-        unsigned char
-            *pYCbCr,      // in, Y: 256 or 64 bytes; Cb: 64 bytes; Cr: 64 bytes
-        struct RGB *pYUV, // in, Y: 256 or 64 bytes; Cb: 64 bytes; Cr: 64 bytes
-        unsigned char
-            *pBgr // out, BGR format, 16*16*3 = 768 bytes; or 8*8*3=192 bytes
-    )
-    {
-        int i, j, pos, m, n;
-        unsigned char cb, cr, *py, *pcb, *pcr, *py420[4];
-        int y;
-        struct RGB *pByte;
-        int nBlocksInMcu = 6;
-        unsigned int pixelX, pixelY;
-
-        pByte = reinterpret_cast<struct RGB *>(pBgr);
-        if (yuvmode == YuvMode::YUV444)
-        {
-            py = pYCbCr;
-            pcb = pYCbCr + 64;
-            pcr = pcb + 64;
-
-            pixelX = txb * 8;
-            pixelY = tyb * 8;
-            pos = (pixelY * width) + pixelX;
-
-            for (j = 0; j < 8; j++)
-            {
-                for (i = 0; i < 8; i++)
-                {
-                    m = ((j << 3) + i);
-                    y = py[m];
-                    cb = pcb[m];
-                    cr = pcr[m];
-                    n = pos + i;
-                    // For 2Pass. Save the YUV value
-                    pYUV[n].b = cb;
-                    pYUV[n].g = y;
-                    pYUV[n].r = cr;
-                    pByte[n].b = rlimitTable[mY[y] + mCbToB[cb]];
-                    pByte[n].g = rlimitTable[mY[y] + mCbToG[cb] + mCrToG[cr]];
-                    pByte[n].r = rlimitTable[mY[y] + mCrToR[cr]];
-                }
-                pos += width;
-            }
-        }
-        else
-        {
-            for (i = 0; i < nBlocksInMcu - 2; i++)
-            {
-                py420[i] = pYCbCr + i * 64;
-            }
-            pcb = pYCbCr + (nBlocksInMcu - 2) * 64;
-            pcr = pcb + 64;
-
-            pixelX = txb * 16;
-            pixelY = tyb * 16;
-            pos = (pixelY * width) + pixelX;
-
-            for (j = 0; j < 16; j++)
-            {
-                for (i = 0; i < 16; i++)
-                {
-                    //	block number is ((j/8) * 2 + i/8)={0, 1, 2, 3}
-                    y = *(py420[(j >> 3) * 2 + (i >> 3)]++);
-                    m = ((j >> 1) << 3) + (i >> 1);
-                    cb = pcb[m];
-                    cr = pcr[m];
-                    n = pos + i;
-                    pByte[n].b = rlimitTable[mY[y] + mCbToB[cb]];
-                    pByte[n].g = rlimitTable[mY[y] + mCbToG[cb] + mCrToG[cr]];
-                    pByte[n].r = rlimitTable[mY[y] + mCrToR[cr]];
-                }
-                pos += width;
-            }
-        }
-    }
-    void yuvToBuffer(
-        int txb, int tyb,
-        unsigned char
-            *pYCbCr, // in, Y: 256 or 64 bytes; Cb: 64 bytes; Cr: 64 bytes
-        struct RGB
-            *pYUV, // out, BGR format, 16*16*3 = 768 bytes; or 8*8*3=192 bytes
-        unsigned char
-            *pBgr // out, BGR format, 16*16*3 = 768 bytes; or 8*8*3=192 bytes
-    )
-    {
-        int i, j, pos, m, n;
-        unsigned char cb, cr, *py, *pcb, *pcr, *py420[4];
-        int y;
-        struct RGB *pByte;
-        int nBlocksInMcu = 6;
-        unsigned int pixelX, pixelY;
-
-        pByte = reinterpret_cast<struct RGB *>(pBgr);
-        if (yuvmode == YuvMode::YUV444)
-        {
-            py = pYCbCr;
-            pcb = pYCbCr + 64;
-            pcr = pcb + 64;
-
-            pixelX = txb * 8;
-            pixelY = tyb * 8;
-            pos = (pixelY * width) + pixelX;
-
-            for (j = 0; j < 8; j++)
-            {
-                for (i = 0; i < 8; i++)
-                {
-                    m = ((j << 3) + i);
-                    n = pos + i;
-                    y = pYUV[n].g + (py[m] - 128);
-                    cb = pYUV[n].b + (pcb[m] - 128);
-                    cr = pYUV[n].r + (pcr[m] - 128);
-                    pYUV[n].b = cb;
-                    pYUV[n].g = y;
-                    pYUV[n].r = cr;
-                    pByte[n].b = rlimitTable[mY[y] + mCbToB[cb]];
-                    pByte[n].g = rlimitTable[mY[y] + mCbToG[cb] + mCrToG[cr]];
-                    pByte[n].r = rlimitTable[mY[y] + mCrToR[cr]];
-                }
-                pos += width;
-            }
-        }
-        else
-        {
-            for (i = 0; i < nBlocksInMcu - 2; i++)
-            {
-                py420[i] = pYCbCr + i * 64;
-            }
-            pcb = pYCbCr + (nBlocksInMcu - 2) * 64;
-            pcr = pcb + 64;
-
-            pixelX = txb * 16;
-            pixelY = tyb * 16;
-            pos = (pixelY * width) + pixelX;
-
-            for (j = 0; j < 16; j++)
-            {
-                for (i = 0; i < 16; i++)
-                {
-                    //	block number is ((j/8) * 2 + i/8)={0, 1, 2, 3}
-                    y = *(py420[(j >> 3) * 2 + (i >> 3)]++);
-                    m = ((j >> 1) << 3) + (i >> 1);
-                    cb = pcb[m];
-                    cr = pcr[m];
-                    n = pos + i;
-                    pByte[n].b = rlimitTable[mY[y] + mCbToB[cb]];
-                    pByte[n].g = rlimitTable[mY[y] + mCbToG[cb] + mCrToG[cr]];
-                    pByte[n].r = rlimitTable[mY[y] + mCrToR[cr]];
-                }
-                pos += width;
-            }
-        }
-    }
-    void decompress(int txb, int tyb, char *outBuf, uint8_t QT_TableSelection)
-    {
-        unsigned char *ptr;
-        unsigned char byTileYuv[768] = {};
-
-        memset(dctCoeff, 0, 384 * 2);
-        ptr = byTileYuv;
-        processHuffmanDataUnit(ydcNr, yacNr, &dcy, 0);
-        idctTransform(dctCoeff, ptr, QT_TableSelection);
-        ptr += 64;
-
-        if (yuvmode == YuvMode::YUV420)
-        {
-            processHuffmanDataUnit(ydcNr, yacNr, &dcy, 64);
-            idctTransform(dctCoeff + 64, ptr, QT_TableSelection);
-            ptr += 64;
-
-            processHuffmanDataUnit(ydcNr, yacNr, &dcy, 128);
-            idctTransform(dctCoeff + 128, ptr, QT_TableSelection);
-            ptr += 64;
-
-            processHuffmanDataUnit(ydcNr, yacNr, &dcy, 192);
-            idctTransform(dctCoeff + 192, ptr, QT_TableSelection);
-            ptr += 64;
-
-            processHuffmanDataUnit(cbDcNr, cbAcNr, &dcCb, 256);
-            idctTransform(dctCoeff + 256, ptr, QT_TableSelection + 1);
-            ptr += 64;
-
-            processHuffmanDataUnit(crDcNr, crAcNr, &dcCr, 320);
-            idctTransform(dctCoeff + 320, ptr, QT_TableSelection + 1);
-        }
-        else
-        {
-            processHuffmanDataUnit(cbDcNr, cbAcNr, &dcCb, 64);
-            idctTransform(dctCoeff + 64, ptr, QT_TableSelection + 1);
-            ptr += 64;
-
-            processHuffmanDataUnit(crDcNr, crAcNr, &dcCr, 128);
-            idctTransform(dctCoeff + 128, ptr, QT_TableSelection + 1);
-        }
-
-        //    yuvToRgb (txb, tyb, byTileYuv, (unsigned char *)outBuf);
-        //  yuvBuffer for YUV record
-        yuvToRgb(txb, tyb, byTileYuv, yuvBuffer.data(),
-                 reinterpret_cast<unsigned char *>(outBuf));
-    }
-
-    void decompress2Pass(int txb, int tyb, char *outBuf,
-                         uint8_t QT_TableSelection)
-    {
-        unsigned char *ptr;
-        unsigned char byTileYuv[768];
-        memset(dctCoeff, 0, 384 * 2);
-
-        ptr = byTileYuv;
-        processHuffmanDataUnit(ydcNr, yacNr, &dcy, 0);
-        idctTransform(dctCoeff, ptr, QT_TableSelection);
-        ptr += 64;
-
-        processHuffmanDataUnit(cbDcNr, cbAcNr, &dcCb, 64);
-        idctTransform(dctCoeff + 64, ptr, QT_TableSelection + 1);
-        ptr += 64;
-
-        processHuffmanDataUnit(crDcNr, crAcNr, &dcCr, 128);
-        idctTransform(dctCoeff + 128, ptr, QT_TableSelection + 1);
-
-        yuvToBuffer(txb, tyb, byTileYuv, yuvBuffer.data(),
-                    reinterpret_cast<unsigned char *>(outBuf));
-        //    yuvToRgb (txb, tyb, byTileYuv, (unsigned char *)outBuf);
-    }
-
-    void vqDecompress(int txb, int tyb, char *outBuf, uint8_t QT_TableSelection,
-                      struct ColorCache *VQ)
-    {
-        unsigned char *ptr, i;
-        unsigned char byTileYuv[192];
-        int data;
-
-        ptr = byTileYuv;
-        if (VQ->bitMapBits == 0)
-        {
-            for (i = 0; i < 64; i++)
-            {
-                ptr[0] = (VQ->color[VQ->index[0]] & 0xFF0000) >> 16;
-                ptr[64] = (VQ->color[VQ->index[0]] & 0x00FF00) >> 8;
-                ptr[128] = VQ->color[VQ->index[0]] & 0x0000FF;
-                ptr += 1;
-            }
-        }
-        else
-        {
-            for (i = 0; i < 64; i++)
-            {
-                data = static_cast<int>(lookKbits(VQ->bitMapBits));
-                ptr[0] = (VQ->color[VQ->index[data]] & 0xFF0000) >> 16;
-                ptr[64] = (VQ->color[VQ->index[data]] & 0x00FF00) >> 8;
-                ptr[128] = VQ->color[VQ->index[data]] & 0x0000FF;
-                ptr += 1;
-                skipKbits(VQ->bitMapBits);
-            }
-        }
-        //    yuvToRgb (txb, tyb, byTileYuv, (unsigned char *)outBuf);
-        yuvToRgb(txb, tyb, byTileYuv, yuvBuffer.data(),
-                 reinterpret_cast<unsigned char *>(outBuf));
-    }
-
-    void moveBlockIndex()
-    {
-        if (yuvmode == YuvMode::YUV444)
-        {
-            txb++;
-            if (txb >= static_cast<int>(width / 8))
-            {
-                tyb++;
-                if (tyb >= static_cast<int>(height / 8))
-                {
-                    tyb = 0;
-                }
-                txb = 0;
-            }
-        }
-        else
-        {
-            txb++;
-            if (txb >= static_cast<int>(width / 16))
-            {
-                tyb++;
-                if (tyb >= static_cast<int>(height / 16))
-                {
-                    tyb = 0;
-                }
-                txb = 0;
-            }
-        }
-    }
-
-    void initColorTable()
-    {
-        int i, x;
-        int nScale = 1L << 16; // equal to power(2,16)
-        int nHalf = nScale >> 1;
-
-#define FIX(x) ((int)((x)*nScale + 0.5))
-
-        /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
-        /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
-        /* Cr=>r value is nearest int to 1.597656 * x */
-        /* Cb=>b value is nearest int to 2.015625 * x */
-        /* Cr=>g value is scaled-up -0.8125 * x */
-        /* Cb=>g value is scaled-up -0.390625 * x */
-        for (i = 0, x = -128; i < 256; i++, x++)
-        {
-            mCrToR[i] = (FIX(1.597656) * x + nHalf) >> 16;
-            mCbToB[i] = (FIX(2.015625) * x + nHalf) >> 16;
-            mCrToG[i] = (-FIX(0.8125) * x + nHalf) >> 16;
-            mCbToG[i] = (-FIX(0.390625) * x + nHalf) >> 16;
-        }
-        for (i = 0, x = -16; i < 256; i++, x++)
-        {
-            mY[i] = (FIX(1.164) * x + nHalf) >> 16;
-        }
-        // For color Text Enchance Y Re-map. Recommend to disable in default
-        /*
-                for (i = 0; i <
-           (VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate); i++) { temp =
-           (double)i / VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate; temp1
-           = 1.0 / VideoEngineInfo->INFData.Gamma1Parameter; mY[i] =
-           (BYTE)(VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate * pow (temp,
-           temp1));
-                        if (mY[i] > 255) mY[i] = 255;
-                }
-                for (i = (VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate); i <
-           256; i++) { mY[i] =
-           (BYTE)((VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate) + (256 -
-           VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate) * ( pow((double)((i
-           - VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate) / (256 -
-           (VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate))), (1.0 /
-           VideoEngineInfo->INFData.Gamma2Parameter)) ));
-                        if (mY[i] > 255) mY[i] = 255;
-                }
-        */
-    }
-    void loadHuffmanTable(HuffmanTable *HT, const unsigned char *nrcode,
-                          const unsigned char *value,
-                          const unsigned short int *Huff_code)
-    {
-        unsigned char k, j, i;
-        unsigned int code, codeIndex;
-
-        for (j = 1; j <= 16; j++)
-        {
-            HT->length[j] = nrcode[j];
-        }
-        for (i = 0, k = 1; k <= 16; k++)
-        {
-            for (j = 0; j < HT->length[k]; j++)
-            {
-                HT->v[wordHiLo(k, j)] = value[i];
-                i++;
-            }
-        }
-
-        code = 0;
-        for (k = 1; k <= 16; k++)
-        {
-            HT->minorCode[k] = static_cast<unsigned short int>(code);
-            for (j = 1; j <= HT->length[k]; j++)
-            {
-                code++;
-            }
-            HT->majorCode[k] = static_cast<unsigned short int>(code - 1);
-            code *= 2;
-            if (HT->length[k] == 0)
-            {
-                HT->minorCode[k] = 0xFFFF;
-                HT->majorCode[k] = 0;
-            }
-        }
-
-        HT->len[0] = 2;
-        i = 2;
-
-        for (codeIndex = 1; codeIndex < 65535; codeIndex++)
-        {
-            if (codeIndex < Huff_code[i])
-            {
-                HT->len[codeIndex] =
-                    static_cast<unsigned char>(Huff_code[i + 1]);
-            }
-            else
-            {
-                i = i + 2;
-                HT->len[codeIndex] =
-                    static_cast<unsigned char>(Huff_code[i + 1]);
-            }
-        }
-    }
-    void initJpgTable()
-    {
-        initColorTable();
-        prepareRangeLimitTable();
-        loadHuffmanTable(&htdc[0], stdDcLuminanceNrcodes, stdDcLuminanceValues,
-                         dcLuminanceHuffmancode);
-        loadHuffmanTable(&htac[0], stdAcLuminanceNrcodes, stdAcLuminanceValues,
-                         acLuminanceHuffmancode);
-        loadHuffmanTable(&htdc[1], stdDcChrominanceNrcodes,
-                         stdDcChrominanceValues, dcChrominanceHuffmancode);
-        loadHuffmanTable(&htac[1], stdAcChrominanceNrcodes,
-                         stdAcChrominanceValues, acChrominanceHuffmancode);
-    }
-
-    void prepareRangeLimitTable()
-    /* Allocate and fill in the sample_range_limit table */
-    {
-        int j;
-        rlimitTable = reinterpret_cast<unsigned char *>(malloc(5 * 256L + 128));
-        /* First segment of "simple" table: limit[x] = 0 for x < 0 */
-        memset((void *)rlimitTable, 0, 256);
-        rlimitTable += 256; /* allow negative subscripts of simple table */
-        /* Main part of "simple" table: limit[x] = x */
-        for (j = 0; j < 256; j++)
-        {
-            rlimitTable[j] = j;
-        }
-        /* End of simple table, rest of first half of post-IDCT table */
-        for (j = 256; j < 640; j++)
-        {
-            rlimitTable[j] = 255;
-        }
-
-        /* Second half of post-IDCT table */
-        memset((void *)(rlimitTable + 640), 0, 384);
-        for (j = 0; j < 128; j++)
-        {
-            rlimitTable[j + 1024] = j;
-        }
-    }
-
-    inline unsigned short int wordHiLo(uint8_t byte_high, uint8_t byte_low)
-    {
-        return (byte_high << 8) + byte_low;
-    }
-
-    // river
-    void processHuffmanDataUnit(uint8_t DC_nr, uint8_t AC_nr,
-                                signed short int *previous_DC,
-                                unsigned short int position)
-    {
-        uint8_t nr = 0;
-        uint8_t k;
-        unsigned short int tmpHcode;
-        uint8_t sizeVal, count0;
-        unsigned short int *minCode;
-        uint8_t *huffValues;
-        uint8_t byteTemp;
-
-        minCode = htdc[DC_nr].minorCode;
-        //   maj_code=htdc[DC_nr].majorCode;
-        huffValues = htdc[DC_nr].v;
-
-        // DC
-        k = htdc[DC_nr].len[static_cast<unsigned short int>(codebuf >> 16)];
-        // river
-        //	 tmp_Hcode=lookKbits(k);
-        tmpHcode = static_cast<unsigned short int>(codebuf >> (32 - k));
-        skipKbits(k);
-        sizeVal = huffValues[wordHiLo(
-            k, static_cast<uint8_t>(tmpHcode - minCode[k]))];
-        if (sizeVal == 0)
-        {
-            dctCoeff[position + 0] = *previous_DC;
-        }
-        else
-        {
-            dctCoeff[position + 0] = *previous_DC + getKbits(sizeVal);
-            *previous_DC = dctCoeff[position + 0];
-        }
-
-        // Second, AC coefficient decoding
-        minCode = htac[AC_nr].minorCode;
-        //   maj_code=htac[AC_nr].majorCode;
-        huffValues = htac[AC_nr].v;
-
-        nr = 1; // AC coefficient
-        do
-        {
-            k = htac[AC_nr].len[static_cast<unsigned short int>(codebuf >> 16)];
-            tmpHcode = static_cast<unsigned short int>(codebuf >> (32 - k));
-            skipKbits(k);
-
-            byteTemp = huffValues[wordHiLo(
-                k, static_cast<uint8_t>(tmpHcode - minCode[k]))];
-            sizeVal = byteTemp & 0xF;
-            count0 = byteTemp >> 4;
-            if (sizeVal == 0)
-            {
-                if (count0 != 0xF)
-                {
-                    break;
-                }
-                nr += 16;
-            }
-            else
-            {
-                nr += count0; // skip count_0 zeroes
-                dctCoeff[position + dezigzag[nr++]] = getKbits(sizeVal);
-            }
-        } while (nr < 64);
-    }
-
-    unsigned short int lookKbits(uint8_t k)
-    {
-        unsigned short int revcode;
-
-        revcode = static_cast<unsigned short int>(codebuf >> (32 - k));
-
-        return (revcode);
-    }
-
-    void skipKbits(uint8_t k)
-    {
-        unsigned long readbuf;
-
-        if ((newbits - k) <= 0)
-        {
-            readbuf = buffer[bufferIndex];
-            bufferIndex++;
-            codebuf = (codebuf << k) |
-                      ((newbuf | (readbuf >> (newbits))) >> (32 - k));
-            newbuf = readbuf << (k - newbits);
-            newbits = 32 + newbits - k;
-        }
-        else
-        {
-            codebuf = (codebuf << k) | (newbuf >> (32 - k));
-            newbuf = newbuf << k;
-            newbits -= k;
-        }
-    }
-
-    signed short int getKbits(uint8_t k)
-    {
-        signed short int signedWordvalue;
-
-        // river
-        // signed_wordvalue=lookKbits(k);
-        signedWordvalue = static_cast<unsigned short int>(codebuf >> (32 - k));
-        if (((1L << (k - 1)) & signedWordvalue) == 0)
-        {
-            // neg_pow2 was previously defined as the below.  It seemed silly to
-            // keep a table of values around for something THat's relatively
-            // easy to compute, so it was replaced with the appropriate math
-            // signed_wordvalue = signed_wordvalue - (0xFFFF >> (16 - k));
-            std::array<signed short int, 17> negPow2 = {
-                0,    -1,   -3,    -7,    -15,   -31,   -63,    -127,
-                -255, -511, -1023, -2047, -4095, -8191, -16383, -32767};
-
-            signedWordvalue = signedWordvalue + negPow2[k];
-        }
-        skipKbits(k);
-        return signedWordvalue;
-    }
-    int initJpgDecoding()
-    {
-        bytePos = 0;
-        loadQuantTable(qt[0]);
-        loadQuantTableCb(qt[1]);
-        //  Note: Added for Dual-JPEG
-        loadAdvanceQuantTable(qt[2]);
-        loadAdvanceQuantTableCb(qt[3]);
-        return 1;
-    }
-
-    void setQuantTable(const uint8_t *basic_table, uint8_t scale_factor,
-                       std::array<uint8_t, 64> &newtable)
-    // Set quantization table and zigzag reorder it
-    {
-        uint8_t i;
-        long temp;
-        for (i = 0; i < 64; i++)
-        {
-            temp = (static_cast<long>(basic_table[i] * 16) / scale_factor);
-            /* limit the values to the valid range */
-            if (temp <= 0L)
-            {
-                temp = 1L;
-            }
-            if (temp > 255L)
-            {
-                temp = 255L; /* limit to baseline range if requested */
-            }
-            newtable[zigzag[i]] = static_cast<uint8_t>(temp);
-        }
-    }
-
-    void updatereadbuf(uint32_t *codebuf, uint32_t *newbuf, int walks,
-                       int *newbits, std::vector<uint32_t> &buffer)
-    {
-        unsigned long readbuf;
-
-        if ((*newbits - walks) <= 0)
-        {
-            readbuf = buffer[bufferIndex];
-            bufferIndex++;
-            *codebuf = (*codebuf << walks) |
-                       ((*newbuf | (readbuf >> (*newbits))) >> (32 - walks));
-            *newbuf = readbuf << (walks - *newbits);
-            *newbits = 32 + *newbits - walks;
-        }
-        else
-        {
-            *codebuf = (*codebuf << walks) | (*newbuf >> (32 - walks));
-            *newbuf = *newbuf << walks;
-            *newbits -= walks;
-        }
-    }
-
-    uint32_t decode(std::vector<uint32_t> &bufferVector, unsigned long width,
-                    unsigned long height, YuvMode yuvmode_in, int ySelector,
-                    int uvSelector)
-    {
-        ColorCache decodeColor;
-        if (width != userWidth || height != userHeight ||
-            yuvmode_in != yuvmode || ySelector != ySelector ||
-            uvSelector != uvSelector)
-        {
-            yuvmode = yuvmode_in;
-            ySelector = ySelector;   // 0-7
-            uvSelector = uvSelector; // 0-7
-            userHeight = height;
-            userWidth = width;
-            width = width;
-            height = height;
-
-            // TODO(ed) Magic number section.  Document appropriately
-            advanceSelector = 0; // 0-7
-            mapping = 0;         // 0 or 1
-
-            if (yuvmode == YuvMode::YUV420)
-            {
-                if ((width % 16) != 0u)
-                {
-                    width = width + 16 - (width % 16);
-                }
-                if ((height % 16) != 0u)
-                {
-                    height = height + 16 - (height % 16);
-                }
-            }
-            else
-            {
-                if ((width % 8) != 0u)
-                {
-                    width = width + 8 - (width % 8);
-                }
-                if ((height % 8) != 0u)
-                {
-                    height = height + 8 - (height % 8);
-                }
-            }
-
-            initJpgDecoding();
-        }
-        // TODO(ed) cleanup cruft
-        buffer = bufferVector.data();
-
-        codebuf = bufferVector[0];
-        newbuf = bufferVector[1];
-        bufferIndex = 2;
-
-        txb = tyb = 0;
-        newbits = 32;
-        dcy = dcCb = dcCr = 0;
-
-        static const uint32_t vqHeaderMask = 0x01;
-        static const uint32_t vqNoUpdateHeader = 0x00;
-        static const uint32_t vqUpdateHeader = 0x01;
-        static const int vqNoUpdateLength = 0x03;
-        static const int vqUpdateLength = 0x1B;
-        static const uint32_t vqIndexMask = 0x03;
-        static const uint32_t vqColorMask = 0xFFFFFF;
-
-        static const int blockAsT2100StartLength = 0x04;
-        static const int blockAsT2100SkipLength = 20; // S:1 H:3 X:8 Y:8
-
-        do
-        {
-            auto blockHeader = static_cast<JpgBlock>((codebuf >> 28) & 0xFF);
-            switch (blockHeader)
-            {
-                case JpgBlock::JPEG_NO_SKIP_CODE:
-                    updatereadbuf(&codebuf, &newbuf, blockAsT2100StartLength,
-                                  &newbits, bufferVector);
-                    decompress(txb, tyb,
-                               reinterpret_cast<char *>(outBuffer.data()), 0);
-                    break;
-                case JpgBlock::FRAME_END_CODE:
-                    return 0;
-                    break;
-                case JpgBlock::JPEG_SKIP_CODE:
-
-                    txb = (codebuf & 0x0FF00000) >> 20;
-                    tyb = (codebuf & 0x0FF000) >> 12;
-
-                    updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength,
-                                  &newbits, bufferVector);
-                    decompress(txb, tyb,
-                               reinterpret_cast<char *>(outBuffer.data()), 0);
-                    break;
-                case JpgBlock::VQ_NO_SKIP_1_COLOR_CODE:
-                    updatereadbuf(&codebuf, &newbuf, blockAsT2100StartLength,
-                                  &newbits, bufferVector);
-                    decodeColor.bitMapBits = 0;
-
-                    for (int i = 0; i < 1; i++)
-                    {
-                        decodeColor.index[i] = ((codebuf >> 29) & vqIndexMask);
-                        if (((codebuf >> 31) & vqHeaderMask) ==
-                            vqNoUpdateHeader)
-                        {
-                            updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength,
-                                          &newbits, bufferVector);
-                        }
-                        else
-                        {
-                            decodeColor.color[decodeColor.index[i]] =
-                                ((codebuf >> 5) & vqColorMask);
-                            updatereadbuf(&codebuf, &newbuf, vqUpdateLength,
-                                          &newbits, bufferVector);
-                        }
-                    }
-                    vqDecompress(txb, tyb,
-                                 reinterpret_cast<char *>(outBuffer.data()), 0,
-                                 &decodeColor);
-                    break;
-                case JpgBlock::VQ_SKIP_1_COLOR_CODE:
-                    txb = (codebuf & 0x0FF00000) >> 20;
-                    tyb = (codebuf & 0x0FF000) >> 12;
-
-                    updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength,
-                                  &newbits, bufferVector);
-                    decodeColor.bitMapBits = 0;
-
-                    for (int i = 0; i < 1; i++)
-                    {
-                        decodeColor.index[i] = ((codebuf >> 29) & vqIndexMask);
-                        if (((codebuf >> 31) & vqHeaderMask) ==
-                            vqNoUpdateHeader)
-                        {
-                            updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength,
-                                          &newbits, bufferVector);
-                        }
-                        else
-                        {
-                            decodeColor.color[decodeColor.index[i]] =
-                                ((codebuf >> 5) & vqColorMask);
-                            updatereadbuf(&codebuf, &newbuf, vqUpdateLength,
-                                          &newbits, bufferVector);
-                        }
-                    }
-                    vqDecompress(txb, tyb,
-                                 reinterpret_cast<char *>(outBuffer.data()), 0,
-                                 &decodeColor);
-                    break;
-
-                case JpgBlock::VQ_NO_SKIP_2_COLOR_CODE:
-                    updatereadbuf(&codebuf, &newbuf, blockAsT2100StartLength,
-                                  &newbits, bufferVector);
-                    decodeColor.bitMapBits = 1;
-
-                    for (int i = 0; i < 2; i++)
-                    {
-                        decodeColor.index[i] = ((codebuf >> 29) & vqIndexMask);
-                        if (((codebuf >> 31) & vqHeaderMask) ==
-                            vqNoUpdateHeader)
-                        {
-                            updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength,
-                                          &newbits, bufferVector);
-                        }
-                        else
-                        {
-                            decodeColor.color[decodeColor.index[i]] =
-                                ((codebuf >> 5) & vqColorMask);
-                            updatereadbuf(&codebuf, &newbuf, vqUpdateLength,
-                                          &newbits, bufferVector);
-                        }
-                    }
-                    vqDecompress(txb, tyb,
-                                 reinterpret_cast<char *>(outBuffer.data()), 0,
-                                 &decodeColor);
-                    break;
-                case JpgBlock::VQ_SKIP_2_COLOR_CODE:
-                    txb = (codebuf & 0x0FF00000) >> 20;
-                    tyb = (codebuf & 0x0FF000) >> 12;
-
-                    updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength,
-                                  &newbits, bufferVector);
-                    decodeColor.bitMapBits = 1;
-
-                    for (int i = 0; i < 2; i++)
-                    {
-                        decodeColor.index[i] = ((codebuf >> 29) & vqIndexMask);
-                        if (((codebuf >> 31) & vqHeaderMask) ==
-                            vqNoUpdateHeader)
-                        {
-                            updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength,
-                                          &newbits, bufferVector);
-                        }
-                        else
-                        {
-                            decodeColor.color[decodeColor.index[i]] =
-                                ((codebuf >> 5) & vqColorMask);
-                            updatereadbuf(&codebuf, &newbuf, vqUpdateLength,
-                                          &newbits, bufferVector);
-                        }
-                    }
-                    vqDecompress(txb, tyb,
-                                 reinterpret_cast<char *>(outBuffer.data()), 0,
-                                 &decodeColor);
-
-                    break;
-                case JpgBlock::VQ_NO_SKIP_4_COLOR_CODE:
-                    updatereadbuf(&codebuf, &newbuf, blockAsT2100StartLength,
-                                  &newbits, bufferVector);
-                    decodeColor.bitMapBits = 2;
-
-                    for (unsigned char &i : decodeColor.index)
-                    {
-                        i = ((codebuf >> 29) & vqIndexMask);
-                        if (((codebuf >> 31) & vqHeaderMask) ==
-                            vqNoUpdateHeader)
-                        {
-                            updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength,
-                                          &newbits, bufferVector);
-                        }
-                        else
-                        {
-                            decodeColor.color[i] =
-                                ((codebuf >> 5) & vqColorMask);
-                            updatereadbuf(&codebuf, &newbuf, vqUpdateLength,
-                                          &newbits, bufferVector);
-                        }
-                    }
-                    vqDecompress(txb, tyb,
-                                 reinterpret_cast<char *>(outBuffer.data()), 0,
-                                 &decodeColor);
-
-                    break;
-
-                case JpgBlock::VQ_SKIP_4_COLOR_CODE:
-                    txb = (codebuf & 0x0FF00000) >> 20;
-                    tyb = (codebuf & 0x0FF000) >> 12;
-
-                    updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength,
-                                  &newbits, bufferVector);
-                    decodeColor.bitMapBits = 2;
-
-                    for (unsigned char &i : decodeColor.index)
-                    {
-                        i = ((codebuf >> 29) & vqIndexMask);
-                        if (((codebuf >> 31) & vqHeaderMask) ==
-                            vqNoUpdateHeader)
-                        {
-                            updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength,
-                                          &newbits, bufferVector);
-                        }
-                        else
-                        {
-                            decodeColor.color[i] =
-                                ((codebuf >> 5) & vqColorMask);
-                            updatereadbuf(&codebuf, &newbuf, vqUpdateLength,
-                                          &newbits, bufferVector);
-                        }
-                    }
-                    vqDecompress(txb, tyb,
-                                 reinterpret_cast<char *>(outBuffer.data()), 0,
-                                 &decodeColor);
-
-                    break;
-                case JpgBlock::JPEG_SKIP_PASS2_CODE:
-                    txb = (codebuf & 0x0FF00000) >> 20;
-                    tyb = (codebuf & 0x0FF000) >> 12;
-
-                    updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength,
-                                  &newbits, bufferVector);
-                    decompress2Pass(txb, tyb,
-                                    reinterpret_cast<char *>(outBuffer.data()),
-                                    2);
-
-                    break;
-                default:
-                    // TODO(ed) propogate errors upstream
-                    return -1;
-                    break;
-            }
-            moveBlockIndex();
-
-        } while (bufferIndex <= bufferVector.size());
-
-        return -1;
-    }
-
-#ifdef cimg_version
-    void dump_to_bitmap_file()
-    {
-        cimg_library::CImg<unsigned char> image(width, height, 1, 3);
-        for (int y = 0; y < width; y++)
-        {
-            for (int x = 0; x < height; x++)
-            {
-                auto pixel = outBuffer[x + (y * width)];
-                image(x, y, 0) = pixel.r;
-                image(x, y, 1) = pixel.g;
-                image(x, y, 2) = pixel.b;
-            }
-        }
-        image.save("/tmp/file2.bmp");
-    }
-#endif
-
-  private:
-    YuvMode yuvmode{};
-    // width and height are the modes your display used
-    unsigned long width{};
-    unsigned long height{};
-    unsigned long userWidth{};
-    unsigned long userHeight{};
-    unsigned char ySelector{};
-    int scalefactor;
-    int scalefactoruv;
-    int advancescalefactor;
-    int advancescalefactoruv;
-    int mapping{};
-    unsigned char uvSelector{};
-    unsigned char advanceSelector{};
-    int bytePos{}; // current byte position
-
-    // quantization tables, no more than 4 quantization tables
-    std::array<std::array<long, 64>, 4> qt{};
-
-    // DC huffman tables , no more than 4 (0..3)
-    std::array<HuffmanTable, 4> htdc{};
-    // AC huffman tables (0..3)
-    std::array<HuffmanTable, 4> htac{};
-    std::array<int, 256> mCrToR{};
-    std::array<int, 256> mCbToB{};
-    std::array<int, 256> mCrToG{};
-    std::array<int, 256> mCbToG{};
-    std::array<int, 256> mY{};
-    unsigned long bufferIndex{};
-    uint32_t codebuf{}, newbuf{}, readbuf{};
-    const unsigned char *stdLuminanceQt{};
-    const uint8_t *stdChrominanceQt{};
-
-    signed short int dcy{}, dcCb{}, dcCr{}; // Coeficientii DC pentru Y,Cb,Cr
-    signed short int dctCoeff[384]{};
-    // std::vector<signed short int> dctCoeff;  // Current DCT_coefficients
-    // quantization table number for Y, Cb, Cr
-    uint8_t yqNr = 0, cbQNr = 1, crQNr = 1;
-    // DC Huffman table number for Y,Cb, Cr
-    uint8_t ydcNr = 0, cbDcNr = 1, crDcNr = 1;
-    // AC Huffman table number for Y,Cb, Cr
-    uint8_t yacNr = 0, cbAcNr = 1, crAcNr = 1;
-    int txb = 0;
-    int tyb = 0;
-    int newbits{};
-    uint8_t *rlimitTable{};
-    std::vector<RGB> yuvBuffer;
-    // TODO(ed) this shouldn't exist.  It is cruft that needs cleaning up
-    uint32_t *buffer{};
-
-  public:
-    std::vector<RGB> outBuffer;
-};
-} // namespace ast_video
\ No newline at end of file
diff --git a/include/kvm_websocket.hpp b/include/kvm_websocket.hpp
new file mode 100644
index 0000000..aa2eaec
--- /dev/null
+++ b/include/kvm_websocket.hpp
@@ -0,0 +1,173 @@
+#pragma once
+#include <crow/app.h>
+#include <crow/websocket.h>
+#include <sys/socket.h>
+
+#include <boost/container/flat_map.hpp>
+#include <boost/container/flat_set.hpp>
+#include <webserver_common.hpp>
+
+namespace crow
+{
+namespace obmc_kvm
+{
+
+static std::unique_ptr<boost::asio::ip::tcp::socket> hostSocket;
+
+// TODO(ed) validate that these buffer sizes are sane
+static boost::beast::flat_static_buffer<1024U * 50U> outputBuffer;
+static boost::beast::flat_static_buffer<1024U> inputBuffer;
+
+static crow::websocket::Connection* session = nullptr;
+
+static bool doingWrite = false;
+
+inline void doWrite()
+{
+    if (doingWrite)
+    {
+        BMCWEB_LOG_DEBUG << "Already writing.  Bailing out";
+        return;
+    }
+    if (inputBuffer.size() == 0)
+    {
+        BMCWEB_LOG_DEBUG << "inputBuffer empty.  Bailing out";
+        return;
+    }
+
+    doingWrite = true;
+    hostSocket->async_write_some(
+        inputBuffer.data(),
+        [](boost::beast::error_code ec, std::size_t bytes_written) {
+            BMCWEB_LOG_DEBUG << "Wrote " << bytes_written << "bytes";
+            doingWrite = false;
+            inputBuffer.consume(bytes_written);
+
+            if (session == nullptr)
+            {
+                return;
+            }
+            if (ec == boost::asio::error::eof)
+            {
+                session->close("KVM socket port closed");
+                return;
+            }
+            if (ec)
+            {
+                session->close("Error in reading to host port");
+                BMCWEB_LOG_ERROR << "Error in KVM socket write " << ec;
+                return;
+            }
+            doWrite();
+        });
+}
+
+inline void doRead();
+
+inline void readDone(const boost::system::error_code& ec, std::size_t bytesRead)
+{
+    outputBuffer.commit(bytesRead);
+    BMCWEB_LOG_DEBUG << "read done.  Read " << bytesRead << " bytes";
+    if (ec)
+    {
+        BMCWEB_LOG_ERROR << "Couldn't read from KVM socket port: " << ec;
+        if (session != nullptr)
+        {
+            session->close("Error in connecting to KVM port");
+        }
+        return;
+    }
+    if (session == nullptr)
+    {
+        return;
+    }
+
+    boost::beast::string_view payload(
+        static_cast<const char*>(outputBuffer.data().data()), bytesRead);
+    BMCWEB_LOG_DEBUG << "Sending payload size " << payload.size();
+    session->sendBinary(payload);
+    outputBuffer.consume(bytesRead);
+
+    doRead();
+}
+
+inline void doRead()
+{
+    std::size_t bytes = outputBuffer.capacity() - outputBuffer.size();
+    BMCWEB_LOG_DEBUG << "Reading " << bytes << " from kvm socket";
+    hostSocket->async_read_some(
+        outputBuffer.prepare(outputBuffer.capacity() - outputBuffer.size()),
+        readDone);
+}
+
+inline void connectHandler(const boost::system::error_code& ec)
+{
+    if (ec)
+    {
+        BMCWEB_LOG_ERROR << "Couldn't connect to KVM socket port: " << ec;
+        if (session != nullptr)
+        {
+            session->close("Error in connecting to KVM port");
+        }
+        return;
+    }
+
+    doWrite();
+    doRead();
+}
+
+inline void requestRoutes(CrowApp& app)
+{
+    BMCWEB_ROUTE(app, "/kvm/0")
+        .websocket()
+        .onopen([](crow::websocket::Connection& conn) {
+            BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
+
+            if (session != nullptr)
+            {
+                conn.close("User already connected");
+                return;
+            }
+
+            session = &conn;
+            if (hostSocket == nullptr)
+            {
+                boost::asio::ip::tcp::endpoint endpoint(
+                    boost::asio::ip::address::from_string("127.0.0.1"), 5900);
+
+                hostSocket = std::make_unique<boost::asio::ip::tcp::socket>(
+                    conn.get_io_context());
+                hostSocket->async_connect(endpoint, connectHandler);
+            }
+        })
+        .onclose(
+            [](crow::websocket::Connection& conn, const std::string& reason) {
+                session = nullptr;
+                hostSocket = nullptr;
+                inputBuffer.reset();
+                outputBuffer.reset();
+            })
+        .onmessage([](crow::websocket::Connection& conn,
+                      const std::string& data, bool is_binary) {
+            if (data.length() > inputBuffer.capacity())
+            {
+                BMCWEB_LOG_ERROR << "Buffer overrun when writing "
+                                 << data.length() << " bytes";
+                conn.close("Buffer overrun");
+                return;
+            }
+
+            BMCWEB_LOG_DEBUG << "Read " << data.size()
+                             << " bytes from websocket";
+            boost::asio::buffer_copy(inputBuffer.prepare(data.size()),
+                                     boost::asio::buffer(data));
+            BMCWEB_LOG_DEBUG << "commiting " << data.size()
+                             << " bytes from websocket";
+            inputBuffer.commit(data.size());
+
+            BMCWEB_LOG_DEBUG << "inputbuffer size " << inputBuffer.size();
+            doWrite();
+        });
+}
+} // namespace obmc_kvm
+} // namespace crow
diff --git a/include/security_headers_middleware.hpp b/include/security_headers_middleware.hpp
index 5e8e7d9..1ebc43c 100644
--- a/include/security_headers_middleware.hpp
+++ b/include/security_headers_middleware.hpp
@@ -36,7 +36,12 @@
 
         res.addHeader(bf::pragma, "no-cache");
         res.addHeader(bf::cache_control, "no-Store,no-Cache");
-        res.addHeader("Content-Security-Policy", "default-src 'self'");
+
+        // The KVM currently needs to load images from base64 encoded strings.
+        // img-src 'self' data: is used to allow that.
+        // https://stackoverflow.com/questions/18447970/content-security-policy-data-not-working-for-base64-images-in-chrome-28
+        res.addHeader("Content-Security-Policy",
+                      "default-src 'self'; img-src 'self' data:");
         res.addHeader("X-XSS-Protection", "1; "
                                           "mode=block");
         res.addHeader("X-Content-Type-Options", "nosniff");
diff --git a/include/web_kvm.hpp b/include/web_kvm.hpp
deleted file mode 100644
index 747a137..0000000
--- a/include/web_kvm.hpp
+++ /dev/null
@@ -1,422 +0,0 @@
-#include <crow/app.h>
-
-#include <ast_jpeg_decoder.hpp>
-#include <ast_video_puller.hpp>
-#include <boost/endian/arithmetic.hpp>
-#include <string>
-
-namespace crow
-{
-namespace kvm
-{
-
-static const std::string rfb33VersionString = "RFB 003.003\n";
-static const std::string rfb37VersionString = "RFB 003.007\n";
-static const std::string rfb38VersionString = "RFB 003.008\n";
-
-enum class RfbAuthScheme : uint8_t
-{
-    connection_failed = 0,
-    no_authentication = 1,
-    vnc_authentication = 2
-};
-
-struct PixelFormatStruct
-{
-    boost::endian::big_uint8_t bitsPerPixel;
-    boost::endian::big_uint8_t depth;
-    boost::endian::big_uint8_t isBigEndian;
-    boost::endian::big_uint8_t isTrueColor;
-    boost::endian::big_uint16_t redMax;
-    boost::endian::big_uint16_t greenMax;
-    boost::endian::big_uint16_t blueMax;
-    boost::endian::big_uint8_t redShift;
-    boost::endian::big_uint8_t greenShift;
-    boost::endian::big_uint8_t blueShift;
-    boost::endian::big_uint8_t pad1;
-    boost::endian::big_uint8_t pad2;
-    boost::endian::big_uint8_t pad3;
-};
-
-struct ServerInitializationMsg
-{
-    boost::endian::big_uint16_t framebufferWidth;
-    boost::endian::big_uint16_t framebufferHeight;
-    PixelFormatStruct pixelFormat;
-    boost::endian::big_uint32_t nameLength;
-};
-
-enum class client_to_server_msg_type : uint8_t
-{
-    set_pixel_format = 0,
-    fix_color_map_entries = 1,
-    set_encodings = 2,
-    framebuffer_update_request = 3,
-    key_event = 4,
-    pointer_event = 5,
-    client_cut_text = 6
-};
-
-enum class server_to_client_message_type : uint8_t
-{
-    framebuffer_update = 0,
-    set_color_map_entries = 1,
-    bell_message = 2,
-    server_cut_text = 3
-};
-
-struct SetPixelFormatMsg
-{
-    boost::endian::big_uint8_t pad1;
-    boost::endian::big_uint8_t pad2;
-    boost::endian::big_uint8_t pad3;
-    PixelFormatStruct pixelFormat;
-};
-
-struct FrameBufferUpdateReq
-{
-    boost::endian::big_uint8_t incremental;
-    boost::endian::big_uint16_t xPosition;
-    boost::endian::big_uint16_t yPosition;
-    boost::endian::big_uint16_t width;
-    boost::endian::big_uint16_t height;
-};
-
-struct KeyEventMsg
-{
-    boost::endian::big_uint8_t downFlag;
-    boost::endian::big_uint8_t pad1;
-    boost::endian::big_uint8_t pad2;
-    boost::endian::big_uint32_t key;
-};
-
-struct PointerEventMsg
-{
-    boost::endian::big_uint8_t buttonMask;
-    boost::endian::big_uint16_t xPosition;
-    boost::endian::big_uint16_t yPosition;
-};
-
-struct ClientCutTextMsg
-{
-    std::vector<uint8_t> data;
-};
-
-enum class encoding_type : uint32_t
-{
-    raw = 0x00,
-    copy_rectangle = 0x01,
-    rising_rectangle = 0x02,
-    corre = 0x04,
-    hextile = 0x05,
-    zlib = 0x06,
-    tight = 0x07,
-    zlibhex = 0x08,
-    ultra = 0x09,
-    zrle = 0x10,
-    zywrle = 0x011,
-    cache_enable = 0xFFFF0001,
-    xor_enable = 0xFFFF0006,
-    server_state_ultranvc = 0xFFFF8000,
-    enable_keepAlive = 0xFFFF8001,
-    enableftp_protocol_version = 0xFFFF8002,
-    tight_compress_level_0 = 0xFFFFFF00,
-    tight_compress_level_9 = 0xFFFFFF09,
-    x_cursor = 0xFFFFFF10,
-    rich_cursor = 0xFFFFFF11,
-    pointer_pos = 0xFFFFFF18,
-    last_rect = 0xFFFFFF20,
-    new_framebuffer_size = 0xFFFFFF21,
-    tight_quality_level_0 = 0xFFFFFFE0,
-    tight_quality_level_9 = 0xFFFFFFE9
-};
-
-struct FramebufferRectangle
-{
-    boost::endian::big_uint16_t x{};
-    boost::endian::big_uint16_t y{};
-    boost::endian::big_uint16_t width{};
-    boost::endian::big_uint16_t height{};
-    boost::endian::big_uint32_t encoding{};
-    std::vector<uint8_t> data;
-};
-
-struct FramebufferUpdateMsg
-{
-    boost::endian::big_uint8_t messageType{};
-    std::vector<FramebufferRectangle> rectangles;
-};
-
-inline std::string serialize(const FramebufferUpdateMsg& msg)
-{
-    // calculate the size of the needed vector for serialization
-    size_t vectorSize = 4;
-    for (const auto& rect : msg.rectangles)
-    {
-        vectorSize += 12 + rect.data.size();
-    }
-
-    std::string serialized(vectorSize, 0);
-
-    size_t i = 0;
-    serialized[i++] = static_cast<char>(
-        server_to_client_message_type::framebuffer_update); // Type
-    serialized[i++] = 0;                                    // Pad byte
-    boost::endian::big_uint16_t numberOfRectangles = msg.rectangles.size();
-    std::memcpy(&serialized[i], &numberOfRectangles,
-                sizeof(numberOfRectangles));
-    i += sizeof(numberOfRectangles);
-
-    for (const auto& rect : msg.rectangles)
-    {
-        // copy the first part of the struct
-        size_t bufferSize =
-            sizeof(FramebufferRectangle) - sizeof(std::vector<uint8_t>);
-        std::memcpy(&serialized[i], &rect, bufferSize);
-        i += bufferSize;
-
-        std::memcpy(&serialized[i], rect.data.data(), rect.data.size());
-        i += rect.data.size();
-    }
-
-    return serialized;
-}
-
-enum class VncState
-{
-    UNSTARTED,
-    AWAITING_CLIENT_VERSION,
-    AWAITING_CLIENT_AUTH_METHOD,
-    AWAITING_CLIENT_INIT_msg,
-    MAIN_LOOP
-};
-
-class ConnectionMetadata
-{
-  public:
-    ConnectionMetadata(){};
-
-    VncState vncState{VncState::UNSTARTED};
-};
-
-using meta_list = std::vector<ConnectionMetadata>;
-meta_list connectionStates(10);
-
-ConnectionMetadata meta;
-
-template <typename... Middlewares> void requestRoutes(Crow<Middlewares...>& app)
-{
-    BMCWEB_ROUTE(app, "/kvmws")
-        .websocket()
-        .onopen([&](crow::websocket::Connection& conn) {
-            if (meta.vncState == VncState::UNSTARTED)
-            {
-                meta.vncState = VncState::AWAITING_CLIENT_VERSION;
-                conn.sendBinary(rfb38VersionString);
-            }
-            else
-            { // SHould never happen
-                conn.close();
-            }
-        })
-        .onclose(
-            [&](crow::websocket::Connection& conn, const std::string& reason) {
-                meta.vncState = VncState::UNSTARTED;
-            })
-        .onmessage([&](crow::websocket::Connection& conn,
-                       const std::string& data, bool is_binary) {
-            switch (meta.vncState)
-            {
-                case VncState::AWAITING_CLIENT_VERSION:
-                {
-                    std::cout << "Client sent: " << data;
-                    if (data == rfb38VersionString ||
-                        data == rfb37VersionString)
-                    {
-                        std::string authTypes{
-                            1, (uint8_t)RfbAuthScheme::no_authentication};
-                        conn.sendBinary(authTypes);
-                        meta.vncState = VncState::AWAITING_CLIENT_AUTH_METHOD;
-                    }
-                    else if (data == rfb33VersionString)
-                    {
-                        // TODO(ed)  Support older protocols
-                        meta.vncState = VncState::UNSTARTED;
-                        conn.close();
-                    }
-                    else
-                    {
-                        // TODO(ed)  Support older protocols
-                        meta.vncState = VncState::UNSTARTED;
-                        conn.close();
-                    }
-                }
-                break;
-                case VncState::AWAITING_CLIENT_AUTH_METHOD:
-                {
-                    std::string securityResult{{0, 0, 0, 0}};
-                    if (data[0] == (uint8_t)RfbAuthScheme::no_authentication)
-                    {
-                        meta.vncState = VncState::AWAITING_CLIENT_INIT_msg;
-                    }
-                    else
-                    {
-                        // Mark auth as failed
-                        securityResult[3] = 1;
-                        meta.vncState = VncState::UNSTARTED;
-                    }
-                    conn.sendBinary(securityResult);
-                }
-                break;
-                case VncState::AWAITING_CLIENT_INIT_msg:
-                {
-                    // Now send the server initialization
-                    ServerInitializationMsg serverInitMsg{};
-                    serverInitMsg.framebufferWidth = 800;
-                    serverInitMsg.framebufferHeight = 600;
-                    serverInitMsg.pixelFormat.bitsPerPixel = 32;
-                    serverInitMsg.pixelFormat.isBigEndian = 0;
-                    serverInitMsg.pixelFormat.isTrueColor = 1;
-                    serverInitMsg.pixelFormat.redMax = 255;
-                    serverInitMsg.pixelFormat.greenMax = 255;
-                    serverInitMsg.pixelFormat.blueMax = 255;
-                    serverInitMsg.pixelFormat.redShift = 16;
-                    serverInitMsg.pixelFormat.greenShift = 8;
-                    serverInitMsg.pixelFormat.blueShift = 0;
-                    serverInitMsg.nameLength = 0;
-                    std::cout << "size: " << sizeof(serverInitMsg);
-                    // TODO(ed) this is ugly.  Crow should really have a span
-                    // type interface to avoid the copy, but alas, today it does
-                    // not.
-                    std::string s(reinterpret_cast<char*>(&serverInitMsg),
-                                  sizeof(serverInitMsg));
-                    std::cout << "s.size() " << s.size();
-                    conn.sendBinary(s);
-                    meta.vncState = VncState::MAIN_LOOP;
-                }
-                break;
-                case VncState::MAIN_LOOP:
-                {
-                    if (data.size() >= sizeof(client_to_server_msg_type))
-                    {
-                        auto type =
-                            static_cast<client_to_server_msg_type>(data[0]);
-                        std::cout << "Received client message type "
-                                  << static_cast<std::size_t>(type) << "\n";
-                        switch (type)
-                        {
-                            case client_to_server_msg_type::set_pixel_format:
-                            {
-                            }
-                            break;
-
-                            case client_to_server_msg_type::
-                                fix_color_map_entries:
-                            {
-                            }
-                            break;
-                            case client_to_server_msg_type::set_encodings:
-                            {
-                            }
-                            break;
-                            case client_to_server_msg_type::
-                                framebuffer_update_request:
-                            {
-                                // Make sure the buffer is long enough to handle
-                                // what we're about to do
-                                if (data.size() >=
-                                    sizeof(FrameBufferUpdateReq) +
-                                        sizeof(client_to_server_msg_type))
-                                {
-                                    auto msg = reinterpret_cast<
-                                        const FrameBufferUpdateReq*>(
-                                        data.data() + // NOLINT
-                                        sizeof(client_to_server_msg_type));
-                                    // TODO(ed) find a better way to do this
-                                    // deserialization
-
-                                    // Todo(ed) lifecycle of the video puller
-                                    // and decoder should be with the websocket,
-                                    // not recreated every time
-                                    ast_video::SimpleVideoPuller p;
-                                    p.initialize();
-                                    auto out = p.readVideo();
-                                    ast_video::AstJpegDecoder d;
-                                    d.decode(out.buffer, out.width, out.height,
-                                             out.mode, out.ySelector,
-                                             out.uvSelector);
-
-                                    FramebufferUpdateMsg bufferUpdateMsg;
-
-                                    // If the viewer is requesting a full
-                                    // update, force write of all pixels
-
-                                    FramebufferRectangle thisRect;
-                                    thisRect.x = msg->xPosition;
-                                    thisRect.y = msg->yPosition;
-                                    thisRect.width = out.width;
-                                    thisRect.height = out.height;
-                                    thisRect.encoding = static_cast<uint8_t>(
-                                        encoding_type::raw);
-                                    std::cout << "Encoding is "
-                                              << thisRect.encoding;
-                                    thisRect.data.reserve(
-                                        static_cast<std::size_t>(
-                                            thisRect.width) *
-                                        static_cast<std::size_t>(
-                                            thisRect.height) *
-                                        4);
-                                    std::cout << "Width " << out.width
-                                              << " Height " << out.height;
-
-                                    for (int i = 0; i < out.width * out.height;
-                                         i++)
-                                    {
-                                        auto& pixel = d.outBuffer[i];
-                                        thisRect.data.push_back(pixel.b);
-                                        thisRect.data.push_back(pixel.g);
-                                        thisRect.data.push_back(pixel.r);
-                                        thisRect.data.push_back(0);
-                                    }
-
-                                    bufferUpdateMsg.rectangles.push_back(
-                                        std::move(thisRect));
-                                    auto serialized =
-                                        serialize(bufferUpdateMsg);
-
-                                    conn.sendBinary(serialized);
-
-                                } // TODO(Ed) handle error
-                            }
-
-                            break;
-
-                            case client_to_server_msg_type::key_event:
-                            {
-                            }
-                            break;
-
-                            case client_to_server_msg_type::pointer_event:
-                            {
-                            }
-                            break;
-
-                            case client_to_server_msg_type::client_cut_text:
-                            {
-                            }
-                            break;
-
-                            default:
-                                break;
-                        }
-                    }
-                }
-                break;
-                case VncState::UNSTARTED:
-                    // Error?  TODO
-                    break;
-            }
-        });
-}
-} // namespace kvm
-} // namespace crow
\ No newline at end of file
diff --git a/src/getvideo_main.cpp b/src/getvideo_main.cpp
deleted file mode 100644
index 849c75d..0000000
--- a/src/getvideo_main.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <chrono>
-#include <cstdio>
-#include <cstdlib>
-#include <fstream>
-#include <iomanip>
-#include <iostream>
-#include <thread>
-#include <vector>
-
-//#define BUILD_CIMG
-#ifdef BUILD_CIMG
-#define cimg_display 0
-#include <CImg.h>
-#endif
-
-#include <ast_jpeg_decoder.hpp>
-#include <ast_video_puller.hpp>
-
-int main()
-{
-    ast_video::RawVideoBuffer out;
-    bool have_hardware = false;
-    if (access("/dev/video", F_OK) != -1)
-    {
-        ast_video::SimpleVideoPuller p;
-        p.initialize();
-        out = p.readVideo();
-    }
-    else
-    {
-        FILE *fp = fopen("/home/ed/screendata.bin", "rb");
-        if (fp != nullptr)
-        {
-            size_t newLen = fread(out.buffer.data(), sizeof(char),
-                                  out.buffer.size() * sizeof(long), fp);
-            if (ferror(fp) != 0)
-            {
-                fputs("Error reading file", stderr);
-            }
-            fclose(fp);
-            out.buffer.resize(newLen);
-            out.mode = ast_video::YuvMode::YUV444;
-            out.width = 800;
-            out.height = 600;
-            out.ySelector = 0;
-            out.uvSelector = 0;
-        }
-    }
-
-    FILE *fp = fopen("/tmp/screendata.bin", "wb");
-    fwrite(out.buffer.data(), sizeof(char), out.buffer.size(), fp);
-    fclose(fp);
-
-    ast_video::AstJpegDecoder d;
-    d.decode(out.buffer, out.width, out.height, out.mode, out.ySelector,
-             out.uvSelector);
-#ifdef BUILD_CIMG
-    cimg_library::CImg<unsigned char> image(out.width, out.height, 1,
-                                            3 /*numchannels*/);
-    for (int y = 0; y < out.height; y++)
-    {
-        for (int x = 0; x < out.width; x++)
-        {
-            auto pixel = d.outBuffer[x + (y * out.width)];
-            image(x, y, 0) = pixel.r;
-            image(x, y, 1) = pixel.g;
-            image(x, y, 2) = pixel.b;
-        }
-    }
-    image.save("/tmp/file2.bmp");
-#endif
-
-    std::cout << "Done!\n";
-
-    return 1;
-}
diff --git a/src/webserver_main.cpp b/src/webserver_main.cpp
index 7c64f4c..b357b4e 100644
--- a/src/webserver_main.cpp
+++ b/src/webserver_main.cpp
@@ -5,6 +5,7 @@
 #include <dbus_monitor.hpp>
 #include <dbus_singleton.hpp>
 #include <image_upload.hpp>
+#include <kvm_websocket.hpp>
 #include <memory>
 #include <obmc_console.hpp>
 #include <openbmc_dbus_rest.hpp>
@@ -18,7 +19,6 @@
 #include <ssl_key_handler.hpp>
 #include <string>
 #include <token_authorization_middleware.hpp>
-#include <web_kvm.hpp>
 #include <webassets.hpp>
 #include <webserver_common.hpp>
 
@@ -77,7 +77,7 @@
 #endif
 
 #ifdef BMCWEB_ENABLE_KVM
-    crow::kvm::requestRoutes(app);
+    crow::obmc_kvm::requestRoutes(app);
 #endif
 
 #ifdef BMCWEB_ENABLE_REDFISH