Introduction

I'm going to assume you know how to setup a new Laravel project, if not check out the excellent series on Laracasts.

HTML5 video has come along way in recent years, every modern browser supports the video element and most having made H264 a supported codec makes life as a developer a lot easier. However it's still a good idea to provide a fallback for those on legacy browsers. In this tutorial I will show you:

  • How to convert any format video file in to HTML5 video format
  • Provide a Flash fallback
  • Generate thumbnail images

All done in the cloud using AWS (so you don't have to worry about local server storage).

Requirements

We're going to be using a couple of web services so before we continue make sure you sign up for:

They both have generous free tiers and I would recommend them for production as well.

Getting started

First we need to prepare our models, controllers and layouts. Lets start by creating a controller using the --resource flag to add the RESTful boilerplate

$ php artisan make:controller VideoController --resource

Models and migrations

Now lets create the Video model with the --migration flag to create the database migration at the same time.

$ php artisan make:model Video --migration

Edit the database migration file: database/migrations/2016_XX_XX_XXXXXX_create_videos_table.php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateVideosTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('videos', function (Blueprint $table) {
            $table->increments('id');
            $table->string('process_id');
            $table->string('title');
            $table->string('description')->nullable();
            $table->string('filename');
            $table->string('video_path');
            $table->string('thumbnail_path');
            $table->string('status');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('videos');
    }
}

We also have to create a model for the video sources that we are going to generate

$ php artisan make:model VideoSource --migration

Edit the migration file database/migrations/2016_XX_XX_XXXXXX_create_video_sources_table.php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateVideoSourcesTable extends Migration
{
  /**
  * Run the migrations.
  *
  * @return void
  */
  public function up()
  {
      Schema::create('video_sources', function (Blueprint $table) {
          $table->increments('id');
          $table->integer('video_id')->unsigned();
          $table->foreign('video_id')
                ->references('id')->on('videos')
                ->onDelete('cascade');
          $table->string('format');
          $table->string('video_path');
          $table->timestamps();
      });
  }

  /**
  * Reverse the migrations.
  *
  * @return void
  */
  public function down()
  {
       Schema::drop('video_sources');
  }
}

Run the migrations and create those two tables.

$ php artisan migrate

One last step with model, we to define the relationship between Video and VideoSource. Edit the model Video.php to add the sources relationship.

namespace App;

use Illuminate\Database\Eloquent\Model;

class Video extends Model
{
    protected $guarded = ['id'];

    public function sources()
    {
        return $this->hasMany('App\VideoSource');
    }

}

Basic layout

Lets create a quick layout using Bootstrap. Make a new file app/resources/views/master.blade.php . We'll use a CDN for now to save time.

<!DOCTYPE html>
<html lang="en">
<head>

    Laravel HTML5 video conversion

</head>
<body>
<nav class="navbar navbar-default">
    <div class="container">
        <div class="navbar-header">
            <a class="navbar-brand" href="/">YourTube</a>
        </div>
        <ul class="nav navbar-nav">
            <li><a href="/video">Videos</a></li>
        </ul>
        <div class="navbar-right"><a href="/video/create" class="btn btn-default navbar-btn">Upload</a></div>
    </div>
</nav>

<div id="content" class="container">
    @yield('content')
</div>

</body>
</html>

We will create a homepage where our videos will be displayed app/resources/views/index.blade.php

@extends('master')
@section('content')
<h2>Recent videos</h2>
@forelse ($videos as $video)
    <div class="col-md-3">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title">{{ $video->title }}</h3>
            </div>
            <div class="panel-body">
                <!-- video will go here later -->
                <!-- @include('partials.video', compact('video')) -->
            </div>
        </div>
    </div>
@empty
    <p class="text-center">No recent videos uploaded</p>
@endforelse

@endsection

Routes

We need to point the homepage to the right view and create the video resource in your app\Http\routes.php

Route::get('/', function () {
    // Take advantage of eager loading with 'sources' relationship
    $videos = \App\Video::with('sources')->get();
    return view('index', compact('videos'));
});
Route::resource('video', 'VideoController');

Video uploading

Now we've setup the basics we can finally get stuck in to the meat of this post

Coming soon