Skip to content

Commit

Permalink
Merge pull request #17 from m1k1o/hls-vod
Browse files Browse the repository at this point in the history
(WIP) Hls vod
  • Loading branch information
m1k1o authored Nov 19, 2021
2 parents 1cfd7d9 + c5e9c47 commit 79505cd
Show file tree
Hide file tree
Showing 10 changed files with 1,486 additions and 6 deletions.
57 changes: 52 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# go-transcode HTTP on-demand transcoding API

On demand transcoding of live sources and static files (with seeking).

## Why

Transcoding is expensive and resource consuming operation on CPU and GPU. For big companies with thousands of customers it is essential, to have a dedicated 24/7 transcoding servers which can store all the transcoded versions.
Expand All @@ -12,17 +14,21 @@ This feature is common in media centers (plex, jellyfin) but there was no simple

Sources:
- [x] Live streams
- [ ] Static files (basic support)
- [x] VOD (static files, basic support)
- [x] Any codec/container supported by ffmpeg

Outputs:
Live Outputs:
- [x] Basic MP4 over HTTP (h264+aac) : `http://go-transcode/[profile]/[stream-id]`
- [x] Basic HLS over HTTP (h264+aac) : `http://go-transcode/[profile]/[stream-id]/index.m3u8`
- [x] Demo HTML player (for HLS) : `http://go-transcode/[profile]/[stream-id]/play.html`
- [x] HLS proxy : `http://go-transcode/hlsproxy/[hls-proxy-id]/[original-request]`

VOD Outputs:
- [x] HLS master playlist (h264+aac) : `http://go-transcode/vod/[media-path]/index.m3u8`
- [x] HLS custom profile (h264+aac) : `http://go-transcode/vod/[media-path]/[profile].m3u8`

Features:
- [ ] Seeking for static files (index)
- [x] Seeking for static files (indexed vod files)
- [ ] Audio/Subtitles tracks
- [ ] Private mode (serve users authenticated by reverse proxy)

Expand Down Expand Up @@ -53,18 +59,58 @@ static: /var/www/html
# TODO: issue #4
proxy: true

# For live streaming
streams:
cam: rtmp://localhost/live/cam
ch1_hd: http://192.168.1.34:9981/stream/channelid/85
ch2_hd: http://192.168.1.34:9981/stream/channelid/43

# For static files
vod:
# Source, where are static files, that will be transcoded
media-dir: ./media
# Temporary transcode output directory, if empty, default tmp folder will be used
transcode-dir: ./transcode
# Available video profiles
video-profiles:
360p:
width: 640 # px
height: 360 # px
bitrate: 800 # kbps
540p:
width: 960
height: 540
bitrate: 1800
720p:
width: 1280
height: 720
bitrate: 2800
1080p:
width: 1920
height: 1080
bitrate: 5000
# Use video keyframes as existing reference for chunks split
# Using this might cause long probing times in order to get
# all keyframes - therefore they should be cached
video-keyframes: false
# Single audio profile used
audio-profile:
bitrate: 192 # kbps
# If cache is enabled
cache: true
# If dir is empty, cache will be stored in the same directory as media source
# If not empty, cache files will be saved to specified directory
cache-dir: ./cache
# Use custom ffmpeg & ffprobe binary paths
ffmpeg-binary: ffmpeg
ffprobe-binary: ffmpeg

# For proxying HLS streams
hls-proxy:
my_server: http://192.168.1.34:9981

```
## Transcoding profiles
## Transcoding profiles for live streams
go-transcode supports any formats that ffmpeg likes. We provide profiles out-of-the-box for h264+aac (mp4 container) for 360p, 540p, 720p and 1080p resolutions: `h264_360p`, `h264_540p`, `h264_720p` and `h264_1080p`. Profiles can have any name, but must match regex: `^[0-9A-Za-z_-]+$`

Expand Down Expand Up @@ -160,6 +206,7 @@ The source code is in the following files/folders:

- `cmd/` and `main.go`: source for the command-line interface
- `hls/`: process runner for HLS transcoding
- `hlsvod/`: process runner for HLS VOD transcoding (for static files)
- `internal/`: actual source code logic

*TODO: document different modules/packages and dependencies*
Expand Down
48 changes: 48 additions & 0 deletions hlsvod/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package hlsvod

import (
"crypto/sha1"
"fmt"
"os"
"path"
)

const cacheFileSuffix = ".go-transcode-cache"

func (m *ManagerCtx) getCacheData() ([]byte, error) {
// check for local cache
localCachePath := m.config.MediaPath + cacheFileSuffix
if _, err := os.Stat(localCachePath); err == nil {
m.logger.Warn().Str("path", localCachePath).Msg("media local cache hit")
return os.ReadFile(localCachePath)
}

// check for global cache
h := sha1.New()
h.Write([]byte(m.config.MediaPath))
hash := h.Sum(nil)

fileName := fmt.Sprintf("%x%s", hash, cacheFileSuffix)
globalCachePath := path.Join(m.config.CacheDir, fileName)
if _, err := os.Stat(globalCachePath); err == nil {
m.logger.Warn().Str("path", globalCachePath).Msg("media global cache hit")
return os.ReadFile(globalCachePath)
}

return nil, os.ErrNotExist
}

func (m *ManagerCtx) saveLocalCacheData(data []byte) error {
localCachePath := m.config.MediaPath + cacheFileSuffix
return os.WriteFile(localCachePath, data, 0755)
}

func (m *ManagerCtx) saveGlobalCacheData(data []byte) error {
h := sha1.New()
h.Write([]byte(m.config.MediaPath))
hash := h.Sum(nil)

fileName := fmt.Sprintf("%x%s", hash, cacheFileSuffix)
globalCachePath := path.Join(m.config.CacheDir, fileName)
return os.WriteFile(globalCachePath, data, 0755)
}
Loading

0 comments on commit 79505cd

Please sign in to comment.