Skip to content

Instantly share code, notes, and snippets.

@sbis04

sbis04/blog.md Secret

Created Feb 17, 2021
Embed
What would you like to do?

Integrating video streaming with Flutter using Mux

Video streaming is an important aspect of various kinds of applications, ranging from social media apps like TikTok and Instagram (Reels), which engage users with short video clips, to proprietary video-sharing applications similar to YouTube, which allow users to share medium-length to long videos.

Though a video streaming platform of some kind is an awesome addition to some apps and a spotlight feature in a few apps, managing the infrastructure and handling all the aspects of streaming is a really cumbersome job.

Some of the main steps involved in video streaming are:

  • Encoding and decoding the video
  • Managing video database storage
  • Support for multiple video formats
  • Distribution

Basic streaming pipeline of Mux

In this article, you will see how Mux helps to handle all the complex steps of the video streaming process and how to integrate it with Flutter.

Getting started

Mux is an API-based video streaming service that handles the encoding and decoding of a video, distributing it to users. On top of that, it also provides a lot of additional features, like subtitles, thumbnails, GIFs, watermarking, etc. It has a data tracking API, which helps to monitor the video streaming performance as well.

Though Mux helps in streaming the video, it doesn't provide any storage. So, you have to provide the URL where you have stored the video.

To get started using Mux, create an account here.

When you log in to Mux, it will take you to the Dashboard.

You can try adding a video by going to the Add a video file section and running the POST request with the URL of the video file.

The videos are stored in the Assets section of Mux.

In order to use the Mux API, you will need to generate an API Access Token from here.

Fill in the details properly, and click on Generate Token.

This will generate a Token ID and Token Secret for API authentication.

Copy these files and store them in a private folder. (Don't commit these keys to the version control system – add them to .gitignore.)

Now, let's dive into the main part, integrating the Mux API with a Flutter app.

App overview

We will build a simple Flutter app containing just two pages:

  • HomePage
  • PreviewPage

Plugins

First of all, let's add the plugins that we need for building this app to the pubspec.yaml file.

  • dio – for making HTTP POST and GET requests
  • video_player – for previewing the video to be streamed
  • intl – to format DateTime objects

Building the backend

It's always better to design the backend of an app first and then structure the UI based on the backend.

We need to build a simple API server to send the API requests to MUX. Though sending GET and POST requests directly from the client (mobile device) to the MUX server is convenient, it leaves massive security hole which may expose your MUX credentials to anyone who uses the app.

You can get a basic API server code written in node.js containing some functions that we require for our implementation here.

Now, inside the root folder you have to create a file called .env with the following content:

https://gist.github.com/8c9904da55749ab566b13ef791699e29

Store your Token ID and Token Secret in this file and add it to .gitignore. The API server will automatically pick up the credentials from here.

For testing your can just run it on your local machine using:

https://gist.github.com/a98ba67d62b7fb604b4abd93ffb93395

This will run the server on port 3000, and you can access it from the client app using the URL:

https://gist.github.com/c57dc9e365c39c086efa60e717860769

The backend of this app will deal with the API calls (i.e., GET and POST requests), so this will mainly consist of two parts:

  • Mux client
  • Model classes

Mux client

We will start building the client class by initializing the Dio. Create a MUXClient class inside a new file called mux_client.dart.

Now, create a Dio object:

https://gist.github.com/37b552ed21213076b0a82db48e366736

Add a method initializeDio():

https://gist.github.com/0325f3f20702056913c665425bf2316e

Here, we will configure the Dio but we don't need to perform any kind of authorization from the client as it is already being done from our API server.

Create a string.dart file containing some constants that we require afterwards:

https://gist.github.com/38198e6dad60d9a1874379eaab0bdac3

The initializeDio() method will look like this:

https://gist.github.com/73e2c5e6ac0c0220ad76063d8259dd5d

Next, we need a method for storing the video to Mux by sending a POST request to the endpoint /assets. For this, create a method called storeVideo(), and pass the video URL to it as a parameter. This method will return the VideoData after processing on Mux is complete.

https://gist.github.com/43f1ce5f6703f52a57cc163ea0748859

Here, I have used the checkPostStatus() method to track the status of the video that is being processed until it is ready. A GET request is sent to the endpoint /asset with the video ID as the query parameter to get a VideoData object containing the status information.

https://gist.github.com/254c7bfd693364fcf71c7651a18f6be9

We will define one more method, getAssetList(), for retrieving a list of all the videos that are stored on Mux by sending a GET request to the endpoint /assets. It will return an AssetData object.

https://gist.github.com/a47f61c80264a529dd2fba947c7b5c1b

You may be wondering what the VideoData and AssetData classes are – they are just model classes for easily parsing the JSON data returned by the Mux API calls.

Model class

There are two main model classes that we need:

  • VideoData: parses the data returned for each video file
  • AssetData: parses the data returned for the list of assets (or videos)

You can define the model classes in this structure:

The VideoData class:

https://gist.github.com/c7abd98cf4cf398f59a5b5989c615409

The AssetData class:

https://gist.github.com/19c576905f9d977e6cb3f73867ec430d

Both of them have three common sub-classes (Data, PlaybackId and Track).

The Data class looks like this:

https://gist.github.com/71494738899dec75e862db36b650c4da

PlaybackId is given below:

https://gist.github.com/1e205a84677f19abdecf4c58b762efa6

The Track class is as follows:

https://gist.github.com/efb91424830872e2db3a48c247938162

HomePage

The HomePage will contain a TextField for taking the video URL as input and a button for uploading it to Mux. It also displays the list of all video assets present on Mux.

The HomePage will be a StatefulWidget. First, we will call the initializeDio() method and initialize a TextEditingController and a FocusNode inside the initState() method.

https://gist.github.com/738824066982577216d42a172907cca4

Let's add a TextField and a RaisedButton for storing the video on Mux. The button will be replaced by a Text widget and a CircularProgressIndicator while the storage is in progress.

https://gist.github.com/42c79e94b97a00eb74ad249eab2b57ba

For displaying the list of all videos, you can add a ListView widget to the Column:

https://gist.github.com/2d9fad03931418352f851968f26bef96

Here, we have parsed and formatted the DateTime object to display as a proper String. The thumbnail URL is created by using the playback ID and specifying the image type and size. The VideoTile widget is used for generating the UI for each list item. The class looks like this:

https://gist.github.com/f63e2da135b14b884bcc76d8639336f5

Each of the tiles is wrapped in an InkWell widget that has an onTap method for navigating to the PreviewPage, passing the asset data present at that index.

PreviewPage

This page will be used for viewing the video using the stream URL and for showing some information related to the video file.

There will be a video player at the top of the page, followed by a list of Text widgets for displaying all of the information.

We have to create a VideoPlayerController and initialize it inside the initState() of this class.

https://gist.github.com/de7c04348d29f4ee3801abdade9252d7

I have used the Mux stream URL for loading and initializing the video controller. Also, _controller.play() is used to start playing the video as soon as it is initialized.

The video player is created inside the Column using the following:

https://gist.github.com/a1c5802cb74bccb0f90f87843adf3348

For displaying the information, we can add this to the Column after the video player widget:

https://gist.github.com/dcb147e5ac63c191fe33828873296f83

The InfoTile widget is used for creating the UI of each item in the Column:

https://gist.github.com/93713d0f61d9b593a97f4347495a6e96

Congratulations, you have created a Flutter app for streaming videos.

Testing

Verifying whether you are getting a correct response from an API call while using a third-party service is very important. We will create some tests to mock the API responses and verify whether they are being correctly parsed.

You can use the plugin http_mock_adapter, which is created with a combination of dio and mockito. It is very effective when used alongside the dio plugin.

We will not go deep into the tests in this article. First of all, create a new file inside the test folder called mux_api_test.dart.

Let's define three tests here:

https://gist.github.com/a7b15f4378e2f0cefcc8ac3ec6b0520b

You can run all the tests by using the command:

https://gist.github.com/cb3c38ce2d55b63c8438f7b4e07eaa79

Running on Codemagic

To maintain a productive development workflow, you should always run tests on a CI/CD service. You can set up and run tests on Codemagic in just a few minutes. To get started with Codemagic CI/CD, check out the blog post here.

Conclusion

This article covers all the aspects related to integrating Mux with Flutter and using it to stream videos, but while implementing it, you will also need a place to store the videos. Firebase Storage is a good option for this, and it works seamlessly with Mux by simply passing the URL of the video file. Don't forget to explore the Mux API, as it provides many more customizations that you can apply while streaming a video.

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment