diff --git a/README.md b/README.md index 31b6bc8..30aac17 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ imagorvideo is a new initiative that brings video thumbnail capability through ffmpeg, built on the foundations of [imagor](https://github.com/cshum/imagor) - a fast, Docker-ready image processing server written in Go with libvips. -imagorvideo uses ffmpeg C bindings that extracts image thumbnail from video by attempting to select the best frame, then forwards to libvips to perform all the image cropping, resizing and filters supported by imagor. +imagorvideo uses ffmpeg C bindings that extracts image thumbnail from video, by attempting to select the best frame. It then forwards to libvips to perform all the image cropping, resizing and filters supported by imagor. imagorvideo uses read stream for mkv and webm video types. For other video types that requires seeking from a non seek-able source such as HTTP or S3, it simulates seek using memory or temp file as buffer. @@ -31,9 +31,9 @@ http://localhost:8000/unsafe/300x0/7x7/filters:label(imagorvideo,-10,-7,20,yello ![imagorvideo](https://raw.githubusercontent.com/cshum/imagorvideo/master/testdata/demo.jpg) -imagorvideo works by streaming out a limited number of frames data from start of the video, looping through and populating the histogram data of each frame. It then choose the best frame for imaging, based on root-mean-square error (RMSE). This allow skipping the black frames that usually occur at the beginning of videos. +imagorvideo works by streaming out a limited number of frame data, looping through and calculating the histogram of each frame. It then choose the best frame for imaging, based on root-mean-square error (RMSE). This allow skipping the black frames that usually occur at the beginning of videos. -imagorvideo then converts the selected frame to RGB image data, forwards to the imagor libvips module, which has always been best at image processing with tons of features. Check out [imagor documentations](https://github.com/cshum/imagor#image-endpoint) for all the image options supported. +imagorvideo then converts the selected frame to RGB image data, forwards to the imagor libvips processor, which has always been best at image processing with tons of features. Check out [imagor documentations](https://github.com/cshum/imagor#image-endpoint) for all the image options supported. ### Filters @@ -51,33 +51,17 @@ http://localhost:8000/unsafe/300x0/7x7/filters:max_frames(70):fill(yellow)/http: imagorvideo provides metadata endpoint that extracts video metadata, dimension and duration data. By default, it only process the header without extracting the frame data for better processing speed. -To use the metadata endpoint, add `/meta` right after the URL signature hash before the image operations. Example: +To use the metadata endpoint, add `/meta` right after the URL signature hash before the image operations: ``` http://localhost:8000/unsafe/meta/https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/1080/Big_Buck_Bunny_1080_10s_30MB.mp4 ``` - -```json -{ - "format": "mp4", - "content_type": "video/mp4", - "orientation": 1, - "duration": 10000, - "width": 1920, - "height": 1080, - "title": "Big Buck Bunny, Sunflower version", - "artist": "Blender Foundation 2008, Janus Bager Kristensen 2013", - "has_video": true, - "has_audio": false -} -``` -Appending the `max_frames()` or `frame(n)` filter however, would activate frame processing. This results more processing time but would also allows retrieving frame related info such as frames per second `fps` and selected frame index. Example: +Appending the `max_frames()` or `frame(n)` filter however, would activate frame processing. This results more processing time but would also allows retrieving frame related info such as frames per second `fps`: ``` http://localhost:8000/unsafe/meta/filters:max_frames()/https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/1080/Big_Buck_Bunny_1080_10s_30MB.mp4 ``` - ```json { "format": "mp4", @@ -88,13 +72,13 @@ http://localhost:8000/unsafe/meta/filters:max_frames()/https://test-videos.co.uk "height": 1080, "title": "Big Buck Bunny, Sunflower version", "artist": "Blender Foundation 2008, Janus Bager Kristensen 2013", - "fps": 30, - "selected_frame": 21, + "fps": 30, // available only if frame processing activated "has_video": true, "has_audio": false } ``` + ### Configuration Config options specific to imagorvideo. Please refer to [imagor configuration](https://github.com/cshum/imagor#configuration) for all existing options supported. diff --git a/ffmpeg/ffmpeg.go b/ffmpeg/ffmpeg.go index 361e161..18cbea7 100644 --- a/ffmpeg/ffmpeg.go +++ b/ffmpeg/ffmpeg.go @@ -21,16 +21,15 @@ const ( ) type Metadata struct { - Orientation int `json:"orientation"` - Duration int `json:"duration,omitempty"` - Width int `json:"width,omitempty"` - Height int `json:"height,omitempty"` - Title string `json:"title,omitempty"` - Artist string `json:"artist,omitempty"` - FPS float64 `json:"fps,omitempty"` - SelectedFrame int `json:"selected_frame,omitempty"` - HasVideo bool `json:"has_video"` - HasAudio bool `json:"has_audio"` + Orientation int `json:"orientation"` + Duration int `json:"duration,omitempty"` + Width int `json:"width,omitempty"` + Height int `json:"height,omitempty"` + Title string `json:"title,omitempty"` + Artist string `json:"artist,omitempty"` + FPS float64 `json:"fps,omitempty"` + HasVideo bool `json:"has_video"` + HasAudio bool `json:"has_audio"` } type AVContext struct { @@ -93,10 +92,32 @@ func (av *AVContext) SelectFrame(n int) (err error) { nn = av.availableIndex } av.selectedIndex = nn - if err = av.ProcessFrames(-1); err != nil { - return + return av.ProcessFrames(-1) +} + +func (av *AVContext) positionToDuration(f float64) time.Duration { + return time.Duration(float64(av.duration) * math.Max(math.Min(f, 1), 0)) +} + +func (av *AVContext) SelectPosition(f float64) (err error) { + return av.SelectDuration(av.positionToDuration(f)) +} + +func (av *AVContext) SelectDuration(ts time.Duration) (err error) { + if ts > 0 { + if err = seekDuration(av, ts); err != nil { + return + } } - return nil + return av.SelectFrame(1) +} + +func (av *AVContext) SeekPosition(f float64) (err error) { + return av.SeekDuration(av.positionToDuration(f)) +} + +func (av *AVContext) SeekDuration(ts time.Duration) (err error) { + return seekDuration(av, ts) } func (av *AVContext) Export(bands int) (buf []byte, err error) { @@ -121,21 +142,16 @@ func (av *AVContext) Metadata() *Metadata { if av.availableDuration > 0 { fps = float64(av.availableIndex) * float64(time.Second) / float64(av.availableDuration) } - var selectedFrame int - if av.availableIndex > 0 && av.selectedIndex > -1 { - selectedFrame = int(av.selectedIndex) + 1 - } return &Metadata{ - Orientation: av.orientation, - Duration: int(av.duration / time.Millisecond), - Width: av.width, - Height: av.height, - Title: av.title, - Artist: av.artist, - FPS: math.Round(fps*10) / 10, - SelectedFrame: selectedFrame, - HasVideo: av.hasVideo, - HasAudio: av.hasAudio, + Orientation: av.orientation, + Duration: int(av.duration / time.Millisecond), + Width: av.width, + Height: av.height, + Title: av.title, + Artist: av.artist, + FPS: math.Round(fps*10) / 10, + HasVideo: av.hasVideo, + HasAudio: av.hasAudio, } } @@ -217,6 +233,16 @@ func createDecoder(av *AVContext) error { return nil } +func seekDuration(av *AVContext, ts time.Duration) error { + tts := C.int64_t(ts.Milliseconds()) * C.AV_TIME_BASE / 1000 + err := C.av_seek_frame(av.formatContext, C.int(-1), tts, C.AVSEEK_FLAG_BACKWARD) + C.avcodec_flush_buffers(av.codecContext) + if err < 0 { + return avError(err) + } + return nil +} + func incrementDuration(av *AVContext, frame *C.AVFrame, i C.int) { av.availableIndex = i if frame.pts != C.AV_NOPTS_VALUE { diff --git a/ffmpeg/ffmpeg_test.go b/ffmpeg/ffmpeg_test.go index 2d4420c..1a23247 100644 --- a/ffmpeg/ffmpeg_test.go +++ b/ffmpeg/ffmpeg_test.go @@ -70,13 +70,12 @@ func TestAVContext(t *testing.T) { defer av.Close() if n == 10 { require.NoError(t, av.ProcessFrames(n)) - } else { - if n == 9999 { - require.NoError(t, av.ProcessFrames(-1)) - } - if n > -1 { - require.NoError(t, av.SelectFrame(n)) - } + } else if n == 99999 { + require.NoError(t, av.SeekPosition(0.6)) + } else if n == 9999 { + require.NoError(t, av.SelectPosition(0.7)) + } else if n > -1 { + require.NoError(t, av.SelectFrame(n)) } meta := av.Metadata() metaBuf, err := json.Marshal(meta) diff --git a/processor.go b/processor.go index d41c470..8b7cc29 100644 --- a/processor.go +++ b/processor.go @@ -10,6 +10,7 @@ import ( "io" "strconv" "strings" + "time" ) type Processor struct { @@ -124,10 +125,31 @@ func (p *Processor) Process(ctx context.Context, in *imagor.Blob, params imagorp bands = 4 } } + case "seek": + if ts, e := time.ParseDuration(filter.Args); e == nil { + if err = av.SeekDuration(ts); err != nil { + return + } + } else if f, e := strconv.ParseFloat(filter.Args, 64); e == nil { + if err = av.SeekPosition(f); err != nil { + return + } + } case "frame": - n, _ := strconv.Atoi(filter.Args) - if err = av.SelectFrame(n); err != nil { - return + if ts, e := time.ParseDuration(filter.Args); e == nil { + if err = av.SelectDuration(ts); err != nil { + return + } + } else if f, e := strconv.ParseFloat(filter.Args, 64); e == nil { + if strings.Contains(filter.Args, ".") { + if err = av.SelectPosition(f); err != nil { + return + } + } else if n := int(f); n >= 1 { + if err = av.SelectFrame(n); err != nil { + return + } + } } case "max_frames": n, _ := strconv.Atoi(filter.Args) diff --git a/processor_test.go b/processor_test.go index 32adde3..9e91531 100644 --- a/processor_test.go +++ b/processor_test.go @@ -32,6 +32,7 @@ type test struct { name string path string expectCode int + sizeOnly bool } func TestProcessor(t *testing.T) { @@ -54,6 +55,10 @@ func TestProcessor(t *testing.T) { {name: "mp4 orient 270", path: "200x100/schizo_270.mp4"}, {name: "image", path: "fit-in/100x100/demo.png"}, {name: "alpha", path: "fit-in/filters:format(png)/alpha-webm.webm"}, + {name: "alpha frame duration", path: "500x/filters:frame(5s):format(png)/alpha-webm.webm", sizeOnly: true}, + {name: "alpha frame position", path: "500x/filters:frame(0.5):format(png)/alpha-webm.webm", sizeOnly: true}, + {name: "alpha seek duration", path: "500x/filters:seek(5s):format(png)/alpha-webm.webm", sizeOnly: true}, + {name: "alpha seek position", path: "500x/filters:seek(0.5):format(png)/alpha-webm.webm", sizeOnly: true}, {name: "corrupted", path: "fit-in/100x100/corrupt/everybody-betray-me.mkv", expectCode: 406}, {name: "no cover meta", path: "meta/no_cover.mp3"}, {name: "no cover 406", path: "fit-in/100x100/no_cover.mp3", expectCode: 406}, @@ -105,6 +110,9 @@ func doGoldenTests(t *testing.T, resultDir string, tests []test, opts ...Option) assert.NoError(t, app.Shutdown(context.Background())) }) for _, tt := range tests { + if i == 1 && tt.sizeOnly { + continue + } t.Run(fmt.Sprintf("%s-%d", tt.name, i+1), func(t *testing.T) { w := httptest.NewRecorder() ctx, cancel := context.WithCancel(context.Background()) diff --git a/testdata/golden/export/alpha-webm.webm-9999.jpg b/testdata/golden/export/alpha-webm.webm-9999.jpg index 2e0017e..68e790b 100644 Binary files a/testdata/golden/export/alpha-webm.webm-9999.jpg and b/testdata/golden/export/alpha-webm.webm-9999.jpg differ diff --git a/testdata/golden/export/alpha-webm.webm-99999.jpg b/testdata/golden/export/alpha-webm.webm-99999.jpg index 2e0017e..3312405 100644 Binary files a/testdata/golden/export/alpha-webm.webm-99999.jpg and b/testdata/golden/export/alpha-webm.webm-99999.jpg differ diff --git a/testdata/golden/export/everybody-betray-me.mkv-9999.jpg b/testdata/golden/export/everybody-betray-me.mkv-9999.jpg index 2f6fb58..76cd84c 100644 Binary files a/testdata/golden/export/everybody-betray-me.mkv-9999.jpg and b/testdata/golden/export/everybody-betray-me.mkv-9999.jpg differ diff --git a/testdata/golden/export/everybody-betray-me.mkv-99999.jpg b/testdata/golden/export/everybody-betray-me.mkv-99999.jpg index 2f6fb58..bb35fbb 100644 Binary files a/testdata/golden/export/everybody-betray-me.mkv-99999.jpg and b/testdata/golden/export/everybody-betray-me.mkv-99999.jpg differ diff --git a/testdata/golden/export/macabre.mp4-9999.jpg b/testdata/golden/export/macabre.mp4-9999.jpg index 59f5451..d1ab9d8 100644 Binary files a/testdata/golden/export/macabre.mp4-9999.jpg and b/testdata/golden/export/macabre.mp4-9999.jpg differ diff --git a/testdata/golden/export/macabre.mp4-99999.jpg b/testdata/golden/export/macabre.mp4-99999.jpg index 59f5451..4b4a16d 100644 Binary files a/testdata/golden/export/macabre.mp4-99999.jpg and b/testdata/golden/export/macabre.mp4-99999.jpg differ diff --git a/testdata/golden/export/schizo.flv-9999.jpg b/testdata/golden/export/schizo.flv-9999.jpg index 84f7b40..a543ab0 100644 Binary files a/testdata/golden/export/schizo.flv-9999.jpg and b/testdata/golden/export/schizo.flv-9999.jpg differ diff --git a/testdata/golden/export/schizo.flv-99999.jpg b/testdata/golden/export/schizo.flv-99999.jpg index 84f7b40..895b026 100644 Binary files a/testdata/golden/export/schizo.flv-99999.jpg and b/testdata/golden/export/schizo.flv-99999.jpg differ diff --git a/testdata/golden/export/schizo_0.mp4-9999.jpg b/testdata/golden/export/schizo_0.mp4-9999.jpg index 935ab8e..9d49888 100644 Binary files a/testdata/golden/export/schizo_0.mp4-9999.jpg and b/testdata/golden/export/schizo_0.mp4-9999.jpg differ diff --git a/testdata/golden/export/schizo_0.mp4-99999.jpg b/testdata/golden/export/schizo_0.mp4-99999.jpg index 935ab8e..bde6e23 100644 Binary files a/testdata/golden/export/schizo_0.mp4-99999.jpg and b/testdata/golden/export/schizo_0.mp4-99999.jpg differ diff --git a/testdata/golden/export/schizo_180.mp4-9999.jpg b/testdata/golden/export/schizo_180.mp4-9999.jpg index 15f6245..df99457 100644 Binary files a/testdata/golden/export/schizo_180.mp4-9999.jpg and b/testdata/golden/export/schizo_180.mp4-9999.jpg differ diff --git a/testdata/golden/export/schizo_180.mp4-99999.jpg b/testdata/golden/export/schizo_180.mp4-99999.jpg index 15f6245..de2ac07 100644 Binary files a/testdata/golden/export/schizo_180.mp4-99999.jpg and b/testdata/golden/export/schizo_180.mp4-99999.jpg differ diff --git a/testdata/golden/export/schizo_270.mp4-9999.jpg b/testdata/golden/export/schizo_270.mp4-9999.jpg index b367d33..8f2ada3 100644 Binary files a/testdata/golden/export/schizo_270.mp4-9999.jpg and b/testdata/golden/export/schizo_270.mp4-9999.jpg differ diff --git a/testdata/golden/export/schizo_270.mp4-99999.jpg b/testdata/golden/export/schizo_270.mp4-99999.jpg index b367d33..8ac4052 100644 Binary files a/testdata/golden/export/schizo_270.mp4-99999.jpg and b/testdata/golden/export/schizo_270.mp4-99999.jpg differ diff --git a/testdata/golden/export/schizo_90.mp4-9999.jpg b/testdata/golden/export/schizo_90.mp4-9999.jpg index e57f442..3ef8b0c 100644 Binary files a/testdata/golden/export/schizo_90.mp4-9999.jpg and b/testdata/golden/export/schizo_90.mp4-9999.jpg differ diff --git a/testdata/golden/export/schizo_90.mp4-99999.jpg b/testdata/golden/export/schizo_90.mp4-99999.jpg index e57f442..6a96a5f 100644 Binary files a/testdata/golden/export/schizo_90.mp4-99999.jpg and b/testdata/golden/export/schizo_90.mp4-99999.jpg differ diff --git a/testdata/golden/meta/alpha-webm.webm-10.meta.json b/testdata/golden/meta/alpha-webm.webm-10.meta.json index 73935a9..e45c027 100644 --- a/testdata/golden/meta/alpha-webm.webm-10.meta.json +++ b/testdata/golden/meta/alpha-webm.webm-10.meta.json @@ -1 +1 @@ -{"orientation":1,"duration":12040,"width":720,"height":576,"fps":25,"selected_frame":5,"has_video":true,"has_audio":false} \ No newline at end of file +{"orientation":1,"duration":12040,"width":720,"height":576,"fps":25,"has_video":true,"has_audio":false} \ No newline at end of file diff --git a/testdata/golden/meta/alpha-webm.webm-5.meta.json b/testdata/golden/meta/alpha-webm.webm-5.meta.json index 73935a9..e45c027 100644 --- a/testdata/golden/meta/alpha-webm.webm-5.meta.json +++ b/testdata/golden/meta/alpha-webm.webm-5.meta.json @@ -1 +1 @@ -{"orientation":1,"duration":12040,"width":720,"height":576,"fps":25,"selected_frame":5,"has_video":true,"has_audio":false} \ No newline at end of file +{"orientation":1,"duration":12040,"width":720,"height":576,"fps":25,"has_video":true,"has_audio":false} \ No newline at end of file diff --git a/testdata/golden/meta/alpha-webm.webm-9999.meta.json b/testdata/golden/meta/alpha-webm.webm-9999.meta.json index cf38939..357c63c 100644 --- a/testdata/golden/meta/alpha-webm.webm-9999.meta.json +++ b/testdata/golden/meta/alpha-webm.webm-9999.meta.json @@ -1 +1 @@ -{"orientation":1,"duration":12040,"width":720,"height":576,"fps":25,"selected_frame":100,"has_video":true,"has_audio":false} \ No newline at end of file +{"orientation":1,"duration":12040,"width":720,"height":576,"has_video":true,"has_audio":false} \ No newline at end of file diff --git a/testdata/golden/meta/alpha-webm.webm-99999.meta.json b/testdata/golden/meta/alpha-webm.webm-99999.meta.json index cf38939..357c63c 100644 --- a/testdata/golden/meta/alpha-webm.webm-99999.meta.json +++ b/testdata/golden/meta/alpha-webm.webm-99999.meta.json @@ -1 +1 @@ -{"orientation":1,"duration":12040,"width":720,"height":576,"fps":25,"selected_frame":100,"has_video":true,"has_audio":false} \ No newline at end of file +{"orientation":1,"duration":12040,"width":720,"height":576,"has_video":true,"has_audio":false} \ No newline at end of file diff --git a/testdata/golden/meta/everybody-betray-me.mkv-10.meta.json b/testdata/golden/meta/everybody-betray-me.mkv-10.meta.json index 8193968..cb2195e 100644 --- a/testdata/golden/meta/everybody-betray-me.mkv-10.meta.json +++ b/testdata/golden/meta/everybody-betray-me.mkv-10.meta.json @@ -1 +1 @@ -{"orientation":1,"duration":7407,"width":640,"height":480,"fps":30,"selected_frame":6,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":1,"duration":7407,"width":640,"height":480,"fps":30,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/everybody-betray-me.mkv-5.meta.json b/testdata/golden/meta/everybody-betray-me.mkv-5.meta.json index 60cee22..85f93c9 100644 --- a/testdata/golden/meta/everybody-betray-me.mkv-5.meta.json +++ b/testdata/golden/meta/everybody-betray-me.mkv-5.meta.json @@ -1 +1 @@ -{"orientation":1,"duration":7407,"width":640,"height":480,"fps":30.1,"selected_frame":5,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":1,"duration":7407,"width":640,"height":480,"fps":30.1,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/everybody-betray-me.mkv-9999.meta.json b/testdata/golden/meta/everybody-betray-me.mkv-9999.meta.json index fcab6af..07cc731 100644 --- a/testdata/golden/meta/everybody-betray-me.mkv-9999.meta.json +++ b/testdata/golden/meta/everybody-betray-me.mkv-9999.meta.json @@ -1 +1 @@ -{"orientation":1,"duration":7407,"width":640,"height":480,"fps":30,"selected_frame":100,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":1,"duration":7407,"width":640,"height":480,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/everybody-betray-me.mkv-99999.meta.json b/testdata/golden/meta/everybody-betray-me.mkv-99999.meta.json index fcab6af..07cc731 100644 --- a/testdata/golden/meta/everybody-betray-me.mkv-99999.meta.json +++ b/testdata/golden/meta/everybody-betray-me.mkv-99999.meta.json @@ -1 +1 @@ -{"orientation":1,"duration":7407,"width":640,"height":480,"fps":30,"selected_frame":100,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":1,"duration":7407,"width":640,"height":480,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/macabre.mp4-10.meta.json b/testdata/golden/meta/macabre.mp4-10.meta.json index ceede88..419bf8d 100644 --- a/testdata/golden/meta/macabre.mp4-10.meta.json +++ b/testdata/golden/meta/macabre.mp4-10.meta.json @@ -1 +1 @@ -{"orientation":1,"duration":3925,"width":492,"height":360,"fps":30,"selected_frame":5,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":1,"duration":3925,"width":492,"height":360,"fps":30,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/macabre.mp4-5.meta.json b/testdata/golden/meta/macabre.mp4-5.meta.json index ceede88..419bf8d 100644 --- a/testdata/golden/meta/macabre.mp4-5.meta.json +++ b/testdata/golden/meta/macabre.mp4-5.meta.json @@ -1 +1 @@ -{"orientation":1,"duration":3925,"width":492,"height":360,"fps":30,"selected_frame":5,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":1,"duration":3925,"width":492,"height":360,"fps":30,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/macabre.mp4-9999.meta.json b/testdata/golden/meta/macabre.mp4-9999.meta.json index a38c5f0..e247d01 100644 --- a/testdata/golden/meta/macabre.mp4-9999.meta.json +++ b/testdata/golden/meta/macabre.mp4-9999.meta.json @@ -1 +1 @@ -{"orientation":1,"duration":3925,"width":492,"height":360,"fps":30,"selected_frame":30,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":1,"duration":3925,"width":492,"height":360,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/macabre.mp4-99999.meta.json b/testdata/golden/meta/macabre.mp4-99999.meta.json index a38c5f0..e247d01 100644 --- a/testdata/golden/meta/macabre.mp4-99999.meta.json +++ b/testdata/golden/meta/macabre.mp4-99999.meta.json @@ -1 +1 @@ -{"orientation":1,"duration":3925,"width":492,"height":360,"fps":30,"selected_frame":30,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":1,"duration":3925,"width":492,"height":360,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/schizo.flv-10.meta.json b/testdata/golden/meta/schizo.flv-10.meta.json index ae0b2d3..6399177 100644 --- a/testdata/golden/meta/schizo.flv-10.meta.json +++ b/testdata/golden/meta/schizo.flv-10.meta.json @@ -1 +1 @@ -{"orientation":1,"duration":2560,"width":480,"height":360,"fps":27.9,"selected_frame":6,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":1,"duration":2560,"width":480,"height":360,"fps":27.9,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/schizo.flv-5.meta.json b/testdata/golden/meta/schizo.flv-5.meta.json index ade7ca6..63e7bc0 100644 --- a/testdata/golden/meta/schizo.flv-5.meta.json +++ b/testdata/golden/meta/schizo.flv-5.meta.json @@ -1 +1 @@ -{"orientation":1,"duration":2560,"width":480,"height":360,"fps":25.6,"selected_frame":5,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":1,"duration":2560,"width":480,"height":360,"fps":25.6,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/schizo.flv-9999.meta.json b/testdata/golden/meta/schizo.flv-9999.meta.json index c157cde..62d3cfb 100644 --- a/testdata/golden/meta/schizo.flv-9999.meta.json +++ b/testdata/golden/meta/schizo.flv-9999.meta.json @@ -1 +1 @@ -{"orientation":1,"duration":2560,"width":480,"height":360,"fps":29.7,"selected_frame":76,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":1,"duration":2560,"width":480,"height":360,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/schizo.flv-99999.meta.json b/testdata/golden/meta/schizo.flv-99999.meta.json index c157cde..62d3cfb 100644 --- a/testdata/golden/meta/schizo.flv-99999.meta.json +++ b/testdata/golden/meta/schizo.flv-99999.meta.json @@ -1 +1 @@ -{"orientation":1,"duration":2560,"width":480,"height":360,"fps":29.7,"selected_frame":76,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":1,"duration":2560,"width":480,"height":360,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/schizo_0.mp4-10.meta.json b/testdata/golden/meta/schizo_0.mp4-10.meta.json index 216174d..3dda84e 100644 --- a/testdata/golden/meta/schizo_0.mp4-10.meta.json +++ b/testdata/golden/meta/schizo_0.mp4-10.meta.json @@ -1 +1 @@ -{"orientation":1,"duration":2544,"width":480,"height":360,"fps":30,"selected_frame":6,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":1,"duration":2544,"width":480,"height":360,"fps":30,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/schizo_0.mp4-5.meta.json b/testdata/golden/meta/schizo_0.mp4-5.meta.json index ddadd37..3dda84e 100644 --- a/testdata/golden/meta/schizo_0.mp4-5.meta.json +++ b/testdata/golden/meta/schizo_0.mp4-5.meta.json @@ -1 +1 @@ -{"orientation":1,"duration":2544,"width":480,"height":360,"fps":30,"selected_frame":5,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":1,"duration":2544,"width":480,"height":360,"fps":30,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/schizo_0.mp4-9999.meta.json b/testdata/golden/meta/schizo_0.mp4-9999.meta.json index f80b288..39438cd 100644 --- a/testdata/golden/meta/schizo_0.mp4-9999.meta.json +++ b/testdata/golden/meta/schizo_0.mp4-9999.meta.json @@ -1 +1 @@ -{"orientation":1,"duration":2544,"width":480,"height":360,"fps":30,"selected_frame":20,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":1,"duration":2544,"width":480,"height":360,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/schizo_0.mp4-99999.meta.json b/testdata/golden/meta/schizo_0.mp4-99999.meta.json index f80b288..39438cd 100644 --- a/testdata/golden/meta/schizo_0.mp4-99999.meta.json +++ b/testdata/golden/meta/schizo_0.mp4-99999.meta.json @@ -1 +1 @@ -{"orientation":1,"duration":2544,"width":480,"height":360,"fps":30,"selected_frame":20,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":1,"duration":2544,"width":480,"height":360,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/schizo_180.mp4-10.meta.json b/testdata/golden/meta/schizo_180.mp4-10.meta.json index af41320..f992f3e 100644 --- a/testdata/golden/meta/schizo_180.mp4-10.meta.json +++ b/testdata/golden/meta/schizo_180.mp4-10.meta.json @@ -1 +1 @@ -{"orientation":3,"duration":2544,"width":480,"height":360,"fps":30,"selected_frame":5,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":3,"duration":2544,"width":480,"height":360,"fps":30,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/schizo_180.mp4-5.meta.json b/testdata/golden/meta/schizo_180.mp4-5.meta.json index af41320..f992f3e 100644 --- a/testdata/golden/meta/schizo_180.mp4-5.meta.json +++ b/testdata/golden/meta/schizo_180.mp4-5.meta.json @@ -1 +1 @@ -{"orientation":3,"duration":2544,"width":480,"height":360,"fps":30,"selected_frame":5,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":3,"duration":2544,"width":480,"height":360,"fps":30,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/schizo_180.mp4-9999.meta.json b/testdata/golden/meta/schizo_180.mp4-9999.meta.json index 16bad73..66e5afd 100644 --- a/testdata/golden/meta/schizo_180.mp4-9999.meta.json +++ b/testdata/golden/meta/schizo_180.mp4-9999.meta.json @@ -1 +1 @@ -{"orientation":3,"duration":2544,"width":480,"height":360,"fps":30,"selected_frame":20,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":3,"duration":2544,"width":480,"height":360,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/schizo_180.mp4-99999.meta.json b/testdata/golden/meta/schizo_180.mp4-99999.meta.json index 16bad73..66e5afd 100644 --- a/testdata/golden/meta/schizo_180.mp4-99999.meta.json +++ b/testdata/golden/meta/schizo_180.mp4-99999.meta.json @@ -1 +1 @@ -{"orientation":3,"duration":2544,"width":480,"height":360,"fps":30,"selected_frame":20,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":3,"duration":2544,"width":480,"height":360,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/schizo_270.mp4-10.meta.json b/testdata/golden/meta/schizo_270.mp4-10.meta.json index eddd15f..10bc562 100644 --- a/testdata/golden/meta/schizo_270.mp4-10.meta.json +++ b/testdata/golden/meta/schizo_270.mp4-10.meta.json @@ -1 +1 @@ -{"orientation":6,"duration":2544,"width":360,"height":480,"fps":30,"selected_frame":7,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":6,"duration":2544,"width":360,"height":480,"fps":30,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/schizo_270.mp4-5.meta.json b/testdata/golden/meta/schizo_270.mp4-5.meta.json index 6e0ff6a..10bc562 100644 --- a/testdata/golden/meta/schizo_270.mp4-5.meta.json +++ b/testdata/golden/meta/schizo_270.mp4-5.meta.json @@ -1 +1 @@ -{"orientation":6,"duration":2544,"width":360,"height":480,"fps":30,"selected_frame":5,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":6,"duration":2544,"width":360,"height":480,"fps":30,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/schizo_270.mp4-9999.meta.json b/testdata/golden/meta/schizo_270.mp4-9999.meta.json index 7500e2e..14ea544 100644 --- a/testdata/golden/meta/schizo_270.mp4-9999.meta.json +++ b/testdata/golden/meta/schizo_270.mp4-9999.meta.json @@ -1 +1 @@ -{"orientation":6,"duration":2544,"width":360,"height":480,"fps":30,"selected_frame":20,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":6,"duration":2544,"width":360,"height":480,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/schizo_270.mp4-99999.meta.json b/testdata/golden/meta/schizo_270.mp4-99999.meta.json index 7500e2e..14ea544 100644 --- a/testdata/golden/meta/schizo_270.mp4-99999.meta.json +++ b/testdata/golden/meta/schizo_270.mp4-99999.meta.json @@ -1 +1 @@ -{"orientation":6,"duration":2544,"width":360,"height":480,"fps":30,"selected_frame":20,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":6,"duration":2544,"width":360,"height":480,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/schizo_90.mp4-10.meta.json b/testdata/golden/meta/schizo_90.mp4-10.meta.json index 9042e84..ee3a3aa 100644 --- a/testdata/golden/meta/schizo_90.mp4-10.meta.json +++ b/testdata/golden/meta/schizo_90.mp4-10.meta.json @@ -1 +1 @@ -{"orientation":8,"duration":2544,"width":360,"height":480,"fps":30,"selected_frame":8,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":8,"duration":2544,"width":360,"height":480,"fps":30,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/schizo_90.mp4-5.meta.json b/testdata/golden/meta/schizo_90.mp4-5.meta.json index e36f985..ee3a3aa 100644 --- a/testdata/golden/meta/schizo_90.mp4-5.meta.json +++ b/testdata/golden/meta/schizo_90.mp4-5.meta.json @@ -1 +1 @@ -{"orientation":8,"duration":2544,"width":360,"height":480,"fps":30,"selected_frame":5,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":8,"duration":2544,"width":360,"height":480,"fps":30,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/schizo_90.mp4-9999.meta.json b/testdata/golden/meta/schizo_90.mp4-9999.meta.json index 782e073..7216654 100644 --- a/testdata/golden/meta/schizo_90.mp4-9999.meta.json +++ b/testdata/golden/meta/schizo_90.mp4-9999.meta.json @@ -1 +1 @@ -{"orientation":8,"duration":2544,"width":360,"height":480,"fps":30,"selected_frame":20,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":8,"duration":2544,"width":360,"height":480,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/meta/schizo_90.mp4-99999.meta.json b/testdata/golden/meta/schizo_90.mp4-99999.meta.json index 782e073..7216654 100644 --- a/testdata/golden/meta/schizo_90.mp4-99999.meta.json +++ b/testdata/golden/meta/schizo_90.mp4-99999.meta.json @@ -1 +1 @@ -{"orientation":8,"duration":2544,"width":360,"height":480,"fps":30,"selected_frame":20,"has_video":true,"has_audio":true} \ No newline at end of file +{"orientation":8,"duration":2544,"width":360,"height":480,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/result/500x/filters%3Aframe%280.5%29%3Aformat%28png%29/alpha-webm.webm b/testdata/golden/result/500x/filters%3Aframe%280.5%29%3Aformat%28png%29/alpha-webm.webm new file mode 100644 index 0000000..5309f98 Binary files /dev/null and b/testdata/golden/result/500x/filters%3Aframe%280.5%29%3Aformat%28png%29/alpha-webm.webm differ diff --git a/testdata/golden/result/500x/filters%3Aframe%285s%29%3Aformat%28png%29/alpha-webm.webm b/testdata/golden/result/500x/filters%3Aframe%285s%29%3Aformat%28png%29/alpha-webm.webm new file mode 100644 index 0000000..736e6c9 Binary files /dev/null and b/testdata/golden/result/500x/filters%3Aframe%285s%29%3Aformat%28png%29/alpha-webm.webm differ diff --git a/testdata/golden/result/500x/filters%3Aseek%280.5%29%3Aformat%28png%29/alpha-webm.webm b/testdata/golden/result/500x/filters%3Aseek%280.5%29%3Aformat%28png%29/alpha-webm.webm new file mode 100644 index 0000000..94ef2fb Binary files /dev/null and b/testdata/golden/result/500x/filters%3Aseek%280.5%29%3Aformat%28png%29/alpha-webm.webm differ diff --git a/testdata/golden/result/500x/filters%3Aseek%285s%29%3Aformat%28png%29/alpha-webm.webm b/testdata/golden/result/500x/filters%3Aseek%285s%29%3Aformat%28png%29/alpha-webm.webm new file mode 100644 index 0000000..8f039c9 Binary files /dev/null and b/testdata/golden/result/500x/filters%3Aseek%285s%29%3Aformat%28png%29/alpha-webm.webm differ diff --git a/testdata/golden/result/meta/filters%3Amax_frames%28%29/everybody-betray-me.mkv b/testdata/golden/result/meta/filters%3Amax_frames%28%29/everybody-betray-me.mkv index 4cf6af1..87a8093 100644 --- a/testdata/golden/result/meta/filters%3Amax_frames%28%29/everybody-betray-me.mkv +++ b/testdata/golden/result/meta/filters%3Amax_frames%28%29/everybody-betray-me.mkv @@ -1 +1 @@ -{"format":"mkv","content_type":"video/x-matroska","orientation":1,"duration":7407,"width":640,"height":480,"fps":30,"selected_frame":44,"has_video":true,"has_audio":true} \ No newline at end of file +{"format":"mkv","content_type":"video/x-matroska","orientation":1,"duration":7407,"width":640,"height":480,"fps":30,"has_video":true,"has_audio":true} \ No newline at end of file diff --git a/testdata/golden/result/meta/filters%3Amax_frames%286%29/everybody-betray-me.mkv b/testdata/golden/result/meta/filters%3Amax_frames%286%29/everybody-betray-me.mkv index 9aba5b3..ea245f6 100644 --- a/testdata/golden/result/meta/filters%3Amax_frames%286%29/everybody-betray-me.mkv +++ b/testdata/golden/result/meta/filters%3Amax_frames%286%29/everybody-betray-me.mkv @@ -1 +1 @@ -{"format":"mkv","content_type":"video/x-matroska","orientation":1,"duration":7407,"width":640,"height":480,"fps":29.9,"selected_frame":4,"has_video":true,"has_audio":true} \ No newline at end of file +{"format":"mkv","content_type":"video/x-matroska","orientation":1,"duration":7407,"width":640,"height":480,"fps":29.9,"has_video":true,"has_audio":true} \ No newline at end of file