151 lines
2.7 KiB
Go
151 lines
2.7 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
"github.com/aws/aws-sdk-go/aws/session"
|
|
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
|
"gopkg.in/fsnotify.v1"
|
|
)
|
|
|
|
// How to stream a static video file as a "live" stream?
|
|
|
|
var s3Session *session.Session
|
|
var s3Uploader *s3manager.Uploader
|
|
|
|
func init() {
|
|
var err error
|
|
s3Session, err = session.NewSession(&aws.Config{Region: aws.String("eu-west-1")})
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
s3Uploader = s3manager.NewUploader(s3Session)
|
|
}
|
|
|
|
type upload struct {
|
|
fname string
|
|
key string
|
|
}
|
|
|
|
func main() {
|
|
var url string
|
|
|
|
flag.StringVar(&url, "url", "", "URL to open")
|
|
flag.Parse()
|
|
|
|
if url == "" {
|
|
fmt.Println("Usage:")
|
|
flag.PrintDefaults()
|
|
os.Exit(-1)
|
|
}
|
|
|
|
// first, create a temporary directory.
|
|
tmpdir, err := ioutil.TempDir("", "playlist")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(tmpdir)
|
|
target := filepath.Join(tmpdir, "out.m3u8")
|
|
|
|
// open URL:
|
|
client := http.Client{}
|
|
resp, err := client.Get(url)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
go func() {
|
|
// in this goroutine we open an HTTP URL and pipe it into the process:
|
|
defer wg.Done()
|
|
|
|
fmt.Println("Set target:", target)
|
|
|
|
cmd := exec.Command("ffmpeg", "-re", "-i", "-", "-f", "hls", target)
|
|
cmd.Stdin = resp.Body
|
|
|
|
err = cmd.Run()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
fmt.Println("ffmpeg exited")
|
|
}()
|
|
|
|
go func() {
|
|
defer wg.Done()
|
|
|
|
watcher, err := fsnotify.NewWatcher()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer watcher.Close()
|
|
|
|
err = watcher.Add(tmpdir)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
for {
|
|
select {
|
|
case event, ok := <-watcher.Events:
|
|
if !ok {
|
|
return
|
|
}
|
|
log.Println("Got event.Name:", event.Name)
|
|
key := filepath.Join("test-stream", filepath.Base(event.Name))
|
|
if event.Op&fsnotify.Create == fsnotify.Create && strings.HasSuffix(event.Name, ".m3u8") {
|
|
uploadFile(upload{event.Name, key})
|
|
}
|
|
if event.Op&fsnotify.Write == fsnotify.Write && strings.HasSuffix(event.Name, ".ts") {
|
|
uploadFile(upload{event.Name, key})
|
|
}
|
|
case err, ok := <-watcher.Errors:
|
|
if !ok {
|
|
return
|
|
}
|
|
log.Println("Got error:", err)
|
|
}
|
|
}
|
|
|
|
fmt.Println("sleep exited")
|
|
}()
|
|
|
|
wg.Add(2)
|
|
wg.Wait()
|
|
|
|
fmt.Println("exiting")
|
|
}
|
|
|
|
func uploadFile(u upload) error {
|
|
f, err := os.Open(u.fname)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer f.Close()
|
|
|
|
result, err := s3Uploader.Upload(&s3manager.UploadInput{
|
|
Key: aws.String(u.key),
|
|
Bucket: aws.String("rfwatson-hls"),
|
|
ACL: aws.String("public-read"),
|
|
Body: f,
|
|
})
|
|
|
|
fmt.Println("Uploaded", u.fname, "to", result.Location)
|
|
|
|
return err
|
|
}
|