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 inMediaLibrary)type: "peer"+peerIppublishesRequestResourceNotificationdirect to that peer and unwraps the firstEventResultas aMediaChunkResponse- Optional
offset/length(-1= EOF). Full-file (offset=0,length=-1) returns raw bytes; otherwise JSON{ offset, length, totalSize, eof, data }with base64data
StreamMedia — ask a peer to start a live encode:
- Client →
StreamMediawith media identity +peerIp - Peer
RequestMediaStreamNotificationHandlerstartsMediaStream.startStream(...) - Peer shells out to
ffmpeg, publishes MPEG-TS byte chunks asMediaStreamServiceNotification - Requester queues by
streamId;ViewMediaStreamFunctionopensViewMediaStreamWindow
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→ targetcreate_run_jar→smf.jar - CLI harness:
TestClientundersrc/.../smf/test/ - Interactive CLI:
java -jar smf.jar --server(startsCLIalongside the service path)
Honest caveats
Drawn from the implementation and ISSUES.md:
- HTTP API has no auth — loopback binding is the main boundary.
MediaLibraryconcurrency is limited; large recursiveUpdateLibrarycan be heavy.- Peer
RetrieveMediaassumes a single usefulEventResultfrom 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
ffmpegon 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.