From 919b52d9be4d785b891e51b0124917d1a7c1842f Mon Sep 17 00:00:00 2001 From: Travis Ralston <travpc@gmail.com> Date: Sun, 16 Aug 2020 12:44:04 -0600 Subject: [PATCH] Add preliminary support for MP4 files This needs to be expanded to cover more of what ffmpeg covers. This does not support animation for a few reasons: * Most clients which will be using a video thumbnail will be using it in such a way where even a GIF isn't supported. * Clients rely on the thumbnail endpoint returning images, which can lead to resource inefficiencies if we return GIFs. * Returning more optimized thumbnails is not feasible for compatibility with most clients. --- CHANGELOG.md | 1 + config.sample.yaml | 1 + thumbnailing/i/mp4.go | 66 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 thumbnailing/i/mp4.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 19136c43..39a155f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), * After running this tool, use the `gdpr_import` tool to bring the export into the media repo. * Added thumbnailing support for some audio waveforms (MP3, WAV, OGG, and FLAC). * Added audio metadata (duration, etc) to the unstable `/info` endpoint. Aligns with [MSC2380](https://github.com/matrix-org/matrix-doc/pull/2380). +* Added simple thumbnailing for MP4 videos. ### Fixed diff --git a/config.sample.yaml b/config.sample.yaml index 78d4366a..f237af47 100644 --- a/config.sample.yaml +++ b/config.sample.yaml @@ -397,6 +397,7 @@ thumbnails: - "audio/ogg" - "audio/wav" - "audio/flac" + #- "video/mp4" # Be sure to have ffmpeg installed to thumbnail video files # Animated thumbnails can be CPU intensive to generate. To disable the generation of animated # thumbnails, set this to false. If disabled, regular thumbnails will be returned. diff --git a/thumbnailing/i/mp4.go b/thumbnailing/i/mp4.go new file mode 100644 index 00000000..82414378 --- /dev/null +++ b/thumbnailing/i/mp4.go @@ -0,0 +1,66 @@ +package i + +import ( + "errors" + _ "image/jpeg" + "io/ioutil" + "os" + "os/exec" + "path" + + "github.com/turt2live/matrix-media-repo/common/rcontext" + "github.com/turt2live/matrix-media-repo/thumbnailing/m" + "github.com/turt2live/matrix-media-repo/util" + "github.com/turt2live/matrix-media-repo/util/cleanup" +) + +type mp4Generator struct { +} + +func (d mp4Generator) supportedContentTypes() []string { + return []string{"video/mp4"} +} + +func (d mp4Generator) supportsAnimation() bool { + return false +} + +func (d mp4Generator) matches(img []byte, contentType string) bool { + return util.ArrayContains(d.supportedContentTypes(), contentType) +} + +func (d mp4Generator) GenerateThumbnail(b []byte, contentType string, width int, height int, method string, animated bool, ctx rcontext.RequestContext) (*m.Thumbnail, error) { + key, err := util.GenerateRandomString(16) + if err != nil { + return nil, errors.New("mp4: error generating temp key: " + err.Error()) + } + + tempFile1 := path.Join(os.TempDir(), "media_repo."+key+".1.mp4") + tempFile2 := path.Join(os.TempDir(), "media_repo."+key+".2.png") + + defer os.Remove(tempFile1) + defer os.Remove(tempFile2) + + f, err := os.OpenFile(tempFile1, os.O_RDWR|os.O_CREATE, 0640) + if err != nil { + return nil, errors.New("mp4: error writing temp video file: " + err.Error()) + } + _, _ = f.Write(b) + cleanup.DumpAndCloseStream(f) + + err = exec.Command("ffmpeg", "-i", tempFile1, "-vf", "select=eq(n\\,0)", tempFile2).Run() + if err != nil { + return nil, errors.New("mp4: error converting video file: " + err.Error()) + } + + b, err = ioutil.ReadFile(tempFile2) + if err != nil { + return nil, errors.New("mp4: error reading temp png file: " + err.Error()) + } + + return pngGenerator{}.GenerateThumbnail(b, "image/png", width, height, method, false, ctx) +} + +func init() { + generators = append(generators, mp4Generator{}) +} -- GitLab