- 17 Jan 2024
- Print
Replace a video
- Updated on 17 Jan 2024
- Print
Replace a Video
In addition to using the REST API for video upload, you can also use it for replacing an existing video.
Similar to the video upload, video replacement also uses chunking. Note that the video will maintain the same metadata, channel ID and group ID.
To replace an existing video entity, you will create a new video source.
Then, you will receive the upload URL, which is then required for the uploading the replacement video.
Steps
To replace a video via the REST API, follow the steps listed below. While the first step is executed through the API, the upload is done via a separate asset-management endpoint.
Create a video source in a specified VideoManager
Upload a video
The following chapters describe how to perform each step using cURL to demonstrate usage in the examples.
The URLs in the methods throughout the following chapters refer to the general live instance of movingimage. Customers using VideoManager Pro on a custom domain must adjust the URLs accordingly.
Create a video source
To replace a video entity, you will need to first create a new video source. This can be done using the following cURL command:
curl --location 'https://api.video-cdn.net/v1/vms/<VideoManager_ID>/videos/<VIDEO_ID>/source' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer Token' \
--data '{
"uploadFilename": "fileName.mp4",
"file": {
"fileName": "fileName.mp4",
"size": 7378888
}
}'
Alternatively, you can use the following URL:
https://api.video-cdn.net/v1/vms/<VIDEOMANAGER_ID>/videos/<VIDEO_ID>/source
Parameters | Data Type | Description |
---|---|---|
VIDEOMANAGER_ID | Integer | mandatory: ID of the VideoManager, to which you intend to upload the video. |
Headers | ||
Authorization: Bearer Token | String | mandatory: Access token (see "Authentication" for more information). |
JSON Body | ||
uploadFileName | String | mandatory: Name of the file to be uploaded |
file | mandatory | |
fileName | String | mandatory: Filename of the video (see suffix note below), nested property of file |
size | String | mandatory: size of the file, nested property of file |
Suffix of the fileName
The suffix of the filename is used to determine the mime type. The following table lists all supported suffixes.
Suffix | Mime Type |
---|---|
mp4 | video/ mp4 |
mov | video/quicktime |
flv | video/x-flv |
wmv | video/x-ms-wmv |
mpg | video/mpeg |
avi | video/x-msvideo |
mp3 | audio/mpeg |
mpeg | video/mpeg |
m4v | video/x-m4v |
vob | video/mpeg |
f4v | video/x-flv |
wav | audio/vnd.wave |
3gp | video/3gpp |
rm | audio/x-pn-realaudio |
mts | video/mpeg |
m2v | video/mpeg |
wma | audio/x-ms-wma |
mxf | application/mxf |
m2p | video/mpeg |
m2t | video/mpeg |
mkv | video/x-matroska |
webm | video/webm |
qt | video/quicktime |
mp2 | audio/mpeg |
m2ts | video/mpeg |
ogv | video/ogg |
Response
The location data of the response header will return a URL containing the newly created video ID. You will need this video ID for the next step.
location: https://asset-in.video-cdn.net/chunks/env/prod/vms/<VideoManager_ID>/videos/<VIDEO_ID>?bucketId=<BUCKET_ID>&fileId=<FILE_ID>&userId=<USERID>&__token__=<SECURITY_TOKEN>
Parameter | Data Type | Description |
---|---|---|
VIDEOMANAGER_ID | Integer | ID of the VideoManager, in which you intend to upload the video. |
VIDEO_ID | String | Video ID of video entity |
BUCKET_ID | String | Primary bucket ID of video file |
FILE_ID | String | File ID of the new video file |
USER_ID | String | ID of user uploading the file |
SECURITY_TOKEN | String | Access token used to access protected resources |
Upload a replacement video
After generating the replacement upload URL, you can now replace your video. This is done using the chunked upload method with retry handling.
Token validity
The token in the upload URL is valid for four hours. This means that if the video upload takes longer than four hours to complete, an error will occur. If this happens, perform the "Get upload URL" request again to generate a new upload URL.
Chunked Upload
Sample
curl --location 'https://asset-in.video-cdn.net/chunks/env/prod/vms/<VideoManager_ID>/videos/<VIDEO_ID>?
bucketId=<BUCKET_ID>&fileId=<FILE_ID>&userId=<USERID>&__token__=<SECURITY_TOKEN>' \
--header 'Content-Type: application/octet-stream' \
--header 'Mi24-Upload-Current-Chunk: 1' \
--header 'Mi24-Upload-Total-Chunks: 1' \
--data '@/Users/<USERNAME>/Downloads/<FILE_NAME>.mp4'
URL | Description |
---|---|
UPLOAD_URL | The complete upload URL (see Getting the Upload URL) from the previous step. Note that the security token must be included as a parameter. |
Headers | |
Mi24-Upload-Total-Chunks | Total number of chunks. The example above uses 1 chunk. |
Mi24-Upload-Current-Chunk | Current chunk number, starting with 1. |
Content-Type | Specify "application/octet-stream" for the content type as in the example above. |
Command-line Options | |
--data-binary <@/FILENAME> | Upload as bytes of binary data and be sure to prefix the filename with "@". Then indicate the filename (and path if necessary) of the local video file to upload. |
Retry handling
If the response to a chunk upload request is not 201 CREATED
, the chunk must be retried. This can happen for a few reasons, such as:
Failure in the connection across the Internet
Expired upload token
Rate-limiting
Timeout in receiving a response from the API
To avoid these situations interrupting your upload, you should implement retry handling in your code. This means that you should:
Identify the conditions that would cause a chunk to fail. For example, you might retry if the response code is not
201 CREATED
.Implement a backoff strategy. This means that you should wait for an incrementally longer or random amount of time between each retry. This will help to prevent you from overloading the API with too many requests.
Set a limit on the number of times you retry. This will help to prevent you from getting stuck in an infinite loop if the chunk is unable to be uploaded.
Here are some examples of backoff strategies:
Fixed backoff: Wait for a fixed amount of time between each retry, such as 1 second.
Exponential backoff: Wait for an exponentially longer amount of time between each retry, such as 1, 2, 4, 8, 16, ... seconds.
Randomized backoff: Wait for a random amount of time between each retry, such as between 1 and 5 seconds.
The best backoff strategy for your specific needs will depend on the frequency of failures and the amount of time you are willing to wait for the upload to complete.
Java 11 Chunk Upload Example
Java 11 Chunk Upload Example
package mi.uploader;
import java.io.*;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
public class App {
public static Integer CHUNK_SIZE = 2_097_152;
public static Integer MAX_RETRIES = 10;
public static HttpClient client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_1_1)
.followRedirects(HttpClient.Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(20))
.build();
public static void main(String[] args) throws IOException, InterruptedException {
/*
Step 1. https://doc.movingimage.com/display/LT/Creating+a+Video+Entity
Step 2. https://doc.movingimage.com/display/LT/Getting+the+Upload+URL
Step 3. Upload
*/
URI url = URI.create("{URL obtained via API}");
File f = new File("sample_600s_25fps_1080.mp4");
InputStream inputStream = new FileInputStream(f);
long totalChunks = calculateChunks(f.length());
for (int i = 1; i <= totalChunks; i++) {
byte[] data = new byte[CHUNK_SIZE];
inputStream.read(data);
int statusCode = 0;
int retryAttempts = 0;
do {
if (statusCode >= 500) {
Thread.sleep(2000);
}
if (retryAttempts++ >= MAX_RETRIES) {
throw new RuntimeException("Upload failed. Please try again later.");
}
HttpRequest request = HttpRequest.newBuilder()
.POST(HttpRequest.BodyPublishers.ofByteArray(data))
.uri(url)
.setHeader("Mi24-Upload-Total-Chunks", String.valueOf(totalChunks)) // add request header
.setHeader("Mi24-Upload-Current-Chunk", String.valueOf(i)) // add request header
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
statusCode = response.statusCode();
System.out.println("Status: "+statusCode);
} while (statusCode >= 500);
}
System.out.println("Done");
}
public static long calculateChunks(long fileSize) {
long remainder = fileSize % CHUNK_SIZE;
int totalChunks = Math.toIntExact(fileSize / CHUNK_SIZE);
if (remainder > 0) {
totalChunks = totalChunks + 1;
}
return totalChunks;
}
}