KINOPIPE WITH JAVA

Video editing from Java, without FFmpeg on your machine.

Trim, resize, compress, convert, caption and transcribe by calling one HTTP endpoint per operation. Parameters are validated before anything renders, so a bad call fails as a typed error rather than a broken encode.

What running FFmpeg from Java usually costs

  • A binary in the container image, which grows the image and puts a native dependency into a deployment that had none.
  • The wrappers that bundle FFmpeg for you ship one build per platform, so the size comes back with a different name.
  • ProcessBuilder hands you an exit code and a stream of stderr, so a wrong argument becomes a string to parse rather than a validation failure.

Trim a clip and wait for the file

Java
import java.net.URI;
import java.net.http.*;
import java.time.Duration;

public class Kinopipe {
    private static final String BASE = "https://kinopipe.com/api/v1";
    private static final HttpClient CLIENT = HttpClient.newHttpClient();
    private static final String KEY = System.getenv("KINOPIPE_API_KEY");

    static String send(HttpRequest.Builder builder) throws Exception {
        HttpRequest request = builder
            .header("Authorization", "Bearer " + KEY)
            .header("Content-Type", "application/json")
            .timeout(Duration.ofSeconds(30))
            .build();
        return CLIENT.send(request, HttpResponse.BodyHandlers.ofString()).body();
    }

    public static void main(String[] args) throws Exception {
        String body = """
            {
              "inputs": [{ "id": "main", "url": "https://example.com/interview.mp4" }],
              "options": { "start": 12, "end": 48 }
            }
            """;

        String started = send(HttpRequest.newBuilder(URI.create(BASE + "/tools/trim-video"))
            .POST(HttpRequest.BodyPublishers.ofString(body)));
        String jobId = started.split("\"jobId\":\"")[1].split("\"")[0];

        while (true) {
            String job = send(HttpRequest.newBuilder(URI.create(BASE + "/jobs/" + jobId)).GET());
            if (job.contains("\"status\":\"succeeded\"") || job.contains("\"status\":\"failed\"")) {
                System.out.println(job);
                return;
            }
            Thread.sleep(2000);
        }
    }
}
  • java.net.http is in the JDK from 11, so nothing above needs a dependency. Use Jackson or Gson rather than splitting strings once this is more than an example.
  • A split job returns every segment under outputs rather than output, which matters if you call split-video or split-video-by-scenes.
  • Send an Idempotency-Key header when you retry, and the retry returns the original job instead of paying for a second render.
Or let an agent write the call
The same operations are exposed over MCP, so an agent in your editor discovers them and calls them directly.

FAQ

Why not ProcessBuilder and a local FFmpeg?

It works when you own the machine and accept the native dependency. The trade is an image that carries a binary and errors that arrive as text on stderr instead of as validation before the render.

Is there a Java SDK?

Not yet. The surface is a bearer token, one POST per operation and a GET to poll, which is why the example above needs nothing but the JDK.

Can I run several edits in parallel?

Yes. Jobs are independent, so submit them from a thread pool and poll each. Credits are reserved per job and refunded when a render fails.