Encode Quickstart for Java

Video streaming is the most common way for users to consume video content. Efficient video streaming is achieved through optimizations like segmenting videos into different framerates for smooth playback, even when network bandwidth changes. Such optimizations are done by encoding the video.

This Quickstart shows how to programmatically encode your first video for streaming using Bitmovin's Java SDK.

Through this Quickstart, you will learn how to build a command-line Java app that:

  • encodes a .mov video from a publicly-accessible GCS folder to DASH format; and
  • stores the resulting DASH video, audio, and manifest files on an S3 bucket.

This app can be useful as the basis for building more complex tools, such as those used in video processing pipelines.

The following subsections describe everything necessary to perform this process:

Prerequisites

The following items are required to complete this tutorial:

  • Bitmovin Account. You can create a free trial account here.
  • S3 bucket to store the encoded files. You can sign up for a free account here.
  • Java SDK 1.8+
  • Compiler/IDE for building Java apps. This Quickstart uses IntelliJ as the IDE.
  • Maven-based Java project.

πŸ“˜

Note

Documentation for Bitmovin's Java API is located here.

Step 1 – Prepare Your pom.xml File

To use the Bitmovin Java SDK, you must first add it, along with several other dependencies to your project's pom.xml file as shown below:

πŸ“˜

Note

You may first need to add the dependencies block to your pom.xml file.

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    ...

    <dependencies>
        <dependency>
            <groupId>com.bitmovin.api.sdk</groupId>
            <artifactId>bitmovin-api-sdk</artifactId>
            <version>1.112.0</version>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-slf4j</artifactId>
            <version>11.8</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.10</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.33</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>
    </dependencies>

    ...

</project>

πŸ“˜

Note

The Bitmovin SDK uses SLF4J for logging.

Step 2 – Copy Your Bitmovin API Key

You will need your Bitmovin API key in order to use the API. Follow the steps below to find the key in your Bitmovin dashboard:

  1. Open your Bitmovin dashboard in a browser and log in.
  2. Click your name at the top right and select Account Settings:
1299
  1. Locate the Api Keys section on the right and click Copy to copy your API key:
1286

You will use this API key next, when you initialize the SDK.

Step 3 – Initialize the SDK

Follow the steps below to import and initialize the SDK:

  1. Open your .class file containing your app's main() method and add the following imports:
import com.bitmovin.api.sdk.BitmovinApi;
import com.bitmovin.api.sdk.model.*;
import feign.slf4j.Slf4jLogger;
import feign.Logger;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
  1. Instantiate a BitmovinApi object in your main() method using BitmovinApi.builder replacing <API_KEY> with the Bitmovin API key you copied earlier:
public class MyEncoderApp {


    public static void main(String[] args){
        BitmovinApi bitmovinApi = BitmovinApi.builder()
                .withApiKey("<API_KEY>")
                .withLogger(new Slf4jLogger(), Logger.Level.BASIC) // set the logger and log level for the API client)
                .build();


    }
}

Step 4 – Create an Input

An Input stores the settings required to access the video that you want to encode. It will be used later in this Quickstart to download the file for encoding.

Instantiate an HttpsInput object in your main() method, set the host URL of the video to encode, and use it to create the final Input object:

public class MyEncoderApp {
    
    public static void main(String[] args){
        ...

        //Create and configure the Input
        HttpsInput input = new HttpsInput();
        input.setHost("https://storage.googleapis.com");
      
        //Call create() which adds the input in the Bitmovin's cloud and assigns an ID
        //We'll use the returned object in subsequent steps
        input = bitmovinApi.encoding.inputs.https.create(input);    
    }
}

Step 5 – Create an Output

An Output stores the settings required to access the location where the encoded video and audio segments, along with the manifests, will be written to. It will be used later in this Quickstart to upload these files, and can be used by a player to play the video.

Follow the steps below to create an Output:

  1. Instantiate an S3Output object, enter your S3 access and secret keys, and specify the name of your bucket.
  2. Use the object to create the final Output object.
  3. Get the Output's ID. This ID will be used later to specify the output settings for writing the encoded files.

The following example shows the API calls to perform these steps:

public class MyEncoderApp {
    
    public static void main(String[] args){
        ...
        //Create and configure the Output
        S3Output output = new S3Output();
        output.setAccessKey("AKI...");
        output.setSecretKey("7WBM...");
        output.setBucketName("mytestbucket");

        //Call create() which adds the output in the Bitmovin's cloud and assigns an ID
        output = bitmovinApi.encoding.outputs.s3.create(output);
      
        //Get the Output's ID for use in subsequent API calls that need to write files to the S3 bucket
        String outputId = output.getId();
     }
}

Step 6 – Configure the Codecs

In the following subsections, you will create and configure the codecs for both the video and audio. This allows you to define properties like the name, bit rate, etc., that the encoder will use:

πŸ‘

Tip

We support a multitude of codecs, including H264, H265, VP9, AV1, and many more. See here for a complete list.

Configure a Video Codec

Here you will create a video codec configuration. This specifies properties like the name, bit rate, and resolution to use when encoding the video. This section shows how to select H264 video encoding.

πŸ“˜

Note

You can create multiple configuration objects to define different codec settings, and pass them to the encoder later on to batch encode your video and produce different outputs.

Follow the steps below to create and configure a video codec configuration:

  1. Instantiate an H264VideoConfiguration object and configure it with a name, bit rate, and resolution.
  2. Specify a quality preset that defines the desired quality for the encoded video.
  3. Use the configuration to create the final video codec configuration object.

The following example shows the API calls to perform these steps:

public class MyEncoderApp {

    public static void main(String[] args){

        ...
         
        //Create an H264 encoding configuration and configure it
        H264VideoConfiguration videoCodecConfiguration1 = new H264VideoConfiguration();
        videoCodecConfiguration1.setName("Getting Started H264 Codec Config 1");
      
        //Set the bitrate to 1.5 Mbps
        videoCodecConfiguration1.setBitrate(1500000L);
        videoCodecConfiguration1.setWidth(1024);
      
        //Configure the desired video quality
        videoCodecConfiguration1.setPresetConfiguration(PresetConfiguration.VOD_STANDARD);

        //Create the final codec configuration object
        videoCodecConfiguration1 = bitmovinApi.encoding.configurations.video.h264.create(videoCodecConfiguration1);
     }
}

Configure an Audio Codec

Similar to the video codec configured above, an audio codec configuration specifies how to encode the video's audio (e.g., desired audio bit rate). This section shows how to configure an AAC audio encoding.

Follow the steps below to create and configure an audio codec configuration:

  1. Instantiate an AACAudioConfiguration object and configure it with a name and bit rate.
  2. Use the configuration to create the final audio codec configuration object.

The following example shows the API calls to perform these steps:

public class MyEncoderApp {

    public static void main(String[] args){
       
        ...
        //Create an AAC encoding configuration and configure it 
        AacAudioConfiguration audioCodecConfiguration = new AacAudioConfiguration();
        audioCodecConfiguration.setName("Getting Started Audio Codec Config");
      
        //Set the bit rate to 128 kps
        audioCodecConfiguration.setBitrate(128000L);

        //Create the final codec configuration object
        audioCodecConfiguration = bitmovinApi.encoding.configurations.audio.aac.create(audioCodecConfiguration);
    }
}

Step 7 – Specify a Regional Bitmovin Encoder

An Encoding is a collection of resources (inputs, outputs, codec configurations, etc.) mapped together. It also specifies which of Bitmovin's global cloud encoders to use.

This section shows how to create an encoding and specify our Western Europe encoder. Choosing a region close to you and/or your target cloud storage can help reduce the amount of time it takes to transfer files.

The encoding will then be used in subsequent sections to map other resources together.

πŸ“˜

Note

If you don't specify a region, our encoder takes the region closest to your input and output.

Follow the steps below to create the Encoder:

  1. Instantiate an Encoding and set the name and cloud region.
  2. Use the encoding to create the final encoding object.

The following example creates an Encoding and sets the region to Western Europe:

public class MyEncoderApp {

    public static void main(String[] args){

        ...
        //Create an Encoding object and set the region to Western Europe
        Encoding encoding = new Encoding();
        encoding.setName("Getting Started Encoding");
        encoding.setCloudRegion(CloudRegion.GOOGLE_EUROPE_WEST_1);

        //Create the final encoding object
        encoding = bitmovinApi.encoding.encodings.create(encoding);
    }
}

πŸ“˜

Note

The encoding's name (Getting Started Encoding in this example) will appear in the Dashboard's Encoding screen later on after encoding begins.

Step 8 – Create Streams

Streams map your input video and audio files to the video and audio codec configurations you defined above.

The following subsections show how to create and configure these streams:

Create a Video Stream

This section shows how to map our example video file (tears_of_steel_1080p.mov) stored on our GCS folder at https://storage.googleapis.com/bitmovin-sample-content/tears_of_steel_1080p.mov to the video codec configuration we defined above. The process involves two objects: a StreamInput to map the video's path to the Input we defined above and a Stream to map the video codec configuration to the StreamInput.

Follow the steps below to create a video stream:

  1. Instantiate a StreamInput and pass in the ID of the Input we defined above and the relative path of the input video file to map it to.
  2. Instantiate a Stream passing in the video codec created above and the StreamInput (created in the previous step) to map it to.
  3. Use the stream to create the final video Stream object.

The following example shows the API calls to perform these steps:

public class MyEncoderApp {

    public static void main(String[] args){

        //Set the relative path of the video to encode
        String inputPath = "/bitmovin-sample-content/tears_of_steel_1080p.mov";

        //Create an stream input for the video data of the input video file
        StreamInput videoStreamInput = new StreamInput();
        videoStreamInput.setInputId(input.getId());
        videoStreamInput.setInputPath(inputPath);
      
        //Configure how to find the video stream within the input file
        //Use AUTO which selects the first available video input stream of the input file.
        videoStreamInput.setSelectionMode(StreamSelectionMode.AUTO);

        //Create a stream to map the input video file to our video codec
        Stream videoStream1 = new Stream();
        videoStream1.setCodecConfigId(videoCodecConfiguration1.getId());
        videoStream1.addInputStreamsItem(videoStreamInput);
        
        //Create the final video stream object
        videoStream1 = bitmovinApi.encoding.encodings.streams.create(encoding.getId(), videoStream1);

    }
}

Create an Audio Stream

Similar to the video stream created above, an audio stream from the video must be mapped to the audio codec configured we created above.

Follow the steps below to create an audio stream:

  1. Instantiate a StreamInput and pass in the ID of the Input we defined above and the relative path of the input video file to map it to.
  2. Instantiate a Stream passing in the audio codec created above and the StreamInput (created in the previous step) to map it to.
  3. Use the stream to create the final audio Stream object.

The following example shows the API calls to perform these steps:

public class MyEncoderApp {

    public static void main(String[] args){
      
        ...
        //Create an stream input for the audio data of the input video file
        StreamInput audioStreamInput = new StreamInput();
        audioStreamInput.setInputId(input.getId());
        audioStreamInput.setInputPath(inputPath);
      
        //Configure how to find the audio stream within the input file
        //Use AUTO which selects the first available audio input stream of your input file.      
        audioStreamInput.setSelectionMode(StreamSelectionMode.AUTO);

        //Create a stream to map the input video file to our audio codec
        Stream audioStream = new Stream();
        audioStream.setCodecConfigId(audioCodecConfiguration.getId());
        audioStream.addInputStreamsItem(audioStreamInput);

        //Create the final audio stream object
        audioStream = bitmovinApi.encoding.encodings.streams.create(encoding.getId(), audioStream);      
      
    }
}

Step 9 – Create Muxings

A Muxing (short for multiplexing) defines the container format to use for the encoded video and audio files (segmented TS, progressive TS, MP4, FMP4, etc.). The muxing process combines encoded bit streams into the containers that can be written to file or streamed as livestreams. A Muxing requires a Stream, an Output, and the output path where the generated segments will be written to.

FMP4 Muxings are used for DASH manifest representations and TS Muxings for HLS playlist representations. The following subsections show how to create FMP4 Muxings:

Prepare Video Permissions

Before creating the video Muxing, set the permissions for the video in cloud storage. The example below shows how to set public read permission so that the video can be viewed in a browser as an anonymous user. Permissions are set by storing them in a collection of AclEntry objects which will be passed to the video Muxing in a subsequent step:

public class MyEncoderApp {
    public static void main(String[] args){       

       ...
       // Prepare the list of AclEntries
       AclEntry aclEntry = new AclEntry();
      
       //Set public read access
       aclEntry.setPermission(AclPermission.PUBLIC_READ);
       List<AclEntry> aclEntries = new ArrayList<AclEntry>();
       aclEntries.add(aclEntry);
        
   }
}

Create a Video Muxing

Follow the steps below to create and configure an output for the encoding, muxing stream, and the FMP4 muxing:

  1. Prepare the following settings that will be used to configure the objects in subsequent steps:
public class MyEncoderApp {
    public static void main(String[] args){       
        ...
          
        //Prepare Segment configuration  
        double segmentLength = 4D;                 //Length of the fragments (in seconds)
        String outputPath = "myvideo";             //name of the subfolder in the output S3 bucket to place the encoded output to
        String segmentNaming = "seg_%number%.m4s"; //Wildcard name for the segment files
        String initSegmentName = "init.mp4";       //Name to use for the initial segment
   }
}
  1. Instantiate and configure an EncodingOutput object that handles writing the video segments to their final destination on the S3 bucket:
public class MyEncoderApp {
    public static void main(String[] args){       
        ...
          
        EncodingOutput videoMuxingOutput = new EncodingOutput();
      
        //Configure the output to use the S3 bucket we defined earlier
        videoMuxingOutput.setOutputId(outputId); 
      
        //Set the output path within the S3 subfolder to place the segments
        videoMuxingOutput.setOutputPath(String.format("%s%s", outputPath, "/video/1024_1500000/fmp4/"));
        
        //Set the permissions we created earlier
        videoMuxingOutput.setAcl(aclEntries);          
   }
}
  1. Instantiate a MuxingStream object and map it to the video stream:
public class MyEncoderApp {
    public static void main(String[] args){       
        ...
        
        //Map the video stream to the video Muxing
        MuxingStream muxingStream1 = new MuxingStream();
        muxingStream1.setStreamId(videoStream1.getId());

   }
}

πŸ“˜

Note

A Muxing can contain one or more Streams. The association is done through MuxingStream objects. For more information see this topic.

  1. Instantiate an Fmp4Muxing object to perform the muxing and configure how it segments the video, the muxing stream to write to, and the output stream on which to write the segments:
public class MyEncoderApp {
    public static void main(String[] args){       
        ...
          
        //Create the video muxing for Fmp4
        Fmp4Muxing fmp4VideoMuxing = new Fmp4Muxing();
      
        //Configure the segment properties using the variables defined earlier
        fmp4VideoMuxing.setSegmentLength(segmentLength);
        fmp4VideoMuxing.setSegmentNaming(segmentNaming);
        fmp4VideoMuxing.setInitSegmentName(initSegmentName);
       
        //Set the muxing stream 
        fmp4VideoMuxing.addStreamsItem(muxingStream1);   
      
        //Set the muxing output that directs the muxing segments to our S3 bucket
        fmp4VideoMuxing.addOutputsItem(videoMuxingOutput);

        //Map the muxing to our cloud encoder (set earlier to our Western European encoder)
        bitmovinApi.encoding.encodings.muxings.fmp4.create(encoding.getId(), fmp4VideoMuxing);          
   }
}

Create an Audio Muxing

  1. Instantiate a MuxingStream object:
public class MyEncoderApp {
    public static void main(String[] args){       
        ...
          
        //Mapp the audio stream to the audio Muxing 
        MuxingStream fmp4AudioMuxingStream = new MuxingStream();
        fmp4AudioMuxingStream.setStreamId(audioStream.getId());          
   }
}
  1. Instantiate and configure an EncodingOutput object that handles writing the audio segments to their final destination on the S3 bucket:
public class MyEncoderApp {
    public static void main(String[] args){     
      
        ...
          
        EncodingOutput audioMuxingOutput = new EncodingOutput();
       
        //Configure the output to use the S3 bucket we defined earlier
        audioMuxingOutput.setOutputId(outputId);
      
        //Set the output path within the S3 subfolder to place the segments
        audioMuxingOutput.setOutputPath(String.format("%s%s", outputPath, "/audio/128000/fmp4/"));
        
        //Set the permissions
        audioMuxingOutput.setAcl(aclEntries);
   }
}
  1. Instantiate an Fmp4Muxing object to perform the muxing and configure how it segments the audio, the muxing stream to write to, and the output stream on which to write the segments:
public class MyEncoderApp {
    public static void main(String[] args){       
        ...
          
        //Create the audio muxing for Fmp4
        Fmp4Muxing fmp4AudioMuxing = new Fmp4Muxing();
      
        //Configure the segment properties using the variables defined earlier
        fmp4AudioMuxing.setSegmentLength(segmentLength);
        fmp4AudioMuxing.setSegmentNaming(segmentNaming);
        fmp4AudioMuxing.setInitSegmentName(initSegmentName);
      
        //Set the muxing stream 
        fmp4AudioMuxing.addStreamsItem(fmp4AudioMuxingStream);
      
        //Set the muxing output that directs the muxing segments to our S3 bucket
        fmp4AudioMuxing.addOutputsItem(audioMuxingOutput);

        //Map the muxing to our cloud encoder (set earlier to our Western European encoder)
        bitmovinApi.encoding.encodings.muxings.fmp4.create(encoding.getId(), fmp4AudioMuxing);          
          
   }
}

Step 10 – Create a Manifest

This section creates and configures a default DASH manifest whereby the encoder determines how to best generate the manifest based on the resources created by the encoding.

Follow the steps below to create a DASH manifest:

  1. Instantiate and configure an EncodingOutput object that handles writing the manifest to its final destination on the S3 bucket:
public class MyEncoderApp {
    public static void main(String[] args){      
            
        ...
          
        final EncodingOutput manifestOutput = new EncodingOutput();
      
        //Configure the output to use the S3 bucket we defined earlier
        manifestOutput.setOutputId(outputId);
      
        //Use the subfolder on the S3 bucket we defined earlier
        manifestOutput.setOutputPath(outputPath);
   }
}
  1. Set the permission and scope for the manifest:
public class MyEncoderApp {
    public static void main(String[] args){      
            
        ...
        final AclEntry aclEntryManifest = new AclEntry();
        aclEntryManifest.setPermission(AclPermission.PUBLIC_READ);
        aclEntryManifest.setScope("*");        
        manifestOutput.setAcl(Arrays.asList(aclEntryManifest));          
   }
}

πŸ“˜

Note:

Dash manifests can have multiple outputs (e.g., to upload the manifest to multiple servers like S3 and GCS) which is why a collection of AclEntry objects is used.

  1. Instantiate a DashManifestDefault object and configure its name, cloud encoder, and version:
public class MyEncoderApp {
    public static void main(String[] args){      
            
        ...
          
        DashManifestDefault dashManifest = new DashManifestDefault();
      
        dashManifest.setManifestName("stream.mpd");
        dashManifest.setEncodingId(encoding.getId());
        dashManifest.setVersion(DashManifestDefaultVersion.V2);
        dashManifest.setOutputs(Arrays.asList(manifestOutput));

        dashManifest = bitmovinApi.encoding.manifests.dash.defaultapi.create(dashManifest);          
          
   }
}
  1. Instantiate a ManifestResource object using the DASH manifest:
public class MyEncoderApp {
    public static void main(String[] args){      
            
        ...
        final ManifestResource dashManifestResource = new ManifestResource();
      
        //Create a ManifestResource. Bitmovin will determine a manifest that makes the
        //most sense based on the encoded video and audio outputs, without requiring
        //further manual configuration.
        dashManifestResource.setManifestId(dashManifest.getId());          
   }
}

Step 11 – Encode the video

Everything is now in place and the video encoding process can begin.

Follow the steps below to encode the video and produce the final output on the S3 bucket:

  1. Create a StartEncodingRequest and configure it with the manifest to use for encoding.

  2. Set the manifest generator version.

  3. Start the encoding.

The following example shows the API calls to perform these steps:

public class MyEncoderApp {
    public static void main(String[] args){      
      
        ...
          
        //Start the encoding process using the manifest configuration we defined earlier
        final StartEncodingRequest startEncodingRequest = new StartEncodingRequest();        
        startEncodingRequest.setVodDashManifests(Arrays.asList(dashManifestResource));
      
        //Encode the video
        bitmovinApi.encoding.encodings.start(encoding.getId(), startEncodingRequest);        
   }
}

Step 12 – Monitor the Encoding Process

After invoking bitmovinApi.encoding.encodings.start() our cloud encoder starts encoding the video.

The following subsections describe how to monitor the encoding's progress:

Monitor Encoding Programmatically

This section shows how to add a simple loop to your code that periodically requests the encoding status until the encoding process ends. This example uses Thread.sleep() in the loop to wait for several seconds between each check.

Follow the steps below to programmatically monitor the encoding's progress:

  1. Modify your main() method to throw InterruptedException. This is required for Thread.sleep().
  2. Add a loop after the call to bitmovinApi.encoding.encodings.start() that does the following:
    • Invoke bitmovinApi.encoding.encodings.status() to get a Task object.
    • Invoke the Task object's getStatus() method to get the Status.
    • Put the thread to sleep for several seconds before repeating.
    • Continue looping when the encoding is in progress.

The following example shows the API calls to perform these steps:

public class MyEncoderApp {

    //Add throws InterruptedException as required by Thread.sleep() below
    public static void main(String[] args) throws InterruptedException {
      
        ...
        //Start the encoding
        BitmovinResponse response = bitmovinApi.encoding.encodings.start(encoding.getId(), startEncodingRequest);

        //Loop until the encoding processes ends
        //While in progress the status can be queued, running, or created
        Status encodingStatus;
        Task encodingTask;
        do
        {
            //Get the encoding Task
            encodingTask = bitmovinApi.encoding.encodings.status(encoding.getId());
          
            //Use the Task to find out the status
            encodingStatus = encodingTask.getStatus();
          
            //Sleep for 4 seconds
            Thread.sleep(4000);

        } while((encodingStatus == Status.QUEUED) || (encodingStatus == Status.RUNNING) || (encodingStatus == Status.CREATED));
   }
}

Monitor Encoding in the Dashboard

Follow the steps below to monitor the progress of the encoding from the Bitmovin dashboard:

  1. Open a browser and navigate to: https://bitmovin.com/dashboard.

  2. Navigate to the menu bar on the left and select Encoding > encodings.

264
  1. Locate your encoding by name in the Encoding list and click on it. The encoding name is that which was set earlier using encoding.setName("Getting Started Encoding");:
1229

The encoding details screen displays and the Event Timeline section which updates as encoding progresses:

1109
  1. Open your S3 bucket dashboard in a browser after encoding successfully completes and verify that the encoded files are present.

This concludes the Encoding Quickstart. You have now successfully encoded a video using the Bitmovin Java SDK.

Next, move on to the Player Quickstart for JavaScript tutorial where you'll learn how to embed and playback the video from a simple web page.