Streaming Video from a PC Webcam to an Amazon Kinesis Video Stream Using GStreamer

Figure showing the Kinesis Video Streams service that receives media data from a camera and a media file.

The Amazon Kinesis Video Streams service makes it easy to securely stream video from different devices to the AWS Cloud for real-time video processing, machine learning (ML), analytics, playback, and storage.

Using the Kinesis Video Streams Producer Library for C++, Java, or Android, you can integrate a wide range of devices with Kinesis Video Streams.

If you do not want to develop applications using the Kinesis Video Streams Producer Library, the simplest way to send media data to Kinesis Video Streams is to use the Kinesis Video Streams GStreamer plugin. GStreamer is a popular multimedia framework that is available on a variety of operating systems including Windows, Linux, macOS, and Android.

The Kinesis Video Streams GStreamer plugin is a GStreamer sink element, kvssink. It is included with the Kinesis Video Streams C++ Producer SDK. To use it, choose one of the following options:

  • Download and build the GStreamer plugin.
    It can take some time, but this is what you should normally do if you do not just intend to play around with the Kinesis Video Streams service.
  • Run on your system the official Docker image with the ready-to-use GStreamer plugin.
    This requires Docker to be installed on your system. Also, this solution can have limitations on some operating systems. For example, streaming video from a USB camera on macOS in a Docker container is not supported.
  • Install on your system only GStreamer.
    Launch a helper EC2 instance in the cloud. Run on this instance the official Docker image with the ready-to-use GStreamer plugin.
    Send media data from a PC webcam or a media file to the EC2 instance over an SSH tunnel using GStreamer. The Kinesis Video Streams GStreamer plugin running in a Docker container on the EC2 instance, in turn, puts data to a Kinesis Video stream.

This blog post describes the latter option that allows you to get started with sending test media data to Kinesis Video Streams in less than half an hour.

How to Send Media Data to a Kinesis Video Stream Using GStreamer

  • In this procedure, you send media data to a Kinesis Video stream not directly but through a helper on-demand EC2 instance. This causes additional EC2 per-hourly charges as well as EC2 data transfer charges.

The following diagram provides a general architectural overview of the solution that you implement using this procedure.

Flow diagram showing a PC with a camera. The PC streams video using GStreamer over an SSH tunnel to an EC2 instance. GStreamer running in a docker container on the EC2 instance, in turn, puts media data to Kinesis Video Streams.

To send media data from a USB Camera to a Kinesis Video stream using the GStreamer multimedia framework perform the following steps:

  1. Install GStreamer on your PC (device).
    Then, use the following command to see the properties and capabilities (caps) of all recognized on your system devices.
    gst-device-monitor-1.0
    
    Also, make sure that the x264enc element that encodes raw video into H.264 compressed data is available.
    gst-inspect-1.0 x264enc
    
    • If the x264enc element is not available on your system, you still can use this procedure with a camera that has onboard H.264 video compression.
  2. Open the Kinesis Video Streams Console at https://console.aws.amazon.com/kinesisvideo and switch to the AWS region where you want to create a Kinesis Video stream. Then, create a new stream with the name example-video-stream and default settings.
  3. Open the EC2 Management Console at https://console.aws.amazon.com/ec2 and switch to the same AWS region where you created your Kinesis Video stream. Then, launch and initialize a new EC2 instance as described in Appendix A, Helper EC2 Instance Configuration.
  4. Create an SSH tunnel to forward the local port 4444 of the loopback interface of your PC to the port 4444 of the loopback interface of the EC2 instance.
    In the following command replace <IPv4 Public IP> with the public IP address of your EC2 instance and <Key-Pair.pem> with the full path to the key pair of this instance.
    ssh -i '<Key-Pair.pem>' -L 127.0.0.1:4444:127.0.0.1:4444 ec2-user@'<IPv4 Public IP>'
    
    • You can also create an SSH tunnel using your favorite SSH client, for example, PuTTY.
  5. On your EC2 instance authenticate the Docker client and pull the ready-to-use Docker image from the Amazon ECR registry of the AWS account 546150905175. For further information about the used Docker image refer to the AWS documentation.
    Execute the following command under ec2-user:
    bash -c "$(aws ecr get-login --registry-ids 546150905175 --no-include-email --region us-west-2)" && docker pull 546150905175.dkr.ecr.us-west-2.amazonaws.com/kinesis-video-producer-sdk-cpp-amazon-linux:latest
    
  6. Run on your EC2 instance a new Docker container and get shell access inside this container.
    Execute the following command under ec2-user:
    docker run -it --rm --network='host' 546150905175.dkr.ecr.us-west-2.amazonaws.com/kinesis-video-producer-sdk-cpp-amazon-linux /bin/bash
    
    • Do not close this shell prompt. In the following steps, it is needed for executing commands within the running container.
  7. In the running Docker container, execute the following command to create the credentials.txt file containing the credentials of the IAM role of your EC2 instance. These credentials will be used by the Kinesis Video Streams GStreamer plugin (kvssink).
    python << EOF > /root/credentials.txt
    from __future__ import print_function
    import urllib2
    import json
    metadata_url = 'http://169.254.169.254/latest/meta-data/iam/security-credentials/'
    iam_role = urllib2.urlopen(metadata_url).read()
    credentials = json.load(urllib2.urlopen(metadata_url + iam_role))
    print('CREDENTIALS', credentials['AccessKeyId'], credentials['Expiration'],
          credentials['SecretAccessKey'], credentials['Token'])
    EOF
    
  8. Send media data to your Kinesis Video stream.
    1. In the running Docker container, execute a consumer GStreamer pipeline that listens to the local port 4444 and puts the received media data to your Amazon Kinesis Video stream.
      In the following command replace <AWS Region> with the region name where you created your Amazon Kinesis Video stream (for example, us-east-1).
      gst-launch-1.0 -e -v tcpserversrc host=127.0.0.1 port=4444 do_timestamp=true ! \
      gdpdepay ! h264parse ! \
      capsfilter caps='video/x-h264,width=320,height=240,framerate=15/1' ! \
      kvssink stream-name='example-video-stream' \
      storage-size=32 credential-path=/root/credentials.txt \
      aws-region='<AWS Region>'
      
    2. On your PC launch a producer GStreamer pipeline that sends media data to the local port 4444 of your PC. This data will be forwarded over the SSH tunnel to the GStreamer pipeline running on the EC2 instance.
      For example, to send video from a USB camera /dev/video0 on a Linux-based system, execute the following command:
      gst-launch-1.0 -v v4l2src device='/dev/video0' do-timestamp=true ! \
      videoconvert ! \
      capsfilter caps='video/x-raw,format=I420,width=320,height=240,framerate=15/1' ! \
      x264enc bframes=0 key-int-max=30 bitrate=300 ! \
      capsfilter caps='video/x-h264,stream-format=avc,alignment=au' ! gdppay ! \
      tcpclientsink host=127.0.0.1 port=4444 sync=false
      
      For other systems and use cases refer to Appendix B, GStreamer Launch Command Examples.
  9. In the output of the GStreamer pipeline running on the EC2 instance observe Kinesis Video client and stream metrics, and transferred bytes to the Kinesis Video Streams service:
    ...
    >> Total streams frame rate (fps): xx
    >> Total streams transfer rate (bps): xxxxxx (xxx Kbps)
    ...
    postReadCallback(): Wrote xxxxx bytes to Kinesis Video. Upload stream handle: 0
    ... 
    
    In the Kinesis Video Streams Console open your stream to preview the transmitted media data.

Appendix A, Helper EC2 Instance Configuration

Simple GStreamer pipelines that do not process high-definition video and do not do complex video encoding/decoding and transformation consume very few system resources. They can be run on an EC2 instance with the following configuration:

Amazon Machine Image (AMI): Amazon Linux 2 AMI (HVM), SSD Volume Type

Instance type: t2.nano

In addition, the following options are required to be able to pull and run on this instance the official Docker image with the ready-to-use Kinesis Video Streams GStreamer plugin, and to create an SSH tunnel to the instance from your PC:

Auto-assign Public IP: Enable

IAM role: create a new EC2 IAM role with the inline policy below.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "kinesisvideo:DescribeStream", "kinesisvideo:GetDataEndpoint",
        "kinesisvideo:PutMedia"
      ],
      "Resource": "arn:aws:kinesisvideo:*:*:stream/example-video-stream*",
      "Effect": "Allow"
    },
    {
      "Action": [
        "ecr:BatchGetImage", "ecr:GetDownloadUrlForLayer"
      ],
      "Resource": [
        "arn:aws:ecr:us-west-2:546150905175:repository/kinesis-video-producer-sdk-cpp*"
      ],
      "Effect": "Allow"
    },
    {
      "Action": "ecr:GetAuthorizationToken",
      "Resource": "*",
      "Effect": "Allow"
    }
  ]
}

Security group: allow SSH access to the instance from your PC.

After your instance entered the running state, log in to the instance under ec2-user and execute the following commands:

sudo yum update -y
sudo yum install -y docker
sudo systemctl enable docker.service
sudo usermod -a -G docker ec2-user

Then, reboot the instance.

sudo reboot

Appendix B, GStreamer Launch Command Examples

In all examples, to find your device (device, device-index or device-path) and its capabilities (caps), use the gst-device-monitor-1.0 command.

To find out the codec and container format of a media file, use the gst-discoverer-1.0 command.

The following general rules apply to the GStreamer pipeline examples:

  • In the first capsfilter of the producer GStreamer pipelines that stream video from a USB camera, use caps supported by your camera. Otherwise, you need to use additionally videoconvert, videoscale or videorate GStreamer elements.
  • If you change width, height, or framerate in the producer GStreamer pipeline, you have to change the corresponding values in the consumer pipeline as well.
  • In the pipelines that have the key-int-max parameter (maximal distance between two keyframes), the value of this parameter should be greater than or equal to framerate, and less than or equal to framerate multiplied by 5.

Linux

The following command creates a producer GStreamer pipeline that streams video from a USB camera that has onboard H.264 video compression. In this case you do not need to compress video in your pipeline using the x264enc element.

gst-launch-1.0 -v uvch264src device='<Device>' \
initial-bitrate=300000 peak-bitrate=500000 average-bitrate=300000 iframe-period=5000 \
do_timestamp=true name=camera auto-start=true camera.vidsrc ! \
capsfilter caps='video/x-h264,width=320,height=240,framerate=15/1' ! gdppay ! \
tcpclientsink host=127.0.0.1 port=4444 sync=false

The following command creates a producer GStreamer pipeline that streams video from a media file. The decodebin element automatically detects and selects the right decoder. Then, video is converted, scaled and compressed to match the format that is expected by the consumer pipeline running on the EC2 instance.

gst-launch-1.0 -v filesrc location='example.mkv' ! decodebin ! \
videoconvert ! videoscale ! videorate ! \
capsfilter caps='video/x-raw,format=I420,width=320,height=240,framerate=15/1' ! \
x264enc bframes=0 key-int-max=30 bitrate=300 ! \
capsfilter caps='video/x-h264,stream-format=avc,alignment=au' ! gdppay ! \
tcpclientsink host=127.0.0.1 port=4444 sync=false

macOS

The following command creates a producer GStreamer pipeline that streams video from a USB camera.

gst-launch-1.0 avfvideosrc device-index='<Device Index>' ! \
videoconvert ! \
capsfilter caps='video/x-raw,format=I420,width=320,height=240,framerate=15/1' ! \
x264enc bframes=0 key-int-max=30 bitrate=300 ! \
capsfilter caps='video/x-h264,stream-format=avc,alignment=au' ! gdppay ! \
tcpclientsink host=127.0.0.1 port=4444 sync=false

Windows

The following command creates a producer GStreamer pipeline that streams video from a USB camera.

gst-launch-1.0 ksvideosrc device-path='<Device Path>' ! \
videoconvert ! \
capsfilter caps='video/x-raw,format=I420,width=320,height=240,framerate=15/1' ! \
x264enc bframes=0 key-int-max=30 bitrate=300 ! \
capsfilter caps='video/x-h264,stream-format=avc,alignment=au' ! gdppay ! \
tcpclientsink host=127.0.0.1 port=4444 sync=false