JavaScript video editor, encoder, switcher - version 5.1.1

Server Developer

The @moviemasher/server-express package builds upon the core @moviemasher/moviemasher.js package to provide an ExpressJS server API capable of video encoding and streaming, as well as managing media and its metadata.

The server package is optimized to work with the @moviemasher/client-react package, but this is not a requirement. It defines several Server classes, each handling a specific set of functionality:

The interface between client and server is highly structured, with both requests and responses consisting of strongly typed JSON objects that effectively constitute the API between them. Communication is funneled through the ApiClient component on the client and the ApiServer class on the server.

Demos

Since the Demo only includes the client-side components of the system, the first step is typically to launch a fully functional one either in the cloud or locally to test out the server-side functionality.

Non-developers or anyone with an Amazon account may find launching Movie Masher within their AWS Marketplace to be the simplest option. The image available there can be used to launch an EC2 instance of any size, to which you have full access. You can even make your own images based on it, including any custom changes or additions.

Developers familar with Docker may want to launch the image available on DockerHub, either locally or within a cloud-based container service. This option provides the same ability to access the instance and build atop the image.

CJS Server Example

The source code is available in CommonJS format for direct use in NodeJS, or as TypScript for rebundling with tools like rollup.js.

Installation

The following shell command installs the server and core libraries to your NPM project, saving the former to the dependencies array in your package.json file.

npm install @moviemasher/server-express --save

Alternatively, if you're wanting to build your own server you can just install and build off the core library instead.

Please note

This does not install a client implementation that interacts with this package. Learn more about how the codebase is structured in the Architecture Overview.

Inclusion

server.ts
import path from 'path'
import { Host, HostDefaultOptions, expandToJson } from '@moviemasher/server-express'

const config = process.argv[2] || path.resolve(__dirname, './server-config.json')
const configuration = expandToJson(config)
const options = HostDefaultOptions(configuration)
const host = new Host(options)
host.start()

In this example we're using the Host class to construct all the Server instances, using arguments provided by the HostDefaultOptions function. We pass this function a parsed JSON file with the following structure:

server-config.json
{
"port": 8570,
"previewSize": { "width": 480, "height": 270 },
"outputSize": { "width": 1920, "height": 1080 }
}

In the configuration we are setting the preview dimensions to their default for demonstration purposes. The server will pass these to the client and the client will apply them, but only after the CSS is applied so a resize will be visible if they differ. Preview dimensions should be overridden either in the client, or better still, in the CSS. If the defaults are overidden there they should be here too, since the client does NOT pass them to the server. The rendering server uses them to optimally size previews of uploaded video and images.

We are also setting the output dimensions here, which are used as default values for both the rendering and streaming servers. They should always be an even multiple of the preview dimensions - in this case it's a multiple of four. Using different aspect ratios is actually supported, but then the preview in the client will not match the output of these servers.

API Server

The ApiServer provides a high-level routing mechanism to other servers, through two endpoints:

Endpoint Request Interface Response Interface
/api/servers ApiServersRequest ApiServersResponse
/api/callbacks ApiCallbacksRequest ApiCallbacksResponse

The /api/servers endpoint is called initially to determine which other servers are enabled, and retrieve any client configuration for them. Before making subsequent requests to another server, the /api/callbacks endpoint is first requested. This endpoint returns the actual request that the client should make, potentially from another server. By default though, the same server is returned.

Data Server

The DataServer is responsible for storing and retrieving JSON formatted data and metadata related to binary files. Specifically, it stores the following types of objects:

Its endpoints support typical CRUD (create, retrieve, update, delete) operations:

Endpoint Request Interface Response Interface
/data/cast/delete DataCastDeleteRequest DataCastDeleteResponse
/data/cast/get DataCastGetRequest DataCastGetResponse
/data/cast/put DataCastPutRequest DataCastPutResponse
/data/cast/retrieve DataCastRetrieveRequest DataCastRetrieveResponse
/data/cast/default DataCastDefaultRequest DataCastDefaultResponse
/data/mash/delete DataMashDeleteRequest DataMashDeleteResponse
/data/mash/get DataMashGetRequest DataMashGetResponse
/data/mash/put DataMashPutRequest DataMashPutResponse
/data/mash/retrieve DataMashRetrieveRequest DataMashRetrieveResponse
/data/mash/default DataMashDefaultRequest DataMashDefaultResponse
/data/definition/delete DataDefinitionDeleteRequest DataDefinitionDeleteResponse
/data/definition/get DataDefinitionGetRequest DataDefinitionGetResponse
/data/definition/put DataDefinitionPutRequest DataDefinitionPutResponse
/data/definition/retrieve DataDefinitionRetrieveRequest DataDefinitionRetrieveResponse

The client will typically request /data/mash/default or /data/cast/default in order to initially populate the Player and Timeline components. If the user has yet to create a Mash or Cast then an empty one is returned, otherwise the most recently created one is returned. A request is also made to /data/mash/retrieve or /data/cast/retrieve to populate the SelectEditedControl component.

The client will likely also start requesting /data/definition/retrieve in order to populate the Browser component. This accepts a types key in its argument to limit each request to a subset of DefinitionTypes, as dictated by the currently selected BrowserPicker component.

The /data/*/put endpoints essentially act as UPSERT (update or insert) mechanisms, depending on the optional id key provided in the object being saved. If it's undefined or prefixed by the data.temporaryIdPrefix value that was provided in the client configuration, then a new unique identifier is generated and the object is inserted into storage, otherwise an existing object is updated.

File Server

The FileServer currently only supports a single endpoint that handles uploading of binary files:

Endpoint Request Interface Response Interface
/file/store FileStoreRequest FileStoreResponse

It is not typically called directly, but rather triggered as a callback from /rendering/upload (see below).

Rendering Server

The RenderingServer produces media files, with the help of Fluent FFmpeg. The processing is asynchronous, so the API supports both starting a rendering job and retrieving its current status:

Endpoint Request Interface Response Interface
/rendering/start RenderingStartRequest RenderingStartResponse
/rendering/status RenderingStatusRequest RenderingStatusResponse
/rendering/upload RenderingUploadRequest RenderingUploadResponse

The /rendering/start endpoint initiates a rendering process and returns a callback to /rendering/status. This endpoint keeps returning a callback to itself until the rendering process is complete. If a Mash was being rendering, a URL to the rendered file is returned in the final response.

Users are able to import new media into the Browser without server interaction.
The /rendering/upload endpoint is called for each new import as part of the saving process. This accepts metadata related to the file in its argument and returns two callbacks - one to /file/store to handle the file upload request itself, and another to /rendering/start that's executed afterwards. The later request may, depending on file type, specify several renderings producing multiple files. For instance, uploading a video file produces:

  • an icon file for display in the Browser component
  • an MP3 file containing the video's soundtrack
  • a sequence of images representing the video's frames

The client uses these files exclusively, while the server will use the original upload whenever it subsequently renders or streams the video. Once all the files are generated for an upload the /rendering/status endpoint returns one final callback to /data/definition/put which saves and returns a DefinitionObject representing it.

Streaming Server

The StreamingServer produces a video stream from a Cast, potentially pushing it to another server.

Endpoint Request Interface Response Interface
/streaming/start StreamingStartRequest StreamingStartResponse
/streaming/status StreamingStatusRequest StreamingStatusResponse
/streaming/delete StreamingDeleteRequest StreamingDeleteResponse
/streaming/preload StreamingPreloadRequest StreamingPreloadResponse
/streaming/cut StreamingCutRequest StreamingCutResponse
/streaming/webrtc StreamingWebrtcRequest StreamingWebrtcResponse
/streaming/rtmp StreamingRtmpRequest StreamingRtmpResponse
/streaming/remote StreamingRemoteRequest StreamingRemoteResponse
/streaming/local StreamingLocalRequest StreamingLocalResponse
Warning
This API is experimental and likely to change in subsequent versions, without being considered a 'breaking change' with regards to version number.