A Java library that turns a local media folder into a JSDF-backed peer library — loopback JSON API on :2424, encrypted Realm traffic on :14789, with chunked retrieve and ffmpeg MPEG-TS streaming between nodes.

SecureMediaFramework (SMF) is a small Java service for indexing a local media library and sharing it with peers over JSDF. Clients talk to a loopback HTTP JSON API; peers exchange library metadata and media bytes (or live streams) through an encrypted Realm.

The desktop UI that usually rides on top of it is SMF Player — this page is about the library/service itself (smf.jar).

What it’s for

Capability Reality in the code
Local library Path → MediaRecord map, persisted as CSV under ~/SMF/config/media_library.csv
Peer advertising PublishLibraryNotification on a timer (~60s) and on join/update
Pull media RetrieveMedia local disk or peer via RequestResourceNotification
Live stream StreamMedia → peer runs ffmpeg → MPEG-TS chunks as JSDF notifications
Security defaults BootstrapExecutor off; post-auth ObjectInputFilter via RealmSecurityPolicy

It is not a public CDN: the HTTP API binds loopback only (127.0.0.1:2424). Peer reachability is the JSDF Distributor path (default TCP 14789).

Architecture

flowchart TB
  client[HTTP client / SMF Player] -->|JSON body /api| servlet[Servlet JDK HttpServer :2424]
  servlet --> api[ApiHandler]
  api --> lib[MediaLibrary]
  api --> dist[JSDF Distributor]
  api --> realm[Realm]
  realm --> events[RealmEventHandler]
  events --> pub[PublishLibraryNotification]
  events --> req[RequestResourceNotification]
  events --> streamReq[RequestMediaStreamNotification]
  streamReq --> ffmpeg[MediaStream + ffmpeg MPEG-TS]
  ffmpeg --> chunks[MediaStreamServiceNotification]
Piece Role
Main MediaLibrary.initialize() then Servlet (or CLI when started with --server)
Servlet JDK HttpServer on loopback 2424, context /api
ApiHandler Parses JSON function field; owns Distributor / active Realm / stream callbacks
MediaLibrary Local + peer maps, hashing, optional pHash/thumbnails, CSV load/save
RealmEventHandler Dispatches JSDF notifications to typed handlers
MediaStream ffmpeg process, chunk publish, transport controls, preview window hooks
RealmSecurityPolicy Centralized bootstrap + deserialization filter policy

Package root: com.java_shell.danschirripa.smf.

HTTP API (grounded)

All calls hit /api with a JSON body that includes "function": "...". The handler reads the body for every method — including GET — so clients must always send JSON.

Realm lifecycle

Function Method Notes
CreateRealm POST New Realm; Beacon UI evaluator (GraphicalUserValidationEvaluator); returns Realm UUID
CreateRealmWithCertificate POST Realm with quick-generated X.509 certificate evaluator
JoinRealm POST Needs realmID + realmAddress
Shutdown POST Process teardown (+ JVM shutdown hook also notifies peers)

Create/join apply RealmSecurityPolicy: BootstrapExecutor disabled, plus a post-auth filter that allows com.java_shell.danschirripa.smf.* and org.json.simple.*, enforces depth/ref/byte caps (env-tunable), and otherwise delegates to JSDF’s hardened filter.

Library

Function Role
UpdateLibrary Recursively add paths; publishes library to the active Realm (create/join first)
SaveLibrary Persist local map to CSV
RemoveMedia Drop one path from the local library
GetLibrary Local path → MediaRecord
GetPeerMediaLibraries peerIp → [MediaRecord, …]
GetKnownPeerList Known peer addresses from the Realm

While a Realm is active, ApiHandler also republishes the local library about once a minute.

Retrieve vs stream

RetrieveMedia — content-addressed pull by path + SHA-256 hash + record id:

  • type: "local" reads disk (with hash verification paths in MediaLibrary)
  • type: "peer" + peerIp publishes RequestResourceNotification direct to that peer and unwraps the first EventResult as a MediaChunkResponse
  • Optional offset / length (-1 = EOF). Full-file (offset=0, length=-1) returns raw bytes; otherwise JSON { offset, length, totalSize, eof, data } with base64 data

StreamMedia — ask a peer to start a live encode:

  1. Client → StreamMedia with media identity + peerIp
  2. Peer RequestMediaStreamNotificationHandler starts MediaStream.startStream(...)
  3. Peer shells out to ffmpeg, publishes MPEG-TS byte chunks as MediaStreamServiceNotification
  4. Requester queues by streamId; ViewMediaStreamFunction opens ViewMediaStreamWindow

Transport controls (PAUSE, RESUME, SEEK, STOP) ride as MediaStreamTransportControlNotification on the Realm — not separate HTTP functions.

MediaRecord

type, hash (SHA-256 hex), path, id (UUID), size, pHash?, thumbnail? (base64 PNG)

Types: VIDEO | AUDIO | IMAGE | TEXT | OTHER. Detection is MIME-aware with extension fallbacks. IMAGE/VIDEO may get a generated thumbnail and optional perceptual hash via PHashing / jphash.

JSDF interaction summary

SMF is a payload + event layer on top of JSDF, not a reimplementation of crypto:

  • Library gossip: PublishLibraryNotification
  • On-demand bytes: RequestResourceNotification → chunk response payload
  • Streaming: RequestMediaStreamNotification → MediaStreamServiceNotification + transport notifications
  • Join UX: graphical Beacon evaluator by default (certificate path available)

See also JSDF_SMF_Interactions.mmd in the repo and the JSDF project page.

Build / packaging

Maven project (release 21), depends on JSDF, jphash, and JavaCV (platform). Sources under src/.

Known packaging flow used with SMF Player (Ant fat jar → copy into the player repo):

cd ../JSDF && mvn -q -DskipTests compile \
  && cd ../jphash && mvn -q -DskipTests compile \
  && cd ../SecureMediaFramework \
  && ant -f eclipse-workspace.xml -Ddir.workspace=.. -Ddir.jarfile=.. create_run_jar \
  && cp ../smf.jar ../SMF_Player/java/smf.jar
  • Ant script: eclipse-workspace.xml → target create_run_jar → smf.jar
  • CLI harness: TestClient under src/.../smf/test/
  • Interactive CLI: java -jar smf.jar --server (starts CLI alongside the service path)

Honest caveats

Drawn from the implementation and ISSUES.md:

  • HTTP API has no auth — loopback binding is the main boundary.
  • MediaLibrary concurrency is limited; large recursive UpdateLibrary can be heavy.
  • Peer RetrieveMedia assumes a single useful EventResult from the direct publish.
  • Chunked retrieve is base64-in-JSON (memory-aware clients required).
  • Default Beacon join is interactive (Swing) — awkward for headless boxes unless you use the certificate create path / custom evaluators.
  • Streaming needs a working ffmpeg on the serving peer.

Where to look

Area Start here
Entry / HTTP bind Main.java, Servlet.java
API dispatch handlers/ApiHandler.java, handlers/functions/*
Library MediaLibrary.java, util/MediaRecord.java
Realm events handlers/RealmEventHandler.java, handlers/realm/*
Streaming util/MediaStream.java, notifications/mediastream/*
Security policy security/RealmSecurityPolicy.java
OpenAPI sketch openapi.yaml

Companion UI: SMF Player. Transport fabric: JSDF.