Video Image

Status: Completed

The video image/poster/thumbnail feature will allow users to see static image on video component before they click play just like youtube. To show the poster on video component (as first frame) we'll provide a way to upload image for particular video via "Video Uploads" page. Since our design for this feature adds a significant infrastructure requirement, we're giving it a dedicated design document.   

Epics:

Manual upload:  EDUCATOR-203 - Getting issue details... STATUS

Auto generated  EDUCATOR-438 - Getting issue details... STATUS

Functionality

  • On Video Uploads page, upload an image for particular video to use as video poster/thumbnail (or replace the existing one)
  • The video image would be specific to course run i.e. changing/adding new image would't impact the other course(s).
  • When a thumbnail is added to a video on the upload page, it should update any component where the video is used.
  • Basic interaction mockup here: http://6qnr7j.axshare.com/thumbnail_upload.html
  • Video pipeline is generating 3 random images from uploaded video and using one of them by default.
  • Moderation: minimal MVP for now

Future (not inclusive)

  • Show the image on Video component editor (so it's easy for course authors to search for an uploaded video - instead of copy-pasting the video-id)
  • We might need to serve the video image in different sizes, keeping this in mind, we'll design the structure much flexible to accommodate this change.
  • Select from auto-generated images.

Upload Video Image End Point

HTTP clients use this end point to upload video images, as well as to update existing ones.

Access Control

Course authors & admin will be able to add / edit the image for videos. 

Also these images will be world readable via S3 link.

Endpoints

video_images/{course_id}/{edx_video_id}

MethodDescriptionAccess
POSTUpload a new video image.  If one already exists, it will be replaced by this one.course staff, admin

Request Details

  • parameters: file data (standard multipart POST upload via user-agent)
  • supported file types: .JPG, .GIF,.BMP or .PNG.
  • maximum upload file size: 2MB
  • maximum upload file size (pixel dimensions):  1280x720

NOTE: Validation will be added to backend as well as client side.

Response Format

  • If the upload is successful, the request returns an HTTP 200  response with url to image.
  • If the upload could not be performed, the request returns an HTTP 400 "Bad Request" response with information about why the request failed.

Implementation Considerations

  • Use Django ImageField.  Keep things maximally customizable using standard Django storage and it should be vendor-neutral (i.e. s3 support optional, but not a requirement.)
  • To store the uploaded images, we'll be adding a new model in edx-val.
    • The new TimeStampedModel model "VideoImage" will have these fields
      • course_id
      • One-to-One field with CourseVideo model
      • ImageField
      • created
      • modified
  • Possible indices would be on these fields:
    • course_id
    • edx_video_id
    • course_id & video_id both ??
  • Video image will be tackled for course re-run and course import/export.
    • For course re-run we just need to add related entries into VideoImage table just like CourseVideo table.

Video Image Usage

  • Video image will be shown on two different places.
    • video uploads page
    • video component as video poster
  • authentication is NOT required to view video images. ?

Configuring Backend Video Image Storage

Video image field will adopt approach just like block structure's data field https://github.com/edx/edx-platform/blob/master/openedx/core/djangoapps/content/block_structure/models.py#L166

For devstack we'll be using default Django storage and for production/stage like environment we'll be using s3 

VIDEO_IMAGE_SETTINGS = dict(
    STORAGE_CLASS='storages.backends.s3boto.S3BotoStorage',
    STORAGE_KWARGS=dict(bucket='video-images-test-bucket'),
    DIRECTORY_PREFIX='video_images/',
)

Storage and access for video images

The video images will be stored using Django Storages to abstract away the details of where the images are stored. Here's how it works:

  • The uploaded images will include the client_max_body_size directive which limits upload size. The value passed to that directive is also given to the CMS as a second line of defense.
  • The image name will have timestamp which will be stored as part of the image URL. 
  • In production, CDN domains will be used in image URLs. The CDN will be configured to cache on unique image URLS, so that whenever a user uploads a new image, the CMS/LMS starts serving image URLs with the new image URL, causing the CDN to cache a new image.

  • When serving images from disk, caching is configured using the expires nginx directive. When serving images from a CDN/S3, caching is configured by including Cache-Control: max-age in the headers. The value is in seconds in both cases.
  • In prod, stage, and load-test, images will be stored in the same bucket under the prodstage, and load-test prefixes. One CDN serves the entire bucket. In edge, all images are at the top level of the bucket. Edge has its own CDN. In the sandbox environment, each sandbox's IAM role allows it to upload to the appropriate bucket only by prefixing all files with the sandbox's IP address.
  • Terraform changes will be required to configure the S3 buckets. As an example we'll look into this PR https://github.com/edx-ops/terraform/pull/340

Cleaning up stale images from s3 bucket

To clean the old/stale images from s3 bucket, the real scenario could be if someone uploads an image and update it later, given that we're using timestamp as image name, the old image would be there forever. Here are different approaches that we can take to address this issue: 

  • Create a new image on s3 and delete the old one right away.