LibMISB - Examples - Dynamic metadata

From RidgeRun Developer Wiki

Follow Us On Twitter LinkedIn Email Share this page



Previous: Examples/RTSP_Streaming_Example Index Next: Evaluating/Evaluating the library





What This Example Does

misb-changing-metadata.cpp demonstrates a live metadata stream workflow with LibMISB:

  • Builds ST0601 JSON metadata on every loop.
  • Changes key fields each iteration:
tag 2: UTC timestamp
tag 3: mission id (MISSION-100, MISSION-101, ...)
tag 4: platform tail (AF-100, AF-101, ...)
tag 5: heading-like numeric value
  • Encodes JSON to KLV bytes.
  • Decodes KLV back to JSON.
  • Prints encoded size and decoded JSON so you can verify changing values.

Example source code

/* Copyright (C) 2026 RidgeRun, LLC (http://www.ridgerun.com)
 * All Rights Reserved.
 *
 * The contents of this software are proprietary and confidential to RidgeRun,
 * LLC.  No part of this program may be photocopied, reproduced or translated
 * into another programming language without prior written consent of
 * RidgeRun, LLC.  The user is free to modify the source code after obtaining
 * a software license from RidgeRun.  All source code changes must be provided
 * back to RidgeRun without any encumbrance.
 */

#include "libmisb/formatter/jsonformatter.hpp"

#include <chrono>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <thread>

#include <libmisb/libmisb.hpp>

namespace {

constexpr char kSt0601Key[] = "060E2B34020B01010E01030101000000";
constexpr unsigned int kDefaultIterations = 20;
constexpr unsigned int kDefaultIntervalMs = 500;

std::string BuildUtcTimestamp() {
  auto now = std::chrono::system_clock::now();
  auto now_time = std::chrono::system_clock::to_time_t(now);
  auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                now.time_since_epoch()) %
            1000;

  std::tm now_tm{};
#if defined(_WIN32)
  gmtime_s(&now_tm, &now_time);
#else
  gmtime_r(&now_time, &now_tm);
#endif

  std::ostringstream stream;
  stream << std::put_time(&now_tm, "%b. %d, %Y. %H:%M:%S");
  stream << '.' << std::setw(3) << std::setfill('0') << ms.count();

  return stream.str();
}

std::string BuildChangingMetadataJson(unsigned int iteration) {
  std::ostringstream heading;
  heading << std::fixed << std::setprecision(2)
          << static_cast<double>((iteration * 11) % 360);

  std::ostringstream mission;
  mission << "MISSION-" << (100 + (iteration % 900));

  std::ostringstream tail_number;
  tail_number << "AF-" << (100 + (iteration % 900));

  std::ostringstream json;
  json << "{\"key\":\"" << kSt0601Key << "\",\"items\":[";
  json << "{\"tag\":\"2\",\"value\":\"" << BuildUtcTimestamp() << "\"},";
  json << "{\"tag\":\"3\",\"value\":\"" << mission.str() << "\"},";
  json << "{\"tag\":\"4\",\"value\":\"" << tail_number.str() << "\"},";
  json << "{\"tag\":\"5\",\"value\":\"" << heading.str() << "\"},";
  json << "{\"tag\":\"48\",\"value\":[";
  json << "{\"tag\":\"2\",\"value\":\"1\"},";
  json << "{\"tag\":\"4\",\"value\":\"TS/SI/CompartmentA//\"}";
  json << "]}";
  json << "]}";
  return json.str();
}

unsigned int ParseUnsignedArgument(const char* value, unsigned int fallback) {
  try {
    return static_cast<unsigned int>(std::stoul(value));
  } catch (...) {
    return fallback;
  }
}

}  // namespace

int main(int argc, char* argv[]) {
  unsigned int iterations = kDefaultIterations;
  unsigned int interval_ms = kDefaultIntervalMs;

  if (argc > 1) {
    iterations = ParseUnsignedArgument(argv[1], kDefaultIterations);
  }
  if (argc > 2) {
    interval_ms = ParseUnsignedArgument(argv[2], kDefaultIntervalMs);
  }

  libmisb::LibMisb libmisb;
  libmisb.SetLogLevel(LIBMISB_INFO);
  libmisb.SetFormatter(std::make_shared<libmisb::formatter::JsonFormatter>());
  const bool run_forever = (iterations == 0);

  if (run_forever) {
    std::cout << "Running continuously. Metadata changes every loop.\n";
  } else {
    std::cout << "Running " << iterations
              << " iterations. Metadata changes every loop.\n";
  }

  for (unsigned int i = 0; run_forever || i < iterations; ++i) {
    const std::string json_input = BuildChangingMetadataJson(i);
    std::vector<unsigned char> packet = libmisb.Encode(json_input);
    if (packet.empty()) {
      LOGGER.Log("Failed to encode metadata for current iteration",
                 LIBMISB_ERROR);
      return 1;
    }

    const std::string decoded_output = libmisb.Decode(packet);
    if (decoded_output.empty()) {
      LOGGER.Log("Failed to decode packet for current iteration", LIBMISB_ERROR);
      return 1;
    }

    std::cout << "Iteration " << i << " -> encoded bytes: " << packet.size()
              << "\n";
    std::cout << "Decoded metadata: " << decoded_output << "\n\n";

    std::this_thread::sleep_for(std::chrono::milliseconds(interval_ms));
  }

  if (!run_forever) {
    std::cout << "Finished metadata update loop.\n";
  }
  return 0;
}

Prerequisites

You need LibMISB built already (or in eval mode), plus its dependencies.

Compile As Standalone External C++ File

This compiles the file from outside the project tree, linking against the already-built LibMISB artifacts.

1) Create misb-changing-metadata.cpp file and copy example source code

2) Compile the application:

g++ misb-changing-metadata.cpp -o misb-changing-metadata-standalone `pkg-config --cflags --libs glib-2.0 misb-0.0`

How To Run

Usage:

./misb-changing-metadata-standalone [iterations] [interval_ms]
  • iterations: loop count. Default is 20. Use 0 for continuous mode.
  • interval_ms: delay between iterations in milliseconds. Default is 500.

Examples:

 # Run 3 iterations, 50 ms interval ./misb-changing-metadata-standalone 3 50
Run forever (Ctrl+C to stop)
./misb-changing-metadata-standalone 0 200

Expected Output

You should see:

  • A startup line indicating finite or continuous mode.
  • Per iteration:
    • INFO Formatted data generated
    • Iteration N -> encoded bytes: ...
    • Decoded metadata: {...} with changing tags (2, 3, 4, 5).
  • For finite mode, a final Finished metadata update loop. line. Representative output:
 Running 3 iterations. Metadata changes every loop. INFO Formatted data generated Iteration 0 -> encoded bytes: 86 Decoded metadata: {"key":"060E2B34020B01010E01030101000000","items":[{"tag":"2","value":"Mar. 17, 2026. 14:33:04.095"},{"tag":"3","value":"MISSION-100"},{"tag":"4","value":"AF-100"},{"tag":"5","value":"0"}, ... ]}
INFO Formatted data generated
Iteration 1 -> encoded bytes: 86
Decoded metadata: {"key":"060E2B34020B01010E01030101000000","items":[{"tag":"2","value":"Mar. 17, 2026. 14:33:04.154"},{"tag":"3","value":"MISSION-101"},{"tag":"4","value":"AF-101"},{"tag":"5","value":"10.9974823"}, ... ]}

INFO Formatted data generated
Iteration 2 -> encoded bytes: 86
Decoded metadata: {"key":"060E2B34020B01010E01030101000000","items":[{"tag":"2","value":"Mar. 17, 2026. 14:33:04.211"},{"tag":"3","value":"MISSION-102"},{"tag":"4","value":"AF-102"},{"tag":"5","value":"22.0004578"}, ... ]}

Finished metadata update loop.

Notes

The exact timestamp and numeric values vary each run. You may also see additional decoded tags (for example tag 65) inserted by codec/standard logic; this is expected.







Previous: Examples/RTSP_Streaming_Example Index  


</noinclude