libklv is a simple C++14 library that implements a KLV class and parser. This library tries to abide by the SMPTE 336M-2007 standard for KLV in motion imagery. This project was motivated by the need for a library to inject and decode UAS KLV metadata from MPEG2-TS video.
- "Data Encoding Protocol Using Key-Length Value" SMPTE 336-2007
- "NATO Digital Motion Imagery Standard" STANAG 4609
- "UAS Datalink Local Set" MISB ST 0601.8
- Compiler that supports C++14
- Google Test
- CMake
Google Test is used in this project as a Git submodules and is therefor built and linked when this project is built.
To checkout/clone this project, run:
git clone https://github.com/Hunter522/libklv.git
cd libklv
git submodule update --init --recursive
To build:
cd libklv
mkdir build && cd build
cmake ..
make
This will build a libklv.so
file in the build/ directory.
To run unit tests, build the project and then:
cd libklv/build
./runUnitTests
Take a look at some of the unit tests to get an idea on how to use this library. KlvParserTest.cpp shows how to use the KlvParser class to parse incoming bytes and construct a KLV object.
This library offers a few classes to allow one to decode and encode KLV data. These classes include:
KLV
KlvParser
To use these classes, simply include these headers:
#include "Klv.h"
#include "KlvParser.hpp"
To construct KLV objects, you can manually create them:
std::vector<uint8_t> key = { 0x06, 0x0E, 0x2B, 0x34, 0x02, 0x0B, 0x01, 0x01, 0x0E, 0x01, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00 };
std::vector<uint8_t> len = { 0x81, 0x90 };
std::vector<uint8_t> val = { 0x02, 0x08, 0x00, 0x04, 0x6C, 0xAE, 0x70, 0xF9, 0x80, 0xCF, 0x41, 0x01, 0x01, 0x05, 0x02, 0xE1, 0x91, 0x06, 0x02, 0x06, 0x0D, 0x07, 0x02, 0x0A, 0xE1, 0x0B, 0x02, 0x49, 0x52, 0x0C, 0x0E, 0x47, 0x65, 0x6F, 0x64, 0x65, 0x74, 0x69, 0x63, 0x20, 0x57, 0x47, 0x53, 0x38, 0x34, 0x0D, 0x04, 0x4D, 0xCC, 0x41, 0x90, 0x0E, 0x04, 0xB1, 0xD0, 0x3D, 0x96, 0x0F, 0x02, 0x1B, 0x2E, 0x10, 0x02, 0x00, 0x84, 0x11, 0x02, 0x00, 0x4A, 0x12, 0x04, 0xE7, 0x23, 0x0B, 0x61, 0x13, 0x04, 0xFD, 0xE8, 0x63, 0x8E, 0x14, 0x04, 0x03, 0x0B, 0xC7, 0x1C, 0x15, 0x04, 0x00, 0x9F, 0xB9, 0x38, 0x16, 0x04, 0x00, 0x00, 0x01, 0xF8, 0x17, 0x04, 0x4D, 0xEC, 0xDA, 0xF4, 0x18, 0x04, 0xB1, 0xBC, 0x81, 0x74, 0x19, 0x02, 0x0B, 0x8A, 0x28, 0x04, 0x4D, 0xEC, 0xDA, 0xF4, 0x29, 0x04, 0xB1, 0xBC, 0x81, 0x74, 0x2A, 0x02, 0x0B, 0x8A, 0x38, 0x01, 0x31, 0x39, 0x04, 0x00, 0x9F, 0x85, 0x4D, 0x01, 0x02, 0xB7, 0xEB };
KLV klv(key, len, val);
or use the KlvParser class to decode a byte vector (originating from a file, or perhaps a incoming data stream):
std::vector<uint8_t> test_pkt_uas = {0x06, 0x0E, 0x2B, 0x34, 0x02, 0x0B, 0x01, 0x01, 0x0E, 0x01, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x81, 0x90, 0x02, 0x08, 0x00, 0x04, 0x6C, 0xAE, 0x70, 0xF9, 0x80, 0xCF, 0x41, 0x01, 0x01, 0x05, 0x02, 0xE1, 0x91, 0x06, 0x02, 0x06, 0x0D, 0x07, 0x02, 0x0A, 0xE1, 0x0B, 0x02, 0x49, 0x52, 0x0C, 0x0E, 0x47, 0x65, 0x6F, 0x64, 0x65, 0x74, 0x69, 0x63, 0x20, 0x57, 0x47, 0x53, 0x38, 0x34, 0x0D, 0x04, 0x4D, 0xCC, 0x41, 0x90, 0x0E, 0x04, 0xB1, 0xD0, 0x3D, 0x96, 0x0F, 0x02, 0x1B, 0x2E, 0x10, 0x02, 0x00, 0x84, 0x11, 0x02, 0x00, 0x4A, 0x12, 0x04, 0xE7, 0x23, 0x0B, 0x61, 0x13, 0x04, 0xFD, 0xE8, 0x63, 0x8E, 0x14, 0x04, 0x03, 0x0B, 0xC7, 0x1C, 0x15, 0x04, 0x00, 0x9F, 0xB9, 0x38, 0x16, 0x04, 0x00, 0x00, 0x01, 0xF8, 0x17, 0x04, 0x4D, 0xEC, 0xDA, 0xF4, 0x18, 0x04, 0xB1, 0xBC, 0x81, 0x74, 0x19, 0x02, 0x0B, 0x8A, 0x28, 0x04, 0x4D, 0xEC, 0xDA, 0xF4, 0x29, 0x04, 0xB1, 0xBC, 0x81, 0x74, 0x2A, 0x02, 0x0B, 0x8A, 0x38, 0x01, 0x31, 0x39, 0x04, 0x00, 0x9F, 0x85, 0x4D, 0x01, 0x02, 0xB7, 0xEB};
// you must provide the parser with a vector<KlvParser::KeyEncoding>
KlvParser parser({KlvParser::KEY_ENCODING_16_BYTE, KlvParser::KEY_ENCODING_BER_OID});
KLV* parsed_klv = NULL;
for(int i = 0; i < test_pkt_uas.size(); i++) {
parsed_klv = parser.parseByte(test_pkt_uas[i]);
if(parsed_klv != NULL)
break;
}
The KLV
class offers a method (indexToMap()
) to index itself and all of its children (if the value has local KLV)
into a flattened map. This method returns a unordered_map
where the key is the KLV key byte vector and the value being
the KLV itself. The map can then be used to easily access the different child KLV elements by simply using the KLV
key/tag.
Once a KLV object is constructed, you can encode the KLV into a byte vector by simply calling KLV::toBytes()
.
This project uses the MIT license. See LICENSE.txt.